diff --git a/.dprint.jsonc b/.dprint.jsonc new file mode 100644 index 0000000000000..081c71f18893a --- /dev/null +++ b/.dprint.jsonc @@ -0,0 +1,56 @@ +{ + "indentWidth": 4, + "lineWidth": 120, + "newLineKind": "auto", + "useTabs": false, + "typescript": { + "newLineKind": "crlf", + "semiColons": "always", + "quoteStyle": "preferDouble", + "quoteProps": "consistent", + "useBraces": "whenNotSingleLine", + "bracePosition": "sameLineUnlessHanging", + "singleBodyPosition": "sameLine", + "nextControlFlowPosition": "nextLine", // Stroustrup style braces. + "trailingCommas": "onlyMultiLine", + "preferHanging": false, + "operatorPosition": "nextLine", + + "arrowFunction.useParentheses": "preferNone", + "conditionalExpression.linePerExpression": false, // Keep our "match/case"-ish conditionals. + "functionExpression.spaceAfterFunctionKeyword": true, + "importDeclaration.forceMultiLine": true, + "constructorType.spaceAfterNewKeyword": true, + "constructSignature.spaceAfterNewKeyword": true, + + // Let eslint-plugin-simple-import-sort handle this. + "module.sortImportDeclarations": "maintain", + "module.sortExportDeclarations": "maintain", + "exportDeclaration.sortNamedExports": "maintain", + "importDeclaration.sortNamedImports": "maintain" + }, + "prettier": { + "associations": [ + "**/*.{yaml,yml}" + ], + "yml.tabWidth": 2, + "yaml.tabWidth": 2, + "yml.singleQuote": true, + "yaml.singleQuote": true + }, + "excludes": [ + "**/node_modules", + "**/*-lock.json", + "coverage/**", + "lib/**", + "built/**", + "tests/**", + "internal/**", + "**/*.generated.*", + "scripts/*.d.*" + ], + "plugins": [ + "https://plugins.dprint.dev/typescript-0.86.1.wasm", + "https://plugins.dprint.dev/prettier-0.27.0.json@3557a62b4507c55a47d8cde0683195b14d13c41dda66d0f0b0e111aed107e2fe" + ] +} diff --git a/.eslintplugin.js b/.eslintplugin.js index 97525acf6ffd3..c950681b24cb4 100644 --- a/.eslintplugin.js +++ b/.eslintplugin.js @@ -3,10 +3,10 @@ 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)); +const ruleFiles = fs.readdirSync(rulesDir).filter(p => p.endsWith(ext)); module.exports = { - rules: Object.fromEntries(ruleFiles.map((p) => { + rules: Object.fromEntries(ruleFiles.map(p => { return [p.slice(0, -ext.length), require(path.join(rulesDir, p))]; })), -} +}; diff --git a/.eslintrc.json b/.eslintrc.json index 0eb936e9be5c8..5f3d49fde9631 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -128,33 +128,7 @@ // eslint-plugin-simple-import-sort "simple-import-sort/imports": "error", - "simple-import-sort/exports": "error", - - // Formatting rules; remove once a formatter enforces these. - "curly": ["error", "multi-line"], - "linebreak-style": ["error", "windows"], - "max-statements-per-line": ["error", { "max": 1 }], - "new-parens": "error", - "no-trailing-spaces": "error", - "quote-props": ["error", "consistent-as-needed"], - "space-in-parens": "error", - "@typescript-eslint/brace-style": ["error", "stroustrup", { "allowSingleLine": true }], - "@typescript-eslint/no-extra-semi": "error", - "@typescript-eslint/quotes": ["error", "double", { "avoidEscape": true, "allowTemplateLiterals": true }], - "@typescript-eslint/semi": "error", - "@typescript-eslint/space-before-function-paren": [ - "error", - { - "asyncArrow": "always", - "anonymous": "always", - "named": "never" - } - ], - "local/object-literal-surrounding-space": "error", - "local/no-type-assertion-whitespace": "error", - "local/type-operator-spacing": "error", - "local/no-double-space": "error", - "local/simple-indent": "error" + "simple-import-sort/exports": "error" }, "overrides": [ // By default, the ESLint CLI only looks at .js files. But, it will also look at diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 6e2a702d8ab99..d48cb08eb5b09 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,5 @@ b6c053882696af8ddd94a600429f30584d303d7f 9a0b85ce2a3f85f498ab2c05474b4c0b96b111c9 # Generated module conversion step - unindent 94724a8c2e68a4c7e267072ca79971f317c45e4a +# dprint +5e8c261b6ab746213f19ee3501eb8c48a6215dd7 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index ac2e1f6bd02c5..61241ea7bf909 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,5 +1,5 @@ -name: "Bug report" -description: "Create a report to help us improve TypeScript" +name: 'Bug report' +description: 'Create a report to help us improve TypeScript' body: - type: markdown attributes: @@ -7,7 +7,7 @@ body: - type: textarea id: search_terms attributes: - label: "🔎 Search Terms" + label: '🔎 Search Terms' description: | What search terms did you use when trying to find an existing bug report? @@ -22,7 +22,7 @@ body: - type: textarea id: version_info attributes: - label: "🕗 Version & Regression Information" + label: '🕗 Version & Regression Information' description: | When did you start seeing this bug occur? @@ -33,7 +33,7 @@ body: If possible, please try testing the nightly version of TS to see if it's already been fixed. For npm: `typescript@next` This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly - + Note: The TypeScript Playground can be used to try older versions of TypeScript. @@ -56,7 +56,7 @@ body: As a last resort, you can link to a repo, but these will be slower for us to investigate. - placeholder: "Playground link with relevant code: https://www.typescriptlang.org/play?#code/PTAEFkE9QYwewCYFNQHM5IM6gBZIE5JA" + placeholder: 'Playground link with relevant code: https://www.typescriptlang.org/play?#code/PTAEFkE9QYwewCYFNQHM5IM6gBZIE5JA' validations: required: false - type: textarea @@ -87,7 +87,7 @@ body: id: actual_behavior attributes: label: 🙁 Actual behavior - description: "What happened, and why it was wrong." + description: 'What happened, and why it was wrong.' validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 69db3e0326a02..9526309bdc220 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,19 +1,15 @@ ---- +--- blank_issues_enabled: false -contact_links: - - - about: "Please ask and answer usage questions on Stack Overflow." +contact_links: + - about: 'Please ask and answer usage questions on Stack Overflow.' name: Question - url: "https://stackoverflow.com/questions/tagged/typescript" - - - about: "Alternatively, you can use the TypeScript Community Discord." + url: 'https://stackoverflow.com/questions/tagged/typescript' + - about: 'Alternatively, you can use the TypeScript Community Discord.' name: Chat - url: "https://discord.gg/typescript" - - - about: "Please check the FAQ before filing new issues" - name: "TypeScript FAQ" - url: "https://github.com/microsoft/TypeScript/wiki/FAQ" - - - about: "Please raise issues about the site on its own repo." + url: 'https://discord.gg/typescript' + - about: 'Please check the FAQ before filing new issues' + name: 'TypeScript FAQ' + url: 'https://github.com/microsoft/TypeScript/wiki/FAQ' + - about: 'Please raise issues about the site on its own repo.' name: Website - url: "https://github.com/microsoft/TypeScript-Website/issues/new" + url: 'https://github.com/microsoft/TypeScript-Website/issues/new' diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 07424b99d7ae4..ad96977fafa9f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,19 +1,19 @@ -name: "Feature request" -description: "Suggest an idea" +name: 'Feature request' +description: 'Suggest an idea' body: - type: markdown attributes: - value: "Please fill in each section completely. Thank you!" + value: 'Please fill in each section completely. Thank you!' - type: textarea id: search_terms attributes: - label: "🔍 Search Terms" + label: '🔍 Search Terms' description: | - 💡 Did you know? TypeScript has over 2,000 open suggestions! + 💡 Did you know? TypeScript has over 2,000 open suggestions! - 🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress. + 🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress. - The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests + The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests placeholder: | List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily and help provide feedback. @@ -24,7 +24,7 @@ body: - type: checkboxes id: viability_checklist attributes: - label: "✅ Viability Checklist" + label: '✅ Viability Checklist' description: | Suggestions that don't meet all these criteria are very, very unlikely to be accepted. We always recommend reviewing the TypeScript design goals before investing time writing @@ -32,36 +32,36 @@ body: My suggestion meets the following guidelines. options: - - label: This wouldn't be a breaking change in existing TypeScript/JavaScript code - required: true - - label: This wouldn't change the runtime behavior of existing JavaScript code - required: true - - label: This could be implemented without emitting different JS based on the types of the expressions - required: true - - label: This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.) - required: true - - label: "This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals" - required: true + - label: This wouldn't be a breaking change in existing TypeScript/JavaScript code + required: true + - label: This wouldn't change the runtime behavior of existing JavaScript code + required: true + - label: This could be implemented without emitting different JS based on the types of the expressions + required: true + - label: This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.) + required: true + - label: 'This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals' + required: true - type: textarea id: suggestion_summary attributes: - label: "⭐ Suggestion" + label: '⭐ Suggestion' description: "A summary of what you'd like to see added or changed" validations: required: true - type: textarea id: motivating_example attributes: - label: "📃 Motivating Example" + label: '📃 Motivating Example' description: | - If you were announcing this feature in a blog post, what's a short - explanation that shows a developer why this feature improves the language? + If you were announcing this feature in a blog post, what's a short + explanation that shows a developer why this feature improves the language? validations: required: true - type: textarea id: use_cases attributes: - label: "💻 Use Cases" + label: '💻 Use Cases' value: | 1. What do you want to use this for? 2. What shortcomings exist with current approaches? diff --git a/.github/ISSUE_TEMPLATE/lib_change.yml b/.github/ISSUE_TEMPLATE/lib_change.yml index 8fc6a3034f36e..f3d5c40b50614 100644 --- a/.github/ISSUE_TEMPLATE/lib_change.yml +++ b/.github/ISSUE_TEMPLATE/lib_change.yml @@ -1,5 +1,5 @@ -name: "Library change" -description: "Fix or improve issues with built-in type definitions like `lib.dom.d.ts`, `lib.es6.d.ts`, etc." +name: 'Library change' +description: 'Fix or improve issues with built-in type definitions like `lib.dom.d.ts`, `lib.es6.d.ts`, etc.' body: - type: markdown attributes: @@ -18,37 +18,37 @@ body: - type: markdown attributes: value: | - If you're missing common new methods like `Array.includes`, you may have a misconfigured project. - Try setting `lib: "es2020"` and checking whether the type you want is present. - You can diagnose further by running `tsc` with `--listFilesOnly` or `--showConfig`. + If you're missing common new methods like `Array.includes`, you may have a misconfigured project. + Try setting `lib: "es2020"` and checking whether the type you want is present. + You can diagnose further by running `tsc` with `--listFilesOnly` or `--showConfig`. - Conversely, if you are seeing built-in methods you expect to *not* see, check your 'lib' setting or review your dependencies for lib/reference directives that might be polluting - your global scope. This is common when using the 'node' type library. See https://github.com/microsoft/TypeScript/issues/40184 + Conversely, if you are seeing built-in methods you expect to *not* see, check your 'lib' setting or review your dependencies for lib/reference directives that might be polluting + your global scope. This is common when using the 'node' type library. See https://github.com/microsoft/TypeScript/issues/40184 - type: input id: compilation_target attributes: - label: "⚙ Compilation target" + label: '⚙ Compilation target' description: "What's your compilation target (e.g.: `ES2015`)?" validations: required: true - type: input id: current_lib attributes: - label: "⚙ Library" + label: '⚙ Library' description: "What's the current library you're using?" validations: required: true - type: textarea id: incorrect_definition attributes: - label: "Missing / Incorrect Definition" - description: "What property, method, function, etc. is missing or incorrect?" + label: 'Missing / Incorrect Definition' + description: 'What property, method, function, etc. is missing or incorrect?' validations: required: true - type: textarea id: sample_code attributes: - label: "Sample Code" + label: 'Sample Code' description: "What's some code using this that should work, but doesn't?" render: TypeScript validations: @@ -56,7 +56,7 @@ body: - type: textarea id: documentation_link attributes: - label: "Documentation Link" + label: 'Documentation Link' description: | Link to relevant documentation (e.g. MDN, W3C, ECMAScript Spec) to consult for this property. Note that lib.dom.d.ts intentionally does not include browser-specific extensions or early experimental features. diff --git a/.github/ISSUE_TEMPLATE/module_resolution.yml b/.github/ISSUE_TEMPLATE/module_resolution.yml index dd3b50a326b6a..bfcff786bc4ec 100644 --- a/.github/ISSUE_TEMPLATE/module_resolution.yml +++ b/.github/ISSUE_TEMPLATE/module_resolution.yml @@ -1,6 +1,6 @@ name: Module resolution description: Report a problem with module resolution -title: "Module resolution:" +title: 'Module resolution:' labels: [] body: - type: markdown @@ -12,6 +12,8 @@ body: Most module resolution bug reports are actually misconfigurations, so we require a thorough pre-investigation before we can look into any potential issues. + Many module problems can be automatically detected with [Are The Types Wrong?](https://arethetypeswrong.github.io/) and you should use this tool first if it appears that the module shape is wrong. + Let's make sure you're ready to file a module resolution bug. - type: markdown @@ -64,7 +66,7 @@ body: attributes: label: Run `tsc --showConfig` and paste its output here description: Repros that depend on running within external tools (yarn, pnpm, esbuild, etc.) are not TypeScript defects and will not be investigated. - placeholder: "> tsc --showConfig" + placeholder: '> tsc --showConfig' validations: required: true @@ -73,7 +75,7 @@ body: attributes: label: Run `tsc --traceResolution` and paste its output here description: Run `tsc --traceResolution` and paste the output here. - placeholder: "> tsc --traceResolution" + placeholder: '> tsc --traceResolution' validations: required: true @@ -81,7 +83,7 @@ body: id: import-package-json attributes: label: Paste the `package.json` of the *importing* module, if it exists - placeholder: "my_project/package.json" + placeholder: 'my_project/package.json' validations: required: true @@ -89,7 +91,7 @@ body: id: export-package-json attributes: label: Paste the `package.json` of the *target* module, if it exists - placeholder: "node_modules/somepkg/package.json" + placeholder: 'node_modules/somepkg/package.json' validations: required: true @@ -97,6 +99,6 @@ body: id: comments attributes: label: Any other comments can go here - placeholder: "Have a nice day!" + placeholder: 'Have a nice day!' validations: required: true diff --git a/.github/ISSUE_TEMPLATE/other.yml b/.github/ISSUE_TEMPLATE/other.yml index e23eee5ccc098..bc9b84fd71b6b 100644 --- a/.github/ISSUE_TEMPLATE/other.yml +++ b/.github/ISSUE_TEMPLATE/other.yml @@ -1,13 +1,13 @@ -name: "Other" -description: "Something not captured by any other template" +name: 'Other' +description: 'Something not captured by any other template' body: - type: checkboxes id: acknowledgement attributes: label: Acknowledgement options: - - label: I acknowledge that issues using this template may be closed without further explanation at the maintainer's discretion. - required: true + - label: I acknowledge that issues using this template may be closed without further explanation at the maintainer's discretion. + required: true - type: textarea id: contents attributes: diff --git a/.github/codeql/codeql-configuration.yml b/.github/codeql/codeql-configuration.yml index f94ac49439139..5012a8c080e48 100644 --- a/.github/codeql/codeql-configuration.yml +++ b/.github/codeql/codeql-configuration.yml @@ -1,4 +1,4 @@ -name : CodeQL Configuration +name: CodeQL Configuration paths: - src diff --git a/.github/workflows/accept-baselines-fix-lints.yaml b/.github/workflows/accept-baselines-fix-lints.yaml index 7462a8ec794c8..cc3f27235f52b 100644 --- a/.github/workflows/accept-baselines-fix-lints.yaml +++ b/.github/workflows/accept-baselines-fix-lints.yaml @@ -20,19 +20,19 @@ jobs: contents: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 - - name: Configure Git, Run Tests, Update Baselines, Apply Fixes - run: | - git config user.email "typescriptbot@microsoft.com" - git config user.name "TypeScript Bot" - npm ci - git rm -r --quiet tests/baselines/reference - npx hereby runtests-parallel --ci --fix || true - npx hereby baseline-accept - git add ./src - git add ./tests/baselines/reference - git diff --cached - git commit -m "Update Baselines and/or Applied Lint Fixes" - git push + - name: Configure Git, Run Tests, Update Baselines, Apply Fixes + run: | + git config user.email "typescriptbot@microsoft.com" + git config user.name "TypeScript Bot" + npm ci + git rm -r --quiet tests/baselines/reference + npx hereby runtests-parallel --ci --fix || true + npx hereby baseline-accept + git add ./src + git add ./tests/baselines/reference + git diff --cached + git commit -m "Update Baselines and/or Applied Lint Fixes" + git push diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a551bed2d27e9..e35bd060e6311 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,219 +26,243 @@ jobs: strategy: matrix: node-version: - - "20" - - "18" - - "16" - - "14" + - '20' + - '18' + - '16' + - '14' bundle: - - "true" + - 'true' include: - - node-version: "*" - bundle: "false" + - node-version: '*' + bundle: 'false' name: Test Node ${{ matrix.node-version }} with --bundle=${{ matrix.bundle }} steps: - - uses: actions/checkout@v3 - - name: Use node version ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - check-latest: true - - run: npm ci - - - name: Tests - # run tests, but lint separately - run: npm run test -- --no-lint --bundle=${{ matrix.bundle }} + - uses: actions/checkout@v3 + - name: Use node version ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + check-latest: true + - run: npm ci + + - name: Tests + # run tests, but lint separately + run: npm run test -- --no-lint --bundle=${{ matrix.bundle }} lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "*" - check-latest: true - - run: npm ci + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: npm ci - - name: Linter - run: npm run lint + - name: Linter + run: npm run lint + + format: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: npm ci + + # TODO: The cache fails when copied between GHA runners. See: + # https://github.com/dprint/dprint/issues/734 + # https://github.com/dprint/dprint/issues/735 + # - uses: actions/cache@v3 + # with: + # path: ~/.cache/dprint + # key: ${{ runner.os }}-dprint-${{ hashFiles('package-lock.json', '.dprint.jsonc') }} + # restore-keys: | + # ${{ runner.os }}-dprint- + + - name: Check formatting + run: npx dprint check browser-integration: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "*" - check-latest: true - - run: npm ci + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: npm ci - - name: Adding playwright - run: npm install --no-save --no-package-lock playwright + - name: Adding playwright + run: npm install --no-save --no-package-lock playwright - - name: Validate the browser can import TypeScript - run: npx hereby test-browser-integration + - name: Validate the browser can import TypeScript + run: npx hereby test-browser-integration typecheck: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "*" - check-latest: true - - run: npm ci + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: npm ci - - name: Build src - run: npx hereby build-src + - name: Build src + run: npx hereby build-src smoke: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-node@v3 - with: - node-version: "*" - check-latest: true - - run: | - npm --version - # corepack enable npm - npm install -g $(jq -r '.packageManager' < package.json) - npm --version - - - run: npm ci - - - run: npx hereby lkg - - run: | - npm pack - mv typescript*.tgz typescript.tgz - echo "package=$PWD/typescript.tgz" >> "$GITHUB_OUTPUT" - id: pack - - - name: Smoke test - run: | - cd "$(mktemp -d)" - npm init --yes - npm install ${{ steps.pack.outputs.package }} - - echo "Testing tsc..." - npx tsc --version - - echo "Testing tsserver..." - echo '{"seq": 1, "command": "status"}' | npx tsserver - - node $GITHUB_WORKSPACE/scripts/checkModuleFormat.mjs typescript - node $GITHUB_WORKSPACE/scripts/checkModuleFormat.mjs typescript/lib/tsserverlibrary + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: | + npm --version + # corepack enable npm + npm install -g $(jq -r '.packageManager' < package.json) + npm --version + + - run: npm ci + + - run: npx hereby lkg + - run: | + npm pack + mv typescript*.tgz typescript.tgz + echo "package=$PWD/typescript.tgz" >> "$GITHUB_OUTPUT" + id: pack + + - name: Smoke test + run: | + cd "$(mktemp -d)" + npm init --yes + npm install ${{ steps.pack.outputs.package }} + + echo "Testing tsc..." + npx tsc --version + + echo "Testing tsserver..." + echo '{"seq": 1, "command": "status"}' | npx tsserver + + node $GITHUB_WORKSPACE/scripts/checkModuleFormat.mjs typescript + node $GITHUB_WORKSPACE/scripts/checkModuleFormat.mjs typescript/lib/tsserverlibrary package-size: runs-on: ubuntu-latest if: github.event_name == 'pull_request' steps: - - uses: actions/checkout@v3 - with: - path: pr - - - uses: actions/checkout@v3 - with: - path: base - ref: ${{ github.base_ref }} - - - uses: actions/setup-node@v3 - with: - node-version: "*" - check-latest: true - - run: | - npm --version - # corepack enable npm - - - run: | - npm install -g $(jq -r '.packageManager' < package.json) - npm --version - working-directory: ./pr - - - run: npm ci - working-directory: ./pr - - - run: npm ci - working-directory: ./base - - - run: npx hereby lkg - working-directory: ./pr - - - run: npx hereby lkg - working-directory: ./base - - - run: | - echo "See $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID for more info." - node ./pr/scripts/checkPackageSize.mjs ./base ./pr >> $GITHUB_STEP_SUMMARY + - uses: actions/checkout@v3 + with: + path: pr + + - uses: actions/checkout@v3 + with: + path: base + ref: ${{ github.base_ref }} + + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: | + npm --version + # corepack enable npm + + - run: | + npm install -g $(jq -r '.packageManager' < package.json) + npm --version + working-directory: ./pr + + - run: npm ci + working-directory: ./pr + + - run: npm ci + working-directory: ./base + + - run: npx hereby lkg + working-directory: ./pr + + - run: npx hereby lkg + working-directory: ./base + + - run: | + echo "See $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID for more info." + node ./pr/scripts/checkPackageSize.mjs ./base ./pr >> $GITHUB_STEP_SUMMARY misc: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "*" - check-latest: true - - run: npm ci + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: npm ci - - name: Build scripts - run: npx hereby scripts + - name: Build scripts + run: npx hereby scripts - - name: ESLint tests - run: npx hereby run-eslint-rules-tests + - name: ESLint tests + run: npx hereby run-eslint-rules-tests self-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "*" - check-latest: true - - run: npm ci + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: npm ci - - name: Build tsc - run: npx hereby tsc + - name: Build tsc + run: npx hereby tsc - - name: Clean - run: npx hereby clean-src + - name: Clean + run: npx hereby clean-src - - name: Self build - run: npx hereby build-src --built + - name: Self build + run: npx hereby build-src --built unused-baselines: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: "*" - check-latest: true - - run: npm ci - - - name: Remove all baselines - run: rm -rf tests/baselines/reference - - - name: Run tests - run: npm test &> /dev/null || exit 0 - - - name: Accept baselines - run: npx hereby baseline-accept - - - name: Check for unused baselines - run: | - if ! git diff --exit-code --quiet; then - echo "Unused baselines:" - git diff --exit-code --name-only - fi + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '*' + check-latest: true + - run: npm ci + + - name: Remove all baselines + run: rm -rf tests/baselines/reference + + - name: Run tests + run: npm test &> /dev/null || exit 0 + + - name: Accept baselines + run: npx hereby baseline-accept + + - name: Check for unused baselines + run: | + if ! git diff --exit-code --quiet; then + echo "Unused baselines:" + git diff --exit-code --name-only + fi diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b90bfec110d5d..a54f05f8c3f04 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,4 +1,4 @@ -name: "Code Scanning - Action" +name: 'Code Scanning - Action' on: push: diff --git a/.github/workflows/ensure-related-repos-run-crons.yml b/.github/workflows/ensure-related-repos-run-crons.yml index 2e72bd2c6e6e3..077095ce9a64d 100644 --- a/.github/workflows/ensure-related-repos-run-crons.yml +++ b/.github/workflows/ensure-related-repos-run-crons.yml @@ -6,10 +6,10 @@ name: Related Repo Commit Bumps on: - schedule: - # Monthly, https://crontab.guru/#0_0_*_1-12_* - - cron: '0 0 1 * *' - workflow_dispatch: {} + schedule: + # Monthly, https://crontab.guru/#0_0_*_1-12_* + - cron: '0 0 1 * *' + workflow_dispatch: {} permissions: contents: read @@ -26,31 +26,31 @@ jobs: if: github.repository == 'microsoft/TypeScript' steps: - - name: Configure git - run: | - git config --global user.email "typescriptbot@microsoft.com" - git config --global user.name "TypeScript Bot" - - - uses: actions/checkout@v3 - with: - repository: 'microsoft/TypeScript-Website' - path: 'ts-site' - - - name: Push Commit to TS Website - run: | - cd ts-site - git commit --allow-empty -m "Monthly Bump" - git config --unset-all http.https://github.com/.extraheader - git push https://${{ secrets.TS_BOT_GITHUB_TOKEN }}@github.com/microsoft/TypeScript-Website.git - - - uses: actions/checkout@v3 - with: - repository: 'microsoft/TypeScript-Make-Monaco-Builds' - path: 'monaco-builds' - - - name: Push Commit to TS Make Monaco Builds - run: | - cd monaco-builds - git commit --allow-empty -m "Monthly Bump" - git config --unset-all http.https://github.com/.extraheader - git push https://${{ secrets.TS_BOT_GITHUB_TOKEN }}@github.com/microsoft/TypeScript-Make-Monaco-Builds.git + - name: Configure git + run: | + git config --global user.email "typescriptbot@microsoft.com" + git config --global user.name "TypeScript Bot" + + - uses: actions/checkout@v3 + with: + repository: 'microsoft/TypeScript-Website' + path: 'ts-site' + + - name: Push Commit to TS Website + run: | + cd ts-site + git commit --allow-empty -m "Monthly Bump" + git config --unset-all http.https://github.com/.extraheader + git push https://${{ secrets.TS_BOT_GITHUB_TOKEN }}@github.com/microsoft/TypeScript-Website.git + + - uses: actions/checkout@v3 + with: + repository: 'microsoft/TypeScript-Make-Monaco-Builds' + path: 'monaco-builds' + + - name: Push Commit to TS Make Monaco Builds + run: | + cd monaco-builds + git commit --allow-empty -m "Monthly Bump" + git config --unset-all http.https://github.com/.extraheader + git push https://${{ secrets.TS_BOT_GITHUB_TOKEN }}@github.com/microsoft/TypeScript-Make-Monaco-Builds.git diff --git a/.github/workflows/error-deltas-watchdog.yaml b/.github/workflows/error-deltas-watchdog.yaml index 14b2cff887408..86aee16a71556 100644 --- a/.github/workflows/error-deltas-watchdog.yaml +++ b/.github/workflows/error-deltas-watchdog.yaml @@ -1,4 +1,4 @@ -name: "typescript-error-deltas Watchdog" +name: 'typescript-error-deltas Watchdog' on: workflow_dispatch: @@ -23,23 +23,23 @@ jobs: issues: write env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAGS: "@navya9singh @RyanCavanaugh @DanielRosenwasser" + TAGS: '@navya9singh @RyanCavanaugh @DanielRosenwasser' steps: - - name: NewErrors - run: | # --json and --jq prints exactly one issue number per line of output - DATE=$(date --date="7 days ago" --iso-8601) - gh issue list --repo microsoft/typescript --search "[NewErrors] created:>=$DATE" --state all --json number --jq ".[].number" \ - | grep -qe "[0-9]" \ - || gh issue create --repo ${{ github.repository }} --title "No NewErrors issue since $DATE" --body "$TAGS Please check the [pipeline](https://typescript.visualstudio.com/TypeScript/_build?definitionId=48)." - - name: ServerErrors TS - run: | - DATE=$(date --date="7 days ago" --iso-8601) - gh issue list --repo microsoft/typescript --search "[ServerErrors][TypeScript] created:>=$DATE" --state all --json number --jq ".[].number" \ - | grep -qe "[0-9]" \ - || gh issue create --repo ${{ github.repository }} --title "No TypeScript ServerErrors issue since $DATE" --body "$TAGS Please check the [pipeline](https://typescript.visualstudio.com/TypeScript/_build?definitionId=59)." - - name: ServerErrors JS - run: | - DATE=$(date --date="7 days ago" --iso-8601) - gh issue list --repo microsoft/typescript --search "[ServerErrors][JavaScript] created:>=$DATE" --state all --json number --jq ".[].number" \ - | grep -qe "[0-9]" \ - || gh issue create --repo ${{ github.repository }} --title "No JavaScript ServerErrors issue since $DATE" --body "$TAGS Please check the [pipeline](https://typescript.visualstudio.com/TypeScript/_build?definitionId=58)." + - name: NewErrors + run: | # --json and --jq prints exactly one issue number per line of output + DATE=$(date --date="7 days ago" --iso-8601) + gh issue list --repo microsoft/typescript --search "[NewErrors] created:>=$DATE" --state all --json number --jq ".[].number" \ + | grep -qe "[0-9]" \ + || gh issue create --repo ${{ github.repository }} --title "No NewErrors issue since $DATE" --body "$TAGS Please check the [pipeline](https://typescript.visualstudio.com/TypeScript/_build?definitionId=48)." + - name: ServerErrors TS + run: | + DATE=$(date --date="7 days ago" --iso-8601) + gh issue list --repo microsoft/typescript --search "[ServerErrors][TypeScript] created:>=$DATE" --state all --json number --jq ".[].number" \ + | grep -qe "[0-9]" \ + || gh issue create --repo ${{ github.repository }} --title "No TypeScript ServerErrors issue since $DATE" --body "$TAGS Please check the [pipeline](https://typescript.visualstudio.com/TypeScript/_build?definitionId=59)." + - name: ServerErrors JS + run: | + DATE=$(date --date="7 days ago" --iso-8601) + gh issue list --repo microsoft/typescript --search "[ServerErrors][JavaScript] created:>=$DATE" --state all --json number --jq ".[].number" \ + | grep -qe "[0-9]" \ + || gh issue create --repo ${{ github.repository }} --title "No JavaScript ServerErrors issue since $DATE" --body "$TAGS Please check the [pipeline](https://typescript.visualstudio.com/TypeScript/_build?definitionId=58)." diff --git a/.github/workflows/new-release-branch.yaml b/.github/workflows/new-release-branch.yaml index 8d5ec9a7010c8..666b322cfcea8 100644 --- a/.github/workflows/new-release-branch.yaml +++ b/.github/workflows/new-release-branch.yaml @@ -21,32 +21,32 @@ jobs: contents: write steps: - - uses: actions/setup-node@v3 - - run: | - npm --version - # corepack enable npm - npm install -g $(jq -r '.packageManager' < package.json) - npm --version - - uses: actions/checkout@v3 - with: - fetch-depth: 5 - - run: | - git checkout -b ${{ github.event.client_payload.branch_name }} - sed -i -e 's/"version": ".*"/"version": "${{ github.event.client_payload.package_version }}"/g' package.json - sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' src/compiler/corePublic.ts - sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/typescript.d.ts - sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/tsserverlibrary.d.ts - sed -i -e 's/const version\(: string\)\{0,1\} = `${versionMajorMinor}.0-.*`/const version = `${versionMajorMinor}.0-${{ github.event.client_payload.core_tag || 'dev' }}`/g' src/compiler/corePublic.ts - npm ci - npx hereby LKG - npm test - git diff - git add package.json - git add src/compiler/corePublic.ts - git add tests/baselines/reference/api/typescript.d.ts - git add tests/baselines/reference/api/tsserverlibrary.d.ts - git add --force ./lib - git config user.email "typescriptbot@microsoft.com" - git config user.name "TypeScript Bot" - git commit -m 'Bump version to ${{ github.event.client_payload.package_version }} and LKG' - git push --set-upstream origin ${{ github.event.client_payload.branch_name }} + - uses: actions/setup-node@v3 + - run: | + npm --version + # corepack enable npm + npm install -g $(jq -r '.packageManager' < package.json) + npm --version + - uses: actions/checkout@v3 + with: + fetch-depth: 5 + - run: | + git checkout -b ${{ github.event.client_payload.branch_name }} + sed -i -e 's/"version": ".*"/"version": "${{ github.event.client_payload.package_version }}"/g' package.json + sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' src/compiler/corePublic.ts + sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/typescript.d.ts + sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/tsserverlibrary.d.ts + sed -i -e 's/const version\(: string\)\{0,1\} = `${versionMajorMinor}.0-.*`/const version = `${versionMajorMinor}.0-${{ github.event.client_payload.core_tag || 'dev' }}`/g' src/compiler/corePublic.ts + npm ci + npx hereby LKG + npm test + git diff + git add package.json + git add src/compiler/corePublic.ts + git add tests/baselines/reference/api/typescript.d.ts + git add tests/baselines/reference/api/tsserverlibrary.d.ts + git add --force ./lib + git config user.email "typescriptbot@microsoft.com" + git config user.name "TypeScript Bot" + git commit -m 'Bump version to ${{ github.event.client_payload.package_version }} and LKG' + git push --set-upstream origin ${{ github.event.client_payload.branch_name }} diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 8692ed2d75e83..20a5d2c590354 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -2,7 +2,7 @@ name: Publish Nightly on: schedule: - - cron: '0 7 * * *' + - cron: '0 7 * * *' # enable users to manually trigger with workflow_dispatch workflow_dispatch: {} repository_dispatch: @@ -23,24 +23,24 @@ jobs: if: github.repository == 'microsoft/TypeScript' steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - # Use NODE_AUTH_TOKEN environment variable to authenticate to this registry. - registry-url: https://registry.npmjs.org/ - - run: | - npm --version - # corepack enable npm - npm install -g $(jq -r '.packageManager' < package.json) - npm --version - - name: Setup and publish nightly - run: | - npm whoami - npm ci - npx hereby configure-nightly - npx hereby LKG - npx hereby runtests-parallel - npx hereby clean - npm publish --tag next - env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + # Use NODE_AUTH_TOKEN environment variable to authenticate to this registry. + registry-url: https://registry.npmjs.org/ + - run: | + npm --version + # corepack enable npm + npm install -g $(jq -r '.packageManager' < package.json) + npm --version + - name: Setup and publish nightly + run: | + npm whoami + npm ci + npx hereby configure-nightly + npx hereby LKG + npx hereby runtests-parallel + npx hereby clean + npm publish --tag next + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/release-branch-artifact.yaml b/.github/workflows/release-branch-artifact.yaml index e0b95bdf00660..7a44017374b7b 100644 --- a/.github/workflows/release-branch-artifact.yaml +++ b/.github/workflows/release-branch-artifact.yaml @@ -19,29 +19,29 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - - run: | - npm --version - # corepack enable npm - npm install -g $(jq -r '.packageManager' < package.json) - npm --version - - name: npm install and test - run: | - npm ci - npm test - - name: Adding playwright - run: npm install --no-save --no-package-lock playwright - - name: Validate the browser can import TypeScript - run: npx hereby test-browser-integration - - name: LKG, clean, and pack - run: | - npx hereby LKG - npx hereby clean - npm pack ./ - mv typescript-*.tgz typescript.tgz - - name: Upload built tarfile - uses: actions/upload-artifact@v3 - with: - name: tgz - path: typescript.tgz + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - run: | + npm --version + # corepack enable npm + npm install -g $(jq -r '.packageManager' < package.json) + npm --version + - name: npm install and test + run: | + npm ci + npm test + - name: Adding playwright + run: npm install --no-save --no-package-lock playwright + - name: Validate the browser can import TypeScript + run: npx hereby test-browser-integration + - name: LKG, clean, and pack + run: | + npx hereby LKG + npx hereby clean + npm pack ./ + mv typescript-*.tgz typescript.tgz + - name: Upload built tarfile + uses: actions/upload-artifact@v3 + with: + name: tgz + path: typescript.tgz diff --git a/.github/workflows/rich-navigation.yml b/.github/workflows/rich-navigation.yml index c5c59e0cdf9f6..83bf30ec0833f 100644 --- a/.github/workflows/rich-navigation.yml +++ b/.github/workflows/rich-navigation.yml @@ -1,4 +1,4 @@ -name: "Rich Navigation Indexing" +name: 'Rich Navigation Indexing' on: workflow_dispatch: push: @@ -31,7 +31,7 @@ jobs: - uses: actions/setup-node@v3 - name: Install dependencies - run: npm ci + run: npm ci - uses: microsoft/RichCodeNavIndexer@v0.1 with: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 0e7e361a188d3..dcfc01ed5f719 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -12,7 +12,7 @@ on: schedule: - cron: '19 15 * * 4' push: - branches: [ "main" ] + branches: ['main'] # Declare default permissions as read only. permissions: read-all @@ -28,12 +28,12 @@ jobs: id-token: write steps: - - name: "Checkout code" + - name: 'Checkout code' uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 with: persist-credentials: false - - name: "Run analysis" + - name: 'Run analysis' uses: ossf/scorecard-action@80e868c13c90f172d68d1f4501dee99e2479f7af # v2.1.3 with: results_file: results.sarif @@ -46,7 +46,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - - name: "Upload artifact" + - name: 'Upload artifact' uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 with: name: SARIF file @@ -54,7 +54,7 @@ jobs: retention-days: 5 # Upload the results to GitHub's code scanning dashboard. - - name: "Upload to code-scanning" + - name: 'Upload to code-scanning' uses: github/codeql-action/upload-sarif@807578363a7869ca324a79039e6db9c843e0e100 # v2.1.27 with: sarif_file: results.sarif diff --git a/.github/workflows/set-version.yaml b/.github/workflows/set-version.yaml index ec04aebfefe0b..8e5ce9399d3e0 100644 --- a/.github/workflows/set-version.yaml +++ b/.github/workflows/set-version.yaml @@ -21,38 +21,38 @@ jobs: contents: write steps: - - uses: actions/setup-node@v3 - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.client_payload.branch_name }} - - run: | - npm --version - # corepack enable npm - npm install -g $(jq -r '.packageManager' < package.json) - npm --version - # notably, this is essentially the same script as `new-release-branch.yaml` (with fewer inputs), but it assumes the branch already exists - # do note that executing the transform below will prevent the `configurePrerelease` script from running on the source, as it makes the - # `version` identifier no longer match the regex it uses - # required client_payload members: - # branch_name - the target branch - # package_version - the full version string (eg, `3.9.1-rc` or `3.9.2`) - # core_major_minor - the major.minor pair associated with the desired package_version (eg, `3.9` for `3.9.3`) - - run: | - sed -i -e 's/"version": ".*"/"version": "${{ github.event.client_payload.package_version }}"/g' package.json - sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' src/compiler/corePublic.ts - sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/typescript.d.ts - sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/tsserverlibrary.d.ts - sed -i -e 's/const version\(: string\)\{0,1\} = .*;/const version = "${{ github.event.client_payload.package_version }}" as string;/g' src/compiler/corePublic.ts - npm ci - npx hereby LKG - npm test - git diff - git add package.json - git add src/compiler/corePublic.ts - git add tests/baselines/reference/api/typescript.d.ts - git add tests/baselines/reference/api/tsserverlibrary.d.ts - git add --force ./lib - git config user.email "typescriptbot@microsoft.com" - git config user.name "TypeScript Bot" - git commit -m 'Bump version to ${{ github.event.client_payload.package_version }} and LKG' - git push + - uses: actions/setup-node@v3 + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.client_payload.branch_name }} + - run: | + npm --version + # corepack enable npm + npm install -g $(jq -r '.packageManager' < package.json) + npm --version + # notably, this is essentially the same script as `new-release-branch.yaml` (with fewer inputs), but it assumes the branch already exists + # do note that executing the transform below will prevent the `configurePrerelease` script from running on the source, as it makes the + # `version` identifier no longer match the regex it uses + # required client_payload members: + # branch_name - the target branch + # package_version - the full version string (eg, `3.9.1-rc` or `3.9.2`) + # core_major_minor - the major.minor pair associated with the desired package_version (eg, `3.9` for `3.9.3`) + - run: | + sed -i -e 's/"version": ".*"/"version": "${{ github.event.client_payload.package_version }}"/g' package.json + sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' src/compiler/corePublic.ts + sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/typescript.d.ts + sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/tsserverlibrary.d.ts + sed -i -e 's/const version\(: string\)\{0,1\} = .*;/const version = "${{ github.event.client_payload.package_version }}" as string;/g' src/compiler/corePublic.ts + npm ci + npx hereby LKG + npm test + git diff + git add package.json + git add src/compiler/corePublic.ts + git add tests/baselines/reference/api/typescript.d.ts + git add tests/baselines/reference/api/tsserverlibrary.d.ts + git add --force ./lib + git config user.email "typescriptbot@microsoft.com" + git config user.name "TypeScript Bot" + git commit -m 'Bump version to ${{ github.event.client_payload.package_version }} and LKG' + git push diff --git a/.github/workflows/sync-branch.yaml b/.github/workflows/sync-branch.yaml index cbe0a3ca0834b..68dc6b286c451 100644 --- a/.github/workflows/sync-branch.yaml +++ b/.github/workflows/sync-branch.yaml @@ -26,19 +26,19 @@ jobs: contents: write steps: - - uses: actions/setup-node@v3 - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.inputs.branch_name || github.event.client_payload.branch_name }} - fetch-depth: 0 - # This does a test post-merge and only pushes the result if the test succeeds - # required client_payload members: - # branch_name - the target branch - - run: | - git config user.email "typescriptbot@microsoft.com" - git config user.name "TypeScript Bot" - git fetch origin main - git merge origin/main --no-ff - npm ci - npm test - git push + - uses: actions/setup-node@v3 + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.inputs.branch_name || github.event.client_payload.branch_name }} + fetch-depth: 0 + # This does a test post-merge and only pushes the result if the test succeeds + # required client_payload members: + # branch_name - the target branch + - run: | + git config user.email "typescriptbot@microsoft.com" + git config user.name "TypeScript Bot" + git fetch origin main + git merge origin/main --no-ff + npm ci + npm test + git push diff --git a/.github/workflows/sync-wiki.yml b/.github/workflows/sync-wiki.yml index 38b20f96657b5..ee20ba8d4c780 100644 --- a/.github/workflows/sync-wiki.yml +++ b/.github/workflows/sync-wiki.yml @@ -15,16 +15,16 @@ jobs: sync: runs-on: ubuntu-latest steps: - - name: Get repo name - run: R=${GITHUB_REPOSITORY%?wiki}; echo "BASENAME=${R##*/}" >> $GITHUB_ENV - - name: Checkout ${{ env.BASENAME }}-wiki - uses: actions/checkout@v3 - with: - repository: "${{ GITHUB.repository_owner }}/${{ env.BASENAME }}-wiki" - token: ${{ secrets.TS_BOT_GITHUB_TOKEN }} - fetch-depth: 0 - - name: Run sync - run: ./.github/workflows/sync - env: - PUSHER: typescript-bot - AUTH: ${{ secrets.TS_BOT_GITHUB_TOKEN }} + - name: Get repo name + run: R=${GITHUB_REPOSITORY%?wiki}; echo "BASENAME=${R##*/}" >> $GITHUB_ENV + - name: Checkout ${{ env.BASENAME }}-wiki + uses: actions/checkout@v3 + with: + repository: '${{ GITHUB.repository_owner }}/${{ env.BASENAME }}-wiki' + token: ${{ secrets.TS_BOT_GITHUB_TOKEN }} + fetch-depth: 0 + - name: Run sync + run: ./.github/workflows/sync + env: + PUSHER: typescript-bot + AUTH: ${{ secrets.TS_BOT_GITHUB_TOKEN }} diff --git a/.github/workflows/twoslash-repros.yaml b/.github/workflows/twoslash-repros.yaml index c4bdbf38258fe..60aba0dc60b80 100644 --- a/.github/workflows/twoslash-repros.yaml +++ b/.github/workflows/twoslash-repros.yaml @@ -5,7 +5,7 @@ on: branches: - orta-twoslash-repros schedule: - - cron: '0 8 * * *' + - cron: '0 8 * * *' repository_dispatch: types: run-twoslash-repros workflow_dispatch: @@ -33,15 +33,15 @@ jobs: if: ${{ github.repository == 'microsoft/TypeScript' }} runs-on: ubuntu-latest steps: - - if: ${{ github.event.inputs.bisect }} - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - if: ${{ !github.event.inputs.bisect }} - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - - uses: microsoft/TypeScript-Twoslash-Repro-Action@master - with: - github-token: ${{ secrets.TS_BOT_GITHUB_TOKEN }} - issue: ${{ github.event.inputs.issue }} - bisect: ${{ github.event.inputs.bisect }} + - if: ${{ github.event.inputs.bisect }} + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - if: ${{ !github.event.inputs.bisect }} + uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - uses: microsoft/TypeScript-Twoslash-Repro-Action@master + with: + github-token: ${{ secrets.TS_BOT_GITHUB_TOKEN }} + issue: ${{ github.event.inputs.issue }} + bisect: ${{ github.event.inputs.bisect }} diff --git a/.github/workflows/update-lkg.yml b/.github/workflows/update-lkg.yml index 3caf672ccc9bb..c335f5a8d159f 100644 --- a/.github/workflows/update-lkg.yml +++ b/.github/workflows/update-lkg.yml @@ -20,17 +20,17 @@ jobs: contents: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 - - name: Configure Git and Update LKG - run: | - git config user.email "typescriptbot@microsoft.com" - git config user.name "TypeScript Bot" - npm ci - npx hereby LKG - npm test - git diff - git add --force ./lib - git commit -m "Update LKG" - git push + - name: Configure Git and Update LKG + run: | + git config user.email "typescriptbot@microsoft.com" + git config user.name "TypeScript Bot" + npm ci + npx hereby LKG + npm test + git diff + git add --force ./lib + git commit -m "Update LKG" + git push diff --git a/.github/workflows/update-package-lock.yaml b/.github/workflows/update-package-lock.yaml index f3b2c35e4e173..da5796e9b0dd8 100644 --- a/.github/workflows/update-package-lock.yaml +++ b/.github/workflows/update-package-lock.yaml @@ -1,11 +1,11 @@ name: Update package-lock.json on: - schedule: - # This is probably 6am UTC, which is 10pm PST or 11pm PDT - # Alternatively, 6am local is also fine - - cron: '0 6 * * *' - workflow_dispatch: {} + schedule: + # This is probably 6am UTC, which is 10pm PST or 11pm PDT + # Alternatively, 6am local is also fine + - cron: '0 6 * * *' + workflow_dispatch: {} permissions: contents: read @@ -25,31 +25,31 @@ jobs: contents: write steps: - - uses: actions/checkout@v3 - with: - token: ${{ secrets.TS_BOT_GITHUB_TOKEN }} - - uses: actions/setup-node@v3 - with: - node-version: 16 - - run: | - npm --version - # corepack enable npm - npm install -g $(jq -r '.packageManager' < package.json) - npm --version - - - name: Update package-lock.json and push - run: | - rm package-lock.json - npm install - - if git diff --exit-code --name-only package-lock.json; then - echo "No change." - else - npm test - npx hereby lkg - git config user.email "typescriptbot@microsoft.com" - git config user.name "TypeScript Bot" - git add -f package-lock.json - git commit -m "Update package-lock.json" - git push - fi + - uses: actions/checkout@v3 + with: + token: ${{ secrets.TS_BOT_GITHUB_TOKEN }} + - uses: actions/setup-node@v3 + with: + node-version: 16 + - run: | + npm --version + # corepack enable npm + npm install -g $(jq -r '.packageManager' < package.json) + npm --version + + - name: Update package-lock.json and push + run: | + rm package-lock.json + npm install + + if git diff --exit-code --name-only package-lock.json; then + echo "No change." + else + npm test + npx hereby lkg + git config user.email "typescriptbot@microsoft.com" + git config user.name "TypeScript Bot" + git add -f package-lock.json + git commit -m "Update package-lock.json" + git push + fi diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c3ea200176d3c..beff1465a0127 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,8 @@ { "recommendations": [ "dbaeumer.vscode-eslint", - "rbuckton.tsserver-live-reload" + "rbuckton.tsserver-live-reload", + "dprint.dprint" ], "unwantedRecommendations": [ diff --git a/.vscode/settings.template.json b/.vscode/settings.template.json index 7d6691df5aa8a..71b1986cf1a46 100644 --- a/.vscode/settings.template.json +++ b/.vscode/settings.template.json @@ -4,6 +4,11 @@ // To use the locally built compiler, after 'npm run build': // "typescript.tsdk": "built/local" + "[typescript][javascript][yaml]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "dprint.dprint" + }, + // To ignore commits listed in .git-blame-ignore-revs in GitLens: "gitlens.advanced.blame.customArguments": [ "--ignore-revs-file", diff --git a/Herebyfile.mjs b/Herebyfile.mjs index 38269cbcc3929..8ca1f0862df5d 100644 --- a/Herebyfile.mjs +++ b/Herebyfile.mjs @@ -1,21 +1,45 @@ // @ts-check -import { CancelToken } from "@esfx/canceltoken"; +import { + CancelToken, +} from "@esfx/canceltoken"; import chalk from "chalk"; import chokidar from "chokidar"; import del from "del"; import esbuild from "esbuild"; -import { EventEmitter } from "events"; +import { + EventEmitter, +} from "events"; import fs from "fs"; import _glob from "glob"; -import { task } from "hereby"; +import { + task, +} from "hereby"; import path from "path"; import util from "util"; -import { localizationDirectories } from "./scripts/build/localization.mjs"; +import { + localizationDirectories, +} from "./scripts/build/localization.mjs"; import cmdLineOptions from "./scripts/build/options.mjs"; -import { buildProject, cleanProject, watchProject } from "./scripts/build/projects.mjs"; -import { localBaseline, refBaseline, runConsoleTests } from "./scripts/build/tests.mjs"; -import { Debouncer, Deferred, exec, getDiffTool, memoize, needsUpdate, readJson } from "./scripts/build/utils.mjs"; +import { + buildProject, + cleanProject, + watchProject, +} from "./scripts/build/projects.mjs"; +import { + localBaseline, + refBaseline, + runConsoleTests, +} from "./scripts/build/tests.mjs"; +import { + Debouncer, + Deferred, + exec, + getDiffTool, + memoize, + needsUpdate, + readJson, +} from "./scripts/build/utils.mjs"; const glob = util.promisify(_glob); @@ -28,11 +52,10 @@ const copyright = memoize(async () => { return contents.replace(/\r\n/g, "\n"); }); - export const buildScripts = task({ name: "scripts", description: "Builds files in the 'scripts' folder.", - run: () => buildProject("scripts") + run: () => buildProject("scripts"), }); const libs = memoize(() => { @@ -48,7 +71,6 @@ const libs = memoize(() => { return libs; }); - export const generateLibs = task({ name: "lib", description: "Builds the library targets", @@ -67,7 +89,6 @@ export const generateLibs = task({ }, }); - const diagnosticInformationMapTs = "src/compiler/diagnosticInformationMap.generated.ts"; const diagnosticMessagesJson = "src/compiler/diagnosticMessages.json"; const diagnosticMessagesGeneratedJson = "src/compiler/diagnosticMessages.generated.json"; @@ -77,7 +98,7 @@ export const generateDiagnostics = task({ description: "Generates a diagnostic file in TypeScript based on an input JSON file", run: async () => { await exec(process.execPath, ["scripts/processDiagnosticMessages.mjs", diagnosticMessagesJson]); - } + }, }); const cleanDiagnostics = task({ @@ -87,7 +108,6 @@ const cleanDiagnostics = task({ run: () => del([diagnosticInformationMapTs, diagnosticMessagesGeneratedJson]), }); - // Localize diagnostics /** * .lcg file is what localization team uses to know what messages to localize. @@ -111,9 +131,14 @@ const localize = task({ dependencies: [generateDiagnostics], run: async () => { if (needsUpdate(diagnosticMessagesGeneratedJson, generatedLCGFile)) { - await exec(process.execPath, ["scripts/generateLocalizedDiagnosticMessages.mjs", "src/loc/lcl", "built/local", diagnosticMessagesGeneratedJson], { ignoreExitCode: true }); + await exec(process.execPath, [ + "scripts/generateLocalizedDiagnosticMessages.mjs", + "src/loc/lcl", + "built/local", + diagnosticMessagesGeneratedJson, + ], { ignoreExitCode: true }); } - } + }, }); export const buildSrc = task({ @@ -151,7 +176,6 @@ async function runDtsBundler(entrypoint, output) { ]); } - /** * @param {string} entrypoint * @param {string} outfile @@ -203,14 +227,14 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { options.plugins = [ { name: "fix-require", - setup: (build) => { + setup: build => { build.onEnd(async () => { let contents = await fs.promises.readFile(outfile, "utf-8"); contents = contents.replace(/\$\$require/g, " require"); await fs.promises.writeFile(outfile, contents); }); }, - } + }, ]; } @@ -226,7 +250,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { const onRebuild = taskOptions.onWatchRebuild; options.plugins = (options.plugins?.slice(0) ?? []).concat([{ name: "watch", - setup: (build) => { + setup: build => { let firstBuild = true; build.onEnd(() => { if (firstBuild) { @@ -236,7 +260,7 @@ function createBundler(entrypoint, outfile, taskOptions = {}) { onRebuild(); } }); - } + }, }]); } @@ -293,7 +317,10 @@ function entrypointBuildTask(options) { const outDir = path.dirname(options.output); await fs.promises.mkdir(outDir, { recursive: true }); const moduleSpecifier = path.relative(outDir, options.builtEntrypoint); - await fs.promises.writeFile(options.output, `module.exports = require("./${moduleSpecifier.replace(/[\\/]/g, "/")}")`); + await fs.promises.writeFile( + options.output, + `module.exports = require("./${moduleSpecifier.replace(/[\\/]/g, "/")}")`, + ); }, }); @@ -317,13 +344,19 @@ function entrypointBuildTask(options) { const watch = task({ name: `watch-${options.name}`, hiddenFromTaskList: true, // This is best effort. - dependencies: (options.buildDeps ?? []).concat(options.mainDeps ?? []).concat(cmdLineOptions.bundle ? [] : [shim]), + dependencies: (options.buildDeps ?? []).concat(options.mainDeps ?? []).concat( + cmdLineOptions.bundle ? [] : [shim], + ), run: () => { // These watch functions return promises that resolve once watch mode has started, // allowing them to operate as regular tasks, while creating unresolved promises // in the background that keep the process running after all tasks have exited. if (!printedWatchWarning) { - console.error(chalk.yellowBright("Warning: watch mode is incomplete and may not work as expected. Use at your own risk.")); + console.error( + chalk.yellowBright( + "Warning: watch mode is incomplete and may not work as expected. Use at your own risk.", + ), + ); printedWatchWarning = true; } @@ -331,13 +364,12 @@ function entrypointBuildTask(options) { return watchProject(options.project); } return bundler.watch(); - } + }, }); return { build, bundle, shim, main, watch }; } - const { main: tsc, watch: watchTsc } = entrypointBuildTask({ name: "tsc", description: "Builds the command-line compiler", @@ -350,7 +382,6 @@ const { main: tsc, watch: watchTsc } = entrypointBuildTask({ }); export { tsc, watchTsc }; - const { main: services, build: buildServices, watch: watchServices } = entrypointBuildTask({ name: "services", description: "Builds the typescript.js library", @@ -369,13 +400,17 @@ export const dtsServices = task({ description: "Bundles typescript.d.ts", dependencies: [buildServices], run: async () => { - if (needsUpdate("./built/local/typescript/tsconfig.tsbuildinfo", ["./built/local/typescript.d.ts", "./built/local/typescript.internal.d.ts"])) { + if ( + needsUpdate("./built/local/typescript/tsconfig.tsbuildinfo", [ + "./built/local/typescript.d.ts", + "./built/local/typescript.internal.d.ts", + ]) + ) { await runDtsBundler("./built/local/typescript/typescript.d.ts", "./built/local/typescript.d.ts"); } }, }); - const { main: tsserver, watch: watchTsserver } = entrypointBuildTask({ name: "tsserver", description: "Builds the language server", @@ -388,7 +423,6 @@ const { main: tsserver, watch: watchTsserver } = entrypointBuildTask({ }); export { tsserver, watchTsserver }; - export const min = task({ name: "min", description: "Builds only tsc and tsserver", @@ -402,8 +436,6 @@ export const watchMin = task({ dependencies: [watchTsc, watchTsserver], }); - - // This is technically not enough to make tsserverlibrary loadable in the // browser, but it's unlikely that anyone has actually been doing that. const lsslJs = ` @@ -438,7 +470,7 @@ const lssl = task({ dependencies: [services], run: async () => { await fs.promises.writeFile("./built/local/tsserverlibrary.js", await fileContentsWithCopyright(lsslJs)); - } + }, }); export const dtsLssl = task({ @@ -447,8 +479,11 @@ export const dtsLssl = task({ dependencies: [dtsServices], run: async () => { await fs.promises.writeFile("./built/local/tsserverlibrary.d.ts", await fileContentsWithCopyright(lsslDts)); - await fs.promises.writeFile("./built/local/tsserverlibrary.internal.d.ts", await fileContentsWithCopyright(lsslDtsInternal)); - } + await fs.promises.writeFile( + "./built/local/tsserverlibrary.internal.d.ts", + await fileContentsWithCopyright(lsslDtsInternal), + ); + }, }); export const dts = task({ @@ -456,7 +491,6 @@ export const dts = task({ dependencies: [dtsServices, dtsLssl], }); - const testRunner = "./built/local/run.js"; const watchTestsEmitter = new EventEmitter(); const { main: tests, watch: watchTests } = entrypointBuildTask({ @@ -473,12 +507,11 @@ const { main: tests, watch: watchTests } = entrypointBuildTask({ treeShaking: false, onWatchRebuild() { watchTestsEmitter.emit("rebuild"); - } + }, }, }); export { tests, watchTests }; - export const runEslintRulesTests = task({ name: "run-eslint-rules-tests", description: "Runs the eslint rule tests", @@ -494,8 +527,10 @@ export const lint = task({ const args = [ "node_modules/eslint/bin/eslint", "--cache", - "--cache-location", `${folder}/.eslintcache`, - "--format", formatter, + "--cache-location", + `${folder}/.eslintcache`, + "--format", + formatter, ]; if (cmdLineOptions.fix) { @@ -506,7 +541,19 @@ export const lint = task({ console.log(`Linting: ${args.join(" ")}`); return exec(process.execPath, args); - } + }, +}); + +export const format = task({ + name: "format", + description: "Formats the codebase.", + run: () => exec(process.execPath, ["node_modules/dprint/bin.js", "fmt"]), +}); + +export const checkFormat = task({ + name: "check-format", + description: "Checks that the codebase is formatted.", + run: () => exec(process.execPath, ["node_modules/dprint/bin.js", "check"], { ignoreStdout: true }), }); const { main: cancellationToken, watch: watchCancellationToken } = entrypointBuildTask({ @@ -543,10 +590,9 @@ export const generateTypesMap = task({ const contents = await fs.promises.readFile(source, "utf-8"); JSON.parse(contents); // Validates that the JSON parses. await fs.promises.writeFile(target, contents); - } + }, }); - // Drop a copy of diagnosticMessages.generated.json into the built/local folder. This allows // it to be synced to the Azure DevOps repo, so that it can get picked up by the build // pipeline that generates the localization artifacts that are then fed into the translation process. @@ -558,10 +604,9 @@ const copyBuiltLocalDiagnosticMessages = task({ const contents = await fs.promises.readFile(diagnosticMessagesGeneratedJson, "utf-8"); JSON.parse(contents); // Validates that the JSON parses. await fs.promises.writeFile(builtLocalDiagnosticMessagesGeneratedJson, contents); - } + }, }); - export const otherOutputs = task({ name: "other-outputs", description: "Builds miscelaneous scripts and documents distributed with the LKG", @@ -572,7 +617,13 @@ export const watchOtherOutputs = task({ name: "watch-other-outputs", description: "Builds miscelaneous scripts and documents distributed with the LKG", hiddenFromTaskList: true, - dependencies: [watchCancellationToken, watchTypingsInstaller, watchWatchGuard, generateTypesMap, copyBuiltLocalDiagnosticMessages], + dependencies: [ + watchCancellationToken, + watchTypingsInstaller, + watchWatchGuard, + generateTypesMap, + copyBuiltLocalDiagnosticMessages, + ], }); export const local = task({ @@ -626,7 +677,7 @@ export const runTestsAndWatch = task({ let watching = true; let running = true; let lastTestChangeTimeMs = Date.now(); - let testsChangedDeferred = /** @type {Deferred} */(new Deferred()); + let testsChangedDeferred = /** @type {Deferred} */ (new Deferred()); let testsChangedCancelSource = CancelToken.source(); const testsChangedDebouncer = new Debouncer(1_000, endRunTests); @@ -636,7 +687,7 @@ export const runTestsAndWatch = task({ "tests/projects/**/*.*", ], { ignorePermissionErrors: true, - alwaysStat: true + alwaysStat: true, }); process.on("SIGINT", endWatchMode); @@ -650,7 +701,10 @@ export const runTestsAndWatch = task({ if (!token.signaled) { running = true; try { - await runConsoleTests(testRunner, "mocha-fivemat-progress-reporter", /*runInParallel*/ false, { token, watching: true }); + await runConsoleTests(testRunner, "mocha-fivemat-progress-reporter", /*runInParallel*/ false, { + token, + watching: true, + }); } catch { // ignore @@ -709,7 +763,7 @@ export const runTestsAndWatch = task({ function endRunTests() { lastTestChangeTimeMs = Date.now(); testsChangedDeferred.resolve(); - testsChangedDeferred = /** @type {Deferred} */(new Deferred()); + testsChangedDeferred = /** @type {Deferred} */ (new Deferred()); } function endWatchMode() { @@ -805,12 +859,14 @@ export const updateSublime = task({ dependencies: [tsserver], run: async () => { for (const file of ["built/local/tsserver.js", "built/local/tsserver.js.map"]) { - await fs.promises.copyFile(file, path.resolve("../TypeScript-Sublime-Plugin/tsserver/", path.basename(file))); + await fs.promises.copyFile( + file, + path.resolve("../TypeScript-Sublime-Plugin/tsserver/", path.basename(file)), + ); } - } + }, }); - export const produceLKG = task({ name: "LKG", description: "Makes a new LKG out of the built js files", @@ -835,11 +891,14 @@ export const produceLKG = task({ .concat(localizationTargets) .filter(f => !fs.existsSync(f)); if (missingFiles.length > 0) { - throw new Error("Cannot replace the LKG unless all built targets are present in directory 'built/local/'. The following files are missing:\n" + missingFiles.join("\n")); + throw new Error( + "Cannot replace the LKG unless all built targets are present in directory 'built/local/'. The following files are missing:\n" + + missingFiles.join("\n"), + ); } await exec(process.execPath, ["scripts/produceLKG.mjs"]); - } + }, }); export const lkg = task({ @@ -863,19 +922,37 @@ export const clean = task({ export const configureNightly = task({ name: "configure-nightly", description: "Runs scripts/configurePrerelease.mjs to prepare a build for nightly publishing", - run: () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "dev", "package.json", "src/compiler/corePublic.ts"]), + run: () => + exec(process.execPath, [ + "scripts/configurePrerelease.mjs", + "dev", + "package.json", + "src/compiler/corePublic.ts", + ]), }); export const configureInsiders = task({ name: "configure-insiders", description: "Runs scripts/configurePrerelease.mjs to prepare a build for insiders publishing", - run: () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "insiders", "package.json", "src/compiler/corePublic.ts"]), + run: () => + exec(process.execPath, [ + "scripts/configurePrerelease.mjs", + "insiders", + "package.json", + "src/compiler/corePublic.ts", + ]), }); export const configureExperimental = task({ name: "configure-experimental", description: "Runs scripts/configurePrerelease.mjs to prepare a build for experimental publishing", - run: () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "experimental", "package.json", "src/compiler/corePublic.ts"]), + run: () => + exec(process.execPath, [ + "scripts/configurePrerelease.mjs", + "experimental", + "package.json", + "src/compiler/corePublic.ts", + ]), }); export const help = task({ diff --git a/package-lock.json b/package-lock.json index c661d8d85002d..183a8a5cfe690 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "chokidar": "^3.5.3", "del": "^6.1.1", "diff": "^5.1.0", + "dprint": "^0.40.2", "esbuild": "^0.19.0", "eslint": "^8.22.0", "eslint-formatter-autolinkable-stylish": "^1.2.0", @@ -75,6 +76,84 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@dprint/darwin-arm64": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/darwin-arm64/-/darwin-arm64-0.40.2.tgz", + "integrity": "sha512-qharMFhxpNq9brgvHLbqzzAgVgPWSHLfzNLwWWhKcGOUUDUIilfAo3SlvOz6w4nQiIifLpYZOvZqK7Lpf9mSSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@dprint/darwin-x64": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/darwin-x64/-/darwin-x64-0.40.2.tgz", + "integrity": "sha512-FPDdOTVr1JfqtLBTCvqlihWslTy3LBUoi3H1gaqIazCKMj2dB9voFWkBiMT+REMHDrlVsoSpFAfsliNr/y7HPA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@dprint/linux-arm64-glibc": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.40.2.tgz", + "integrity": "sha512-GmUWfKwEwXA+onvewX9hEJSMcd9V184+uRbEhI5tG28tBP9+IjQhrY7jCjxPvaZA+EvzNPnAy5D1wbJdlNLBNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@dprint/linux-x64-glibc": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.40.2.tgz", + "integrity": "sha512-vMHAHdsOY+2thieSWbIrIioDfPgvipwUgd0MZUWOqycTrXU6kLyi2B+5J/2Jc+QO3CiLIbumQd2FH/0vB1eWqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@dprint/linux-x64-musl": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/linux-x64-musl/-/linux-x64-musl-0.40.2.tgz", + "integrity": "sha512-nFSbDWd9ORyOhJ7a+RmE39WbuPoQ3OQutIgfAmfikiu/wENzEwxxv4QJ7aFnBaoZb0wuVEEpXShr8vY4p0exkg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@dprint/win32-x64": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/win32-x64/-/win32-x64-0.40.2.tgz", + "integrity": "sha512-qF4VCQzFTZYD61lbQqXLU/IwUTbLK22CancO+uVtXmZRoKU9GaVjcBhMUB7URxsa8rvxWHhHT6ldillI/aOWCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@esbuild/android-arm": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", @@ -1700,6 +1779,24 @@ "node": ">=6.0.0" } }, + "node_modules/dprint": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/dprint/-/dprint-0.40.2.tgz", + "integrity": "sha512-3LdyUV0itEW59UPtsRA2StOWOu8FyOW+BgvJpH/tACRHKi0z5gaQnvSxdS3mbG7dgtEhdRnGg6JoiQyGib6NTg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "dprint": "bin.js" + }, + "optionalDependencies": { + "@dprint/darwin-arm64": "0.40.2", + "@dprint/darwin-x64": "0.40.2", + "@dprint/linux-arm64-glibc": "0.40.2", + "@dprint/linux-x64-glibc": "0.40.2", + "@dprint/linux-x64-musl": "0.40.2", + "@dprint/win32-x64": "0.40.2" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -3905,6 +4002,48 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@dprint/darwin-arm64": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/darwin-arm64/-/darwin-arm64-0.40.2.tgz", + "integrity": "sha512-qharMFhxpNq9brgvHLbqzzAgVgPWSHLfzNLwWWhKcGOUUDUIilfAo3SlvOz6w4nQiIifLpYZOvZqK7Lpf9mSSw==", + "dev": true, + "optional": true + }, + "@dprint/darwin-x64": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/darwin-x64/-/darwin-x64-0.40.2.tgz", + "integrity": "sha512-FPDdOTVr1JfqtLBTCvqlihWslTy3LBUoi3H1gaqIazCKMj2dB9voFWkBiMT+REMHDrlVsoSpFAfsliNr/y7HPA==", + "dev": true, + "optional": true + }, + "@dprint/linux-arm64-glibc": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/linux-arm64-glibc/-/linux-arm64-glibc-0.40.2.tgz", + "integrity": "sha512-GmUWfKwEwXA+onvewX9hEJSMcd9V184+uRbEhI5tG28tBP9+IjQhrY7jCjxPvaZA+EvzNPnAy5D1wbJdlNLBNA==", + "dev": true, + "optional": true + }, + "@dprint/linux-x64-glibc": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/linux-x64-glibc/-/linux-x64-glibc-0.40.2.tgz", + "integrity": "sha512-vMHAHdsOY+2thieSWbIrIioDfPgvipwUgd0MZUWOqycTrXU6kLyi2B+5J/2Jc+QO3CiLIbumQd2FH/0vB1eWqA==", + "dev": true, + "optional": true + }, + "@dprint/linux-x64-musl": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/linux-x64-musl/-/linux-x64-musl-0.40.2.tgz", + "integrity": "sha512-nFSbDWd9ORyOhJ7a+RmE39WbuPoQ3OQutIgfAmfikiu/wENzEwxxv4QJ7aFnBaoZb0wuVEEpXShr8vY4p0exkg==", + "dev": true, + "optional": true + }, + "@dprint/win32-x64": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/@dprint/win32-x64/-/win32-x64-0.40.2.tgz", + "integrity": "sha512-qF4VCQzFTZYD61lbQqXLU/IwUTbLK22CancO+uVtXmZRoKU9GaVjcBhMUB7URxsa8rvxWHhHT6ldillI/aOWCg==", + "dev": true, + "optional": true + }, "@esbuild/android-arm": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", @@ -5008,6 +5147,20 @@ "esutils": "^2.0.2" } }, + "dprint": { + "version": "0.40.2", + "resolved": "https://registry.npmjs.org/dprint/-/dprint-0.40.2.tgz", + "integrity": "sha512-3LdyUV0itEW59UPtsRA2StOWOu8FyOW+BgvJpH/tACRHKi0z5gaQnvSxdS3mbG7dgtEhdRnGg6JoiQyGib6NTg==", + "dev": true, + "requires": { + "@dprint/darwin-arm64": "0.40.2", + "@dprint/darwin-x64": "0.40.2", + "@dprint/linux-arm64-glibc": "0.40.2", + "@dprint/linux-x64-glibc": "0.40.2", + "@dprint/linux-x64-musl": "0.40.2", + "@dprint/win32-x64": "0.40.2" + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", diff --git a/package.json b/package.json index cc39f6cba399e..ea2323bac3b81 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "chokidar": "^3.5.3", "del": "^6.1.1", "diff": "^5.1.0", + "dprint": "^0.40.2", "esbuild": "^0.19.0", "eslint": "^8.22.0", "eslint-formatter-autolinkable-stylish": "^1.2.0", @@ -96,6 +97,7 @@ "clean": "hereby clean", "gulp": "hereby", "lint": "hereby lint", + "format": "dprint fmt", "setup-hooks": "node scripts/link-hooks.mjs" }, "browser": { diff --git a/scripts/browserIntegrationTest.mjs b/scripts/browserIntegrationTest.mjs index fd06edc654ee1..bb1007743b4a6 100644 --- a/scripts/browserIntegrationTest.mjs +++ b/scripts/browserIntegrationTest.mjs @@ -1,6 +1,10 @@ import chalk from "chalk"; -import { readFileSync } from "fs"; -import { join } from "path"; +import { + readFileSync, +} from "fs"; +import { + join, +} from "path"; let playwright; try { diff --git a/scripts/build/findUpDir.mjs b/scripts/build/findUpDir.mjs index 246e11b8e1be9..44bbc658beda5 100644 --- a/scripts/build/findUpDir.mjs +++ b/scripts/build/findUpDir.mjs @@ -1,5 +1,11 @@ -import { existsSync } from "fs"; -import { dirname, join, resolve } from "path"; +import { + existsSync, +} from "fs"; +import { + dirname, + join, + resolve, +} from "path"; import url from "url"; const __filename = url.fileURLToPath(new URL(import.meta.url)); diff --git a/scripts/build/localization.mjs b/scripts/build/localization.mjs index 142bd14c1a073..e429db6ea3b32 100644 --- a/scripts/build/localization.mjs +++ b/scripts/build/localization.mjs @@ -1 +1,15 @@ -export const localizationDirectories = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"].map(f => f.toLowerCase()); +export const localizationDirectories = [ + "cs", + "de", + "es", + "fr", + "it", + "ja", + "ko", + "pl", + "pt-br", + "ru", + "tr", + "zh-cn", + "zh-tw", +].map(f => f.toLowerCase()); diff --git a/scripts/build/options.mjs b/scripts/build/options.mjs index ce2aa1330cb67..90abf4af7ed35 100644 --- a/scripts/build/options.mjs +++ b/scripts/build/options.mjs @@ -4,19 +4,35 @@ import os from "os"; const ci = ["1", "true"].includes(process.env.CI ?? ""); const parsed = minimist(process.argv.slice(2), { - boolean: ["dirty", "light", "colors", "lkg", "soft", "fix", "failed", "keepFailed", "force", "built", "ci", "bundle", "typecheck", "lint", "coverage"], + boolean: [ + "dirty", + "light", + "colors", + "lkg", + "soft", + "fix", + "failed", + "keepFailed", + "force", + "built", + "ci", + "bundle", + "typecheck", + "lint", + "coverage", + ], string: ["browser", "tests", "break", "host", "reporter", "stackTraceLimit", "timeout", "shards", "shardId"], alias: { /* eslint-disable quote-props */ - "b": "browser", - "i": ["inspect", "inspect-brk", "break", "debug", "debug-brk"], - "t": ["tests", "test"], - "ru": ["runners", "runner"], - "r": "reporter", - "c": ["colors", "color"], - "skippercent": "skipPercent", - "w": "workers", - "f": "fix" + b: "browser", + i: ["inspect", "inspect-brk", "break", "debug", "debug-brk"], + t: ["tests", "test"], + ru: ["runners", "runner"], + r: "reporter", + c: ["colors", "color"], + skippercent: "skipPercent", + w: "workers", + f: "fix", /* eslint-enable quote-props */ }, default: { @@ -43,7 +59,7 @@ const parsed = minimist(process.argv.slice(2), { typecheck: true, lint: true, coverage: false, - } + }, }); /** @type {CommandLineOptions} */ @@ -59,8 +75,6 @@ if (!options.bundle && !options.typecheck) { export default options; - - /** * @typedef CommandLineOptions * @property {boolean} dirty diff --git a/scripts/build/projects.mjs b/scripts/build/projects.mjs index 812bdb5c6287c..5657c71abd9dc 100644 --- a/scripts/build/projects.mjs +++ b/scripts/build/projects.mjs @@ -1,8 +1,15 @@ -import { resolve } from "path"; +import { + resolve, +} from "path"; -import { findUpRoot } from "./findUpDir.mjs"; +import { + findUpRoot, +} from "./findUpDir.mjs"; import cmdLineOptions from "./options.mjs"; -import { Debouncer, exec } from "./utils.mjs"; +import { + Debouncer, + exec, +} from "./utils.mjs"; class ProjectQueue { /** @@ -32,30 +39,33 @@ class ProjectQueue { const tscPath = resolve( findUpRoot(), - cmdLineOptions.lkg ? "./lib/tsc.js" : - cmdLineOptions.built ? "./built/local/tsc.js" : - "./node_modules/typescript/lib/tsc.js", + cmdLineOptions.lkg ? "./lib/tsc.js" + : cmdLineOptions.built ? "./built/local/tsc.js" + : "./node_modules/typescript/lib/tsc.js", ); -const execTsc = (/** @type {string[]} */ ...args) => exec(process.execPath, [tscPath, "-b", ...args], { hidePrompt: true }); +const execTsc = (/** @type {string[]} */ ...args) => + exec(process.execPath, [tscPath, "-b", ...args], { hidePrompt: true }); -const projectBuilder = new ProjectQueue((projects) => execTsc(...(cmdLineOptions.bundle ? [] : ["--emitDeclarationOnly", "false"]), ...projects)); +const projectBuilder = new ProjectQueue(projects => + execTsc(...(cmdLineOptions.bundle ? [] : ["--emitDeclarationOnly", "false"]), ...projects) +); /** * @param {string} project */ -export const buildProject = (project) => projectBuilder.enqueue(project); +export const buildProject = project => projectBuilder.enqueue(project); -const projectCleaner = new ProjectQueue((projects) => execTsc("--clean", ...projects)); +const projectCleaner = new ProjectQueue(projects => execTsc("--clean", ...projects)); /** * @param {string} project */ -export const cleanProject = (project) => projectCleaner.enqueue(project); +export const cleanProject = project => projectCleaner.enqueue(project); -const projectWatcher = new ProjectQueue((projects) => execTsc("--watch", "--preserveWatchOutput", ...projects)); +const projectWatcher = new ProjectQueue(projects => execTsc("--watch", "--preserveWatchOutput", ...projects)); /** * @param {string} project */ -export const watchProject = (project) => projectWatcher.enqueue(project); +export const watchProject = project => projectWatcher.enqueue(project); diff --git a/scripts/build/tests.mjs b/scripts/build/tests.mjs index 205076f51dd3e..6bd776a17b029 100644 --- a/scripts/build/tests.mjs +++ b/scripts/build/tests.mjs @@ -1,13 +1,21 @@ -import { CancelError } from "@esfx/canceltoken"; +import { + CancelError, +} from "@esfx/canceltoken"; import chalk from "chalk"; import del from "del"; import fs from "fs"; import os from "os"; import path from "path"; -import { findUpFile, findUpRoot } from "./findUpDir.mjs"; +import { + findUpFile, + findUpRoot, +} from "./findUpDir.mjs"; import cmdLineOptions from "./options.mjs"; -import { exec, ExecError } from "./utils.mjs"; +import { + exec, + ExecError, +} from "./utils.mjs"; const mochaJs = path.resolve(findUpRoot(), "node_modules", "mocha", "bin", "_mocha"); export const localBaseline = "tests/baselines/local/"; @@ -59,7 +67,8 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, opt do { taskConfigsFolder = prefix + i; i++; - } while (fs.existsSync(taskConfigsFolder)); + } + while (fs.existsSync(taskConfigsFolder)); fs.mkdirSync(taskConfigsFolder); workerCount = cmdLineOptions.workers; @@ -70,7 +79,18 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, opt } if (tests || runners || light || testTimeout || taskConfigsFolder || keepFailed || shards || shardId) { - writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, testTimeout, keepFailed, shards, shardId); + writeTestConfigFile( + tests, + runners, + light, + taskConfigsFolder, + workerCount, + stackTraceLimit, + testTimeout, + keepFailed, + shards, + shardId, + ); } const colors = cmdLineOptions.colors; @@ -106,7 +126,7 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, opt args.push("--no-colors"); } if (inspect !== undefined) { - args.unshift((inspect === "" || inspect === true) ? "--inspect-brk" : "--inspect-brk="+inspect); + args.unshift((inspect === "" || inspect === true) ? "--inspect-brk" : "--inspect-brk=" + inspect); args.push("-t", "0"); } else { @@ -189,7 +209,18 @@ async function cleanCoverageDir() { * @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, + runners, + light, + taskConfigsFolder, + workerCount, + stackTraceLimit, + timeout, + keepFailed, + shards, + shardId, +) { const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, runners: runners ? runners.split(",") : undefined, @@ -201,7 +232,7 @@ export function writeTestConfigFile(tests, runners, light, taskConfigsFolder, wo timeout, keepFailed, shards, - shardId + shardId, }); console.info("Running tests with config: " + testConfigContents); fs.writeFileSync("test.config", testConfigContents); diff --git a/scripts/build/utils.mjs b/scripts/build/utils.mjs index ec3b7bccaa220..dfd862bced779 100644 --- a/scripts/build/utils.mjs +++ b/scripts/build/utils.mjs @@ -1,7 +1,11 @@ -import { CancelError } from "@esfx/canceltoken"; +import { + CancelError, +} from "@esfx/canceltoken"; import assert from "assert"; import chalk from "chalk"; -import { spawn } from "child_process"; +import { + spawn, +} from "child_process"; import fs from "fs"; import JSONC from "jsonc-parser"; import which from "which"; @@ -16,14 +20,17 @@ import which from "which"; * @property {boolean} [ignoreExitCode] * @property {boolean} [hidePrompt] * @property {boolean} [waitForExit=true] + * @property {boolean} [ignoreStdout] * @property {import("@esfx/canceltoken").CancelToken} [token] */ export async function exec(cmd, args, options = {}) { - return /**@type {Promise<{exitCode?: number}>}*/(new Promise((resolve, reject) => { - const { ignoreExitCode, waitForExit = true } = options; + return /**@type {Promise<{exitCode?: number}>}*/ (new Promise((resolve, reject) => { + const { ignoreExitCode, waitForExit = true, ignoreStdout } = options; if (!options.hidePrompt) console.log(`> ${chalk.green(cmd)} ${args.join(" ")}`); - const proc = spawn(which.sync(cmd), args, { stdio: waitForExit ? "inherit" : "ignore" }); + const proc = spawn(which.sync(cmd), args, { + stdio: waitForExit ? ignoreStdout ? ["inherit", "ignore", "inherit"] : "inherit" : "ignore", + }); if (waitForExit) { const onCanceled = () => { proc.kill(); @@ -34,8 +41,8 @@ export async function exec(cmd, args, options = {}) { resolve({ exitCode: exitCode ?? undefined }); } else { - const reason = options.token?.signaled ? options.token.reason ?? new CancelError() : - new ExecError(exitCode); + const reason = options.token?.signaled ? options.token.reason ?? new CancelError() + : new ExecError(exitCode); reject(reason); } subscription?.unsubscribe(); @@ -83,18 +90,18 @@ export function readJson(jsonPath) { export function needsUpdate(source, dest) { if (typeof source === "string" && typeof dest === "string") { if (fs.existsSync(dest)) { - const {mtime: outTime} = fs.statSync(dest); - const {mtime: inTime} = fs.statSync(source); + const { mtime: outTime } = fs.statSync(dest); + const { mtime: inTime } = fs.statSync(source); if (+inTime <= +outTime) { return false; } } } else if (typeof source === "string" && typeof dest !== "string") { - const {mtime: inTime} = fs.statSync(source); + const { mtime: inTime } = fs.statSync(source); for (const filepath of dest) { if (fs.existsSync(filepath)) { - const {mtime: outTime} = fs.statSync(filepath); + const { mtime: outTime } = fs.statSync(filepath); if (+inTime > +outTime) { return true; } @@ -107,10 +114,10 @@ export function needsUpdate(source, dest) { } else if (typeof source !== "string" && typeof dest === "string") { if (fs.existsSync(dest)) { - const {mtime: outTime} = fs.statSync(dest); + const { mtime: outTime } = fs.statSync(dest); for (const filepath of source) { if (fs.existsSync(filepath)) { - const {mtime: inTime} = fs.statSync(filepath); + const { mtime: inTime } = fs.statSync(filepath); if (+inTime > +outTime) { return true; } @@ -128,8 +135,8 @@ export function needsUpdate(source, dest) { continue; } if (fs.existsSync(dest[i])) { - const {mtime: outTime} = fs.statSync(dest[i]); - const {mtime: inTime} = fs.statSync(source[i]); + const { mtime: outTime } = fs.statSync(dest[i]); + const { mtime: inTime } = fs.statSync(source[i]); if (+inTime > +outTime) { return true; } @@ -175,7 +182,9 @@ export class Debouncer { this._action = action; } - get empty() { return !this._deferred; } + get empty() { + return !this._deferred; + } enqueue() { if (this._timer) { diff --git a/scripts/checkModuleFormat.mjs b/scripts/checkModuleFormat.mjs index 0ce73003b7a0a..6c461d370a32e 100644 --- a/scripts/checkModuleFormat.mjs +++ b/scripts/checkModuleFormat.mjs @@ -1,5 +1,10 @@ -import { createRequire } from "module"; -import { __importDefault, __importStar } from "tslib"; +import { + createRequire, +} from "module"; +import { + __importDefault, + __importStar, +} from "tslib"; // This script tests that TypeScript's CJS API is structured // as expected. It calls "require" as though it were in CWD, @@ -13,12 +18,12 @@ const ts = require(process.argv[2]); // See: https://github.com/microsoft/TypeScript/pull/51474#issuecomment-1310871623 /** @type {[fn: (() => any), shouldSucceed: boolean][]} */ const fns = [ - [() => ts.version, true], - [() => ts.default.version, false], - [() => __importDefault(ts).version, false], + [() => ts.version, true], + [() => ts.default.version, false], + [() => __importDefault(ts).version, false], [() => __importDefault(ts).default.version, true], - [() => __importStar(ts).version, true], - [() => __importStar(ts).default.version, true], + [() => __importStar(ts).version, true], + [() => __importStar(ts).default.version, true], ]; for (const [fn, shouldSucceed] of fns) { diff --git a/scripts/checkPackageSize.mjs b/scripts/checkPackageSize.mjs index 9614ca195842a..4ba086b9bfa84 100644 --- a/scripts/checkPackageSize.mjs +++ b/scripts/checkPackageSize.mjs @@ -5,7 +5,9 @@ const baseRepo = process.argv[2]; const headRepo = process.argv[3]; /** @type {Array<{ size: number, unpackedSize: number; files: Array<{ path: string; size: number; }>; }>} */ -const [before, after] = JSON.parse(cp.execFileSync("npm", ["pack", "--dry-run", "--json", baseRepo, headRepo], { encoding: "utf8" })); +const [before, after] = JSON.parse( + cp.execFileSync("npm", ["pack", "--dry-run", "--json", baseRepo, headRepo], { encoding: "utf8" }), +); /** @param {{ path: string; size: number; }[]} files */ function filesToMap(files) { @@ -117,7 +119,7 @@ else { prettyPrintSizeDiff(before.unpackedSize, after.unpackedSize), prettyPercentDiff(before.unpackedSize, after.unpackedSize), ], - ] + ], ); } @@ -126,7 +128,6 @@ failIfTooBig(before.unpackedSize, after.unpackedSize); console.log(); - /** @type {Map} */ const fileCounts = new Map(); const inBefore = -1; diff --git a/scripts/configurePrerelease.mjs b/scripts/configurePrerelease.mjs index 66c83c207ae42..41e157e9d63bc 100644 --- a/scripts/configurePrerelease.mjs +++ b/scripts/configurePrerelease.mjs @@ -1,7 +1,15 @@ import assert from "assert"; -import { execFileSync } from "child_process"; -import { readFileSync, writeFileSync } from "fs"; -import { normalize, relative } from "path"; +import { + execFileSync, +} from "child_process"; +import { + readFileSync, + writeFileSync, +} from "fs"; +import { + normalize, + relative, +} from "path"; import url from "url"; const __filename = url.fileURLToPath(new URL(import.meta.url)); @@ -46,7 +54,8 @@ function main() { // Ensure we are actually changing something - the user probably wants to know that the update failed. if (tsFileContents === modifiedTsFileContents) { let err = `\n '${tsFilePath}' was not updated while configuring for a prerelease publish for '${tag}'.\n `; - err += `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`; + err += + `Ensure that you have not already run this script; otherwise, erase your changes using 'git checkout -- "${tsFilePath}"'.`; throw new Error(err + "\n"); } @@ -70,19 +79,31 @@ function main() { function updateTsFile(tsFilePath, tsFileContents, majorMinor, patch, nightlyPatch) { const majorMinorRgx = /export const versionMajorMinor = "(\d+\.\d+)"/; const majorMinorMatch = majorMinorRgx.exec(tsFileContents); - assert(majorMinorMatch !== null, `The file '${tsFilePath}' seems to no longer have a string matching '${majorMinorRgx}'.`); + assert( + majorMinorMatch !== null, + `The file '${tsFilePath}' seems to no longer have a string matching '${majorMinorRgx}'.`, + ); const parsedMajorMinor = majorMinorMatch[1]; - assert(parsedMajorMinor === majorMinor, `versionMajorMinor does not match. ${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`); + assert( + parsedMajorMinor === majorMinor, + `versionMajorMinor does not match. ${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`, + ); const versionRgx = /export const version(?:: string)? = `\$\{versionMajorMinor\}\.(\d)(-\w+)?`;/; const patchMatch = versionRgx.exec(tsFileContents); - assert(patchMatch !== null, `The file '${tsFilePath}' seems to no longer have a string matching '${versionRgx.toString()}'.`); + assert( + patchMatch !== null, + `The file '${tsFilePath}' seems to no longer have a string matching '${versionRgx.toString()}'.`, + ); const parsedPatch = patchMatch[1]; if (parsedPatch !== patch) { throw new Error(`patch does not match. ${tsFilePath}: '${parsedPatch}; package.json: '${patch}'`); } - return tsFileContents.replace(versionRgx, `export const version: string = \`\${versionMajorMinor}.${nightlyPatch}\`;`); + return tsFileContents.replace( + versionRgx, + `export const version: string = \`\${versionMajorMinor}.${nightlyPatch}\`;`, + ); } /** diff --git a/scripts/dtsBundler.mjs b/scripts/dtsBundler.mjs index 305172d3199e1..cf95f1575ef46 100644 --- a/scripts/dtsBundler.mjs +++ b/scripts/dtsBundler.mjs @@ -5,7 +5,10 @@ * bundle as namespaces again, even though the project is modules. */ -import assert, { fail } from "assert"; +import assert, { + fail, +} from "assert"; +import cp from "child_process"; import fs from "fs"; import minimist from "minimist"; import path from "path"; @@ -48,21 +51,25 @@ function isInternalDeclaration(node) { } /** - * * @param {ts.VariableDeclaration} node * @returns {ts.VariableStatement} */ function getParentVariableStatement(node) { const declarationList = node.parent; - assert(ts.isVariableDeclarationList(declarationList), `expected VariableDeclarationList at ${nodeToLocation(node)}`); - assert(declarationList.declarations.length === 1, `expected VariableDeclarationList of length 1 at ${nodeToLocation(node)}`); + assert( + ts.isVariableDeclarationList(declarationList), + `expected VariableDeclarationList at ${nodeToLocation(node)}`, + ); + assert( + declarationList.declarations.length === 1, + `expected VariableDeclarationList of length 1 at ${nodeToLocation(node)}`, + ); const variableStatement = declarationList.parent; assert(ts.isVariableStatement(variableStatement), `expected VariableStatement at ${nodeToLocation(node)}`); return variableStatement; } /** - * * @param {ts.Declaration} node * @returns {ts.Statement | undefined} */ @@ -207,8 +214,8 @@ function nodeToLocation(node) { function removeDeclareConstExport(node) { switch (node.kind) { case ts.SyntaxKind.DeclareKeyword: // No need to emit this in d.ts files. - case ts.SyntaxKind.ConstKeyword: // Remove const from const enums. - case ts.SyntaxKind.ExportKeyword: // No export modifier; we are already in the namespace. + case ts.SyntaxKind.ConstKeyword: // Remove const from const enums. + case ts.SyntaxKind.ExportKeyword: // No export modifier; we are already in the namespace. return undefined; } return node; @@ -234,7 +241,8 @@ function findInScope(name) { /** @type {(symbol: ts.Symbol | undefined, excludes?: ts.SymbolFlags) => boolean} */ function isNonLocalAlias(symbol, excludes = ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace) { if (!symbol) return false; - return (symbol.flags & (ts.SymbolFlags.Alias | excludes)) === ts.SymbolFlags.Alias || !!(symbol.flags & ts.SymbolFlags.Alias && symbol.flags & ts.SymbolFlags.Assignment); + return (symbol.flags & (ts.SymbolFlags.Alias | excludes)) === ts.SymbolFlags.Alias + || !!(symbol.flags & ts.SymbolFlags.Alias && symbol.flags & ts.SymbolFlags.Assignment); } /** @@ -318,7 +326,13 @@ function verifyMatchingSymbols(decl) { } if (symbolsConflict(symbolOfNode, symbolInScope)) { - fail(`Declaration at ${nodeToLocation(decl)}\n references ${symbolOfNode.name} at ${symbolOfNode.declarations && nodeToLocation(symbolOfNode.declarations[0])},\n but containing scope contains a symbol with the same name declared at ${symbolInScope.declarations && nodeToLocation(symbolInScope.declarations[0])}`); + fail( + `Declaration at ${nodeToLocation(decl)}\n references ${symbolOfNode.name} at ${ + symbolOfNode.declarations && nodeToLocation(symbolOfNode.declarations[0]) + },\n but containing scope contains a symbol with the same name declared at ${ + symbolInScope.declarations && nodeToLocation(symbolInScope.declarations[0]) + }`, + ); } } @@ -374,7 +388,7 @@ function emitAsNamespace(name, moduleSymbol) { const isInternal = isInternalDeclaration(statement); if (!isInternal) { - const publicStatement = ts.visitEachChild(statement, (node) => { + const publicStatement = ts.visitEachChild(statement, node => { // No @internal comments in the public API. if (isInternalDeclaration(node)) { return undefined; @@ -409,5 +423,24 @@ if (publicContents.includes("@internal")) { console.error("Output includes untrimmed @internal nodes!"); } -fs.writeFileSync(output, publicContents); -fs.writeFileSync(internalOutput, internalContents); +const dprintPath = path.resolve(__dirname, "..", "node_modules", "dprint", "bin.js"); + +/** + * @param {string} contents + * @returns {string} + */ +function dprint(contents) { + return cp.execFileSync( + process.execPath, + [dprintPath, "fmt", "--stdin", "ts"], + { + stdio: ["pipe", "pipe", "inherit"], + encoding: "utf-8", + input: contents, + maxBuffer: 100 * 1024 * 1024, // 100 MB "ought to be enough for anyone"; https://github.com/nodejs/node/issues/9829 + }, + ); +} + +fs.writeFileSync(output, dprint(publicContents)); +fs.writeFileSync(internalOutput, dprint(internalContents)); diff --git a/scripts/eslint/rules/argument-trivia.cjs b/scripts/eslint/rules/argument-trivia.cjs index 49ec726dc4b04..4e3b6011e765b 100644 --- a/scripts/eslint/rules/argument-trivia.cjs +++ b/scripts/eslint/rules/argument-trivia.cjs @@ -19,7 +19,6 @@ function memoize(fn) { }; } - module.exports = createRule({ name: "argument-trivia", meta: { @@ -42,9 +41,9 @@ module.exports = createRule({ const sourceCodeText = sourceCode.getText(); /** @type {(name: string) => boolean} */ - const isSetOrAssert = (name) => name.startsWith("set") || name.startsWith("assert"); + const isSetOrAssert = name => name.startsWith("set") || name.startsWith("assert"); /** @type {(node: TSESTree.Node) => boolean} */ - const isTrivia = (node) => { + const isTrivia = node => { if (node.type === AST_NODE_TYPES.Identifier) { return node.name === "undefined"; } @@ -58,7 +57,7 @@ module.exports = createRule({ }; /** @type {(node: TSESTree.CallExpression | TSESTree.NewExpression) => boolean} */ - const shouldIgnoreCalledExpression = (node) => { + const shouldIgnoreCalledExpression = node => { if (node.callee && node.callee.type === AST_NODE_TYPES.MemberExpression) { const methodName = node.callee.property.type === AST_NODE_TYPES.Identifier ? node.callee.property.name @@ -98,7 +97,6 @@ module.exports = createRule({ return false; }; - /** @type {(node: TSESTree.Node, i: number, getSignature: () => ts.Signature | undefined) => void} */ const checkArg = (node, i, getSignature) => { if (!isTrivia(node)) { @@ -130,9 +128,9 @@ module.exports = createRule({ context.report({ messageId: "argumentTriviaArgumentError", node, - fix: (fixer) => { + fix: fixer => { return fixer.insertTextBefore(node, `/*${expectedName}*/ `); - } + }, }); } else { @@ -151,7 +149,7 @@ module.exports = createRule({ messageId: "argumentTriviaArgumentNameError", data: { got, want: expectedName }, node: comment, - fix: (fixer) => { + fix: fixer => { return fixer.replaceText(comment, `/*${expectedName}*/`); }, }); @@ -165,15 +163,15 @@ module.exports = createRule({ context.report({ messageId: "argumentTriviaArgumentSpaceError", node, - fix: (fixer) => { + fix: fixer => { return fixer.replaceTextRange([commentRangeEnd, argRangeStart], " "); - } + }, }); } }; /** @type {(node: TSESTree.CallExpression | TSESTree.NewExpression) => void} */ - const checkArgumentTrivia = (node) => { + const checkArgumentTrivia = node => { if (shouldIgnoreCalledExpression(node)) { return; } diff --git a/scripts/eslint/rules/debug-assert.cjs b/scripts/eslint/rules/debug-assert.cjs index 8b2e0b0596a11..58f289e0de2ff 100644 --- a/scripts/eslint/rules/debug-assert.cjs +++ b/scripts/eslint/rules/debug-assert.cjs @@ -9,7 +9,8 @@ module.exports = createRule({ }, messages: { secondArgumentDebugAssertError: `Second argument to 'Debug.assert' should be a string literal`, - thirdArgumentDebugAssertError: `Third argument to 'Debug.assert' should be a string literal or arrow function`, + thirdArgumentDebugAssertError: + `Third argument to 'Debug.assert' should be a string literal or arrow function`, }, schema: [], type: "problem", @@ -18,22 +19,23 @@ module.exports = createRule({ create(context) { /** @type {(node: TSESTree.Node) => boolean} */ - const isArrowFunction = (node) => node.type === AST_NODE_TYPES.ArrowFunctionExpression; + const isArrowFunction = node => node.type === AST_NODE_TYPES.ArrowFunctionExpression; /** @type {(node: TSESTree.Node) => boolean} */ - const isStringLiteral = (node) => ( - (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") || node.type === AST_NODE_TYPES.TemplateLiteral + const isStringLiteral = node => ( + (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") + || node.type === AST_NODE_TYPES.TemplateLiteral ); /** @type {(node: TSESTree.MemberExpression) => boolean} */ - const isDebugAssert = (node) => ( + const isDebugAssert = node => ( node.object.type === AST_NODE_TYPES.Identifier - && node.object.name === "Debug" - && node.property.type === AST_NODE_TYPES.Identifier - && node.property.name === "assert" + && node.object.name === "Debug" + && node.property.type === AST_NODE_TYPES.Identifier + && node.property.name === "assert" ); /** @type {(node: TSESTree.CallExpression) => void} */ - const checkDebugAssert = (node) => { + const checkDebugAssert = node => { const args = node.arguments; const argsLen = args.length; if (!(node.callee.type === AST_NODE_TYPES.MemberExpression && isDebugAssert(node.callee)) || argsLen < 2) { diff --git a/scripts/eslint/rules/jsdoc-format.cjs b/scripts/eslint/rules/jsdoc-format.cjs index 140e22b5e4fd3..be7f8586465c0 100644 --- a/scripts/eslint/rules/jsdoc-format.cjs +++ b/scripts/eslint/rules/jsdoc-format.cjs @@ -11,8 +11,8 @@ module.exports = createRule({ internalCommentInNonJSDocError: `@internal should not appear in non-JSDoc comment for declaration.`, internalCommentNotLastError: `@internal should only appear in final JSDoc comment for declaration.`, multipleJSDocError: `Declaration has multiple JSDoc comments.`, - internalCommentOnParameterProperty: `@internal cannot appear on a JSDoc comment; use a declared property and an assignment in the constructor instead.`, - misalignedJSDocComment: `This JSDoc comment is misaligned.`, + internalCommentOnParameterProperty: + `@internal cannot appear on a JSDoc comment; use a declared property and an assignment in the constructor instead.`, }, schema: [], type: "problem", @@ -46,7 +46,7 @@ module.exports = createRule({ }; /** @type {(c: TSESTree.Comment) => TSESTree.SourceLocation} */ - const getJSDocStartLoc = (c) => { + const getJSDocStartLoc = c => { return { start: c.loc.start, end: { @@ -57,7 +57,7 @@ module.exports = createRule({ }; /** @type {(node: TSESTree.Node) => void} */ - const checkDeclaration = (node) => { + const checkDeclaration = node => { const blockComments = sourceCode.getCommentsBefore(node).filter(c => c.type === "Block"); if (blockComments.length === 0) { return; @@ -81,78 +81,30 @@ module.exports = createRule({ } if (!isJSDoc) { - context.report({ messageId: "internalCommentInNonJSDocError", node: c, loc: getAtInternalLoc(c, indexInComment) }); + context.report({ + messageId: "internalCommentInNonJSDocError", + node: c, + loc: getAtInternalLoc(c, indexInComment), + }); } else if (i !== last) { - context.report({ messageId: "internalCommentNotLastError", node: c, loc: getAtInternalLoc(c, indexInComment) }); + context.report({ + messageId: "internalCommentNotLastError", + node: c, + loc: getAtInternalLoc(c, indexInComment), + }); } else if (node.type === "TSParameterProperty") { - context.report({ messageId: "internalCommentOnParameterProperty", node: c, loc: getAtInternalLoc(c, indexInComment) }); - } - } - }; - - /** @type {(node: TSESTree.Node) => void} */ - const checkProgram = () => { - const comments = sourceCode.getAllComments(); - - for (const c of comments) { - if (c.type !== "Block") { - continue; - } - - const rawComment = sourceCode.getText(c); - if (!isJSDocText(rawComment)) { - continue; - } - - const expected = c.loc.start.column + 2; - const split = rawComment.split(/\r?\n/g); - for (let i = 1; i < split.length; i++) { - const line = split[i]; - const match = /^ *\*/.exec(line); - if (!match) { - continue; - } - - const actual = match[0].length; - const diff = actual - expected; - if (diff !== 0) { - const line = c.loc.start.line + i; - context.report({ - messageId: "misalignedJSDocComment", - node: c, - loc: { - start: { - line, - column: 0, - }, - end: { - line, - column: actual - 1, - } - }, - fix: (fixer) => { - if (diff > 0) { - // Too many - const start = sourceCode.getIndexFromLoc({ line, column: expected - 1 }); - return fixer.removeRange([start, start + diff]); - } - else { - // Too few - const start = sourceCode.getIndexFromLoc({ line, column: 0 }); - return fixer.insertTextAfterRange([start, start], " ".repeat(-diff)); - } - }, - }); - break; - } + context.report({ + messageId: "internalCommentOnParameterProperty", + node: c, + loc: getAtInternalLoc(c, indexInComment), + }); } } }; return { - Program: checkProgram, ClassDeclaration: checkDeclaration, FunctionDeclaration: checkDeclaration, TSEnumDeclaration: checkDeclaration, diff --git a/scripts/eslint/rules/no-double-space.cjs b/scripts/eslint/rules/no-double-space.cjs deleted file mode 100644 index 75c74d031a4fe..0000000000000 --- a/scripts/eslint/rules/no-double-space.cjs +++ /dev/null @@ -1,72 +0,0 @@ -const { TSESTree, AST_NODE_TYPES } = require("@typescript-eslint/utils"); -const { createRule } = require("./utils.cjs"); - -module.exports = createRule({ - name: "no-double-space", - meta: { - docs: { - description: ``, - }, - messages: { - noDoubleSpaceError: `Use only one space`, - }, - schema: [], - type: "problem", - }, - defaultOptions: [], - - create(context) { - const sourceCode = context.getSourceCode(); - const lines = sourceCode.getLines(); - - /** @type {(node: TSESTree.Node | null) => boolean} */ - const isStringLiteral = (node) => { - return !!(node && ( - (node.type === AST_NODE_TYPES.TemplateElement) || - (node.type === AST_NODE_TYPES.TemplateLiteral && node.quasis) || - (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") - )); - }; - - /** @type {(node: TSESTree.Node | null) => boolean} */ - const isRegexLiteral = (node) => { - return !!(node && node.type === AST_NODE_TYPES.Literal && Object.prototype.hasOwnProperty.call(node, "regex")); - }; - - /** @type {(node: TSESTree.Node) => void} */ - const checkDoubleSpace = (node) => { - lines.forEach((line, index) => { - const firstNonSpace = /\S/.exec(line); - if (!firstNonSpace || line.includes("@param")) { - return; - } - - // Allow common uses of double spaces - // * To align `=` or `!=` signs - // * To align comments at the end of lines - // * To indent inside a comment - // * To use two spaces after a period - // * To include aligned `->` in a comment - const rgx = /[^/*. ][ ]{2}[^-!/= ]/g; - rgx.lastIndex = firstNonSpace.index; - const doubleSpace = rgx.exec(line); - - if (!doubleSpace) { - return; - } - - const locIndex = sourceCode.getIndexFromLoc({ column: doubleSpace.index, line: index + 1 }); - const sourceNode = sourceCode.getNodeByRangeIndex(locIndex); - if (isStringLiteral(sourceNode) || isRegexLiteral(sourceNode)) { - return; - } - - context.report({ messageId: "noDoubleSpaceError", node, loc: { line: index + 1, column: doubleSpace.index + 1 } }); - }); - }; - - return { - Program: checkDoubleSpace, - }; - }, -}); diff --git a/scripts/eslint/rules/no-in-operator.cjs b/scripts/eslint/rules/no-in-operator.cjs index bbd2b60532596..cbd357b86823e 100644 --- a/scripts/eslint/rules/no-in-operator.cjs +++ b/scripts/eslint/rules/no-in-operator.cjs @@ -18,7 +18,7 @@ module.exports = createRule({ create(context) { const IN_OPERATOR = "in"; /** @type {(node: TSESTree.BinaryExpression) => void} */ - const checkInOperator = (node) => { + const checkInOperator = node => { if (node.operator === IN_OPERATOR) { context.report({ messageId: "noInOperatorError", node }); } diff --git a/scripts/eslint/rules/no-keywords.cjs b/scripts/eslint/rules/no-keywords.cjs index 0cb0c9f7b1d4f..d7c9f6f3fd8aa 100644 --- a/scripts/eslint/rules/no-keywords.cjs +++ b/scripts/eslint/rules/no-keywords.cjs @@ -35,21 +35,21 @@ module.exports = createRule({ ]; /** @type {(name: string) => boolean} */ - const isKeyword = (name) => keywords.includes(name); + const isKeyword = name => keywords.includes(name); /** @type {(node: TSESTree.Identifier) => void} */ - const report = (node) => { + const report = node => { context.report({ messageId: "noKeywordsError", data: { name: node.name }, node }); }; /** @type {(node: TSESTree.ObjectPattern) => void} */ - const checkProperties = (node) => { + const checkProperties = node => { node.properties.forEach(property => { if ( - property && - property.type === AST_NODE_TYPES.Property && - property.key.type === AST_NODE_TYPES.Identifier && - isKeyword(property.key.name) + property + && property.type === AST_NODE_TYPES.Property + && property.key.type === AST_NODE_TYPES.Identifier + && isKeyword(property.key.name) ) { report(property.key); } @@ -57,12 +57,12 @@ module.exports = createRule({ }; /** @type {(node: TSESTree.ArrayPattern) => void} */ - const checkElements = (node) => { + const checkElements = node => { node.elements.forEach(element => { if ( - element && - element.type === AST_NODE_TYPES.Identifier && - isKeyword(element.name) + element + && element.type === AST_NODE_TYPES.Identifier + && isKeyword(element.name) ) { report(element); } @@ -70,16 +70,16 @@ module.exports = createRule({ }; /** @type {(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.TSMethodSignature | TSESTree.TSFunctionType) => void} */ - const checkParams = (node) => { + const checkParams = node => { if (!node || !node.params || !node.params.length) { return; } node.params.forEach(param => { if ( - param && - param.type === AST_NODE_TYPES.Identifier && - isKeyword(param.name) + param + && param.type === AST_NODE_TYPES.Identifier + && isKeyword(param.name) ) { report(param); } @@ -97,8 +97,8 @@ module.exports = createRule({ } if ( - node.id.type === AST_NODE_TYPES.Identifier && - isKeyword(node.id.name) + node.id.type === AST_NODE_TYPES.Identifier + && isKeyword(node.id.name) ) { report(node.id); } diff --git a/scripts/eslint/rules/no-type-assertion-whitespace.cjs b/scripts/eslint/rules/no-type-assertion-whitespace.cjs deleted file mode 100644 index 3f10a85dbc7f8..0000000000000 --- a/scripts/eslint/rules/no-type-assertion-whitespace.cjs +++ /dev/null @@ -1,42 +0,0 @@ -const { TSESTree } = require("@typescript-eslint/utils"); -const { createRule } = require("./utils.cjs"); - -module.exports = createRule({ - name: "no-type-assertion-whitespace", - meta: { - docs: { - description: ``, - }, - messages: { - noTypeAssertionWhitespace: `Excess trailing whitespace found around type assertion`, - }, - schema: [], - type: "problem", - }, - defaultOptions: [], - - create(context) { - const sourceCode = context.getSourceCode(); - /** @type {(node: TSESTree.TSTypeAssertion) => void} */ - const checkTypeAssertionWhitespace = (node) => { - const leftToken = sourceCode.getLastToken(node.typeAnnotation); - const rightToken = sourceCode.getFirstToken(node.expression); - - if (!leftToken || !rightToken) { - return; - } - - if (sourceCode.isSpaceBetweenTokens(leftToken, rightToken)) { - context.report({ - messageId: "noTypeAssertionWhitespace", - node, - loc: { column: leftToken.loc.end.column + 1, line: leftToken.loc.end.line }, - }); - } - }; - - return { - TSTypeAssertion: checkTypeAssertionWhitespace, - }; - }, -}); diff --git a/scripts/eslint/rules/object-literal-surrounding-space.cjs b/scripts/eslint/rules/object-literal-surrounding-space.cjs deleted file mode 100644 index b2c8604790170..0000000000000 --- a/scripts/eslint/rules/object-literal-surrounding-space.cjs +++ /dev/null @@ -1,71 +0,0 @@ -const { TSESTree } = require("@typescript-eslint/utils"); -const { createRule } = require("./utils.cjs"); - -module.exports = createRule({ - name: "object-literal-surrounding-space", - meta: { - docs: { - description: ``, - }, - messages: { - leadingExcessStringError: `No trailing whitespace found on single-line object literal`, - leadingStringError: `No leading whitespace found on single-line object literal`, - - trailingExcessStringError: `Excess trailing whitespace found on single-line object literal.`, - trailingStringError: `No trailing whitespace found on single-line object literal`, - }, - schema: [], - type: "suggestion", - }, - defaultOptions: [], - - create(context) { - const sourceCode = context.getSourceCode(); - const SPACE_SYMBOL = " "; - const CLOSE_SYMBOL = "}"; - const OPEN_SYMBOL = "{"; - - /** @type {(text: string, startIndex: number) => boolean} */ - const manySpaces = (text, startIndex) => ( - [startIndex, startIndex + 1].every(i => text.charAt(i) === SPACE_SYMBOL) - ); - - /** @type {(node: TSESTree.ObjectExpression) => void} */ - const checkObjectLiteralSurroundingSpace = (node) => { - const text = sourceCode.getText(node); - const startLine = node.loc.start.line; - const endLine = node.loc.end.line; - - if (!node.properties.length || !text.match(/^{[^\n]+}$/g)) { - return; - } - - if (text.charAt(0) === OPEN_SYMBOL) { - if (text.charAt(1) !== SPACE_SYMBOL) { - context.report({ messageId: "leadingStringError", node }); - } - - if (manySpaces(text, 1)) { - context.report({ messageId: "leadingExcessStringError", node, loc: { column: node.loc.start.column + 1, line: startLine } }); - } - } - - if (text.charAt(text.length - 1) === CLOSE_SYMBOL) { - const index = text.length - 2; - const endColumn = node.loc.end.column; - - if (text.charAt(index) !== SPACE_SYMBOL) { - context.report({ messageId: "trailingStringError", node, loc: { column: endColumn - 1, line: endLine } }); - } - - if (manySpaces(text, index - 1)) { - context.report({ messageId: "trailingExcessStringError", node, loc: { column: endColumn - 2, line: endLine } }); - } - } - }; - - return { - ObjectExpression: checkObjectLiteralSurroundingSpace, - }; - }, -}); diff --git a/scripts/eslint/rules/only-arrow-functions.cjs b/scripts/eslint/rules/only-arrow-functions.cjs index d68ab8a397a67..898d96dce0efb 100644 --- a/scripts/eslint/rules/only-arrow-functions.cjs +++ b/scripts/eslint/rules/only-arrow-functions.cjs @@ -27,12 +27,13 @@ module.exports = createRule({ }], create(context, [{ allowNamedFunctions, allowDeclarations }]) { - /** @type {(node: TSESTree.FunctionDeclaration | TSESTree.FunctionExpression) => boolean} */ - const isThisParameter = (node) => !!node.params.length && !!node.params.find(param => param.type === AST_NODE_TYPES.Identifier && param.name === "this"); + const isThisParameter = node => + !!node.params.length + && !!node.params.find(param => param.type === AST_NODE_TYPES.Identifier && param.name === "this"); /** @type {(node: TSESTree.Node) => boolean} */ - const isMethodType = (node) => { + const isMethodType = node => { const types = [ AST_NODE_TYPES.MethodDefinition, AST_NODE_TYPES.Property, @@ -59,7 +60,7 @@ module.exports = createRule({ }; /** @type {(node: TSESTree.FunctionDeclaration | TSESTree.FunctionExpression) => void} */ - const exitFunction = (node) => { + const exitFunction = node => { const methodUsesThis = stack.pop(); if (node.type === AST_NODE_TYPES.FunctionDeclaration && allowDeclarations) { diff --git a/scripts/eslint/rules/simple-indent.cjs b/scripts/eslint/rules/simple-indent.cjs deleted file mode 100644 index 958e04658ee29..0000000000000 --- a/scripts/eslint/rules/simple-indent.cjs +++ /dev/null @@ -1,68 +0,0 @@ -const { TSESTree } = require("@typescript-eslint/utils"); -const { createRule } = require("./utils.cjs"); - -module.exports = createRule({ - name: "simple-indent", - meta: { - docs: { - description: "Enforce consistent indentation", - }, - messages: { - simpleIndentError: "4 space indentation expected", - }, - fixable: "whitespace", - schema: [], - type: "layout", - }, - defaultOptions: [], - create(context) { - const TAB_SIZE = 4; - const TAB_REGEX = /\t/g; - const sourceCode = context.getSourceCode(); - const linebreaks = sourceCode.getText().match(/\r\n|[\r\n\u2028\u2029]/gu); - - /** @type {(node: TSESTree.Program) => void} */ - const checkIndent = (node) => { - const lines = sourceCode.getLines(); - const linesLen = lines.length; - - let totalLen = 0; - for (let i = 0; i < linesLen; i++) { - const lineNumber = i + 1; - const line = lines[i]; - const linebreaksLen = linebreaks && linebreaks[i] ? linebreaks[i].length : 1; - const lineLen = line.length + linebreaksLen; - const matches = /\S/.exec(line); - - if (matches && matches.index) { - const indentEnd = matches.index; - const whitespace = line.slice(0, indentEnd); - - if (!TAB_REGEX.test(whitespace)) { - totalLen += lineLen; - continue; - } - - context.report({ - messageId: "simpleIndentError", - node, - loc: { column: indentEnd, line: lineNumber }, - fix(fixer) { - const rangeStart = totalLen; - const rangeEnd = rangeStart + indentEnd; - - return fixer - .replaceTextRange([rangeStart, rangeEnd], whitespace.replace(TAB_REGEX, " ".repeat(TAB_SIZE))); - } - }); - } - - totalLen += lineLen; - } - }; - - return { - Program: checkIndent, - }; - }, -}); diff --git a/scripts/eslint/rules/type-operator-spacing.cjs b/scripts/eslint/rules/type-operator-spacing.cjs deleted file mode 100644 index 5d0fd8f1e9794..0000000000000 --- a/scripts/eslint/rules/type-operator-spacing.cjs +++ /dev/null @@ -1,43 +0,0 @@ -const { TSESTree, AST_TOKEN_TYPES } = require("@typescript-eslint/utils"); -const { createRule } = require("./utils.cjs"); - -module.exports = createRule({ - name: "type-operator-spacing", - meta: { - docs: { - description: ``, - }, - messages: { - typeOperatorSpacingError: `The '|' and '&' operators must be surrounded by spaces`, - }, - schema: [], - type: "suggestion", - }, - defaultOptions: [], - - create(context) { - const sourceCode = context.getSourceCode(); - const tokens = ["|", "&"]; - const text = sourceCode.getText(); - - /** @type {(node: TSESTree.TSIntersectionType | TSESTree.TSUnionType) => void} */ - const checkTypeOperatorSpacing = (node) => { - node.types.forEach(node => { - const token = sourceCode.getTokenBefore(node); - - if (!!token && token.type === AST_TOKEN_TYPES.Punctuator && tokens.indexOf(token.value) >= 0) { - const [start, end] = token.range; - - if (/\S/.test(text[start - 1]) || /\S/.test(text[end])) { - context.report({ messageId: "typeOperatorSpacingError", node: token }); - } - } - }); - }; - - return { - TSIntersectionType: checkTypeOperatorSpacing, - TSUnionType: checkTypeOperatorSpacing, - }; - }, -}); diff --git a/scripts/eslint/tests/argument-trivia.test.cjs b/scripts/eslint/tests/argument-trivia.test.cjs index 3e749bdf25512..932a2bbf1c5d5 100644 --- a/scripts/eslint/tests/argument-trivia.test.cjs +++ b/scripts/eslint/tests/argument-trivia.test.cjs @@ -77,10 +77,10 @@ const fn = (prop: boolean) => {}; fn(/* boolean arg */false); `, errors: [{ messageId: "argumentTriviaArgumentSpaceError" }], - output:` + output: ` const fn = (prop: boolean) => {}; fn(/* boolean arg */ false); - ` + `, }, ], }); diff --git a/scripts/eslint/tests/debug-assert.test.cjs b/scripts/eslint/tests/debug-assert.test.cjs index ae5961e41fc12..702017ff7afec 100644 --- a/scripts/eslint/tests/debug-assert.test.cjs +++ b/scripts/eslint/tests/debug-assert.test.cjs @@ -45,6 +45,6 @@ ruleTester.run("debug-assert", rule, { { messageId: "secondArgumentDebugAssertError" }, { messageId: "thirdArgumentDebugAssertError" }, ], - } + }, ], }); diff --git a/scripts/eslint/tests/no-double-space.test.cjs b/scripts/eslint/tests/no-double-space.test.cjs deleted file mode 100644 index b411fbe6ea85f..0000000000000 --- a/scripts/eslint/tests/no-double-space.test.cjs +++ /dev/null @@ -1,154 +0,0 @@ -const { RuleTester } = require("./support/RuleTester.cjs"); -const rule = require("../rules/no-double-space.cjs"); - -const ruleTester = new RuleTester({ - parser: require.resolve("@typescript-eslint/parser"), - parserOptions: { - warnOnUnsupportedTypeScriptVersion: false, - }, -}); - -ruleTester.run("no-double-space", rule, { - valid: [ - { - code: `const a = {};`, - }, - { - code: `function fn() {}`, - }, - { - code: `const a = " ";`, - }, - { - code: `// ^ ^`, - }, - { - code: `class Cl {}`, - }, - { - code: `// comment `, - }, - { - code: `/* comment */`, - }, - { - code: `" string ";`, - }, - { - code: `/ regexp /g;`, - }, - { - code: `const rgx = / regexp /g;`, - }, - { - code: "const str = ` string template`;", - }, - { - code: ` // comment`, - }, - { - code: ` /* comment */`, - }, - { - code: `// `, - }, - { - code: ` -const a = - 1; - `, - }, - { - code: ` -/** - * comment - */ - `, - }, - { - code: ` -// comment -// - comment -// - comment - `, - }, - { - code: ` -interface Props { - prop: string[]; // comment prop - propB: string[]; // comment propB -} - `, - }, - { - code: ` -/** - * Returns a JSON-encoded value of the type: string[] - * - * @param exclude A JSON encoded string[] containing the paths to exclude - * when enumerating the directory. - */ - `, - }, - { - code: ` -const obj = { - content: "function f() { 1; }", -}; - `, - }, - ], - - invalid: [ - { - code: `const a = {};`, - errors: [ - { messageId: "noDoubleSpaceError", line: 1, column: 6 }, - ], - }, - { - code: `function fn() {}`, - errors: [ - { messageId: "noDoubleSpaceError", line: 1, column: 9 }, - ], - }, - { - code: `class Cl {}`, - errors: [{ messageId: "noDoubleSpaceError", line: 1, column: 6 }], - }, - { - code: "const str = ` string template`;", - errors: [ - { messageId: "noDoubleSpaceError", line: 1, column: 12 }, - ], - }, - { - code: `/** comment */`, - errors: [ - { messageId: "noDoubleSpaceError", line: 1, column: 12 }, - ], - }, - { - code: `/** comment with many spaces */`, - errors: [ - { messageId: "noDoubleSpaceError", line: 1, column: 12 }, - ], - }, - { - code: `// comment with many spaces`, - errors: [ - { messageId: "noDoubleSpaceError", line: 1, column: 11 }, - ], - }, - { - code: ` -const a = 1; -const b = 2; -const c = 3; - `, - errors: [ - { messageId: "noDoubleSpaceError", line: 4, column: 10 }, - ], - }, - ], -}); diff --git a/scripts/eslint/tests/no-keywords.test.cjs b/scripts/eslint/tests/no-keywords.test.cjs index 3618329b68aba..731b05a9d1ffe 100644 --- a/scripts/eslint/tests/no-keywords.test.cjs +++ b/scripts/eslint/tests/no-keywords.test.cjs @@ -76,7 +76,7 @@ interface Foo { number: string; } `, - } + }, ], invalid: [ @@ -144,14 +144,14 @@ interface A { code: `let [number, string] = [3, ''];`, errors: [ { messageId: "noKeywordsError" }, - { messageId: "noKeywordsError" } + { messageId: "noKeywordsError" }, ], }, { code: `let { String, Boolean } = { String: 1, Boolean: false };`, errors: [ { messageId: "noKeywordsError" }, - { messageId: "noKeywordsError" } + { messageId: "noKeywordsError" }, ], }, ], diff --git a/scripts/eslint/tests/no-type-assertion-whitespace.test.cjs b/scripts/eslint/tests/no-type-assertion-whitespace.test.cjs deleted file mode 100644 index aa820094a0ee9..0000000000000 --- a/scripts/eslint/tests/no-type-assertion-whitespace.test.cjs +++ /dev/null @@ -1,39 +0,0 @@ -const { RuleTester } = require("./support/RuleTester.cjs"); -const rule = require("../rules/no-type-assertion-whitespace.cjs"); - -const ruleTester = new RuleTester({ - parserOptions: { - warnOnUnsupportedTypeScriptVersion: false, - }, - parser: require.resolve("@typescript-eslint/parser"), -}); - -ruleTester.run("no-type-assertion-whitespace", rule, { - valid: [ - { - code: `const a = 1`, - }, - { - code: `const s = (new Symbol(1, 'name'));`, - }, - ], - - invalid: [ - { - code: `const a = 1`, - errors: [{ messageId: "noTypeAssertionWhitespace", column: 19, line: 1 }], - }, - { - code: `const a = 1`, - errors: [{ messageId: "noTypeAssertionWhitespace", column: 19, line: 1 }], - }, - { - code: `const a = 1`, - errors: [{ messageId: "noTypeAssertionWhitespace", column: 19, line: 1 }], - }, - { - code: `const s = (new Symbol(1, 'name'));`, - errors: [{ messageId: "noTypeAssertionWhitespace", column: 17, line: 1 }], - }, - ], -}); diff --git a/scripts/eslint/tests/object-literal-surrounding-space.test.cjs b/scripts/eslint/tests/object-literal-surrounding-space.test.cjs deleted file mode 100644 index 7c697af531fb9..0000000000000 --- a/scripts/eslint/tests/object-literal-surrounding-space.test.cjs +++ /dev/null @@ -1,49 +0,0 @@ -const { RuleTester } = require("./support/RuleTester.cjs"); -const rule = require("../rules/object-literal-surrounding-space.cjs"); - -const ruleTester = new RuleTester({ - parserOptions: { - warnOnUnsupportedTypeScriptVersion: false, - }, - parser: require.resolve("@typescript-eslint/parser"), -}); - -ruleTester.run("object-literal-surrounding-space", rule, { - valid: [ - { - code: `const prop = {}`, - }, - { - code: `const prop = { }`, - }, - { - code: `const prop = { x: 1 }`, - }, - ], - - invalid: [ - { - code: `const prop = {x: 1}`, - errors: [ - { messageId: "leadingStringError" }, - { messageId: "trailingStringError" } - ], - }, - { - code: `const prop = { x: 1 }`, - errors: [{ messageId: "leadingExcessStringError" }], - }, - { - code: `const prop = { x: 1 }`, - errors: [{ messageId: "trailingExcessStringError" }], - }, - { - code: `const prop = { x: 1}`, - errors: [{ messageId: "trailingStringError" }], - }, - { - code: `const prop = {x: 1 }`, - errors: [{ messageId: "leadingStringError" }], - }, - ], -}); diff --git a/scripts/eslint/tests/simple-indent.test.cjs b/scripts/eslint/tests/simple-indent.test.cjs deleted file mode 100644 index 0e4d925c56091..0000000000000 --- a/scripts/eslint/tests/simple-indent.test.cjs +++ /dev/null @@ -1,333 +0,0 @@ -const { RuleTester } = require("./support/RuleTester.cjs"); -const rule = require("../rules/simple-indent.cjs"); - -const ruleTester = new RuleTester({ - parserOptions: { - warnOnUnsupportedTypeScriptVersion: false, - }, - parser: require.resolve("@typescript-eslint/parser"), -}); - -ruleTester.run("simple-indent", rule, { - valid: [ - { - code: ` -/** - * Comment - */ - ` - }, - { - code: ` -module TestModule { - var func = () => { - console.warn("hi"); - }; -} - `, - }, - { - code: ` -class TestClass { - private variable; - - testFunction() { - this.variable = 3; - } -} - `, - }, - { - code: ` -var obj = { - a: 1, - b: 2, - c: 3 -}; - `, - }, - { - code: ` -export enum TestEnum { - VALUE1, - VALUE2 -} - `, - }, - { - code: ` -switch (integerValue) { - case 1: - console.warn("1"); - break; - default: - console.warn("default"); - break; -} - `, - }, - { - code: ` -function loops() { - for (var i = 0; i < 1; ++i) { - console.warn(i); - } - - while (i < 1) { - console.warn(i); - } - - do { - console.warn(i); - } while (i < 1); - - if (i < 1) { - console.warn(i); - } else { - console.warn(i + 1); - } -} - `, - }, - ], - - invalid: [ - { - code: ` -module TestModule { -\tvar testVariable = 123; -} - `, - output: ` -module TestModule { - var testVariable = 123; -} - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - ], - }, - { - code: ` -function a() { -\t\tvar test = 123; -} - `, - output: ` -function a() { - var test = 123; -} - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 3 }, - ], - }, - { - code: ` -class TestClass { -\tprivate variable; - -\ttestFunction() { -\t\tthis.variable = 3; -\t} -} - `, - output: ` -class TestClass { - private variable; - - testFunction() { - this.variable = 3; - } -} - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - { messageId: "simpleIndentError", line: 5, column: 2 }, - { messageId: "simpleIndentError", line: 6, column: 3 }, - { messageId: "simpleIndentError", line: 7, column: 2 }, - ], - }, - { - code: ` -var obj = { -\ta: 1, -\tb: 2, -\tc: 3 -}; - `, - output: ` -var obj = { - a: 1, - b: 2, - c: 3 -}; - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - { messageId: "simpleIndentError", line: 4, column: 2 }, - { messageId: "simpleIndentError", line: 5, column: 2 }, - ] - }, - { - code: ` -enum TestEnum { -\tVALUE1, - VALUE2 -} - `, - output: ` -enum TestEnum { - VALUE1, - VALUE2 -} - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - ], - }, - { - code: ` -switch (integerValue) { -\tcase 0: -\t\tconsole.warn("1"); -\t\tbreak; - case 1: - console.warn("1"); - break; -\tdefault: -\t\tconsole.log("2"); -\t\tbreak; -} - `, - output: ` -switch (integerValue) { - case 0: - console.warn("1"); - break; - case 1: - console.warn("1"); - break; - default: - console.log("2"); - break; -} - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - { messageId: "simpleIndentError", line: 4, column: 3 }, - { messageId: "simpleIndentError", line: 5, column: 3 }, - { messageId: "simpleIndentError", line: 9, column: 2 }, - { messageId: "simpleIndentError", line: 10, column: 3 }, - { messageId: "simpleIndentError", line: 11, column: 3 }, - ] - }, - { - code: ` -for (var i = 0; i < 1; ++i) { -\tconsole.warn("123"); -} - `, - output: ` -for (var i = 0; i < 1; ++i) { - console.warn("123"); -} - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - ], - }, - { - code: ` -while (i < 1) { -\tconsole.warn("123"); -} - `, - output: ` -while (i < 1) { - console.warn("123"); -} - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - ] - }, - { - code: ` -do { -\tconsole.warn("123"); -} while (i < 1); - `, - output: ` -do { - console.warn("123"); -} while (i < 1); - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - ] - }, - { - code: ` -if (i < 1) { -\tconsole.warn("123"); -} - `, - output: ` -if (i < 1) { - console.warn("123"); -} - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - ] - }, - { - code: ` -var arr = [ -\t1, - 2 -]; - `, - output: ` -var arr = [ - 1, - 2 -]; - `, - errors: [ - { messageId: "simpleIndentError", line: 3, column: 2 }, - ] - }, - { - code: ` -var arr2 = [ - { -\t\ta: 1, - b: 2 - }, - { - a: 3, -\t\tb: 4 - } -]; - `, - output: ` -var arr2 = [ - { - a: 1, - b: 2 - }, - { - a: 3, - b: 4 - } -]; - `, - errors: [ - { messageId: "simpleIndentError", line: 4, column: 3 }, - { messageId: "simpleIndentError", line: 9, column: 3 }, - ] - } - ], -}); diff --git a/scripts/eslint/tests/type-operator-spacing.test.cjs b/scripts/eslint/tests/type-operator-spacing.test.cjs deleted file mode 100644 index 3341348828e1a..0000000000000 --- a/scripts/eslint/tests/type-operator-spacing.test.cjs +++ /dev/null @@ -1,45 +0,0 @@ -const { RuleTester } = require("./support/RuleTester.cjs"); -const rule = require("../rules/type-operator-spacing.cjs"); - -const ruleTester = new RuleTester({ - parserOptions: { - warnOnUnsupportedTypeScriptVersion: false, - }, - parser: require.resolve("@typescript-eslint/parser"), -}); - -ruleTester.run("type-operator-spacing", rule, { - valid: [ - { - code: `type T = string | number`, - }, - { - code: `type T = string & number`, - }, - { - code: `function fn(): string | number {}`, - }, - { - code: `function fn(): string & number {}`, - }, - ], - - invalid: [ - { - code: `type T = string|number`, - errors: [{ messageId: "typeOperatorSpacingError" }], - }, - { - code: `type T = string&number`, - errors: [{ messageId: "typeOperatorSpacingError" }], - }, - { - code: `function fn(): string|number {}`, - errors: [{ messageId: "typeOperatorSpacingError" }], - }, - { - code: `function fn(): string&number {}`, - errors: [{ messageId: "typeOperatorSpacingError" }], - }, - ], -}); diff --git a/scripts/failed-tests.cjs b/scripts/failed-tests.cjs index b669db47c0313..8160b73de506e 100644 --- a/scripts/failed-tests.cjs +++ b/scripts/failed-tests.cjs @@ -76,7 +76,7 @@ class FailedTestsReporter extends Mocha.reporters.Base { */ static writeFailures(file, passes, failures, keepFailed, done) { const failingTests = new Set(fs.existsSync(file) ? readTests() : undefined); - const possiblyPassingSuites = /**@type {Set}*/(new Set()); + const possiblyPassingSuites = /**@type {Set}*/ (new Set()); // Remove tests that are now passing and track suites that are now // possibly passing. @@ -138,17 +138,23 @@ class FailedTestsReporter extends Mocha.reporters.Base { done(failures, fn) { assert(this.reporterOptions); assert(this.reporterOptions.file); - FailedTestsReporter.writeFailures(this.reporterOptions.file, this.passes, this.failures, this.reporterOptions.keepFailed || this.stats.tests === 0, (err) => { - const reporter = this.reporter; - if (reporter && reporter.done) { - reporter.done(failures, fn); - } - else if (fn) { - fn(failures); - } + FailedTestsReporter.writeFailures( + this.reporterOptions.file, + this.passes, + this.failures, + this.reporterOptions.keepFailed || this.stats.tests === 0, + err => { + const reporter = this.reporter; + if (reporter && reporter.done) { + reporter.done(failures, fn); + } + else if (fn) { + fn(failures); + } - if (err) console.error(err); - }); + if (err) console.error(err); + }, + ); } } diff --git a/scripts/find-unused-diganostic-messages.mjs b/scripts/find-unused-diganostic-messages.mjs index ad116ef5a5325..b4aff5913b437 100644 --- a/scripts/find-unused-diganostic-messages.mjs +++ b/scripts/find-unused-diganostic-messages.mjs @@ -1,9 +1,15 @@ // This file requires a modern version of node 14+, and grep to be available. // node scripts/find-unused-diagnostic-messages.mjs -import { execSync } from "child_process"; -import { readFileSync } from "fs"; -import { EOL } from "os"; +import { + execSync, +} from "child_process"; +import { + readFileSync, +} from "fs"; +import { + EOL, +} from "os"; const diags = readFileSync("src/compiler/diagnosticInformationMap.generated.ts", "utf8"); const startOfDiags = diags.split("export const Diagnostics")[1]; diff --git a/scripts/generateLocalizedDiagnosticMessages.mjs b/scripts/generateLocalizedDiagnosticMessages.mjs index e8711a0ca1c43..dfb89c207d492 100644 --- a/scripts/generateLocalizedDiagnosticMessages.mjs +++ b/scripts/generateLocalizedDiagnosticMessages.mjs @@ -1,4 +1,6 @@ -import { XMLParser } from "fast-xml-parser"; +import { + XMLParser, +} from "fast-xml-parser"; import fs from "fs"; import path from "path"; @@ -26,7 +28,9 @@ async function main() { const args = process.argv.slice(2); if (args.length !== 3) { console.log("Usage:"); - console.log("\tnode generateLocalizedDiagnosticMessages.js "); + console.log( + "\tnode generateLocalizedDiagnosticMessages.js ", + ); return; } @@ -50,8 +54,7 @@ async function main() { const inputFilePath = path.join(inputPath, name, "diagnosticMessages", "diagnosticMessages.generated.json.lcl"); const contents = await fs.promises.readFile(inputFilePath); /** @type {ParsedLCL} */ - // eslint-disable-next-line local/object-literal-surrounding-space - const result = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "$_"}).parse(contents); + const result = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "$_" }).parse(contents); if (!result || !result.LCX || !result.LCX.$_TgtCul) { console.error("Unexpected XML file structure. Expected to find result.LCX.$_TgtCul."); process.exit(1); @@ -61,7 +64,10 @@ async function main() { console.error(`Invalid output locale name for '${result.LCX.$_TgtCul}'.`); process.exit(1); } - await writeFile(path.join(outputPath, outputDirectoryName, "diagnosticMessages.generated.json"), xmlObjectToString(result)); + await writeFile( + path.join(outputPath, outputDirectoryName, "diagnosticMessages.generated.json"), + xmlObjectToString(result), + ); } /** @@ -135,8 +141,8 @@ async function main() { path.join(outputPath, "enu", "diagnosticMessages.generated.json.lcg"), getLCGFileXML( Object.entries(JSON.parse(contents)) - .sort((a, b) => a[0] > b[0] ? 1 : -1) // lcg sorted by property keys - .reduce((s, [key, value]) => s + getItemXML(key, value), "") + .sort((a, b) => a[0] > b[0] ? 1 : -1) // lcg sorted by property keys + .reduce((s, [key, value]) => s + getItemXML(key, value), ""), ), ); return; diff --git a/scripts/link-hooks.mjs b/scripts/link-hooks.mjs index c54456fcacf66..6d5594b49062b 100644 --- a/scripts/link-hooks.mjs +++ b/scripts/link-hooks.mjs @@ -2,16 +2,18 @@ import fs from "fs"; import path from "path"; import url from "url"; -import { findUpRoot } from "./build/findUpDir.mjs"; +import { + findUpRoot, +} from "./build/findUpDir.mjs"; const __filename = url.fileURLToPath(new URL(import.meta.url)); const __dirname = path.dirname(__filename); const hooks = [ - "post-checkout" + "post-checkout", ]; -hooks.forEach((hook) => { +hooks.forEach(hook => { const hookInSourceControl = path.resolve(__dirname, "hooks", hook); if (fs.existsSync(hookInSourceControl)) { diff --git a/scripts/open-cherry-pick-pr.mjs b/scripts/open-cherry-pick-pr.mjs index 6b9fc9b1ab2fa..13002bb7b0e36 100644 --- a/scripts/open-cherry-pick-pr.mjs +++ b/scripts/open-cherry-pick-pr.mjs @@ -1,9 +1,13 @@ -import { Octokit } from "@octokit/rest"; +import { + Octokit, +} from "@octokit/rest"; import fs from "fs"; import path from "path"; import url from "url"; -import { runSequence } from "./run-sequence.mjs"; +import { + runSequence, +} from "./run-sequence.mjs"; const __filename = url.fileURLToPath(new URL(import.meta.url)); const __dirname = path.dirname(__filename); @@ -22,30 +26,34 @@ async function main() { throw new Error("Source issue not specified"); } const currentSha = runSequence([ - ["git", ["rev-parse", "HEAD"]] + ["git", ["rev-parse", "HEAD"]], ]); const currentAuthor = runSequence([ - ["git", ["log", "-1", `--pretty="%aN <%aE>"`]] + ["git", ["log", "-1", `--pretty="%aN <%aE>"`]], ]); const gh = new Octokit({ - auth: process.argv[2] + auth: process.argv[2], }); - const inputPR = (await gh.pulls.get({ pull_number: +process.env.SOURCE_ISSUE, owner: "microsoft", repo: "TypeScript" })).data; + const inputPR = + (await gh.pulls.get({ pull_number: +process.env.SOURCE_ISSUE, owner: "microsoft", repo: "TypeScript" })).data; let remoteName = "origin"; - if (inputPR.base.repo.git_url !== `git:github.com/microsoft/TypeScript` && inputPR.base.repo.git_url !== `git://github.com/microsoft/TypeScript`) { + if ( + inputPR.base.repo.git_url !== `git:github.com/microsoft/TypeScript` + && inputPR.base.repo.git_url !== `git://github.com/microsoft/TypeScript` + ) { runSequence([ - ["git", ["remote", "add", "nonlocal", inputPR.base.repo.git_url.replace(/^git:(?:\/\/)?/, "https://")]] + ["git", ["remote", "add", "nonlocal", inputPR.base.repo.git_url.replace(/^git:(?:\/\/)?/, "https://")]], ]); remoteName = "nonlocal"; } const baseBranchName = inputPR.base.ref; runSequence([ - ["git", ["fetch", remoteName, baseBranchName]] + ["git", ["fetch", remoteName, baseBranchName]], ]); let logText = runSequence([ - ["git", ["log", `${remoteName}/${baseBranchName}..${currentSha.trim()}`, `--pretty="%h %s%n%b"`, "--reverse"]] + ["git", ["log", `${remoteName}/${baseBranchName}..${currentSha.trim()}`, `--pretty="%h %s%n%b"`, "--reverse"]], ]); logText = `Cherry-pick PR #${process.env.SOURCE_ISSUE} into ${process.env.TARGET_BRANCH} @@ -55,15 +63,15 @@ ${logText.trim()}`; const mergebase = runSequence([["git", ["merge-base", `${remoteName}/${baseBranchName}`, currentSha]]]).trim(); runSequence([ ["git", ["checkout", "-b", "temp-branch"]], - ["git", ["reset", mergebase, "--soft"]] + ["git", ["reset", mergebase, "--soft"]], ]); fs.writeFileSync(logpath, logText); runSequence([ - ["git", ["commit", "-F", logpath, `--author="${currentAuthor.trim()}"`]] + ["git", ["commit", "-F", logpath, `--author="${currentAuthor.trim()}"`]], ]); fs.unlinkSync(logpath); const squashSha = runSequence([ - ["git", ["rev-parse", "HEAD"]] + ["git", ["rev-parse", "HEAD"]], ]); runSequence([ ["git", ["checkout", process.env.TARGET_BRANCH]], // checkout the target branch @@ -74,24 +82,28 @@ ${logText.trim()}`; runSequence([ ["node", ["./node_modules/hereby/dist/cli.js", "LKG"]], ["git", ["add", "lib"]], - ["git", ["commit", "-m", `"Update LKG"`]] + ["git", ["commit", "-m", `"Update LKG"`]], ]); } runSequence([ ["git", ["remote", "add", "fork", remoteUrl]], // Add the remote fork - ["git", ["push", "--set-upstream", "fork", branchName, "-f"]] // push the branch + ["git", ["push", "--set-upstream", "fork", branchName, "-f"]], // push the branch ]); const r = await gh.pulls.create({ owner: "Microsoft", repo: "TypeScript", maintainer_can_modify: true, - title: `🤖 Pick PR #${process.env.SOURCE_ISSUE} (${inputPR.title.substring(0, 35)}${inputPR.title.length > 35 ? "..." : ""}) into ${process.env.TARGET_BRANCH}`, + title: `🤖 Pick PR #${process.env.SOURCE_ISSUE} (${inputPR.title.substring(0, 35)}${ + inputPR.title.length > 35 ? "..." : "" + }) into ${process.env.TARGET_BRANCH}`, head: `${userName}:${branchName}`, base: process.env.TARGET_BRANCH, body: - `This cherry-pick was triggered by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} -Please review the diff and merge if no changes are unexpected.${produceLKG ? ` An LKG update commit is included separately from the base change.` : ""} + `This cherry-pick was triggered by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} +Please review the diff and merge if no changes are unexpected.${ + produceLKG ? ` An LKG update commit is included separately from the base change.` : "" + } You can view the cherry-pick log [here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary). cc ${reviewers.map(r => "@" + r).join(" ")}`, @@ -103,7 +115,7 @@ cc ${reviewers.map(r => "@" + r).join(" ")}`, issue_number: +process.env.SOURCE_ISSUE, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${process.env.REQUESTING_USER}, I've opened #${num} for you.` + body: `Hey @${process.env.REQUESTING_USER}, I've opened #${num} for you.`, }); } @@ -112,13 +124,14 @@ main().catch(async e => { process.exitCode = 1; if (process.env.SOURCE_ISSUE) { const gh = new Octokit({ - auth: process.argv[2] + auth: process.argv[2], }); await gh.issues.createComment({ issue_number: +process.env.SOURCE_ISSUE, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${process.env.REQUESTING_USER}, I couldn't open a PR with the cherry-pick. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)). You may need to squash and pick this PR into ${process.env.TARGET_BRANCH} manually.` + body: + `Hey @${process.env.REQUESTING_USER}, I couldn't open a PR with the cherry-pick. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)). You may need to squash and pick this PR into ${process.env.TARGET_BRANCH} manually.`, }); } }); diff --git a/scripts/open-user-pr.mjs b/scripts/open-user-pr.mjs index f79e56f0fb71d..ac706c3a1da5a 100644 --- a/scripts/open-user-pr.mjs +++ b/scripts/open-user-pr.mjs @@ -1,12 +1,18 @@ -import { Octokit } from "@octokit/rest"; +import { + Octokit, +} from "@octokit/rest"; -import { runSequence } from "./run-sequence.mjs"; +import { + runSequence, +} from "./run-sequence.mjs"; const userName = process.env.GH_USERNAME || "typescript-bot"; -const reviewers = process.env.REQUESTING_USER ? [process.env.REQUESTING_USER] : ["weswigham", "sandersn", "RyanCavanaugh"]; +const reviewers = process.env.REQUESTING_USER ? [process.env.REQUESTING_USER] + : ["weswigham", "sandersn", "RyanCavanaugh"]; const masterBranchname = `user-baseline-updates`; const targetBranch = process.env.TARGET_BRANCH || "main"; -const branchName = process.env.TARGET_FORK?.toLowerCase() === "microsoft" && (targetBranch === "main" || targetBranch === "refs/heads/main") +const branchName = process.env.TARGET_FORK?.toLowerCase() === "microsoft" + && (targetBranch === "main" || targetBranch === "refs/heads/main") ? masterBranchname : `user-update-${process.env.TARGET_FORK}-${process.env.TARGET_BRANCH ? "-" + process.env.TARGET_BRANCH : ""}`; const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`; @@ -19,23 +25,31 @@ runSequence([ ["node", ["./node_modules/hereby/dist/cli.js", "baseline-accept"]], // accept baselines ["git", ["checkout", "-b", branchName]], // create a branch ["git", ["add", "."]], // Add all changes - ["git", ["commit", "-m", `"Update user baselines${+(process.env.SOURCE_ISSUE ?? 0) === 33716 ? " +cc @sandersn" : ""}"`]], // Commit all changes (ping nathan if we would post to CI thread) - ["git", ["push", "--set-upstream", "fork", branchName, "-f"]] // push the branch + ["git", [ + "commit", + "-m", + `"Update user baselines${+(process.env.SOURCE_ISSUE ?? 0) === 33716 ? " +cc @sandersn" : ""}"`, + ]], // Commit all changes (ping nathan if we would post to CI thread) + ["git", ["push", "--set-upstream", "fork", branchName, "-f"]], // push the branch ]); const gh = new Octokit({ - auth: process.argv[2] + auth: process.argv[2], }); const prOwner = branchName === masterBranchname ? "microsoft" : userName; gh.pulls.create({ owner: prOwner, repo: "TypeScript", maintainer_can_modify: true, - title: `🤖 User test baselines have changed` + (process.env.TARGET_BRANCH ? ` for ${process.env.TARGET_BRANCH}` : ""), + title: `🤖 User test baselines have changed` + + (process.env.TARGET_BRANCH ? ` for ${process.env.TARGET_BRANCH}` : ""), head: `${userName}:${branchName}`, base: branchName === masterBranchname ? "main" : masterBranchname, - body: -`${process.env.SOURCE_ISSUE ? `This test run was triggerd by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} `+"\n" : ""}Please review the diff and merge if no changes are unexpected. + body: `${ + process.env.SOURCE_ISSUE + ? `This test run was triggerd by a request on https://github.com/Microsoft/TypeScript/pull/${process.env.SOURCE_ISSUE} ` + + "\n" : "" + }Please review the diff and merge if no changes are unexpected. You can view the build log [here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary). cc ${reviewers.map(r => "@" + r).join(" ")}`, @@ -55,7 +69,8 @@ cc ${reviewers.map(r => "@" + r).join(" ")}`, issue_number: +process.env.SOURCE_ISSUE, owner: "microsoft", repo: "TypeScript", - body: `The user suite test run you requested has finished and _failed_. I've opened a [PR with the baseline diff from master](${r.data.html_url}).` + body: + `The user suite test run you requested has finished and _failed_. I've opened a [PR with the baseline diff from master](${r.data.html_url}).`, }); } }).then(() => { diff --git a/scripts/perf-result-post.mjs b/scripts/perf-result-post.mjs index 77ce392688828..c64ae5eb6ca01 100644 --- a/scripts/perf-result-post.mjs +++ b/scripts/perf-result-post.mjs @@ -1,10 +1,11 @@ -import { Octokit } from "@octokit/rest"; +import { + Octokit, +} from "@octokit/rest"; import assert from "assert"; import ado from "azure-devops-node-api"; import fs from "fs"; import fetch from "node-fetch"; - async function main() { const source = process.env.SOURCE_ISSUE; if (!source) throw new Error("SOURCE_ISSUE environment variable not set."); @@ -31,7 +32,10 @@ async function main() { let benchmarkText = ""; if (includeArtifact === "--include-artifact") { // post a link to the benchmark file - const cli = new ado.WebApi("https://typescript.visualstudio.com/defaultcollection", ado.getHandlerFromToken("")); // Empty token, anon auth + const cli = new ado.WebApi( + "https://typescript.visualstudio.com/defaultcollection", + ado.getHandlerFromToken(""), + ); // Empty token, anon auth const build = await cli.getBuildApi(); const artifact = await build.getArtifact("typescript", +buildId, "benchmark"); assert(artifact.resource?.url); @@ -42,7 +46,8 @@ async function main() { if (/[\\/]linux\.benchmark$/.test(file.path)) { const benchmarkUrl = new URL(artifact.resource.url); benchmarkUrl.search = `artifactName=benchmark&fileId=${file.blob.id}&fileName=linux.benchmark`; - benchmarkText = `\n
Developer Information:

Download Benchmark

\n`; + benchmarkText = + `\n
Developer Information:

Download Benchmark

\n`; break; } } @@ -52,7 +57,8 @@ async function main() { issue_number: +source, owner: "Microsoft", repo: "TypeScript", - body: `@${requester}\nThe results of the perf run you requested are in!\n
Here they are:

\n${outputTableText}\n

${benchmarkText}
` + body: + `@${requester}\nThe results of the perf run you requested are in!\n
Here they are:

\n${outputTableText}\n

${benchmarkText}
`, }); console.log(`Results posted!`); @@ -60,14 +66,14 @@ async function main() { const comment = await gh.issues.getComment({ owner: "Microsoft", repo: "TypeScript", - comment_id: +postedComment + comment_id: +postedComment, }); const newBody = `${comment.data.body}\n\nUpdate: [The results are in!](${newCommentUrl})`; await gh.issues.updateComment({ owner: "Microsoft", repo: "TypeScript", comment_id: +postedComment, - body: newBody + body: newBody, }); } catch (e) { @@ -76,7 +82,8 @@ async function main() { issue_number: +source, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${requester}, something went wrong when publishing results. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${buildId}&_a=summary)).` + body: + `Hey @${requester}, something went wrong when publishing results. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${buildId}&_a=summary)).`, }); } } diff --git a/scripts/post-vsts-artifact-comment.mjs b/scripts/post-vsts-artifact-comment.mjs index 8c345c5842798..8b16a90a4ae1b 100644 --- a/scripts/post-vsts-artifact-comment.mjs +++ b/scripts/post-vsts-artifact-comment.mjs @@ -1,4 +1,6 @@ -import { Octokit } from "@octokit/rest"; +import { + Octokit, +} from "@octokit/rest"; import assert from "assert"; import ado from "azure-devops-node-api"; import fetch from "node-fetch"; @@ -23,7 +25,7 @@ async function main() { tgzUrl.search = `artifactName=tgz&fileId=${file.blob.id}&fileName=${file.path}`; const link = "" + tgzUrl; const gh = new Octokit({ - auth: process.argv[2] + auth: process.argv[2], }); // Please keep the strings "an installable tgz" and "packed" in this message, as well as the devDependencies section, @@ -33,7 +35,8 @@ async function main() { issue_number: +process.env.SOURCE_ISSUE, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${process.env.REQUESTING_USER}, I've packed this into [an installable tgz](${link}). You can install it for testing by referencing it in your \`package.json\` like so: + body: + `Hey @${process.env.REQUESTING_USER}, I've packed this into [an installable tgz](${link}). You can install it for testing by referencing it in your \`package.json\` like so: \`\`\` { "devDependencies": { @@ -42,12 +45,15 @@ async function main() { } \`\`\` and then running \`npm install\`. -` +`, }); // Temporarily disable until we get access controls set up right // Send a ping to https://github.com/microsoft/typescript-make-monaco-builds#pull-request-builds - await gh.request("POST /repos/microsoft/typescript-make-monaco-builds/dispatches", { event_type: process.env.SOURCE_ISSUE, headers: { Accept: "application/vnd.github.everest-preview+json" } }); + await gh.request("POST /repos/microsoft/typescript-make-monaco-builds/dispatches", { + event_type: process.env.SOURCE_ISSUE, + headers: { Accept: "application/vnd.github.everest-preview+json" }, + }); } main().catch(async e => { @@ -55,13 +61,14 @@ main().catch(async e => { process.exitCode = 1; if (process.env.SOURCE_ISSUE) { const gh = new Octokit({ - auth: process.argv[2] + auth: process.argv[2], }); await gh.issues.createComment({ issue_number: +process.env.SOURCE_ISSUE, owner: "Microsoft", repo: "TypeScript", - body: `Hey @${process.env.REQUESTING_USER}, something went wrong when looking for the build artifact. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)).` + body: + `Hey @${process.env.REQUESTING_USER}, something went wrong when looking for the build artifact. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${process.env.BUILD_BUILDID}&_a=summary)).`, }); } }); diff --git a/scripts/processDiagnosticMessages.mjs b/scripts/processDiagnosticMessages.mjs index da207ec7ec3b3..986be171e248f 100644 --- a/scripts/processDiagnosticMessages.mjs +++ b/scripts/processDiagnosticMessages.mjs @@ -24,7 +24,7 @@ async function main() { * @param {string} fileName * @param {string} contents */ - async function writeFile(fileName, contents) { + async function writeFile(fileName, contents) { const filePath = path.join(path.dirname(inputFilePath), fileName); try { const existingContents = await fs.promises.readFile(filePath, "utf-8"); @@ -86,7 +86,7 @@ function buildInfoFileOutput(messageTable, inputFilePathRel) { "// ", `// generated from '${inputFilePathRel}'`, "", - "import { DiagnosticCategory, DiagnosticMessage } from \"./types\";", + 'import { DiagnosticCategory, DiagnosticMessage } from "./types";', "", "function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean, reportsDeprecated?: {}): DiagnosticMessage {", " return { code, category, key, message, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated };", @@ -95,14 +95,27 @@ function buildInfoFileOutput(messageTable, inputFilePathRel) { "/** @internal */", "export const Diagnostics = {", ]; - messageTable.forEach(({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated }, name) => { - const propName = convertPropertyName(name); - const argReportsUnnecessary = reportsUnnecessary ? `, /*reportsUnnecessary*/ ${reportsUnnecessary}` : ""; - const argElidedInCompatabilityPyramid = elidedInCompatabilityPyramid ? `${!reportsUnnecessary ? ", /*reportsUnnecessary*/ undefined" : ""}, /*elidedInCompatabilityPyramid*/ ${elidedInCompatabilityPyramid}` : ""; - const argReportsDeprecated = reportsDeprecated ? `${!argElidedInCompatabilityPyramid ? ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined" : ""}, /*reportsDeprecated*/ ${reportsDeprecated}` : ""; - - result.push(` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}),`); - }); + messageTable.forEach( + ({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated }, name) => { + const propName = convertPropertyName(name); + const argReportsUnnecessary = reportsUnnecessary ? `, /*reportsUnnecessary*/ ${reportsUnnecessary}` : ""; + const argElidedInCompatabilityPyramid = elidedInCompatabilityPyramid + ? `${ + !reportsUnnecessary ? ", /*reportsUnnecessary*/ undefined" : "" + }, /*elidedInCompatabilityPyramid*/ ${elidedInCompatabilityPyramid}` : ""; + const argReportsDeprecated = reportsDeprecated + ? `${ + !argElidedInCompatabilityPyramid + ? ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined" : "" + }, /*reportsDeprecated*/ ${reportsDeprecated}` : ""; + + result.push( + ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${ + JSON.stringify(name) + }${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}),`, + ); + }, + ); result.push("};"); @@ -126,7 +139,6 @@ function buildDiagnosticMessageOutput(messageTable) { } /** - * * @param {string} name * @param {number} code * @returns {string} diff --git a/scripts/produceLKG.mjs b/scripts/produceLKG.mjs index 8db2e831d7828..f5dc7a5c27c22 100644 --- a/scripts/produceLKG.mjs +++ b/scripts/produceLKG.mjs @@ -3,7 +3,9 @@ import glob from "glob"; import path from "path"; import url from "url"; -import { localizationDirectories } from "./build/localization.mjs"; +import { + localizationDirectories, +} from "./build/localization.mjs"; const __filename = url.fileURLToPath(new URL(import.meta.url)); const __dirname = path.dirname(__filename); diff --git a/scripts/regenerate-unicode-identifier-parts.mjs b/scripts/regenerate-unicode-identifier-parts.mjs index 60730b77e2509..a21b0bf848eea 100644 --- a/scripts/regenerate-unicode-identifier-parts.mjs +++ b/scripts/regenerate-unicode-identifier-parts.mjs @@ -1,9 +1,10 @@ - const MAX_UNICODE_CODEPOINT = 0x10FFFF; /** @type {(c: string) => boolean} */ const isStart = c => /[\p{ID_Start}\u{2118}\u{212E}\u{309B}\u{309C}]/u.test(c); // Other_ID_Start explicitly included for back compat - see http://www.unicode.org/reports/tr31/#Introduction /** @type {(c: string) => boolean} */ -const isPart = c => /[\p{ID_Continue}\u{00B7}\u{0387}\u{19DA}\u{1369}\u{136A}\u{136B}\u{136C}\u{136D}\u{136E}\u{136F}\u{1370}\u{1371}]/u.test(c) || isStart(c); // Likewise for Other_ID_Continue +const isPart = c => + /[\p{ID_Continue}\u{00B7}\u{0387}\u{19DA}\u{1369}\u{136A}\u{136B}\u{136C}\u{136D}\u{136E}\u{136F}\u{1370}\u{1371}]/u + .test(c) || isStart(c); // Likewise for Other_ID_Continue const parts = []; let partsActive = false; let startsActive = false; diff --git a/scripts/request-pr-review.mjs b/scripts/request-pr-review.mjs index 51c9e90e786a6..ef5a69808deed 100644 --- a/scripts/request-pr-review.mjs +++ b/scripts/request-pr-review.mjs @@ -1,4 +1,6 @@ -import { Octokit } from "@octokit/rest"; +import { + Octokit, +} from "@octokit/rest"; import minimist from "minimist"; const options = minimist(process.argv.slice(2), { @@ -7,15 +9,15 @@ const options = minimist(process.argv.slice(2), { alias: { pr: "pull", h: "help", - ["?"]: "help" + ["?"]: "help", }, default: { token: process.env.GH_TOKEN, pull: process.env.GH_PULL_NUMBER, reviewer: process.env.REQUESTED_REVIEWER, owner: "microsoft", - repo: "TypeScript" - } + repo: "TypeScript", + }, }); if (options.help) { diff --git a/scripts/run-sequence.mjs b/scripts/run-sequence.mjs index 910c9e5e5182d..96ccb1e220cb1 100644 --- a/scripts/run-sequence.mjs +++ b/scripts/run-sequence.mjs @@ -11,7 +11,13 @@ export function runSequence(tasks, opts = { timeout: 100000, shell: true }) { for (const task of tasks) { console.log(`${task[0]} ${task[1].join(" ")}`); const result = cp.spawnSync(task[0], task[1], opts); - if (result.status !== 0) throw new Error(`${task[0]} ${task[1].join(" ")} failed: ${result.stderr && "stderr: " + result.stderr.toString()}${result.stdout && "\nstdout: " + result.stdout.toString()}`); + if (result.status !== 0) { + throw new Error( + `${task[0]} ${task[1].join(" ")} failed: ${result.stderr && "stderr: " + result.stderr.toString()}${ + result.stdout && "\nstdout: " + result.stdout.toString() + }`, + ); + } console.log(result.stdout && result.stdout.toString()); lastResult = result; } diff --git a/scripts/update-experimental-branches.mjs b/scripts/update-experimental-branches.mjs index 3251d8a0a7d0e..5f2205f7a3c77 100644 --- a/scripts/update-experimental-branches.mjs +++ b/scripts/update-experimental-branches.mjs @@ -1,6 +1,10 @@ -import { Octokit } from "@octokit/rest"; +import { + Octokit, +} from "@octokit/rest"; -import { runSequence } from "./run-sequence.mjs"; +import { + runSequence, +} from "./run-sequence.mjs"; // The first is used by bot-based kickoffs, the second by automatic triggers const triggeredPR = process.env.SOURCE_ISSUE || process.env.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER; @@ -13,7 +17,7 @@ const triggeredPR = process.env.SOURCE_ISSUE || process.env.SYSTEM_PULLREQUEST_P */ async function main() { const gh = new Octokit({ - auth: process.argv[2] + auth: process.argv[2], }); const prnums = (await gh.issues.listForRepo({ labels: "typescript@experimental", @@ -50,7 +54,8 @@ async function main() { owner: "Microsoft", repo: "TypeScript", issue_number: num, - body: `This PR is configured as an experiment, and currently has rebase conflicts with main - please rebase onto main and fix the conflicts.` + body: + `This PR is configured as an experiment, and currently has rebase conflicts with main - please rebase onto main and fix the conflicts.`, }); } throw new Error(`Rebase conflict detected in PR ${num} with main`); // A PR is currently in conflict, give up @@ -61,7 +66,6 @@ async function main() { ["git", ["rebase", "main"]], ["git", ["push", "-f", "-u", "fork", `${num}`]], // Keep a rebased copy of this branch in our fork ]); - } else { throw new Error(`Invalid PR number: ${numRaw}`); @@ -83,7 +87,7 @@ async function main() { ]); // Simulate the merge and abort if there are conflicts const mergeTree = runSequence([ - ["git", ["merge-tree", mergeBase.trim(), branch, "experimental"]] + ["git", ["merge-tree", mergeBase.trim(), branch, "experimental"]], ]); if (mergeTree.indexOf(`===${"="}===`) >= 0) { // 7 equals is the center of the merge conflict marker throw new Error(`Merge conflict detected involving PR ${branch} with other experiment`); diff --git a/src/cancellationToken/cancellationToken.ts b/src/cancellationToken/cancellationToken.ts index 7f1b3998210e1..ff087607e1ef2 100644 --- a/src/cancellationToken/cancellationToken.ts +++ b/src/cancellationToken/cancellationToken.ts @@ -29,7 +29,7 @@ function createCancellationToken(args: string[]): ServerCancellationToken { return { isCancellationRequested: () => false, setRequest: (_requestId: number): void => void 0, - resetRequest: (_requestId: number): void => void 0 + resetRequest: (_requestId: number): void => void 0, }; } // cancellationPipeName is a string without '*' inside that can optionally end with '*' @@ -40,7 +40,9 @@ function createCancellationToken(args: string[]): ServerCancellationToken { if (cancellationPipeName.charAt(cancellationPipeName.length - 1) === "*") { const namePrefix = cancellationPipeName.slice(0, -1); if (namePrefix.length === 0 || namePrefix.indexOf("*") >= 0) { - throw new Error("Invalid name for template cancellation pipe: it should have length greater than 2 characters and contain only one '*'."); + throw new Error( + "Invalid name for template cancellation pipe: it should have length greater than 2 characters and contain only one '*'.", + ); } let perRequestPipeName: string | undefined; let currentRequestId: number; @@ -55,14 +57,14 @@ function createCancellationToken(args: string[]): ServerCancellationToken { throw new Error(`Mismatched request id, expected ${currentRequestId}, actual ${requestId}`); } perRequestPipeName = undefined; - } + }, }; } else { return { isCancellationRequested: () => pipeExists(cancellationPipeName!), // TODO: GH#18217 setRequest: (_requestId: number): void => void 0, - resetRequest: (_requestId: number): void => void 0 + resetRequest: (_requestId: number): void => void 0, }; } } diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index cefe7b9c88797..da6cf53bba1b4 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -313,7 +313,7 @@ import { unusedLabelIsError, VariableDeclaration, WhileStatement, - WithStatement + WithStatement, } from "./_namespaces/ts"; import * as performance from "./_namespaces/ts.performance"; @@ -321,7 +321,7 @@ import * as performance from "./_namespaces/ts.performance"; export const enum ModuleInstanceState { NonInstantiated = 0, Instantiated = 1, - ConstEnumOnly = 2 + ConstEnumOnly = 2, } interface ActiveLabel { @@ -333,7 +333,10 @@ interface ActiveLabel { } /** @internal */ -export function getModuleInstanceState(node: ModuleDeclaration, visited?: Map): ModuleInstanceState { +export function getModuleInstanceState( + node: ModuleDeclaration, + visited?: Map, +): ModuleInstanceState { if (node.body && !node.body.parent) { // getModuleInstanceStateForAliasTarget needs to walk up the parent chain, so parent pointers must be set on this tree already setParent(node.body, node); @@ -353,7 +356,10 @@ function getModuleInstanceStateCached(node: Node, visited = new Map): ModuleInstanceState { +function getModuleInstanceStateWorker( + node: Node, + visited: Map, +): ModuleInstanceState { // A module is uninstantiated if it contains only switch (node.kind) { // 1. interface declarations, type alias declarations @@ -376,7 +382,10 @@ function getModuleInstanceStateWorker(node: Node, visited: Map) { +function getModuleInstanceStateForAliasTarget( + specifier: ExportSpecifier, + visited: Map, +) { const name = specifier.propertyName || specifier.name; let p: Node | undefined = specifier.parent; while (p) { @@ -566,7 +578,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { * If so, the node _must_ be in the current file (as that's the only way anything could have traversed to it to yield it as the error node) * This version of `createDiagnosticForNode` uses the binder's context to account for this, and always yields correct diagnostics even in these situations. */ - function createDiagnosticForNode(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { + function createDiagnosticForNode( + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): DiagnosticWithLocation { return createDiagnosticForNodeInSourceFile(getSourceFileOfNode(node) || file, node, message, ...args); } @@ -637,16 +653,26 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { node.symbol = symbol; symbol.declarations = appendIfUnique(symbol.declarations, node); - if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) && !symbol.exports) { + if ( + symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) + && !symbol.exports + ) { symbol.exports = createSymbolTable(); } - if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && !symbol.members) { + if ( + symbolFlags + & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) + && !symbol.members + ) { symbol.members = createSymbolTable(); } // On merge of const enum module with class or function, reset const enum only flag (namespaces will already recalculate) - if (symbol.constEnumOnlyModule && (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum))) { + if ( + symbol.constEnumOnlyModule + && (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum)) + ) { symbol.constEnumOnlyModule = false; } @@ -659,14 +685,16 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // unless it is a well known Symbol. function getDeclarationName(node: Declaration): __String | undefined { if (node.kind === SyntaxKind.ExportAssignment) { - return (node as ExportAssignment).isExportEquals ? InternalSymbolName.ExportEquals : InternalSymbolName.Default; + return (node as ExportAssignment).isExportEquals ? InternalSymbolName.ExportEquals + : InternalSymbolName.Default; } const name = getNameOfDeclaration(node); if (name) { if (isAmbientModule(node)) { const moduleName = getTextOfIdentifierOrLiteral(name as Identifier | StringLiteral); - return (isGlobalScopeAugmentation(node as ModuleDeclaration) ? "__global" : `"${moduleName}"`) as __String; + return (isGlobalScopeAugmentation(node as ModuleDeclaration) ? "__global" + : `"${moduleName}"`) as __String; } if (name.kind === SyntaxKind.ComputedPropertyName) { const nameExpression = name.expression; @@ -715,7 +743,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // module.exports = ... return InternalSymbolName.ExportEquals; case SyntaxKind.BinaryExpression: - if (getAssignmentDeclarationKind(node as BinaryExpression) === AssignmentDeclarationKind.ModuleExports) { + if ( + getAssignmentDeclarationKind(node as BinaryExpression) === AssignmentDeclarationKind.ModuleExports + ) { // module.exports = ... return InternalSymbolName.ExportEquals; } @@ -726,7 +756,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { case SyntaxKind.Parameter: // Parameters with names are handled at the top of this function. Parameters // without names can only come from JSDocFunctionTypes. - Debug.assert(node.parent.kind === SyntaxKind.JSDocFunctionType, "Impossible parameter parent kind", () => `parent is: ${Debug.formatSyntaxKind(node.parent.kind)}, expected JSDocFunctionType`); + Debug.assert( + node.parent.kind === SyntaxKind.JSDocFunctionType, + "Impossible parameter parent kind", + () => `parent is: ${Debug.formatSyntaxKind(node.parent.kind)}, expected JSDocFunctionType`, + ); const functionType = node.parent as JSDocFunctionType; const index = functionType.parameters.indexOf(node as ParameterDeclaration); return "arg" + index as __String; @@ -734,7 +768,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } function getDisplayName(node: Declaration): string { - return isNamedDeclaration(node) ? declarationNameToString(node.name) : unescapeLeadingUnderscores(Debug.checkDefined(getDeclarationName(node))); + return isNamedDeclaration(node) ? declarationNameToString(node.name) + : unescapeLeadingUnderscores(Debug.checkDefined(getDeclarationName(node))); } /** @@ -745,10 +780,19 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { * @param includes - The SymbolFlags that node has in addition to its declaration type (eg: export, ambient, etc.) * @param excludes - The flags which node cannot be declared alongside in a symbol table. Used to report forbidden declarations. */ - function declareSymbol(symbolTable: SymbolTable, parent: Symbol | undefined, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags, isReplaceableByMethod?: boolean, isComputedName?: boolean): Symbol { + function declareSymbol( + symbolTable: SymbolTable, + parent: Symbol | undefined, + node: Declaration, + includes: SymbolFlags, + excludes: SymbolFlags, + isReplaceableByMethod?: boolean, + isComputedName?: boolean, + ): Symbol { Debug.assert(isComputedName || !hasDynamicName(node)); - const isDefaultExport = hasSyntacticModifier(node, ModifierFlags.Default) || isExportSpecifier(node) && node.name.escapedText === "default"; + const isDefaultExport = hasSyntacticModifier(node, ModifierFlags.Default) + || isExportSpecifier(node) && node.name.escapedText === "default"; // The exported symbol for an export default function/class node is always named "default" const name = isComputedName ? InternalSymbolName.Computed @@ -816,7 +860,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { let messageNeedsName = true; if (symbol.flags & SymbolFlags.Enum || includes & SymbolFlags.Enum) { - message = Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations; + message = + Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations; messageNeedsName = false; } @@ -835,8 +880,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // Error on multiple export default in the following case: // 1. multiple export default of class declaration or function declaration by checking NodeFlags.Default // 2. multiple export default of export assignment. This one doesn't have NodeFlags.Default on (as export default doesn't considered as modifiers) - if (symbol.declarations && symbol.declarations.length && - (node.kind === SyntaxKind.ExportAssignment && !(node as ExportAssignment).isExportEquals)) { + if ( + symbol.declarations && symbol.declarations.length + && (node.kind === SyntaxKind.ExportAssignment + && !(node as ExportAssignment).isExportEquals) + ) { message = Diagnostics.A_module_cannot_have_multiple_default_exports; messageNeedsName = false; multipleDefaultExports = true; @@ -845,24 +893,47 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } const relatedInformation: DiagnosticRelatedInformation[] = []; - if (isTypeAliasDeclaration(node) && nodeIsMissing(node.type) && hasSyntacticModifier(node, ModifierFlags.Export) && symbol.flags & (SymbolFlags.Alias | SymbolFlags.Type | SymbolFlags.Namespace)) { + if ( + isTypeAliasDeclaration(node) && nodeIsMissing(node.type) + && hasSyntacticModifier(node, ModifierFlags.Export) + && symbol.flags & (SymbolFlags.Alias | SymbolFlags.Type | SymbolFlags.Namespace) + ) { // export type T; - may have meant export type { T }? - relatedInformation.push(createDiagnosticForNode(node, Diagnostics.Did_you_mean_0, `export type { ${unescapeLeadingUnderscores(node.name.escapedText)} }`)); + relatedInformation.push( + createDiagnosticForNode( + node, + Diagnostics.Did_you_mean_0, + `export type { ${unescapeLeadingUnderscores(node.name.escapedText)} }`, + ), + ); } const declarationName = getNameOfDeclaration(node) || node; forEach(symbol.declarations, (declaration, index) => { const decl = getNameOfDeclaration(declaration) || declaration; - const diag = messageNeedsName ? createDiagnosticForNode(decl, message, getDisplayName(declaration)) : createDiagnosticForNode(decl, message); + const diag = messageNeedsName + ? createDiagnosticForNode(decl, message, getDisplayName(declaration)) + : createDiagnosticForNode(decl, message); file.bindDiagnostics.push( - multipleDefaultExports ? addRelatedInfo(diag, createDiagnosticForNode(declarationName, index === 0 ? Diagnostics.Another_export_default_is_here : Diagnostics.and_here)) : diag + multipleDefaultExports + ? addRelatedInfo( + diag, + createDiagnosticForNode( + declarationName, + index === 0 ? Diagnostics.Another_export_default_is_here : Diagnostics.and_here, + ), + ) : diag, ); if (multipleDefaultExports) { - relatedInformation.push(createDiagnosticForNode(decl, Diagnostics.The_first_export_default_is_here)); + relatedInformation.push( + createDiagnosticForNode(decl, Diagnostics.The_first_export_default_is_here), + ); } }); - const diag = messageNeedsName ? createDiagnosticForNode(declarationName, message, getDisplayName(node)) : createDiagnosticForNode(declarationName, message); + const diag = messageNeedsName + ? createDiagnosticForNode(declarationName, message, getDisplayName(node)) + : createDiagnosticForNode(declarationName, message); file.bindDiagnostics.push(addRelatedInfo(diag, ...relatedInformation)); symbol = createSymbol(SymbolFlags.None, name); @@ -882,9 +953,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { - const hasExportModifier = !!(getCombinedModifierFlags(node) & ModifierFlags.Export) || jsdocTreatAsExported(node); + const hasExportModifier = !!(getCombinedModifierFlags(node) & ModifierFlags.Export) + || jsdocTreatAsExported(node); if (symbolFlags & SymbolFlags.Alias) { - if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier)) { + if ( + node.kind === SyntaxKind.ExportSpecifier + || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier) + ) { return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); } else { @@ -910,12 +985,27 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed. if (isJSDocTypeAlias(node)) Debug.assert(isInJSFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file. if (!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) { - if (!canHaveLocals(container) || !container.locals || (hasSyntacticModifier(node, ModifierFlags.Default) && !getDeclarationName(node))) { - return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default! + if ( + !canHaveLocals(container) || !container.locals + || (hasSyntacticModifier(node, ModifierFlags.Default) && !getDeclarationName(node)) + ) { + return declareSymbol( + container.symbol.exports!, + container.symbol, + node, + symbolFlags, + symbolExcludes, + ); // No local symbol for an unnamed default! } const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0; const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes); - local.exportSymbol = declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); + local.exportSymbol = declareSymbol( + container.symbol.exports!, + container.symbol, + node, + symbolFlags, + symbolExcludes, + ); node.localSymbol = local; return local; } @@ -937,8 +1027,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // 2. The thing a nameless typedef pulls its name from is implicitly a direct export (either by assignment or actual export flag). const declName = getNameOfDeclaration(node); if (!declName) return false; - if (isPropertyAccessEntityNameExpression(declName.parent) && isTopLevelNamespaceAssignment(declName.parent)) return true; - if (isDeclaration(declName.parent) && getCombinedModifierFlags(declName.parent) & ModifierFlags.Export) return true; + if (isPropertyAccessEntityNameExpression(declName.parent) && isTopLevelNamespaceAssignment(declName.parent)) { + return true; + } + if (isDeclaration(declName.parent) && getCombinedModifierFlags(declName.parent) & ModifierFlags.Export) { + return true; + } // This could potentially be simplified by having `delayedBindJSDocTypedefTag` pass in an override for `hasExportModifier`, since it should // already have calculated and branched on most of this. return false; @@ -996,23 +1090,35 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { const saveExceptionTarget = currentExceptionTarget; const saveActiveLabelList = activeLabelList; const saveHasExplicitReturn = hasExplicitReturn; - const isImmediatelyInvoked = - (containerFlags & ContainerFlags.IsFunctionExpression && - !hasSyntacticModifier(node, ModifierFlags.Async) && - !(node as FunctionLikeDeclaration).asteriskToken && - !!getImmediatelyInvokedFunctionExpression(node)) || - node.kind === SyntaxKind.ClassStaticBlockDeclaration; + const isImmediatelyInvoked = ( + containerFlags & ContainerFlags.IsFunctionExpression + && !hasSyntacticModifier(node, ModifierFlags.Async) + && !(node as FunctionLikeDeclaration).asteriskToken + && !!getImmediatelyInvokedFunctionExpression(node) + ) || node.kind === SyntaxKind.ClassStaticBlockDeclaration; // A non-async, non-generator IIFE is considered part of the containing control flow. Return statements behave // similarly to break statements that exit to a label just past the statement body. if (!isImmediatelyInvoked) { currentFlow = initFlowNode({ flags: FlowFlags.Start }); - if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor)) { - currentFlow.node = node as FunctionExpression | ArrowFunction | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration; + if ( + containerFlags + & (ContainerFlags.IsFunctionExpression + | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor) + ) { + currentFlow.node = node as + | FunctionExpression + | ArrowFunction + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration; } } // We create a return control flow graph for IIFEs and constructors. For constructors // we use the return control flow graph in strict property initialization checks. - currentReturnTarget = isImmediatelyInvoked || node.kind === SyntaxKind.Constructor || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined; + currentReturnTarget = isImmediatelyInvoked || node.kind === SyntaxKind.Constructor + || (isInJSFile(node) + && (node.kind === SyntaxKind.FunctionDeclaration + || node.kind === SyntaxKind.FunctionExpression)) ? createBranchLabel() : undefined; currentExceptionTarget = undefined; currentBreakTarget = undefined; currentContinueTarget = undefined; @@ -1021,7 +1127,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { bindChildren(node); // Reset all reachability check related flags on node (for incremental scenarios) node.flags &= ~NodeFlags.ReachabilityAndEmitFlags; - if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).body)) { + if ( + !(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike + && nodeIsPresent((node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).body) + ) { node.flags |= NodeFlags.HasImplicitReturn; if (hasExplicitReturn) node.flags |= NodeFlags.HasExplicitReturn; (node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).endFlowNode = currentFlow; @@ -1034,7 +1143,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (currentReturnTarget) { addAntecedent(currentReturnTarget, currentFlow); currentFlow = finishFlowLabel(currentReturnTarget); - if (node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration || (isInJSFile(node) && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression))) { + if ( + node.kind === SyntaxKind.Constructor || node.kind === SyntaxKind.ClassStaticBlockDeclaration + || (isInJSFile(node) + && (node.kind === SyntaxKind.FunctionDeclaration + || node.kind === SyntaxKind.FunctionExpression)) + ) { (node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).returnFlowNode = currentFlow; } } @@ -1091,7 +1205,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { inAssignmentPattern = saveInAssignmentPattern; return; } - if (node.kind >= SyntaxKind.FirstStatement && node.kind <= SyntaxKind.LastStatement && !options.allowUnreachableCode) { + if ( + node.kind >= SyntaxKind.FirstStatement && node.kind <= SyntaxKind.LastStatement + && !options.allowUnreachableCode + ) { (node as HasFlowNode).flowNode = currentFlow; } switch (node.kind) { @@ -1225,7 +1342,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { case SyntaxKind.BinaryExpression: return isNarrowingBinaryExpression(expr as BinaryExpression); case SyntaxKind.PrefixUnaryExpression: - return (expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken && isNarrowingExpression((expr as PrefixUnaryExpression).operand); + return (expr as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken + && isNarrowingExpression((expr as PrefixUnaryExpression).operand); case SyntaxKind.TypeOfExpression: return isNarrowingExpression((expr as TypeOfExpression).expression); } @@ -1234,9 +1352,14 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function isNarrowableReference(expr: Expression): boolean { return isDottedName(expr) - || (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression) - || isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right) - || isElementAccessExpression(expr) && (isStringOrNumericLiteralLike(expr.argumentExpression) || isEntityNameExpression(expr.argumentExpression)) && isNarrowableReference(expr.expression) + || (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) + && isNarrowableReference(expr.expression) + || isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken + && isNarrowableReference(expr.right) + || isElementAccessExpression(expr) + && (isStringOrNumericLiteralLike(expr.argumentExpression) + || isEntityNameExpression(expr.argumentExpression)) + && isNarrowableReference(expr.expression) || isAssignmentExpression(expr) && isNarrowableReference(expr.left); } @@ -1252,8 +1375,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } } } - if (expr.expression.kind === SyntaxKind.PropertyAccessExpression && - containsNarrowableReference((expr.expression as PropertyAccessExpression).expression)) { + if ( + expr.expression.kind === SyntaxKind.PropertyAccessExpression + && containsNarrowableReference((expr.expression as PropertyAccessExpression).expression) + ) { return true; } return false; @@ -1274,8 +1399,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { case SyntaxKind.ExclamationEqualsToken: case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: - return isNarrowableOperand(expr.left) || isNarrowableOperand(expr.right) || - isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right); + return isNarrowableOperand(expr.left) || isNarrowableOperand(expr.right) + || isNarrowingTypeofOperands(expr.right, expr.left) + || isNarrowingTypeofOperands(expr.left, expr.right); case SyntaxKind.InstanceOfKeyword: return isNarrowableOperand(expr.left); case SyntaxKind.InKeyword: @@ -1332,9 +1458,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (!expression) { return flags & FlowFlags.TrueCondition ? antecedent : unreachableFlow; } - if ((expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition || - expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) && - !isExpressionOfOptionalChainRoot(expression) && !isNullishCoalesce(expression.parent)) { + if ( + (expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition + || expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) + && !isExpressionOfOptionalChainRoot(expression) && !isNullishCoalesce(expression.parent) + ) { return unreachableFlow; } if (!isNarrowingExpression(expression)) { @@ -1344,12 +1472,21 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return initFlowNode({ flags, antecedent, node: expression }); } - function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode { + function createFlowSwitchClause( + antecedent: FlowNode, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + ): FlowNode { setFlowNodeReferenced(antecedent); return initFlowNode({ flags: FlowFlags.SwitchClause, antecedent, switchStatement, clauseStart, clauseEnd }); } - function createFlowMutation(flags: FlowFlags, antecedent: FlowNode, node: Expression | VariableDeclaration | ArrayBindingElement): FlowNode { + function createFlowMutation( + flags: FlowFlags, + antecedent: FlowNode, + node: Expression | VariableDeclaration | ArrayBindingElement, + ): FlowNode { setFlowNodeReferenced(antecedent); const result = initFlowNode({ flags, antecedent, node }); if (currentExceptionTarget) { @@ -1393,7 +1530,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (node.kind === SyntaxKind.ParenthesizedExpression) { node = (node as ParenthesizedExpression).expression; } - else if (node.kind === SyntaxKind.PrefixUnaryExpression && (node as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken) { + else if ( + node.kind === SyntaxKind.PrefixUnaryExpression + && (node as PrefixUnaryExpression).operator === SyntaxKind.ExclamationToken + ) { node = (node as PrefixUnaryExpression).operand; } else { @@ -1407,16 +1547,23 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } function isTopLevelLogicalExpression(node: Node): boolean { - while (isParenthesizedExpression(node.parent) || - isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.ExclamationToken) { + while ( + isParenthesizedExpression(node.parent) + || isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.ExclamationToken + ) { node = node.parent; } - return !isStatementCondition(node) && - !isLogicalExpression(node.parent) && - !(isOptionalChain(node.parent) && node.parent.expression === node); + return !isStatementCondition(node) + && !isLogicalExpression(node.parent) + && !(isOptionalChain(node.parent) && node.parent.expression === node); } - function doWithConditionalBranches(action: (value: T) => void, value: T, trueTarget: FlowLabel, falseTarget: FlowLabel) { + function doWithConditionalBranches( + action: (value: T) => void, + value: T, + trueTarget: FlowLabel, + falseTarget: FlowLabel, + ) { const savedTrueTarget = currentTrueTarget; const savedFalseTarget = currentFalseTarget; currentTrueTarget = trueTarget; @@ -1428,7 +1575,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function bindCondition(node: Expression | undefined, trueTarget: FlowLabel, falseTarget: FlowLabel) { doWithConditionalBranches(bind, node, trueTarget, falseTarget); - if (!node || !isLogicalAssignmentExpression(node) && !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node))) { + if ( + !node + || !isLogicalAssignmentExpression(node) && !isLogicalExpression(node) + && !(isOptionalChain(node) && isOutermostOptionalChain(node)) + ) { addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node)); addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node)); } @@ -1548,7 +1699,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return undefined; } - function bindBreakOrContinueFlow(node: BreakOrContinueStatement, breakTarget: FlowLabel | undefined, continueTarget: FlowLabel | undefined) { + function bindBreakOrContinueFlow( + node: BreakOrContinueStatement, + breakTarget: FlowLabel | undefined, + continueTarget: FlowLabel | undefined, + ) { const flowLabel = node.kind === SyntaxKind.BreakStatement ? breakTarget : continueTarget; if (flowLabel) { addAntecedent(flowLabel, currentFlow); @@ -1619,7 +1774,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // set of antecedents for the pre-finally label. As control flow analysis passes by a ReduceLabel // node, the pre-finally label is temporarily switched to the reduced antecedent set. const finallyLabel = createBranchLabel(); - finallyLabel.antecedents = concatenate(concatenate(normalExitLabel.antecedents, exceptionLabel.antecedents), returnLabel.antecedents); + finallyLabel.antecedents = concatenate( + concatenate(normalExitLabel.antecedents, exceptionLabel.antecedents), + returnLabel.antecedents, + ); currentFlow = finallyLabel; bind(node.finallyBlock); if (currentFlow.flags & FlowFlags.Unreachable) { @@ -1630,17 +1788,24 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // If we have an IIFE return target and return statements in the try or catch blocks, add a control // flow that goes back through the finally block and back through only the return statements. if (currentReturnTarget && returnLabel.antecedents) { - addAntecedent(currentReturnTarget, createReduceLabel(finallyLabel, returnLabel.antecedents, currentFlow)); + addAntecedent( + currentReturnTarget, + createReduceLabel(finallyLabel, returnLabel.antecedents, currentFlow), + ); } // If we have an outer exception target (i.e. a containing try-finally or try-catch-finally), add a // control flow that goes back through the finally blok and back through each possible exception source. if (currentExceptionTarget && exceptionLabel.antecedents) { - addAntecedent(currentExceptionTarget, createReduceLabel(finallyLabel, exceptionLabel.antecedents, currentFlow)); + addAntecedent( + currentExceptionTarget, + createReduceLabel(finallyLabel, exceptionLabel.antecedents, currentFlow), + ); } // If the end of the finally block is reachable, but the end of the try and catch blocks are not, // convert the current flow to unreachable. For example, 'try { return 1; } finally { ... }' should // result in an unreachable current control flow. - currentFlow = normalExitLabel.antecedents ? createReduceLabel(finallyLabel, normalExitLabel.antecedents, currentFlow) : unreachableFlow; + currentFlow = normalExitLabel.antecedents + ? createReduceLabel(finallyLabel, normalExitLabel.antecedents, currentFlow) : unreachableFlow; } } else { @@ -1681,13 +1846,20 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { i++; } const preCaseLabel = createBranchLabel(); - addAntecedent(preCaseLabel, isNarrowingSwitch ? createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1) : preSwitchCaseFlow!); + addAntecedent( + preCaseLabel, + isNarrowingSwitch ? createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1) + : preSwitchCaseFlow!, + ); addAntecedent(preCaseLabel, fallthroughFlow); currentFlow = finishFlowLabel(preCaseLabel); const clause = clauses[i]; bind(clause); fallthroughFlow = currentFlow; - if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) { + if ( + !(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 + && options.noFallthroughCasesInSwitch + ) { clause.fallthroughFlowNode = currentFlow; } } @@ -1724,7 +1896,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { name: node.label.escapedText, breakTarget: postStatementLabel, continueTarget: undefined, - referenced: false + referenced: false, }; bind(node.label); bind(node.statement); @@ -1737,7 +1909,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } function bindDestructuringTargetFlow(node: Expression) { - if (node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { bindAssignmentTargetFlow((node as BinaryExpression).left); } else { @@ -1776,7 +1951,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function bindLogicalLikeExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) { const preRightLabel = createBranchLabel(); - if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || node.operatorToken.kind === SyntaxKind.AmpersandAmpersandEqualsToken) { + if ( + node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken + || node.operatorToken.kind === SyntaxKind.AmpersandAmpersandEqualsToken + ) { bindCondition(node.left, preRightLabel, falseTarget); } else { @@ -1868,7 +2046,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { stackIndex: 0, skip: false, inStrictModeStack: [undefined], - parentStack: [undefined] + parentStack: [undefined], }; } // TODO: bindLogicalExpression is recursive - if we want to handle deeply nested `&&` expressions @@ -2149,7 +2327,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { const propertyAccess = node.expression as PropertyAccessExpression; - if (isIdentifier(propertyAccess.name) && isNarrowableOperand(propertyAccess.expression) && isPushOrUnshiftIdentifier(propertyAccess.name)) { + if ( + isIdentifier(propertyAccess.name) && isNarrowableOperand(propertyAccess.expression) + && isPushOrUnshiftIdentifier(propertyAccess.name) + ) { currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node); } } @@ -2163,7 +2344,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { lastContainer = next; } - function declareSymbolAndAddToSymbolTable(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol | undefined { + function declareSymbolAndAddToSymbolTable( + node: Declaration, + symbolFlags: SymbolFlags, + symbolExcludes: SymbolFlags, + ): Symbol | undefined { switch (container.kind) { // Modules, source files, and classes need specialized handling for how their // members are declared (for example, a member of a class will go into a specific @@ -2255,7 +2440,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { setExportContextFlag(node); if (isAmbientModule(node)) { if (hasSyntacticModifier(node, ModifierFlags.Export)) { - errorOnFirstToken(node, Diagnostics.export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible); + errorOnFirstToken( + node, + Diagnostics + .export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible, + ); } if (isModuleAugmentationExternal(node)) { declareModuleSymbol(node); @@ -2266,12 +2455,23 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { const { text } = node.name; pattern = tryParsePattern(text); if (pattern === undefined) { - errorOnFirstToken(node.name, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, text); + errorOnFirstToken( + node.name, + Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, + text, + ); } } - const symbol = declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes)!; - file.patternAmbientModules = append(file.patternAmbientModules, pattern && !isString(pattern) ? { pattern, symbol } : undefined); + const symbol = declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.ValueModule, + SymbolFlags.ValueModuleExcludes, + )!; + file.patternAmbientModules = append( + file.patternAmbientModules, + pattern && !isString(pattern) ? { pattern, symbol } : undefined, + ); } } else { @@ -2279,7 +2479,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (state !== ModuleInstanceState.NonInstantiated) { const { symbol } = node; // if module was already merged with some function, class or non-const enum, treat it as non-const-enum-only - symbol.constEnumOnlyModule = (!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum))) + symbol.constEnumOnlyModule = + (!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum))) // Current must be `const enum` only && state === ModuleInstanceState.ConstEnumOnly // Can't have been set to 'false' in a previous merged symbol. ('undefined' OK) @@ -2291,9 +2492,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function declareModuleSymbol(node: ModuleDeclaration): ModuleInstanceState { const state = getModuleInstanceState(node); const instantiated = state !== ModuleInstanceState.NonInstantiated; - declareSymbolAndAddToSymbolTable(node, + declareSymbolAndAddToSymbolTable( + node, instantiated ? SymbolFlags.ValueModule : SymbolFlags.NamespaceModule, - instantiated ? SymbolFlags.ValueModuleExcludes : SymbolFlags.NamespaceModuleExcludes); + instantiated ? SymbolFlags.ValueModuleExcludes : SymbolFlags.NamespaceModuleExcludes, + ); return state; } @@ -2372,12 +2575,23 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { parent = typeAlias; bind(typeAlias.typeExpression); const declName = getNameOfDeclaration(typeAlias); - if ((isJSDocEnumTag(typeAlias) || !typeAlias.fullName) && declName && isPropertyAccessEntityNameExpression(declName.parent)) { + if ( + (isJSDocEnumTag(typeAlias) || !typeAlias.fullName) && declName + && isPropertyAccessEntityNameExpression(declName.parent) + ) { // typedef anchored to an A.B.C assignment - we need to bind into B's namespace under name C const isTopLevel = isTopLevelNamespaceAssignment(declName.parent); if (isTopLevel) { - bindPotentiallyMissingNamespaces(file.symbol, declName.parent, isTopLevel, - !!findAncestor(declName, d => isPropertyAccessExpression(d) && d.name.escapedText === "prototype"), /*containerIsClass*/ false); + bindPotentiallyMissingNamespaces( + file.symbol, + declName.parent, + isTopLevel, + !!findAncestor( + declName, + d => isPropertyAccessExpression(d) && d.name.escapedText === "prototype", + ), + /*containerIsClass*/ false, + ); const oldContainer = container; switch (getAssignmentDeclarationPropertyAccessKind(declName.parent)) { case AssignmentDeclarationKind.ExportsProperty: @@ -2397,7 +2611,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { break; case AssignmentDeclarationKind.Property: container = isExportsOrModuleExportsOrAlias(file, declName.parent.expression) ? file - : isPropertyAccessExpression(declName.parent.expression) ? declName.parent.expression.name + : isPropertyAccessExpression(declName.parent.expression) + ? declName.parent.expression.name : declName.parent.expression; break; case AssignmentDeclarationKind.None: @@ -2409,7 +2624,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { container = oldContainer; } } - else if (isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier) { + else if ( + isJSDocEnumTag(typeAlias) || !typeAlias.fullName || typeAlias.fullName.kind === SyntaxKind.Identifier + ) { parent = typeAlias.parent; bindBlockScopedDeclaration(typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); } @@ -2429,39 +2646,55 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // [Yield] or [Await] contexts, respectively. function checkContextualIdentifier(node: Identifier) { // Report error only if there are no parse errors in file - if (!file.parseDiagnostics.length && - !(node.flags & NodeFlags.Ambient) && - !(node.flags & NodeFlags.JSDoc) && - !isIdentifierName(node)) { - + if ( + !file.parseDiagnostics.length + && !(node.flags & NodeFlags.Ambient) + && !(node.flags & NodeFlags.JSDoc) + && !isIdentifierName(node) + ) { // strict mode identifiers const originalKeywordKind = identifierToKeywordKind(node); if (originalKeywordKind === undefined) { return; } - if (inStrictMode && - originalKeywordKind >= SyntaxKind.FirstFutureReservedWord && - originalKeywordKind <= SyntaxKind.LastFutureReservedWord) { - file.bindDiagnostics.push(createDiagnosticForNode(node, - getStrictModeIdentifierMessage(node), declarationNameToString(node))); + if ( + inStrictMode + && originalKeywordKind >= SyntaxKind.FirstFutureReservedWord + && originalKeywordKind <= SyntaxKind.LastFutureReservedWord + ) { + file.bindDiagnostics.push( + createDiagnosticForNode(node, getStrictModeIdentifierMessage(node), declarationNameToString(node)), + ); } else if (originalKeywordKind === SyntaxKind.AwaitKeyword) { if (isExternalModule(file) && isInTopLevelContext(node)) { - file.bindDiagnostics.push(createDiagnosticForNode(node, - Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, - declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, + declarationNameToString(node), + ), + ); } else if (node.flags & NodeFlags.AwaitContext) { - file.bindDiagnostics.push(createDiagnosticForNode(node, - Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, - declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, + declarationNameToString(node), + ), + ); } } else if (originalKeywordKind === SyntaxKind.YieldKeyword && node.flags & NodeFlags.YieldContext) { - file.bindDiagnostics.push(createDiagnosticForNode(node, - Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, - declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, + declarationNameToString(node), + ), + ); } } } @@ -2470,11 +2703,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // Provide specialized messages to help the user understand why we think they're in // strict mode. if (getContainingClass(node)) { - return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode; + return Diagnostics + .Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode; } if (file.externalModuleIndicator) { - return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode; + return Diagnostics + .Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode; } return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode; @@ -2486,8 +2721,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (node.escapedText === "#constructor") { // Report error only if there are no parse errors in file if (!file.parseDiagnostics.length) { - file.bindDiagnostics.push(createDiagnosticForNode(node, - Diagnostics.constructor_is_a_reserved_word, declarationNameToString(node))); + file.bindDiagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.constructor_is_a_reserved_word, + declarationNameToString(node), + ), + ); } } } @@ -2514,7 +2754,14 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // When a delete operator occurs within strict mode code, a SyntaxError is thrown if its // UnaryExpression is a direct reference to a variable, function argument, or function name const span = getErrorSpanForNode(file, node.expression); - file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode)); + file.bindDiagnostics.push( + createFileDiagnostic( + file, + span.start, + span.length, + Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode, + ), + ); } } @@ -2529,8 +2776,15 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // We check first if the name is inside class declaration or class expression; if so give explicit message // otherwise report generic error message. const span = getErrorSpanForNode(file, name); - file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, - getStrictModeEvalOrArgumentsMessage(contextNode), idText(identifier))); + file.bindDiagnostics.push( + createFileDiagnostic( + file, + span.start, + span.length, + getStrictModeEvalOrArgumentsMessage(contextNode), + idText(identifier), + ), + ); } } } @@ -2539,7 +2793,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // Provide specialized messages to help the user understand why we think they're in // strict mode. if (getContainingClass(node)) { - return Diagnostics.Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode; + return Diagnostics + .Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode; } if (file.externalModuleIndicator) { @@ -2560,11 +2815,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // Provide specialized messages to help the user understand why we think they're in // strict mode. if (getContainingClass(node)) { - return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Class_definitions_are_automatically_in_strict_mode; + return Diagnostics + .Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Class_definitions_are_automatically_in_strict_mode; } if (file.externalModuleIndicator) { - return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Modules_are_automatically_in_strict_mode; + return Diagnostics + .Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_Modules_are_automatically_in_strict_mode; } return Diagnostics.Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5; @@ -2573,14 +2830,22 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function checkStrictModeFunctionDeclaration(node: FunctionDeclaration) { if (languageVersion < ScriptTarget.ES2015) { // Report error if function is not top level function declaration - if (blockScopeContainer.kind !== SyntaxKind.SourceFile && - blockScopeContainer.kind !== SyntaxKind.ModuleDeclaration && - !isFunctionLikeOrClassStaticBlockDeclaration(blockScopeContainer)) { + if ( + blockScopeContainer.kind !== SyntaxKind.SourceFile + && blockScopeContainer.kind !== SyntaxKind.ModuleDeclaration + && !isFunctionLikeOrClassStaticBlockDeclaration(blockScopeContainer) + ) { // We check first if the name is inside class declaration or class expression; if so give explicit message // otherwise report generic error message. const errorSpan = getErrorSpanForNode(file, node); - file.bindDiagnostics.push(createFileDiagnostic(file, errorSpan.start, errorSpan.length, - getStrictModeBlockScopeFunctionDeclarationMessage(node))); + file.bindDiagnostics.push( + createFileDiagnostic( + file, + errorSpan.start, + errorSpan.length, + getStrictModeBlockScopeFunctionDeclarationMessage(node), + ), + ); } } } @@ -2629,7 +2894,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { errorOrSuggestionOnRange(isError, node, node, message); } - function errorOrSuggestionOnRange(isError: boolean, startNode: Node, endNode: Node, message: DiagnosticMessage): void { + function errorOrSuggestionOnRange( + isError: boolean, + startNode: Node, + endNode: Node, + message: DiagnosticMessage, + ): void { addErrorOrSuggestionDiagnostic(isError, { pos: getTokenPosOfNode(startNode, file), end: endNode.end }, message); } @@ -2639,7 +2909,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { file.bindDiagnostics.push(diag); } else { - file.bindSuggestionDiagnostics = append(file.bindSuggestionDiagnostics, { ...diag, category: DiagnosticCategory.Suggestion }); + file.bindSuggestionDiagnostics = append(file.bindSuggestionDiagnostics, { + ...diag, + category: DiagnosticCategory.Suggestion, + }); } } @@ -2750,7 +3023,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { while (parentNode && !isJSDocTypeAlias(parentNode)) { parentNode = parentNode.parent; } - bindBlockScopedDeclaration(parentNode as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); + bindBlockScopedDeclaration( + parentNode as Declaration, + SymbolFlags.TypeAlias, + SymbolFlags.TypeAliasExcludes, + ); break; } // falls through @@ -2781,12 +3058,19 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (isSpecialPropertyDeclaration(expr)) { bindSpecialPropertyDeclaration(expr); } - if (isInJSFile(expr) && - file.commonJsModuleIndicator && - isModuleExportsAccessExpression(expr) && - !lookupSymbolForName(blockScopeContainer, "module" as __String)) { - declareSymbol(file.locals!, /*parent*/ undefined, expr.expression, - SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, SymbolFlags.FunctionScopedVariableExcludes); + if ( + isInJSFile(expr) + && file.commonJsModuleIndicator + && isModuleExportsAccessExpression(expr) + && !lookupSymbolForName(blockScopeContainer, "module" as __String) + ) { + declareSymbol( + file.locals!, + /*parent*/ undefined, + expr.expression, + SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, + SymbolFlags.FunctionScopedVariableExcludes, + ); } break; case SyntaxKind.BinaryExpression: @@ -2799,7 +3083,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { bindModuleExportsAssignment(node as BindablePropertyAssignmentExpression); break; case AssignmentDeclarationKind.PrototypeProperty: - bindPrototypePropertyAssignment((node as BindableStaticPropertyAssignmentExpression).left, node); + bindPrototypePropertyAssignment( + (node as BindableStaticPropertyAssignmentExpression).left, + node, + ); break; case AssignmentDeclarationKind.Prototype: bindPrototypeAssignment(node as BindableStaticPropertyAssignmentExpression); @@ -2856,9 +3143,17 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return bindPropertyWorker(node as PropertyDeclaration | PropertySignature); case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.Property, + SymbolFlags.PropertyExcludes, + ); case SyntaxKind.EnumMember: - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.EnumMember, + SymbolFlags.EnumMemberExcludes, + ); case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: @@ -2870,16 +3165,32 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // as other properties in the object literal. So we use SymbolFlags.PropertyExcludes // so that it will conflict with any other object literal members with the same // name. - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.Method | ((node as MethodDeclaration).questionToken ? SymbolFlags.Optional : SymbolFlags.None), - isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.Method + | ((node as MethodDeclaration).questionToken ? SymbolFlags.Optional : SymbolFlags.None), + isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes, + ); case SyntaxKind.FunctionDeclaration: return bindFunctionDeclaration(node as FunctionDeclaration); case SyntaxKind.Constructor: - return declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Constructor, /*symbolExcludes:*/ SymbolFlags.None); + return declareSymbolAndAddToSymbolTable( + node as Declaration, + SymbolFlags.Constructor, + /*symbolExcludes:*/ SymbolFlags.None, + ); case SyntaxKind.GetAccessor: - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.GetAccessor, + SymbolFlags.GetAccessorExcludes, + ); case SyntaxKind.SetAccessor: - return bindPropertyOrMethodOrAccessor(node as Declaration, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes); + return bindPropertyOrMethodOrAccessor( + node as Declaration, + SymbolFlags.SetAccessor, + SymbolFlags.SetAccessorExcludes, + ); case SyntaxKind.FunctionType: case SyntaxKind.JSDocFunctionType: case SyntaxKind.JSDocSignature: @@ -2923,9 +3234,17 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { inStrictMode = true; return bindClassLikeDeclaration(node as ClassLikeDeclaration); case SyntaxKind.InterfaceDeclaration: - return bindBlockScopedDeclaration(node as Declaration, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes); + return bindBlockScopedDeclaration( + node as Declaration, + SymbolFlags.Interface, + SymbolFlags.InterfaceExcludes, + ); case SyntaxKind.TypeAliasDeclaration: - return bindBlockScopedDeclaration(node as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); + return bindBlockScopedDeclaration( + node as Declaration, + SymbolFlags.TypeAlias, + SymbolFlags.TypeAliasExcludes, + ); case SyntaxKind.EnumDeclaration: return bindEnumDeclaration(node as EnumDeclaration); case SyntaxKind.ModuleDeclaration: @@ -2941,7 +3260,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { case SyntaxKind.NamespaceImport: case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: - return declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Alias, SymbolFlags.AliasExcludes); + return declareSymbolAndAddToSymbolTable( + node as Declaration, + SymbolFlags.Alias, + SymbolFlags.AliasExcludes, + ); case SyntaxKind.NamespaceExportDeclaration: return bindNamespaceExportDeclaration(node as NamespaceExportDeclaration); case SyntaxKind.ImportClause: @@ -2971,14 +3294,17 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // falls through case SyntaxKind.JSDocPropertyTag: const propTag = node as JSDocPropertyLikeTag; - const flags = propTag.isBracketed || propTag.typeExpression && propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType ? - SymbolFlags.Property | SymbolFlags.Optional : - SymbolFlags.Property; + const flags = propTag.isBracketed + || propTag.typeExpression && propTag.typeExpression.type.kind === SyntaxKind.JSDocOptionalType + ? SymbolFlags.Property | SymbolFlags.Optional + : SymbolFlags.Property; return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes); case SyntaxKind.JSDocTypedefTag: case SyntaxKind.JSDocCallbackTag: case SyntaxKind.JSDocEnumTag: - return (delayedTypeAliases || (delayedTypeAliases = [])).push(node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag); + return (delayedTypeAliases || (delayedTypeAliases = [])).push( + node as JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag, + ); case SyntaxKind.JSDocOverloadTag: return bind((node as JSDocOverloadTag).typeExpression); } @@ -2988,7 +3314,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { const isAutoAccessor = isAutoAccessorPropertyDeclaration(node); const includes = isAutoAccessor ? SymbolFlags.Accessor : SymbolFlags.Property; const excludes = isAutoAccessor ? SymbolFlags.AccessorExcludes : SymbolFlags.PropertyExcludes; - return bindPropertyOrMethodOrAccessor(node, includes | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), excludes); + return bindPropertyOrMethodOrAccessor( + node, + includes | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), + excludes, + ); } function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral) { @@ -3065,7 +3395,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // declareSymbol walks up parents to find name text, parent _must_ be set // but won't be set by the normal binder walk until `bindChildren` later on. setParent(node.exportClause, node); - declareSymbol(container.symbol.exports, container.symbol, node.exportClause, SymbolFlags.Alias, SymbolFlags.AliasExcludes); + declareSymbol( + container.symbol.exports, + container.symbol, + node.exportClause, + SymbolFlags.Alias, + SymbolFlags.AliasExcludes, + ); } } @@ -3117,7 +3453,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return symbol; }); if (symbol) { - const isAlias = isAliasableExpression(node.right) && (isExportsIdentifier(node.left.expression) || isModuleExportsAccessExpression(node.left.expression)); + const isAlias = isAliasableExpression(node.right) + && (isExportsIdentifier(node.left.expression) || isModuleExportsAccessExpression(node.left.expression)); const flags = isAlias ? SymbolFlags.Alias : SymbolFlags.Property | SymbolFlags.ExportValue; setParent(node.left, node); declareSymbol(symbol.exports!, symbol, node.left, flags, SymbolFlags.None); @@ -3133,11 +3470,17 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return; } const assignedExpression = getRightMostAssignedExpression(node.right); - if (isEmptyObjectLiteral(assignedExpression) || container === file && isExportsOrModuleExportsOrAlias(file, assignedExpression)) { + if ( + isEmptyObjectLiteral(assignedExpression) + || container === file && isExportsOrModuleExportsOrAlias(file, assignedExpression) + ) { return; } - if (isObjectLiteralExpression(assignedExpression) && every(assignedExpression.properties, isShorthandPropertyAssignment)) { + if ( + isObjectLiteralExpression(assignedExpression) + && every(assignedExpression.properties, isShorthandPropertyAssignment) + ) { forEach(assignedExpression.properties, bindExportAssignedObjectMemberAlias); return; } @@ -3146,29 +3489,51 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { const flags = exportAssignmentIsAlias(node) ? SymbolFlags.Alias // An export= with an EntityNameExpression or a ClassExpression exports all meanings of that identifier or class : SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule; - const symbol = declareSymbol(file.symbol.exports!, file.symbol, node, flags | SymbolFlags.Assignment, SymbolFlags.None); + const symbol = declareSymbol( + file.symbol.exports!, + file.symbol, + node, + flags | SymbolFlags.Assignment, + SymbolFlags.None, + ); setValueDeclaration(symbol, node); } function bindExportAssignedObjectMemberAlias(node: ShorthandPropertyAssignment) { - declareSymbol(file.symbol.exports!, file.symbol, node, SymbolFlags.Alias | SymbolFlags.Assignment, SymbolFlags.None); - } - - function bindThisPropertyAssignment(node: BindablePropertyAssignmentExpression | PropertyAccessExpression | LiteralLikeElementAccessExpression) { + declareSymbol( + file.symbol.exports!, + file.symbol, + node, + SymbolFlags.Alias | SymbolFlags.Assignment, + SymbolFlags.None, + ); + } + + function bindThisPropertyAssignment( + node: BindablePropertyAssignmentExpression | PropertyAccessExpression | LiteralLikeElementAccessExpression, + ) { Debug.assert(isInJSFile(node)); // private identifiers *must* be declared (even in JS files) - const hasPrivateIdentifier = (isBinaryExpression(node) && isPropertyAccessExpression(node.left) && isPrivateIdentifier(node.left.name)) + const hasPrivateIdentifier = + (isBinaryExpression(node) && isPropertyAccessExpression(node.left) && isPrivateIdentifier(node.left.name)) || (isPropertyAccessExpression(node) && isPrivateIdentifier(node.name)); if (hasPrivateIdentifier) { return; } - const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const thisContainer = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); switch (thisContainer.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: let constructorSymbol: Symbol | undefined = thisContainer.symbol; // For `f.prototype.m = function() { this.x = 0; }`, `this.x = 0` should modify `f`'s members, not the function expression. - if (isBinaryExpression(thisContainer.parent) && thisContainer.parent.operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + isBinaryExpression(thisContainer.parent) + && thisContainer.parent.operatorToken.kind === SyntaxKind.EqualsToken + ) { const l = thisContainer.parent.left; if (isBindableStaticAccessExpression(l) && isPrototypeAccess(l.expression)) { constructorSymbol = lookupSymbolForPropertyAccess(l.expression.expression, thisParentContainer); @@ -3183,7 +3548,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { bindDynamicallyNamedThisPropertyAssignment(node, constructorSymbol, constructorSymbol.members); } else { - declareSymbol(constructorSymbol.members, constructorSymbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property); + declareSymbol( + constructorSymbol.members, + constructorSymbol, + node, + SymbolFlags.Property | SymbolFlags.Assignment, + SymbolFlags.PropertyExcludes & ~SymbolFlags.Property, + ); } addDeclarationToSymbol(constructorSymbol, constructorSymbol.valueDeclaration, SymbolFlags.Class); } @@ -3198,12 +3569,20 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // this.foo assignment in a JavaScript class // Bind this property to the containing class const containingClass = thisContainer.parent; - const symbolTable = isStatic(thisContainer) ? containingClass.symbol.exports! : containingClass.symbol.members!; + const symbolTable = isStatic(thisContainer) ? containingClass.symbol.exports! + : containingClass.symbol.members!; if (hasDynamicName(node)) { bindDynamicallyNamedThisPropertyAssignment(node, containingClass.symbol, symbolTable); } else { - declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.None, /*isReplaceableByMethod*/ true); + declareSymbol( + symbolTable, + containingClass.symbol, + node, + SymbolFlags.Property | SymbolFlags.Assignment, + SymbolFlags.None, + /*isReplaceableByMethod*/ true, + ); } break; case SyntaxKind.SourceFile: @@ -3212,10 +3591,20 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { break; } else if (thisContainer.commonJsModuleIndicator) { - declareSymbol(thisContainer.symbol.exports!, thisContainer.symbol, node, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None); + declareSymbol( + thisContainer.symbol.exports!, + thisContainer.symbol, + node, + SymbolFlags.Property | SymbolFlags.ExportValue, + SymbolFlags.None, + ); } else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes); + declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.FunctionScopedVariable, + SymbolFlags.FunctionScopedVariableExcludes, + ); } break; // Namespaces are not allowed in javascript files, so do nothing here @@ -3226,14 +3615,32 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } } - function bindDynamicallyNamedThisPropertyAssignment(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol, symbolTable: SymbolTable) { - declareSymbol(symbolTable, symbol, node, SymbolFlags.Property, SymbolFlags.None, /*isReplaceableByMethod*/ true, /*isComputedName*/ true); + function bindDynamicallyNamedThisPropertyAssignment( + node: BinaryExpression | DynamicNamedDeclaration, + symbol: Symbol, + symbolTable: SymbolTable, + ) { + declareSymbol( + symbolTable, + symbol, + node, + SymbolFlags.Property, + SymbolFlags.None, + /*isReplaceableByMethod*/ true, + /*isComputedName*/ true, + ); addLateBoundAssignmentDeclarationToSymbol(node, symbol); } - function addLateBoundAssignmentDeclarationToSymbol(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol | undefined) { + function addLateBoundAssignmentDeclarationToSymbol( + node: BinaryExpression | DynamicNamedDeclaration, + symbol: Symbol | undefined, + ) { if (symbol) { - (symbol.assignmentDeclarationMembers || (symbol.assignmentDeclarationMembers = new Map())).set(getNodeId(node), node); + (symbol.assignmentDeclarationMembers || (symbol.assignmentDeclarationMembers = new Map())).set( + getNodeId(node), + node, + ); } } @@ -3255,11 +3662,18 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function bindPrototypeAssignment(node: BindableStaticPropertyAssignmentExpression) { setParent(node.left, node); setParent(node.right, node); - bindPropertyAssignment(node.left.expression, node.left, /*isPrototypeProperty*/ false, /*containerIsClass*/ true); + bindPropertyAssignment( + node.left.expression, + node.left, + /*isPrototypeProperty*/ false, + /*containerIsClass*/ true, + ); } function bindObjectDefinePrototypeProperty(node: BindableObjectDefinePropertyCall) { - const namespaceSymbol = lookupSymbolForPropertyAccess((node.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression); + const namespaceSymbol = lookupSymbolForPropertyAccess( + (node.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression, + ); if (namespaceSymbol && namespaceSymbol.valueDeclaration) { // Ensure the namespace symbol becomes class-like addDeclarationToSymbol(namespaceSymbol, namespaceSymbol.valueDeclaration, SymbolFlags.Class); @@ -3288,24 +3702,36 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function bindObjectDefinePropertyAssignment(node: BindableObjectDefinePropertyCall) { let namespaceSymbol = lookupSymbolForPropertyAccess(node.arguments[0]); const isToplevel = node.parent.parent.kind === SyntaxKind.SourceFile; - namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, node.arguments[0], isToplevel, /*isPrototypeProperty*/ false, /*containerIsClass*/ false); + namespaceSymbol = bindPotentiallyMissingNamespaces( + namespaceSymbol, + node.arguments[0], + isToplevel, + /*isPrototypeProperty*/ false, + /*containerIsClass*/ false, + ); bindPotentiallyNewExpandoMemberToNamespace(node, namespaceSymbol, /*isPrototypeProperty*/ false); } function bindSpecialPropertyAssignment(node: BindablePropertyAssignmentExpression) { // Class declarations in Typescript do not allow property declarations - const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression, container) || lookupSymbolForPropertyAccess(node.left.expression, blockScopeContainer) ; + const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression, container) + || lookupSymbolForPropertyAccess(node.left.expression, blockScopeContainer); if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) { return; } const rootExpr = getLeftmostAccessExpression(node.left); - if (isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)?.flags! & SymbolFlags.Alias) { + if ( + isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)?.flags! & SymbolFlags.Alias + ) { return; } // Fix up parent pointers since we're going to use these nodes before we bind into them setParent(node.left, node); setParent(node.right, node); - if (isIdentifier(node.left.expression) && container === file && isExportsOrModuleExportsOrAlias(file, node.left.expression)) { + if ( + isIdentifier(node.left.expression) && container === file + && isExportsOrModuleExportsOrAlias(file, node.left.expression) + ) { // This can be an alias for the 'exports' or 'module.exports' names, e.g. // var util = module.exports; // util.property = function ... @@ -3313,7 +3739,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } else if (hasDynamicName(node)) { bindAnonymousDeclaration(node, SymbolFlags.Property | SymbolFlags.Assignment, InternalSymbolName.Computed); - const sym = bindPotentiallyMissingNamespaces(parentSymbol, node.left.expression, isTopLevelNamespaceAssignment(node.left), /*isPrototypeProperty*/ false, /*containerIsClass*/ false); + const sym = bindPotentiallyMissingNamespaces( + parentSymbol, + node.left.expression, + isTopLevelNamespaceAssignment(node.left), + /*isPrototypeProperty*/ false, + /*containerIsClass*/ false, + ); addLateBoundAssignmentDeclarationToSymbol(node, sym); } else { @@ -3331,7 +3763,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { bindPropertyAssignment(node.expression, node, /*isPrototypeProperty*/ false, /*containerIsClass*/ false); } - function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: BindableStaticNameExpression, isToplevel: boolean, isPrototypeProperty: boolean, containerIsClass: boolean) { + function bindPotentiallyMissingNamespaces( + namespaceSymbol: Symbol | undefined, + entityName: BindableStaticNameExpression, + isToplevel: boolean, + isPrototypeProperty: boolean, + containerIsClass: boolean, + ) { if (namespaceSymbol?.flags! & SymbolFlags.Alias) { return namespaceSymbol; } @@ -3345,8 +3783,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return symbol; } else { - const table = parent ? parent.exports! : - file.jsGlobalAugmentations || (file.jsGlobalAugmentations = createSymbolTable()); + const table = parent ? parent.exports! + : file.jsGlobalAugmentations || (file.jsGlobalAugmentations = createSymbolTable()); return declareSymbol(table, parent, id, flags, excludeFlags); } }); @@ -3357,15 +3795,19 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return namespaceSymbol; } - function bindPotentiallyNewExpandoMemberToNamespace(declaration: BindableStaticAccessExpression | CallExpression, namespaceSymbol: Symbol | undefined, isPrototypeProperty: boolean) { + function bindPotentiallyNewExpandoMemberToNamespace( + declaration: BindableStaticAccessExpression | CallExpression, + namespaceSymbol: Symbol | undefined, + isPrototypeProperty: boolean, + ) { if (!namespaceSymbol || !isExpandoSymbol(namespaceSymbol)) { return; } // Set up the members collection if it doesn't exist already - const symbolTable = isPrototypeProperty ? - (namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) : - (namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable())); + const symbolTable = isPrototypeProperty + ? (namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) + : (namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable())); let includes = SymbolFlags.None; let excludes = SymbolFlags.None; @@ -3376,19 +3818,23 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } // Maybe accessor-like else if (isCallExpression(declaration) && isBindableObjectDefinePropertyCall(declaration)) { - if (some(declaration.arguments[2].properties, p => { - const id = getNameOfDeclaration(p); - return !!id && isIdentifier(id) && idText(id) === "set"; - })) { + if ( + some(declaration.arguments[2].properties, p => { + const id = getNameOfDeclaration(p); + return !!id && isIdentifier(id) && idText(id) === "set"; + }) + ) { // We mix in `SymbolFLags.Property` so in the checker `getTypeOfVariableParameterOrProperty` is used for this // symbol, instead of `getTypeOfAccessor` (which will assert as there is no real accessor declaration) includes |= SymbolFlags.SetAccessor | SymbolFlags.Property; excludes |= SymbolFlags.SetAccessorExcludes; } - if (some(declaration.arguments[2].properties, p => { - const id = getNameOfDeclaration(p); - return !!id && isIdentifier(id) && idText(id) === "get"; - })) { + if ( + some(declaration.arguments[2].properties, p => { + const id = getNameOfDeclaration(p); + return !!id && isIdentifier(id) && idText(id) === "get"; + }) + ) { includes |= SymbolFlags.GetAccessor | SymbolFlags.Property; excludes |= SymbolFlags.GetAccessorExcludes; } @@ -3399,7 +3845,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { excludes = SymbolFlags.PropertyExcludes; } - declareSymbol(symbolTable, namespaceSymbol, declaration, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment); + declareSymbol( + symbolTable, + namespaceSymbol, + declaration, + includes | SymbolFlags.Assignment, + excludes & ~SymbolFlags.Assignment, + ); } function isTopLevelNamespaceAssignment(propertyAccess: BindableAccessExpression) { @@ -3408,10 +3860,22 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { : propertyAccess.parent.parent.kind === SyntaxKind.SourceFile; } - function bindPropertyAssignment(name: BindableStaticNameExpression, propertyAccess: BindableStaticAccessExpression, isPrototypeProperty: boolean, containerIsClass: boolean) { - let namespaceSymbol = lookupSymbolForPropertyAccess(name, container) || lookupSymbolForPropertyAccess(name, blockScopeContainer); + function bindPropertyAssignment( + name: BindableStaticNameExpression, + propertyAccess: BindableStaticAccessExpression, + isPrototypeProperty: boolean, + containerIsClass: boolean, + ) { + let namespaceSymbol = lookupSymbolForPropertyAccess(name, container) + || lookupSymbolForPropertyAccess(name, blockScopeContainer); const isToplevel = isTopLevelNamespaceAssignment(propertyAccess); - namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty, containerIsClass); + namespaceSymbol = bindPotentiallyMissingNamespaces( + namespaceSymbol, + propertyAccess.expression, + isToplevel, + isPrototypeProperty, + containerIsClass, + ); bindPotentiallyNewExpandoMemberToNamespace(propertyAccess, namespaceSymbol, isPrototypeProperty); } @@ -3433,15 +3897,22 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (node && isCallExpression(node)) { return !!getAssignedExpandoInitializer(node); } - let init = !node ? undefined : - isVariableDeclaration(node) ? node.initializer : - isBinaryExpression(node) ? node.right : - isPropertyAccessExpression(node) && isBinaryExpression(node.parent) ? node.parent.right : - undefined; + let init = !node ? undefined + : isVariableDeclaration(node) ? node.initializer + : isBinaryExpression(node) ? node.right + : isPropertyAccessExpression(node) && isBinaryExpression(node.parent) ? node.parent.right + : undefined; init = init && getRightMostAssignedExpression(init); if (init) { - const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node!) ? node.name : isBinaryExpression(node!) ? node.left : node!); - return !!getExpandoInitializer(isBinaryExpression(init) && (init.operatorToken.kind === SyntaxKind.BarBarToken || init.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? init.right : init, isPrototypeAssignment); + const isPrototypeAssignment = isPrototypeAccess( + isVariableDeclaration(node!) ? node.name : isBinaryExpression(node!) ? node.left : node!, + ); + return !!getExpandoInitializer( + isBinaryExpression(init) + && (init.operatorToken.kind === SyntaxKind.BarBarToken + || init.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? init.right : init, + isPrototypeAssignment, + ); } return false; } @@ -3453,7 +3924,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { return expr.parent; } - function lookupSymbolForPropertyAccess(node: BindableStaticNameExpression, lookupContainer: IsContainer | IsBlockScopedContainer | EntityNameExpression = container): Symbol | undefined { + function lookupSymbolForPropertyAccess( + node: BindableStaticNameExpression, + lookupContainer: IsContainer | IsBlockScopedContainer | EntityNameExpression = container, + ): Symbol | undefined { if (isIdentifier(node)) { return lookupSymbolForName(lookupContainer, node.escapedText); } @@ -3463,7 +3937,11 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } } - function forEachIdentifierInEntityName(e: BindableStaticNameExpression, parent: Symbol | undefined, action: (e: Declaration, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined { + function forEachIdentifierInEntityName( + e: BindableStaticNameExpression, + parent: Symbol | undefined, + action: (e: Declaration, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined, + ): Symbol | undefined { if (isExportsOrModuleExportsOrAlias(file, e)) { return file.symbol; } @@ -3519,7 +3997,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (node.name) { setParent(node.name, node); } - file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations![0], Diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol))); + file.bindDiagnostics.push( + createDiagnosticForNode( + symbolExport.declarations![0], + Diagnostics.Duplicate_identifier_0, + symbolName(prototypeSymbol), + ), + ); } symbol.exports!.set(prototypeSymbol.escapedName, prototypeSymbol); prototypeSymbol.parent = symbol; @@ -3538,16 +4022,21 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (!isBindingPattern(node.name)) { const possibleVariableDecl = node.kind === SyntaxKind.VariableDeclaration ? node : node.parent.parent; - if (isInJSFile(node) && - shouldResolveJsRequire(options) && - isVariableDeclarationInitializedToBareOrAccessedRequire(possibleVariableDecl) && - !getJSDocTypeTag(node) && - !(getCombinedModifierFlags(node) & ModifierFlags.Export) + if ( + isInJSFile(node) + && shouldResolveJsRequire(options) + && isVariableDeclarationInitializedToBareOrAccessedRequire(possibleVariableDecl) + && !getJSDocTypeTag(node) + && !(getCombinedModifierFlags(node) & ModifierFlags.Export) ) { declareSymbolAndAddToSymbolTable(node as Declaration, SymbolFlags.Alias, SymbolFlags.AliasExcludes); } else if (isBlockOrCatchScoped(node)) { - bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes); + bindBlockScopedDeclaration( + node, + SymbolFlags.BlockScopedVariable, + SymbolFlags.BlockScopedVariableExcludes, + ); } else if (isParameterDeclaration(node)) { // It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration @@ -3559,10 +4048,18 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // function foo([a,a]) {} // Duplicate Identifier error // function bar(a,a) {} // Duplicate Identifier error, parameter declaration in this case is handled in bindParameter // // which correctly set excluded symbols - declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes); + declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.FunctionScopedVariable, + SymbolFlags.ParameterExcludes, + ); } else { - declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes); + declareSymbolAndAddToSymbolTable( + node, + SymbolFlags.FunctionScopedVariable, + SymbolFlags.FunctionScopedVariableExcludes, + ); } } } @@ -3578,7 +4075,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } if (isBindingPattern(node.name)) { - bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + (node as ParameterDeclaration).parent.parameters.indexOf(node as ParameterDeclaration) as __String); + bindAnonymousDeclaration( + node, + SymbolFlags.FunctionScopedVariable, + "__" + + (node as ParameterDeclaration).parent.parameters.indexOf(node as ParameterDeclaration) as __String, + ); } else { declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes); @@ -3588,7 +4090,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // containing class. if (isParameterPropertyDeclaration(node, node.parent)) { const classDeclaration = node.parent.parent; - declareSymbol(classDeclaration.symbol.members!, classDeclaration.symbol, node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes); + declareSymbol( + classDeclaration.symbol.members!, + classDeclaration.symbol, + node, + SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), + SymbolFlags.PropertyExcludes, + ); } } @@ -3638,7 +4146,10 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } function getInferTypeContainer(node: Node): ConditionalTypeNode | undefined { - const extendsType = findAncestor(node, n => n.parent && isConditionalTypeNode(n.parent) && n.parent.extendsType === n); + const extendsType = findAncestor( + node, + n => n.parent && isConditionalTypeNode(n.parent) && n.parent.extendsType === n, + ); return extendsType && extendsType.parent as ConditionalTypeNode; } @@ -3648,7 +4159,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (container) { Debug.assertNode(container, canHaveLocals); container.locals ??= createSymbolTable(); - declareSymbol(container.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); + declareSymbol( + container.locals, + /*parent*/ undefined, + node, + SymbolFlags.TypeParameter, + SymbolFlags.TypeParameterExcludes, + ); } else { declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); @@ -3659,7 +4176,13 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (container) { Debug.assertNode(container, canHaveLocals); container.locals ??= createSymbolTable(); - declareSymbol(container.locals, /*parent*/ undefined, node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); + declareSymbol( + container.locals, + /*parent*/ undefined, + node, + SymbolFlags.TypeParameter, + SymbolFlags.TypeParameterExcludes, + ); } else { bindAnonymousDeclaration(node, SymbolFlags.TypeParameter, getDeclarationName(node)!); // TODO: GH#18217 @@ -3674,7 +4197,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean { const instanceState = getModuleInstanceState(node); - return instanceState === ModuleInstanceState.Instantiated || (instanceState === ModuleInstanceState.ConstEnumOnly && shouldPreserveConstEnums(options)); + return instanceState === ModuleInstanceState.Instantiated + || (instanceState === ModuleInstanceState.ConstEnumOnly && shouldPreserveConstEnums(options)); } function checkUnreachable(node: Node): boolean { @@ -3684,11 +4208,12 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (currentFlow === unreachableFlow) { const reportError = // report error on all statements except empty ones - (isStatementButNotDeclaration(node) && node.kind !== SyntaxKind.EmptyStatement) || + (isStatementButNotDeclaration(node) && node.kind !== SyntaxKind.EmptyStatement) // report error on class declarations - node.kind === SyntaxKind.ClassDeclaration || + || node.kind === SyntaxKind.ClassDeclaration // report error on instantiated modules or const-enums only modules if preserveConstEnums is set - (node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(node as ModuleDeclaration)); + || (node.kind === SyntaxKind.ModuleDeclaration + && shouldReportErrorOnModuleDeclaration(node as ModuleDeclaration)); if (reportError) { currentFlow = reportedUnreachableFlow; @@ -3703,16 +4228,19 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { // - node is not block scoped variable statement and at least one variable declaration has initializer // Rationale: we don't want to report errors on non-initialized var's since they are hoisted // On the other side we do want to report errors on non-initialized 'lets' because of TDZ - const isError = - unreachableCodeIsError(options) && - !(node.flags & NodeFlags.Ambient) && - ( - !isVariableStatement(node) || - !!(getCombinedNodeFlags(node.declarationList) & NodeFlags.BlockScoped) || - node.declarationList.declarations.some(d => !!d.initializer) + const isError = unreachableCodeIsError(options) + && !(node.flags & NodeFlags.Ambient) + && ( + !isVariableStatement(node) + || !!(getCombinedNodeFlags(node.declarationList) & NodeFlags.BlockScoped) + || node.declarationList.declarations.some(d => !!d.initializer) ); - eachUnreachableRange(node, (start, end) => errorOrSuggestionOnRange(isError, start, end, Diagnostics.Unreachable_code_detected)); + eachUnreachableRange( + node, + (start, end) => + errorOrSuggestionOnRange(isError, start, end, Diagnostics.Unreachable_code_detected), + ); } } } @@ -3733,9 +4261,10 @@ function eachUnreachableRange(node: Node, cb: (start: Node, last: Node) => void) // As opposed to a pure declaration like an `interface` function isExecutableStatement(s: Statement): boolean { // Don't remove statements that can validly be used before they appear. - return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) && + return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) // `var x;` may declare a variable used above - !(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.BlockScoped)) && s.declarationList.declarations.some(d => !d.initializer)); + && !(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.BlockScoped)) + && s.declarationList.declarations.some(d => !d.initializer)); } function isPurelyTypeDeclaration(s: Statement): boolean { @@ -3765,7 +4294,10 @@ export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Ex } else if (isIdentifier(node)) { const symbol = lookupSymbolForName(sourceFile, node.escapedText); - if (!!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && !!symbol.valueDeclaration.initializer) { + if ( + !!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) + && !!symbol.valueDeclaration.initializer + ) { const init = symbol.valueDeclaration.initializer; q.enqueue(init); if (isAssignmentExpression(init, /*excludeCompoundAssignment*/ true)) { @@ -3806,7 +4338,8 @@ export function getContainerFlags(node: Node): ContainerFlags { case SyntaxKind.SetAccessor: case SyntaxKind.MethodDeclaration: if (isObjectLiteralOrClassExpressionMethodOrAccessor(node)) { - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor; + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals + | ContainerFlags.IsFunctionLike | ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor; } // falls through case SyntaxKind.Constructor: @@ -3819,11 +4352,13 @@ export function getContainerFlags(node: Node): ContainerFlags { case SyntaxKind.ConstructSignature: case SyntaxKind.ConstructorType: case SyntaxKind.ClassStaticBlockDeclaration: - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike; + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals + | ContainerFlags.IsFunctionLike; case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression; + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals + | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression; case SyntaxKind.ModuleBlock: return ContainerFlags.IsControlFlowContainer; @@ -3854,7 +4389,8 @@ export function getContainerFlags(node: Node): ContainerFlags { // By not creating a new block-scoped-container here, we ensure that both 'var x' // and 'let x' go into the Function-container's locals, and we do get a collision // conflict. - return isFunctionLike(node.parent) || isClassStaticBlockDeclaration(node.parent) ? ContainerFlags.None : ContainerFlags.IsBlockScopedContainer | ContainerFlags.HasLocals; + return isFunctionLike(node.parent) || isClassStaticBlockDeclaration(node.parent) ? ContainerFlags.None + : ContainerFlags.IsBlockScopedContainer | ContainerFlags.HasLocals; } return ContainerFlags.None; diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 7eae60d4e434b..a0ef7833271ec 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -90,7 +90,7 @@ import { export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation { /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ reportsUnnecessary?: {}; - reportDeprecated?: {} + reportDeprecated?: {}; source?: string; relatedInformation?: ReusableDiagnosticRelatedInformation[]; skippedOn?: keyof CompilerOptions; @@ -176,6 +176,7 @@ export interface ReusableBuilderProgramState extends BuilderState { bundle?: BundleBuildInfo; } +// dprint-ignore /** @internal */ export const enum BuilderFileEmit { None = 0, @@ -250,15 +251,18 @@ export interface BuilderProgramState extends BuilderState, ReusableBuilderProgra } /** @internal */ -export type SavedBuildProgramEmitState = Pick & { changedFilesSet: BuilderProgramState["changedFilesSet"] | undefined }; +export type SavedBuildProgramEmitState = + & Pick< + BuilderProgramState, + | "affectedFilesPendingEmit" + | "seenEmittedFiles" + | "programEmitPending" + | "emitSignatures" + | "outSignature" + | "latestChangedDtsFile" + | "hasChangedEmitSignature" + > + & { changedFilesSet: BuilderProgramState["changedFilesSet"] | undefined; }; /** * Get flags determining what all needs to be emitted @@ -280,8 +284,12 @@ export function getBuilderFileEmit(options: CompilerOptions) { * * @internal */ -export function getPendingEmitKind(optionsOrEmitKind: CompilerOptions | BuilderFileEmit, oldOptionsOrEmitKind: CompilerOptions | BuilderFileEmit | undefined): BuilderFileEmit { - const oldEmitKind = oldOptionsOrEmitKind && (isNumber(oldOptionsOrEmitKind) ? oldOptionsOrEmitKind : getBuilderFileEmit(oldOptionsOrEmitKind)); +export function getPendingEmitKind( + optionsOrEmitKind: CompilerOptions | BuilderFileEmit, + oldOptionsOrEmitKind: CompilerOptions | BuilderFileEmit | undefined, +): BuilderFileEmit { + const oldEmitKind = oldOptionsOrEmitKind + && (isNumber(oldOptionsOrEmitKind) ? oldOptionsOrEmitKind : getBuilderFileEmit(oldOptionsOrEmitKind)); const emitKind = isNumber(optionsOrEmitKind) ? optionsOrEmitKind : getBuilderFileEmit(optionsOrEmitKind); if (oldEmitKind === emitKind) return BuilderFileEmit.None; if (!oldEmitKind || !emitKind) return emitKind; @@ -294,16 +302,28 @@ export function getPendingEmitKind(optionsOrEmitKind: CompilerOptions | BuilderF return result; } -function hasSameKeys(map1: ReadonlyCollection | undefined, map2: ReadonlyCollection | undefined): boolean { +function hasSameKeys( + map1: ReadonlyCollection | undefined, + map2: ReadonlyCollection | undefined, +): boolean { // Has same size and every key is present in both maps - return map1 === map2 || map1 !== undefined && map2 !== undefined && map1.size === map2.size && !forEachKey(map1, key => !map2.has(key)); + return map1 === map2 + || map1 !== undefined && map2 !== undefined && map1.size === map2.size + && !forEachKey(map1, key => !map2.has(key)); } /** * Create the state so that we can iterate on changedFiles/affected files */ -function createBuilderProgramState(newProgram: Program, oldState: Readonly | undefined): BuilderProgramState { - const state = BuilderState.create(newProgram, oldState, /*disableUseFileVersionAsSignature*/ false) as BuilderProgramState; +function createBuilderProgramState( + newProgram: Program, + oldState: Readonly | undefined, +): BuilderProgramState { + const state = BuilderState.create( + newProgram, + oldState, + /*disableUseFileVersionAsSignature*/ false, + ) as BuilderProgramState; state.program = newProgram; const compilerOptions = newProgram.getCompilerOptions(); state.compilerOptions = compilerOptions; @@ -312,26 +332,30 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly state.changedFilesSet.add(value)); @@ -349,24 +373,32 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly { let oldInfo: Readonly | undefined; let newReferences: ReadonlySet | undefined; // if not using old state, every file is changed - if (!useOldState || + if ( + !useOldState // File wasn't present in old state - !(oldInfo = oldState!.fileInfos.get(sourceFilePath)) || + || !(oldInfo = oldState!.fileInfos.get(sourceFilePath)) // versions dont match - oldInfo.version !== info.version || + || oldInfo.version !== info.version // Implied formats dont match - oldInfo.impliedFormat !== info.impliedFormat || + || oldInfo.impliedFormat !== info.impliedFormat // Referenced files changed - !hasSameKeys(newReferences = referencedMap && referencedMap.getValues(sourceFilePath), oldReferencedMap && oldReferencedMap.getValues(sourceFilePath)) || + || !hasSameKeys( + newReferences = referencedMap && referencedMap.getValues(sourceFilePath), + oldReferencedMap && oldReferencedMap.getValues(sourceFilePath), + ) // Referenced file was deleted in the new program - newReferences && forEachKey(newReferences, path => !state.fileInfos.has(path) && oldState!.fileInfos.has(path))) { + || newReferences + && forEachKey(newReferences, path => !state.fileInfos.has(path) && oldState!.fileInfos.has(path)) + ) { // Register file as changed file and do not copy semantic diagnostics, since all changed files need to be re-evaluated addFileToChangeSet(state, sourceFilePath); } @@ -381,9 +413,9 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly { - if (state.fileInfos.has(sourceFilePath)) return false; - if (outFilePath || info.affectsGlobalScope) return true; - // if file is deleted we need to write buildInfo again - state.buildInfoEmitPending = true; - return false; - })) { + if ( + useOldState && forEachEntry(oldState!.fileInfos, (info, sourceFilePath) => { + if (state.fileInfos.has(sourceFilePath)) return false; + if (outFilePath || info.affectsGlobalScope) return true; + // if file is deleted we need to write buildInfo again + state.buildInfoEmitPending = true; + return false; + }) + ) { BuilderState.getAllFilesExcludingDefaultLibraryFile(state, newProgram, /*firstSourceFile*/ undefined) .forEach(file => addFileToChangeSet(state, file.resolvedPath)); } else if (oldCompilerOptions) { // If options affect emit, then we need to do complete emit per compiler options // otherwise only the js or dts that needs to emitted because its different from previously emitted options - const pendingEmitKind = compilerOptionsAffectEmit(compilerOptions, oldCompilerOptions) ? - getBuilderFileEmit(compilerOptions) : - getPendingEmitKind(compilerOptions, oldCompilerOptions); + const pendingEmitKind = compilerOptionsAffectEmit(compilerOptions, oldCompilerOptions) + ? getBuilderFileEmit(compilerOptions) + : getPendingEmitKind(compilerOptions, oldCompilerOptions); if (pendingEmitKind !== BuilderFileEmit.None) { if (!outFilePath) { // Add all files to affectedFilesPendingEmit since emit changed @@ -425,7 +462,7 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly !!ref.prepend)) state.programEmitPending = getBuilderFileEmit(compilerOptions); + if (some(newProgram.getProjectReferences(), ref => !!ref.prepend)) { + state.programEmitPending = getBuilderFileEmit(compilerOptions); + } } return state; } @@ -460,22 +499,31 @@ function addFileToChangeSet(state: BuilderProgramState, path: Path) { * Covert to Emit signature based on oldOptions and EmitSignature format * If d.ts map options differ then swap the format, otherwise use as is */ -function getEmitSignatureFromOldSignature(options: CompilerOptions, oldOptions: CompilerOptions, oldEmitSignature: EmitSignature): EmitSignature { - return !!options.declarationMap === !!oldOptions.declarationMap ? +function getEmitSignatureFromOldSignature( + options: CompilerOptions, + oldOptions: CompilerOptions, + oldEmitSignature: EmitSignature, +): EmitSignature { + return !!options.declarationMap === !!oldOptions.declarationMap // Use same format of signature - oldEmitSignature : + ? oldEmitSignature // Convert to different format - isString(oldEmitSignature) ? [oldEmitSignature] : oldEmitSignature[0]; + : isString(oldEmitSignature) ? [oldEmitSignature] : oldEmitSignature[0]; } function repopulateDiagnostics(diagnostics: readonly Diagnostic[], newProgram: Program): readonly Diagnostic[] { if (!diagnostics.length) return diagnostics; return sameMap(diagnostics, diag => { if (isString(diag.messageText)) return diag; - const repopulatedChain = convertOrRepopulateDiagnosticMessageChain(diag.messageText, diag.file, newProgram, chain => chain.repopulateInfo?.()); - return repopulatedChain === diag.messageText ? - diag : - { ...diag, messageText: repopulatedChain }; + const repopulatedChain = convertOrRepopulateDiagnosticMessageChain( + diag.messageText, + diag.file, + newProgram, + chain => chain.repopulateInfo?.(), + ); + return repopulatedChain === diag.messageText + ? diag + : { ...diag, messageText: repopulatedChain }; }); } @@ -488,56 +536,97 @@ function convertOrRepopulateDiagnosticMessageChain( +function convertOrRepopulateDiagnosticMessageChainArray< + T extends DiagnosticMessageChain | ReusableDiagnosticMessageChain, +>( array: T[] | undefined, sourceFile: SourceFile | undefined, newProgram: Program, repopulateInfo: (chain: T) => RepopulateDiagnosticChainInfo | undefined, ): DiagnosticMessageChain[] | undefined { - return sameMap(array, chain => convertOrRepopulateDiagnosticMessageChain(chain, sourceFile, newProgram, repopulateInfo)); + return sameMap( + array, + chain => convertOrRepopulateDiagnosticMessageChain(chain, sourceFile, newProgram, repopulateInfo), + ); } function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newProgram: Program): readonly Diagnostic[] { if (!diagnostics.length) return emptyArray; let buildInfoDirectory: string | undefined; return diagnostics.map(diagnostic => { - const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, newProgram, toPathInBuildInfoDirectory); + const result: Diagnostic = convertToDiagnosticRelatedInformation( + diagnostic, + newProgram, + toPathInBuildInfoDirectory, + ); result.reportsUnnecessary = diagnostic.reportsUnnecessary; result.reportsDeprecated = diagnostic.reportDeprecated; result.source = diagnostic.source; result.skippedOn = diagnostic.skippedOn; const { relatedInformation } = diagnostic; - result.relatedInformation = relatedInformation ? - relatedInformation.length ? - relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram, toPathInBuildInfoDirectory)) : - [] : - undefined; + result.relatedInformation = relatedInformation + ? relatedInformation.length + ? relatedInformation.map(r => + convertToDiagnosticRelatedInformation(r, newProgram, toPathInBuildInfoDirectory) + ) + : [] + : undefined; return result; }); function toPathInBuildInfoDirectory(path: string) { - buildInfoDirectory ??= getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(newProgram.getCompilerOptions())!, newProgram.getCurrentDirectory())); + buildInfoDirectory ??= getDirectoryPath( + getNormalizedAbsolutePath( + getTsBuildInfoEmitOutputFilePath(newProgram.getCompilerOptions())!, + newProgram.getCurrentDirectory(), + ), + ); return toPath(path, buildInfoDirectory, newProgram.getCanonicalFileName); } } -function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation { +function convertToDiagnosticRelatedInformation( + diagnostic: ReusableDiagnosticRelatedInformation, + newProgram: Program, + toPath: (path: string) => Path, +): DiagnosticRelatedInformation { const { file } = diagnostic; const sourceFile = file ? newProgram.getSourceFileByPath(toPath(file)) : undefined; return { ...diagnostic, file: sourceFile, - messageText: isString(diagnostic.messageText) ? - diagnostic.messageText : - convertOrRepopulateDiagnosticMessageChain(diagnostic.messageText, sourceFile, newProgram, chain => (chain as ReusableRepopulateModuleNotFoundChain).info), + messageText: isString(diagnostic.messageText) + ? diagnostic.messageText + : convertOrRepopulateDiagnosticMessageChain( + diagnostic.messageText, + sourceFile, + newProgram, + chain => (chain as ReusableRepopulateModuleNotFoundChain).info, + ), }; } @@ -580,7 +669,10 @@ function restoreBuilderProgramEmitState(state: BuilderProgramState, savedEmitSta * Verifies that source file is ok to be used in calls that arent handled by next */ function assertSourceFileOkWithoutNextAffectedCall(state: BuilderProgramState, sourceFile: SourceFile | undefined) { - Debug.assert(!sourceFile || !state.affectedFiles || state.affectedFiles[state.affectedFilesIndex! - 1] !== sourceFile || !state.semanticDiagnosticsPerFile!.has(sourceFile.resolvedPath)); + Debug.assert( + !sourceFile || !state.affectedFiles || state.affectedFiles[state.affectedFilesIndex! - 1] !== sourceFile + || !state.semanticDiagnosticsPerFile!.has(sourceFile.resolvedPath), + ); } /** @@ -592,7 +684,7 @@ function assertSourceFileOkWithoutNextAffectedCall(state: BuilderProgramState, s function getNextAffectedFile( state: BuilderProgramState, cancellationToken: CancellationToken | undefined, - host: BuilderProgramHost + host: BuilderProgramHost, ): SourceFile | Program | undefined { while (true) { const { affectedFiles } = state; @@ -604,12 +696,16 @@ function getNextAffectedFile( if (!seenAffectedFiles.has(affectedFile.resolvedPath)) { // Set the next affected file as seen and remove the cached semantic diagnostics state.affectedFilesIndex = affectedFilesIndex; - addToAffectedFilesPendingEmit(state, affectedFile.resolvedPath, getBuilderFileEmit(state.compilerOptions)); + addToAffectedFilesPendingEmit( + state, + affectedFile.resolvedPath, + getBuilderFileEmit(state.compilerOptions), + ); handleDtsMayChangeOfAffectedFile( state, affectedFile, cancellationToken, - host + host, ); return affectedFile; } @@ -690,10 +786,9 @@ function removeDiagnosticsOfLibraryFiles(state: BuilderProgramState) { const program = Debug.checkDefined(state.program); const options = program.getCompilerOptions(); forEach(program.getSourceFiles(), f => - program.isSourceFileDefaultLibrary(f) && - !skipTypeChecking(f, options, program) && - removeSemanticDiagnosticsOf(state, f.resolvedPath) - ); + program.isSourceFileDefaultLibrary(f) + && !skipTypeChecking(f, options, program) + && removeSemanticDiagnosticsOf(state, f.resolvedPath)); } } @@ -741,7 +836,7 @@ function handleDtsMayChangeOf( state: BuilderProgramState, path: Path, cancellationToken: CancellationToken | undefined, - host: BuilderProgramHost + host: BuilderProgramHost, ): void { removeSemanticDiagnosticsOf(state, path); @@ -760,11 +855,15 @@ function handleDtsMayChangeOf( sourceFile, cancellationToken, host, - /*useFileVersionAsSignature*/ true + /*useFileVersionAsSignature*/ true, ); // If not dts emit, nothing more to do if (getEmitDeclarations(state.compilerOptions)) { - addToAffectedFilesPendingEmit(state, path, state.compilerOptions.declarationMap ? BuilderFileEmit.AllDts : BuilderFileEmit.Dts); + addToAffectedFilesPendingEmit( + state, + path, + state.compilerOptions.declarationMap ? BuilderFileEmit.AllDts : BuilderFileEmit.Dts, + ); } } } @@ -798,12 +897,14 @@ function handleDtsMayChangeOfGlobalScope( if (!state.fileInfos.get(filePath)?.affectsGlobalScope) return false; // Every file needs to be handled BuilderState.getAllFilesExcludingDefaultLibraryFile(state, state.program!, /*firstSourceFile*/ undefined) - .forEach(file => handleDtsMayChangeOf( - state, - file.resolvedPath, - cancellationToken, - host, - )); + .forEach(file => + handleDtsMayChangeOf( + state, + file.resolvedPath, + cancellationToken, + host, + ) + ); removeDiagnosticsOfLibraryFiles(state); return true; } @@ -815,7 +916,7 @@ function handleDtsMayChangeOfReferencingExportOfAffectedFile( state: BuilderProgramState, affectedFile: SourceFile, cancellationToken: CancellationToken | undefined, - host: BuilderProgramHost + host: BuilderProgramHost, ) { // If there was change in signature (dts output) for the changed file, // then only we need to handle pending file emit @@ -855,8 +956,7 @@ function handleDtsMayChangeOfReferencingExportOfAffectedFile( seenFileAndExportsOfFile, cancellationToken, host, - ) - ); + )); }); } @@ -889,8 +989,8 @@ function handleDtsMayChangeOfFileAndExportsOfFile( // Remove diagnostics of files that import this file (without going to exports of referencing files) state.referencedMap!.getKeys(filePath)?.forEach(referencingFilePath => - !seenFileAndExportsOfFile.has(referencingFilePath) && // Not already removed diagnostic file - handleDtsMayChangeOf( // Dont add to seen since this is not yet done with the export removal + !seenFileAndExportsOfFile.has(referencingFilePath) // Not already removed diagnostic file + && handleDtsMayChangeOf( // Dont add to seen since this is not yet done with the export removal state, referencingFilePath, cancellationToken, @@ -904,10 +1004,14 @@ function handleDtsMayChangeOfFileAndExportsOfFile( * Gets semantic diagnostics for the file which are * bindAndCheckDiagnostics (from cache) and program diagnostics */ -function getSemanticDiagnosticsOfFile(state: BuilderProgramState, sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { +function getSemanticDiagnosticsOfFile( + state: BuilderProgramState, + sourceFile: SourceFile, + cancellationToken?: CancellationToken, +): readonly Diagnostic[] { return concatenate( getBinderAndCheckerDiagnosticsOfFile(state, sourceFile, cancellationToken), - Debug.checkDefined(state.program).getProgramDiagnostics(sourceFile) + Debug.checkDefined(state.program).getProgramDiagnostics(sourceFile), ); } @@ -915,7 +1019,11 @@ function getSemanticDiagnosticsOfFile(state: BuilderProgramState, sourceFile: So * Gets the binder and checker diagnostics either from cache if present, or otherwise from program and caches it * Note that it is assumed that when asked about binder and checker diagnostics, the file has been taken out of affected files/changed file set */ -function getBinderAndCheckerDiagnosticsOfFile(state: BuilderProgramState, sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { +function getBinderAndCheckerDiagnosticsOfFile( + state: BuilderProgramState, + sourceFile: SourceFile, + cancellationToken?: CancellationToken, +): readonly Diagnostic[] { const path = sourceFile.resolvedPath; if (state.semanticDiagnosticsPerFile) { const cachedDiagnostics = state.semanticDiagnosticsPerFile.get(path); @@ -934,11 +1042,14 @@ function getBinderAndCheckerDiagnosticsOfFile(state: BuilderProgramState, source } /** @internal */ -export type ProgramBuildInfoFileId = number & { __programBuildInfoFileIdBrand: any }; +export type ProgramBuildInfoFileId = number & { __programBuildInfoFileIdBrand: any; }; /** @internal */ -export type ProgramBuildInfoFileIdListId = number & { __programBuildInfoFileIdListIdBrand: any }; +export type ProgramBuildInfoFileIdListId = number & { __programBuildInfoFileIdListIdBrand: any; }; /** @internal */ -export type ProgramBuildInfoDiagnostic = ProgramBuildInfoFileId | [fileId: ProgramBuildInfoFileId, diagnostics: readonly ReusableDiagnostic[]]; +export type ProgramBuildInfoDiagnostic = ProgramBuildInfoFileId | [ + fileId: ProgramBuildInfoFileId, + diagnostics: readonly ReusableDiagnostic[], +]; /** * fileId if pending emit is same as what compilerOptions suggest * [fileId] if pending emit is only dts file emit @@ -946,9 +1057,15 @@ export type ProgramBuildInfoDiagnostic = ProgramBuildInfoFileId | [fileId: Progr * * @internal */ -export type ProgramBuilderInfoFilePendingEmit = ProgramBuildInfoFileId | [fileId: ProgramBuildInfoFileId] | [fileId: ProgramBuildInfoFileId, emitKind: BuilderFileEmit]; +export type ProgramBuilderInfoFilePendingEmit = ProgramBuildInfoFileId | [fileId: ProgramBuildInfoFileId] | [ + fileId: ProgramBuildInfoFileId, + emitKind: BuilderFileEmit, +]; /** @internal */ -export type ProgramBuildInfoReferencedMap = [fileId: ProgramBuildInfoFileId, fileIdListId: ProgramBuildInfoFileIdListId][]; +export type ProgramBuildInfoReferencedMap = [ + fileId: ProgramBuildInfoFileId, + fileIdListId: ProgramBuildInfoFileIdListId, +][]; /** @internal */ export type ProgramMultiFileEmitBuildInfoBuilderStateFileInfo = Omit & { /** @@ -965,7 +1082,10 @@ export type ProgramMultiFileEmitBuildInfoBuilderStateFileInfo = Omit(); const root: ProgramBuildInfoRoot[] = []; @@ -1045,9 +1168,14 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde // Ensure fileId const fileId = toFileId(key); tryAddRoot(key, fileId); - return value.impliedFormat ? - { version: value.version, impliedFormat: value.impliedFormat, signature: undefined, affectsGlobalScope: undefined } : - value.version; + return value.impliedFormat + ? { + version: value.version, + impliedFormat: value.impliedFormat, + signature: undefined, + affectsGlobalScope: undefined, + } + : value.version; }); const program: ProgramBundleEmitBuildInfo = { fileNames, @@ -1056,11 +1184,11 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde options: convertToProgramBuildInfoCompilerOptions(state.compilerOptions), outSignature: state.outSignature, latestChangedDtsFile, - pendingEmit: !state.programEmitPending ? - undefined : // Pending is undefined or None is encoded as undefined - state.programEmitPending === getBuilderFileEmit(state.compilerOptions) ? - false : // Pending emit is same as deteremined by compilerOptions - state.programEmitPending, // Actual value + pendingEmit: !state.programEmitPending + ? undefined // Pending is undefined or None is encoded as undefined + : state.programEmitPending === getBuilderFileEmit(state.compilerOptions) + ? false // Pending emit is same as deteremined by compilerOptions + : state.programEmitPending, // Actual value }; // Complete the bundle information if we are doing partial emit (only js or only dts) const { js, dts, commonSourceDirectory, sourceFiles } = bundle!; @@ -1088,46 +1216,74 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde if (!isJsonSourceFile(file) && sourceFileMayBeEmitted(file, state.program!)) { const emitSignature = state.emitSignatures?.get(key); if (emitSignature !== actualSignature) { - (emitSignatures ||= []).push(emitSignature === undefined ? - fileId : // There is no emit, encode as false - // fileId, signature: emptyArray if signature only differs in dtsMap option than our own compilerOptions otherwise EmitSignature - [fileId, !isString(emitSignature) && emitSignature[0] === actualSignature ? emptyArray as [] : emitSignature]); + (emitSignatures ||= []).push( + emitSignature === undefined + ? fileId // There is no emit, encode as false + // fileId, signature: emptyArray if signature only differs in dtsMap option than our own compilerOptions otherwise EmitSignature + : [ + fileId, + !isString(emitSignature) && emitSignature[0] === actualSignature ? emptyArray as [] + : emitSignature, + ], + ); } } } - return value.version === actualSignature ? - value.affectsGlobalScope || value.impliedFormat ? + return value.version === actualSignature + ? value.affectsGlobalScope || value.impliedFormat // If file version is same as signature, dont serialize signature - { version: value.version, signature: undefined, affectsGlobalScope: value.affectsGlobalScope, impliedFormat: value.impliedFormat } : + ? { + version: value.version, + signature: undefined, + affectsGlobalScope: value.affectsGlobalScope, + impliedFormat: value.impliedFormat, + } // If file info only contains version and signature and both are same we can just write string - value.version : - actualSignature !== undefined ? // If signature is not same as version, encode signature in the fileInfo - oldSignature === undefined ? - // If we havent computed signature, use fileInfo as is - value : - // Serialize fileInfo with new updated signature - { version: value.version, signature: actualSignature, affectsGlobalScope: value.affectsGlobalScope, impliedFormat: value.impliedFormat } : - // Signature of the FileInfo is undefined, serialize it as false - { version: value.version, signature: false, affectsGlobalScope: value.affectsGlobalScope, impliedFormat: value.impliedFormat }; + : value.version + : actualSignature !== undefined // If signature is not same as version, encode signature in the fileInfo + ? oldSignature === undefined + // If we havent computed signature, use fileInfo as is + ? value + // Serialize fileInfo with new updated signature + : { + version: value.version, + signature: actualSignature, + affectsGlobalScope: value.affectsGlobalScope, + impliedFormat: value.impliedFormat, + } + // Signature of the FileInfo is undefined, serialize it as false + : { + version: value.version, + signature: false, + affectsGlobalScope: value.affectsGlobalScope, + impliedFormat: value.impliedFormat, + }; }); let referencedMap: ProgramBuildInfoReferencedMap | undefined; if (state.referencedMap) { referencedMap = arrayFrom(state.referencedMap.keys()).sort(compareStringsCaseSensitive).map(key => [ toFileId(key), - toFileIdListId(state.referencedMap!.getValues(key)!) + toFileIdListId(state.referencedMap!.getValues(key)!), ]); } let exportedModulesMap: ProgramBuildInfoReferencedMap | undefined; if (state.exportedModulesMap) { - exportedModulesMap = mapDefined(arrayFrom(state.exportedModulesMap.keys()).sort(compareStringsCaseSensitive), key => { - const oldValue = state.oldExportedModulesMap?.get(key); - // Not in temporary cache, use existing value - if (oldValue === undefined) return [toFileId(key), toFileIdListId(state.exportedModulesMap!.getValues(key)!)]; - if (oldValue) return [toFileId(key), toFileIdListId(oldValue)]; - return undefined; - }); + exportedModulesMap = mapDefined( + arrayFrom(state.exportedModulesMap.keys()).sort(compareStringsCaseSensitive), + key => { + const oldValue = state.oldExportedModulesMap?.get(key); + // Not in temporary cache, use existing value + if (oldValue === undefined) { + return [toFileId(key), toFileIdListId(state.exportedModulesMap!.getValues(key)!)]; + } + if (oldValue) { + return [toFileId(key), toFileIdListId(oldValue)]; + } + return undefined; + }, + ); } let semanticDiagnosticsPerFile: ProgramBuildInfoDiagnostic[] | undefined; @@ -1135,12 +1291,12 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde for (const key of arrayFrom(state.semanticDiagnosticsPerFile.keys()).sort(compareStringsCaseSensitive)) { const value = state.semanticDiagnosticsPerFile.get(key)!; (semanticDiagnosticsPerFile ||= []).push( - value.length ? - [ + value.length + ? [ toFileId(key), - convertToReusableDiagnostics(value, relativeToBuildInfo) - ] : - toFileId(key) + convertToReusableDiagnostics(value, relativeToBuildInfo), + ] + : toFileId(key), ); } } @@ -1155,11 +1311,11 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde if (!file || !sourceFileMayBeEmitted(file, state.program!)) continue; const fileId = toFileId(path), pendingEmit = state.affectedFilesPendingEmit.get(path)!; (affectedFilesPendingEmit ||= []).push( - pendingEmit === fullEmitForOptions ? - fileId : // Pending full emit per options - pendingEmit === BuilderFileEmit.Dts ? - [fileId] : // Pending on Dts only - [fileId, pendingEmit] // Anything else + pendingEmit === fullEmitForOptions + ? fileId // Pending full emit per options + : pendingEmit === BuilderFileEmit.Dts + ? [fileId] // Pending on Dts only + : [fileId, pendingEmit], // Anything else ); } } @@ -1193,7 +1349,9 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde } function relativeToBuildInfo(path: string) { - return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, state.program!.getCanonicalFileName)); + return ensurePathIsNonModuleName( + getRelativePathFromDirectory(buildInfoDirectory, path, state.program!.getCanonicalFileName), + ); } function toFileId(path: Path): ProgramBuildInfoFileId { @@ -1211,14 +1369,19 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde let fileIdListId = fileNamesToFileIdListId?.get(key); if (fileIdListId === undefined) { (fileIdsList ||= []).push(fileIds); - (fileNamesToFileIdListId ||= new Map()).set(key, fileIdListId = fileIdsList.length as ProgramBuildInfoFileIdListId); + (fileNamesToFileIdListId ||= new Map()).set( + key, + fileIdListId = fileIdsList.length as ProgramBuildInfoFileIdListId, + ); } return fileIdListId; } function tryAddRoot(path: Path, fileId: ProgramBuildInfoFileId) { const file = state.program!.getSourceFile(path)!; - if (!state.program!.getFileIncludeReasons().get(file.path)!.some(r => r.kind === FileIncludeKind.RootFile)) return; + if (!state.program!.getFileIncludeReasons().get(file.path)!.some(r => r.kind === FileIncludeKind.RootFile)) { + return; + } // First fileId as is if (!root.length) return root.push(fileId); const last = root[root.length - 1]; @@ -1247,7 +1410,7 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde (result ||= {})[name] = convertToReusableCompilerOptionValue( optionInfo, options[name] as CompilerOptionsValue, - relativeToBuildInfoEnsuringAbsolutePath + relativeToBuildInfoEnsuringAbsolutePath, ); } } @@ -1255,7 +1418,11 @@ function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | unde } } -function convertToReusableCompilerOptionValue(option: CommandLineOption | undefined, value: CompilerOptionsValue, relativeToBuildInfo: (path: string) => string) { +function convertToReusableCompilerOptionValue( + option: CommandLineOption | undefined, + value: CompilerOptionsValue, + relativeToBuildInfo: (path: string) => string, +) { if (option) { Debug.assert(option.type !== "listOrElement"); if (option.type === "list") { @@ -1271,30 +1438,40 @@ function convertToReusableCompilerOptionValue(option: CommandLineOption | undefi return value; } -function convertToReusableDiagnostics(diagnostics: readonly Diagnostic[], relativeToBuildInfo: (path: string) => string): readonly ReusableDiagnostic[] { +function convertToReusableDiagnostics( + diagnostics: readonly Diagnostic[], + relativeToBuildInfo: (path: string) => string, +): readonly ReusableDiagnostic[] { Debug.assert(!!diagnostics.length); return diagnostics.map(diagnostic => { - const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic, relativeToBuildInfo); + const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation( + diagnostic, + relativeToBuildInfo, + ); result.reportsUnnecessary = diagnostic.reportsUnnecessary; result.reportDeprecated = diagnostic.reportsDeprecated; result.source = diagnostic.source; result.skippedOn = diagnostic.skippedOn; const { relatedInformation } = diagnostic; - result.relatedInformation = relatedInformation ? - relatedInformation.length ? - relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r, relativeToBuildInfo)) : - [] : - undefined; + result.relatedInformation = relatedInformation + ? relatedInformation.length + ? relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r, relativeToBuildInfo)) + : [] + : undefined; return result; }); } -function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation, relativeToBuildInfo: (path: string) => string): ReusableDiagnosticRelatedInformation { +function convertToReusableDiagnosticRelatedInformation( + diagnostic: DiagnosticRelatedInformation, + relativeToBuildInfo: (path: string) => string, +): ReusableDiagnosticRelatedInformation { const { file } = diagnostic; return { ...diagnostic, file: file ? relativeToBuildInfo(file.resolvedPath) : undefined, - messageText: isString(diagnostic.messageText) ? diagnostic.messageText : convertToReusableDiagnosticMessageChain(diagnostic.messageText), + messageText: isString(diagnostic.messageText) ? diagnostic.messageText + : convertToReusableDiagnosticMessageChain(diagnostic.messageText), }; } @@ -1309,7 +1486,9 @@ function convertToReusableDiagnosticMessageChain(chain: DiagnosticMessageChain): return next === chain.next ? chain : { ...chain, next }; } -function convertToReusableDiagnosticMessageChainArray(array: DiagnosticMessageChain[] | undefined): ReusableDiagnosticMessageChain[] | undefined { +function convertToReusableDiagnosticMessageChainArray( + array: DiagnosticMessageChain[] | undefined, +): ReusableDiagnosticMessageChain[] | undefined { if (!array) return array; return forEach(array, (chain, index) => { const reusable = convertToReusableDiagnosticMessageChain(chain); @@ -1326,7 +1505,7 @@ function convertToReusableDiagnosticMessageChainArray(array: DiagnosticMessageCh /** @internal */ export enum BuilderProgramKind { SemanticDiagnosticsBuilderProgram, - EmitAndSemanticDiagnosticsBuilderProgram + EmitAndSemanticDiagnosticsBuilderProgram, } /** @internal */ @@ -1338,7 +1517,14 @@ export interface BuilderCreationParameters { } /** @internal */ -export function getBuilderCreationParameters(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: BuilderProgram | CompilerHost, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderCreationParameters { +export function getBuilderCreationParameters( + newProgramOrRootNames: Program | readonly string[] | undefined, + hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, + oldProgramOrHost?: BuilderProgram | CompilerHost, + configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], +): BuilderCreationParameters { let host: BuilderProgramHost; let newProgram: Program; let oldProgram: BuilderProgram; @@ -1357,7 +1543,7 @@ export function getBuilderCreationParameters(newProgramOrRootNames: Program | re host: oldProgramOrHost as CompilerHost, oldProgram: oldProgram && oldProgram.getProgramOrUndefined(), configFileParsingDiagnostics, - projectReferences + projectReferences, }); host = oldProgramOrHost as CompilerHost; } @@ -1380,35 +1566,41 @@ export function computeSignatureWithDiagnostics( sourceFile: SourceFile, text: string, host: HostForComputeHash, - data: WriteFileCallbackData | undefined + data: WriteFileCallbackData | undefined, ) { text = getTextHandlingSourceMapForSignature(text, data); let sourceFileDirectory: string | undefined; if (data?.diagnostics?.length) { text += data.diagnostics.map(diagnostic => - `${locationInfo(diagnostic)}${DiagnosticCategory[diagnostic.category]}${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText)}` + `${locationInfo(diagnostic)}${DiagnosticCategory[diagnostic.category]}${diagnostic.code}: ${ + flattenDiagnosticMessageText(diagnostic.messageText) + }` ).join("\n"); } return (host.createHash ?? generateDjb2Hash)(text); function flattenDiagnosticMessageText(diagnostic: string | DiagnosticMessageChain | undefined): string { - return isString(diagnostic) ? - diagnostic : - diagnostic === undefined ? - "" : - !diagnostic.next ? - diagnostic.messageText : - diagnostic.messageText + diagnostic.next.map(flattenDiagnosticMessageText).join("\n"); + return isString(diagnostic) + ? diagnostic + : diagnostic === undefined + ? "" + : !diagnostic.next + ? diagnostic.messageText + : diagnostic.messageText + diagnostic.next.map(flattenDiagnosticMessageText).join("\n"); } function locationInfo(diagnostic: DiagnosticWithLocation) { - if (diagnostic.file.resolvedPath === sourceFile.resolvedPath) return `(${diagnostic.start},${diagnostic.length})`; + if (diagnostic.file.resolvedPath === sourceFile.resolvedPath) { + return `(${diagnostic.start},${diagnostic.length})`; + } if (sourceFileDirectory === undefined) sourceFileDirectory = getDirectoryPath(sourceFile.resolvedPath); - return `${ensurePathIsNonModuleName(getRelativePathFromDirectory( - sourceFileDirectory, - diagnostic.file.resolvedPath, - program.getCanonicalFileName, - ))}(${diagnostic.start},${diagnostic.length})`; + return `${ + ensurePathIsNonModuleName(getRelativePathFromDirectory( + sourceFileDirectory, + diagnostic.file.resolvedPath, + program.getCanonicalFileName, + )) + }(${diagnostic.start},${diagnostic.length})`; } } @@ -1418,14 +1610,26 @@ export function computeSignature(text: string, host: HostForComputeHash, data?: } /** @internal */ -export function createBuilderProgram(kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): SemanticDiagnosticsBuilderProgram; +export function createBuilderProgram( + kind: BuilderProgramKind.SemanticDiagnosticsBuilderProgram, + builderCreationParameters: BuilderCreationParameters, +): SemanticDiagnosticsBuilderProgram; /** @internal */ -export function createBuilderProgram(kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, builderCreationParameters: BuilderCreationParameters): EmitAndSemanticDiagnosticsBuilderProgram; +export function createBuilderProgram( + kind: BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, + builderCreationParameters: BuilderCreationParameters, +): EmitAndSemanticDiagnosticsBuilderProgram; /** @internal */ -export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters) { +export function createBuilderProgram( + kind: BuilderProgramKind, + { newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters, +) { // Return same program if underlying program doesnt change let oldState = oldProgram && oldProgram.getState(); - if (oldState && newProgram === oldState.program && configFileParsingDiagnostics === newProgram.getConfigFileParsingDiagnostics()) { + if ( + oldState && newProgram === oldState.program + && configFileParsingDiagnostics === newProgram.getConfigFileParsingDiagnostics() + ) { newProgram = undefined!; // TODO: GH#18217 oldState = undefined; return oldProgram; @@ -1443,18 +1647,21 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos const builderProgram = createRedirectedBuilderProgram(getState, configFileParsingDiagnostics); builderProgram.getState = getState; builderProgram.saveEmitState = () => backupBuilderProgramEmitState(state); - builderProgram.restoreEmitState = (saved) => restoreBuilderProgramEmitState(state, saved); + builderProgram.restoreEmitState = saved => restoreBuilderProgramEmitState(state, saved); builderProgram.hasChangedEmitSignature = () => !!state.hasChangedEmitSignature; - builderProgram.getAllDependencies = sourceFile => BuilderState.getAllDependencies(state, Debug.checkDefined(state.program), sourceFile); + builderProgram.getAllDependencies = sourceFile => + BuilderState.getAllDependencies(state, Debug.checkDefined(state.program), sourceFile); builderProgram.getSemanticDiagnostics = getSemanticDiagnostics; builderProgram.emit = emit; builderProgram.releaseProgram = () => releaseCache(state); if (kind === BuilderProgramKind.SemanticDiagnosticsBuilderProgram) { - (builderProgram as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile; + (builderProgram as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = + getSemanticDiagnosticsOfNextAffectedFile; } else if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) { - (builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile; + (builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = + getSemanticDiagnosticsOfNextAffectedFile; (builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).emitNextAffectedFile = emitNextAffectedFile; builderProgram.emitBuildInfo = emitBuildInfo; } @@ -1466,7 +1673,10 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos function emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult { if (state.buildInfoEmitPending) { - const result = Debug.checkDefined(state.program).emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken); + const result = Debug.checkDefined(state.program).emitBuildInfo( + writeFile || maybeBind(host, host.writeFile), + cancellationToken, + ); state.buildInfoEmitPending = false; return result; } @@ -1478,11 +1688,16 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos * 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, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): AffectedFileResult { + function emitNextAffectedFile( + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): AffectedFileResult { let affected = getNextAffectedFile(state, cancellationToken, host); const programEmitKind = getBuilderFileEmit(state.compilerOptions); - let emitKind: BuilderFileEmit = emitOnlyDtsFiles ? - programEmitKind & BuilderFileEmit.AllDts : programEmitKind; + let emitKind: BuilderFileEmit = emitOnlyDtsFiles + ? programEmitKind & BuilderFileEmit.AllDts : programEmitKind; if (!affected) { if (!outFile(state.compilerOptions)) { const pendingAffectedFile = getNextAffectedFilePendingEmit(state, emitOnlyDtsFiles); @@ -1490,7 +1705,10 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos // Emit buildinfo if pending if (!state.buildInfoEmitPending) return undefined; const affected = state.program!; - const result = affected.emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken); + const result = affected.emitBuildInfo( + writeFile || maybeBind(host, host.writeFile), + cancellationToken, + ); state.buildInfoEmitPending = false; return { result, affected }; } @@ -1512,11 +1730,11 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos if (emitKind & BuilderFileEmit.AllDts) emitOnly = emitOnly === undefined ? EmitOnly.Dts : undefined; if (affected === state.program) { // Set up programEmit before calling emit so that its set in buildInfo - state.programEmitPending = state.changedFilesSet.size ? - getPendingEmitKind(programEmitKind, emitKind) : - state.programEmitPending ? - getPendingEmitKind(state.programEmitPending, emitKind) : - undefined; + state.programEmitPending = state.changedFilesSet.size + ? getPendingEmitKind(programEmitKind, emitKind) + : state.programEmitPending + ? getPendingEmitKind(state.programEmitPending, emitKind) + : undefined; } // Actual emit const result = state.program!.emit( @@ -1524,7 +1742,7 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos getWriteFileCallback(writeFile, customTransformers), cancellationToken, emitOnly, - customTransformers + customTransformers, ); if (affected !== state.program) { // update affected files @@ -1536,9 +1754,12 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos // Update the pendingEmit for the file const existing = state.seenEmittedFiles?.get(affectedSourceFile.resolvedPath) || BuilderFileEmit.None; (state.seenEmittedFiles ??= new Map()).set(affectedSourceFile.resolvedPath, emitKind | existing); - const existingPending = state.affectedFilesPendingEmit?.get(affectedSourceFile.resolvedPath) || programEmitKind; + const existingPending = state.affectedFilesPendingEmit?.get(affectedSourceFile.resolvedPath) + || programEmitKind; const pendingKind = getPendingEmitKind(existingPending, emitKind | existing); - if (pendingKind) (state.affectedFilesPendingEmit ??= new Map()).set(affectedSourceFile.resolvedPath, pendingKind); + if (pendingKind) { + (state.affectedFilesPendingEmit ??= new Map()).set(affectedSourceFile.resolvedPath, pendingKind); + } else state.affectedFilesPendingEmit?.delete(affectedSourceFile.resolvedPath); } else { @@ -1548,7 +1769,10 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos return { result, affected }; } - function getWriteFileCallback(writeFile: WriteFileCallback | undefined, customTransformers: CustomTransformers | undefined): WriteFileCallback | undefined { + function getWriteFileCallback( + writeFile: WriteFileCallback | undefined, + customTransformers: CustomTransformers | undefined, + ): WriteFileCallback | undefined { if (!getEmitDeclarations(state.compilerOptions)) return writeFile || maybeBind(host, host.writeFile); return (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => { if (isDeclarationFileName(fileName)) { @@ -1569,12 +1793,25 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos // With d.ts diagnostics they are also part of the signature so emitSignature will be different from it since its just hash of d.ts if (!data?.diagnostics?.length) emitSignature = signature; if (signature !== file.version) { // Update it - if (host.storeFilesChangingSignatureDuringEmit) (state.filesChangingSignature ??= new Set()).add(file.resolvedPath); - if (state.exportedModulesMap) BuilderState.updateExportedModules(state, file, file.exportedModulesFromDeclarationEmit); + if (host.storeFilesChangingSignatureDuringEmit) { + (state.filesChangingSignature ??= new Set()).add(file.resolvedPath); + } + if (state.exportedModulesMap) { + BuilderState.updateExportedModules( + state, + file, + file.exportedModulesFromDeclarationEmit, + ); + } if (state.affectedFiles) { // Keep old signature so we know what to undo if cancellation happens const existing = state.oldSignatures?.get(file.resolvedPath); - if (existing === undefined) (state.oldSignatures ??= new Map()).set(file.resolvedPath, info.signature || false); + if (existing === undefined) { + (state.oldSignatures ??= new Map()).set( + file.resolvedPath, + info.signature || false, + ); + } info.signature = signature; } else { @@ -1610,8 +1847,12 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos * Compare to existing computed signature and store it or handle the changes in d.ts map option from before * returning undefined means that, we dont need to emit this d.ts file since its contents didnt change */ - function handleNewSignature(oldSignatureFormat: EmitSignature | undefined, newSignature: string | undefined) { - const oldSignature = !oldSignatureFormat || isString(oldSignatureFormat) ? oldSignatureFormat : oldSignatureFormat[0]; + function handleNewSignature( + oldSignatureFormat: EmitSignature | undefined, + newSignature: string | undefined, + ) { + const oldSignature = !oldSignatureFormat || isString(oldSignatureFormat) ? oldSignatureFormat + : oldSignatureFormat[0]; newSignature ??= computeSignature(text, host, data); // Dont write dts files if they didn't change if (newSignature === oldSignature) { @@ -1642,7 +1883,13 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos * 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 emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult { + function emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): EmitResult { if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) { assertSourceFileOkWithoutNextAffectedCall(state, targetSourceFile); } @@ -1659,7 +1906,14 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos let emittedFiles: string[] = []; let affectedEmitResult: AffectedFileResult; - while (affectedEmitResult = emitNextAffectedFile(writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers)) { + while ( + affectedEmitResult = emitNextAffectedFile( + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers, + ) + ) { emitSkipped = emitSkipped || affectedEmitResult.result.emitSkipped; diagnostics = addRange(diagnostics, affectedEmitResult.result.diagnostics); emittedFiles = addRange(emittedFiles, affectedEmitResult.result.emittedFiles); @@ -1669,7 +1923,7 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos emitSkipped, diagnostics: diagnostics || emptyArray, emittedFiles, - sourceMaps + sourceMaps, }; } // In non Emit builder, clear affected files pending emit @@ -1682,7 +1936,7 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos getWriteFileCallback(writeFile, customTransformers), cancellationToken, emitOnlyDtsFiles, - customTransformers + customTransformers, ); } @@ -1690,7 +1944,10 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos * Return the semantic diagnostics for the next affected file or undefined if iteration is complete * If provided ignoreSourceFile would be called before getting the diagnostics and would ignore the sourceFile if the returned value was true */ - function getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult { + function getSemanticDiagnosticsOfNextAffectedFile( + cancellationToken?: CancellationToken, + ignoreSourceFile?: (sourceFile: SourceFile) => boolean, + ): AffectedFileResult { while (true) { const affected = getNextAffectedFile(state, cancellationToken, host); let result; @@ -1725,7 +1982,10 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos * In case of SemanticDiagnosticsBuilderProgram if the source file is not provided, * it will iterate through all the affected files, to ensure that cache stays valid and yet provide a way to get all semantic diagnostics */ - function getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + function getSemanticDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { assertSourceFileOkWithoutNextAffectedCall(state, sourceFile); const compilerOptions = Debug.checkDefined(state.program).getCompilerOptions(); if (outFile(compilerOptions)) { @@ -1752,32 +2012,53 @@ export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, hos } } -function addToAffectedFilesPendingEmit(state: BuilderProgramState, affectedFilePendingEmit: Path, kind: BuilderFileEmit) { +function addToAffectedFilesPendingEmit( + state: BuilderProgramState, + affectedFilePendingEmit: Path, + kind: BuilderFileEmit, +) { const existingKind = state.affectedFilesPendingEmit?.get(affectedFilePendingEmit) || BuilderFileEmit.None; (state.affectedFilesPendingEmit ??= new Map()).set(affectedFilePendingEmit, existingKind | kind); } /** @internal */ -export function toBuilderStateFileInfoForMultiEmit(fileInfo: ProgramMultiFileEmitBuildInfoFileInfo): BuilderState.FileInfo { - return isString(fileInfo) ? - { version: fileInfo, signature: fileInfo, affectsGlobalScope: undefined, impliedFormat: undefined } : - isString(fileInfo.signature) ? - fileInfo as BuilderState.FileInfo : - { version: fileInfo.version, signature: fileInfo.signature === false ? undefined : fileInfo.version, affectsGlobalScope: fileInfo.affectsGlobalScope, impliedFormat: fileInfo.impliedFormat }; +export function toBuilderStateFileInfoForMultiEmit( + fileInfo: ProgramMultiFileEmitBuildInfoFileInfo, +): BuilderState.FileInfo { + return isString(fileInfo) + ? { version: fileInfo, signature: fileInfo, affectsGlobalScope: undefined, impliedFormat: undefined } + : isString(fileInfo.signature) + ? fileInfo as BuilderState.FileInfo + : { + version: fileInfo.version, + signature: fileInfo.signature === false ? undefined : fileInfo.version, + affectsGlobalScope: fileInfo.affectsGlobalScope, + impliedFormat: fileInfo.impliedFormat, + }; } /** @internal */ -export function toBuilderFileEmit(value: ProgramBuilderInfoFilePendingEmit, fullEmitForOptions: BuilderFileEmit): BuilderFileEmit{ +export function toBuilderFileEmit( + value: ProgramBuilderInfoFilePendingEmit, + fullEmitForOptions: BuilderFileEmit, +): BuilderFileEmit { return isNumber(value) ? fullEmitForOptions : value[1] || BuilderFileEmit.Dts; } /** @internal */ -export function toProgramEmitPending(value: ProgramBuildInfoBundlePendingEmit, options: CompilerOptions | undefined): BuilderFileEmit | undefined { +export function toProgramEmitPending( + value: ProgramBuildInfoBundlePendingEmit, + options: CompilerOptions | undefined, +): BuilderFileEmit | undefined { return !value ? getBuilderFileEmit(options || {}) : value; } /** @internal */ -export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo, buildInfoPath: string, host: ReadBuildProgramHost): EmitAndSemanticDiagnosticsBuilderProgram { +export function createBuilderProgramUsingProgramBuildInfo( + buildInfo: BuildInfo, + buildInfoPath: string, + host: ReadBuildProgramHost, +): EmitAndSemanticDiagnosticsBuilderProgram { const program = buildInfo.program!; const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory())); const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); @@ -1785,26 +2066,38 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo, let state: ReusableBuilderProgramState; const filePaths = program.fileNames?.map(toPathInBuildInfoDirectory); let filePathsSetList: Set[] | undefined; - const latestChangedDtsFile = program.latestChangedDtsFile ? toAbsolutePath(program.latestChangedDtsFile) : undefined; + const latestChangedDtsFile = program.latestChangedDtsFile ? toAbsolutePath(program.latestChangedDtsFile) + : undefined; if (isProgramBundleEmitBuildInfo(program)) { const fileInfos = new Map(); program.fileInfos.forEach((fileInfo, index) => { const path = toFilePath(index + 1 as ProgramBuildInfoFileId); - fileInfos.set(path, isString(fileInfo) ? { version: fileInfo, signature: undefined, affectsGlobalScope: undefined, impliedFormat: undefined } : fileInfo); + fileInfos.set( + path, + isString(fileInfo) + ? { + version: fileInfo, + signature: undefined, + affectsGlobalScope: undefined, + impliedFormat: undefined, + } : fileInfo, + ); }); state = { fileInfos, compilerOptions: program.options ? convertToOptionsWithAbsolutePaths(program.options, toAbsolutePath) : {}, latestChangedDtsFile, outSignature: program.outSignature, - programEmitPending: program.pendingEmit === undefined ? undefined : toProgramEmitPending(program.pendingEmit, program.options), + programEmitPending: program.pendingEmit === undefined ? undefined + : toProgramEmitPending(program.pendingEmit, program.options), bundle: buildInfo.bundle, }; } else { filePathsSetList = program.fileIdsList?.map(fileIds => new Set(fileIds.map(toFilePath))); const fileInfos = new Map(); - const emitSignatures = program.options?.composite && !outFile(program.options) ? new Map() : undefined; + const emitSignatures = program.options?.composite && !outFile(program.options) ? new Map() + : undefined; program.fileInfos.forEach((fileInfo, index) => { const path = toFilePath(index + 1 as ProgramBuildInfoFileId); const stateFileInfo = toBuilderStateFileInfoForMultiEmit(fileInfo); @@ -1815,22 +2108,35 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo, if (isNumber(value)) emitSignatures!.delete(toFilePath(value)); else { const key = toFilePath(value[0]); - emitSignatures!.set(key, !isString(value[1]) && !value[1].length ? - // File signature is emit signature but differs in map - [emitSignatures!.get(key)! as string] : - value[1] + emitSignatures!.set( + key, + !isString(value[1]) && !value[1].length + // File signature is emit signature but differs in map + ? [emitSignatures!.get(key)! as string] + : value[1], ); } }); - const fullEmitForOptions = program.affectedFilesPendingEmit ? getBuilderFileEmit(program.options || {}) : undefined; + const fullEmitForOptions = program.affectedFilesPendingEmit ? getBuilderFileEmit(program.options || {}) + : undefined; state = { fileInfos, compilerOptions: program.options ? convertToOptionsWithAbsolutePaths(program.options, toAbsolutePath) : {}, referencedMap: toManyToManyPathMap(program.referencedMap), exportedModulesMap: toManyToManyPathMap(program.exportedModulesMap), - semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile && arrayToMap(program.semanticDiagnosticsPerFile, value => toFilePath(isNumber(value) ? value : value[0]), value => isNumber(value) ? emptyArray : value[1]), + semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile + && arrayToMap( + program.semanticDiagnosticsPerFile, + value => toFilePath(isNumber(value) ? value : value[0]), + value => isNumber(value) ? emptyArray : value[1], + ), hasReusableDiagnostic: true, - affectedFilesPendingEmit: program.affectedFilesPendingEmit && arrayToMap(program.affectedFilesPendingEmit, value => toFilePath(isNumber(value) ? value : value[0]), value => toBuilderFileEmit(value, fullEmitForOptions!)), + affectedFilesPendingEmit: program.affectedFilesPendingEmit + && arrayToMap( + program.affectedFilesPendingEmit, + value => toFilePath(isNumber(value) ? value : value[0]), + value => toBuilderFileEmit(value, fullEmitForOptions!), + ), changedFilesSet: new Set(map(program.changeFileSet, toFilePath)), latestChangedDtsFile, emitSignatures: emitSignatures?.size ? emitSignatures : undefined, @@ -1879,15 +2185,15 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo, return filePathsSetList![fileIdsListId - 1]; } - function toManyToManyPathMap(referenceMap: ProgramBuildInfoReferencedMap | undefined): BuilderState.ManyToManyPathMap | undefined { + function toManyToManyPathMap( + referenceMap: ProgramBuildInfoReferencedMap | undefined, + ): BuilderState.ManyToManyPathMap | undefined { if (!referenceMap) { return undefined; } const map = BuilderState.createManyToManyPathMap(); - referenceMap.forEach(([fileId, fileIdListId]) => - map.set(toFilePath(fileId), toFilePathsSet(fileIdListId)) - ); + referenceMap.forEach(([fileId, fileIdListId]) => map.set(toFilePath(fileId), toFilePathsSet(fileIdListId))); return map; } } @@ -1896,7 +2202,7 @@ export function createBuilderProgramUsingProgramBuildInfo(buildInfo: BuildInfo, export function getBuildInfoFileVersionMap( program: ProgramBuildInfo, buildInfoPath: string, - host: Pick + host: Pick, ) { const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory())); const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); @@ -1926,7 +2232,10 @@ export function getBuildInfoFileVersionMap( } /** @internal */ -export function createRedirectedBuilderProgram(getState: () => { program?: Program | undefined; compilerOptions: CompilerOptions; }, configFileParsingDiagnostics: readonly Diagnostic[]): BuilderProgram { +export function createRedirectedBuilderProgram( + getState: () => { program?: Program | undefined; compilerOptions: CompilerOptions; }, + configFileParsingDiagnostics: readonly Diagnostic[], +): BuilderProgram { return { getState: notImplemented, saveEmitState: noop as BuilderProgram["saveEmitState"], @@ -1940,10 +2249,14 @@ export function createRedirectedBuilderProgram(getState: () => { program?: Progr getOptionsDiagnostics: cancellationToken => getProgram().getOptionsDiagnostics(cancellationToken), getGlobalDiagnostics: cancellationToken => getProgram().getGlobalDiagnostics(cancellationToken), getConfigFileParsingDiagnostics: () => configFileParsingDiagnostics, - getSyntacticDiagnostics: (sourceFile, cancellationToken) => getProgram().getSyntacticDiagnostics(sourceFile, cancellationToken), - getDeclarationDiagnostics: (sourceFile, cancellationToken) => getProgram().getDeclarationDiagnostics(sourceFile, cancellationToken), - getSemanticDiagnostics: (sourceFile, cancellationToken) => getProgram().getSemanticDiagnostics(sourceFile, cancellationToken), - emit: (sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers) => getProgram().emit(sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers), + getSyntacticDiagnostics: (sourceFile, cancellationToken) => + getProgram().getSyntacticDiagnostics(sourceFile, cancellationToken), + getDeclarationDiagnostics: (sourceFile, cancellationToken) => + getProgram().getDeclarationDiagnostics(sourceFile, cancellationToken), + getSemanticDiagnostics: (sourceFile, cancellationToken) => + getProgram().getSemanticDiagnostics(sourceFile, cancellationToken), + emit: (sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers) => + getProgram().emit(sourceFile, writeFile, cancellationToken, emitOnlyDts, customTransformers), emitBuildInfo: (writeFile, cancellationToken) => getProgram().emitBuildInfo(writeFile, cancellationToken), getAllDependencies: notImplemented, getCurrentDirectory: () => getProgram().getCurrentDirectory(), diff --git a/src/compiler/builderPublic.ts b/src/compiler/builderPublic.ts index 4cfcb731fb61c..a6ef2a942531f 100644 --- a/src/compiler/builderPublic.ts +++ b/src/compiler/builderPublic.ts @@ -100,7 +100,10 @@ export interface BuilderProgram { /** * Get the declaration diagnostics, for all source files if source file is not supplied */ - getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; + getDeclarationDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; /** * Get all the dependencies of the file */ @@ -126,7 +129,13 @@ export interface BuilderProgram { * 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 */ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult; + emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): EmitResult; /** @internal */ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult; /** @@ -145,7 +154,10 @@ export interface SemanticDiagnosticsBuilderProgram extends BuilderProgram { * Gets the semantic diagnostics from the program for the next affected file and caches it * Returns undefined if the iteration is complete */ - getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult; + getSemanticDiagnosticsOfNextAffectedFile( + cancellationToken?: CancellationToken, + ignoreSourceFile?: (sourceFile: SourceFile) => boolean, + ): AffectedFileResult; } /** @@ -158,34 +170,126 @@ export interface EmitAndSemanticDiagnosticsBuilderProgram extends SemanticDiagno * 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 */ - emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): AffectedFileResult; + emitNextAffectedFile( + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): AffectedFileResult; } /** * Create the builder to manage semantic diagnostics and cache them */ -export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): SemanticDiagnosticsBuilderProgram; -export function createSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): SemanticDiagnosticsBuilderProgram; -export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) { - return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences)); +export function createSemanticDiagnosticsBuilderProgram( + newProgram: Program, + host: BuilderProgramHost, + oldProgram?: SemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], +): SemanticDiagnosticsBuilderProgram; +export function createSemanticDiagnosticsBuilderProgram( + rootNames: readonly string[] | undefined, + options: CompilerOptions | undefined, + host?: CompilerHost, + oldProgram?: SemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], +): SemanticDiagnosticsBuilderProgram; +export function createSemanticDiagnosticsBuilderProgram( + newProgramOrRootNames: Program | readonly string[] | undefined, + hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, + oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, + configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | SemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], +) { + return createBuilderProgram( + BuilderProgramKind.SemanticDiagnosticsBuilderProgram, + getBuilderCreationParameters( + newProgramOrRootNames, + hostOrOptions, + oldProgramOrHost, + configFileParsingDiagnosticsOrOldProgram, + configFileParsingDiagnostics, + projectReferences, + ), + ); } /** * Create the builder that can handle the changes in program and iterate through changed files * to emit the those files and manage semantic diagnostics cache as well */ -export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): EmitAndSemanticDiagnosticsBuilderProgram; -export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): EmitAndSemanticDiagnosticsBuilderProgram; -export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) { - return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences)); +export function createEmitAndSemanticDiagnosticsBuilderProgram( + newProgram: Program, + host: BuilderProgramHost, + oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], +): EmitAndSemanticDiagnosticsBuilderProgram; +export function createEmitAndSemanticDiagnosticsBuilderProgram( + rootNames: readonly string[] | undefined, + options: CompilerOptions | undefined, + host?: CompilerHost, + oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], +): EmitAndSemanticDiagnosticsBuilderProgram; +export function createEmitAndSemanticDiagnosticsBuilderProgram( + newProgramOrRootNames: Program | readonly string[] | undefined, + hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, + oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, + configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | EmitAndSemanticDiagnosticsBuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], +) { + return createBuilderProgram( + BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, + getBuilderCreationParameters( + newProgramOrRootNames, + hostOrOptions, + oldProgramOrHost, + configFileParsingDiagnosticsOrOldProgram, + configFileParsingDiagnostics, + projectReferences, + ), + ); } /** * Creates a builder thats just abstraction over program and can be used with watch */ -export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): BuilderProgram; -export function createAbstractBuilder(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram; -export function createAbstractBuilder(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram { - const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences); - return createRedirectedBuilderProgram(() => ({ program: newProgram, compilerOptions: newProgram.getCompilerOptions() }), newConfigFileParsingDiagnostics); +export function createAbstractBuilder( + newProgram: Program, + host: BuilderProgramHost, + oldProgram?: BuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], +): BuilderProgram; +export function createAbstractBuilder( + rootNames: readonly string[] | undefined, + options: CompilerOptions | undefined, + host?: CompilerHost, + oldProgram?: BuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], +): BuilderProgram; +export function createAbstractBuilder( + newProgramOrRootNames: Program | readonly string[] | undefined, + hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, + oldProgramOrHost?: CompilerHost | BuilderProgram, + configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[], +): BuilderProgram { + const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = getBuilderCreationParameters( + newProgramOrRootNames, + hostOrOptions, + oldProgramOrHost, + configFileParsingDiagnosticsOrOldProgram, + configFileParsingDiagnostics, + projectReferences, + ); + return createRedirectedBuilderProgram( + () => ({ program: newProgram, compilerOptions: newProgram.getCompilerOptions() }), + newConfigFileParsingDiagnostics, + ); } diff --git a/src/compiler/builderState.ts b/src/compiler/builderState.ts index 5424336399c4e..fd98799a1e4b1 100644 --- a/src/compiler/builderState.ts +++ b/src/compiler/builderState.ts @@ -36,10 +36,23 @@ import { } from "./_namespaces/ts"; /** @internal */ -export function getFileEmitOutput(program: Program, sourceFile: SourceFile, emitOnlyDtsFiles: boolean, - cancellationToken?: CancellationToken, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitOutput { +export function getFileEmitOutput( + program: Program, + sourceFile: SourceFile, + emitOnlyDtsFiles: boolean, + cancellationToken?: CancellationToken, + customTransformers?: CustomTransformers, + forceDtsEmit?: boolean, +): EmitOutput { const outputFiles: OutputFile[] = []; - const { emitSkipped, diagnostics } = program.emit(sourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers, forceDtsEmit); + const { emitSkipped, diagnostics } = program.emit( + sourceFile, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers, + forceDtsEmit, + ); return { outputFiles, emitSkipped, diagnostics }; function writeFile(fileName: string, text: string, writeByteOrderMark: boolean) { @@ -118,7 +131,11 @@ export namespace BuilderState { } export function createManyToManyPathMap(): ManyToManyPathMap { - function create(forward: Map>, reverse: Map>, deleted: Set | undefined): ManyToManyPathMap { + function create( + forward: Map>, + reverse: Map>, + deleted: Set | undefined, + ): ManyToManyPathMap { const map: ManyToManyPathMap = { getKeys: v => reverse.get(v), getValues: k => forward.get(k), @@ -193,7 +210,10 @@ export namespace BuilderState { /** * Get the module source file and all augmenting files from the import name node from file */ - function getReferencedFilesFromImportLiteral(checker: TypeChecker, importName: StringLiteralLike): Path[] | undefined { + function getReferencedFilesFromImportLiteral( + checker: TypeChecker, + importName: StringLiteralLike, + ): Path[] | undefined { const symbol = checker.getSymbolAtLocation(importName); return symbol && getReferencedFilesFromImportedModuleSymbol(symbol); } @@ -201,14 +221,27 @@ export namespace BuilderState { /** * Gets the path to reference file from file name, it could be resolvedPath if present otherwise path */ - function getReferencedFileFromFileName(program: Program, fileName: string, sourceFileDirectory: Path, getCanonicalFileName: GetCanonicalFileName): Path { - return toPath(program.getProjectReferenceRedirect(fileName) || fileName, sourceFileDirectory, getCanonicalFileName); + function getReferencedFileFromFileName( + program: Program, + fileName: string, + sourceFileDirectory: Path, + getCanonicalFileName: GetCanonicalFileName, + ): Path { + return toPath( + program.getProjectReferenceRedirect(fileName) || fileName, + sourceFileDirectory, + getCanonicalFileName, + ); } /** * Gets the referenced files for a file from the program with values for the keys as referenced file's path to be true */ - function getReferencedFiles(program: Program, sourceFile: SourceFile, getCanonicalFileName: GetCanonicalFileName): Set | undefined { + function getReferencedFiles( + program: Program, + sourceFile: SourceFile, + getCanonicalFileName: GetCanonicalFileName, + ): Set | undefined { let referencedFiles: Set | undefined; // We need to use a set here since the code can contain the same import twice, @@ -226,7 +259,12 @@ export namespace BuilderState { // Handle triple slash references if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) { for (const referencedFile of sourceFile.referencedFiles) { - const referencedPath = getReferencedFileFromFileName(program, referencedFile.fileName, sourceFileDirectory, getCanonicalFileName); + const referencedPath = getReferencedFileFromFileName( + program, + referencedFile.fileName, + sourceFileDirectory, + getCanonicalFileName, + ); addReferencedFile(referencedPath); } } @@ -239,7 +277,12 @@ export namespace BuilderState { } const fileName = resolvedTypeReferenceDirective.resolvedFileName!; // TODO: GH#18217 - const typeFilePath = getReferencedFileFromFileName(program, fileName, sourceFileDirectory, getCanonicalFileName); + const typeFilePath = getReferencedFileFromFileName( + program, + fileName, + sourceFileDirectory, + getCanonicalFileName, + ); addReferencedFile(typeFilePath); }); } @@ -273,8 +316,10 @@ export namespace BuilderState { // Add any file other than our own as reference for (const declaration of symbol.declarations) { const declarationSourceFile = getSourceFileOfNode(declaration); - if (declarationSourceFile && - declarationSourceFile !== sourceFile) { + if ( + declarationSourceFile + && declarationSourceFile !== sourceFile + ) { addReferencedFile(declarationSourceFile.resolvedPath); } } @@ -288,19 +333,26 @@ export namespace BuilderState { /** * Returns true if oldState is reusable, that is the emitKind = module/non module has not changed */ - export function canReuseOldState(newReferencedMap: ReadonlyManyToManyPathMap | undefined, oldState: BuilderState | undefined) { + export function canReuseOldState( + newReferencedMap: ReadonlyManyToManyPathMap | undefined, + oldState: BuilderState | undefined, + ) { return oldState && !oldState.referencedMap === !newReferencedMap; } /** * Creates the state of file references and signature for the new program from oldState if it is safe */ - export function create(newProgram: Program, oldState: Readonly | undefined, disableUseFileVersionAsSignature: boolean): BuilderState { + export function create( + newProgram: Program, + oldState: Readonly | undefined, + disableUseFileVersionAsSignature: boolean, + ): BuilderState { const fileInfos = new Map(); const options = newProgram.getCompilerOptions(); const isOutFile = outFile(options); - const referencedMap = options.module !== ModuleKind.None && !isOutFile ? - createManyToManyPathMap() : undefined; + const referencedMap = options.module !== ModuleKind.None && !isOutFile + ? createManyToManyPathMap() : undefined; const exportedModulesMap = referencedMap ? createManyToManyPathMap() : undefined; const useOldState = canReuseOldState(referencedMap, oldState); @@ -309,11 +361,15 @@ export namespace BuilderState { // Create the reference map, and set the file infos for (const sourceFile of newProgram.getSourceFiles()) { - const version = Debug.checkDefined(sourceFile.version, "Program intended to be used with Builder should have source files with versions set"); - const oldUncommittedSignature = useOldState ? oldState!.oldSignatures?.get(sourceFile.resolvedPath) : undefined; - const signature = oldUncommittedSignature === undefined ? - useOldState ? oldState!.fileInfos.get(sourceFile.resolvedPath)?.signature : undefined : - oldUncommittedSignature || undefined; + const version = Debug.checkDefined( + sourceFile.version, + "Program intended to be used with Builder should have source files with versions set", + ); + const oldUncommittedSignature = useOldState ? oldState!.oldSignatures?.get(sourceFile.resolvedPath) + : undefined; + const signature = oldUncommittedSignature === undefined + ? useOldState ? oldState!.fileInfos.get(sourceFile.resolvedPath)?.signature : undefined + : oldUncommittedSignature || undefined; if (referencedMap) { const newReferences = getReferencedFiles(newProgram, sourceFile, newProgram.getCanonicalFileName); if (newReferences) { @@ -322,9 +378,9 @@ export namespace BuilderState { // Copy old visible to outside files map if (useOldState) { const oldUncommittedExportedModules = oldState!.oldExportedModulesMap?.get(sourceFile.resolvedPath); - const exportedModules = oldUncommittedExportedModules === undefined ? - oldState!.exportedModulesMap!.getValues(sourceFile.resolvedPath) : - oldUncommittedExportedModules || undefined; + const exportedModules = oldUncommittedExportedModules === undefined + ? oldState!.exportedModulesMap!.getValues(sourceFile.resolvedPath) + : oldUncommittedExportedModules || undefined; if (exportedModules) { exportedModulesMap!.set(sourceFile.resolvedPath, exportedModules); } @@ -335,7 +391,7 @@ export namespace BuilderState { signature, // No need to calculate affectsGlobalScope with --out since its not used at all affectsGlobalScope: !isOutFile ? isFileAffectingGlobalScope(sourceFile) || undefined : undefined, - impliedFormat: sourceFile.impliedNodeFormat + impliedFormat: sourceFile.impliedNodeFormat, }); } @@ -343,7 +399,7 @@ export namespace BuilderState { fileInfos, referencedMap, exportedModulesMap, - useFileVersionAsSignature: !disableUseFileVersionAsSignature && !useOldState + useFileVersionAsSignature: !disableUseFileVersionAsSignature && !useOldState, }; } @@ -393,7 +449,14 @@ export namespace BuilderState { return [sourceFile]; } - return (state.referencedMap ? getFilesAffectedByUpdatedShapeWhenModuleEmit : getFilesAffectedByUpdatedShapeWhenNonModuleEmit)(state, programOfThisState, sourceFile, cancellationToken, host); + return (state.referencedMap ? getFilesAffectedByUpdatedShapeWhenModuleEmit + : getFilesAffectedByUpdatedShapeWhenNonModuleEmit)( + state, + programOfThisState, + sourceFile, + cancellationToken, + host, + ); } export function updateSignatureOfFile(state: BuilderState, signature: string | undefined, path: Path) { @@ -411,19 +474,25 @@ export namespace BuilderState { programOfThisState.emit( sourceFile, (fileName, text, _writeByteOrderMark, _onError, sourceFiles, data) => { - Debug.assert(isDeclarationFileName(fileName), `File extension for signature expected to be dts: Got:: ${fileName}`); - onNewSignature(computeSignatureWithDiagnostics( - programOfThisState, - sourceFile, - text, - host, - data, - ), sourceFiles!); + Debug.assert( + isDeclarationFileName(fileName), + `File extension for signature expected to be dts: Got:: ${fileName}`, + ); + onNewSignature( + computeSignatureWithDiagnostics( + programOfThisState, + sourceFile, + text, + host, + data, + ), + sourceFiles!, + ); }, cancellationToken, /*emitOnly*/ true, /*customTransformers*/ undefined, - /*forceDtsEmit*/ true + /*forceDtsEmit*/ true, ); } @@ -456,9 +525,13 @@ export namespace BuilderState { if (latestSignature === undefined) { latestSignature = sourceFile.version; if (state.exportedModulesMap && latestSignature !== prevSignature) { - (state.oldExportedModulesMap ||= new Map()).set(sourceFile.resolvedPath, state.exportedModulesMap.getValues(sourceFile.resolvedPath) || false); + (state.oldExportedModulesMap ||= new Map()).set( + sourceFile.resolvedPath, + state.exportedModulesMap.getValues(sourceFile.resolvedPath) || false, + ); // All the references in this file are exported - const references = state.referencedMap ? state.referencedMap.getValues(sourceFile.resolvedPath) : undefined; + const references = state.referencedMap ? state.referencedMap.getValues(sourceFile.resolvedPath) + : undefined; if (references) { state.exportedModulesMap.set(sourceFile.resolvedPath, references); } @@ -476,9 +549,16 @@ export namespace BuilderState { /** * Coverts the declaration emit result into exported modules map */ - export function updateExportedModules(state: BuilderState, sourceFile: SourceFile, exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined) { + export function updateExportedModules( + state: BuilderState, + sourceFile: SourceFile, + exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined, + ) { if (!state.exportedModulesMap) return; - (state.oldExportedModulesMap ||= new Map()).set(sourceFile.resolvedPath, state.exportedModulesMap.getValues(sourceFile.resolvedPath) || false); + (state.oldExportedModulesMap ||= new Map()).set( + sourceFile.resolvedPath, + state.exportedModulesMap.getValues(sourceFile.resolvedPath) || false, + ); const exportedModules = getExportedModules(exportedModulesFromDeclarationEmit); if (exportedModules) { state.exportedModulesMap.set(sourceFile.resolvedPath, exportedModules); @@ -488,12 +568,15 @@ export namespace BuilderState { } } - export function getExportedModules(exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined) { + export function getExportedModules( + exportedModulesFromDeclarationEmit: ExportedModulesFromDeclarationEmit | undefined, + ) { let exportedModules: Set | undefined; exportedModulesFromDeclarationEmit?.forEach( - symbol => getReferencedFilesFromImportedModuleSymbol(symbol).forEach( - path => (exportedModules ??= new Set()).add(path) - ) + symbol => + getReferencedFilesFromImportedModuleSymbol(symbol).forEach( + path => (exportedModules ??= new Set()).add(path), + ), ); return exportedModules; } @@ -501,7 +584,11 @@ export namespace BuilderState { /** * Get all the dependencies of the sourceFile */ - export function getAllDependencies(state: BuilderState, programOfThisState: Program, sourceFile: SourceFile): readonly string[] { + export function getAllDependencies( + state: BuilderState, + programOfThisState: Program, + sourceFile: SourceFile, + ): readonly string[] { const compilerOptions = programOfThisState.getCompilerOptions(); // With --out or --outFile all outputs go into single file, all files depend on each other if (outFile(compilerOptions)) { @@ -529,7 +616,9 @@ export namespace BuilderState { } } - return arrayFrom(mapDefinedIterator(seenMap.keys(), path => programOfThisState.getSourceFileByPath(path)?.fileName ?? path)); + return arrayFrom( + mapDefinedIterator(seenMap.keys(), path => programOfThisState.getSourceFileByPath(path)?.fileName ?? path), + ); } /** @@ -571,21 +660,29 @@ export namespace BuilderState { * they are global files as well as module */ function containsGlobalScopeAugmentation(sourceFile: SourceFile) { - return some(sourceFile.moduleAugmentations, augmentation => isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration)); + return some( + sourceFile.moduleAugmentations, + augmentation => isGlobalScopeAugmentation(augmentation.parent as ModuleDeclaration), + ); } /** * Return true if the file will invalidate all files because it affectes global scope */ function isFileAffectingGlobalScope(sourceFile: SourceFile) { - return containsGlobalScopeAugmentation(sourceFile) || - !isExternalOrCommonJsModule(sourceFile) && !isJsonSourceFile(sourceFile) && !containsOnlyAmbientModules(sourceFile); + return containsGlobalScopeAugmentation(sourceFile) + || !isExternalOrCommonJsModule(sourceFile) && !isJsonSourceFile(sourceFile) + && !containsOnlyAmbientModules(sourceFile); } /** * Gets all files of the program excluding the default library file */ - export function getAllFilesExcludingDefaultLibraryFile(state: BuilderState, programOfThisState: Program, firstSourceFile: SourceFile | undefined): readonly SourceFile[] { + export function getAllFilesExcludingDefaultLibraryFile( + state: BuilderState, + programOfThisState: Program, + firstSourceFile: SourceFile | undefined, + ): readonly SourceFile[] { // Use cached result if (state.allFilesExcludingDefaultLibraryFile) { return state.allFilesExcludingDefaultLibraryFile; @@ -611,7 +708,11 @@ export namespace BuilderState { /** * When program emits non modular code, gets the files affected by the sourceFile whose shape has changed */ - function getFilesAffectedByUpdatedShapeWhenNonModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile) { + function getFilesAffectedByUpdatedShapeWhenNonModuleEmit( + state: BuilderState, + programOfThisState: Program, + sourceFileWithUpdatedShape: SourceFile, + ) { const compilerOptions = programOfThisState.getCompilerOptions(); // If `--out` or `--outFile` is specified, any new emit will result in re-emitting the entire project, // so returning the file itself is good enough. @@ -653,7 +754,10 @@ export namespace BuilderState { if (!seenFileNamesMap.has(currentPath)) { const currentSourceFile = programOfThisState.getSourceFileByPath(currentPath)!; seenFileNamesMap.set(currentPath, currentSourceFile); - if (currentSourceFile && updateShapeSignature(state, programOfThisState, currentSourceFile, cancellationToken, host)) { + if ( + currentSourceFile + && updateShapeSignature(state, programOfThisState, currentSourceFile, cancellationToken, host) + ) { queue.push(...getReferencedByPaths(state, currentSourceFile.resolvedPath)); } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 918da100936a7..1def4db0989c4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1075,7 +1075,7 @@ import { WhileStatement, WideningContext, WithStatement, - YieldExpression + YieldExpression, } from "./_namespaces/ts"; import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers"; import * as performance from "./_namespaces/ts.performance"; @@ -1111,7 +1111,6 @@ const enum IterationUse { GeneratorReturnType = AllowsSyncIterablesFlag, AsyncGeneratorReturnType = AllowsAsyncIterablesFlag, - } const enum IterationTypeKind { @@ -1141,6 +1140,7 @@ const enum WideningKind { GeneratorYield, } +// dprint-ignore /** @internal */ export const enum TypeFacts { None = 0, @@ -1233,7 +1233,7 @@ const typeofNEFacts: ReadonlyMap = new Map(Object.entries({ symbol: TypeFacts.TypeofNESymbol, undefined: TypeFacts.NEUndefined, object: TypeFacts.TypeofNEObject, - function: TypeFacts.TypeofNEFunction + function: TypeFacts.TypeofNEFunction, })); type TypeSystemEntity = Node | Symbol | Type | Signature; @@ -1251,6 +1251,7 @@ const enum TypeSystemPropertyName { ParameterInitializerContainsUndefined, } +// dprint-ignore /** @internal */ export const enum CheckMode { Normal = 0, // Normal type checking @@ -1279,8 +1280,8 @@ export const enum SignatureCheckMode { const enum IntersectionState { None = 0, - Source = 1 << 0, // Source type is a constituent of an outer intersection - Target = 1 << 1, // Target type is a constituent of an outer intersection + Source = 1 << 0, // Source type is a constituent of an outer intersection + Target = 1 << 1, // Target type is a constituent of an outer intersection } const enum RecursionFlags { @@ -1306,7 +1307,7 @@ const enum ExpandingFlags { const enum MembersOrExportsResolutionKind { resolvedExports = "resolvedExports", - resolvedMembers = "resolvedMembers" + resolvedMembers = "resolvedMembers", } const enum UnusedKind { @@ -1346,14 +1347,14 @@ const enum IntrinsicTypeKind { Uppercase, Lowercase, Capitalize, - Uncapitalize + Uncapitalize, } const intrinsicTypeKinds: ReadonlyMap = new Map(Object.entries({ Uppercase: IntrinsicTypeKind.Uppercase, Lowercase: IntrinsicTypeKind.Lowercase, Capitalize: IntrinsicTypeKind.Capitalize, - Uncapitalize: IntrinsicTypeKind.Uncapitalize + Uncapitalize: IntrinsicTypeKind.Uncapitalize, })); const SymbolLinks = class implements SymbolLinks { @@ -1386,8 +1387,8 @@ export function getSymbolId(symbol: Symbol): SymbolId { /** @internal */ export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) { const moduleState = getModuleInstanceState(node); - return moduleState === ModuleInstanceState.Instantiated || - (preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly); + return moduleState === ModuleInstanceState.Instantiated + || (preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly); } /** @internal */ @@ -1470,7 +1471,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules"; // It is an error to use `importsNotUsedAsValues` alongside `verbatimModuleSyntax`, but we still need to not crash. // Given that, in such a scenario, `verbatimModuleSyntax` is basically disabled, as least as far as alias visibility tracking goes. - var canCollectSymbolAliasAccessabilityData = !compilerOptions.verbatimModuleSyntax || !!compilerOptions.importsNotUsedAsValues; + var canCollectSymbolAliasAccessabilityData = !compilerOptions.verbatimModuleSyntax + || !!compilerOptions.importsNotUsedAsValues; /** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */ var apparentArgumentCount: number | undefined; @@ -1512,7 +1514,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getTypeOfSymbol, getSymbolsOfParameterPropertyDeclaration: (parameterIn, parameterName) => { const parameter = getParseTreeNode(parameterIn, isParameter); - if (parameter === undefined) return Debug.fail("Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node."); + if (parameter === undefined) { + return Debug.fail( + "Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node.", + ); + } Debug.assert(isParameterPropertyDeclaration(parameter, parameter.parent)); return getSymbolsOfParameterPropertyDeclaration(parameter, escapeLeadingUnderscores(parameterName)); }, @@ -1526,14 +1532,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const propName = escapeLeadingUnderscores(name); const lexicallyScopedIdentifier = lookupSymbolForPrivateIdentifierDeclaration(propName, node); - return lexicallyScopedIdentifier ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedIdentifier) : undefined; + return lexicallyScopedIdentifier ? getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedIdentifier) + : undefined; }, getTypeOfPropertyOfType: (type, name) => getTypeOfPropertyOfType(type, escapeLeadingUnderscores(name)), - getIndexInfoOfType: (type, kind) => getIndexInfoOfType(type, kind === IndexKind.String ? stringType : numberType), + getIndexInfoOfType: (type, kind) => + getIndexInfoOfType(type, kind === IndexKind.String ? stringType : numberType), getIndexInfosOfType, getIndexInfosOfIndexSymbol, getSignaturesOfType, - getIndexTypeOfType: (type, kind) => getIndexTypeOfType(type, kind === IndexKind.String ? stringType : numberType), + getIndexTypeOfType: (type, kind) => + getIndexTypeOfType(type, kind === IndexKind.String ? stringType : numberType), getIndexType: type => getIndexType(type), getBaseTypes, getBaseTypeOfLiteralType, @@ -1642,7 +1651,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const node = getParseTreeNode(nodeIn, isCallLikeExpression); return node && getContextualTypeForArgumentAtIndex(node, argIndex); }, - getContextualTypeForJsxAttribute: (nodeIn) => { + getContextualTypeForJsxAttribute: nodeIn => { const node = getParseTreeNode(nodeIn, isJsxAttributeLike); return node && getContextualTypeForJsxAttribute(node, /*contextFlags*/ undefined); }, @@ -1651,14 +1660,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getFullyQualifiedName, getResolvedSignature: (node, candidatesOutArray, argumentCount) => getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.Normal), - getResolvedSignatureForStringLiteralCompletions: (call, editingArgument, candidatesOutArray, checkMode = CheckMode.IsForStringLiteralArgumentCompletions) => { + getResolvedSignatureForStringLiteralCompletions: ( + call, + editingArgument, + candidatesOutArray, + checkMode = CheckMode.IsForStringLiteralArgumentCompletions, + ) => { if (checkMode & CheckMode.IsForStringLiteralArgumentCompletions) { - return runWithInferenceBlockedFromSourceNode(editingArgument, () => getResolvedSignatureWorker(call, candidatesOutArray, /*argumentCount*/ undefined, checkMode & ~CheckMode.IsForStringLiteralArgumentCompletions)); + return runWithInferenceBlockedFromSourceNode( + editingArgument, + () => + getResolvedSignatureWorker( + call, + candidatesOutArray, + /*argumentCount*/ undefined, + checkMode & ~CheckMode.IsForStringLiteralArgumentCompletions, + ), + ); } - return runWithoutResolvedSignatureCaching(editingArgument, () => getResolvedSignatureWorker(call, candidatesOutArray, /*argumentCount*/ undefined, checkMode & ~CheckMode.IsForStringLiteralArgumentCompletions)); + return runWithoutResolvedSignatureCaching( + editingArgument, + () => + getResolvedSignatureWorker( + call, + candidatesOutArray, + /*argumentCount*/ undefined, + checkMode & ~CheckMode.IsForStringLiteralArgumentCompletions, + ), + ); }, getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, argumentCount) => - runWithoutResolvedSignatureCaching(node, () => getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.IsForSignatureHelp)), + runWithoutResolvedSignatureCaching( + node, + () => getResolvedSignatureWorker(node, candidatesOutArray, argumentCount, CheckMode.IsForSignatureHelp), + ), getExpandedParameters, hasEffectiveRestParameter, containsArgumentsReference, @@ -1706,8 +1741,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const node = getParseTreeNode(nodeIn, isParameter); return node ? isOptionalParameter(node) : false; }, - tryGetMemberInModuleExports: (name, symbol) => tryGetMemberInModuleExports(escapeLeadingUnderscores(name), symbol), - tryGetMemberInModuleExportsAndProperties: (name, symbol) => tryGetMemberInModuleExportsAndProperties(escapeLeadingUnderscores(name), symbol), + tryGetMemberInModuleExports: (name, symbol) => + tryGetMemberInModuleExports(escapeLeadingUnderscores(name), symbol), + tryGetMemberInModuleExportsAndProperties: (name, symbol) => + tryGetMemberInModuleExportsAndProperties(escapeLeadingUnderscores(name), symbol), tryFindAmbientModule: moduleName => tryFindAmbientModule(moduleName, /*withAugmentations*/ true), tryFindAmbientModuleWithoutAugmentations: moduleName => { // we deliberately exclude augmentations @@ -1757,15 +1794,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getSuggestedSymbolForNonexistentProperty, getSuggestionForNonexistentProperty, getSuggestedSymbolForNonexistentJSXAttribute, - getSuggestedSymbolForNonexistentSymbol: (location, name, meaning) => getSuggestedSymbolForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), - getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), + getSuggestedSymbolForNonexistentSymbol: (location, name, meaning) => + getSuggestedSymbolForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), + getSuggestionForNonexistentSymbol: (location, name, meaning) => + getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), getSuggestedSymbolForNonexistentModule, getSuggestionForNonexistentExport, getSuggestedSymbolForNonexistentClassMember, getBaseConstraintOfType, - getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined, + getDefaultFromTypeParameter: type => + type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) + : undefined, resolveName(name, location, meaning, excludeGlobals) { - return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false, excludeGlobals); + return resolveName( + location, + escapeLeadingUnderscores(name), + meaning, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + excludeGlobals, + ); }, getJsxNamespace: n => unescapeLeadingUnderscores(getJsxNamespace(n)), getJsxFragmentFactory: n => { @@ -1776,7 +1825,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getTypePredicateOfSignature, resolveExternalModuleName: moduleSpecifierIn => { const moduleSpecifier = getParseTreeNode(moduleSpecifierIn, isExpression); - return moduleSpecifier && resolveExternalModuleName(moduleSpecifier, moduleSpecifier, /*ignoreErrors*/ true); + return moduleSpecifier + && resolveExternalModuleName(moduleSpecifier, moduleSpecifier, /*ignoreErrors*/ true); }, resolveExternalModuleSymbol, tryGetThisTypeAt: (nodeIn, includeGlobalThis, container) => { @@ -1788,7 +1838,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return node && getTypeArgumentConstraint(node); }, getSuggestionDiagnostics: (fileIn, ct) => { - const file = getParseTreeNode(fileIn, isSourceFile) || Debug.fail("Could not determine parsed source file."); + const file = getParseTreeNode(fileIn, isSourceFile) + || Debug.fail("Could not determine parsed source file."); if (skipTypeChecking(file, compilerOptions, host)) { return emptyArray; } @@ -1806,7 +1857,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { diagnostics = addRange(diagnostics, suggestionDiagnostics.getDiagnostics(file.fileName)); checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (containingNode, kind, diag) => { - if (!containsParseError(containingNode) && !unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient))) { + if ( + !containsParseError(containingNode) + && !unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient)) + ) { (diagnostics || (diagnostics = [])).push({ ...diag, category: DiagnosticCategory.Suggestion }); } }); @@ -1862,7 +1916,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { do { getNodeLinks(toMarkSkip).skipDirectInference = true; toMarkSkip = toMarkSkip.parent; - } while (toMarkSkip && toMarkSkip !== containingCall); + } + while (toMarkSkip && toMarkSkip !== containingCall); } isInferencePartiallyBlocked = true; @@ -1874,12 +1929,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { do { getNodeLinks(toMarkSkip).skipDirectInference = undefined; toMarkSkip = toMarkSkip.parent; - } while (toMarkSkip && toMarkSkip !== containingCall); + } + while (toMarkSkip && toMarkSkip !== containingCall); } return result; } - function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, checkMode: CheckMode): Signature | undefined { + function getResolvedSignatureWorker( + nodeIn: CallLikeExpression, + candidatesOutArray: Signature[] | undefined, + argumentCount: number | undefined, + checkMode: CheckMode, + ): Signature | undefined { const node = getParseTreeNode(nodeIn, isCallLikeExpression); apparentArgumentCount = argumentCount; const res = !node ? undefined : getResolvedSignature(node, candidatesOutArray, checkMode); @@ -1925,12 +1986,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); var nonNullUnknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); var undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined"); - var undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType); + var undefinedWideningType = strictNullChecks ? undefinedType + : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType); var missingType = createIntrinsicType(TypeFlags.Undefined, "undefined"); var undefinedOrMissingType = exactOptionalPropertyTypes ? missingType : undefinedType; var optionalType = createIntrinsicType(TypeFlags.Undefined, "undefined"); var nullType = createIntrinsicType(TypeFlags.Null, "null"); - var nullWideningType = strictNullChecks ? nullType : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType); + var nullWideningType = strictNullChecks ? nullType + : createIntrinsicType(TypeFlags.Null, "null", ObjectFlags.ContainsWideningType); var stringType = createIntrinsicType(TypeFlags.String, "string"); var numberType = createIntrinsicType(TypeFlags.Number, "number"); var bigintType = createIntrinsicType(TypeFlags.BigInt, "bigint"); @@ -1958,13 +2021,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var stringNumberSymbolType = getUnionType([stringType, numberType, esSymbolType]); var keyofConstraintType = keyofStringsOnly ? stringType : stringNumberSymbolType; var numberOrBigIntType = getUnionType([numberType, bigintType]); - var templateConstraintType = getUnionType([stringType, numberType, booleanType, bigintType, nullType, undefinedType]) as UnionType; - var numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type - - var restrictiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t, () => "(restrictive mapper)"); - var permissiveMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? wildcardType : t, () => "(permissive mapper)"); + var templateConstraintType = getUnionType([ + stringType, + numberType, + booleanType, + bigintType, + nullType, + undefinedType, + ]) as UnionType; + var numericStringType = getTemplateLiteralType(["", ""], [numberType]); // The `${number}` type + + var restrictiveMapper: TypeMapper = makeFunctionTypeMapper( + t => t.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(t as TypeParameter) : t, + () => "(restrictive mapper)", + ); + var permissiveMapper: TypeMapper = makeFunctionTypeMapper( + t => t.flags & TypeFlags.TypeParameter ? wildcardType : t, + () => "(permissive mapper)", + ); var uniqueLiteralType = createIntrinsicType(TypeFlags.Never, "never"); // `uniqueLiteralType` is a special `never` flagged by union reduction to behave as a literal - var uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper(t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t, () => "(unique literal mapper)"); // replace all type parameters with the unique literal type (disregarding constraints) + var uniqueLiteralMapper: TypeMapper = makeFunctionTypeMapper( + t => t.flags & TypeFlags.TypeParameter ? uniqueLiteralType : t, + () => "(unique literal mapper)", + ); // replace all type parameters with the unique literal type (disregarding constraints) var outofbandVarianceMarkerHandler: ((onlyUnreliable: boolean) => void) | undefined; var reportUnreliableMapper = makeFunctionTypeMapper(t => { if (outofbandVarianceMarkerHandler && (t === markerSuperType || t === markerSubType || t === markerOtherType)) { @@ -1980,17 +2059,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }, () => "(unreliable reporter)"); var emptyObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - var emptyJsxObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); + var emptyJsxObjectType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray, + ); emptyJsxObjectType.objectFlags |= ObjectFlags.JsxAttributes; var emptyTypeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); emptyTypeLiteralSymbol.members = createSymbolTable(); - var emptyTypeLiteralType = createAnonymousType(emptyTypeLiteralSymbol, emptySymbols, emptyArray, emptyArray, emptyArray); - - var unknownEmptyObjectType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - var unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) : unknownType; - - var emptyGenericType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray) as ObjectType as GenericType; + var emptyTypeLiteralType = createAnonymousType( + emptyTypeLiteralSymbol, + emptySymbols, + emptyArray, + emptyArray, + emptyArray, + ); + + var unknownEmptyObjectType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray, + ); + var unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) + : unknownType; + + var emptyGenericType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray, + ) as ObjectType as GenericType; emptyGenericType.instantiations = new Map(); var anyFunctionType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); @@ -1999,8 +2103,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { anyFunctionType.objectFlags |= ObjectFlags.NonInferrableType; var noConstraintType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - var circularConstraintType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); - var resolvingDefaultType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); + var circularConstraintType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray, + ); + var resolvingDefaultType = createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + emptyArray, + ); var markerSuperType = createTypeParameter(); var markerSubType = createTypeParameter(); @@ -2013,18 +2129,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var noTypePredicate = createTypePredicate(TypePredicateKind.Identifier, "<>", 0, anyType); - var anySignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - var unknownSignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, errorType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - var resolvingSignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, anyType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); - var silentNeverSignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, silentNeverType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.None); + var anySignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + anyType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); + var unknownSignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + errorType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); + var resolvingSignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + anyType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); + var silentNeverSignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + silentNeverType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.None, + ); var enumNumberIndexInfo = createIndexInfo(numberType, stringType, /*isReadonly*/ true); var iterationTypesCache = new Map(); // cache for common IterationTypes instances var noIterationTypes: IterationTypes = { - get yieldType(): Type { return Debug.fail("Not supported"); }, - get returnType(): Type { return Debug.fail("Not supported"); }, - get nextType(): Type { return Debug.fail("Not supported"); }, + get yieldType(): Type { + return Debug.fail("Not supported"); + }, + get returnType(): Type { + return Debug.fail("Not supported"); + }, + get nextType(): Type { + return Debug.fail("Not supported"); + }, }; var anyIterationTypes = createIterationTypes(anyType, anyType, anyType); @@ -2039,10 +2197,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getGlobalIterableType: getGlobalAsyncIterableType, getGlobalIterableIteratorType: getGlobalAsyncIterableIteratorType, getGlobalGeneratorType: getGlobalAsyncGeneratorType, - resolveIterationType: (type, errorNode) => getAwaitedType(type, errorNode, Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member), + resolveIterationType: (type, errorNode) => + getAwaitedType( + type, + errorNode, + Diagnostics + .Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ), mustHaveANextMethodDiagnostic: Diagnostics.An_async_iterator_must_have_a_next_method, mustBeAMethodDiagnostic: Diagnostics.The_0_property_of_an_async_iterator_must_be_a_method, - mustHaveAValueDiagnostic: Diagnostics.The_type_returned_by_the_0_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value_property, + mustHaveAValueDiagnostic: Diagnostics + .The_type_returned_by_the_0_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value_property, }; var syncIterationTypesResolver: IterationTypesResolver = { @@ -2056,7 +2221,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resolveIterationType: (type, _errorNode) => type, mustHaveANextMethodDiagnostic: Diagnostics.An_iterator_must_have_a_next_method, mustBeAMethodDiagnostic: Diagnostics.The_0_property_of_an_iterator_must_be_a_method, - mustHaveAValueDiagnostic: Diagnostics.The_type_returned_by_the_0_method_of_an_iterator_must_have_a_value_property, + mustHaveAValueDiagnostic: + Diagnostics.The_type_returned_by_the_0_method_of_an_iterator_must_have_a_value_property, }; interface DuplicateInfoForSymbol { @@ -2250,10 +2416,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const jsxFragmentPragma = file.pragmas.get("jsxfrag"); if (jsxFragmentPragma) { const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma; - file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion); + file.localJsxFragmentFactory = parseIsolatedEntityName( + chosenPragma.arguments.factory, + languageVersion, + ); visitNode(file.localJsxFragmentFactory, markAsSynthetic, isEntityName); if (file.localJsxFragmentFactory) { - return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText; + return file.localJsxFragmentNamespace = + getFirstIdentifier(file.localJsxFragmentFactory).escapedText; } } const entity = getJsxFragmentFactoryEntity(location); @@ -2284,7 +2454,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (!_jsxFactoryEntity) { - _jsxFactoryEntity = factory.createQualifiedName(factory.createIdentifier(unescapeLeadingUnderscores(_jsxNamespace)), "createElement"); + _jsxFactoryEntity = factory.createQualifiedName( + factory.createIdentifier(unescapeLeadingUnderscores(_jsxNamespace)), + "createElement", + ); } return _jsxNamespace; } @@ -2316,7 +2489,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return emitResolver; } - function lookupOrIssueError(location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + function lookupOrIssueError( + location: Node | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): Diagnostic { const diagnostic = location ? createDiagnosticForNode(location, message, ...args) : createCompilerDiagnostic(message, ...args); @@ -2330,13 +2507,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function errorSkippedOn(key: keyof CompilerOptions, location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + function errorSkippedOn( + key: keyof CompilerOptions, + location: Node | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): Diagnostic { const diagnostic = error(location, message, ...args); diagnostic.skippedOn = key; return diagnostic; } - function createError(location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + function createError( + location: Node | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): Diagnostic { return location ? createDiagnosticForNode(location, message, ...args) : createCompilerDiagnostic(message, ...args); @@ -2356,25 +2542,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { suggestionDiagnostics.add({ ...diagnostic, category: DiagnosticCategory.Suggestion }); } } - function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): void { - // Pseudo-synthesized input node + function errorOrSuggestion( + isError: boolean, + location: Node, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: DiagnosticArguments + ): void { + // Pseudo-synthesized input node if (location.pos < 0 || location.end < 0) { if (!isError) { return; // Drop suggestions (we have no span to suggest on) } // Issue errors globally const file = getSourceFileOfNode(location); - addErrorOrSuggestion(isError, "message" in message ? createFileDiagnostic(file, 0, 0, message, ...args) : createDiagnosticForFileFromMessageChain(file, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion( + isError, + "message" in message ? createFileDiagnostic(file, 0, 0, message, ...args) + : createDiagnosticForFileFromMessageChain(file, message), + ); // eslint-disable-line local/no-in-operator return; } - addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, ...args) : createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(location), location, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion( + isError, + "message" in message ? createDiagnosticForNode(location, message, ...args) + : createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(location), location, message), + ); // eslint-disable-line local/no-in-operator } function errorAndMaybeSuggestAwait( location: Node, maybeMissingAwait: boolean, message: DiagnosticMessage, - ...args: DiagnosticArguments): Diagnostic { + ...args: DiagnosticArguments + ): Diagnostic { const diagnostic = error(location, message, ...args); if (maybeMissingAwait) { const related = createDiagnosticForNode(location, Diagnostics.Did_you_forget_to_use_await); @@ -2384,11 +2584,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function addDeprecatedSuggestionWorker(declarations: Node | Node[], diagnostic: DiagnosticWithLocation) { - const deprecatedTag = Array.isArray(declarations) ? forEach(declarations, getJSDocDeprecatedTag) : getJSDocDeprecatedTag(declarations); + const deprecatedTag = Array.isArray(declarations) ? forEach(declarations, getJSDocDeprecatedTag) + : getJSDocDeprecatedTag(declarations); if (deprecatedTag) { addRelatedInfo( diagnostic, - createDiagnosticForNode(deprecatedTag, Diagnostics.The_declaration_was_marked_as_deprecated_here) + createDiagnosticForNode(deprecatedTag, Diagnostics.The_declaration_was_marked_as_deprecated_here), ); } // We call `addRelatedInfo()` before adding the diagnostic to prevent duplicates. @@ -2399,7 +2600,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isDeprecatedSymbol(symbol: Symbol) { const parentSymbol = getParentOfSymbol(symbol); if (parentSymbol && length(symbol.declarations) > 1) { - return parentSymbol.flags & SymbolFlags.Interface ? some(symbol.declarations, isDeprecatedDeclaration) : every(symbol.declarations, isDeprecatedDeclaration); + return parentSymbol.flags & SymbolFlags.Interface ? some(symbol.declarations, isDeprecatedDeclaration) + : every(symbol.declarations, isDeprecatedDeclaration); } return !!symbol.valueDeclaration && isDeprecatedDeclaration(symbol.valueDeclaration) || length(symbol.declarations) && every(symbol.declarations, isDeprecatedDeclaration); @@ -2414,9 +2616,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return addDeprecatedSuggestionWorker(declarations, diagnostic); } - function addDeprecatedSuggestionWithSignature(location: Node, declaration: Node, deprecatedEntity: string | undefined, signatureString: string) { + function addDeprecatedSuggestionWithSignature( + location: Node, + declaration: Node, + deprecatedEntity: string | undefined, + signatureString: string, + ) { const diagnostic = deprecatedEntity - ? createDiagnosticForNode(location, Diagnostics.The_signature_0_of_1_is_deprecated, signatureString, deprecatedEntity) + ? createDiagnosticForNode( + location, + Diagnostics.The_signature_0_of_1_is_deprecated, + signatureString, + deprecatedEntity, + ) : createDiagnosticForNode(location, Diagnostics._0_is_deprecated, signatureString); return addDeprecatedSuggestionWorker(declaration, diagnostic); } @@ -2487,8 +2699,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * If target is not transient, mergeSymbol will produce a transient clone, mutate that and return it. */ function mergeSymbol(target: Symbol, source: Symbol, unidirectional = false): Symbol { - if (!(target.flags & getExcludedSymbolFlags(source.flags)) || - (source.flags | target.flags) & SymbolFlags.Assignment) { + if ( + !(target.flags & getExcludedSymbolFlags(source.flags)) + || (source.flags | target.flags) & SymbolFlags.Assignment + ) { if (source === target) { // This can happen when an export assigned namespace exports something also erroneously exported at the top level // See `declarationFileNoCrashOnExtraExportModifier` for an example @@ -2502,7 +2716,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target = cloneSymbol(resolvedTarget); } // Javascript static-property-assignment declarations always merge, even though they are also values - if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) { + if ( + source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule + && target.constEnumOnlyModule && !source.constEnumOnlyModule + ) { // reset flag when merging instantiated module into value module that has only const enums target.constEnumOnlyModule = false; } @@ -2531,13 +2748,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error( source.declarations && getNameOfDeclaration(source.declarations[0]), Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, - symbolToString(target)); + symbolToString(target), + ); } } else { // error const isEitherEnum = !!(target.flags & SymbolFlags.Enum || source.flags & SymbolFlags.Enum); - const isEitherBlockScoped = !!(target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable); - const message = isEitherEnum ? Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations + const isEitherBlockScoped = + !!(target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable); + const message = isEitherEnum + ? Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations : isEitherBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; const sourceSymbolFile = source.declarations && getSourceFileOfNode(source.declarations[0]); @@ -2548,13 +2768,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbolName = symbolToString(source); // Collect top-level duplicate identifier errors into one mapping, so we can then merge their diagnostics if there are a bunch - if (sourceSymbolFile && targetSymbolFile && amalgamatedDuplicates && !isEitherEnum && sourceSymbolFile !== targetSymbolFile) { - const firstFile = comparePaths(sourceSymbolFile.path, targetSymbolFile.path) === Comparison.LessThan ? sourceSymbolFile : targetSymbolFile; + if ( + sourceSymbolFile && targetSymbolFile && amalgamatedDuplicates && !isEitherEnum + && sourceSymbolFile !== targetSymbolFile + ) { + const firstFile = comparePaths(sourceSymbolFile.path, targetSymbolFile.path) === Comparison.LessThan + ? sourceSymbolFile : targetSymbolFile; const secondFile = firstFile === sourceSymbolFile ? targetSymbolFile : sourceSymbolFile; - const filesDuplicates = getOrUpdate(amalgamatedDuplicates, `${firstFile.path}|${secondFile.path}`, (): DuplicateInfoForFiles => - ({ firstFile, secondFile, conflictingSymbols: new Map() })); - const conflictingSymbolInfo = getOrUpdate(filesDuplicates.conflictingSymbols, symbolName, (): DuplicateInfoForSymbol => - ({ isBlockScoped: isEitherBlockScoped, firstFileLocations: [], secondFileLocations: [] })); + const filesDuplicates = getOrUpdate( + amalgamatedDuplicates, + `${firstFile.path}|${secondFile.path}`, + (): DuplicateInfoForFiles => ({ firstFile, secondFile, conflictingSymbols: new Map() }), + ); + const conflictingSymbolInfo = getOrUpdate( + filesDuplicates.conflictingSymbols, + symbolName, + (): DuplicateInfoForSymbol => ({ + isBlockScoped: isEitherBlockScoped, + firstFileLocations: [], + secondFileLocations: [], + }), + ); if (!isSourcePlainJs) addDuplicateLocations(conflictingSymbolInfo.firstFileLocations, source); if (!isTargetPlainJs) addDuplicateLocations(conflictingSymbolInfo.secondFileLocations, target); } @@ -2574,27 +2808,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function addDuplicateDeclarationErrorsForSymbols(target: Symbol, message: DiagnosticMessage, symbolName: string, source: Symbol) { + function addDuplicateDeclarationErrorsForSymbols( + target: Symbol, + message: DiagnosticMessage, + symbolName: string, + source: Symbol, + ) { forEach(target.declarations, node => { addDuplicateDeclarationError(node, message, symbolName, source.declarations); }); } - function addDuplicateDeclarationError(node: Declaration, message: DiagnosticMessage, symbolName: string, relatedNodes: readonly Declaration[] | undefined) { - const errorNode = (getExpandoInitializer(node, /*isPrototypeAssignment*/ false) ? getNameOfExpando(node) : getNameOfDeclaration(node)) || node; + function addDuplicateDeclarationError( + node: Declaration, + message: DiagnosticMessage, + symbolName: string, + relatedNodes: readonly Declaration[] | undefined, + ) { + const errorNode = (getExpandoInitializer(node, /*isPrototypeAssignment*/ false) ? getNameOfExpando(node) + : getNameOfDeclaration(node)) || node; const err = lookupOrIssueError(errorNode, message, symbolName); for (const relatedNode of relatedNodes || emptyArray) { - const adjustedNode = (getExpandoInitializer(relatedNode, /*isPrototypeAssignment*/ false) ? getNameOfExpando(relatedNode) : getNameOfDeclaration(relatedNode)) || relatedNode; + const adjustedNode = + (getExpandoInitializer(relatedNode, /*isPrototypeAssignment*/ false) ? getNameOfExpando(relatedNode) + : getNameOfDeclaration(relatedNode)) || relatedNode; if (adjustedNode === errorNode) continue; err.relatedInformation = err.relatedInformation || []; - const leadingMessage = createDiagnosticForNode(adjustedNode, Diagnostics._0_was_also_declared_here, symbolName); + const leadingMessage = createDiagnosticForNode( + adjustedNode, + Diagnostics._0_was_also_declared_here, + symbolName, + ); const followOnMessage = createDiagnosticForNode(adjustedNode, Diagnostics.and_here); - if (length(err.relatedInformation) >= 5 || some(err.relatedInformation, r => compareDiagnostics(r, followOnMessage) === Comparison.EqualTo || compareDiagnostics(r, leadingMessage) === Comparison.EqualTo)) continue; + if ( + length(err.relatedInformation) >= 5 + || some(err.relatedInformation, r => + compareDiagnostics(r, followOnMessage) === Comparison.EqualTo + || compareDiagnostics(r, leadingMessage) === Comparison.EqualTo) + ) continue; addRelatedInfo(err, !length(err.relatedInformation) ? leadingMessage : followOnMessage); } } - function combineSymbolTables(first: SymbolTable | undefined, second: SymbolTable | undefined): SymbolTable | undefined { + function combineSymbolTables( + first: SymbolTable | undefined, + second: SymbolTable | undefined, + ): SymbolTable | undefined { if (!first?.size) return second; if (!second?.size) return first; const combined = createSymbolTable(); @@ -2606,7 +2865,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function mergeSymbolTable(target: SymbolTable, source: SymbolTable, unidirectional = false) { source.forEach((sourceSymbol, id) => { const targetSymbol = target.get(id); - target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : getMergedSymbol(sourceSymbol)); + target.set( + id, + targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : getMergedSymbol(sourceSymbol), + ); }); } @@ -2629,7 +2891,12 @@ 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, + /*isForAugmentation*/ true, + ); if (!mainModule) { return; } @@ -2650,9 +2917,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { patternAmbientModuleAugmentations.set((moduleName as StringLiteral).text, merged); } else { - if (mainModule.exports?.get(InternalSymbolName.ExportStar) && moduleAugmentation.symbol.exports?.size) { + if ( + mainModule.exports?.get(InternalSymbolName.ExportStar) + && moduleAugmentation.symbol.exports?.size + ) { // We may need to merge the module augmentation's exports into the target symbols of the resolved exports - const resolvedExports = getResolvedMembersOrExportsOfSymbol(mainModule, MembersOrExportsResolutionKind.resolvedExports); + const resolvedExports = getResolvedMembersOrExportsOfSymbol( + mainModule, + MembersOrExportsResolutionKind.resolvedExports, + ); for (const [key, value] of arrayFrom(moduleAugmentation.symbol.exports.entries())) { if (resolvedExports.has(key) && !mainModule.exports.has(key)) { mergeSymbol(resolvedExports.get(key)!, value); @@ -2664,7 +2937,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { // moduleName will be a StringLiteral since this is not `declare global`. - error(moduleName, Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, (moduleName as StringLiteral).text); + error( + moduleName, + Diagnostics.Cannot_augment_module_0_because_it_resolves_to_a_non_module_entity, + (moduleName as StringLiteral).text, + ); } } } @@ -2705,7 +2982,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (meaning) { const symbol = getMergedSymbol(symbols.get(name)); if (symbol) { - Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); + Debug.assert( + (getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, + "Should never get an instantiated symbol here.", + ); if (symbol.flags & meaning) { return symbol; } @@ -2727,7 +3007,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param parameterName a name of the parameter to get the symbols for. * @return a tuple of two symbols */ - function getSymbolsOfParameterPropertyDeclaration(parameter: ParameterPropertyDeclaration, parameterName: __String): [Symbol, Symbol] { + function getSymbolsOfParameterPropertyDeclaration( + parameter: ParameterPropertyDeclaration, + parameterName: __String, + ): [Symbol, Symbol] { const constructorDeclaration = parameter.parent; const classDeclaration = parameter.parent.parent; @@ -2738,7 +3021,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return [parameterSymbol, propertySymbol]; } - return Debug.fail("There should exist two symbols, one as property declaration and one as parameter declaration"); + return Debug.fail( + "There should exist two symbols, one as property declaration and one as parameter declaration", + ); } function isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean { @@ -2746,10 +3031,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const useFile = getSourceFileOfNode(usage); const declContainer = getEnclosingBlockScopeContainer(declaration); if (declarationFile !== useFile) { - if ((moduleKind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) || - (!outFile(compilerOptions)) || - isInTypeQuery(usage) || - declaration.flags & NodeFlags.Ambient) { + if ( + (moduleKind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) + || (!outFile(compilerOptions)) + || isInTypeQuery(usage) + || declaration.flags & NodeFlags.Ambient + ) { // nodes are in different files and order cannot be determined return true; } @@ -2762,17 +3049,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile); } - if (declaration.pos <= usage.pos && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer && !declaration.exclamationToken)) { + if ( + declaration.pos <= usage.pos + && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer + && !declaration.exclamationToken) + ) { // declaration is before usage if (declaration.kind === SyntaxKind.BindingElement) { // still might be illegal if declaration and usage are both binding elements (eg var [a = b, b = b] = [1, 2]) const errorBindingElement = getAncestor(usage, SyntaxKind.BindingElement) as BindingElement; if (errorBindingElement) { - return findAncestor(errorBindingElement, isBindingElement) !== findAncestor(declaration, isBindingElement) || - declaration.pos < errorBindingElement.pos; + return findAncestor(errorBindingElement, isBindingElement) + !== findAncestor(declaration, isBindingElement) + || declaration.pos < errorBindingElement.pos; } // or it might be illegal if usage happens before parent variable is declared (eg var [a] = a) - return isBlockScopedNameDeclaredBeforeUse(getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration, usage); + return isBlockScopedNameDeclaredBeforeUse( + getAncestor(declaration, SyntaxKind.VariableDeclaration) as Declaration, + usage, + ); } else if (declaration.kind === SyntaxKind.VariableDeclaration) { // still might be illegal if usage is in the initializer of the variable declaration (eg var a = a) @@ -2784,18 +3079,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (isPropertyDeclaration(declaration)) { // still might be illegal if a self-referencing property initializer (eg private x = this.x) - return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ false); + return !isPropertyImmediatelyReferencedWithinDeclaration( + declaration, + usage, + /*stopAtAnyPropertyDeclaration*/ false, + ); } else if (isParameterPropertyDeclaration(declaration, declaration.parent)) { // foo = this.bar is illegal in emitStandardClassFields when bar is a parameter property return !(emitStandardClassFields - && getContainingClass(declaration) === getContainingClass(usage) - && isUsedInFunctionOrInstanceProperty(usage, declaration)); + && getContainingClass(declaration) === getContainingClass(usage) + && isUsedInFunctionOrInstanceProperty(usage, declaration)); } return true; } - // declaration is after usage, but it can still be legal if usage is deferred: // 1. inside an export specifier // 2. inside a function @@ -2806,7 +3104,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // or if usage is in a type context: // 1. inside a type query (typeof in type position) // 2. inside a jsdoc comment - if (usage.parent.kind === SyntaxKind.ExportSpecifier || (usage.parent.kind === SyntaxKind.ExportAssignment && (usage.parent as ExportAssignment).isExportEquals)) { + if ( + usage.parent.kind === SyntaxKind.ExportSpecifier + || (usage.parent.kind === SyntaxKind.ExportAssignment && (usage.parent as ExportAssignment).isExportEquals) + ) { // export specifiers do not use the variable, they only make it available for use return true; } @@ -2819,10 +3120,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } if (isUsedInFunctionOrInstanceProperty(usage, declaration)) { - if (emitStandardClassFields + if ( + emitStandardClassFields && getContainingClass(declaration) - && (isPropertyDeclaration(declaration) || isParameterPropertyDeclaration(declaration, declaration.parent))) { - return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage, /*stopAtAnyPropertyDeclaration*/ true); + && (isPropertyDeclaration(declaration) + || isParameterPropertyDeclaration(declaration, declaration.parent)) + ) { + return !isPropertyImmediatelyReferencedWithinDeclaration( + declaration, + usage, + /*stopAtAnyPropertyDeclaration*/ true, + ); } else { return true; @@ -2830,7 +3138,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return false; - function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean { + function isImmediatelyUsedInInitializerOfBlockScopedVariable( + declaration: VariableDeclaration, + usage: Node, + ): boolean { switch (declaration.parent.parent.kind) { case SyntaxKind.VariableStatement: case SyntaxKind.ForStatement: @@ -2845,7 +3156,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // ForIn/ForOf case - use site should not be used in expression part const grandparent = declaration.parent.parent; - return isForInOrOfStatement(grandparent) && isSameScopeDescendentOf(usage, grandparent.expression, declContainer); + return isForInOrOfStatement(grandparent) + && isSameScopeDescendentOf(usage, grandparent.expression, declContainer); } function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node): boolean { @@ -2868,20 +3180,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (declaration.kind === SyntaxKind.MethodDeclaration) { return true; } - if (isPropertyDeclaration(declaration) && getContainingClass(usage) === getContainingClass(declaration)) { + if ( + isPropertyDeclaration(declaration) + && getContainingClass(usage) === getContainingClass(declaration) + ) { const propName = declaration.name; if (isIdentifier(propName) || isPrivateIdentifier(propName)) { const type = getTypeOfSymbol(getSymbolOfDeclaration(declaration)); - const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration); - if (isPropertyInitializedInStaticBlocks(propName, type, staticBlocks, declaration.parent.pos, current.pos)) { + const staticBlocks = filter( + declaration.parent.members, + isClassStaticBlockDeclaration, + ); + if ( + isPropertyInitializedInStaticBlocks( + propName, + type, + staticBlocks, + declaration.parent.pos, + current.pos, + ) + ) { return true; } } } } else { - const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !isStatic(declaration); - if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) { + const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration + && !isStatic(declaration); + if ( + !isDeclarationInstanceProperty + || getContainingClass(usage) !== getContainingClass(declaration) + ) { return true; } } @@ -2892,7 +3222,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** stopAtAnyPropertyDeclaration is used for detecting ES-standard class field use-before-def errors */ - function isPropertyImmediatelyReferencedWithinDeclaration(declaration: PropertyDeclaration | ParameterPropertyDeclaration, usage: Node, stopAtAnyPropertyDeclaration: boolean) { + function isPropertyImmediatelyReferencedWithinDeclaration( + declaration: PropertyDeclaration | ParameterPropertyDeclaration, + usage: Node, + stopAtAnyPropertyDeclaration: boolean, + ) { // always legal if usage is after declaration if (usage.end > declaration.end) { return false; @@ -2910,10 +3244,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; case SyntaxKind.PropertyDeclaration: // even when stopping at any property declaration, they need to come from the same class - return stopAtAnyPropertyDeclaration && - (isPropertyDeclaration(declaration) && node.parent === declaration.parent - || isParameterPropertyDeclaration(declaration, declaration.parent) && node.parent === declaration.parent.parent) - ? "quit": true; + return stopAtAnyPropertyDeclaration + && (isPropertyDeclaration(declaration) && node.parent === declaration.parent + || isParameterPropertyDeclaration(declaration, declaration.parent) + && node.parent === declaration.parent.parent) + ? "quit" : true; case SyntaxKind.Block: switch (node.parent.kind) { case SyntaxKind.GetAccessor: @@ -2935,11 +3270,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function useOuterVariableScopeInParameter(result: Symbol, location: Node, lastLocation: Node) { const target = getEmitScriptTarget(compilerOptions); const functionLocation = location as FunctionLikeDeclaration; - if (isParameter(lastLocation) + if ( + isParameter(lastLocation) && functionLocation.body && result.valueDeclaration && result.valueDeclaration.pos >= functionLocation.body.pos - && result.valueDeclaration.end <= functionLocation.body.end) { + && result.valueDeclaration.end <= functionLocation.body.end + ) { // check for several cases where we introduce temporaries that require moving the name/initializer of the parameter to the body // - static field in a class expression // - optional chaining pre-es2020 @@ -2948,7 +3285,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (target >= ScriptTarget.ES2015) { const links = getNodeLinks(functionLocation); if (links.declarationRequiresScopeChange === undefined) { - links.declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) || false; + links.declarationRequiresScopeChange = forEach(functionLocation.parameters, requiresScopeChange) + || false; } return !links.declarationRequiresScopeChange; } @@ -2972,7 +3310,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.PropertyAssignment: - return requiresScopeChangeWorker((node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name); + return requiresScopeChangeWorker( + (node as MethodDeclaration | AccessorDeclaration | PropertyAssignment).name, + ); case SyntaxKind.PropertyDeclaration: // static properties in classes introduce temporary variables if (hasStaticModifier(node)) { @@ -3014,8 +3354,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { nameArg: __String | Identifier | undefined, isUse: boolean, excludeGlobals = false, - getSpellingSuggestions = true): Symbol | undefined { - return resolveNameHelper(location, name, meaning, nameNotFoundMessage, nameArg, isUse, excludeGlobals, getSpellingSuggestions, getSymbol); + getSpellingSuggestions = true, + ): Symbol | undefined { + return resolveNameHelper( + location, + name, + meaning, + nameNotFoundMessage, + nameArg, + isUse, + excludeGlobals, + getSpellingSuggestions, + getSymbol, + ); } function resolveNameHelper( @@ -3027,19 +3378,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isUse: boolean, excludeGlobals: boolean, getSpellingSuggestions: boolean, - lookup: typeof getSymbol): Symbol | undefined { + lookup: typeof getSymbol, + ): Symbol | undefined { const originalLocation = location; // needed for did-you-mean error reporting, which gathers candidates starting from the original location let result: Symbol | undefined; let lastLocation: Node | undefined; let lastSelfReferenceLocation: Declaration | undefined; let propertyWithInvalidInitializer: PropertyDeclaration | undefined; - let associatedDeclarationForContainingInitializerOrBindingName: ParameterDeclaration | BindingElement | undefined; + let associatedDeclarationForContainingInitializerOrBindingName: + | ParameterDeclaration + | BindingElement + | undefined; let withinDeferredContext = false; const errorLocation = location; let grandparent: Node; let isInExternalModule = false; - loop: while (location) { + loop: + while (location) { if (name === "const" && isConstAssertion(location)) { // `const` in an `as const` has no symbol, but issues no error because there is no *actual* lookup of the type // (it refers to the constant type of the expression instead) @@ -3055,7 +3411,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (canHaveLocals(location) && location.locals && !isGlobalSourceFile(location)) { if (result = lookup(location.locals, name, meaning)) { let useResult = true; - if (isFunctionLike(location) && lastLocation && lastLocation !== (location as FunctionLikeDeclaration).body) { + if ( + isFunctionLike(location) && lastLocation + && lastLocation !== (location as FunctionLikeDeclaration).body + ) { // symbol lookup restrictions for function-like declarations // - Type parameters of a function are in scope in the entire function declaration, including the parameter // list and return type. However, local types are only in scope in the function body. @@ -3065,11 +3424,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (meaning & result.flags & SymbolFlags.Type && lastLocation.kind !== SyntaxKind.JSDoc) { useResult = result.flags & SymbolFlags.TypeParameter // type parameters are visible in parameter list, return type and type parameter list - ? lastLocation === (location as FunctionLikeDeclaration).type || - lastLocation.kind === SyntaxKind.Parameter || - lastLocation.kind === SyntaxKind.JSDocParameterTag || - lastLocation.kind === SyntaxKind.JSDocReturnTag || - lastLocation.kind === SyntaxKind.TypeParameter + ? lastLocation === (location as FunctionLikeDeclaration).type + || lastLocation.kind === SyntaxKind.Parameter + || lastLocation.kind === SyntaxKind.JSDocParameterTag + || lastLocation.kind === SyntaxKind.JSDocReturnTag + || lastLocation.kind === SyntaxKind.TypeParameter // local types not visible outside the function body : false; } @@ -3083,11 +3442,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // technically for parameter list case here we might mix parameters and variables declared in function, // however it is detected separately when checking initializers of parameters // to make sure that they reference no variables declared after them. - useResult = - lastLocation.kind === SyntaxKind.Parameter || - ( - lastLocation === (location as FunctionLikeDeclaration).type && - !!findAncestor(result.valueDeclaration, isParameter) + useResult = lastLocation.kind === SyntaxKind.Parameter + || ( + lastLocation === (location as FunctionLikeDeclaration).type + && !!findAncestor(result.valueDeclaration, isParameter) ); } } @@ -3113,9 +3471,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isInExternalModule = true; // falls through case SyntaxKind.ModuleDeclaration: - const moduleExports = getSymbolOfDeclaration(location as SourceFile | ModuleDeclaration)?.exports || emptySymbols; - if (location.kind === SyntaxKind.SourceFile || (isModuleDeclaration(location) && location.flags & NodeFlags.Ambient && !isGlobalScopeAugmentation(location))) { - + const moduleExports = getSymbolOfDeclaration(location as SourceFile | ModuleDeclaration)?.exports + || emptySymbols; + if ( + location.kind === SyntaxKind.SourceFile + || (isModuleDeclaration(location) && location.flags & NodeFlags.Ambient + && !isGlobalScopeAugmentation(location)) + ) { // It's an external module. First see if the module has an export default and if the local // name of that export default matches. if (result = moduleExports.get(InternalSymbolName.Default)) { @@ -3138,16 +3500,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // an alias. If we used &, we'd be throwing out symbols that have non alias aspects, // which is not the desired behavior. const moduleExport = moduleExports.get(name); - if (moduleExport && - moduleExport.flags === SymbolFlags.Alias && - (getDeclarationOfKind(moduleExport, SyntaxKind.ExportSpecifier) || getDeclarationOfKind(moduleExport, SyntaxKind.NamespaceExport))) { + if ( + moduleExport + && moduleExport.flags === SymbolFlags.Alias + && (getDeclarationOfKind(moduleExport, SyntaxKind.ExportSpecifier) + || getDeclarationOfKind(moduleExport, SyntaxKind.NamespaceExport)) + ) { break; } } // ES6 exports are also visible locally (except for 'default'), but commonjs exports are not (except typedefs) - if (name !== InternalSymbolName.Default && (result = lookup(moduleExports, name, meaning & SymbolFlags.ModuleMember))) { - if (isSourceFile(location) && location.commonJsModuleIndicator && !result.declarations?.some(isJSDocTypeAlias)) { + if ( + name !== InternalSymbolName.Default + && (result = lookup(moduleExports, name, meaning & SymbolFlags.ModuleMember)) + ) { + if ( + isSourceFile(location) && location.commonJsModuleIndicator + && !result.declarations?.some(isJSDocTypeAlias) + ) { result = undefined; } else { @@ -3156,14 +3527,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } break; case SyntaxKind.EnumDeclaration: - if (result = lookup(getSymbolOfDeclaration(location as EnumDeclaration)?.exports || emptySymbols, name, meaning & SymbolFlags.EnumMember)) { - if (nameNotFoundMessage && getIsolatedModules(compilerOptions) && !(location.flags & NodeFlags.Ambient) && getSourceFileOfNode(location) !== getSourceFileOfNode(result.valueDeclaration)) { + if ( + result = lookup( + getSymbolOfDeclaration(location as EnumDeclaration)?.exports || emptySymbols, + name, + meaning & SymbolFlags.EnumMember, + ) + ) { + if ( + nameNotFoundMessage && getIsolatedModules(compilerOptions) + && !(location.flags & NodeFlags.Ambient) + && getSourceFileOfNode(location) !== getSourceFileOfNode(result.valueDeclaration) + ) { error( errorLocation, - Diagnostics.Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead, + Diagnostics + .Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead, unescapeLeadingUnderscores(name), isolatedModulesLikeFlagName, - `${unescapeLeadingUnderscores(getSymbolOfNode(location)!.escapedName)}.${unescapeLeadingUnderscores(name)}`); + `${unescapeLeadingUnderscores(getSymbolOfNode(location)!.escapedName)}.${ + unescapeLeadingUnderscores(name) + }`, + ); } break loop; } @@ -3192,7 +3577,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The below is used to lookup type parameters within a class or interface, as they are added to the class/interface locals // These can never be latebound, so the symbol's raw members are sufficient. `getMembersOfNode` cannot be used, as it would // trigger resolving late-bound names, which we may already be in the process of doing while we're here! - if (result = lookup(getSymbolOfDeclaration(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols, name, meaning & SymbolFlags.Type)) { + if ( + result = lookup( + getSymbolOfDeclaration(location as ClassLikeDeclaration | InterfaceDeclaration).members + || emptySymbols, + name, + meaning & SymbolFlags.Type, + ) + ) { if (!isTypeParameterSymbolDeclaredInContainer(result, location)) { // ignore type parameters not declared in this container result = undefined; @@ -3219,11 +3611,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; case SyntaxKind.ExpressionWithTypeArguments: // The type parameters of a class are not in scope in the base class expression. - if (lastLocation === (location as ExpressionWithTypeArguments).expression && (location.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword) { + if ( + lastLocation === (location as ExpressionWithTypeArguments).expression + && (location.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword + ) { const container = location.parent.parent; - if (isClassLike(container) && (result = lookup(getSymbolOfDeclaration(container).members!, name, meaning & SymbolFlags.Type))) { + if ( + isClassLike(container) + && (result = lookup( + getSymbolOfDeclaration(container).members!, + name, + meaning & SymbolFlags.Type, + )) + ) { if (nameNotFoundMessage) { - error(errorLocation, Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters); + error( + errorLocation, + Diagnostics.Base_class_expressions_cannot_reference_class_type_parameters, + ); } return undefined; } @@ -3241,9 +3646,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { grandparent = location.parent.parent; if (isClassLike(grandparent) || grandparent.kind === SyntaxKind.InterfaceDeclaration) { // A reference to this grandparent's type parameters would be an error - if (result = lookup(getSymbolOfDeclaration(grandparent as ClassLikeDeclaration | InterfaceDeclaration).members!, name, meaning & SymbolFlags.Type)) { + if ( + result = lookup( + getSymbolOfDeclaration(grandparent as ClassLikeDeclaration | InterfaceDeclaration) + .members!, + name, + meaning & SymbolFlags.Type, + ) + ) { if (nameNotFoundMessage) { - error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type); + error( + errorLocation, + Diagnostics + .A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type, + ); } return undefined; } @@ -3305,7 +3721,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // declare function y(x: T): any; // @param(1 as T) // <-- T should resolve to the type alias outside of class C // class C {} - if (location.parent && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration)) { + if ( + location.parent + && (isClassElement(location.parent) || location.parent.kind === SyntaxKind.ClassDeclaration) + ) { location = location.parent; } break; @@ -3319,19 +3738,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } break; case SyntaxKind.Parameter: - if (lastLocation && ( - lastLocation === (location as ParameterDeclaration).initializer || - lastLocation === (location as ParameterDeclaration).name && isBindingPattern(lastLocation))) { + if ( + lastLocation && ( + lastLocation === (location as ParameterDeclaration).initializer + || lastLocation === (location as ParameterDeclaration).name + && isBindingPattern(lastLocation) + ) + ) { if (!associatedDeclarationForContainingInitializerOrBindingName) { - associatedDeclarationForContainingInitializerOrBindingName = location as ParameterDeclaration; + associatedDeclarationForContainingInitializerOrBindingName = + location as ParameterDeclaration; } } break; case SyntaxKind.BindingElement: - if (lastLocation && ( - lastLocation === (location as BindingElement).initializer || - lastLocation === (location as BindingElement).name && isBindingPattern(lastLocation))) { - if (isParameterDeclaration(location as BindingElement) && !associatedDeclarationForContainingInitializerOrBindingName) { + if ( + lastLocation && ( + lastLocation === (location as BindingElement).initializer + || lastLocation === (location as BindingElement).name && isBindingPattern(lastLocation) + ) + ) { + if ( + isParameterDeclaration(location as BindingElement) + && !associatedDeclarationForContainingInitializerOrBindingName + ) { associatedDeclarationForContainingInitializerOrBindingName = location as BindingElement; } } @@ -3347,9 +3777,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; case SyntaxKind.ExportSpecifier: // External module export bindings shouldn't be resolved to local symbols. - if (lastLocation && - lastLocation === (location as ExportSpecifier).propertyName && - (location as ExportSpecifier).parent.parent.moduleSpecifier) { + if ( + lastLocation + && lastLocation === (location as ExportSpecifier).propertyName + && (location as ExportSpecifier).parent.parent.moduleSpecifier + ) { location = location.parent.parent.parent; } break; @@ -3358,9 +3790,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { lastSelfReferenceLocation = location; } lastLocation = location; - location = isJSDocTemplateTag(location) ? getEffectiveContainerForJSDocTemplateTag(location) || location.parent : - isJSDocParameterTag(location) || isJSDocReturnTag(location) ? getHostSignatureFromJSDoc(location) || location.parent : - location.parent; + location = isJSDocTemplateTag(location) + ? getEffectiveContainerForJSDocTemplateTag(location) || location.parent + : isJSDocParameterTag(location) || isJSDocReturnTag(location) + ? getHostSignatureFromJSDoc(location) || location.parent + : location.parent; } // We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`. @@ -3398,11 +3832,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We have a match, but the reference occurred within a property initializer and the identifier also binds // to a local variable in the constructor where the code will be emitted. Note that this is actually allowed // with emitStandardClassFields because the scope semantics are different. - error(errorLocation, - errorLocation && propertyWithInvalidInitializer.type && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos) - ? Diagnostics.Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor - : Diagnostics.Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, - declarationNameToString(propertyWithInvalidInitializer.name), diagnosticName(nameArg!)); + error( + errorLocation, + errorLocation && propertyWithInvalidInitializer.type + && textRangeContainsPositionInclusive(propertyWithInvalidInitializer.type, errorLocation.pos) + ? Diagnostics + .Type_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor + : Diagnostics + .Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor, + declarationNameToString(propertyWithInvalidInitializer.name), + diagnosticName(nameArg!), + ); return true; } return false; @@ -3411,16 +3851,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!result) { if (nameNotFoundMessage) { addLazyDiagnostic(() => { - if (!errorLocation || - errorLocation.parent.kind !== SyntaxKind.JSDocLink && - !checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg!) && // TODO: GH#18217 - !checkAndReportErrorForInvalidInitializer() && - !checkAndReportErrorForExtendingInterface(errorLocation) && - !checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) && - !checkAndReportErrorForExportingPrimitiveType(errorLocation, name) && - !checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation, name, meaning) && - !checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning) && - !checkAndReportErrorForUsingValueAsType(errorLocation, name, meaning)) { + if ( + !errorLocation + || errorLocation.parent.kind !== SyntaxKind.JSDocLink + && !checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg!) // TODO: GH#18217 + && !checkAndReportErrorForInvalidInitializer() + && !checkAndReportErrorForExtendingInterface(errorLocation) + && !checkAndReportErrorForUsingTypeAsNamespace(errorLocation, name, meaning) + && !checkAndReportErrorForExportingPrimitiveType(errorLocation, name) + && !checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation, name, meaning) + && !checkAndReportErrorForUsingTypeAsValue(errorLocation, name, meaning) + && !checkAndReportErrorForUsingValueAsType(errorLocation, name, meaning) + ) { let suggestion: Symbol | undefined; let suggestedLib: string | undefined; // Report missing lib first @@ -3433,22 +3875,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // then spelling suggestions if (!suggestedLib && getSpellingSuggestions && suggestionCount < maximumSuggestionCount) { suggestion = getSuggestedSymbolForNonexistentSymbol(originalLocation, name, meaning); - const isGlobalScopeAugmentationDeclaration = suggestion?.valueDeclaration && isAmbientModule(suggestion.valueDeclaration) && isGlobalScopeAugmentation(suggestion.valueDeclaration); + const isGlobalScopeAugmentationDeclaration = suggestion?.valueDeclaration + && isAmbientModule(suggestion.valueDeclaration) + && isGlobalScopeAugmentation(suggestion.valueDeclaration); if (isGlobalScopeAugmentationDeclaration) { suggestion = undefined; } if (suggestion) { const suggestionName = symbolToString(suggestion); - const isUncheckedJS = isUncheckedJSSuggestion(originalLocation, suggestion, /*excludeClasses*/ false); - const message = meaning === SymbolFlags.Namespace || nameArg && typeof nameArg !== "string" && nodeIsSynthesized(nameArg) ? Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 + const isUncheckedJS = isUncheckedJSSuggestion( + originalLocation, + suggestion, + /*excludeClasses*/ false, + ); + const message = meaning === SymbolFlags.Namespace + || nameArg && typeof nameArg !== "string" && nodeIsSynthesized(nameArg) + ? Diagnostics.Cannot_find_namespace_0_Did_you_mean_1 : isUncheckedJS ? Diagnostics.Could_not_find_name_0_Did_you_mean_1 : Diagnostics.Cannot_find_name_0_Did_you_mean_1; - const diagnostic = createError(errorLocation, message, diagnosticName(nameArg!), suggestionName); + const diagnostic = createError( + errorLocation, + message, + diagnosticName(nameArg!), + suggestionName, + ); addErrorOrSuggestion(!isUncheckedJS, diagnostic); if (suggestion.valueDeclaration) { addRelatedInfo( diagnostic, - createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName) + createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestionName, + ), ); } } @@ -3481,47 +3940,96 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // block-scoped variable and namespace module. However, only when we // try to resolve name in /*1*/ which is used in variable position, // we want to check for block-scoped - if (errorLocation && - (meaning & SymbolFlags.BlockScopedVariable || - ((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) && (meaning & SymbolFlags.Value) === SymbolFlags.Value))) { + if ( + errorLocation + && (meaning & SymbolFlags.BlockScopedVariable + || ((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) + && (meaning & SymbolFlags.Value) === SymbolFlags.Value)) + ) { const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result!); - if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable || exportOrLocalSymbol.flags & SymbolFlags.Class || exportOrLocalSymbol.flags & SymbolFlags.Enum) { + if ( + exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable + || exportOrLocalSymbol.flags & SymbolFlags.Class || exportOrLocalSymbol.flags & SymbolFlags.Enum + ) { checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation); } } // If we're in an external module, we can't reference value symbols created from UMD export declarations - if (result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value && !(originalLocation!.flags & NodeFlags.JSDoc)) { + if ( + result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value + && !(originalLocation!.flags & NodeFlags.JSDoc) + ) { const merged = getMergedSymbol(result); - if (length(merged.declarations) && every(merged.declarations, d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports)) { - errorOrSuggestion(!compilerOptions.allowUmdGlobalAccess, errorLocation!, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, unescapeLeadingUnderscores(name)); + if ( + length(merged.declarations) + && every( + merged.declarations, + d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports, + ) + ) { + errorOrSuggestion( + !compilerOptions.allowUmdGlobalAccess, + errorLocation!, + Diagnostics + ._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, + unescapeLeadingUnderscores(name), + ); } } // If we're in a parameter initializer or binding name, we can't reference the values of the parameter whose initializer we're within or parameters to the right - if (result && associatedDeclarationForContainingInitializerOrBindingName && !withinDeferredContext && (meaning & SymbolFlags.Value) === SymbolFlags.Value) { + if ( + result && associatedDeclarationForContainingInitializerOrBindingName && !withinDeferredContext + && (meaning & SymbolFlags.Value) === SymbolFlags.Value + ) { const candidate = getMergedSymbol(getLateBoundSymbol(result)); - const root = (getRootDeclaration(associatedDeclarationForContainingInitializerOrBindingName) as ParameterDeclaration); + const root = getRootDeclaration( + associatedDeclarationForContainingInitializerOrBindingName, + ) as ParameterDeclaration; // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself - if (candidate === getSymbolOfDeclaration(associatedDeclarationForContainingInitializerOrBindingName)) { - error(errorLocation, Diagnostics.Parameter_0_cannot_reference_itself, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name)); + if ( + candidate === getSymbolOfDeclaration(associatedDeclarationForContainingInitializerOrBindingName) + ) { + error( + errorLocation, + Diagnostics.Parameter_0_cannot_reference_itself, + declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name), + ); } // And it cannot refer to any declarations which come after it - else if (candidate.valueDeclaration && candidate.valueDeclaration.pos > associatedDeclarationForContainingInitializerOrBindingName.pos && root.parent.locals && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate) { - error(errorLocation, Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name), declarationNameToString(errorLocation as Identifier)); + else if ( + candidate.valueDeclaration + && candidate.valueDeclaration.pos + > associatedDeclarationForContainingInitializerOrBindingName.pos + && root.parent.locals + && lookup(root.parent.locals, candidate.escapedName, meaning) === candidate + ) { + error( + errorLocation, + Diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, + declarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.name), + declarationNameToString(errorLocation as Identifier), + ); } } - if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation)) { + if ( + result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias + && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation) + ) { const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(result, SymbolFlags.Value); if (typeOnlyDeclaration) { - const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport + const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier + || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration + || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport ? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type : Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type; const unescapedName = unescapeLeadingUnderscores(name); addTypeOnlyDeclarationRelatedInfo( error(errorLocation, message, unescapedName), typeOnlyDeclaration, - unescapedName); + unescapedName, + ); } } }); @@ -3529,31 +4037,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function addTypeOnlyDeclarationRelatedInfo(diagnostic: Diagnostic, typeOnlyDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, unescapedName: string) { + function addTypeOnlyDeclarationRelatedInfo( + diagnostic: Diagnostic, + typeOnlyDeclaration: TypeOnlyCompatibleAliasDeclaration | undefined, + unescapedName: string, + ) { if (!typeOnlyDeclaration) return diagnostic; return addRelatedInfo( diagnostic, createDiagnosticForNode( typeOnlyDeclaration, - typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport + typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier + || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration + || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here, - unescapedName)); + unescapedName, + ), + ); } function getIsDeferredContext(location: Node, lastLocation: Node | undefined): boolean { if (location.kind !== SyntaxKind.ArrowFunction && location.kind !== SyntaxKind.FunctionExpression) { // initializers in instance property declaration of class like entities are executed in constructor and thus deferred return isTypeQueryNode(location) || (( - isFunctionLikeDeclaration(location) || - (location.kind === SyntaxKind.PropertyDeclaration && !isStatic(location)) + isFunctionLikeDeclaration(location) + || (location.kind === SyntaxKind.PropertyDeclaration && !isStatic(location)) ) && (!lastLocation || lastLocation !== (location as SignatureDeclaration | PropertyDeclaration).name)); // A name is evaluated within the enclosing scope - so it shouldn't count as deferred } if (lastLocation && lastLocation === (location as FunctionExpression | ArrowFunction).name) { return false; } // generator functions and async functions are not inlined in control flow when immediately invoked - if ((location as FunctionExpression | ArrowFunction).asteriskToken || hasSyntacticModifier(location, ModifierFlags.Async)) { + if ( + (location as FunctionExpression | ArrowFunction).asteriskToken + || hasSyntacticModifier(location, ModifierFlags.Async) + ) { return true; } return !getImmediatelyInvokedFunctionExpression(location); @@ -3565,8 +4084,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { | InterfaceDeclaration | EnumDeclaration | TypeAliasDeclaration - | ModuleDeclaration - ; + | ModuleDeclaration; function isSelfReferenceLocation(node: Node): node is SelfReferenceLocation { switch (node.kind) { @@ -3583,7 +4101,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function diagnosticName(nameArg: __String | Identifier | PrivateIdentifier) { - return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier); + return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) + : declarationNameToString(nameArg as Identifier); } function isTypeParameterSymbolDeclaredInContainer(symbol: Symbol, container: Node) { @@ -3592,7 +4111,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (decl.kind === SyntaxKind.TypeParameter) { const parent = isJSDocTemplateTag(decl.parent) ? getJSDocHost(decl.parent) : decl.parent; if (parent === container) { - return !(isJSDocTemplateTag(decl.parent) && find((decl.parent.parent as JSDoc).tags, isJSDocTypeAlias)); + return !(isJSDocTemplateTag(decl.parent) + && find((decl.parent.parent as JSDoc).tags, isJSDocTypeAlias)); } } } @@ -3601,12 +4121,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: __String, nameArg: __String | Identifier): boolean { - if (!isIdentifier(errorLocation) || errorLocation.escapedText !== name || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation)) { + function checkAndReportErrorForMissingPrefix( + errorLocation: Node, + name: __String, + nameArg: __String | Identifier, + ): boolean { + if ( + !isIdentifier(errorLocation) || errorLocation.escapedText !== name + || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation) + ) { return false; } - const container = getThisContainer(errorLocation, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + errorLocation, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); let location: Node = container; while (location) { if (isClassLike(location.parent)) { @@ -3618,7 +4149,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Check to see if a static member exists. const constructorType = getTypeOfSymbol(classSymbol); if (getPropertyOfType(constructorType, name)) { - error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, diagnosticName(nameArg), symbolToString(classSymbol)); + error( + errorLocation, + Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, + diagnosticName(nameArg), + symbolToString(classSymbol), + ); return true; } @@ -3627,7 +4163,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (location === container && !isStatic(location)) { const instanceType = (getDeclaredTypeOfSymbol(classSymbol) as InterfaceType).thisType!; // TODO: GH#18217 if (getPropertyOfType(instanceType, name)) { - error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, diagnosticName(nameArg)); + error( + errorLocation, + Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, + diagnosticName(nameArg), + ); return true; } } @@ -3638,11 +4178,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkAndReportErrorForExtendingInterface(errorLocation: Node): boolean { const expression = getEntityNameForExtendingInterface(errorLocation); if (expression && resolveEntityName(expression, SymbolFlags.Interface, /*ignoreErrors*/ true)) { - error(errorLocation, Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, getTextOfNode(expression)); + error( + errorLocation, + Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements, + getTextOfNode(expression), + ); return true; } return false; @@ -3666,27 +4209,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkAndReportErrorForUsingTypeAsNamespace(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingTypeAsNamespace( + errorLocation: Node, + name: __String, + meaning: SymbolFlags, + ): boolean { const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(errorLocation) ? SymbolFlags.Value : 0); if (meaning === namespaceMeaning) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~namespaceMeaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Type & ~namespaceMeaning, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); const parent = errorLocation.parent; if (symbol) { if (isQualifiedName(parent)) { - Debug.assert(parent.left === errorLocation, "Should only be resolving left side of qualified name as a namespace"); + Debug.assert( + parent.left === errorLocation, + "Should only be resolving left side of qualified name as a namespace", + ); const propName = parent.right.escapedText; const propType = getPropertyOfType(getDeclaredTypeOfSymbol(symbol), propName); if (propType) { error( parent, - Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, + Diagnostics + .Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, unescapeLeadingUnderscores(name), unescapeLeadingUnderscores(propName), ); return true; } } - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_namespace_here, + unescapeLeadingUnderscores(name), + ); return true; } } @@ -3694,11 +4258,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkAndReportErrorForUsingValueAsType(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingValueAsType( + errorLocation: Node, + name: __String, + meaning: SymbolFlags, + ): boolean { if (meaning & (SymbolFlags.Type & ~SymbolFlags.Namespace)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, ~SymbolFlags.Type & SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + ~SymbolFlags.Type & SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); if (symbol && !(symbol.flags & SymbolFlags.Namespace)) { - error(errorLocation, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, + unescapeLeadingUnderscores(name), + ); return true; } } @@ -3706,40 +4287,82 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isPrimitiveTypeName(name: __String) { - return name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never" || name === "unknown"; + return name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never" + || name === "unknown"; } function checkAndReportErrorForExportingPrimitiveType(errorLocation: Node, name: __String): boolean { if (isPrimitiveTypeName(name) && errorLocation.parent.kind === SyntaxKind.ExportSpecifier) { - error(errorLocation, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, name as string); + error( + errorLocation, + Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, + name as string, + ); return true; } return false; } - function checkAndReportErrorForUsingTypeAsValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingTypeAsValue( + errorLocation: Node, + name: __String, + meaning: SymbolFlags, + ): boolean { if (meaning & SymbolFlags.Value) { if (isPrimitiveTypeName(name)) { if (isExtendedByInterface(errorLocation)) { - error(errorLocation, Diagnostics.An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics + .An_interface_cannot_extend_a_primitive_type_like_0_an_interface_can_only_extend_named_types_and_classes, + unescapeLeadingUnderscores(name), + ); } else { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, unescapeLeadingUnderscores(name)); + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, + unescapeLeadingUnderscores(name), + ); } return true; } - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Type & ~SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); const allFlags = symbol && getSymbolFlags(symbol); if (symbol && allFlags !== undefined && !(allFlags & SymbolFlags.Value)) { const rawName = unescapeLeadingUnderscores(name); if (isES2015OrLaterConstructorName(name)) { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_es2015_or_later, rawName); + error( + errorLocation, + Diagnostics + ._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_es2015_or_later, + rawName, + ); } else if (maybeMappedType(errorLocation, symbol)) { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0, rawName, rawName === "K" ? "P" : "K"); + error( + errorLocation, + Diagnostics + ._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0, + rawName, + rawName === "K" ? "P" : "K", + ); } else { - error(errorLocation, Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, rawName); + error( + errorLocation, + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here, + rawName, + ); } return true; } @@ -3750,7 +4373,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isExtendedByInterface(node: Node): boolean { const grandparent = node.parent.parent; const parentOfGrandparent = grandparent.parent; - if(grandparent && parentOfGrandparent){ + if (grandparent && parentOfGrandparent) { const isExtending = isHeritageClause(grandparent) && grandparent.token === SyntaxKind.ExtendsKeyword; const isInterface = isInterfaceDeclaration(parentOfGrandparent); return isExtending && isInterface; @@ -3759,11 +4382,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function maybeMappedType(node: Node, symbol: Symbol) { - const container = findAncestor(node.parent, n => - isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit") as TypeLiteralNode | undefined; + const container = findAncestor( + node.parent, + n => isComputedPropertyName(n) || isPropertySignature(n) ? false : isTypeLiteralNode(n) || "quit", + ) as TypeLiteralNode | undefined; if (container && container.members.length === 1) { const type = getDeclaredTypeOfSymbol(symbol); - return !!(type.flags & TypeFlags.Union) && allTypesAssignableToKind(type, TypeFlags.StringOrNumberLiteral, /*strict*/ true); + return !!(type.flags & TypeFlags.Union) + && allTypesAssignableToKind(type, TypeFlags.StringOrNumberLiteral, /*strict*/ true); } return false; } @@ -3781,19 +4407,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkAndReportErrorForUsingNamespaceAsTypeOrValue(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean { + function checkAndReportErrorForUsingNamespaceAsTypeOrValue( + errorLocation: Node, + name: __String, + meaning: SymbolFlags, + ): boolean { if (meaning & (SymbolFlags.Value & ~SymbolFlags.Type)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.NamespaceModule, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.NamespaceModule, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); if (symbol) { error( errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_value, - unescapeLeadingUnderscores(name)); + unescapeLeadingUnderscores(name), + ); return true; } } else if (meaning & (SymbolFlags.Type & ~SymbolFlags.Value)) { - const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Module, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)); + const symbol = resolveSymbol( + resolveName( + errorLocation, + name, + SymbolFlags.Module, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ), + ); if (symbol) { error(errorLocation, Diagnostics.Cannot_use_namespace_0_as_a_type, unescapeLeadingUnderscores(name)); return true; @@ -3803,33 +4452,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void { - Debug.assert(!!(result.flags & SymbolFlags.BlockScopedVariable || result.flags & SymbolFlags.Class || result.flags & SymbolFlags.Enum)); - if (result.flags & (SymbolFlags.Function | SymbolFlags.FunctionScopedVariable | SymbolFlags.Assignment) && result.flags & SymbolFlags.Class) { + Debug.assert( + !!(result.flags & SymbolFlags.BlockScopedVariable || result.flags & SymbolFlags.Class + || result.flags & SymbolFlags.Enum), + ); + if ( + result.flags & (SymbolFlags.Function | SymbolFlags.FunctionScopedVariable | SymbolFlags.Assignment) + && result.flags & SymbolFlags.Class + ) { // constructor functions aren't block scoped return; } // Block-scoped variables cannot be used before their definition const declaration = result.declarations?.find( - d => isBlockOrCatchScoped(d) || isClassLike(d) || (d.kind === SyntaxKind.EnumDeclaration)); + d => isBlockOrCatchScoped(d) || isClassLike(d) || (d.kind === SyntaxKind.EnumDeclaration), + ); - if (declaration === undefined) return Debug.fail("checkResolvedBlockScopedVariable could not find block-scoped declaration"); + if (declaration === undefined) { + return Debug.fail("checkResolvedBlockScopedVariable could not find block-scoped declaration"); + } - if (!(declaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation)) { + if ( + !(declaration.flags & NodeFlags.Ambient) && !isBlockScopedNameDeclaredBeforeUse(declaration, errorLocation) + ) { let diagnosticMessage; const declarationName = declarationNameToString(getNameOfDeclaration(declaration)); if (result.flags & SymbolFlags.BlockScopedVariable) { - diagnosticMessage = error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + errorLocation, + Diagnostics.Block_scoped_variable_0_used_before_its_declaration, + declarationName, + ); } else if (result.flags & SymbolFlags.Class) { - diagnosticMessage = error(errorLocation, Diagnostics.Class_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + errorLocation, + Diagnostics.Class_0_used_before_its_declaration, + declarationName, + ); } else if (result.flags & SymbolFlags.RegularEnum) { - diagnosticMessage = error(errorLocation, Diagnostics.Enum_0_used_before_its_declaration, declarationName); + diagnosticMessage = error( + errorLocation, + Diagnostics.Enum_0_used_before_its_declaration, + declarationName, + ); } if (diagnosticMessage) { - addRelatedInfo(diagnosticMessage, - createDiagnosticForNode(declaration, Diagnostics._0_is_declared_here, declarationName) + addRelatedInfo( + diagnosticMessage, + createDiagnosticForNode(declaration, Diagnostics._0_is_declared_here, declarationName), ); } } @@ -3841,8 +4514,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Return false if 'stopAt' node is reached or isFunctionLike(current) === true. */ function isSameScopeDescendentOf(initial: Node, parent: Node | undefined, stopAt: Node): boolean { - return !!parent && !!findAncestor(initial, n => n === parent - || (n === stopAt || isFunctionLike(n) && (!getImmediatelyInvokedFunctionExpression(n) || isAsyncFunction(n)) ? "quit" : false)); + return !!parent && !!findAncestor(initial, n => + n === parent + || (n === stopAt || isFunctionLike(n) && (!getImmediatelyInvokedFunctionExpression(n) || isAsyncFunction(n)) + ? "quit" : false)); } function getAnyImportSyntax(node: Node): AnyImportSyntax | undefined { @@ -3888,34 +4563,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.ExportSpecifier || node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node as ExportAssignment) - || isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) + || isBinaryExpression(node) + && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports + && exportAssignmentIsAlias(node) || isAccessExpression(node) && isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAliasableOrJsExpression(node.parent.right) || node.kind === SyntaxKind.ShorthandPropertyAssignment - || node.kind === SyntaxKind.PropertyAssignment && isAliasableOrJsExpression((node as PropertyAssignment).initializer) - || node.kind === SyntaxKind.VariableDeclaration && isVariableDeclarationInitializedToBareOrAccessedRequire(node) - || node.kind === SyntaxKind.BindingElement && isVariableDeclarationInitializedToBareOrAccessedRequire(node.parent.parent); + || node.kind === SyntaxKind.PropertyAssignment + && isAliasableOrJsExpression((node as PropertyAssignment).initializer) + || node.kind === SyntaxKind.VariableDeclaration + && isVariableDeclarationInitializedToBareOrAccessedRequire(node) + || node.kind === SyntaxKind.BindingElement + && isVariableDeclarationInitializedToBareOrAccessedRequire(node.parent.parent); } function isAliasableOrJsExpression(e: Expression) { return isAliasableExpression(e) || isFunctionExpression(e) && isJSConstructor(e); } - function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration | VariableDeclaration, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfImportEqualsDeclaration( + node: ImportEqualsDeclaration | VariableDeclaration, + dontResolveAlias: boolean, + ): Symbol | undefined { const commonJSPropertyAccess = getCommonJSPropertyAccess(node); if (commonJSPropertyAccess) { - const name = (getLeftmostAccessExpression(commonJSPropertyAccess.expression) as CallExpression).arguments[0] as StringLiteral; + const name = (getLeftmostAccessExpression(commonJSPropertyAccess.expression) as CallExpression) + .arguments[0] as StringLiteral; return isIdentifier(commonJSPropertyAccess.name) - ? resolveSymbol(getPropertyOfType(resolveExternalModuleTypeByLiteral(name), commonJSPropertyAccess.name.escapedText)) + ? resolveSymbol( + getPropertyOfType( + resolveExternalModuleTypeByLiteral(name), + commonJSPropertyAccess.name.escapedText, + ), + ) : undefined; } if (isVariableDeclaration(node) || node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { const immediate = resolveExternalModuleName( node, - getExternalModuleRequireArgument(node) || getExternalModuleImportEqualsDeclarationExpression(node)); + getExternalModuleRequireArgument(node) || getExternalModuleImportEqualsDeclarationExpression(node), + ); const resolved = resolveExternalModuleSymbol(immediate); markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); return resolved; @@ -3925,10 +4615,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return resolved; } - function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) { - if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false) && !node.isTypeOnly) { + function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol( + node: ImportEqualsDeclaration, + resolved: Symbol | undefined, + ) { + if ( + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false, + ) && !node.isTypeOnly + ) { const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfDeclaration(node))!; - const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration; + const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier + || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration; const message = isExport ? Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_exported_using_export_type : Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_imported_using_import_type; @@ -3937,12 +4638,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { : Diagnostics._0_was_imported_here; // TODO: how to get name for export *? - const name = typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration ? "*" : unescapeLeadingUnderscores(typeOnlyDeclaration.name.escapedText); - addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name)); + const name = typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration ? "*" + : unescapeLeadingUnderscores(typeOnlyDeclaration.name.escapedText); + addRelatedInfo( + error(node.moduleReference, message), + createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name), + ); } } - function resolveExportByName(moduleSymbol: Symbol, name: __String, sourceNode: TypeOnlyCompatibleAliasDeclaration | undefined, dontResolveAlias: boolean) { + function resolveExportByName( + moduleSymbol: Symbol, + name: __String, + sourceNode: TypeOnlyCompatibleAliasDeclaration | undefined, + dontResolveAlias: boolean, + ) { const exportValue = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); const exportSymbol = exportValue ? getPropertyOfType(getTypeOfSymbol(exportValue), name, /*skipObjectFunctionPropertyAugment*/ true) @@ -3953,7 +4663,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isSyntacticDefault(node: Node) { - return ((isExportAssignment(node) && !node.isExportEquals) || hasSyntacticModifier(node, ModifierFlags.Default) || isExportSpecifier(node)); + return ((isExportAssignment(node) && !node.isExportEquals) || hasSyntacticModifier(node, ModifierFlags.Default) + || isExportSpecifier(node)); } function getUsageModeForExpression(usage: Expression) { @@ -3969,7 +4680,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return usageMode === ModuleKind.ESNext && endsWith((usage as StringLiteralLike).text, Extension.Json); } - function canHaveSyntheticDefault(file: SourceFile | undefined, moduleSymbol: Symbol, dontResolveAlias: boolean, usage: Expression) { + function canHaveSyntheticDefault( + file: SourceFile | undefined, + moduleSymbol: Symbol, + dontResolveAlias: boolean, + usage: Expression, + ) { const usageMode = file && getUsageModeForExpression(usage); if (file && usageMode !== undefined) { const result = isESMFormatImportImportingCommonjsFormatFile(usageMode, file.impliedNodeFormat); @@ -3984,13 +4700,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Declaration files (and ambient modules) if (!file || file.isDeclarationFile) { // Definitely cannot have a synthetic default if they have a syntactic default member specified - const defaultExportSymbol = resolveExportByName(moduleSymbol, InternalSymbolName.Default, /*sourceNode*/ undefined, /*dontResolveAlias*/ true); // Dont resolve alias because we want the immediately exported symbol's declaration + const defaultExportSymbol = resolveExportByName( + moduleSymbol, + InternalSymbolName.Default, + /*sourceNode*/ undefined, + /*dontResolveAlias*/ true, + ); // Dont resolve alias because we want the immediately exported symbol's declaration if (defaultExportSymbol && some(defaultExportSymbol.declarations, isSyntacticDefault)) { return false; } // It _might_ still be incorrect to assume there is no __esModule marker on the import at runtime, even if there is no `default` member // So we check a bit more, - if (resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias)) { + if ( + resolveExportByName( + moduleSymbol, + escapeLeadingUnderscores("__esModule"), + /*sourceNode*/ undefined, + dontResolveAlias, + ) + ) { // If there is an `__esModule` specified in the declaration (meaning someone explicitly added it or wrote it in their code), // it definitely is a module and does not have a synthetic default return false; @@ -4005,7 +4733,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return hasExportAssignmentSymbol(moduleSymbol); } // JS files have a synthetic default if they do not contain ES2015+ module syntax (export = is not valid in js) _and_ do not have an __esModule marker - return typeof file.externalModuleIndicator !== "object" && !resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias); + return typeof file.externalModuleIndicator !== "object" + && !resolveExportByName( + moduleSymbol, + escapeLeadingUnderscores("__esModule"), + /*sourceNode*/ undefined, + dontResolveAlias, + ); } function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol | undefined { @@ -4015,7 +4749,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getTargetofModuleDefault(moduleSymbol: Symbol, node: ImportClause | ImportOrExportSpecifier, dontResolveAlias: boolean) { + function getTargetofModuleDefault( + moduleSymbol: Symbol, + node: ImportClause | ImportOrExportSpecifier, + dontResolveAlias: boolean, + ) { let exportDefaultSymbol: Symbol | undefined; if (isShorthandAmbientModuleSymbol(moduleSymbol)) { exportDefaultSymbol = moduleSymbol; @@ -4033,44 +4771,73 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const hasSyntheticDefault = canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier); if (!exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly) { if (hasExportAssignmentSymbol(moduleSymbol) && !allowSyntheticDefaultImports) { - const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" : "esModuleInterop"; + const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" + : "esModuleInterop"; const exportEqualsSymbol = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); const exportAssignment = exportEqualsSymbol!.valueDeclaration; - const err = error(node.name, Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, symbolToString(moduleSymbol), compilerOptionName); + const err = error( + node.name, + Diagnostics.Module_0_can_only_be_default_imported_using_the_1_flag, + symbolToString(moduleSymbol), + compilerOptionName, + ); if (exportAssignment) { - addRelatedInfo(err, createDiagnosticForNode( - exportAssignment, - Diagnostics.This_module_is_declared_with_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, - compilerOptionName - )); + addRelatedInfo( + err, + createDiagnosticForNode( + exportAssignment, + Diagnostics + .This_module_is_declared_with_export_and_can_only_be_used_with_a_default_import_when_using_the_0_flag, + compilerOptionName, + ), + ); } } else if (isImportClause(node)) { reportNonDefaultExport(moduleSymbol, node); } else { - errorNoModuleMemberSymbol(moduleSymbol, moduleSymbol, node, isImportOrExportSpecifier(node) && node.propertyName || node.name); + errorNoModuleMemberSymbol( + moduleSymbol, + moduleSymbol, + node, + isImportOrExportSpecifier(node) && node.propertyName || node.name, + ); } } else if (hasSyntheticDefault || hasDefaultOnly) { // per emit behavior, a synthetic default overrides a "real" .default member if `__esModule` is not present - const resolved = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); + const resolved = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) + || resolveSymbol(moduleSymbol, dontResolveAlias); markSymbolOfAliasDeclarationIfTypeOnly(node, moduleSymbol, resolved, /*overwriteEmpty*/ false); return resolved; } - markSymbolOfAliasDeclarationIfTypeOnly(node, exportDefaultSymbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + exportDefaultSymbol, + /*finalTarget*/ undefined, + /*overwriteEmpty*/ false, + ); return exportDefaultSymbol; } - function getModuleSpecifierForImportOrExport(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportOrExportSpecifier): Expression | undefined { + function getModuleSpecifierForImportOrExport( + node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportOrExportSpecifier, + ): Expression | undefined { switch (node.kind) { - case SyntaxKind.ImportClause: return node.parent.moduleSpecifier; - case SyntaxKind.ImportEqualsDeclaration: return isExternalModuleReference(node.moduleReference) ? node.moduleReference.expression : undefined; - case SyntaxKind.NamespaceImport: return node.parent.parent.moduleSpecifier; - case SyntaxKind.ImportSpecifier: return node.parent.parent.parent.moduleSpecifier; - case SyntaxKind.ExportSpecifier: return node.parent.parent.moduleSpecifier; - default: return Debug.assertNever(node); + case SyntaxKind.ImportClause: + return node.parent.moduleSpecifier; + case SyntaxKind.ImportEqualsDeclaration: + return isExternalModuleReference(node.moduleReference) ? node.moduleReference.expression : undefined; + case SyntaxKind.NamespaceImport: + return node.parent.parent.moduleSpecifier; + case SyntaxKind.ImportSpecifier: + return node.parent.parent.parent.moduleSpecifier; + case SyntaxKind.ExportSpecifier: + return node.parent.parent.moduleSpecifier; + default: + return Debug.assertNever(node); } } @@ -4084,15 +4851,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ); } else { - const diagnostic = error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol)); + const diagnostic = error( + node.name, + Diagnostics.Module_0_has_no_default_export, + symbolToString(moduleSymbol), + ); const exportStar = moduleSymbol.exports?.get(InternalSymbolName.ExportStar); if (exportStar) { - const defaultExport = exportStar.declarations?.find(decl => !!( - isExportDeclaration(decl) && decl.moduleSpecifier && - resolveExternalModuleName(decl, decl.moduleSpecifier)?.exports?.has(InternalSymbolName.Default) - )); + const defaultExport = exportStar.declarations?.find(decl => + !!( + isExportDeclaration(decl) && decl.moduleSpecifier + && resolveExternalModuleName(decl, decl.moduleSpecifier)?.exports?.has( + InternalSymbolName.Default, + ) + ) + ); if (defaultExport) { - addRelatedInfo(diagnostic, createDiagnosticForNode(defaultExport, Diagnostics.export_Asterisk_does_not_re_export_a_default)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + defaultExport, + Diagnostics.export_Asterisk_does_not_re_export_a_default, + ), + ); } } } @@ -4101,7 +4882,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol | undefined { const moduleSpecifier = node.parent.parent.moduleSpecifier; const immediate = resolveExternalModuleName(node, moduleSpecifier); - const resolved = resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressInteropError*/ false); + const resolved = resolveESModuleSymbol( + immediate, + moduleSpecifier, + dontResolveAlias, + /*suppressInteropError*/ false, + ); markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); return resolved; } @@ -4109,7 +4895,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTargetOfNamespaceExport(node: NamespaceExport, dontResolveAlias: boolean): Symbol | undefined { const moduleSpecifier = node.parent.moduleSpecifier; const immediate = moduleSpecifier && resolveExternalModuleName(node, moduleSpecifier); - const resolved = moduleSpecifier && resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressInteropError*/ false); + const resolved = moduleSpecifier + && resolveESModuleSymbol(immediate, moduleSpecifier, dontResolveAlias, /*suppressInteropError*/ false); markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false); return resolved; } @@ -4141,7 +4928,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const result = createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.escapedName); Debug.assert(valueSymbol.declarations || typeSymbol.declarations); - result.declarations = deduplicate(concatenate(valueSymbol.declarations!, typeSymbol.declarations), equateValues); + result.declarations = deduplicate( + concatenate(valueSymbol.declarations!, typeSymbol.declarations), + equateValues, + ); result.parent = valueSymbol.parent || typeSymbol.parent; if (valueSymbol.valueDeclaration) result.valueDeclaration = valueSymbol.valueDeclaration; if (typeSymbol.members) result.members = new Map(typeSymbol.members); @@ -4149,12 +4939,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function getExportOfModule(symbol: Symbol, name: Identifier, specifier: Declaration, dontResolveAlias: boolean): Symbol | undefined { + function getExportOfModule( + symbol: Symbol, + name: Identifier, + specifier: Declaration, + dontResolveAlias: boolean, + ): Symbol | undefined { if (symbol.flags & SymbolFlags.Module) { const exportSymbol = getExportsOfSymbol(symbol).get(name.escapedText); const resolved = resolveSymbol(exportSymbol, dontResolveAlias); const exportStarDeclaration = getSymbolLinks(symbol).typeOnlyExportStarMap?.get(name.escapedText); - markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false, exportStarDeclaration, name.escapedText); + markSymbolOfAliasDeclarationIfTypeOnly( + specifier, + exportSymbol, + resolved, + /*overwriteEmpty*/ false, + exportStarDeclaration, + name.escapedText, + ); return resolved; } } @@ -4168,15 +4970,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration | VariableDeclaration, specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, dontResolveAlias = false): Symbol | undefined { - const moduleSpecifier = getExternalModuleRequireArgument(node) || (node as ImportDeclaration | ExportDeclaration).moduleSpecifier!; + function getExternalModuleMember( + node: ImportDeclaration | ExportDeclaration | VariableDeclaration, + specifier: ImportOrExportSpecifier | BindingElement | PropertyAccessExpression, + dontResolveAlias = false, + ): Symbol | undefined { + const moduleSpecifier = getExternalModuleRequireArgument(node) + || (node as ImportDeclaration | ExportDeclaration).moduleSpecifier!; const moduleSymbol = resolveExternalModuleName(node, moduleSpecifier)!; // TODO: GH#18217 const name = !isPropertyAccessExpression(specifier) && specifier.propertyName || specifier.name; if (!isIdentifier(name)) { return undefined; } const suppressInteropError = name.escapedText === InternalSymbolName.Default && allowSyntheticDefaultImports; - const targetSymbol = resolveESModuleSymbol(moduleSymbol, moduleSpecifier, /*dontResolveAlias*/ false, suppressInteropError); + const targetSymbol = resolveESModuleSymbol( + moduleSymbol, + moduleSpecifier, + /*dontResolveAlias*/ false, + suppressInteropError, + ); if (targetSymbol) { if (name.escapedText) { if (isShorthandAmbientModuleSymbol(moduleSymbol)) { @@ -4186,7 +4998,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let symbolFromVariable: Symbol | undefined; // First check if module was specified with "export=". If so, get the member from the resolved type if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports.get(InternalSymbolName.ExportEquals)) { - symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.escapedText, /*skipObjectFunctionPropertyAugment*/ true); + symbolFromVariable = getPropertyOfType( + getTypeOfSymbol(targetSymbol), + name.escapedText, + /*skipObjectFunctionPropertyAugment*/ true, + ); } else { symbolFromVariable = getPropertyOfVariable(targetSymbol, name.escapedText); @@ -4197,14 +5013,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let symbolFromModule = getExportOfModule(targetSymbol, name, specifier, dontResolveAlias); if (symbolFromModule === undefined && name.escapedText === InternalSymbolName.Default) { const file = moduleSymbol.declarations?.find(isSourceFile); - if (isOnlyImportedAsDefault(moduleSpecifier) || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier)) { - symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias); + if ( + isOnlyImportedAsDefault(moduleSpecifier) + || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier) + ) { + symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) + || resolveSymbol(moduleSymbol, dontResolveAlias); } } - const symbol = symbolFromModule && symbolFromVariable && symbolFromModule !== symbolFromVariable ? - combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) : - symbolFromModule || symbolFromVariable; + const symbol = symbolFromModule && symbolFromVariable && symbolFromModule !== symbolFromVariable + ? combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) + : symbolFromModule || symbolFromVariable; if (!symbol) { errorNoModuleMemberSymbol(moduleSymbol, targetSymbol, node, name); } @@ -4219,10 +5039,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const suggestion = getSuggestedSymbolForNonexistentModule(name, targetSymbol); if (suggestion !== undefined) { const suggestionName = symbolToString(suggestion); - const diagnostic = error(name, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, moduleName, declarationName, suggestionName); + const diagnostic = error( + name, + Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, + moduleName, + declarationName, + suggestionName, + ); if (suggestion.valueDeclaration) { - addRelatedInfo(diagnostic, - createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestionName) + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestionName, + ), ); } } @@ -4232,7 +5063,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { name, Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_to_use_import_1_from_0_instead, moduleName, - declarationName + declarationName, ); } else { @@ -4241,23 +5072,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function reportNonExportedMember(node: Node, name: Identifier, declarationName: string, moduleSymbol: Symbol, moduleName: string): void { + function reportNonExportedMember( + node: Node, + name: Identifier, + declarationName: string, + moduleSymbol: Symbol, + moduleName: string, + ): void { const localSymbol = tryCast(moduleSymbol.valueDeclaration, canHaveLocals)?.locals?.get(name.escapedText); const exports = moduleSymbol.exports; if (localSymbol) { const exportedEqualsSymbol = exports?.get(InternalSymbolName.ExportEquals); if (exportedEqualsSymbol) { - getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) ? reportInvalidImportEqualsExportMember(node, name, declarationName, moduleName) : - error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); + getSymbolIfSameReference(exportedEqualsSymbol, localSymbol) + ? reportInvalidImportEqualsExportMember(node, name, declarationName, moduleName) + : error(name, Diagnostics.Module_0_has_no_exported_member_1, moduleName, declarationName); } else { - const exportedSymbol = exports ? find(symbolsToArray(exports), symbol => !!getSymbolIfSameReference(symbol, localSymbol)) : undefined; - const diagnostic = exportedSymbol ? error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, moduleName, declarationName, symbolToString(exportedSymbol)) : - error(name, Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, moduleName, declarationName); + const exportedSymbol = exports ? find(symbolsToArray(exports), symbol => + !!getSymbolIfSameReference(symbol, localSymbol)) : undefined; + const diagnostic = exportedSymbol + ? error( + name, + Diagnostics.Module_0_declares_1_locally_but_it_is_exported_as_2, + moduleName, + declarationName, + symbolToString(exportedSymbol), + ) + : error( + name, + Diagnostics.Module_0_declares_1_locally_but_it_is_not_exported, + moduleName, + declarationName, + ); if (localSymbol.declarations) { - addRelatedInfo(diagnostic, + addRelatedInfo( + diagnostic, ...map(localSymbol.declarations, (decl, index) => - createDiagnosticForNode(decl, index === 0 ? Diagnostics._0_is_declared_here : Diagnostics.and_here, declarationName))); + createDiagnosticForNode( + decl, + index === 0 ? Diagnostics._0_is_declared_here : Diagnostics.and_here, + declarationName, + )), + ); } } } @@ -4266,27 +5123,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function reportInvalidImportEqualsExportMember(node: Node, name: Identifier, declarationName: string, moduleName: string) { + function reportInvalidImportEqualsExportMember( + node: Node, + name: Identifier, + declarationName: string, + moduleName: string, + ) { if (moduleKind >= ModuleKind.ES2015) { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_a_default_import : - Diagnostics._0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_a_default_import + : Diagnostics._0_can_only_be_imported_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; error(name, message, declarationName); } else { if (isInJSFile(node)) { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_using_a_default_import : - Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_a_require_call_or_by_using_a_default_import + : Diagnostics + ._0_can_only_be_imported_by_using_a_require_call_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; error(name, message, declarationName); } else { - const message = getESModuleInterop(compilerOptions) ? Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import : - Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; + const message = getESModuleInterop(compilerOptions) + ? Diagnostics._0_can_only_be_imported_by_using_import_1_require_2_or_a_default_import + : Diagnostics + ._0_can_only_be_imported_by_using_import_1_require_2_or_by_turning_on_the_esModuleInterop_flag_and_using_a_default_import; error(name, message, declarationName, declarationName, moduleName); } } } - function getTargetOfImportSpecifier(node: ImportSpecifier | BindingElement, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfImportSpecifier( + node: ImportSpecifier | BindingElement, + dontResolveAlias: boolean, + ): Symbol | undefined { if (isImportSpecifier(node) && idText(node.propertyName || node.name) === InternalSymbolName.Default) { const specifier = getModuleSpecifierForImportOrExport(node); const moduleSymbol = specifier && resolveExternalModuleName(node, specifier); @@ -4294,7 +5164,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTargetofModuleDefault(moduleSymbol, node, dontResolveAlias); } } - const root = isBindingElement(node) ? getRootDeclaration(node) as VariableDeclaration : node.parent.parent.parent; + const root = isBindingElement(node) ? getRootDeclaration(node) as VariableDeclaration + : node.parent.parent.parent; const commonJSPropertyAccess = getCommonJSPropertyAccess(root); const resolved = getExternalModuleMember(root, commonJSPropertyAccess || node, dontResolveAlias); const name = node.propertyName || node.name; @@ -4311,10 +5182,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfNamespaceExportDeclaration( + node: NamespaceExportDeclaration, + dontResolveAlias: boolean, + ): Symbol | undefined { if (canHaveSymbol(node.parent)) { const resolved = resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias); - markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); + markSymbolOfAliasDeclarationIfTypeOnly( + node, + /*immediateTarget*/ undefined, + resolved, + /*overwriteEmpty*/ false, + ); return resolved; } } @@ -4327,14 +5206,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTargetofModuleDefault(moduleSymbol, node, !!dontResolveAlias); } } - const resolved = node.parent.parent.moduleSpecifier ? - getExternalModuleMember(node.parent.parent, node, dontResolveAlias) : - resolveEntityName(node.propertyName || node.name, meaning, /*ignoreErrors*/ false, dontResolveAlias); + const resolved = node.parent.parent.moduleSpecifier + ? getExternalModuleMember(node.parent.parent, node, dontResolveAlias) + : resolveEntityName(node.propertyName || node.name, meaning, /*ignoreErrors*/ false, dontResolveAlias); markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); return resolved; } - function getTargetOfExportAssignment(node: ExportAssignment | BinaryExpression, dontResolveAlias: boolean): Symbol | undefined { + function getTargetOfExportAssignment( + node: ExportAssignment | BinaryExpression, + dontResolveAlias: boolean, + ): Symbol | undefined { const expression = isExportAssignment(node) ? node.expression : node.right; const resolved = getTargetOfAliasLikeExpression(expression, dontResolveAlias); markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false); @@ -4348,7 +5230,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isEntityName(expression) && !isEntityNameExpression(expression)) { return undefined; } - const aliasLike = resolveEntityName(expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontResolveAlias); + const aliasLike = resolveEntityName( + expression, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*ignoreErrors*/ true, + dontResolveAlias, + ); if (aliasLike) { return aliasLike; } @@ -4357,7 +5244,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTargetOfAccessExpression(node: AccessExpression, dontRecursivelyResolve: boolean): Symbol | undefined { - if (!(isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken)) { + if ( + !(isBinaryExpression(node.parent) && node.parent.left === node + && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) + ) { return undefined; } @@ -4368,7 +5258,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.VariableDeclaration: - return getTargetOfImportEqualsDeclaration(node as ImportEqualsDeclaration | VariableDeclaration, dontRecursivelyResolve); + return getTargetOfImportEqualsDeclaration( + node as ImportEqualsDeclaration | VariableDeclaration, + dontRecursivelyResolve, + ); case SyntaxKind.ImportClause: return getTargetOfImportClause(node as ImportClause, dontRecursivelyResolve); case SyntaxKind.NamespaceImport: @@ -4379,14 +5272,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.BindingElement: return getTargetOfImportSpecifier(node as ImportSpecifier | BindingElement, dontRecursivelyResolve); case SyntaxKind.ExportSpecifier: - return getTargetOfExportSpecifier(node as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, dontRecursivelyResolve); + return getTargetOfExportSpecifier( + node as ExportSpecifier, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + dontRecursivelyResolve, + ); case SyntaxKind.ExportAssignment: case SyntaxKind.BinaryExpression: - return getTargetOfExportAssignment((node as ExportAssignment | BinaryExpression), dontRecursivelyResolve); + return getTargetOfExportAssignment(node as ExportAssignment | BinaryExpression, dontRecursivelyResolve); case SyntaxKind.NamespaceExportDeclaration: - return getTargetOfNamespaceExportDeclaration(node as NamespaceExportDeclaration, dontRecursivelyResolve); + return getTargetOfNamespaceExportDeclaration( + node as NamespaceExportDeclaration, + dontRecursivelyResolve, + ); case SyntaxKind.ShorthandPropertyAssignment: - return resolveEntityName((node as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ true, dontRecursivelyResolve); + return resolveEntityName( + (node as ShorthandPropertyAssignment).name, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*ignoreErrors*/ true, + dontRecursivelyResolve, + ); case SyntaxKind.PropertyAssignment: return getTargetOfAliasLikeExpression((node as PropertyAssignment).initializer, dontRecursivelyResolve); case SyntaxKind.ElementAccessExpression: @@ -4401,9 +5306,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Indicates that a symbol is an alias that does not merge with a local declaration. * OR Is a JSContainer which may merge an alias with a local declaration */ - function isNonLocalAlias(symbol: Symbol | undefined, excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace): symbol is Symbol { + function isNonLocalAlias( + symbol: Symbol | undefined, + excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + ): symbol is Symbol { if (!symbol) return false; - return (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias || !!(symbol.flags & SymbolFlags.Alias && symbol.flags & SymbolFlags.Assignment); + return (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias + || !!(symbol.flags & SymbolFlags.Alias && symbol.flags & SymbolFlags.Assignment); } function resolveSymbol(symbol: Symbol, dontResolveAlias?: boolean): Symbol; @@ -4462,20 +5371,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @returns SymbolFlags.All if `symbol` is an alias that ultimately resolves to `unknown`; * combined flags of all alias targets otherwise. */ - function getSymbolFlags(symbol: Symbol, excludeTypeOnlyMeanings?: boolean, excludeLocalMeanings?: boolean): SymbolFlags { + function getSymbolFlags( + symbol: Symbol, + excludeTypeOnlyMeanings?: boolean, + excludeLocalMeanings?: boolean, + ): SymbolFlags { const typeOnlyDeclaration = excludeTypeOnlyMeanings && getTypeOnlyAliasDeclaration(symbol); const typeOnlyDeclarationIsExportStar = typeOnlyDeclaration && isExportDeclaration(typeOnlyDeclaration); const typeOnlyResolution = typeOnlyDeclaration && ( typeOnlyDeclarationIsExportStar - ? resolveExternalModuleName(typeOnlyDeclaration.moduleSpecifier, typeOnlyDeclaration.moduleSpecifier, /*ignoreErrors*/ true) - : resolveAlias(typeOnlyDeclaration.symbol)); - const typeOnlyExportStarTargets = typeOnlyDeclarationIsExportStar && typeOnlyResolution ? getExportsOfModule(typeOnlyResolution) : undefined; + ? resolveExternalModuleName( + typeOnlyDeclaration.moduleSpecifier, + typeOnlyDeclaration.moduleSpecifier, + /*ignoreErrors*/ true, + ) + : resolveAlias(typeOnlyDeclaration.symbol) + ); + const typeOnlyExportStarTargets = typeOnlyDeclarationIsExportStar && typeOnlyResolution + ? getExportsOfModule(typeOnlyResolution) : undefined; let flags = excludeLocalMeanings ? SymbolFlags.None : symbol.flags; let seenSymbols; while (symbol.flags & SymbolFlags.Alias) { const target = getExportSymbolOfValueSymbolIfExported(resolveAlias(symbol)); - if (!typeOnlyDeclarationIsExportStar && target === typeOnlyResolution || - typeOnlyExportStarTargets?.get(target.escapedName) === target + if ( + !typeOnlyDeclarationIsExportStar && target === typeOnlyResolution + || typeOnlyExportStarTargets?.get(target.escapedName) === target ) { break; } @@ -4527,7 +5447,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { immediateTarget: Symbol | undefined, finalTarget: Symbol | undefined, overwriteEmpty: boolean, - exportStarDeclaration?: ExportDeclaration & { readonly isTypeOnly: true, readonly moduleSpecifier: Expression }, + exportStarDeclaration?: ExportDeclaration & { + readonly isTypeOnly: true; + readonly moduleSpecifier: Expression; + }, exportStarName?: __String, ): boolean { if (!aliasDeclaration || isPropertyAccessExpression(aliasDeclaration)) return false; @@ -4554,11 +5477,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, finalTarget, overwriteEmpty); } - function markSymbolOfAliasDeclarationIfTypeOnlyWorker(aliasDeclarationLinks: SymbolLinks, target: Symbol | undefined, overwriteEmpty: boolean): boolean { - if (target && (aliasDeclarationLinks.typeOnlyDeclaration === undefined || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclaration === false)) { + function markSymbolOfAliasDeclarationIfTypeOnlyWorker( + aliasDeclarationLinks: SymbolLinks, + target: Symbol | undefined, + overwriteEmpty: boolean, + ): boolean { + if ( + target + && (aliasDeclarationLinks.typeOnlyDeclaration === undefined + || overwriteEmpty && aliasDeclarationLinks.typeOnlyDeclaration === false) + ) { const exportSymbol = target.exports?.get(InternalSymbolName.ExportEquals) ?? target; - const typeOnly = exportSymbol.declarations && find(exportSymbol.declarations, isTypeOnlyImportOrExportDeclaration); - aliasDeclarationLinks.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(exportSymbol).typeOnlyDeclaration ?? false; + const typeOnly = exportSymbol.declarations + && find(exportSymbol.declarations, isTypeOnlyImportOrExportDeclaration); + aliasDeclarationLinks.typeOnlyDeclaration = typeOnly ?? getSymbolLinks(exportSymbol).typeOnlyDeclaration + ?? false; } return !!aliasDeclarationLinks.typeOnlyDeclaration; } @@ -4574,7 +5507,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (links.typeOnlyDeclaration) { const resolved = links.typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration - ? resolveSymbol(getExportsOfModule(links.typeOnlyDeclaration.symbol.parent!).get(links.typeOnlyExportStarName || symbol.escapedName))! + ? resolveSymbol( + getExportsOfModule(links.typeOnlyDeclaration.symbol.parent!).get( + links.typeOnlyExportStarName || symbol.escapedName, + ), + )! : resolveAlias(links.typeOnlyDeclaration.symbol); return getSymbolFlags(resolved) & include ? links.typeOnlyDeclaration : undefined; } @@ -4588,8 +5525,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getSymbolOfDeclaration(node); const target = resolveAlias(symbol); if (target) { - const markAlias = target === unknownSymbol || - ((getSymbolFlags(symbol, /*excludeTypeOnlyMeanings*/ true) & SymbolFlags.Value) && !isConstEnumOrConstEnumOnlyModule(target)); + const markAlias = target === unknownSymbol + || ((getSymbolFlags(symbol, /*excludeTypeOnlyMeanings*/ true) & SymbolFlags.Value) + && !isConstEnumOrConstEnumOnlyModule(target)); if (markAlias) { markAliasSymbolAsReferenced(symbol); @@ -4629,7 +5567,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // This function is only for imports with entity names - function getSymbolOfPartOfRightHandSideOfImportEquals(entityName: EntityName, dontResolveAlias?: boolean): Symbol | undefined { + function getSymbolOfPartOfRightHandSideOfImportEquals( + entityName: EntityName, + dontResolveAlias?: boolean, + ): Symbol | undefined { // There are three things we might try to look for. In the following examples, // the search term is enclosed in |...|: // @@ -4647,12 +5588,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Case 2 in above example // entityName.kind could be a QualifiedName or a Missing identifier Debug.assert(entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration); - return resolveEntityName(entityName, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias); + return resolveEntityName( + entityName, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*ignoreErrors*/ false, + dontResolveAlias, + ); } } function getFullyQualifiedName(symbol: Symbol, containingLocation?: Node): string { - return symbol.parent ? getFullyQualifiedName(symbol.parent, containingLocation) + "." + symbolToString(symbol) : symbolToString(symbol, containingLocation, /*meaning*/ undefined, SymbolFormatFlags.DoNotIncludeSymbolChain | SymbolFormatFlags.AllowAnyNodeKind); + return symbol.parent ? getFullyQualifiedName(symbol.parent, containingLocation) + "." + symbolToString(symbol) + : symbolToString( + symbol, + containingLocation, + /*meaning*/ undefined, + SymbolFormatFlags.DoNotIncludeSymbolChain | SymbolFormatFlags.AllowAnyNodeKind, + ); } function getContainingQualifiedNameNode(node: QualifiedName) { @@ -4664,7 +5616,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function tryGetQualifiedNameAsValue(node: QualifiedName) { let left: Identifier | QualifiedName = getFirstIdentifier(node); - let symbol = resolveName(left, left.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, left, /*isUse*/ true); + let symbol = resolveName( + left, + left.escapedText, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + left, + /*isUse*/ true, + ); if (!symbol) { return undefined; } @@ -4682,7 +5641,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Resolves a qualified name and any involved aliases. */ - function resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean, location?: Node): Symbol | undefined { + function resolveEntityName( + name: EntityNameOrEntityNameExpression, + meaning: SymbolFlags, + ignoreErrors?: boolean, + dontResolveAlias?: boolean, + location?: Node, + ): Symbol | undefined { if (nodeIsMissing(name)) { return undefined; } @@ -4690,9 +5655,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const namespaceMeaning = SymbolFlags.Namespace | (isInJSFile(name) ? meaning & SymbolFlags.Value : 0); let symbol: Symbol | undefined; if (name.kind === SyntaxKind.Identifier) { - const message = meaning === namespaceMeaning || nodeIsSynthesized(name) ? Diagnostics.Cannot_find_namespace_0 : getCannotFindNameDiagnosticForName(getFirstIdentifier(name)); - const symbolFromJSPrototype = isInJSFile(name) && !nodeIsSynthesized(name) ? resolveEntityNameFromAssignmentDeclaration(name, meaning) : undefined; - symbol = getMergedSymbol(resolveName(location || name, name.escapedText, meaning, ignoreErrors || symbolFromJSPrototype ? undefined : message, name, /*isUse*/ true, /*excludeGlobals*/ false)); + const message = meaning === namespaceMeaning || nodeIsSynthesized(name) + ? Diagnostics.Cannot_find_namespace_0 : getCannotFindNameDiagnosticForName(getFirstIdentifier(name)); + const symbolFromJSPrototype = isInJSFile(name) && !nodeIsSynthesized(name) + ? resolveEntityNameFromAssignmentDeclaration(name, meaning) : undefined; + symbol = getMergedSymbol( + resolveName( + location || name, + name.escapedText, + meaning, + ignoreErrors || symbolFromJSPrototype ? undefined : message, + name, + /*isUse*/ true, + /*excludeGlobals*/ false, + ), + ); if (!symbol) { return getMergedSymbol(symbolFromJSPrototype); } @@ -4700,7 +5677,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) { const left = name.kind === SyntaxKind.QualifiedName ? name.left : name.expression; const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name; - let namespace = resolveEntityName(left, namespaceMeaning, ignoreErrors, /*dontResolveAlias*/ false, location); + let namespace = resolveEntityName( + left, + namespaceMeaning, + ignoreErrors, + /*dontResolveAlias*/ false, + location, + ); if (!namespace || nodeIsMissing(right)) { return undefined; } @@ -4708,14 +5691,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return namespace; } if ( - namespace.valueDeclaration && - isInJSFile(namespace.valueDeclaration) && - getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler && - isVariableDeclaration(namespace.valueDeclaration) && - namespace.valueDeclaration.initializer && - isCommonJsRequire(namespace.valueDeclaration.initializer) + namespace.valueDeclaration + && isInJSFile(namespace.valueDeclaration) + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler + && isVariableDeclaration(namespace.valueDeclaration) + && namespace.valueDeclaration.initializer + && isCommonJsRequire(namespace.valueDeclaration.initializer) ) { - const moduleName = (namespace.valueDeclaration.initializer as CallExpression).arguments[0] as StringLiteral; + const moduleName = (namespace.valueDeclaration.initializer as CallExpression) + .arguments[0] as StringLiteral; const moduleSym = resolveExternalModuleName(moduleName, moduleName); if (moduleSym) { const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym); @@ -4727,7 +5711,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning)); if (!symbol && (namespace.flags & SymbolFlags.Alias)) { // `namespace` can be resolved further if there was a symbol merge with a re-export - symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(resolveAlias(namespace)), right.escapedText, meaning)); + symbol = getMergedSymbol( + getSymbol(getExportsOfSymbol(resolveAlias(namespace)), right.escapedText, meaning), + ); } if (!symbol) { if (!ignoreErrors) { @@ -4735,7 +5721,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const declarationName = declarationNameToString(right); const suggestionForNonexistentModule = getSuggestedSymbolForNonexistentModule(right, namespace); if (suggestionForNonexistentModule) { - error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestionForNonexistentModule)); + error( + right, + Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, + namespaceName, + declarationName, + symbolToString(suggestionForNonexistentModule), + ); return undefined; } @@ -4749,19 +5741,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error( containingQualifiedName, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, - entityNameToString(containingQualifiedName) + entityNameToString(containingQualifiedName), ); return undefined; } if (meaning & SymbolFlags.Namespace && isQualifiedName(name.parent)) { - const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type)); + const exportedTypeSymbol = getMergedSymbol( + getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type), + ); if (exportedTypeSymbol) { error( name.parent.right, - Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, + Diagnostics + .Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, symbolToString(exportedTypeSymbol), - unescapeLeadingUnderscores(name.parent.right.escapedText) + unescapeLeadingUnderscores(name.parent.right.escapedText), ); return undefined; } @@ -4775,9 +5770,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { Debug.assertNever(name, "Unknown entity name kind."); } - Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); - if (!nodeIsSynthesized(name) && isEntityName(name) && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment)) { - markSymbolOfAliasDeclarationIfTypeOnly(getAliasDeclarationFromName(name), symbol, /*finalTarget*/ undefined, /*overwriteEmpty*/ true); + Debug.assert( + (getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, + "Should never get an instantiated symbol here.", + ); + if ( + !nodeIsSynthesized(name) && isEntityName(name) + && (symbol.flags & SymbolFlags.Alias || name.parent.kind === SyntaxKind.ExportAssignment) + ) { + markSymbolOfAliasDeclarationIfTypeOnly( + getAliasDeclarationFromName(name), + symbol, + /*finalTarget*/ undefined, + /*overwriteEmpty*/ true, + ); } return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol); } @@ -4792,13 +5798,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isJSDocTypeReference(name.parent)) { const secondaryLocation = getAssignmentDeclarationLocation(name.parent); if (secondaryLocation) { - return resolveName(secondaryLocation, name.escapedText, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ true); + return resolveName( + secondaryLocation, + name.escapedText, + meaning, + /*nameNotFoundMessage*/ undefined, + name, + /*isUse*/ true, + ); } } } function getAssignmentDeclarationLocation(node: TypeReferenceNode): Node | undefined { - const typeAlias = findAncestor(node, node => !(isJSDocNode(node) || node.flags & NodeFlags.JSDoc) ? "quit" : isJSDocTypeAlias(node)); + const typeAlias = findAncestor( + node, + node => !(isJSDocNode(node) || node.flags & NodeFlags.JSDoc) ? "quit" : isJSDocTypeAlias(node), + ); if (typeAlias) { return; } @@ -4810,16 +5826,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getDeclarationOfJSPrototypeContainer(symbol); } } - if (host && isFunctionExpression(host) && isPrototypePropertyAssignment(host.parent) && isExpressionStatement(host.parent.parent)) { + if ( + host && isFunctionExpression(host) && isPrototypePropertyAssignment(host.parent) + && isExpressionStatement(host.parent.parent) + ) { // X.prototype.m = /** @param {K} p */ function () { } <-- look for K on X's declaration const symbol = getSymbolOfDeclaration(host.parent.left); if (symbol) { return getDeclarationOfJSPrototypeContainer(symbol); } } - if (host && (isObjectLiteralMethod(host) || isPropertyAssignment(host)) && - isBinaryExpression(host.parent.parent) && - getAssignmentDeclarationKind(host.parent.parent) === AssignmentDeclarationKind.Prototype) { + if ( + host && (isObjectLiteralMethod(host) || isPropertyAssignment(host)) + && isBinaryExpression(host.parent.parent) + && getAssignmentDeclarationKind(host.parent.parent) === AssignmentDeclarationKind.Prototype + ) { // X.prototype = { /** @param {K} p */m() { } } <-- look for K on X's declaration const symbol = getSymbolOfDeclaration(host.parent.parent.left as BindableStaticNameExpression); if (symbol) { @@ -4838,9 +5859,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!decl) { return undefined; } - const initializer = isAssignmentDeclaration(decl) ? getAssignedExpandoInitializer(decl) : - hasOnlyExpressionInitializer(decl) ? getDeclaredExpandoInitializer(decl) : - undefined; + const initializer = isAssignmentDeclaration(decl) ? getAssignedExpandoInitializer(decl) + : hasOnlyExpressionInitializer(decl) ? getDeclaredExpandoInitializer(decl) + : undefined; return initializer || decl; } @@ -4852,10 +5873,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function getExpandoSymbol(symbol: Symbol): Symbol | undefined { const decl = symbol.valueDeclaration; - if (!decl || !isInJSFile(decl) || symbol.flags & SymbolFlags.TypeAlias || getExpandoInitializer(decl, /*isPrototypeAssignment*/ false)) { + if ( + !decl || !isInJSFile(decl) || symbol.flags & SymbolFlags.TypeAlias + || getExpandoInitializer(decl, /*isPrototypeAssignment*/ false) + ) { return undefined; } - const init = isVariableDeclaration(decl) ? getDeclaredExpandoInitializer(decl) : getAssignedExpandoInitializer(decl); + const init = isVariableDeclaration(decl) ? getDeclaredExpandoInitializer(decl) + : getAssignedExpandoInitializer(decl); if (init) { const initSymbol = getSymbolOfNode(init); if (initSymbol) { @@ -4864,21 +5889,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function resolveExternalModuleName(location: Node, moduleReferenceExpression: Expression, ignoreErrors?: boolean): Symbol | undefined { + function resolveExternalModuleName( + location: Node, + moduleReferenceExpression: Expression, + ignoreErrors?: boolean, + ): Symbol | undefined { const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic; - 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); + 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, + ); } - function resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage | undefined, isForAugmentation = false): Symbol | undefined { + function resolveExternalModuleNameWorker( + location: Node, + moduleReferenceExpression: Expression, + moduleNotFoundError: DiagnosticMessage | undefined, + isForAugmentation = false, + ): Symbol | undefined { return isStringLiteralLike(moduleReferenceExpression) - ? resolveExternalModule(location, moduleReferenceExpression.text, moduleNotFoundError, moduleReferenceExpression, isForAugmentation) + ? resolveExternalModule( + location, + moduleReferenceExpression.text, + moduleNotFoundError, + moduleReferenceExpression, + isForAugmentation, + ) : undefined; } - function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage | undefined, errorNode: Node, isForAugmentation = false): Symbol | undefined { + function resolveExternalModule( + location: Node, + moduleReference: string, + moduleNotFoundError: DiagnosticMessage | undefined, + errorNode: Node, + isForAugmentation = false, + ): Symbol | undefined { if (startsWith(moduleReference, "@types/")) { const diag = Diagnostics.Cannot_import_type_declaration_files_Consider_importing_0_instead_of_1; const withoutAtTypePrefix = removePrefix(moduleReference, "@types/"); @@ -4892,18 +5943,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const currentSourceFile = getSourceFileOfNode(location); const contextSpecifier = isStringLiteralLike(location) ? location - : findAncestor(location, isImportCall)?.arguments[0] || - findAncestor(location, isImportDeclaration)?.moduleSpecifier || - findAncestor(location, isExternalModuleImportEqualsDeclaration)?.moduleReference.expression || - findAncestor(location, isExportDeclaration)?.moduleSpecifier || - (isModuleDeclaration(location) ? location : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location ? location.parent : undefined)?.name || - (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal; - const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) ? getModeForUsageLocation(currentSourceFile, contextSpecifier) : currentSourceFile.impliedNodeFormat; + : findAncestor(location, isImportCall)?.arguments[0] + || findAncestor(location, isImportDeclaration)?.moduleSpecifier + || findAncestor(location, isExternalModuleImportEqualsDeclaration)?.moduleReference.expression + || findAncestor(location, isExportDeclaration)?.moduleSpecifier + || (isModuleDeclaration(location) ? location + : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location + ? location.parent : undefined)?.name + || (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal; + const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) + ? getModeForUsageLocation(currentSourceFile, contextSpecifier) : currentSourceFile.impliedNodeFormat; const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); const resolvedModule = getResolvedModule(currentSourceFile, moduleReference, mode); - const resolutionDiagnostic = resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule, currentSourceFile); + const resolutionDiagnostic = resolvedModule + && getResolutionDiagnostic(compilerOptions, resolvedModule, currentSourceFile); const sourceFile = resolvedModule - && (!resolutionDiagnostic || resolutionDiagnostic === Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set) + && (!resolutionDiagnostic + || resolutionDiagnostic === Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set) && host.getSourceFile(resolvedModule.resolvedFileName); if (sourceFile) { // If there's a resolutionDiagnostic we need to report it even if a sourceFile is found. @@ -4912,81 +5968,133 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (resolvedModule.resolvedUsingTsExtension && isDeclarationFileName(moduleReference)) { - const importOrExport = - findAncestor(location, isImportDeclaration)?.importClause || - findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)); + const importOrExport = findAncestor(location, isImportDeclaration)?.importClause + || findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)); if (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, - getSuggestedImportSource(Debug.checkDefined(tryExtractTSExtension(moduleReference)))); + Diagnostics + .A_declaration_file_cannot_be_imported_without_import_type_Did_you_mean_to_import_an_implementation_file_0_instead, + getSuggestedImportSource(Debug.checkDefined(tryExtractTSExtension(moduleReference))), + ); } } - else if (resolvedModule.resolvedUsingTsExtension && !shouldAllowImportingTsExtension(compilerOptions, currentSourceFile.fileName)) { - const importOrExport = - findAncestor(location, isImportDeclaration)?.importClause || - findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)); + 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))) { const tsExtension = Debug.checkDefined(tryExtractTSExtension(moduleReference)); - error(errorNode, Diagnostics.An_import_path_can_only_end_with_a_0_extension_when_allowImportingTsExtensions_is_enabled, tsExtension); + 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)) { - errorOnImplicitAnyModule(/*isError*/ false, errorNode, currentSourceFile, mode, resolvedModule, moduleReference); + if ( + resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension) + ) { + errorOnImplicitAnyModule( + /*isError*/ false, + errorNode, + currentSourceFile, + mode, + resolvedModule, + moduleReference, + ); } - if (moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext) { - const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS && !findAncestor(location, isImportCall)) || !!findAncestor(location, isImportEqualsDeclaration); - const overrideClauseHost = findAncestor(location, l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l)) as ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined; - const overrideClause = overrideClauseHost && isImportTypeNode(overrideClauseHost) ? overrideClauseHost.assertions?.assertClause : overrideClauseHost?.assertClause; + if ( + moduleResolutionKind === ModuleResolutionKind.Node16 + || moduleResolutionKind === ModuleResolutionKind.NodeNext + ) { + const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS + && !findAncestor(location, isImportCall)) + || !!findAncestor(location, isImportEqualsDeclaration); + const overrideClauseHost = findAncestor( + location, + l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l), + ) as ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined; + const overrideClause = overrideClauseHost && isImportTypeNode(overrideClauseHost) + ? overrideClauseHost.assertions?.assertClause : overrideClauseHost?.assertClause; // 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 && !getResolutionModeOverrideForClause(overrideClause)) { + if ( + isSyncImport && sourceFile.impliedNodeFormat === ModuleKind.ESNext + && !getResolutionModeOverrideForClause(overrideClause) + ) { if (findAncestor(location, isImportEqualsDeclaration)) { // ImportEquals in a ESM file resolving to another ESM file - error(errorNode, Diagnostics.Module_0_cannot_be_imported_using_this_construct_The_specifier_only_resolves_to_an_ES_module_which_cannot_be_imported_with_require_Use_an_ECMAScript_import_instead, moduleReference); + error( + errorNode, + Diagnostics + .Module_0_cannot_be_imported_using_this_construct_The_specifier_only_resolves_to_an_ES_module_which_cannot_be_imported_with_require_Use_an_ECMAScript_import_instead, + moduleReference, + ); } else { // CJS file resolving to an ESM file let diagnosticDetails; const ext = tryGetExtensionFromPath(currentSourceFile.fileName); - if (ext === Extension.Ts || ext === Extension.Js || ext === Extension.Tsx || ext === Extension.Jsx) { + if ( + ext === Extension.Ts || ext === Extension.Js || ext === Extension.Tsx + || ext === Extension.Jsx + ) { const scope = currentSourceFile.packageJsonScope; - const targetExt = ext === Extension.Ts ? Extension.Mts : ext === Extension.Js ? Extension.Mjs : undefined; + const targetExt = ext === Extension.Ts ? Extension.Mts + : ext === Extension.Js ? Extension.Mjs : undefined; if (scope && !scope.contents.packageJsonContent.type) { if (targetExt) { diagnosticDetails = chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_add_the_field_type_Colon_module_to_1, + Diagnostics + .To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_add_the_field_type_Colon_module_to_1, targetExt, - combinePaths(scope.packageDirectory, "package.json")); + combinePaths(scope.packageDirectory, "package.json"), + ); } else { diagnosticDetails = chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.To_convert_this_file_to_an_ECMAScript_module_add_the_field_type_Colon_module_to_0, - combinePaths(scope.packageDirectory, "package.json")); + Diagnostics + .To_convert_this_file_to_an_ECMAScript_module_add_the_field_type_Colon_module_to_0, + combinePaths(scope.packageDirectory, "package.json"), + ); } } else { if (targetExt) { diagnosticDetails = chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_create_a_local_package_json_file_with_type_Colon_module, - targetExt); + Diagnostics + .To_convert_this_file_to_an_ECMAScript_module_change_its_file_extension_to_0_or_create_a_local_package_json_file_with_type_Colon_module, + targetExt, + ); } else { diagnosticDetails = chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.To_convert_this_file_to_an_ECMAScript_module_create_a_local_package_json_file_with_type_Colon_module); + Diagnostics + .To_convert_this_file_to_an_ECMAScript_module_create_a_local_package_json_file_with_type_Colon_module, + ); } } } - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode), errorNode, chainDiagnosticMessages( - diagnosticDetails, - Diagnostics.The_current_file_is_a_CommonJS_module_whose_imports_will_produce_require_calls_however_the_referenced_file_is_an_ECMAScript_module_and_cannot_be_imported_with_require_Consider_writing_a_dynamic_import_0_call_instead, - moduleReference))); + diagnostics.add(createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorNode), + errorNode, + chainDiagnosticMessages( + diagnosticDetails, + Diagnostics + .The_current_file_is_a_CommonJS_module_whose_imports_will_produce_require_calls_however_the_referenced_file_is_an_ECMAScript_module_and_cannot_be_imported_with_require_Consider_writing_a_dynamic_import_0_call_instead, + moduleReference, + ), + )); } } } @@ -5007,7 +6115,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // module augmentation by the specific name requested ('a.foo'), we store the merged symbol // by the augmentation name ('a.foo'), because asking for *.foo should not give you exports // from a.foo. - const augmentation = patternAmbientModuleAugmentations && patternAmbientModuleAugmentations.get(moduleReference); + const augmentation = patternAmbientModuleAugmentations + && patternAmbientModuleAugmentations.get(moduleReference); if (augmentation) { return getMergedSymbol(augmentation); } @@ -5016,13 +6125,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // 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 ( + 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) { - const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; + const diag = Diagnostics + .Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; error(errorNode, diag, moduleReference, resolvedModule!.resolvedFileName); } else { - errorOnImplicitAnyModule(/*isError*/ noImplicitAny && !!moduleNotFoundError, errorNode, currentSourceFile, mode, resolvedModule!, moduleReference); + errorOnImplicitAnyModule( + /*isError*/ noImplicitAny && !!moduleNotFoundError, + errorNode, + currentSourceFile, + mode, + resolvedModule!, + moduleReference, + ); } // Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first. return undefined; @@ -5033,7 +6155,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (resolvedModule) { const redirect = host.getProjectReferenceRedirect(resolvedModule.resolvedFileName); if (redirect) { - error(errorNode, Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, redirect, resolvedModule.resolvedFileName); + error( + errorNode, + Diagnostics.Output_file_0_has_not_been_built_from_source_file_1, + redirect, + resolvedModule.resolvedFileName, + ); return undefined; } } @@ -5042,25 +6169,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); } else { - const isExtensionlessRelativePathImport = pathIsRelative(moduleReference) && !hasExtension(moduleReference); - const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 || - moduleResolutionKind === ModuleResolutionKind.NodeNext; - if (!getResolveJsonModule(compilerOptions) && - fileExtensionIs(moduleReference, Extension.Json) && - moduleResolutionKind !== ModuleResolutionKind.Classic && - hasJsonModuleEmitEnabled(compilerOptions)) { - error(errorNode, Diagnostics.Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension, moduleReference); + const isExtensionlessRelativePathImport = pathIsRelative(moduleReference) + && !hasExtension(moduleReference); + const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 + || moduleResolutionKind === ModuleResolutionKind.NodeNext; + if ( + !getResolveJsonModule(compilerOptions) + && fileExtensionIs(moduleReference, Extension.Json) + && moduleResolutionKind !== ModuleResolutionKind.Classic + && hasJsonModuleEmitEnabled(compilerOptions) + ) { + error( + errorNode, + Diagnostics + .Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension, + moduleReference, + ); } else if (mode === ModuleKind.ESNext && resolutionIsNode16OrNext && isExtensionlessRelativePathImport) { - const absoluteRef = getNormalizedAbsolutePath(moduleReference, getDirectoryPath(currentSourceFile.path)); - const suggestedExt = suggestedExtensions.find(([actualExt, _importExt]) => host.fileExists(absoluteRef + actualExt))?.[1]; + const absoluteRef = getNormalizedAbsolutePath( + moduleReference, + getDirectoryPath(currentSourceFile.path), + ); + const suggestedExt = suggestedExtensions.find(([actualExt, _importExt]) => + host.fileExists(absoluteRef + actualExt) + )?.[1]; if (suggestedExt) { - error(errorNode, - Diagnostics.Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Did_you_mean_0, - moduleReference + suggestedExt); + error( + errorNode, + Diagnostics + .Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Did_you_mean_0, + moduleReference + suggestedExt, + ); } else { - error(errorNode, Diagnostics.Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Consider_adding_an_extension_to_the_import_path); + error( + errorNode, + Diagnostics + .Relative_import_paths_need_explicit_file_extensions_in_EcmaScript_imports_when_moduleResolution_is_node16_or_nodenext_Consider_adding_an_extension_to_the_import_path, + ); } } else { @@ -5077,34 +6224,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @see https://github.com/microsoft/TypeScript/issues/42151 */ if (emitModuleKindIsNonNodeESM(moduleKind) || mode === ModuleKind.ESNext) { - const preferTs = isDeclarationFileName(moduleReference) && shouldAllowImportingTsExtension(compilerOptions); - const ext = - tsExtension === Extension.Mts || tsExtension === Extension.Dmts ? preferTs ? ".mts" : ".mjs" : - tsExtension === Extension.Cts || tsExtension === Extension.Dmts ? preferTs ? ".cts" : ".cjs" : - preferTs ? ".ts" : ".js"; + const preferTs = isDeclarationFileName(moduleReference) + && shouldAllowImportingTsExtension(compilerOptions); + const ext = tsExtension === Extension.Mts || tsExtension === Extension.Dmts ? preferTs ? ".mts" : ".mjs" + : tsExtension === Extension.Cts || tsExtension === Extension.Dmts ? preferTs ? ".cts" : ".cjs" + : preferTs ? ".ts" : ".js"; return importSourceWithoutExtension + ext; } return importSourceWithoutExtension; } } - function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, sourceFile: SourceFile, mode: ResolutionMode, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void { + function errorOnImplicitAnyModule( + isError: boolean, + errorNode: Node, + sourceFile: SourceFile, + mode: ResolutionMode, + { packageId, resolvedFileName }: ResolvedModuleFull, + moduleReference: string, + ): void { let errorInfo: DiagnosticMessageChain | undefined; if (!isExternalModuleNameRelative(moduleReference) && packageId) { errorInfo = createModuleNotFoundChain(sourceFile, host, moduleReference, mode, packageId.name); } - errorOrSuggestion(isError, errorNode, chainDiagnosticMessages( - errorInfo, - Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type, - moduleReference, - resolvedFileName)); + errorOrSuggestion( + isError, + errorNode, + chainDiagnosticMessages( + errorInfo, + Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type, + moduleReference, + resolvedFileName, + ), + ); } function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol; - function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined; - function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined { + function resolveExternalModuleSymbol( + moduleSymbol: Symbol | undefined, + dontResolveAlias?: boolean, + ): Symbol | undefined; + function resolveExternalModuleSymbol( + moduleSymbol: Symbol | undefined, + dontResolveAlias?: boolean, + ): Symbol | undefined { if (moduleSymbol?.exports) { - const exportEquals = resolveSymbol(moduleSymbol.exports.get(InternalSymbolName.ExportEquals), dontResolveAlias); + const exportEquals = resolveSymbol( + moduleSymbol.exports.get(InternalSymbolName.ExportEquals), + dontResolveAlias, + ); const exported = getCommonJsExportEquals(getMergedSymbol(exportEquals), getMergedSymbol(moduleSymbol)); return getMergedSymbol(exported) || moduleSymbol; } @@ -5112,7 +6280,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getCommonJsExportEquals(exported: Symbol | undefined, moduleSymbol: Symbol): Symbol | undefined { - if (!exported || exported === unknownSymbol || exported === moduleSymbol || moduleSymbol.exports!.size === 1 || exported.flags & SymbolFlags.Alias) { + if ( + !exported || exported === unknownSymbol || exported === moduleSymbol || moduleSymbol.exports!.size === 1 + || exported.flags & SymbolFlags.Alias + ) { return exported; } const links = getSymbolLinks(exported); @@ -5141,26 +6312,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export =' // references a symbol that is at least declared as a module or a variable. The target of the 'export =' may // combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable). - function resolveESModuleSymbol(moduleSymbol: Symbol | undefined, referencingLocation: Node, dontResolveAlias: boolean, suppressInteropError: boolean): Symbol | undefined { + function resolveESModuleSymbol( + moduleSymbol: Symbol | undefined, + referencingLocation: Node, + dontResolveAlias: boolean, + suppressInteropError: boolean, + ): Symbol | undefined { const symbol = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias); if (!dontResolveAlias && symbol) { - if (!suppressInteropError && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable)) && !getDeclarationOfKind(symbol, SyntaxKind.SourceFile)) { + if ( + !suppressInteropError && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable)) + && !getDeclarationOfKind(symbol, SyntaxKind.SourceFile) + ) { const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" : "esModuleInterop"; - error(referencingLocation, Diagnostics.This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, compilerOptionName); + error( + referencingLocation, + Diagnostics + .This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, + compilerOptionName, + ); return symbol; } const referenceParent = referencingLocation.parent; if ( - (isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent)) || - isImportCall(referenceParent) + (isImportDeclaration(referenceParent) && getNamespaceDeclarationNode(referenceParent)) + || isImportCall(referenceParent) ) { - const reference = isImportCall(referenceParent) ? referenceParent.arguments[0] : referenceParent.moduleSpecifier; + const reference = isImportCall(referenceParent) ? referenceParent.arguments[0] + : referenceParent.moduleSpecifier; const type = getTypeOfSymbol(symbol); const defaultOnlyType = getTypeWithSyntheticDefaultOnly(type, symbol, moduleSymbol!, reference); if (defaultOnlyType) { @@ -5168,16 +6353,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const targetFile = moduleSymbol?.declarations?.find(isSourceFile); - const isEsmCjsRef = targetFile && isESMFormatImportImportingCommonjsFormatFile(getUsageModeForExpression(reference), targetFile.impliedNodeFormat); + const isEsmCjsRef = targetFile + && isESMFormatImportImportingCommonjsFormatFile( + getUsageModeForExpression(reference), + targetFile.impliedNodeFormat, + ); if (getESModuleInterop(compilerOptions) || isEsmCjsRef) { let sigs = getSignaturesOfStructuredType(type, SignatureKind.Call); if (!sigs || !sigs.length) { sigs = getSignaturesOfStructuredType(type, SignatureKind.Construct); } if ( - (sigs && sigs.length) || - getPropertyOfType(type, InternalSymbolName.Default, /*skipObjectFunctionPropertyAugment*/ true) || - isEsmCjsRef + (sigs && sigs.length) + || getPropertyOfType( + type, + InternalSymbolName.Default, + /*skipObjectFunctionPropertyAugment*/ true, + ) + || isEsmCjsRef ) { const moduleType = type.flags & TypeFlags.StructuredType ? getTypeWithSyntheticDefaultImportType(type, symbol, moduleSymbol!, reference) @@ -5204,7 +6397,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol.members) result.members = new Map(symbol.members); if (symbol.exports) result.exports = new Map(symbol.exports); const resolvedModuleType = resolveStructuredTypeMembers(moduleType as StructuredType); // Should already be resolved from the signature checks above - result.links.type = createAnonymousType(result, resolvedModuleType.members, emptyArray, emptyArray, resolvedModuleType.indexInfos); + result.links.type = createAnonymousType( + result, + resolvedModuleType.members, + emptyArray, + emptyArray, + resolvedModuleType.indexInfos, + ); return result; } @@ -5269,17 +6468,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function shouldTreatPropertiesOfExternalModuleAsExports(resolvedExternalModuleType: Type) { - return !(resolvedExternalModuleType.flags & TypeFlags.Primitive || - getObjectFlags(resolvedExternalModuleType) & ObjectFlags.Class || - // `isArrayOrTupleLikeType` is too expensive to use in this auto-imports hot path - isArrayType(resolvedExternalModuleType) || - isTupleType(resolvedExternalModuleType)); + return !(resolvedExternalModuleType.flags & TypeFlags.Primitive + || getObjectFlags(resolvedExternalModuleType) & ObjectFlags.Class + // `isArrayOrTupleLikeType` is too expensive to use in this auto-imports hot path + || isArrayType(resolvedExternalModuleType) + || isTupleType(resolvedExternalModuleType)); } function getExportsOfSymbol(symbol: Symbol): SymbolTable { - return symbol.flags & SymbolFlags.LateBindingContainer ? getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKind.resolvedExports) : - symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) : - symbol.exports || emptySymbols; + return symbol.flags & SymbolFlags.LateBindingContainer + ? getResolvedMembersOrExportsOfSymbol(symbol, MembersOrExportsResolutionKind.resolvedExports) + : symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) + : symbol.exports || emptySymbols; } function getExportsOfModule(moduleSymbol: Symbol): SymbolTable { @@ -5303,7 +6503,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Extends one symbol table with another while collecting information on name collisions for error message generation into the `lookupTable` argument * Not passing `lookupTable` and `exportNode` disables this collection, and just extends the tables */ - function extendExportSymbols(target: SymbolTable, source: SymbolTable | undefined, lookupTable?: ExportCollisionTrackerTable, exportNode?: ExportDeclaration) { + function extendExportSymbols( + target: SymbolTable, + source: SymbolTable | undefined, + lookupTable?: ExportCollisionTrackerTable, + exportNode?: ExportDeclaration, + ) { if (!source) return; source.forEach((sourceSymbol, id) => { if (id === InternalSymbolName.Default) return; @@ -5313,11 +6518,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target.set(id, sourceSymbol); if (lookupTable && exportNode) { lookupTable.set(id, { - specifierText: getTextOfNode(exportNode.moduleSpecifier!) + specifierText: getTextOfNode(exportNode.moduleSpecifier!), }); } } - else if (lookupTable && exportNode && targetSymbol && resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol)) { + else if ( + lookupTable && exportNode && targetSymbol && resolveSymbol(targetSymbol) !== resolveSymbol(sourceSymbol) + ) { const collisionTracker = lookupTable.get(id)!; if (!collisionTracker.exportsWithDuplicate) { collisionTracker.exportsWithDuplicate = [exportNode]; @@ -5331,7 +6538,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getExportsOfModuleWorker(moduleSymbol: Symbol) { const visitedSymbols: Symbol[] = []; - let typeOnlyExportStarMap: Map<__String, ExportDeclaration & { readonly isTypeOnly: true, readonly moduleSpecifier: Expression }> | undefined; + let typeOnlyExportStarMap: + | Map<__String, ExportDeclaration & { readonly isTypeOnly: true; readonly moduleSpecifier: Expression; }> + | undefined; const nonTypeOnlyNames = new Set<__String>(); // A module defined by an 'export=' consists of one export that needs to be resolved @@ -5349,7 +6558,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example, // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error. - function visit(symbol: Symbol | undefined, exportStar?: ExportDeclaration, isTypeOnly?: boolean): SymbolTable | undefined { + function visit( + symbol: Symbol | undefined, + exportStar?: ExportDeclaration, + isTypeOnly?: boolean, + ): SymbolTable | undefined { if (!isTypeOnly && symbol?.exports) { // Add non-type-only names before checking if we've visited this module, // because we might have visited it via an 'export type *', and visiting @@ -5368,13 +6581,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const lookupTable: ExportCollisionTrackerTable = new Map(); if (exportStars.declarations) { for (const node of exportStars.declarations) { - const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); - const exportedSymbols = visit(resolvedModule, node as ExportDeclaration, isTypeOnly || (node as ExportDeclaration).isTypeOnly); + const resolvedModule = resolveExternalModuleName( + node, + (node as ExportDeclaration).moduleSpecifier!, + ); + const exportedSymbols = visit( + resolvedModule, + node as ExportDeclaration, + isTypeOnly || (node as ExportDeclaration).isTypeOnly, + ); extendExportSymbols( nestedSymbols, exportedSymbols, lookupTable, - node as ExportDeclaration + node as ExportDeclaration, ); } } @@ -5386,9 +6606,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const node of exportsWithDuplicate) { diagnostics.add(createDiagnosticForNode( node, - Diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, + Diagnostics + .Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, lookupTable.get(id)!.specifierText, - unescapeLeadingUnderscores(id) + unescapeLeadingUnderscores(id), )); } }); @@ -5396,9 +6617,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (exportStar?.isTypeOnly) { typeOnlyExportStarMap ??= new Map(); - symbols.forEach((_, escapedName) => typeOnlyExportStarMap!.set( - escapedName, - exportStar as ExportDeclaration & { readonly isTypeOnly: true, readonly moduleSpecifier: Expression })); + symbols.forEach((_, escapedName) => + typeOnlyExportStarMap!.set( + escapedName, + exportStar as ExportDeclaration & { + readonly isTypeOnly: true; + readonly moduleSpecifier: Expression; + }, + ) + ); } return symbols; } @@ -5439,7 +6666,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Try to make an import using an import already in the enclosing file, if possible for (const importRef of containingFile.imports) { if (nodeIsSynthesized(importRef)) continue; // Synthetic names can't be resolved by `resolveExternalModuleName` - they'll cause a debug assert if they error - const resolvedModule = resolveExternalModuleName(enclosingDeclaration, importRef, /*ignoreErrors*/ true); + const resolvedModule = resolveExternalModuleName( + enclosingDeclaration, + importRef, + /*ignoreErrors*/ true, + ); if (!resolvedModule) continue; const ref = getAliasForSymbolInContainer(resolvedModule, symbol); if (!ref) continue; @@ -5469,50 +6700,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Attempts to find the symbol corresponding to the container a symbol is in - usually this * is just its' `.parent`, but for locals, this value is `undefined` */ - function getContainersOfSymbol(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): Symbol[] | undefined { + function getContainersOfSymbol( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + ): Symbol[] | undefined { const container = getParentOfSymbol(symbol); // Type parameters end up in the `members` lists but are not externally visible if (container && !(symbol.flags & SymbolFlags.TypeParameter)) { - const additionalContainers = mapDefined(container.declarations, fileSymbolIfFileSymbolExportEqualsContainer); - const reexportContainers = enclosingDeclaration && getAlternativeContainingModules(symbol, enclosingDeclaration); + const additionalContainers = mapDefined( + container.declarations, + fileSymbolIfFileSymbolExportEqualsContainer, + ); + const reexportContainers = enclosingDeclaration + && getAlternativeContainingModules(symbol, enclosingDeclaration); const objectLiteralContainer = getVariableDeclarationOfObjectLiteral(container, meaning); if ( - enclosingDeclaration && - container.flags & getQualifiedLeftMeaning(meaning) && - getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*useOnlyExternalAliasing*/ false) + enclosingDeclaration + && container.flags & getQualifiedLeftMeaning(meaning) + && getAccessibleSymbolChain( + container, + enclosingDeclaration, + SymbolFlags.Namespace, + /*useOnlyExternalAliasing*/ false, + ) ) { - return append(concatenate(concatenate([container], additionalContainers), reexportContainers), objectLiteralContainer); // This order expresses a preference for the real container if it is in scope + return append( + concatenate(concatenate([container], additionalContainers), reexportContainers), + objectLiteralContainer, + ); // This order expresses a preference for the real container if it is in scope } // we potentially have a symbol which is a member of the instance side of something - look for a variable in scope with the container's type // which may be acting like a namespace (eg, `Symbol` acts like a namespace when looking up `Symbol.toStringTag`) const firstVariableMatch = !(container.flags & getQualifiedLeftMeaning(meaning)) - && container.flags & SymbolFlags.Type - && getDeclaredTypeOfSymbol(container).flags & TypeFlags.Object - && meaning === SymbolFlags.Value - ? forEachSymbolTableInScope(enclosingDeclaration, t => { - return forEachEntry(t, s => { - if (s.flags & getQualifiedLeftMeaning(meaning) && getTypeOfSymbol(s) === getDeclaredTypeOfSymbol(container)) { - return s; - } - }); - }) : undefined; - let res = firstVariableMatch ? [firstVariableMatch, ...additionalContainers, container] : [...additionalContainers, container]; + && container.flags & SymbolFlags.Type + && getDeclaredTypeOfSymbol(container).flags & TypeFlags.Object + && meaning === SymbolFlags.Value + ? forEachSymbolTableInScope(enclosingDeclaration, t => { + return forEachEntry(t, s => { + if ( + s.flags & getQualifiedLeftMeaning(meaning) + && getTypeOfSymbol(s) === getDeclaredTypeOfSymbol(container) + ) { + return s; + } + }); + }) : undefined; + let res = firstVariableMatch ? [firstVariableMatch, ...additionalContainers, container] + : [...additionalContainers, container]; res = append(res, objectLiteralContainer); res = addRange(res, reexportContainers); return res; } const candidates = mapDefined(symbol.declarations, d => { - if (!isAmbientModule(d) && d.parent){ + if (!isAmbientModule(d) && d.parent) { // direct children of a module if (hasNonGlobalAugmentationExternalModuleSymbol(d.parent)) { return getSymbolOfDeclaration(d.parent as Declaration); } // export ='d member of an ambient module - if (isModuleBlock(d.parent) && d.parent.parent && resolveExternalModuleSymbol(getSymbolOfDeclaration(d.parent.parent)) === symbol) { + if ( + isModuleBlock(d.parent) && d.parent.parent + && resolveExternalModuleSymbol(getSymbolOfDeclaration(d.parent.parent)) === symbol + ) { return getSymbolOfDeclaration(d.parent.parent); } } - if (isClassExpression(d) && isBinaryExpression(d.parent) && d.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAccessExpression(d.parent.left) && isEntityNameExpression(d.parent.left.expression)) { + if ( + isClassExpression(d) && isBinaryExpression(d.parent) + && d.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAccessExpression(d.parent.left) + && isEntityNameExpression(d.parent.left.expression) + ) { if (isModuleExportsAccessExpression(d.parent.left) || isExportsIdentifier(d.parent.left.expression)) { return getSymbolOfDeclaration(getSourceFileOfNode(d)); } @@ -5523,7 +6781,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!length(candidates)) { return undefined; } - return mapDefined(candidates, candidate => getAliasForSymbolInContainer(candidate, symbol) ? candidate : undefined); + return mapDefined( + candidates, + candidate => getAliasForSymbolInContainer(candidate, symbol) ? candidate : undefined, + ); function fileSymbolIfFileSymbolExportEqualsContainer(d: Declaration) { return container && getFileSymbolIfFileSymbolExportEqualsContainer(d, container); @@ -5536,7 +6797,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // we'd like to make that connection here - potentially causing us to paint the declaration's visibility, and therefore the literal. const firstDecl: Node | false = !!length(symbol.declarations) && first(symbol.declarations!); if (meaning & SymbolFlags.Value && firstDecl && firstDecl.parent && isVariableDeclaration(firstDecl.parent)) { - if (isObjectLiteralExpression(firstDecl) && firstDecl === firstDecl.parent.initializer || isTypeLiteralNode(firstDecl) && firstDecl === firstDecl.parent.type) { + if ( + isObjectLiteralExpression(firstDecl) && firstDecl === firstDecl.parent.initializer + || isTypeLiteralNode(firstDecl) && firstDecl === firstDecl.parent.type + ) { return getSymbolOfDeclaration(firstDecl.parent); } } @@ -5575,7 +6839,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Checks if two symbols, through aliasing and/or merging, refer to the same thing */ function getSymbolIfSameReference(s1: Symbol, s2: Symbol) { - if (getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) === getMergedSymbol(resolveSymbol(getMergedSymbol(s2)))) { + if ( + getMergedSymbol(resolveSymbol(getMergedSymbol(s1))) === getMergedSymbol(resolveSymbol(getMergedSymbol(s2))) + ) { return s1; } } @@ -5583,13 +6849,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol; function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined; function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined { - return getMergedSymbol(symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0 && symbol.exportSymbol || symbol); + return getMergedSymbol( + symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0 && symbol.exportSymbol || symbol, + ); } function symbolIsValue(symbol: Symbol, includeTypeOnlyMembers?: boolean): boolean { return !!( - symbol.flags & SymbolFlags.Value || - symbol.flags & SymbolFlags.Alias && getSymbolFlags(symbol, !includeTypeOnlyMembers) & SymbolFlags.Value); + symbol.flags & SymbolFlags.Value + || symbol.flags & SymbolFlags.Alias && getSymbolFlags(symbol, !includeTypeOnlyMembers) & SymbolFlags.Value + ); } function findConstructorDeclaration(node: ClassLikeDeclaration): ConstructorDeclaration | undefined { @@ -5619,10 +6888,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return new Type(checker, flags); } - function createIntrinsicType(kind: TypeFlags, intrinsicName: string, objectFlags = ObjectFlags.None): IntrinsicType { + function createIntrinsicType( + kind: TypeFlags, + intrinsicName: string, + objectFlags = ObjectFlags.None, + ): IntrinsicType { const type = createType(kind) as IntrinsicType; type.intrinsicName = intrinsicName; - type.objectFlags = objectFlags | ObjectFlags.CouldContainTypeVariablesComputed | ObjectFlags.IsGenericTypeComputed | ObjectFlags.IsUnknownLikeUnionComputed | ObjectFlags.IsNeverIntersectionComputed; + type.objectFlags = objectFlags | ObjectFlags.CouldContainTypeVariablesComputed + | ObjectFlags.IsGenericTypeComputed | ObjectFlags.IsUnknownLikeUnionComputed + | ObjectFlags.IsNeverIntersectionComputed; return type; } @@ -5650,11 +6925,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // with at least two underscores. The @ character indicates that the name is denoted by a well known ES // Symbol instance and the # character indicates that the name is a PrivateIdentifier. function isReservedMemberName(name: __String) { - return (name as string).charCodeAt(0) === CharacterCodes._ && - (name as string).charCodeAt(1) === CharacterCodes._ && - (name as string).charCodeAt(2) !== CharacterCodes._ && - (name as string).charCodeAt(2) !== CharacterCodes.at && - (name as string).charCodeAt(2) !== CharacterCodes.hash; + return (name as string).charCodeAt(0) === CharacterCodes._ + && (name as string).charCodeAt(1) === CharacterCodes._ + && (name as string).charCodeAt(2) !== CharacterCodes._ + && (name as string).charCodeAt(2) !== CharacterCodes.at + && (name as string).charCodeAt(2) !== CharacterCodes.hash; } function getNamedMembers(members: SymbolTable): Symbol[] { @@ -5677,7 +6952,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return index ? concatenate(result, [index]) : result; } - function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], indexInfos: readonly IndexInfo[]): ResolvedType { + function setStructuredTypeMembers( + type: StructuredType, + members: SymbolTable, + callSignatures: readonly Signature[], + constructSignatures: readonly Signature[], + indexInfos: readonly IndexInfo[], + ): ResolvedType { const resolved = type as ResolvedType; resolved.members = members; resolved.properties = emptyArray; @@ -5689,33 +6970,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return resolved; } - function createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: readonly Signature[], constructSignatures: readonly Signature[], indexInfos: readonly IndexInfo[]): ResolvedType { - return setStructuredTypeMembers(createObjectType(ObjectFlags.Anonymous, symbol), - members, callSignatures, constructSignatures, indexInfos); + function createAnonymousType( + symbol: Symbol | undefined, + members: SymbolTable, + callSignatures: readonly Signature[], + constructSignatures: readonly Signature[], + indexInfos: readonly IndexInfo[], + ): ResolvedType { + return setStructuredTypeMembers( + createObjectType(ObjectFlags.Anonymous, symbol), + members, + callSignatures, + constructSignatures, + indexInfos, + ); } function getResolvedTypeWithoutAbstractConstructSignatures(type: ResolvedType) { if (type.constructSignatures.length === 0) return type; if (type.objectTypeWithoutAbstractConstructSignatures) return type.objectTypeWithoutAbstractConstructSignatures; - const constructSignatures = filter(type.constructSignatures, signature => !(signature.flags & SignatureFlags.Abstract)); + const constructSignatures = filter( + type.constructSignatures, + signature => !(signature.flags & SignatureFlags.Abstract), + ); if (type.constructSignatures === constructSignatures) return type; const typeCopy = createAnonymousType( type.symbol, type.members, type.callSignatures, some(constructSignatures) ? constructSignatures : emptyArray, - type.indexInfos); + type.indexInfos, + ); type.objectTypeWithoutAbstractConstructSignatures = typeCopy; typeCopy.objectTypeWithoutAbstractConstructSignatures = typeCopy; return typeCopy; } - function forEachSymbolTableInScope(enclosingDeclaration: Node | undefined, callback: (symbolTable: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean, scopeNode?: Node) => T): T { + function forEachSymbolTableInScope( + enclosingDeclaration: Node | undefined, + callback: ( + symbolTable: SymbolTable, + ignoreQualification?: boolean, + isLocalNameLookup?: boolean, + scopeNode?: Node, + ) => T, + ): T { let result: T; for (let location = enclosingDeclaration; location; location = location.parent) { // Locals of a source file are not in scope (because they get merged into the global symbol table) if (canHaveLocals(location) && location.locals && !isGlobalSourceFile(location)) { - if (result = callback(location.locals, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) { + if ( + result = callback( + location.locals, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ true, + location, + ) + ) { return result; } } @@ -5730,7 +7041,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // `sym` may not have exports if this module declaration is backed by the symbol for a `const` that's being rewritten // into a namespace - in such cases, it's best to just let the namespace appear empty (the const members couldn't have referred // to one another anyway) - if (result = callback(sym?.exports || emptySymbols, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ true, location)) { + if ( + result = callback( + sym?.exports || emptySymbols, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ true, + location, + ) + ) { return result; } break; @@ -5746,12 +7064,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // trigger resolving late-bound names, which we may already be in the process of doing while we're here! let table: Map<__String, Symbol> | undefined; // TODO: Should this filtered table be cached in some way? - (getSymbolOfDeclaration(location as ClassLikeDeclaration | InterfaceDeclaration).members || emptySymbols).forEach((memberSymbol, key) => { - if (memberSymbol.flags & (SymbolFlags.Type & ~SymbolFlags.Assignment)) { - (table || (table = createSymbolTable())).set(key, memberSymbol); - } - }); - if (table && (result = callback(table, /*ignoreQualification*/ undefined, /*isLocalNameLookup*/ false, location))) { + (getSymbolOfDeclaration(location as ClassLikeDeclaration | InterfaceDeclaration).members + || emptySymbols).forEach((memberSymbol, key) => { + if (memberSymbol.flags & (SymbolFlags.Type & ~SymbolFlags.Assignment)) { + (table || (table = createSymbolTable())).set(key, memberSymbol); + } + }); + if ( + table + && (result = callback( + table, + /*ignoreQualification*/ undefined, + /*isLocalNameLookup*/ false, + location, + )) + ) { return result; } break; @@ -5766,7 +7093,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return rightMeaning === SymbolFlags.Value ? SymbolFlags.Value : SymbolFlags.Namespace; } - function getAccessibleSymbolChain(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean, visitedSymbolTablesMap = new Map()): Symbol[] | undefined { + function getAccessibleSymbolChain( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + useOnlyExternalAliasing: boolean, + visitedSymbolTablesMap = new Map(), + ): Symbol[] | undefined { if (!(symbol && !isPropertyOrMethodDeclarationSymbol(symbol))) { return undefined; } @@ -5774,7 +7107,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const cache = (links.accessibleChainCache ||= new Map()); // Go from enclosingDeclaration to the first scope we check, so the cache is keyed off the scope and thus shared more const firstRelevantLocation = forEachSymbolTableInScope(enclosingDeclaration, (_, __, ___, node) => node); - const key = `${useOnlyExternalAliasing ? 0 : 1}|${firstRelevantLocation && getNodeId(firstRelevantLocation)}|${meaning}`; + const key = `${useOnlyExternalAliasing ? 0 : 1}|${ + firstRelevantLocation && getNodeId(firstRelevantLocation) + }|${meaning}`; if (cache.has(key)) { return cache.get(key); } @@ -5791,7 +7126,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already) */ - function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean, isLocalNameLookup?: boolean): Symbol[] | undefined { + function getAccessibleSymbolChainFromSymbolTable( + symbols: SymbolTable, + ignoreQualification?: boolean, + isLocalNameLookup?: boolean, + ): Symbol[] | undefined { if (!pushIfUnique(visitedSymbolTables!, symbols)) { return undefined; } @@ -5803,59 +7142,95 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) { // If the symbol is equivalent and doesn't need further qualification, this symbol is accessible - return !needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning) || + return !needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning) // If symbol needs qualification, make sure that parent is accessible, if it is then this symbol is accessible too - !!getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing, visitedSymbolTablesMap); + || !!getAccessibleSymbolChain( + symbolFromSymbolTable.parent, + enclosingDeclaration, + getQualifiedLeftMeaning(meaning), + useOnlyExternalAliasing, + visitedSymbolTablesMap, + ); } - function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol, ignoreQualification?: boolean) { - return (symbol === (resolvedAliasSymbol || symbolFromSymbolTable) || getMergedSymbol(symbol) === getMergedSymbol(resolvedAliasSymbol || symbolFromSymbolTable)) && + function isAccessible( + symbolFromSymbolTable: Symbol, + resolvedAliasSymbol?: Symbol, + ignoreQualification?: boolean, + ) { + return (symbol === (resolvedAliasSymbol || symbolFromSymbolTable) + || getMergedSymbol(symbol) === getMergedSymbol(resolvedAliasSymbol || symbolFromSymbolTable)) // if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table) // and if symbolFromSymbolTable or alias resolution matches the symbol, // check the symbol can be qualified, it is only then this symbol is accessible - !some(symbolFromSymbolTable.declarations, hasNonGlobalAugmentationExternalModuleSymbol) && - (ignoreQualification || canQualifySymbol(getMergedSymbol(symbolFromSymbolTable), meaning)); + && !some(symbolFromSymbolTable.declarations, hasNonGlobalAugmentationExternalModuleSymbol) + && (ignoreQualification || canQualifySymbol(getMergedSymbol(symbolFromSymbolTable), meaning)); } - function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined, isLocalNameLookup: boolean | undefined): Symbol[] | undefined { + function trySymbolTable( + symbols: SymbolTable, + ignoreQualification: boolean | undefined, + isLocalNameLookup: boolean | undefined, + ): Symbol[] | undefined { // If symbol is directly available by its name in the symbol table - if (isAccessible(symbols.get(symbol!.escapedName)!, /*resolvedAliasSymbol*/ undefined, ignoreQualification)) { + if ( + isAccessible(symbols.get(symbol!.escapedName)!, /*resolvedAliasSymbol*/ undefined, ignoreQualification) + ) { return [symbol!]; } // Check if symbol is any of the aliases in scope const result = forEachEntry(symbols, symbolFromSymbolTable => { - if (symbolFromSymbolTable.flags & SymbolFlags.Alias + if ( + symbolFromSymbolTable.flags & SymbolFlags.Alias && symbolFromSymbolTable.escapedName !== InternalSymbolName.ExportEquals && symbolFromSymbolTable.escapedName !== InternalSymbolName.Default - && !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration && isExternalModule(getSourceFileOfNode(enclosingDeclaration))) + && !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration + && isExternalModule(getSourceFileOfNode(enclosingDeclaration))) // If `!useOnlyExternalAliasing`, we can use any type of alias to get the name - && (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) + && (!useOnlyExternalAliasing + || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration)) // If we're looking up a local name to reference directly, omit namespace reexports, otherwise when we're trawling through an export list to make a dotted name, we can keep it - && (isLocalNameLookup ? !some(symbolFromSymbolTable.declarations, isNamespaceReexportDeclaration) : true) + && (isLocalNameLookup ? !some(symbolFromSymbolTable.declarations, isNamespaceReexportDeclaration) + : true) // While exports are generally considered to be in scope, export-specifier declared symbols are _not_ // See similar comment in `resolveName` for details && (ignoreQualification || !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) ) { - const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable); - const candidate = getCandidateListForSymbol(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification); + const candidate = getCandidateListForSymbol( + symbolFromSymbolTable, + resolvedImportedSymbol, + ignoreQualification, + ); if (candidate) { return candidate; } } if (symbolFromSymbolTable.escapedName === symbol!.escapedName && symbolFromSymbolTable.exportSymbol) { - if (isAccessible(getMergedSymbol(symbolFromSymbolTable.exportSymbol), /*resolvedAliasSymbol*/ undefined, ignoreQualification)) { + if ( + isAccessible( + getMergedSymbol(symbolFromSymbolTable.exportSymbol), + /*resolvedAliasSymbol*/ undefined, + ignoreQualification, + ) + ) { return [symbol!]; } } }); // If there's no result and we're looking at the global symbol table, treat `globalThis` like an alias and try to lookup thru that - return result || (symbols === globals ? getCandidateListForSymbol(globalThisSymbol, globalThisSymbol, ignoreQualification) : undefined); + return result + || (symbols === globals + ? getCandidateListForSymbol(globalThisSymbol, globalThisSymbol, ignoreQualification) : undefined); } - function getCandidateListForSymbol(symbolFromSymbolTable: Symbol, resolvedImportedSymbol: Symbol, ignoreQualification: boolean | undefined) { + function getCandidateListForSymbol( + symbolFromSymbolTable: Symbol, + resolvedImportedSymbol: Symbol, + ignoreQualification: boolean | undefined, + ) { if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification)) { return [symbolFromSymbolTable]; } @@ -5863,8 +7238,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain // but only if the symbolFromSymbolTable can be qualified const candidateTable = getExportsOfSymbol(resolvedImportedSymbol); - const accessibleSymbolsFromExports = candidateTable && getAccessibleSymbolChainFromSymbolTable(candidateTable, /*ignoreQualification*/ true); - if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) { + const accessibleSymbolsFromExports = candidateTable + && getAccessibleSymbolChainFromSymbolTable(candidateTable, /*ignoreQualification*/ true); + if ( + accessibleSymbolsFromExports + && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning)) + ) { return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports); } } @@ -5886,7 +7265,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Qualify if the symbol from symbol table has same meaning as expected - const shouldResolveAlias = (symbolFromSymbolTable.flags & SymbolFlags.Alias && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)); + const shouldResolveAlias = symbolFromSymbolTable.flags & SymbolFlags.Alias + && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier); symbolFromSymbolTable = shouldResolveAlias ? resolveAlias(symbolFromSymbolTable) : symbolFromSymbolTable; const flags = shouldResolveAlias ? getSymbolFlags(symbolFromSymbolTable) : symbolFromSymbolTable.flags; if (flags & meaning) { @@ -5920,31 +7300,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node | undefined): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ true); + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + SymbolFlags.Type, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ true, + ); return access.accessibility === SymbolAccessibility.Accessible; } function isValueSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node | undefined): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, SymbolFlags.Value, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ true); + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + SymbolFlags.Value, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ true, + ); return access.accessibility === SymbolAccessibility.Accessible; } - function isSymbolAccessibleByFlags(typeSymbol: Symbol, enclosingDeclaration: Node | undefined, flags: SymbolFlags): boolean { - const access = isSymbolAccessibleWorker(typeSymbol, enclosingDeclaration, flags, /*shouldComputeAliasesToMakeVisible*/ false, /*allowModules*/ false); + function isSymbolAccessibleByFlags( + typeSymbol: Symbol, + enclosingDeclaration: Node | undefined, + flags: SymbolFlags, + ): boolean { + const access = isSymbolAccessibleWorker( + typeSymbol, + enclosingDeclaration, + flags, + /*shouldComputeAliasesToMakeVisible*/ false, + /*allowModules*/ false, + ); return access.accessibility === SymbolAccessibility.Accessible; } - function isAnySymbolAccessible(symbols: Symbol[] | undefined, enclosingDeclaration: Node | undefined, initialSymbol: Symbol, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, allowModules: boolean): SymbolAccessibilityResult | undefined { + function isAnySymbolAccessible( + symbols: Symbol[] | undefined, + enclosingDeclaration: Node | undefined, + initialSymbol: Symbol, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean, + allowModules: boolean, + ): SymbolAccessibilityResult | undefined { if (!length(symbols)) return; let hadAccessibleChain: Symbol | undefined; let earlyModuleBail = false; for (const symbol of symbols!) { // Symbol is accessible if it by itself is accessible - const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/ false); + const accessibleSymbolChain = getAccessibleSymbolChain( + symbol, + enclosingDeclaration, + meaning, + /*useOnlyExternalAliasing*/ false, + ); if (accessibleSymbolChain) { hadAccessibleChain = symbol; - const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible); + const hasAccessibleDeclarations = hasVisibleDeclarations( + accessibleSymbolChain[0], + shouldComputeAliasesToMakeVisible, + ); if (hasAccessibleDeclarations) { return hasAccessibleDeclarations; } @@ -5961,7 +7378,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Any meaning of a module symbol is always accessible via an `import` type return { - accessibility: SymbolAccessibility.Accessible + accessibility: SymbolAccessibility.Accessible, }; } } @@ -5980,7 +7397,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // It is accessible if the parent m is accessible because then m.c can be accessed through qualification const containers = getContainersOfSymbol(symbol, enclosingDeclaration, meaning); - const parentResult = isAnySymbolAccessible(containers, enclosingDeclaration, initialSymbol, initialSymbol === symbol ? getQualifiedLeftMeaning(meaning) : meaning, shouldComputeAliasesToMakeVisible, allowModules); + const parentResult = isAnySymbolAccessible( + containers, + enclosingDeclaration, + initialSymbol, + initialSymbol === symbol ? getQualifiedLeftMeaning(meaning) : meaning, + shouldComputeAliasesToMakeVisible, + allowModules, + ); if (parentResult) { return parentResult; } @@ -5988,7 +7412,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (earlyModuleBail) { return { - accessibility: SymbolAccessibility.Accessible + accessibility: SymbolAccessibility.Accessible, }; } @@ -5996,7 +7420,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), - errorModuleName: hadAccessibleChain !== initialSymbol ? symbolToString(hadAccessibleChain, enclosingDeclaration, SymbolFlags.Namespace) : undefined, + errorModuleName: hadAccessibleChain !== initialSymbol + ? symbolToString(hadAccessibleChain, enclosingDeclaration, SymbolFlags.Namespace) : undefined, }; } } @@ -6009,13 +7434,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param meaning a SymbolFlags to check if such meaning of the symbol is accessible * @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible */ - function isSymbolAccessible(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult { - return isSymbolAccessibleWorker(symbol, enclosingDeclaration, meaning, shouldComputeAliasesToMakeVisible, /*allowModules*/ true); + function isSymbolAccessible( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean, + ): SymbolAccessibilityResult { + return isSymbolAccessibleWorker( + symbol, + enclosingDeclaration, + meaning, + shouldComputeAliasesToMakeVisible, + /*allowModules*/ true, + ); } - function isSymbolAccessibleWorker(symbol: Symbol | undefined, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, allowModules: boolean): SymbolAccessibilityResult { + function isSymbolAccessibleWorker( + symbol: Symbol | undefined, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + shouldComputeAliasesToMakeVisible: boolean, + allowModules: boolean, + ): SymbolAccessibilityResult { if (symbol && enclosingDeclaration) { - const result = isAnySymbolAccessible([symbol], enclosingDeclaration, symbol, meaning, shouldComputeAliasesToMakeVisible, allowModules); + const result = isAnySymbolAccessible( + [symbol], + enclosingDeclaration, + symbol, + meaning, + shouldComputeAliasesToMakeVisible, + allowModules, + ); if (result) { return result; } @@ -6052,14 +7501,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function hasExternalModuleSymbol(declaration: Node) { - return isAmbientModule(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); + return isAmbientModule(declaration) + || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); } function hasNonGlobalAugmentationExternalModuleSymbol(declaration: Node) { - return isModuleWithStringLiteralName(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); + return isModuleWithStringLiteralName(declaration) + || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration as SourceFile)); } - function hasVisibleDeclarations(symbol: Symbol, shouldComputeAliasToMakeVisible: boolean): SymbolVisibilityResult | undefined { + function hasVisibleDeclarations( + symbol: Symbol, + shouldComputeAliasToMakeVisible: boolean, + ): SymbolVisibilityResult | undefined { let aliasesToMakeVisible: LateVisibilityPaintedStatement[] | undefined; if (!every(filter(symbol.declarations, d => d.kind !== SyntaxKind.Identifier), getIsDeclarationVisible)) { return undefined; @@ -6072,28 +7526,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // because these kind of aliases can be used to name types in declaration file const anyImportSyntax = getAnyImportSyntax(declaration); - if (anyImportSyntax && - !hasSyntacticModifier(anyImportSyntax, ModifierFlags.Export) && // import clause without export - isDeclarationVisible(anyImportSyntax.parent)) { + if ( + anyImportSyntax + && !hasSyntacticModifier(anyImportSyntax, ModifierFlags.Export) // import clause without export + && isDeclarationVisible(anyImportSyntax.parent) + ) { return addVisibleAlias(declaration, anyImportSyntax); } - else if (isVariableDeclaration(declaration) && isVariableStatement(declaration.parent.parent) && - !hasSyntacticModifier(declaration.parent.parent, ModifierFlags.Export) && // unexported variable statement - isDeclarationVisible(declaration.parent.parent.parent)) { + else if ( + isVariableDeclaration(declaration) && isVariableStatement(declaration.parent.parent) + && !hasSyntacticModifier(declaration.parent.parent, ModifierFlags.Export) // unexported variable statement + && isDeclarationVisible(declaration.parent.parent.parent) + ) { return addVisibleAlias(declaration, declaration.parent.parent); } - else if (isLateVisibilityPaintedStatement(declaration) // unexported top-level statement + else if ( + isLateVisibilityPaintedStatement(declaration) // unexported top-level statement && !hasSyntacticModifier(declaration, ModifierFlags.Export) - && isDeclarationVisible(declaration.parent)) { + && isDeclarationVisible(declaration.parent) + ) { return addVisibleAlias(declaration, declaration); } else if (isBindingElement(declaration)) { - if (symbol.flags & SymbolFlags.Alias && isInJSFile(declaration) && declaration.parent?.parent // exported import-like top-level JS require statement + if ( + symbol.flags & SymbolFlags.Alias && isInJSFile(declaration) && declaration.parent?.parent // exported import-like top-level JS require statement && isVariableDeclaration(declaration.parent.parent) - && declaration.parent.parent.parent?.parent && isVariableStatement(declaration.parent.parent.parent.parent) + && declaration.parent.parent.parent?.parent + && isVariableStatement(declaration.parent.parent.parent.parent) && !hasSyntacticModifier(declaration.parent.parent.parent.parent, ModifierFlags.Export) && declaration.parent.parent.parent.parent.parent // check if the thing containing the variable statement is visible (ie, the file) - && isDeclarationVisible(declaration.parent.parent.parent.parent.parent)) { + && isDeclarationVisible(declaration.parent.parent.parent.parent.parent) + ) { return addVisibleAlias(declaration, declaration.parent.parent.parent.parent); } else if (symbol.flags & SymbolFlags.BlockScopedVariable) { @@ -6127,17 +7590,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult { + function isEntityNameVisible( + entityName: EntityNameOrEntityNameExpression, + enclosingDeclaration: Node, + ): SymbolVisibilityResult { // get symbol of the first identifier of the entityName let meaning: SymbolFlags; - if (entityName.parent.kind === SyntaxKind.TypeQuery || - entityName.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isPartOfTypeNode(entityName.parent) || - entityName.parent.kind === SyntaxKind.ComputedPropertyName) { + if ( + entityName.parent.kind === SyntaxKind.TypeQuery + || entityName.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isPartOfTypeNode(entityName.parent) + || entityName.parent.kind === SyntaxKind.ComputedPropertyName + ) { // Typeof value meaning = SymbolFlags.Value | SymbolFlags.ExportValue; } - else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression || - entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration) { + else if ( + entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccessExpression + || entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration + ) { // Left identifier from type reference or TypeAlias // Entity name of the import declaration meaning = SymbolFlags.Namespace; @@ -6148,11 +7618,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const firstIdentifier = getFirstIdentifier(entityName); - const symbol = resolveName(enclosingDeclaration, firstIdentifier.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + const symbol = resolveName( + enclosingDeclaration, + firstIdentifier.escapedText, + meaning, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); if (symbol && symbol.flags & SymbolFlags.TypeParameter && meaning & SymbolFlags.Type) { return { accessibility: SymbolAccessibility.Accessible }; } - if (!symbol && isThisIdentifier(firstIdentifier) && isSymbolAccessible(getSymbolOfDeclaration(getThisContainer(firstIdentifier, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false)), firstIdentifier, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { + if ( + !symbol && isThisIdentifier(firstIdentifier) + && isSymbolAccessible( + getSymbolOfDeclaration( + getThisContainer( + firstIdentifier, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ), + ), + firstIdentifier, + meaning, + /*shouldComputeAliasesToMakeVisible*/ false, + ).accessibility === SymbolAccessibility.Accessible + ) { return { accessibility: SymbolAccessibility.Accessible }; } @@ -6160,11 +7651,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return (symbol && hasVisibleDeclarations(symbol, /*shouldComputeAliasToMakeVisible*/ true)) || { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: getTextOfNode(firstIdentifier), - errorNode: firstIdentifier + errorNode: firstIdentifier, }; } - function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, writer?: EmitTextWriter): string { + function symbolToString( + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags: SymbolFormatFlags = SymbolFormatFlags.AllowAnyNodeKind, + writer?: EmitTextWriter, + ): string { let nodeFlags = NodeBuilderFlags.IgnoreErrors; if (flags & SymbolFormatFlags.UseOnlyExternalAliasing) { nodeFlags |= NodeBuilderFlags.UseOnlyExternalAliasing; @@ -6181,7 +7678,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & SymbolFormatFlags.WriteComputedProps) { nodeFlags |= NodeBuilderFlags.WriteComputedProps; } - const builder = flags & SymbolFormatFlags.AllowAnyNodeKind ? nodeBuilder.symbolToNode : nodeBuilder.symbolToEntityName; + const builder = flags & SymbolFormatFlags.AllowAnyNodeKind ? nodeBuilder.symbolToNode + : nodeBuilder.symbolToEntityName; return writer ? symbolToStringWorker(writer).getText() : usingSingleLineStringWriter(symbolToStringWorker); function symbolToStringWorker(writer: EmitTextWriter) { @@ -6196,8 +7694,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags = TypeFormatFlags.None, kind?: SignatureKind, writer?: EmitTextWriter): string { - return writer ? signatureToStringWorker(writer).getText() : usingSingleLineStringWriter(signatureToStringWorker); + function signatureToString( + signature: Signature, + enclosingDeclaration?: Node, + flags = TypeFormatFlags.None, + kind?: SignatureKind, + writer?: EmitTextWriter, + ): string { + return writer ? signatureToStringWorker(writer).getText() + : usingSingleLineStringWriter(signatureToStringWorker); function signatureToStringWorker(writer: EmitTextWriter) { let sigOutput: SyntaxKind; @@ -6207,17 +7712,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructSignature : SyntaxKind.CallSignature; } - const sig = nodeBuilder.signatureToSignatureDeclaration(signature, sigOutput, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); + const sig = nodeBuilder.signatureToSignatureDeclaration( + signature, + sigOutput, + enclosingDeclaration, + toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors + | NodeBuilderFlags.WriteTypeParametersInQualifiedName, + ); const printer = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); - printer.writeNode(EmitHint.Unspecified, sig!, /*sourceFile*/ sourceFile, getTrailingSemicolonDeferringWriter(writer)); // TODO: GH#18217 + printer.writeNode( + EmitHint.Unspecified, + sig!, + /*sourceFile*/ sourceFile, + getTrailingSemicolonDeferringWriter(writer), + ); // TODO: GH#18217 return writer; } } - function typeToString(type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer: EmitTextWriter = createTextWriter("")): string { + function typeToString( + type: Type, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType + | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer: EmitTextWriter = createTextWriter(""), + ): string { const noTruncation = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation; - const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | (noTruncation ? NodeBuilderFlags.NoTruncation : 0)); + const typeNode = nodeBuilder.typeToTypeNode( + type, + enclosingDeclaration, + toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors + | (noTruncation ? NodeBuilderFlags.NoTruncation : 0), + ); if (typeNode === undefined) return Debug.fail("should always get typenode"); // The unresolved type gets a synthesized comment on `any` to hint to users that it's not a plain `any`. // Otherwise, we always strip comments out. @@ -6234,8 +7761,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeNamesForErrorDisplay(left: Type, right: Type): [string, string] { - let leftStr = symbolValueDeclarationIsContextSensitive(left.symbol) ? typeToString(left, left.symbol.valueDeclaration) : typeToString(left); - let rightStr = symbolValueDeclarationIsContextSensitive(right.symbol) ? typeToString(right, right.symbol.valueDeclaration) : typeToString(right); + let leftStr = symbolValueDeclarationIsContextSensitive(left.symbol) + ? typeToString(left, left.symbol.valueDeclaration) : typeToString(left); + let rightStr = symbolValueDeclarationIsContextSensitive(right.symbol) + ? typeToString(right, right.symbol.valueDeclaration) : typeToString(right); if (leftStr === rightStr) { leftStr = getTypeNameForErrorDisplay(left); rightStr = getTypeNameForErrorDisplay(right); @@ -6248,7 +7777,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function symbolValueDeclarationIsContextSensitive(symbol: Symbol): boolean { - return symbol && !!symbol.valueDeclaration && isExpression(symbol.valueDeclaration) && !isContextSensitive(symbol.valueDeclaration); + return symbol && !!symbol.valueDeclaration && isExpression(symbol.valueDeclaration) + && !isContextSensitive(symbol.valueDeclaration); } function toNodeBuilderFlags(flags = TypeFormatFlags.None): NodeBuilderFlags { @@ -6256,31 +7786,118 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isClassInstanceSide(type: Type) { - return !!type.symbol && !!(type.symbol.flags & SymbolFlags.Class) && (type === getDeclaredTypeOfClassOrInterface(type.symbol) || (!!(type.flags & TypeFlags.Object) && !!(getObjectFlags(type) & ObjectFlags.IsClassInstanceClone))); + return !!type.symbol && !!(type.symbol.flags & SymbolFlags.Class) + && (type === getDeclaredTypeOfClassOrInterface(type.symbol) + || (!!(type.flags & TypeFlags.Object) && !!(getObjectFlags(type) & ObjectFlags.IsClassInstanceClone))); } function createNodeBuilder() { return { - typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)), - indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => indexInfoToIndexSignatureDeclarationHelper(indexInfo, context, /*typeNode*/ undefined)), - signatureToSignatureDeclaration: (signature: Signature, kind: SignatureDeclaration["kind"], enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => signatureToSignatureDeclarationHelper(signature, kind, context)), - symbolToEntityName: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => symbolToName(symbol, context, meaning, /*expectsIdentifier*/ false)), - symbolToExpression: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => symbolToExpression(symbol, context, meaning)), - symbolToTypeParameterDeclarations: (symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => typeParametersToTypeParameterDeclarations(symbol, context)), - symbolToParameterDeclaration: (symbol: Symbol, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => symbolToParameterDeclaration(symbol, context)), - typeParameterToDeclaration: (parameter: TypeParameter, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => typeParameterToDeclaration(parameter, context)), - symbolTableToDeclarationStatements: (symbolTable: SymbolTable, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker, bundled?: boolean) => - withContext(enclosingDeclaration, flags, tracker, context => symbolTableToDeclarationStatements(symbolTable, context, bundled)), - symbolToNode: (symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) => - withContext(enclosingDeclaration, flags, tracker, context => symbolToNode(symbol, context, meaning)), + typeToTypeNode: ( + type: Type, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)), + indexInfoToIndexSignatureDeclaration: ( + indexInfo: IndexInfo, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => indexInfoToIndexSignatureDeclarationHelper(indexInfo, context, /*typeNode*/ undefined), + ), + signatureToSignatureDeclaration: ( + signature: Signature, + kind: SignatureDeclaration["kind"], + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => signatureToSignatureDeclarationHelper(signature, kind, context), + ), + symbolToEntityName: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolToName(symbol, context, meaning, /*expectsIdentifier*/ false), + ), + symbolToExpression: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolToExpression(symbol, context, meaning), + ), + symbolToTypeParameterDeclarations: ( + symbol: Symbol, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => typeParametersToTypeParameterDeclarations(symbol, context), + ), + symbolToParameterDeclaration: ( + symbol: Symbol, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolToParameterDeclaration(symbol, context), + ), + typeParameterToDeclaration: ( + parameter: TypeParameter, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => typeParameterToDeclaration(parameter, context), + ), + symbolTableToDeclarationStatements: ( + symbolTable: SymbolTable, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + bundled?: boolean, + ) => withContext( + enclosingDeclaration, + flags, + tracker, + context => symbolTableToDeclarationStatements(symbolTable, context, bundled), + ), + symbolToNode: ( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration?: Node, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, + ) => withContext(enclosingDeclaration, flags, tracker, context => symbolToNode(symbol, context, meaning)), }; function symbolToNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags) { @@ -6291,19 +7908,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const nameType = getSymbolLinks(symbol).nameType; if (nameType && nameType.flags & (TypeFlags.EnumLiteral | TypeFlags.UniqueESSymbol)) { - context.enclosingDeclaration = nameType.symbol.valueDeclaration; - return factory.createComputedPropertyName(symbolToExpression(nameType.symbol, context, meaning)); + context.enclosingDeclaration = nameType.symbol.valueDeclaration; + return factory.createComputedPropertyName(symbolToExpression(nameType.symbol, context, meaning)); } } return symbolToExpression(symbol, context, meaning); } - function withContext(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker: SymbolTracker | undefined, cb: (context: NodeBuilderContext) => T): T | undefined { - Debug.assert(enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0); - const moduleResolverHost = - tracker?.trackSymbol ? tracker.moduleResolverHost : - flags! & NodeBuilderFlags.DoNotIncludeSymbolChain ? createBasicNodeBuilderModuleSpecifierResolutionHost(host) : - undefined; + function withContext( + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + tracker: SymbolTracker | undefined, + cb: (context: NodeBuilderContext) => T, + ): T | undefined { + Debug.assert( + enclosingDeclaration === undefined || (enclosingDeclaration.flags & NodeFlags.Synthesized) === 0, + ); + const moduleResolverHost = tracker?.trackSymbol ? tracker.moduleResolverHost + : flags! & NodeBuilderFlags.DoNotIncludeSymbolChain + ? createBasicNodeBuilderModuleSpecifierResolutionHost(host) + : undefined; const context: NodeBuilderContext = { enclosingDeclaration, flags: flags || NodeBuilderFlags.None, @@ -6313,7 +7937,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { visitedTypes: undefined, symbolDepth: undefined, inferTypeParameters: undefined, - approximateLength: 0 + approximateLength: 0, }; context.tracker = new SymbolTrackerImpl(context, tracker, moduleResolverHost); const resultingNode = cb(context); @@ -6325,7 +7949,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkTruncationLength(context: NodeBuilderContext): boolean { if (context.truncating) return context.truncating; - return context.truncating = context.approximateLength > ((context.flags & NodeBuilderFlags.NoTruncation) ? noTruncationMaximumTruncationLength : defaultMaximumTruncationLength); + return context.truncating = context.approximateLength + > ((context.flags & NodeBuilderFlags.NoTruncation) ? noTruncationMaximumTruncationLength + : defaultMaximumTruncationLength); } function typeToTypeNodeHelper(type: Type, context: NodeBuilderContext): TypeNode { @@ -6357,13 +7983,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Any) { if (type.aliasSymbol) { - return factory.createTypeReferenceNode(symbolToEntityNameNode(type.aliasSymbol), mapToTypeNodes(type.aliasTypeArguments, context)); + return factory.createTypeReferenceNode( + symbolToEntityNameNode(type.aliasSymbol), + mapToTypeNodes(type.aliasTypeArguments, context), + ); } if (type === unresolvedType) { - return addSyntheticLeadingComment(factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), SyntaxKind.MultiLineCommentTrivia, "unresolved"); + return addSyntheticLeadingComment( + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + SyntaxKind.MultiLineCommentTrivia, + "unresolved", + ); } context.approximateLength += 3; - return factory.createKeywordTypeNode(type === intrinsicMarkerType ? SyntaxKind.IntrinsicKeyword : SyntaxKind.AnyKeyword); + return factory.createKeywordTypeNode( + type === intrinsicMarkerType ? SyntaxKind.IntrinsicKeyword : SyntaxKind.AnyKeyword, + ); } if (type.flags & TypeFlags.Unknown) { return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); @@ -6395,15 +8030,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isIdentifierText(memberName, ScriptTarget.ES3)) { return appendReferenceToType( parentName as TypeReferenceNode | ImportTypeNode, - factory.createTypeReferenceNode(memberName, /*typeArguments*/ undefined) + factory.createTypeReferenceNode(memberName, /*typeArguments*/ undefined), ); } if (isImportTypeNode(parentName)) { (parentName as any).isTypeOf = true; // mutably update, node is freshly manufactured anyhow - return factory.createIndexedAccessTypeNode(parentName, factory.createLiteralTypeNode(factory.createStringLiteral(memberName))); + return factory.createIndexedAccessTypeNode( + parentName, + factory.createLiteralTypeNode(factory.createStringLiteral(memberName)), + ); } else if (isTypeReferenceNode(parentName)) { - return factory.createIndexedAccessTypeNode(factory.createTypeQueryNode(parentName.typeName), factory.createLiteralTypeNode(factory.createStringLiteral(memberName))); + return factory.createIndexedAccessTypeNode( + factory.createTypeQueryNode(parentName.typeName), + factory.createLiteralTypeNode(factory.createStringLiteral(memberName)), + ); } else { return Debug.fail("Unhandled type node kind returned from `symbolToTypeNode`."); @@ -6412,21 +8053,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbolToTypeNode(type.symbol, context, SymbolFlags.Type); } if (type.flags & TypeFlags.StringLiteral) { - context.approximateLength += ((type as StringLiteralType).value.length + 2); - return factory.createLiteralTypeNode(setEmitFlags(factory.createStringLiteral((type as StringLiteralType).value, !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType)), EmitFlags.NoAsciiEscaping)); + context.approximateLength += (type as StringLiteralType).value.length + 2; + return factory.createLiteralTypeNode( + setEmitFlags( + factory.createStringLiteral( + (type as StringLiteralType).value, + !!(context.flags & NodeBuilderFlags.UseSingleQuotesForStringLiteralType), + ), + EmitFlags.NoAsciiEscaping, + ), + ); } if (type.flags & TypeFlags.NumberLiteral) { const value = (type as NumberLiteralType).value; context.approximateLength += ("" + value).length; - return factory.createLiteralTypeNode(value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(-value)) : factory.createNumericLiteral(value)); + return factory.createLiteralTypeNode( + value < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(-value), + ) : factory.createNumericLiteral(value), + ); } if (type.flags & TypeFlags.BigIntLiteral) { context.approximateLength += (pseudoBigIntToString((type as BigIntLiteralType).value).length) + 1; - return factory.createLiteralTypeNode((factory.createBigIntLiteral((type as BigIntLiteralType).value))); + return factory.createLiteralTypeNode(factory.createBigIntLiteral((type as BigIntLiteralType).value)); } if (type.flags & TypeFlags.BooleanLiteral) { context.approximateLength += (type as IntrinsicType).intrinsicName.length; - return factory.createLiteralTypeNode((type as IntrinsicType).intrinsicName === "true" ? factory.createTrue() : factory.createFalse()); + return factory.createLiteralTypeNode( + (type as IntrinsicType).intrinsicName === "true" ? factory.createTrue() : factory.createFalse(), + ); } if (type.flags & TypeFlags.UniqueESSymbol) { if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) { @@ -6439,7 +8096,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } context.approximateLength += 13; - return factory.createTypeOperatorNode(SyntaxKind.UniqueKeyword, factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword)); + return factory.createTypeOperatorNode( + SyntaxKind.UniqueKeyword, + factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword), + ); } if (type.flags & TypeFlags.Void) { context.approximateLength += 4; @@ -6476,9 +8136,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createThisTypeNode(); } - if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) { + if ( + !inTypeAlias && type.aliasSymbol + && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope + || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration)) + ) { const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); - if (isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class)) return factory.createTypeReferenceNode(factory.createIdentifier(""), typeArgumentNodes); + if ( + isReservedMemberName(type.aliasSymbol.escapedName) && !(type.aliasSymbol.flags & SymbolFlags.Class) + ) return factory.createTypeReferenceNode(factory.createIdentifier(""), typeArgumentNodes); if (length(typeArgumentNodes) === 1 && type.aliasSymbol === globalArrayType.symbol) { return factory.createArrayTypeNode(typeArgumentNodes![0]); } @@ -6489,11 +8155,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (objectFlags & ObjectFlags.Reference) { Debug.assert(!!(type.flags & TypeFlags.Object)); - return (type as TypeReference).node ? visitAndTransformType(type as TypeReference, typeReferenceToTypeNode) : typeReferenceToTypeNode(type as TypeReference); + return (type as TypeReference).node + ? visitAndTransformType(type as TypeReference, typeReferenceToTypeNode) + : typeReferenceToTypeNode(type as TypeReference); } if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) { - context.approximateLength += (symbolName(type.symbol).length + 6); + context.approximateLength += symbolName(type.symbol).length + 6; let constraintNode: TypeNode | undefined; const constraint = getConstraintOfTypeParameter(type as TypeParameter); if (constraint) { @@ -6501,43 +8169,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // we would have normally inferred based on context, we emit the constraint // using `infer T extends ?`. We omit inferred constraints from type references // as they may be elided. - const inferredConstraint = getInferredTypeParameterConstraint(type as TypeParameter, /*omitTypeReferences*/ true); + const inferredConstraint = getInferredTypeParameterConstraint( + type as TypeParameter, + /*omitTypeReferences*/ true, + ); if (!(inferredConstraint && isTypeIdenticalTo(constraint, inferredConstraint))) { context.approximateLength += 9; constraintNode = constraint && typeToTypeNodeHelper(constraint, context); } } - return factory.createInferTypeNode(typeParameterToDeclarationWithConstraint(type as TypeParameter, context, constraintNode)); + return factory.createInferTypeNode( + typeParameterToDeclarationWithConstraint(type as TypeParameter, context, constraintNode), + ); } - if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && - type.flags & TypeFlags.TypeParameter && - !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration)) { + if ( + context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams + && type.flags & TypeFlags.TypeParameter + && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) + ) { const name = typeParameterToName(type, context); context.approximateLength += idText(name).length; - return factory.createTypeReferenceNode(factory.createIdentifier(idText(name)), /*typeArguments*/ undefined); + return factory.createTypeReferenceNode( + factory.createIdentifier(idText(name)), + /*typeArguments*/ undefined, + ); } // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. if (type.symbol) { return symbolToTypeNode(type.symbol, context, SymbolFlags.Type); } - const name = (type === markerSuperTypeForCheck || type === markerSubTypeForCheck) && varianceTypeParameter && varianceTypeParameter.symbol ? - (type === markerSubTypeForCheck ? "sub-" : "super-") + symbolName(varianceTypeParameter.symbol) : "?"; + const name = + (type === markerSuperTypeForCheck || type === markerSubTypeForCheck) && varianceTypeParameter + && varianceTypeParameter.symbol + ? (type === markerSubTypeForCheck ? "sub-" : "super-") + + symbolName(varianceTypeParameter.symbol) : "?"; return factory.createTypeReferenceNode(factory.createIdentifier(name), /*typeArguments*/ undefined); } if (type.flags & TypeFlags.Union && (type as UnionType).origin) { type = (type as UnionType).origin!; } if (type.flags & (TypeFlags.Union | TypeFlags.Intersection)) { - const types = type.flags & TypeFlags.Union ? formatUnionTypes((type as UnionType).types) : (type as IntersectionType).types; + const types = type.flags & TypeFlags.Union ? formatUnionTypes((type as UnionType).types) + : (type as IntersectionType).types; if (length(types) === 1) { return typeToTypeNodeHelper(types[0], context); } const typeNodes = mapToTypeNodes(types, context, /*isBareList*/ true); if (typeNodes && typeNodes.length > 0) { - return type.flags & TypeFlags.Union ? factory.createUnionTypeNode(typeNodes) : factory.createIntersectionTypeNode(typeNodes); + return type.flags & TypeFlags.Union ? factory.createUnionTypeNode(typeNodes) + : factory.createIntersectionTypeNode(typeNodes); } else { - if (!context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection)) { + if ( + !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowEmptyUnionOrIntersection) + ) { context.encounteredError = true; } return undefined!; // TODO: GH#18217 @@ -6559,9 +8244,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const types = (type as TemplateLiteralType).types; const templateHead = factory.createTemplateHead(texts[0]); const templateSpans = factory.createNodeArray( - map(types, (t, i) => factory.createTemplateLiteralTypeSpan( - typeToTypeNodeHelper(t, context), - (i < types.length - 1 ? factory.createTemplateMiddle : factory.createTemplateTail)(texts[i + 1])))); + map(types, (t, i) => + factory.createTemplateLiteralTypeSpan( + typeToTypeNodeHelper(t, context), + (i < types.length - 1 ? factory.createTemplateMiddle : factory.createTemplateTail)( + texts[i + 1], + ), + )), + ); context.approximateLength += 2; return factory.createTemplateLiteralType(templateHead, templateSpans); } @@ -6584,11 +8274,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Debug.fail("Should be unreachable."); - function conditionalTypeToTypeNode(type: ConditionalType) { const checkTypeNode = typeToTypeNodeHelper(type.checkType, context); context.approximateLength += 15; - if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.root.isDistributive && !(type.checkType.flags & TypeFlags.TypeParameter)) { + if ( + context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && type.root.isDistributive + && !(type.checkType.flags & TypeFlags.TypeParameter) + ) { const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); const name = typeParameterToName(newParam, context); const newTypeVariable = factory.createTypeReferenceNode(name); @@ -6596,11 +8288,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const newMapper = prependTypeMapping(type.root.checkType, newParam, type.mapper); const saveInferTypeParameters = context.inferTypeParameters; context.inferTypeParameters = type.root.inferTypeParameters; - const extendsTypeNode = typeToTypeNodeHelper(instantiateType(type.root.extendsType, newMapper), context); + const extendsTypeNode = typeToTypeNodeHelper( + instantiateType(type.root.extendsType, newMapper), + context, + ); context.inferTypeParameters = saveInferTypeParameters; - const trueTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(type.root.node.trueType), newMapper)); - const falseTypeNode = typeToTypeNodeOrCircularityElision(instantiateType(getTypeFromTypeNode(type.root.node.falseType), newMapper)); - + const trueTypeNode = typeToTypeNodeOrCircularityElision( + instantiateType(getTypeFromTypeNode(type.root.node.trueType), newMapper), + ); + const falseTypeNode = typeToTypeNodeOrCircularityElision( + instantiateType(getTypeFromTypeNode(type.root.node.falseType), newMapper), + ); // outermost conditional makes `T` a type parameter, allowing the inner conditionals to be distributive // second conditional makes `T` have `T & checkType` substitution, so it is correctly usable as the checkType @@ -6614,14 +8312,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // may also work with `infer ... extends ...` in, but would produce declarations only compatible with the latest TS. return factory.createConditionalTypeNode( checkTypeNode, - factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable.typeName) as Identifier)), + factory.createInferTypeNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + factory.cloneNode(newTypeVariable.typeName) as Identifier, + ), + ), factory.createConditionalTypeNode( factory.createTypeReferenceNode(factory.cloneNode(name)), typeToTypeNodeHelper(type.checkType, context), - factory.createConditionalTypeNode(newTypeVariable, extendsTypeNode, trueTypeNode, falseTypeNode), - factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) + factory.createConditionalTypeNode( + newTypeVariable, + extendsTypeNode, + trueTypeNode, + falseTypeNode, + ), + factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), ), - factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) + factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), ); } const saveInferTypeParameters = context.inferTypeParameters; @@ -6652,29 +8360,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type: MappedType) { - return !!type.target && isMappedTypeHomomorphic(type.target as MappedType) && !isMappedTypeHomomorphic(type); + return !!type.target && isMappedTypeHomomorphic(type.target as MappedType) + && !isMappedTypeHomomorphic(type); } function createMappedTypeNodeFromType(type: MappedType) { Debug.assert(!!(type.flags & TypeFlags.Object)); - const readonlyToken = type.declaration.readonlyToken ? factory.createToken(type.declaration.readonlyToken.kind) as ReadonlyKeyword | PlusToken | MinusToken : undefined; - const questionToken = type.declaration.questionToken ? factory.createToken(type.declaration.questionToken.kind) as QuestionToken | PlusToken | MinusToken : undefined; + const readonlyToken = type.declaration.readonlyToken + ? factory.createToken(type.declaration.readonlyToken.kind) as + | ReadonlyKeyword + | PlusToken + | MinusToken : undefined; + const questionToken = type.declaration.questionToken + ? factory.createToken(type.declaration.questionToken.kind) as QuestionToken | PlusToken | MinusToken + : undefined; let appropriateConstraintTypeNode: TypeNode; let newTypeVariable: TypeReferenceNode | undefined; // If the mapped type isn't `keyof` constraint-declared, _but_ still has modifiers preserved, and its naive instantiation won't preserve modifiers because its constraint isn't `keyof` constrained, we have work to do const needsModifierPreservingWrapper = !isMappedTypeWithKeyofConstraintDeclaration(type) && !(getModifiersTypeFromMappedType(type).flags & TypeFlags.Unknown) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams - && !(getConstraintTypeFromMappedType(type).flags & TypeFlags.TypeParameter && getConstraintOfTypeParameter(getConstraintTypeFromMappedType(type))?.flags! & TypeFlags.Index); + && !(getConstraintTypeFromMappedType(type).flags & TypeFlags.TypeParameter + && getConstraintOfTypeParameter(getConstraintTypeFromMappedType(type))?.flags! + & TypeFlags.Index); if (isMappedTypeWithKeyofConstraintDeclaration(type)) { // We have a { [P in keyof T]: X } // We do this to ensure we retain the toplevel keyof-ness of the type which may be lost due to keyof distribution during `getConstraintTypeFromMappedType` - if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { + if ( + isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) + && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams + ) { const newParam = createTypeParameter(createSymbol(SymbolFlags.TypeParameter, "T" as __String)); const name = typeParameterToName(newParam, context); newTypeVariable = factory.createTypeReferenceNode(name); } - appropriateConstraintTypeNode = factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, newTypeVariable || typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context)); + appropriateConstraintTypeNode = factory.createTypeOperatorNode( + SyntaxKind.KeyOfKeyword, + newTypeVariable || typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context), + ); } else if (needsModifierPreservingWrapper) { // So, step 1: new type variable @@ -6685,24 +8408,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { appropriateConstraintTypeNode = newTypeVariable; } else { - appropriateConstraintTypeNode = typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context); + appropriateConstraintTypeNode = typeToTypeNodeHelper( + getConstraintTypeFromMappedType(type), + context, + ); } - const typeParameterNode = typeParameterToDeclarationWithConstraint(getTypeParameterFromMappedType(type), context, appropriateConstraintTypeNode); - const nameTypeNode = type.declaration.nameType ? typeToTypeNodeHelper(getNameTypeFromMappedType(type)!, context) : undefined; - const templateTypeNode = typeToTypeNodeHelper(removeMissingType(getTemplateTypeFromMappedType(type), !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), context); - const mappedTypeNode = factory.createMappedTypeNode(readonlyToken, typeParameterNode, nameTypeNode, questionToken, templateTypeNode, /*members*/ undefined); + const typeParameterNode = typeParameterToDeclarationWithConstraint( + getTypeParameterFromMappedType(type), + context, + appropriateConstraintTypeNode, + ); + const nameTypeNode = type.declaration.nameType + ? typeToTypeNodeHelper(getNameTypeFromMappedType(type)!, context) : undefined; + const templateTypeNode = typeToTypeNodeHelper( + removeMissingType( + getTemplateTypeFromMappedType(type), + !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional), + ), + context, + ); + const mappedTypeNode = factory.createMappedTypeNode( + readonlyToken, + typeParameterNode, + nameTypeNode, + questionToken, + templateTypeNode, + /*members*/ undefined, + ); context.approximateLength += 10; const result = setEmitFlags(mappedTypeNode, EmitFlags.SingleLine); - if (isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams) { + if ( + isHomomorphicMappedTypeWithNonHomomorphicInstantiation(type) + && context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams + ) { // homomorphic mapped type with a non-homomorphic naive inlining // wrap it with a conditional like `SomeModifiersType extends infer U ? {..the mapped type...} : never` to ensure the resulting // type stays homomorphic - const originalConstraint = instantiateType(getConstraintOfTypeParameter(getTypeFromTypeNode((type.declaration.typeParameter.constraint! as TypeOperatorNode).type) as TypeParameter) || unknownType, type.mapper); + const originalConstraint = instantiateType( + getConstraintOfTypeParameter( + getTypeFromTypeNode( + (type.declaration.typeParameter.constraint! as TypeOperatorNode).type, + ) as TypeParameter, + ) || unknownType, + type.mapper, + ); return factory.createConditionalTypeNode( typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context), - factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable!.typeName) as Identifier, originalConstraint.flags & TypeFlags.Unknown ? undefined : typeToTypeNodeHelper(originalConstraint, context))), + factory.createInferTypeNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + factory.cloneNode(newTypeVariable!.typeName) as Identifier, + originalConstraint.flags & TypeFlags.Unknown ? undefined + : typeToTypeNodeHelper(originalConstraint, context), + ), + ), result, - factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) + factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), ); } else if (needsModifierPreservingWrapper) { @@ -6712,9 +8473,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // just homomorphic ones. return factory.createConditionalTypeNode( typeToTypeNodeHelper(getConstraintTypeFromMappedType(type), context), - factory.createInferTypeNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, factory.cloneNode(newTypeVariable!.typeName) as Identifier, factory.createTypeOperatorNode(SyntaxKind.KeyOfKeyword, typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context)))), + factory.createInferTypeNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + factory.cloneNode(newTypeVariable!.typeName) as Identifier, + factory.createTypeOperatorNode( + SyntaxKind.KeyOfKeyword, + typeToTypeNodeHelper(getModifiersTypeFromMappedType(type), context), + ), + ), + ), result, - factory.createKeywordTypeNode(SyntaxKind.NeverKeyword) + factory.createKeywordTypeNode(SyntaxKind.NeverKeyword), ); } return result; @@ -6730,11 +8500,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbolToTypeNode(symbol, context, isInstanceType); } // Always use 'typeof T' for type of class, enum, and module objects - else if (symbol.flags & SymbolFlags.Class - && !getBaseTypeVariableOfClass(symbol) - && !(symbol.valueDeclaration && isClassLike(symbol.valueDeclaration) && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && (!isClassDeclaration(symbol.valueDeclaration) || isSymbolAccessible(symbol, context.enclosingDeclaration, isInstanceType, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible)) || - symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) || - shouldWriteTypeOfFunctionSymbol()) { + else if ( + symbol.flags & SymbolFlags.Class + && !getBaseTypeVariableOfClass(symbol) + && !(symbol.valueDeclaration && isClassLike(symbol.valueDeclaration) + && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + && (!isClassDeclaration(symbol.valueDeclaration) + || isSymbolAccessible( + symbol, + context.enclosingDeclaration, + isInstanceType, + /*shouldComputeAliasesToMakeVisible*/ false, + ).accessibility !== SymbolAccessibility.Accessible)) + || symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) + || shouldWriteTypeOfFunctionSymbol() + ) { return symbolToTypeNode(symbol, context, isInstanceType); } else if (context.visitedTypes?.has(typeId)) { @@ -6753,7 +8533,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else { - const isInstantiationExpressionType = !!(getObjectFlags(type) & ObjectFlags.InstantiationExpressionType); + const isInstantiationExpressionType = + !!(getObjectFlags(type) & ObjectFlags.InstantiationExpressionType); if (isInstantiationExpressionType) { const instantiationExpressionType = type as InstantiationExpressionType; if (isTypeQueryNode(instantiationExpressionType.node)) { @@ -6771,27 +8552,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createTypeNodeFromObjectType(type); } function shouldWriteTypeOfFunctionSymbol() { - const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) && // typeof static method - some(symbol.declarations, declaration => isStatic(declaration)); - const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) && - (symbol.parent || // is exported function symbol - forEach(symbol.declarations, declaration => - declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); + const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) // typeof static method + && some(symbol.declarations, declaration => isStatic(declaration)); + const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) + && (symbol.parent // is exported function symbol + || forEach( + symbol.declarations, + declaration => + declaration.parent.kind === SyntaxKind.SourceFile + || declaration.parent.kind === SyntaxKind.ModuleBlock, + )); if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { // typeof is allowed only for static/non local functions - return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) || (context.visitedTypes?.has(typeId))) && // it is type of the symbol uses itself recursively - (!(context.flags & NodeBuilderFlags.UseStructuralFallback) || isValueSymbolAccessible(symbol, context.enclosingDeclaration)); // And the build is going to succeed without visibility error or there is no structural fallback allowed + return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) + || (context.visitedTypes?.has(typeId))) // it is type of the symbol uses itself recursively + && (!(context.flags & NodeBuilderFlags.UseStructuralFallback) + || isValueSymbolAccessible(symbol, context.enclosingDeclaration)); // And the build is going to succeed without visibility error or there is no structural fallback allowed } } } function visitAndTransformType(type: T, transform: (type: T) => TypeNode) { const typeId = type.id; - const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; - const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference & T).node ? "N" + getNodeId((type as TypeReference & T).node!) : - type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType & T).root.node) : - type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) : - undefined; + const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol + && type.symbol.flags & SymbolFlags.Class; + const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference & T).node + ? "N" + getNodeId((type as TypeReference & T).node!) + : type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType & T).root.node) + : type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) + : undefined; // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead // of types allows us to catch circular references to instantiations of the same anonymous type if (!context.visitedTypes) { @@ -6840,7 +8629,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) { return node; } - return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext, deepCloneOrReuseNodes)), node); + return setTextRange( + factory.cloneNode( + visitEachChild( + node, + deepCloneOrReuseNode, + nullTransformationContext, + deepCloneOrReuseNodes, + ), + ), + node, + ); } function deepCloneOrReuseNodes( @@ -6853,7 +8652,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (nodes && nodes.length === 0) { // Ensure we explicitly make a copy of an empty array; visitNodes will not do this unless the array has elements, // which can lead to us reusing the same empty NodeArray more than once within the same AST during type noding. - return setTextRange(factory.createNodeArray(/*elements*/ undefined, nodes.hasTrailingComma), nodes); + return setTextRange( + factory.createNodeArray(/*elements*/ undefined, nodes.hasTrailingComma), + nodes, + ); } return visitNodes(nodes, visitor, test, start, count); } @@ -6873,31 +8675,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; - const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, context) as FunctionTypeNode; + const signatureNode = signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.FunctionType, + context, + ) as FunctionTypeNode; return signatureNode; - } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { const signature = resolved.constructSignatures[0]; - const signatureNode = signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, context) as ConstructorTypeNode; + const signatureNode = signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.ConstructorType, + context, + ) as ConstructorTypeNode; return signatureNode; } } - const abstractSignatures = filter(resolved.constructSignatures, signature => !!(signature.flags & SignatureFlags.Abstract)); + const abstractSignatures = filter( + resolved.constructSignatures, + signature => !!(signature.flags & SignatureFlags.Abstract), + ); if (some(abstractSignatures)) { const types = map(abstractSignatures, getOrCreateTypeFromSignature); // count the number of type elements excluding abstract constructors - const typeElementCount = - resolved.callSignatures.length + - (resolved.constructSignatures.length - abstractSignatures.length) + - resolved.indexInfos.length + + const typeElementCount = resolved.callSignatures.length + + (resolved.constructSignatures.length - abstractSignatures.length) + + resolved.indexInfos.length // exclude `prototype` when writing a class expression as a type literal, as per // the logic in `createTypeNodesFromResolvedType`. - (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral ? - countWhere(resolved.properties, p => !(p.flags & SymbolFlags.Prototype)) : - length(resolved.properties)); + + (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + ? countWhere(resolved.properties, p => !(p.flags & SymbolFlags.Prototype)) + : length(resolved.properties)); // don't include an empty object literal if there were no other static-side // properties to write, i.e. `abstract class C { }` becomes `abstract new () => {}` // and not `(abstract new () => {}) & {}` @@ -6914,7 +8725,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.flags = savedFlags; const typeLiteralNode = factory.createTypeLiteralNode(members); context.approximateLength += 2; - setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine); + setEmitFlags( + typeLiteralNode, + (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine, + ); return typeLiteralNode; } @@ -6923,14 +8737,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.target === globalArrayType || type.target === globalReadonlyArrayType) { if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) { const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context); - return factory.createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]); + return factory.createTypeReferenceNode( + type.target === globalArrayType ? "Array" : "ReadonlyArray", + [typeArgumentNode], + ); } const elementType = typeToTypeNodeHelper(typeArguments[0], context); const arrayType = factory.createArrayTypeNode(elementType); - return type.target === globalArrayType ? arrayType : factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); + return type.target === globalArrayType ? arrayType + : factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType); } else if (type.target.objectFlags & ObjectFlags.Tuple) { - typeArguments = sameMap(typeArguments, (t, i) => removeMissingType(t, !!((type.target as TupleType).elementFlags[i] & ElementFlags.Optional))); + typeArguments = sameMap( + typeArguments, + (t, i) => + removeMissingType( + t, + !!((type.target as TupleType).elementFlags[i] & ElementFlags.Optional), + ), + ); if (typeArguments.length > 0) { const arity = getTypeReferenceArity(type); const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, arity), context); @@ -6942,35 +8767,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (labeledElementDeclaration) { tupleConstituentNodes[i] = factory.createNamedTupleMember( - flags & ElementFlags.Variable ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined, - factory.createIdentifier(unescapeLeadingUnderscores(getTupleElementLabel(labeledElementDeclaration))), - flags & ElementFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : - tupleConstituentNodes[i] + flags & ElementFlags.Variable ? factory.createToken(SyntaxKind.DotDotDotToken) + : undefined, + factory.createIdentifier( + unescapeLeadingUnderscores(getTupleElementLabel(labeledElementDeclaration)), + ), + flags & ElementFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) + : undefined, + flags & ElementFlags.Rest + ? factory.createArrayTypeNode(tupleConstituentNodes[i]) + : tupleConstituentNodes[i], ); } else { - tupleConstituentNodes[i] = - flags & ElementFlags.Variable ? factory.createRestTypeNode(flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : tupleConstituentNodes[i]) : - flags & ElementFlags.Optional ? factory.createOptionalTypeNode(tupleConstituentNodes[i]) : - tupleConstituentNodes[i]; + tupleConstituentNodes[i] = flags & ElementFlags.Variable + ? factory.createRestTypeNode( + flags & ElementFlags.Rest + ? factory.createArrayTypeNode(tupleConstituentNodes[i]) + : tupleConstituentNodes[i], + ) + : flags & ElementFlags.Optional + ? factory.createOptionalTypeNode(tupleConstituentNodes[i]) + : tupleConstituentNodes[i]; } } - const tupleTypeNode = setEmitFlags(factory.createTupleTypeNode(tupleConstituentNodes), EmitFlags.SingleLine); - return (type.target as TupleType).readonly ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; + const tupleTypeNode = setEmitFlags( + factory.createTupleTypeNode(tupleConstituentNodes), + EmitFlags.SingleLine, + ); + return (type.target as TupleType).readonly + ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) + : tupleTypeNode; } } if (context.encounteredError || (context.flags & NodeBuilderFlags.AllowEmptyTuple)) { const tupleTypeNode = setEmitFlags(factory.createTupleTypeNode([]), EmitFlags.SingleLine); - return (type.target as TupleType).readonly ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; + return (type.target as TupleType).readonly + ? factory.createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, tupleTypeNode) : tupleTypeNode; } context.encounteredError = true; return undefined!; // TODO: GH#18217 } - else if (context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral && - type.symbol.valueDeclaration && - isClassLike(type.symbol.valueDeclaration) && - !isValueSymbolAccessible(type.symbol, context.enclosingDeclaration) + else if ( + context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + && type.symbol.valueDeclaration + && isClassLike(type.symbol.valueDeclaration) + && !isValueSymbolAccessible(type.symbol, context.enclosingDeclaration) ) { return createAnonymousTypeNode(type); } @@ -6986,16 +8828,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = getParentSymbolOfTypeParameter(outerTypeParameters[i])!; do { i++; - } while (i < length && getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent); + } + while (i < length && getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent); // When type parameters are their own type arguments for the whole group (i.e. we have // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { const typeArgumentSlice = mapToTypeNodes(typeArguments.slice(start, i), context); const flags = context.flags; context.flags |= NodeBuilderFlags.ForbidIndexedAccessSymbolReferences; - const ref = symbolToTypeNode(parent, context, SymbolFlags.Type, typeArgumentSlice) as TypeReferenceNode | ImportTypeNode; + const ref = symbolToTypeNode(parent, context, SymbolFlags.Type, typeArgumentSlice) as + | TypeReferenceNode + | ImportTypeNode; context.flags = flags; - resultType = !resultType ? ref : appendReferenceToType(resultType, ref as TypeReferenceNode); + resultType = !resultType ? ref + : appendReferenceToType(resultType, ref as TypeReferenceNode); } } } @@ -7012,8 +8858,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - - function appendReferenceToType(root: TypeReferenceNode | ImportTypeNode, ref: TypeReferenceNode): TypeReferenceNode | ImportTypeNode { + function appendReferenceToType( + root: TypeReferenceNode | ImportTypeNode, + ref: TypeReferenceNode, + ): TypeReferenceNode | ImportTypeNode { if (isImportTypeNode(root)) { // first shift type arguments let typeArguments = root.typeArguments; @@ -7026,9 +8874,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { if (typeArguments !== getIdentifierTypeArguments(qualifier.right)) { - qualifier = factory.updateQualifiedName(qualifier, + qualifier = factory.updateQualifiedName( + qualifier, qualifier.left, - setIdentifierTypeArguments(factory.cloneNode(qualifier.right), typeArguments)); + setIdentifierTypeArguments(factory.cloneNode(qualifier.right), typeArguments), + ); } } } @@ -7044,7 +8894,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { root.assertions, qualifier, typeArguments, - root.isTypeOf); + root.isTypeOf, + ); } else { // first shift type arguments @@ -7057,9 +8908,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { if (typeArguments !== getIdentifierTypeArguments(typeName.right)) { - typeName = factory.updateQualifiedName(typeName, + typeName = factory.updateQualifiedName( + typeName, typeName.left, - setIdentifierTypeArguments(factory.cloneNode(typeName.right), typeArguments)); + setIdentifierTypeArguments(factory.cloneNode(typeName.right), typeArguments), + ); } } typeArguments = ref.typeArguments; @@ -7071,7 +8924,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.updateTypeReferenceNode( root, typeName, - typeArguments); + typeArguments, + ); } } @@ -7088,18 +8942,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] | undefined { if (checkTruncationLength(context)) { - return [factory.createPropertySignature(/*modifiers*/ undefined, "...", /*questionToken*/ undefined, /*type*/ undefined)]; + return [ + factory.createPropertySignature( + /*modifiers*/ undefined, + "...", + /*questionToken*/ undefined, + /*type*/ undefined, + ), + ]; } const typeElements: TypeElement[] = []; for (const signature of resolvedType.callSignatures) { - typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, context) as CallSignatureDeclaration); + typeElements.push( + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.CallSignature, + context, + ) as CallSignatureDeclaration, + ); } for (const signature of resolvedType.constructSignatures) { if (signature.flags & SignatureFlags.Abstract) continue; - typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, context) as ConstructSignatureDeclaration); + typeElements.push( + signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.ConstructSignature, + context, + ) as ConstructSignatureDeclaration, + ); } for (const info of resolvedType.indexInfos) { - typeElements.push(indexInfoToIndexSignatureDeclarationHelper(info, context, resolvedType.objectFlags & ObjectFlags.ReverseMapped ? createElidedInformationPlaceholder(context) : undefined)); + typeElements.push( + indexInfoToIndexSignatureDeclarationHelper( + info, + context, + resolvedType.objectFlags & ObjectFlags.ReverseMapped + ? createElidedInformationPlaceholder(context) : undefined, + ), + ); } const properties = resolvedType.properties; @@ -7114,17 +8994,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (propertySymbol.flags & SymbolFlags.Prototype) { continue; } - if (getDeclarationModifierFlagsFromSymbol(propertySymbol) & (ModifierFlags.Private | ModifierFlags.Protected) && context.tracker.reportPrivateInBaseOfClassExpression) { - context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName)); + if ( + getDeclarationModifierFlagsFromSymbol(propertySymbol) + & (ModifierFlags.Private | ModifierFlags.Protected) + && context.tracker.reportPrivateInBaseOfClassExpression + ) { + context.tracker.reportPrivateInBaseOfClassExpression( + unescapeLeadingUnderscores(propertySymbol.escapedName), + ); } } if (checkTruncationLength(context) && (i + 2 < properties.length - 1)) { - typeElements.push(factory.createPropertySignature(/*modifiers*/ undefined, `... ${properties.length - i} more ...`, /*questionToken*/ undefined, /*type*/ undefined)); + typeElements.push( + factory.createPropertySignature( + /*modifiers*/ undefined, + `... ${properties.length - i} more ...`, + /*questionToken*/ undefined, + /*type*/ undefined, + ), + ); addPropertyToElementList(properties[properties.length - 1], context, typeElements); break; } addPropertyToElementList(propertySymbol, context, typeElements); - } return typeElements.length ? typeElements : undefined; } @@ -7150,15 +9042,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol) || ( context.reverseMappedStack?.[0] - && !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous) + && !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) + & ObjectFlags.Anonymous) ) ); } - function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) { + function addPropertyToElementList( + propertySymbol: Symbol, + context: NodeBuilderContext, + typeElements: TypeElement[], + ) { const propertyIsReverseMapped = !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped); - const propertyType = shouldUsePlaceholderForProperty(propertySymbol, context) ? - anyType : getNonMissingTypeOfSymbol(propertySymbol); + const propertyType = shouldUsePlaceholderForProperty(propertySymbol, context) + ? anyType : getNonMissingTypeOfSymbol(propertySymbol); const saveEnclosingDeclaration = context.enclosingDeclaration; context.enclosingDeclaration = undefined; if (context.tracker.canTrackSymbol && isLateBoundName(propertySymbol.escapedName)) { @@ -7167,7 +9064,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (hasLateBindableName(decl)) { if (isBinaryExpression(decl)) { const name = getNameOfDeclaration(decl); - if (name && isElementAccessExpression(name) && isPropertyAccessEntityNameExpression(name.argumentExpression)) { + if ( + name && isElementAccessExpression(name) + && isPropertyAccessEntityNameExpression(name.argumentExpression) + ) { trackComputedName(name.argumentExpression, saveEnclosingDeclaration, context); } } @@ -7180,15 +9080,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.tracker.reportNonSerializableProperty(symbolToString(propertySymbol)); } } - context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] || saveEnclosingDeclaration; + context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] + || saveEnclosingDeclaration; const propertyName = getPropertyNameNodeForSymbol(propertySymbol, context); context.enclosingDeclaration = saveEnclosingDeclaration; - context.approximateLength += (symbolName(propertySymbol).length + 1); - const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; - if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol)) { - const signatures = getSignaturesOfType(filterType(propertyType, t => !(t.flags & TypeFlags.Undefined)), SignatureKind.Call); + context.approximateLength += symbolName(propertySymbol).length + 1; + const optionalToken = propertySymbol.flags & SymbolFlags.Optional + ? factory.createToken(SyntaxKind.QuestionToken) : undefined; + if ( + propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) + && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol) + ) { + const signatures = getSignaturesOfType( + filterType(propertyType, t => !(t.flags & TypeFlags.Undefined)), + SignatureKind.Call, + ); for (const signature of signatures) { - const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context, { name: propertyName, questionToken: optionalToken }) as MethodSignature; + const methodDeclaration = signatureToSignatureDeclarationHelper( + signature, + SyntaxKind.MethodSignature, + context, + { name: propertyName, questionToken: optionalToken }, + ) as MethodSignature; typeElements.push(preserveCommentsOn(methodDeclaration)); } if (signatures.length || !optionalToken) { @@ -7204,13 +9117,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.reverseMappedStack ||= []; context.reverseMappedStack.push(propertySymbol as ReverseMappedSymbol); } - propertyTypeNode = propertyType ? serializeTypeForDeclaration(context, propertyType, propertySymbol, saveEnclosingDeclaration) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + propertyTypeNode = propertyType + ? serializeTypeForDeclaration(context, propertyType, propertySymbol, saveEnclosingDeclaration) + : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); if (propertyIsReverseMapped) { context.reverseMappedStack!.pop(); } } - const modifiers = isReadonlySymbol(propertySymbol) ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] : undefined; + const modifiers = isReadonlySymbol(propertySymbol) ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] + : undefined; if (modifiers) { context.approximateLength += 9; } @@ -7218,16 +9134,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { modifiers, propertyName, optionalToken, - propertyTypeNode); + propertyTypeNode, + ); typeElements.push(preserveCommentsOn(propertySignature)); function preserveCommentsOn(node: T) { if (some(propertySymbol.declarations, d => d.kind === SyntaxKind.JSDocPropertyTag)) { - const d = propertySymbol.declarations?.find(d => d.kind === SyntaxKind.JSDocPropertyTag)! as JSDocPropertyTag; + const d = propertySymbol.declarations?.find(d => + d.kind === SyntaxKind.JSDocPropertyTag + )! as JSDocPropertyTag; const commentText = getTextOfJSDocComment(d.comment); if (commentText) { - setSyntheticLeadingComments(node, [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }]); + setSyntheticLeadingComments(node, [{ + kind: SyntaxKind.MultiLineCommentTrivia, + text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }]); } } else if (propertySymbol.valueDeclaration) { @@ -7238,7 +9163,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function mapToTypeNodes(types: readonly Type[] | undefined, context: NodeBuilderContext, isBareList?: boolean): TypeNode[] | undefined { + function mapToTypeNodes( + types: readonly Type[] | undefined, + context: NodeBuilderContext, + isBareList?: boolean, + ): TypeNode[] | undefined { if (some(types)) { if (checkTruncationLength(context)) { if (!isBareList) { @@ -7247,8 +9176,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (types.length > 2) { return [ typeToTypeNodeHelper(types[0], context), - factory.createTypeReferenceNode(`... ${types.length - 2} more ...`, /*typeArguments*/ undefined), - typeToTypeNodeHelper(types[types.length - 1], context) + factory.createTypeReferenceNode( + `... ${types.length - 2} more ...`, + /*typeArguments*/ undefined, + ), + typeToTypeNodeHelper(types[types.length - 1], context), ]; } } @@ -7260,7 +9192,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const type of types) { i++; if (checkTruncationLength(context) && (i + 2 < types.length - 1)) { - result.push(factory.createTypeReferenceNode(`... ${types.length - i} more ...`, /*typeArguments*/ undefined)); + result.push( + factory.createTypeReferenceNode( + `... ${types.length - i} more ...`, + /*typeArguments*/ undefined, + ), + ); const typeNode = typeToTypeNodeHelper(types[types.length - 1], context); if (typeNode) { result.push(typeNode); @@ -7307,7 +9244,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || !!a.aliasSymbol && a.aliasSymbol === b.aliasSymbol; } - function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, context: NodeBuilderContext, typeNode: TypeNode | undefined): IndexSignatureDeclaration { + function indexInfoToIndexSignatureDeclarationHelper( + indexInfo: IndexInfo, + context: NodeBuilderContext, + typeNode: TypeNode | undefined, + ): IndexSignatureDeclaration { const name = getNameFromIndexInfo(indexInfo) || "x"; const indexerTypeNode = typeToTypeNodeHelper(indexInfo.keyType, context); @@ -7317,18 +9258,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { name, /*questionToken*/ undefined, indexerTypeNode, - /*initializer*/ undefined); + /*initializer*/ undefined, + ); if (!typeNode) { typeNode = typeToTypeNodeHelper(indexInfo.type || anyType, context); } if (!indexInfo.type && !(context.flags & NodeBuilderFlags.AllowEmptyIndexInfoType)) { context.encounteredError = true; } - context.approximateLength += (name.length + 4); + context.approximateLength += name.length + 4; return factory.createIndexSignature( indexInfo.isReadonly ? [factory.createToken(SyntaxKind.ReadonlyKeyword)] : undefined, [indexingParameter], - typeNode); + typeNode, + ); } interface SignatureToSignatureDeclarationOptions { @@ -7339,17 +9282,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { bundledImports?: boolean; } - function signatureToSignatureDeclarationHelper(signature: Signature, kind: SignatureDeclaration["kind"], context: NodeBuilderContext, options?: SignatureToSignatureDeclarationOptions): SignatureDeclaration { + function signatureToSignatureDeclarationHelper( + signature: Signature, + kind: SignatureDeclaration["kind"], + context: NodeBuilderContext, + options?: SignatureToSignatureDeclarationOptions, + ): SignatureDeclaration { const suppressAny = context.flags & NodeBuilderFlags.SuppressAnyReturnType; if (suppressAny) context.flags &= ~NodeBuilderFlags.SuppressAnyReturnType; // suppress only toplevel `any`s context.approximateLength += 3; // Usually a signature contributes a few more characters than this, but 3 is the minimum let typeParameters: TypeParameterDeclaration[] | undefined; let typeArguments: TypeNode[] | undefined; - if (context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature && signature.target && signature.mapper && signature.target.typeParameters) { - typeArguments = signature.target.typeParameters.map(parameter => typeToTypeNodeHelper(instantiateType(parameter, signature.mapper), context)); + if ( + context.flags & NodeBuilderFlags.WriteTypeArgumentsOfSignature && signature.target && signature.mapper + && signature.target.typeParameters + ) { + typeArguments = signature.target.typeParameters.map(parameter => + typeToTypeNodeHelper(instantiateType(parameter, signature.mapper), context) + ); } else { - typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); + typeParameters = signature.typeParameters + && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context)); } const expandedParams = getExpandedParameters(signature, /*skipUnionExpanding*/ true)[0]; @@ -7393,7 +9347,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Note that we only check the most immediate enclosingDeclaration; the only place we // could potentially add another fake scope into the chain is right here, so we don't // traverse all ancestors. - const existingFakeScope = getNodeLinks(context.enclosingDeclaration).fakeScopeForSignatureDeclaration ? context.enclosingDeclaration : undefined; + const existingFakeScope = getNodeLinks(context.enclosingDeclaration).fakeScopeForSignatureDeclaration + ? context.enclosingDeclaration : undefined; Debug.assertOptionalNode(existingFakeScope, isBlock); const locals = existingFakeScope?.locals ?? createSymbolTable(); @@ -7434,8 +9389,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // If the expanded parameter list had a variadic in a non-trailing position, don't expand it - const parameters = (some(expandedParams, p => p !== expandedParams[expandedParams.length - 1] && !!(getCheckFlags(p) & CheckFlags.RestParameter)) ? signature.parameters : expandedParams).map(parameter => symbolToParameterDeclaration(parameter, context, kind === SyntaxKind.Constructor, options?.privateSymbolVisitor, options?.bundledImports)); - const thisParameter = context.flags & NodeBuilderFlags.OmitThisParameter ? undefined : tryGetThisParameterDeclaration(signature, context); + const parameters = (some( + expandedParams, + p => p !== expandedParams[expandedParams.length - 1] + && !!(getCheckFlags(p) & CheckFlags.RestParameter), + ) ? signature.parameters : expandedParams).map(parameter => + symbolToParameterDeclaration( + parameter, + context, + kind === SyntaxKind.Constructor, + options?.privateSymbolVisitor, + options?.bundledImports, + ) + ); + const thisParameter = context.flags & NodeBuilderFlags.OmitThisParameter ? undefined + : tryGetThisParameterDeclaration(signature, context); if (thisParameter) { parameters.unshift(thisParameter); } @@ -7443,19 +9411,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let returnTypeNode: TypeNode | undefined; const typePredicate = getTypePredicateOfSignature(signature); if (typePredicate) { - const assertsModifier = typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? - factory.createToken(SyntaxKind.AssertsKeyword) : - undefined; - const parameterName = typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? - setEmitFlags(factory.createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) : - factory.createThisTypeNode(); + const assertsModifier = typePredicate.kind === TypePredicateKind.AssertsThis + || typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? factory.createToken(SyntaxKind.AssertsKeyword) + : undefined; + const parameterName = typePredicate.kind === TypePredicateKind.Identifier + || typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? setEmitFlags(factory.createIdentifier(typePredicate.parameterName), EmitFlags.NoAsciiEscaping) + : factory.createThisTypeNode(); const typeNode = typePredicate.type && typeToTypeNodeHelper(typePredicate.type, context); returnTypeNode = factory.createTypePredicateNode(assertsModifier, parameterName, typeNode); } else { const returnType = getReturnTypeOfSignature(signature); if (returnType && !(suppressAny && isTypeAny(returnType))) { - returnTypeNode = serializeReturnTypeForSignature(context, returnType, signature, options?.privateSymbolVisitor, options?.bundledImports); + returnTypeNode = serializeReturnTypeForSignature( + context, + returnType, + signature, + options?.privateSymbolVisitor, + options?.bundledImports, + ); } else if (!suppressAny) { returnTypeNode = factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); @@ -7467,29 +9443,109 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { modifiers = factory.createModifiersFromModifierFlags(flags | ModifierFlags.Abstract); } - const node = - kind === SyntaxKind.CallSignature ? factory.createCallSignature(typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.ConstructSignature ? factory.createConstructSignature(typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.MethodSignature ? factory.createMethodSignature(modifiers, options?.name ?? factory.createIdentifier(""), options?.questionToken, typeParameters, parameters, returnTypeNode) : - kind === SyntaxKind.MethodDeclaration ? factory.createMethodDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ?? factory.createIdentifier(""), /*questionToken*/ undefined, typeParameters, parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.Constructor ? factory.createConstructorDeclaration(modifiers, parameters, /*body*/ undefined) : - kind === SyntaxKind.GetAccessor ? factory.createGetAccessorDeclaration(modifiers, options?.name ?? factory.createIdentifier(""), parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.SetAccessor ? factory.createSetAccessorDeclaration(modifiers, options?.name ?? factory.createIdentifier(""), parameters, /*body*/ undefined) : - kind === SyntaxKind.IndexSignature ? factory.createIndexSignature(modifiers, parameters, returnTypeNode) : - kind === SyntaxKind.JSDocFunctionType ? factory.createJSDocFunctionType(parameters, returnTypeNode) : - kind === SyntaxKind.FunctionType ? factory.createFunctionTypeNode(typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : - kind === SyntaxKind.ConstructorType ? factory.createConstructorTypeNode(modifiers, typeParameters, parameters, returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier(""))) : - kind === SyntaxKind.FunctionDeclaration ? factory.createFunctionDeclaration(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, /*body*/ undefined) : - kind === SyntaxKind.FunctionExpression ? factory.createFunctionExpression(modifiers, /*asteriskToken*/ undefined, options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), typeParameters, parameters, returnTypeNode, factory.createBlock([])) : - kind === SyntaxKind.ArrowFunction ? factory.createArrowFunction(modifiers, typeParameters, parameters, returnTypeNode, /*equalsGreaterThanToken*/ undefined, factory.createBlock([])) : - Debug.assertNever(kind); + const node = kind === SyntaxKind.CallSignature + ? factory.createCallSignature(typeParameters, parameters, returnTypeNode) + : kind === SyntaxKind.ConstructSignature + ? factory.createConstructSignature(typeParameters, parameters, returnTypeNode) + : kind === SyntaxKind.MethodSignature + ? factory.createMethodSignature( + modifiers, + options?.name ?? factory.createIdentifier(""), + options?.questionToken, + typeParameters, + parameters, + returnTypeNode, + ) + : kind === SyntaxKind.MethodDeclaration + ? factory.createMethodDeclaration( + modifiers, + /*asteriskToken*/ undefined, + options?.name ?? factory.createIdentifier(""), + /*questionToken*/ undefined, + typeParameters, + parameters, + returnTypeNode, + /*body*/ undefined, + ) + : kind === SyntaxKind.Constructor + ? factory.createConstructorDeclaration(modifiers, parameters, /*body*/ undefined) + : kind === SyntaxKind.GetAccessor + ? factory.createGetAccessorDeclaration( + modifiers, + options?.name ?? factory.createIdentifier(""), + parameters, + returnTypeNode, + /*body*/ undefined, + ) + : kind === SyntaxKind.SetAccessor + ? factory.createSetAccessorDeclaration( + modifiers, + options?.name ?? factory.createIdentifier(""), + parameters, + /*body*/ undefined, + ) + : kind === SyntaxKind.IndexSignature + ? factory.createIndexSignature(modifiers, parameters, returnTypeNode) + : kind === SyntaxKind.JSDocFunctionType ? factory.createJSDocFunctionType(parameters, returnTypeNode) + : kind === SyntaxKind.FunctionType + ? factory.createFunctionTypeNode( + typeParameters, + parameters, + returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier("")), + ) + : kind === SyntaxKind.ConstructorType + ? factory.createConstructorTypeNode( + modifiers, + typeParameters, + parameters, + returnTypeNode ?? factory.createTypeReferenceNode(factory.createIdentifier("")), + ) + : kind === SyntaxKind.FunctionDeclaration + ? factory.createFunctionDeclaration( + modifiers, + /*asteriskToken*/ undefined, + options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), + typeParameters, + parameters, + returnTypeNode, + /*body*/ undefined, + ) + : kind === SyntaxKind.FunctionExpression + ? factory.createFunctionExpression( + modifiers, + /*asteriskToken*/ undefined, + options?.name ? cast(options.name, isIdentifier) : factory.createIdentifier(""), + typeParameters, + parameters, + returnTypeNode, + factory.createBlock([]), + ) + : kind === SyntaxKind.ArrowFunction + ? factory.createArrowFunction( + modifiers, + typeParameters, + parameters, + returnTypeNode, + /*equalsGreaterThanToken*/ undefined, + factory.createBlock([]), + ) + : Debug.assertNever(kind); if (typeArguments) { node.typeArguments = factory.createNodeArray(typeArguments); } - if (signature.declaration?.kind === SyntaxKind.JSDocSignature && signature.declaration.parent.kind === SyntaxKind.JSDocOverloadTag) { - const comment = getTextOfNode(signature.declaration.parent.parent, /*includeTrivia*/ true).slice(2, -2).split(/\r\n|\n|\r/).map(line => line.replace(/^\s+/, " ")).join("\n"); - addSyntheticLeadingComment(node, SyntaxKind.MultiLineCommentTrivia, comment, /*hasTrailingNewLine*/ true); + if ( + signature.declaration?.kind === SyntaxKind.JSDocSignature + && signature.declaration.parent.kind === SyntaxKind.JSDocOverloadTag + ) { + const comment = getTextOfNode(signature.declaration.parent.parent, /*includeTrivia*/ true).slice(2, -2) + .split(/\r\n|\n|\r/).map(line => line.replace(/^\s+/, " ")).join("\n"); + addSyntheticLeadingComment( + node, + SyntaxKind.MultiLineCommentTrivia, + comment, + /*hasTrailingNewLine*/ true, + ); } cleanup?.(); @@ -7508,13 +9564,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*dotDotDotToken*/ undefined, "this", /*questionToken*/ undefined, - typeToTypeNodeHelper(getTypeFromTypeNode(thisTag.typeExpression), context) + typeToTypeNodeHelper(getTypeFromTypeNode(thisTag.typeExpression), context), ); } } } - function typeParameterToDeclarationWithConstraint(type: TypeParameter, context: NodeBuilderContext, constraintNode: TypeNode | undefined): TypeParameterDeclaration { + function typeParameterToDeclarationWithConstraint( + type: TypeParameter, + context: NodeBuilderContext, + constraintNode: TypeNode | undefined, + ): TypeParameterDeclaration { const savedContextFlags = context.flags; context.flags &= ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic const modifiers = factory.createModifiersFromModifierFlags(getTypeParameterModifiers(type)); @@ -7525,33 +9585,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createTypeParameterDeclaration(modifiers, name, constraintNode, defaultParameterNode); } - function typeParameterToDeclaration(type: TypeParameter, context: NodeBuilderContext, constraint = getConstraintOfTypeParameter(type)): TypeParameterDeclaration { + function typeParameterToDeclaration( + type: TypeParameter, + context: NodeBuilderContext, + constraint = getConstraintOfTypeParameter(type), + ): TypeParameterDeclaration { const constraintNode = constraint && typeToTypeNodeHelper(constraint, context); return typeParameterToDeclarationWithConstraint(type, context, constraintNode); } - function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext, preserveModifierFlags?: boolean, privateSymbolVisitor?: (s: Symbol) => void, bundledImports?: boolean): ParameterDeclaration { - let parameterDeclaration: ParameterDeclaration | JSDocParameterTag | undefined = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); + function symbolToParameterDeclaration( + parameterSymbol: Symbol, + context: NodeBuilderContext, + preserveModifierFlags?: boolean, + privateSymbolVisitor?: (s: Symbol) => void, + bundledImports?: boolean, + ): ParameterDeclaration { + let parameterDeclaration: ParameterDeclaration | JSDocParameterTag | undefined = getDeclarationOfKind< + ParameterDeclaration + >(parameterSymbol, SyntaxKind.Parameter); if (!parameterDeclaration && !isTransientSymbol(parameterSymbol)) { - parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.JSDocParameterTag); + parameterDeclaration = getDeclarationOfKind( + parameterSymbol, + SyntaxKind.JSDocParameterTag, + ); } let parameterType = getTypeOfSymbol(parameterSymbol); if (parameterDeclaration && isRequiredInitializedParameter(parameterDeclaration)) { parameterType = getOptionalType(parameterType); } - const parameterTypeNode = serializeTypeForDeclaration(context, parameterType, parameterSymbol, context.enclosingDeclaration, privateSymbolVisitor, bundledImports); + const parameterTypeNode = serializeTypeForDeclaration( + context, + parameterType, + parameterSymbol, + context.enclosingDeclaration, + privateSymbolVisitor, + bundledImports, + ); - const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && canHaveModifiers(parameterDeclaration) ? map(getModifiers(parameterDeclaration), factory.cloneNode) : undefined; - const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; + const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags + && parameterDeclaration && canHaveModifiers(parameterDeclaration) + ? map(getModifiers(parameterDeclaration), factory.cloneNode) : undefined; + const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) + || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; const dotDotDotToken = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined; - const name = parameterDeclaration ? parameterDeclaration.name ? - parameterDeclaration.name.kind === SyntaxKind.Identifier ? setEmitFlags(factory.cloneNode(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) : - parameterDeclaration.name.kind === SyntaxKind.QualifiedName ? setEmitFlags(factory.cloneNode(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) : - cloneBindingName(parameterDeclaration.name) : - symbolName(parameterSymbol) : - symbolName(parameterSymbol); - const isOptional = parameterDeclaration && isOptionalParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.OptionalParameter; + const name = parameterDeclaration ? parameterDeclaration.name + ? parameterDeclaration.name.kind === SyntaxKind.Identifier + ? setEmitFlags(factory.cloneNode(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) + : parameterDeclaration.name.kind === SyntaxKind.QualifiedName + ? setEmitFlags(factory.cloneNode(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) + : cloneBindingName(parameterDeclaration.name) + : symbolName(parameterSymbol) + : symbolName(parameterSymbol); + const isOptional = parameterDeclaration && isOptionalParameter(parameterDeclaration) + || getCheckFlags(parameterSymbol) & CheckFlags.OptionalParameter; const questionToken = isOptional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; const parameterNode = factory.createParameterDeclaration( modifiers, @@ -7559,7 +9647,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { name, questionToken, parameterTypeNode, - /*initializer*/ undefined); + /*initializer*/ undefined, + ); context.approximateLength += symbolName(parameterSymbol).length + 3; return parameterNode; @@ -7569,14 +9658,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (context.tracker.canTrackSymbol && isComputedPropertyName(node) && isLateBindableName(node)) { trackComputedName(node.expression, context.enclosingDeclaration, context); } - let visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags)!; + let visited = visitEachChild( + node, + elideInitializerAndSetEmitFlags, + nullTransformationContext, + /*nodesVisitor*/ undefined, + elideInitializerAndSetEmitFlags, + )!; if (isBindingElement(visited)) { visited = factory.updateBindingElement( visited, visited.dotDotDotToken, visited.propertyName, visited.name, - /*initializer*/ undefined); + /*initializer*/ undefined, + ); } if (!nodeIsSynthesized(visited)) { visited = factory.cloneNode(visited); @@ -7586,26 +9682,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function trackComputedName(accessExpression: EntityNameOrEntityNameExpression, enclosingDeclaration: Node | undefined, context: NodeBuilderContext) { + function trackComputedName( + accessExpression: EntityNameOrEntityNameExpression, + enclosingDeclaration: Node | undefined, + context: NodeBuilderContext, + ) { if (!context.tracker.canTrackSymbol) return; // get symbol of the first identifier of the entityName const firstIdentifier = getFirstIdentifier(accessExpression); - const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); + const name = resolveName( + firstIdentifier, + firstIdentifier.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + ); if (name) { context.tracker.trackSymbol(name, enclosingDeclaration, SymbolFlags.Value); } } - function lookupSymbolChain(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) { + function lookupSymbolChain( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + yieldModuleSymbol?: boolean, + ) { context.tracker.trackSymbol(symbol, context.enclosingDeclaration, meaning); return lookupSymbolChainWorker(symbol, context, meaning, yieldModuleSymbol); } - function lookupSymbolChainWorker(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) { + function lookupSymbolChainWorker( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + yieldModuleSymbol?: boolean, + ) { // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. let chain: Symbol[]; const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; - if (!isTypeParameter && (context.enclosingDeclaration || context.flags & NodeBuilderFlags.UseFullyQualifiedType) && !(context.flags & NodeBuilderFlags.DoNotIncludeSymbolChain)) { + if ( + !isTypeParameter + && (context.enclosingDeclaration || context.flags & NodeBuilderFlags.UseFullyQualifiedType) + && !(context.flags & NodeBuilderFlags.DoNotIncludeSymbolChain) + ) { chain = Debug.checkDefined(getSymbolChain(symbol, meaning, /*endOfChain*/ true)); Debug.assert(chain && chain.length > 0); } @@ -7616,32 +9737,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */ function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined { - let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing)); + let accessibleSymbolChain = getAccessibleSymbolChain( + symbol, + context.enclosingDeclaration, + meaning, + !!(context.flags & NodeBuilderFlags.UseOnlyExternalAliasing), + ); let parentSpecifiers: (string | undefined)[]; - if (!accessibleSymbolChain || - needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { - + if ( + !accessibleSymbolChain + || needsQualification( + accessibleSymbolChain[0], + context.enclosingDeclaration, + accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning), + ) + ) { // Go up and add our parent. - const parents = getContainersOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol, context.enclosingDeclaration, meaning); + const parents = getContainersOfSymbol( + accessibleSymbolChain ? accessibleSymbolChain[0] : symbol, + context.enclosingDeclaration, + meaning, + ); if (length(parents)) { parentSpecifiers = parents!.map(symbol => some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol) ? getSpecifierForModuleSymbol(symbol, context) - : undefined); + : undefined + ); const indices = parents!.map((_, i) => i); indices.sort(sortByBestName); const sortedParents = indices.map(i => parents![i]); for (const parent of sortedParents) { - const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false); + const parentChain = getSymbolChain( + parent, + getQualifiedLeftMeaning(meaning), + /*endOfChain*/ false, + ); if (parentChain) { - if (parent.exports && parent.exports.get(InternalSymbolName.ExportEquals) && - getSymbolIfSameReference(parent.exports.get(InternalSymbolName.ExportEquals)!, symbol)) { + if ( + parent.exports && parent.exports.get(InternalSymbolName.ExportEquals) + && getSymbolIfSameReference( + parent.exports.get(InternalSymbolName.ExportEquals)!, + symbol, + ) + ) { // parentChain root _is_ symbol - symbol is a module export=, so it kinda looks like it's own parent // No need to lookup an alias for the symbol in itself accessibleSymbolChain = parentChain; break; } - accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]); + accessibleSymbolChain = parentChain.concat( + accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol], + ); break; } } @@ -7653,11 +9800,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if ( // If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols. - endOfChain || + endOfChain // If a parent symbol is an anonymous type, don't write it. - !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) { + || !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral)) + ) { // If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.) - if (!endOfChain && !yieldModuleSymbol && !!forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { + if ( + !endOfChain && !yieldModuleSymbol + && !!forEach(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol) + ) { return; } return [symbol]; @@ -7670,7 +9821,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isBRelative = pathIsRelative(specifierB); if (pathIsRelative(specifierA) === isBRelative) { // Both relative or both non-relative, sort by number of parts - return moduleSpecifiers.countPathComponents(specifierA) - moduleSpecifiers.countPathComponents(specifierB); + return moduleSpecifiers.countPathComponents(specifierA) + - moduleSpecifiers.countPathComponents(specifierB); } if (isBRelative) { // A is non-relative, B is relative: prefer A @@ -7688,7 +9840,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let typeParameterNodes: NodeArray | undefined; const targetSymbol = getTargetSymbol(symbol); if (targetSymbol.flags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeAlias)) { - typeParameterNodes = factory.createNodeArray(map(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), tp => typeParameterToDeclaration(tp, context))); + typeParameterNodes = factory.createNodeArray( + map( + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), + tp => typeParameterToDeclaration(tp, context), + ), + ); } return typeParameterNodes; } @@ -7707,10 +9864,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const nextSymbol = chain[index + 1]; if (getCheckFlags(nextSymbol) & CheckFlags.Instantiated) { const params = getTypeParametersOfClassOrInterface( - parentSymbol.flags & SymbolFlags.Alias ? resolveAlias(parentSymbol) : parentSymbol + parentSymbol.flags & SymbolFlags.Alias ? resolveAlias(parentSymbol) : parentSymbol, ); // NOTE: cast to TransientSymbol should be safe because only TransientSymbol can have CheckFlags.Instantiated - typeParameterNodes = mapToTypeNodes(map(params, t => getMappedType(t, (nextSymbol as TransientSymbol).links.mapper!)), context); + typeParameterNodes = mapToTypeNodes( + map(params, t => getMappedType(t, (nextSymbol as TransientSymbol).links.mapper!)), + context, + ); } else { typeParameterNodes = typeParametersToTypeParameterDeclarations(symbol, context); @@ -7729,10 +9889,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return top; } - function getSpecifierForModuleSymbol(symbol: Symbol, context: NodeBuilderContext, overrideImportMode?: ResolutionMode) { + function getSpecifierForModuleSymbol( + symbol: Symbol, + context: NodeBuilderContext, + overrideImportMode?: ResolutionMode, + ) { let file = getDeclarationOfKind(symbol, SyntaxKind.SourceFile); if (!file) { - const equivalentFileSymbol = firstDefined(symbol.declarations, d => getFileSymbolIfFileSymbolExportEqualsContainer(d, symbol)); + const equivalentFileSymbol = firstDefined( + symbol.declarations, + d => getFileSymbolIfFileSymbolExportEqualsContainer(d, symbol), + ); if (equivalentFileSymbol) { file = getDeclarationOfKind(equivalentFileSymbol, SyntaxKind.SourceFile); } @@ -7773,7 +9940,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative // specifier preference const { moduleResolverHost } = context.tracker; - const specifierCompilerOptions = isBundle ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } : compilerOptions; + const specifierCompilerOptions = isBundle + ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } : compilerOptions; specifier = first(moduleSpecifiers.getModuleSpecifiers( symbol, checker, @@ -7786,7 +9954,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { : resolutionMode === ModuleKind.ESNext ? "js" : undefined, }, - { overrideImportMode } + { overrideImportMode }, )); links.specifierCache ??= new Map(); links.specifierCache.set(cacheKey, specifier); @@ -7796,42 +9964,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function symbolToEntityNameNode(symbol: Symbol): EntityName { const identifier = factory.createIdentifier(unescapeLeadingUnderscores(symbol.escapedName)); - return symbol.parent ? factory.createQualifiedName(symbolToEntityNameNode(symbol.parent), identifier) : identifier; - } - - function symbolToTypeNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, overrideTypeArguments?: readonly TypeNode[]): TypeNode { - const chain = lookupSymbolChain(symbol, context, meaning, !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope)); // If we're using aliases outside the current scope, dont bother with the module + return symbol.parent ? factory.createQualifiedName(symbolToEntityNameNode(symbol.parent), identifier) + : identifier; + } + + function symbolToTypeNode( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + overrideTypeArguments?: readonly TypeNode[], + ): TypeNode { + const chain = lookupSymbolChain( + symbol, + context, + meaning, + !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope), + ); // If we're using aliases outside the current scope, dont bother with the module const isTypeOf = meaning === SymbolFlags.Value; if (some(chain[0].declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { // module is root, must use `ImportTypeNode` - const nonRootParts = chain.length > 1 ? createAccessFromSymbolChain(chain, chain.length - 1, 1) : undefined; + const nonRootParts = chain.length > 1 ? createAccessFromSymbolChain(chain, chain.length - 1, 1) + : undefined; const typeParameterNodes = overrideTypeArguments || lookupTypeParameterNodes(chain, 0, context); const contextFile = getSourceFileOfNode(getOriginalNode(context.enclosingDeclaration)); const targetFile = getSourceFileOfModule(chain[0]); let specifier: string | undefined; let assertion: ImportTypeAssertionContainer | undefined; - if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { + if ( + getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext + ) { // An `import` type directed at an esm format file is only going to resolve in esm mode - set the esm mode assertion - if (targetFile?.impliedNodeFormat === ModuleKind.ESNext && targetFile.impliedNodeFormat !== contextFile?.impliedNodeFormat) { + if ( + targetFile?.impliedNodeFormat === ModuleKind.ESNext + && targetFile.impliedNodeFormat !== contextFile?.impliedNodeFormat + ) { specifier = getSpecifierForModuleSymbol(chain[0], context, ModuleKind.ESNext); - assertion = factory.createImportTypeAssertionContainer(factory.createAssertClause(factory.createNodeArray([ - factory.createAssertEntry( - factory.createStringLiteral("resolution-mode"), - factory.createStringLiteral("import") - ) - ]))); + assertion = factory.createImportTypeAssertionContainer( + factory.createAssertClause(factory.createNodeArray([ + factory.createAssertEntry( + factory.createStringLiteral("resolution-mode"), + factory.createStringLiteral("import"), + ), + ])), + ); context.tracker.reportImportTypeNodeResolutionModeOverride?.(); } } if (!specifier) { specifier = getSpecifierForModuleSymbol(chain[0], context); } - if (!(context.flags & NodeBuilderFlags.AllowNodeModulesRelativePaths) && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic && specifier.indexOf("/node_modules/") >= 0) { + if ( + !(context.flags & NodeBuilderFlags.AllowNodeModulesRelativePaths) + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic + && specifier.indexOf("/node_modules/") >= 0 + ) { const oldSpecifier = specifier; - if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { + if ( + getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext + ) { // We might be able to write a portable import type using a mode override; try specifier generation again, but with a different mode set - const swappedMode = contextFile?.impliedNodeFormat === ModuleKind.ESNext ? ModuleKind.CommonJS : ModuleKind.ESNext; + const swappedMode = contextFile?.impliedNodeFormat === ModuleKind.ESNext ? ModuleKind.CommonJS + : ModuleKind.ESNext; specifier = getSpecifierForModuleSymbol(chain[0], context, swappedMode); if (specifier.indexOf("/node_modules/") >= 0) { @@ -7839,12 +10035,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { specifier = oldSpecifier; } else { - assertion = factory.createImportTypeAssertionContainer(factory.createAssertClause(factory.createNodeArray([ - factory.createAssertEntry( - factory.createStringLiteral("resolution-mode"), - factory.createStringLiteral(swappedMode === ModuleKind.ESNext ? "import" : "require") - ) - ]))); + assertion = factory.createImportTypeAssertionContainer( + factory.createAssertClause(factory.createNodeArray([ + factory.createAssertEntry( + factory.createStringLiteral("resolution-mode"), + factory.createStringLiteral( + swappedMode === ModuleKind.ESNext ? "import" : "require", + ), + ), + ])), + ); context.tracker.reportImportTypeNodeResolutionModeOverride?.(); } } @@ -7859,19 +10059,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } const lit = factory.createLiteralTypeNode(factory.createStringLiteral(specifier)); - if (context.tracker.trackExternalModuleSymbolOfImportTypeNode) context.tracker.trackExternalModuleSymbolOfImportTypeNode(chain[0]); + if (context.tracker.trackExternalModuleSymbolOfImportTypeNode) { + context.tracker.trackExternalModuleSymbolOfImportTypeNode(chain[0]); + } context.approximateLength += specifier.length + 10; // specifier + import("") if (!nonRootParts || isEntityName(nonRootParts)) { if (nonRootParts) { const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right; setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined); } - return factory.createImportTypeNode(lit, assertion, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf); + return factory.createImportTypeNode( + lit, + assertion, + nonRootParts as EntityName, + typeParameterNodes as readonly TypeNode[], + isTypeOf, + ); } else { const splitNode = getTopmostIndexedAccessType(nonRootParts); const qualifier = (splitNode.objectType as TypeReferenceNode).typeName; - return factory.createIndexedAccessTypeNode(factory.createImportTypeNode(lit, assertion, qualifier, typeParameterNodes as readonly TypeNode[], isTypeOf), splitNode.indexType); + return factory.createIndexedAccessTypeNode( + factory.createImportTypeNode( + lit, + assertion, + qualifier, + typeParameterNodes as readonly TypeNode[], + isTypeOf, + ), + splitNode.indexType, + ); } } @@ -7889,8 +10106,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray); } - function createAccessFromSymbolChain(chain: Symbol[], index: number, stopper: number): EntityName | IndexedAccessTypeNode { - const typeParameterNodes = index === (chain.length - 1) ? overrideTypeArguments : lookupTypeParameterNodes(chain, index, context); + function createAccessFromSymbolChain( + chain: Symbol[], + index: number, + stopper: number, + ): EntityName | IndexedAccessTypeNode { + const typeParameterNodes = index === (chain.length - 1) ? overrideTypeArguments + : lookupTypeParameterNodes(chain, index, context); const symbol = chain[index]; const parent = chain[index - 1]; @@ -7905,7 +10127,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (parent && getExportsOfSymbol(parent)) { const exports = getExportsOfSymbol(parent); forEachEntry(exports, (ex, name) => { - if (getSymbolIfSameReference(ex, symbol) && !isLateBoundName(name) && name !== InternalSymbolName.ExportEquals) { + if ( + getSymbolIfSameReference(ex, symbol) && !isLateBoundName(name) + && name !== InternalSymbolName.ExportEquals + ) { symbolName = unescapeLeadingUnderscores(name); return true; } @@ -7918,7 +10143,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (name && isComputedPropertyName(name) && isEntityName(name.expression)) { const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); if (isEntityName(LHS)) { - return factory.createIndexedAccessTypeNode(factory.createParenthesizedType(factory.createTypeQueryNode(LHS)), factory.createTypeQueryNode(name.expression)); + return factory.createIndexedAccessTypeNode( + factory.createParenthesizedType(factory.createTypeQueryNode(LHS)), + factory.createTypeQueryNode(name.expression), + ); } return LHS; } @@ -7926,21 +10154,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } context.approximateLength += symbolName.length + 1; - if (!(context.flags & NodeBuilderFlags.ForbidIndexedAccessSymbolReferences) && parent && - getMembersOfSymbol(parent) && getMembersOfSymbol(parent).get(symbol.escapedName) && - getSymbolIfSameReference(getMembersOfSymbol(parent).get(symbol.escapedName)!, symbol)) { + if ( + !(context.flags & NodeBuilderFlags.ForbidIndexedAccessSymbolReferences) && parent + && getMembersOfSymbol(parent) && getMembersOfSymbol(parent).get(symbol.escapedName) + && getSymbolIfSameReference(getMembersOfSymbol(parent).get(symbol.escapedName)!, symbol) + ) { // Should use an indexed access const LHS = createAccessFromSymbolChain(chain, index - 1, stopper); if (isIndexedAccessTypeNode(LHS)) { - return factory.createIndexedAccessTypeNode(LHS, factory.createLiteralTypeNode(factory.createStringLiteral(symbolName))); + return factory.createIndexedAccessTypeNode( + LHS, + factory.createLiteralTypeNode(factory.createStringLiteral(symbolName)), + ); } else { - return factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(LHS, typeParameterNodes as readonly TypeNode[]), factory.createLiteralTypeNode(factory.createStringLiteral(symbolName))); + return factory.createIndexedAccessTypeNode( + factory.createTypeReferenceNode(LHS, typeParameterNodes as readonly TypeNode[]), + factory.createLiteralTypeNode(factory.createStringLiteral(symbolName)), + ); } } const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); - if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + if (typeParameterNodes) { + setIdentifierTypeArguments( + identifier, + factory.createNodeArray(typeParameterNodes), + ); + } identifier.symbol = symbol; if (index > stopper) { @@ -7954,8 +10195,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function typeParameterShadowsNameInScope(escapedName: __String, context: NodeBuilderContext, type: TypeParameter) { - const result = resolveName(context.enclosingDeclaration, escapedName, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, escapedName, /*isUse*/ false); + function typeParameterShadowsNameInScope( + escapedName: __String, + context: NodeBuilderContext, + type: TypeParameter, + ) { + const result = resolveName( + context.enclosingDeclaration, + escapedName, + SymbolFlags.Type, + /*nameNotFoundMessage*/ undefined, + escapedName, + /*isUse*/ false, + ); if (result) { if (result.flags & SymbolFlags.TypeParameter && result === type.symbol) { return false; @@ -7980,7 +10232,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const rawtext = result.escapedText as string; let i = context.typeParameterNamesByTextNextNameCount?.get(rawtext) || 0; let text = rawtext; - while (context.typeParameterNamesByText?.has(text) || typeParameterShadowsNameInScope(text as __String, context, type)) { + while ( + context.typeParameterNamesByText?.has(text) + || typeParameterShadowsNameInScope(text as __String, context, type) + ) { i++; text = `${rawtext}_${i}`; } @@ -7998,14 +10253,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: true): Identifier; - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: false): EntityName; - function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: boolean): EntityName { + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: true, + ): Identifier; + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: false, + ): EntityName; + function symbolToName( + symbol: Symbol, + context: NodeBuilderContext, + meaning: SymbolFlags, + expectsIdentifier: boolean, + ): EntityName { const chain = lookupSymbolChain(symbol, context, meaning); - if (expectsIdentifier && chain.length !== 1 + if ( + expectsIdentifier && chain.length !== 1 && !context.encounteredError - && !(context.flags & NodeBuilderFlags.AllowQualifiedNameInPlaceOfIdentifier)) { + && !(context.flags & NodeBuilderFlags.AllowQualifiedNameInPlaceOfIdentifier) + ) { context.encounteredError = true; } return createEntityNameFromSymbolChain(chain, chain.length - 1); @@ -8023,10 +10295,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); - if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + if (typeParameterNodes) { + setIdentifierTypeArguments( + identifier, + factory.createNodeArray(typeParameterNodes), + ); + } identifier.symbol = symbol; - return index > 0 ? factory.createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; + return index > 0 + ? factory.createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) + : identifier; } } @@ -8048,15 +10327,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let firstChar = symbolName.charCodeAt(0); - if (isSingleOrDoubleQuote(firstChar) && some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol)) { + if ( + isSingleOrDoubleQuote(firstChar) + && some(symbol.declarations, hasNonGlobalAugmentationExternalModuleSymbol) + ) { return factory.createStringLiteral(getSpecifierForModuleSymbol(symbol, context)); } if (index === 0 || canUsePropertyAccess(symbolName, languageVersion)) { const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); - if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + if (typeParameterNodes) { + setIdentifierTypeArguments( + identifier, + factory.createNodeArray(typeParameterNodes), + ); + } identifier.symbol = symbol; - return index > 0 ? factory.createPropertyAccessExpression(createExpressionFromSymbolChain(chain, index - 1), identifier) : identifier; + return index > 0 + ? factory.createPropertyAccessExpression( + createExpressionFromSymbolChain(chain, index - 1), + identifier, + ) : identifier; } else { if (firstChar === CharacterCodes.openBracket) { @@ -8065,18 +10356,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let expression: Expression | undefined; if (isSingleOrDoubleQuote(firstChar) && !(symbol.flags & SymbolFlags.EnumMember)) { - expression = factory.createStringLiteral(stripQuotes(symbolName).replace(/\\./g, s => s.substring(1)), firstChar === CharacterCodes.singleQuote); + expression = factory.createStringLiteral( + stripQuotes(symbolName).replace(/\\./g, s => s.substring(1)), + firstChar === CharacterCodes.singleQuote, + ); } else if (("" + +symbolName) === symbolName) { expression = factory.createNumericLiteral(+symbolName); } if (!expression) { - const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); - if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + const identifier = setEmitFlags( + factory.createIdentifier(symbolName), + EmitFlags.NoAsciiEscaping, + ); + if (typeParameterNodes) { + setIdentifierTypeArguments( + identifier, + factory.createNodeArray(typeParameterNodes), + ); + } identifier.symbol = symbol; expression = identifier; } - return factory.createElementAccessExpression(createExpressionFromSymbolChain(chain, index - 1), expression); + return factory.createElementAccessExpression( + createExpressionFromSymbolChain(chain, index - 1), + expression, + ); } } } @@ -8095,7 +10400,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isSingleQuotedStringNamed(d: Declaration) { const name = getNameOfDeclaration(d); - return !!(name && isStringLiteral(name) && (name.singleQuote || !nodeIsSynthesized(name) && startsWith(getTextOfNode(name, /*includeTrivia*/ false), "'"))); + return !!(name && isStringLiteral(name) + && (name.singleQuote + || !nodeIsSynthesized(name) && startsWith(getTextOfNode(name, /*includeTrivia*/ false), "'"))); } function getPropertyNameNodeForSymbol(symbol: Symbol, context: NodeBuilderContext) { @@ -8106,25 +10413,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return fromNameType; } const rawName = unescapeLeadingUnderscores(symbol.escapedName); - return createPropertyNameNodeForIdentifierOrLiteral(rawName, getEmitScriptTarget(compilerOptions), singleQuote, stringNamed); + return createPropertyNameNodeForIdentifierOrLiteral( + rawName, + getEmitScriptTarget(compilerOptions), + singleQuote, + stringNamed, + ); } // See getNameForSymbolFromNameType for a stringy equivalent - function getPropertyNameNodeForSymbolFromNameType(symbol: Symbol, context: NodeBuilderContext, singleQuote?: boolean, stringNamed?: boolean) { + function getPropertyNameNodeForSymbolFromNameType( + symbol: Symbol, + context: NodeBuilderContext, + singleQuote?: boolean, + stringNamed?: boolean, + ) { const nameType = getSymbolLinks(symbol).nameType; if (nameType) { if (nameType.flags & TypeFlags.StringOrNumberLiteral) { const name = "" + (nameType as StringLiteralType | NumberLiteralType).value; - if (!isIdentifierText(name, getEmitScriptTarget(compilerOptions)) && (stringNamed || !isNumericLiteralName(name))) { + if ( + !isIdentifierText(name, getEmitScriptTarget(compilerOptions)) + && (stringNamed || !isNumericLiteralName(name)) + ) { return factory.createStringLiteral(name, !!singleQuote); } if (isNumericLiteralName(name) && startsWith(name, "-")) { - return factory.createComputedPropertyName(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(+name)))); + return factory.createComputedPropertyName( + factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(Math.abs(+name)), + ), + ); } return createPropertyNameNodeForIdentifierOrLiteral(name, getEmitScriptTarget(compilerOptions)); } if (nameType.flags & TypeFlags.UniqueESSymbol) { - return factory.createComputedPropertyName(symbolToExpression((nameType as UniqueESSymbolType).symbol, context, SymbolFlags.Value)); + return factory.createComputedPropertyName( + symbolToExpression((nameType as UniqueESSymbolType).symbol, context, SymbolFlags.Value), + ); } } } @@ -8156,30 +10483,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return initial; } - function getDeclarationWithTypeAnnotation(symbol: Symbol, enclosingDeclaration: Node | undefined) { - return symbol.declarations && find(symbol.declarations, s => !!getEffectiveTypeAnnotationNode(s) && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration))); + return symbol.declarations + && find( + symbol.declarations, + s => !!getEffectiveTypeAnnotationNode(s) + && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration)), + ); } - function existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing: TypeNode, type: Type) { - return !(getObjectFlags(type) & ObjectFlags.Reference) || !isTypeReferenceNode(existing) || length(existing.typeArguments) >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters); + function existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + existing: TypeNode, + type: Type, + ) { + return !(getObjectFlags(type) & ObjectFlags.Reference) || !isTypeReferenceNode(existing) + || length(existing.typeArguments) + >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters); } function getEnclosingDeclarationIgnoringFakeScope(enclosingDeclaration: Node) { - return getNodeLinks(enclosingDeclaration).fakeScopeForSignatureDeclaration ? enclosingDeclaration.parent : enclosingDeclaration; + return getNodeLinks(enclosingDeclaration).fakeScopeForSignatureDeclaration ? enclosingDeclaration.parent + : enclosingDeclaration; } /** * Unlike `typeToTypeNodeHelper`, this handles setting up the `AllowUniqueESSymbolType` flag * so a `unique symbol` is returned when appropriate for the input symbol, rather than `typeof sym` */ - function serializeTypeForDeclaration(context: NodeBuilderContext, type: Type, symbol: Symbol, enclosingDeclaration: Node | undefined, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { + function serializeTypeForDeclaration( + context: NodeBuilderContext, + type: Type, + symbol: Symbol, + enclosingDeclaration: Node | undefined, + includePrivateSymbol?: (s: Symbol) => void, + bundled?: boolean, + ) { if (!isErrorType(type) && enclosingDeclaration) { - const declWithExistingAnnotation = getDeclarationWithTypeAnnotation(symbol, getEnclosingDeclarationIgnoringFakeScope(enclosingDeclaration)); - if (declWithExistingAnnotation && !isFunctionLikeDeclaration(declWithExistingAnnotation) && !isGetAccessorDeclaration(declWithExistingAnnotation)) { + const declWithExistingAnnotation = getDeclarationWithTypeAnnotation( + symbol, + getEnclosingDeclarationIgnoringFakeScope(enclosingDeclaration), + ); + if ( + declWithExistingAnnotation && !isFunctionLikeDeclaration(declWithExistingAnnotation) + && !isGetAccessorDeclaration(declWithExistingAnnotation) + ) { // try to reuse the existing annotation const existing = getEffectiveTypeAnnotationNode(declWithExistingAnnotation)!; - if (typeNodeIsEquivalentToType(existing, declWithExistingAnnotation, type) && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing, type)) { + if ( + typeNodeIsEquivalentToType(existing, declWithExistingAnnotation, type) + && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing, type) + ) { const result = serializeExistingTypeNode(context, existing, includePrivateSymbol, bundled); if (result) { return result; @@ -8188,8 +10541,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } const oldFlags = context.flags; - if (type.flags & TypeFlags.UniqueESSymbol && - type.symbol === symbol && (!context.enclosingDeclaration || some(symbol.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!)))) { + if ( + type.flags & TypeFlags.UniqueESSymbol + && type.symbol === symbol + && (!context.enclosingDeclaration + || some( + symbol.declarations, + d => getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!), + )) + ) { context.flags |= NodeBuilderFlags.AllowUniqueESSymbolType; } const result = typeToTypeNodeHelper(type, context); @@ -8208,14 +10568,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function serializeReturnTypeForSignature(context: NodeBuilderContext, type: Type, signature: Signature, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { + function serializeReturnTypeForSignature( + context: NodeBuilderContext, + type: Type, + signature: Signature, + includePrivateSymbol?: (s: Symbol) => void, + bundled?: boolean, + ) { if (!isErrorType(type) && context.enclosingDeclaration) { const annotation = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); - const enclosingDeclarationIgnoringFakeScope = getEnclosingDeclarationIgnoringFakeScope(context.enclosingDeclaration); + const enclosingDeclarationIgnoringFakeScope = getEnclosingDeclarationIgnoringFakeScope( + context.enclosingDeclaration, + ); if (!!findAncestor(annotation, n => n === enclosingDeclarationIgnoringFakeScope) && annotation) { const annotated = getTypeFromTypeNode(annotation); - const thisInstantiated = annotated.flags & TypeFlags.TypeParameter && (annotated as TypeParameter).isThisType ? instantiateType(annotated, signature.mapper) : annotated; - if (thisInstantiated === type && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(annotation, type)) { + const thisInstantiated = + annotated.flags & TypeFlags.TypeParameter && (annotated as TypeParameter).isThisType + ? instantiateType(annotated, signature.mapper) : annotated; + if ( + thisInstantiated === type + && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(annotation, type) + ) { const result = serializeExistingTypeNode(context, annotation, includePrivateSymbol, bundled); if (result) { return result; @@ -8226,16 +10599,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeToTypeNodeHelper(type, context); } - function trackExistingEntityName(node: T, context: NodeBuilderContext, includePrivateSymbol?: (s: Symbol) => void) { + function trackExistingEntityName( + node: T, + context: NodeBuilderContext, + includePrivateSymbol?: (s: Symbol) => void, + ) { let introducesError = false; const leftmost = getFirstIdentifier(node); - if (isInJSFile(node) && (isExportsIdentifier(leftmost) || isModuleExportsAccessExpression(leftmost.parent) || (isQualifiedName(leftmost.parent) && isModuleIdentifier(leftmost.parent.left) && isExportsIdentifier(leftmost.parent.right)))) { + if ( + isInJSFile(node) + && (isExportsIdentifier(leftmost) || isModuleExportsAccessExpression(leftmost.parent) + || (isQualifiedName(leftmost.parent) && isModuleIdentifier(leftmost.parent.left) + && isExportsIdentifier(leftmost.parent.right))) + ) { introducesError = true; return { introducesError, node }; } const sym = resolveEntityName(leftmost, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true); if (sym) { - if (isSymbolAccessible(sym, context.enclosingDeclaration, SymbolFlags.All, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible) { + if ( + isSymbolAccessible( + sym, + context.enclosingDeclaration, + SymbolFlags.All, + /*shouldComputeAliasesToMakeVisible*/ false, + ).accessibility !== SymbolAccessibility.Accessible + ) { introducesError = true; } else { @@ -8244,16 +10633,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isIdentifier(node)) { const type = getDeclaredTypeOfSymbol(sym); - const name = sym.flags & SymbolFlags.TypeParameter && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) ? typeParameterToName(type, context) : factory.cloneNode(node); + const name = sym.flags & SymbolFlags.TypeParameter + && !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration) + ? typeParameterToName(type, context) : factory.cloneNode(node); name.symbol = sym; // for quickinfo, which uses identifier symbol information - return { introducesError, node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping) }; + return { + introducesError, + node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping), + }; } } return { introducesError, node }; } - function serializeExistingTypeNode(context: NodeBuilderContext, existing: TypeNode, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) { + function serializeExistingTypeNode( + context: NodeBuilderContext, + existing: TypeNode, + includePrivateSymbol?: (s: Symbol) => void, + bundled?: boolean, + ) { if (cancellationToken && cancellationToken.throwIfCancellationRequested) { cancellationToken.throwIfCancellationRequested(); } @@ -8274,10 +10673,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); } if (isJSDocNullableType(node)) { - return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode), factory.createLiteralTypeNode(factory.createNull())]); + return factory.createUnionTypeNode([ + visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode), + factory.createLiteralTypeNode(factory.createNull()), + ]); } if (isJSDocOptionalType(node)) { - return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode), factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); + return factory.createUnionTypeNode([ + visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode), + factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword), + ]); } if (isJSDocNonNullableType(node)) { return visitNode(node.type, visitExistingNodeTreeSymbols); @@ -8289,13 +10694,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createTypeLiteralNode(map(node.jsDocPropertyTags, t => { const name = isIdentifier(t.name) ? t.name : t.name.right; const typeViaParent = getTypeOfPropertyOfType(getTypeFromTypeNode(node), name.escapedText); - const overrideTypeNode = typeViaParent && t.typeExpression && getTypeFromTypeNode(t.typeExpression.type) !== typeViaParent ? typeToTypeNodeHelper(typeViaParent, context) : undefined; + const overrideTypeNode = typeViaParent && t.typeExpression + && getTypeFromTypeNode(t.typeExpression.type) !== typeViaParent + ? typeToTypeNodeHelper(typeViaParent, context) : undefined; return factory.createPropertySignature( /*modifiers*/ undefined, name, - t.isBracketed || t.typeExpression && isJSDocOptionalType(t.typeExpression.type) ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - overrideTypeNode || (t.typeExpression && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols, isTypeNode)) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + t.isBracketed || t.typeExpression && isJSDocOptionalType(t.typeExpression.type) + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + overrideTypeNode + || (t.typeExpression + && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols, isTypeNode)) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), ); })); } @@ -8306,13 +10717,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createTypeLiteralNode([factory.createIndexSignature( /*modifiers*/ undefined, [factory.createParameterDeclaration( - /*modifiers*/ undefined, + /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "x", /*questionToken*/ undefined, - visitNode(node.typeArguments![0], visitExistingNodeTreeSymbols, isTypeNode) + visitNode(node.typeArguments![0], visitExistingNodeTreeSymbols, isTypeNode), )], - visitNode(node.typeArguments![1], visitExistingNodeTreeSymbols, isTypeNode) + visitNode(node.typeArguments![1], visitExistingNodeTreeSymbols, isTypeNode), )]); } if (isJSDocFunctionType(node)) { @@ -8321,74 +10732,106 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createConstructorTypeNode( /*modifiers*/ undefined, visitNodes(node.typeParameters, visitExistingNodeTreeSymbols, isTypeParameterDeclaration), - mapDefined(node.parameters, (p, i) => p.name && isIdentifier(p.name) && p.name.escapedText === "new" ? (newTypeNode = p.type, undefined) : factory.createParameterDeclaration( - /*modifiers*/ undefined, - getEffectiveDotDotDotForParameter(p), - getNameForJSDocFunctionParameter(p, i), - p.questionToken, - visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), - /*initializer*/ undefined - )), - visitNode(newTypeNode || node.type, visitExistingNodeTreeSymbols, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + mapDefined( + node.parameters, + (p, i) => + p.name && isIdentifier(p.name) && p.name.escapedText === "new" + ? (newTypeNode = p.type, undefined) : factory.createParameterDeclaration( + /*modifiers*/ undefined, + getEffectiveDotDotDotForParameter(p), + getNameForJSDocFunctionParameter(p, i), + p.questionToken, + visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), + /*initializer*/ undefined, + ), + ), + visitNode(newTypeNode || node.type, visitExistingNodeTreeSymbols, isTypeNode) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), ); } else { return factory.createFunctionTypeNode( visitNodes(node.typeParameters, visitExistingNodeTreeSymbols, isTypeParameterDeclaration), - map(node.parameters, (p, i) => factory.createParameterDeclaration( - /*modifiers*/ undefined, - getEffectiveDotDotDotForParameter(p), - getNameForJSDocFunctionParameter(p, i), - p.questionToken, - visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), - /*initializer*/ undefined - )), - visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + map(node.parameters, (p, i) => + factory.createParameterDeclaration( + /*modifiers*/ undefined, + getEffectiveDotDotDotForParameter(p), + getNameForJSDocFunctionParameter(p, i), + p.questionToken, + visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), + /*initializer*/ undefined, + )), + visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), ); } } - if (isTypeReferenceNode(node) && isInJSDoc(node) && (!existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(node, getTypeFromTypeNode(node)) || getIntendedTypeFromJSDocTypeReference(node) || unknownSymbol === resolveTypeReferenceName(node, SymbolFlags.Type, /*ignoreErrors*/ true))) { + if ( + isTypeReferenceNode(node) && isInJSDoc(node) + && (!existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount( + node, + getTypeFromTypeNode(node), + ) || getIntendedTypeFromJSDocTypeReference(node) + || unknownSymbol === resolveTypeReferenceName(node, SymbolFlags.Type, /*ignoreErrors*/ true)) + ) { return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node); } if (isLiteralImportTypeNode(node)) { const nodeSymbol = getNodeLinks(node).resolvedSymbol; - if (isInJSDoc(node) && - nodeSymbol && - ( + if ( + isInJSDoc(node) + && nodeSymbol + && ( // The import type resolved using jsdoc fallback logic - (!node.isTypeOf && !(nodeSymbol.flags & SymbolFlags.Type)) || + (!node.isTypeOf && !(nodeSymbol.flags & SymbolFlags.Type)) // The import type had type arguments autofilled by js fallback logic - !(length(node.typeArguments) >= getMinTypeArgumentCount(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(nodeSymbol))) + || !(length(node.typeArguments) + >= getMinTypeArgumentCount( + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(nodeSymbol), + )) ) ) { return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node); } return factory.updateImportTypeNode( node, - factory.updateLiteralTypeNode(node.argument, rewriteModuleSpecifier(node, node.argument.literal)), + factory.updateLiteralTypeNode( + node.argument, + rewriteModuleSpecifier(node, node.argument.literal), + ), node.assertions, node.qualifier, visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode), - node.isTypeOf + node.isTypeOf, ); } if (isEntityName(node) || isEntityNameExpression(node)) { - const { introducesError, node: result } = trackExistingEntityName(node, context, includePrivateSymbol); + const { introducesError, node: result } = trackExistingEntityName( + node, + context, + includePrivateSymbol, + ); hadError = hadError || introducesError; if (result !== node) { return result; } } - if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) { + if ( + file && isTupleTypeNode(node) + && (getLineAndCharacterOfPosition(file, node.pos).line + === getLineAndCharacterOfPosition(file, node.end).line) + ) { setEmitFlags(node, EmitFlags.SingleLine); } return visitEachChild(node, visitExistingNodeTreeSymbols, nullTransformationContext); function getEffectiveDotDotDotForParameter(p: ParameterDeclaration) { - return p.dotDotDotToken || (p.type && isJSDocVariadicType(p.type) ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined); + return p.dotDotDotToken + || (p.type && isJSDocVariadicType(p.type) ? factory.createToken(SyntaxKind.DotDotDotToken) + : undefined); } /** Note that `new:T` parameters are not handled, but should be before calling this function. */ @@ -8403,11 +10846,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (context.tracker && context.tracker.moduleResolverHost) { const targetFile = getExternalModuleFileFromDeclaration(parent); if (targetFile) { - const getCanonicalFileName = createGetCanonicalFileName(!!host.useCaseSensitiveFileNames); + const getCanonicalFileName = createGetCanonicalFileName( + !!host.useCaseSensitiveFileNames, + ); const resolverHost = { getCanonicalFileName, - getCurrentDirectory: () => context.tracker.moduleResolverHost!.getCurrentDirectory(), - getCommonSourceDirectory: () => context.tracker.moduleResolverHost!.getCommonSourceDirectory() + getCurrentDirectory: () => + context.tracker.moduleResolverHost!.getCurrentDirectory(), + getCommonSourceDirectory: () => + context.tracker.moduleResolverHost!.getCommonSourceDirectory(), }; const newName = getResolvedExternalModuleName(resolverHost, targetFile); return factory.createStringLiteral(newName); @@ -8416,7 +10863,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { if (context.tracker && context.tracker.trackExternalModuleSymbolOfImportTypeNode) { - const moduleSym = resolveExternalModuleNameWorker(lit, lit, /*moduleNotFoundError*/ undefined); + const moduleSym = resolveExternalModuleNameWorker( + lit, + lit, + /*moduleNotFoundError*/ undefined, + ); if (moduleSym) { context.tracker.trackExternalModuleSymbolOfImportTypeNode(moduleSym); } @@ -8427,9 +10878,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function symbolTableToDeclarationStatements(symbolTable: SymbolTable, context: NodeBuilderContext, bundled?: boolean): Statement[] { - const serializePropertySymbolForClass = makeSerializePropertySymbol(factory.createPropertyDeclaration, SyntaxKind.MethodDeclaration, /*useAccessors*/ true); - const serializePropertySymbolForInterfaceWorker = makeSerializePropertySymbol((mods, name, question, type) => factory.createPropertySignature(mods, name, question, type), SyntaxKind.MethodSignature, /*useAccessors*/ false); + function symbolTableToDeclarationStatements( + symbolTable: SymbolTable, + context: NodeBuilderContext, + bundled?: boolean, + ): Statement[] { + const serializePropertySymbolForClass = makeSerializePropertySymbol( + factory.createPropertyDeclaration, + SyntaxKind.MethodDeclaration, + /*useAccessors*/ true, + ); + const serializePropertySymbolForInterfaceWorker = makeSerializePropertySymbol( + (mods, name, question, type) => factory.createPropertySignature(mods, name, question, type), + SyntaxKind.MethodSignature, + /*useAccessors*/ false, + ); // TODO: Use `setOriginalNode` on original declaration names where possible so these declarations see some kind of // declaration mapping @@ -8451,12 +10914,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const tracker: SymbolTracker = { ...oldcontext.tracker.inner, trackSymbol: (sym, decl, meaning) => { - const accessibleResult = isSymbolAccessible(sym, decl, meaning, /*shouldComputeAliasesToMakeVisible*/ false); + const accessibleResult = isSymbolAccessible( + sym, + decl, + meaning, + /*shouldComputeAliasesToMakeVisible*/ false, + ); if (accessibleResult.accessibility === SymbolAccessibility.Accessible) { // Lookup the root symbol of the chain of refs we'll use to access it and serialize it const chain = lookupSymbolChainWorker(sym, context, meaning); if (!(sym.flags & SymbolFlags.Property)) { - includePrivateSymbol(chain[0]); + // Only include referenced privates in the same file. Weird JS aliases may expose privates + // from other files - assume JS transforms will make those available via expected means + const root = chain[0]; + const contextFile = getSourceFileOfNode(oldcontext.enclosingDeclaration); + if (some(root.declarations, d => getSourceFileOfNode(d) === contextFile)) { + includePrivateSymbol(root); + } } } else if (oldcontext.tracker.inner?.trackSymbol) { @@ -8487,7 +10961,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getNamesOfDeclaration(statement: Statement): Identifier[] { if (isVariableStatement(statement)) { - return filter(map(statement.declarationList.declarations, getNameOfDeclaration), isIdentifierAndNotUndefined); + return filter( + map(statement.declarationList.declarations, getNameOfDeclaration), + isIdentifierAndNotUndefined, + ); } return filter([getNameOfDeclaration(statement as DeclarationStatement)], isIdentifierAndNotUndefined); } @@ -8496,12 +10973,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const exportAssignment = find(statements, isExportAssignment); const nsIndex = findIndex(statements, isModuleDeclaration); let ns = nsIndex !== -1 ? statements[nsIndex] as ModuleDeclaration : undefined; - if (ns && exportAssignment && exportAssignment.isExportEquals && - isIdentifier(exportAssignment.expression) && isIdentifier(ns.name) && idText(ns.name) === idText(exportAssignment.expression) && - ns.body && isModuleBlock(ns.body)) { + if ( + ns && exportAssignment && exportAssignment.isExportEquals + && isIdentifier(exportAssignment.expression) && isIdentifier(ns.name) + && idText(ns.name) === idText(exportAssignment.expression) + && ns.body && isModuleBlock(ns.body) + ) { // Pass 0: Correct situations where a module has both an `export = ns` and multiple top-level exports by stripping the export modifiers from // the top-level exports and exporting them in the targeted ns, as can occur when a js file has both typedefs and `module.export` assignments - const excessExports = filter(statements, s => !!(getEffectiveModifierFlags(s) & ModifierFlags.Export)); + const excessExports = filter( + statements, + s => !!(getEffectiveModifierFlags(s) & ModifierFlags.Export), + ); const name = ns.name; let body = ns.body; if (length(excessExports)) { @@ -8511,13 +10994,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ns.name, body = factory.updateModuleBlock( body, - factory.createNodeArray([...ns.body.statements, factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports(map(flatMap(excessExports, e => getNamesOfDeclaration(e)), id => factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, id))), - /*moduleSpecifier*/ undefined - )]) - ) + factory.createNodeArray([ + ...ns.body.statements, + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports( + map( + flatMap(excessExports, e => getNamesOfDeclaration(e)), + id => + factory.createExportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + id, + ), + ), + ), + /*moduleSpecifier*/ undefined, + ), + ]), + ), ); statements = [...statements.slice(0, nsIndex), ns, ...statements.slice(nsIndex + 1)]; } @@ -8527,7 +11023,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { results = []; // If the namespace contains no export assignments or declarations, and no declarations flagged with `export`, then _everything_ is exported - // to respect this as the top level, we need to add an `export` modifier to everything - const mixinExportFlag = !some(body.statements, s => hasSyntacticModifier(s, ModifierFlags.Export) || isExportAssignment(s) || isExportDeclaration(s)); + const mixinExportFlag = !some( + body.statements, + s => hasSyntacticModifier(s, ModifierFlags.Export) || isExportAssignment(s) + || isExportDeclaration(s), + ); forEach(body.statements, s => { addResult(s, mixinExportFlag ? ModifierFlags.Export : ModifierFlags.None); // Recalculates the ambient (and export, if applicable from above) flag }); @@ -8539,20 +11039,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function mergeExportDeclarations(statements: Statement[]) { // Pass 2: Combine all `export {}` declarations - const exports = filter(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause)) as ExportDeclaration[]; + const exports = filter( + statements, + d => isExportDeclaration(d) && !d.moduleSpecifier && !!d.exportClause + && isNamedExports(d.exportClause), + ) as ExportDeclaration[]; if (length(exports) > 1) { - const nonExports = filter(statements, d => !isExportDeclaration(d) || !!d.moduleSpecifier || !d.exportClause); - statements = [...nonExports, factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports(flatMap(exports, e => cast(e.exportClause, isNamedExports).elements)), - /*moduleSpecifier*/ undefined - )]; + const nonExports = filter( + statements, + d => !isExportDeclaration(d) || !!d.moduleSpecifier || !d.exportClause, + ); + statements = [ + ...nonExports, + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports( + flatMap(exports, e => cast(e.exportClause, isNamedExports).elements), + ), + /*moduleSpecifier*/ undefined, + ), + ]; } // Pass 2b: Also combine all `export {} from "..."` declarations as needed - const reexports = filter(statements, d => isExportDeclaration(d) && !!d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause)) as ExportDeclaration[]; + const reexports = filter( + statements, + d => isExportDeclaration(d) && !!d.moduleSpecifier && !!d.exportClause + && isNamedExports(d.exportClause), + ) as ExportDeclaration[]; if (length(reexports) > 1) { - const groups = group(reexports, decl => isStringLiteral(decl.moduleSpecifier!) ? ">" + decl.moduleSpecifier.text : ">"); + const groups = group( + reexports, + decl => isStringLiteral(decl.moduleSpecifier!) ? ">" + decl.moduleSpecifier.text : ">", + ); if (groups.length !== reexports.length) { for (const group of groups) { if (group.length > 1) { @@ -8562,9 +11081,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(flatMap(group, e => cast(e.exportClause, isNamedExports).elements)), - group[0].moduleSpecifier - ) + factory.createNamedExports( + flatMap(group, e => cast(e.exportClause, isNamedExports).elements), + ), + group[0].moduleSpecifier, + ), ]; } } @@ -8575,17 +11096,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function inlineExportModifiers(statements: Statement[]) { // Pass 3: Move all `export {}`'s to `export` modifiers where possible - const index = findIndex(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !d.assertClause && !!d.exportClause && isNamedExports(d.exportClause)); + const index = findIndex( + statements, + d => isExportDeclaration(d) && !d.moduleSpecifier && !d.assertClause && !!d.exportClause + && isNamedExports(d.exportClause), + ); if (index >= 0) { - const exportDecl = statements[index] as ExportDeclaration & { readonly exportClause: NamedExports }; + const exportDecl = statements[index] as ExportDeclaration & { + readonly exportClause: NamedExports; + }; const replacements = mapDefined(exportDecl.exportClause.elements, e => { if (!e.propertyName) { // export {name} - look thru `statements` for `name`, and if all results can take an `export` modifier, do so and filter it const indices = indicesOf(statements); const associatedIndices = filter(indices, i => nodeHasName(statements[i], e.name)); - if (length(associatedIndices) && every(associatedIndices, i => canHaveExportModifier(statements[i]))) { + if ( + length(associatedIndices) + && every(associatedIndices, i => canHaveExportModifier(statements[i])) + ) { for (const index of associatedIndices) { - statements[index] = addExportModifier(statements[index] as Extract); + statements[index] = addExportModifier( + statements[index] as Extract, + ); } return undefined; } @@ -8604,10 +11136,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { exportDecl.isTypeOnly, factory.updateNamedExports( exportDecl.exportClause, - replacements + replacements, ), exportDecl.moduleSpecifier, - exportDecl.assertClause + exportDecl.assertClause, ); } } @@ -8621,9 +11153,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Not a cleanup, but as a final step: If there is a mix of `export` and non-`export` declarations, but no `export =` or `export {}` add a `export {};` so // declaration privacy is respected. - if (enclosingDeclaration && - ((isSourceFile(enclosingDeclaration) && isExternalOrCommonJsModule(enclosingDeclaration)) || isModuleDeclaration(enclosingDeclaration)) && - (!some(statements, isExternalModuleIndicator) || (!hasScopeMarker(statements) && some(statements, needsScopeMarker)))) { + if ( + enclosingDeclaration + && ((isSourceFile(enclosingDeclaration) && isExternalOrCommonJsModule(enclosingDeclaration)) + || isModuleDeclaration(enclosingDeclaration)) + && (!some(statements, isExternalModuleIndicator) + || (!hasScopeMarker(statements) && some(statements, needsScopeMarker))) + ) { statements.push(createEmptyExports(factory)); } return statements; @@ -8639,7 +11175,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.updateModifiers(node, flags); } - function visitSymbolTable(symbolTable: SymbolTable, suppressNewPrivateContext?: boolean, propertyAsAlias?: boolean) { + function visitSymbolTable( + symbolTable: SymbolTable, + suppressNewPrivateContext?: boolean, + propertyAsAlias?: boolean, + ) { if (!suppressNewPrivateContext) { deferredPrivatesStack.push(new Map()); } @@ -8667,7 +11207,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { visitedSymbols.add(getSymbolId(visitedSym)); // Only actually serialize symbols within the correct enclosing declaration, otherwise do nothing with the out-of-context symbol const skipMembershipCheck = !isPrivate; // We only call this on exported symbols when we know they're in the correct scope - if (skipMembershipCheck || (!!length(symbol.declarations) && some(symbol.declarations, d => !!findAncestor(d, n => n === enclosingDeclaration)))) { + if ( + skipMembershipCheck + || (!!length(symbol.declarations) + && some(symbol.declarations, d => !!findAncestor(d, n => n === enclosingDeclaration))) + ) { const oldContext = context; context = cloneNodeBuilderContext(context); serializeSymbolWorker(symbol, isPrivate, propertyAsAlias); @@ -8678,7 +11222,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - // Synthesize declarations for a symbol - might be an Interface, a Class, a Namespace, a Type, a Variable (const, let, or var), an Alias // or a merge of some number of those. // An interesting challenge is ensuring that when classes merge with namespaces and interfaces, is keeping @@ -8691,40 +11234,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function serializeSymbolWorker(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean): void { const symbolName = unescapeLeadingUnderscores(symbol.escapedName); const isDefault = symbol.escapedName === InternalSymbolName.Default; - if (isPrivate && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) && isStringANonContextualKeyword(symbolName) && !isDefault) { + if ( + isPrivate && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) + && isStringANonContextualKeyword(symbolName) && !isDefault + ) { // Oh no. We cannot use this symbol's name as it's name... It's likely some jsdoc had an invalid name like `export` or `default` :( context.encounteredError = true; // TODO: Issue error via symbol tracker? return; // If we need to emit a private with a keyword name, we're done for, since something else will try to refer to it by that name } let needsPostExportDefault = isDefault && !!( - symbol.flags & SymbolFlags.ExportDoesNotSupportDefaultModifier + symbol.flags & SymbolFlags.ExportDoesNotSupportDefaultModifier || (symbol.flags & SymbolFlags.Function && length(getPropertiesOfType(getTypeOfSymbol(symbol)))) ) && !(symbol.flags & SymbolFlags.Alias); // An alias symbol should preclude needing to make an alias ourselves - let needsExportDeclaration = !needsPostExportDefault && !isPrivate && isStringANonContextualKeyword(symbolName) && !isDefault; + let needsExportDeclaration = !needsPostExportDefault && !isPrivate + && isStringANonContextualKeyword(symbolName) && !isDefault; // `serializeVariableOrProperty` will handle adding the export declaration if it is run (since `getInternalSymbolName` will create the name mapping), so we need to ensuer we unset `needsExportDeclaration` if it is if (needsPostExportDefault || needsExportDeclaration) { isPrivate = true; } - const modifierFlags = (!isPrivate ? ModifierFlags.Export : 0) | (isDefault && !needsPostExportDefault ? ModifierFlags.Default : 0); - const isConstMergedWithNS = symbol.flags & SymbolFlags.Module && - symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) && - symbol.escapedName !== InternalSymbolName.ExportEquals; - const isConstMergedWithNSPrintableAsSignatureMerge = isConstMergedWithNS && isTypeRepresentableAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol); - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) || isConstMergedWithNSPrintableAsSignatureMerge) { - serializeAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); + const modifierFlags = (!isPrivate ? ModifierFlags.Export : 0) + | (isDefault && !needsPostExportDefault ? ModifierFlags.Default : 0); + const isConstMergedWithNS = symbol.flags & SymbolFlags.Module + && symbol.flags + & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) + && symbol.escapedName !== InternalSymbolName.ExportEquals; + const isConstMergedWithNSPrintableAsSignatureMerge = isConstMergedWithNS + && isTypeRepresentableAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol); + if ( + symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) + || isConstMergedWithNSPrintableAsSignatureMerge + ) { + serializeAsFunctionNamespaceMerge( + getTypeOfSymbol(symbol), + symbol, + getInternalSymbolName(symbol, symbolName), + modifierFlags, + ); } if (symbol.flags & SymbolFlags.TypeAlias) { serializeTypeAlias(symbol, symbolName, modifierFlags); } // Need to skip over export= symbols below - json source files get a single `Property` flagged // symbol of name `export=` which needs to be handled like an alias. It's not great, but it is what it is. - if (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property | SymbolFlags.Accessor) + if ( + symbol.flags + & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property + | SymbolFlags.Accessor) && symbol.escapedName !== InternalSymbolName.ExportEquals && !(symbol.flags & SymbolFlags.Prototype) && !(symbol.flags & SymbolFlags.Class) && !(symbol.flags & SymbolFlags.Method) - && !isConstMergedWithNSPrintableAsSignatureMerge) { + && !isConstMergedWithNSPrintableAsSignatureMerge + ) { if (propertyAsAlias) { const createdExport = serializeMaybeAliasAssignment(symbol); if (createdExport) { @@ -8735,7 +11297,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { const type = getTypeOfSymbol(symbol); const localName = getInternalSymbolName(symbol, symbolName); - if (!(symbol.flags & SymbolFlags.Function) && isTypeRepresentableAsFunctionNamespaceMerge(type, symbol)) { + if ( + !(symbol.flags & SymbolFlags.Function) + && isTypeRepresentableAsFunctionNamespaceMerge(type, symbol) + ) { // If the type looks like a function declaration + ns could represent it, and it's type is sourced locally, rewrite it into a function declaration + ns serializeAsFunctionNamespaceMerge(type, symbol, localName, modifierFlags); } @@ -8747,32 +11312,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? NodeFlags.Const // exports are immutable in es6, which is what we emulate and check; so it's safe to mark all exports as `const` (there's no difference to consumers, but it allows unique symbol type declarations) : undefined : isConstantVariable(symbol) - ? NodeFlags.Const - : NodeFlags.Let; - const name = (needsPostExportDefault || !(symbol.flags & SymbolFlags.Property)) ? localName : getUnusedName(localName, symbol); - let textRange: Node | undefined = symbol.declarations && find(symbol.declarations, d => isVariableDeclaration(d)); - if (textRange && isVariableDeclarationList(textRange.parent) && textRange.parent.declarations.length === 1) { + ? NodeFlags.Const + : NodeFlags.Let; + const name = (needsPostExportDefault || !(symbol.flags & SymbolFlags.Property)) ? localName + : getUnusedName(localName, symbol); + let textRange: Node | undefined = symbol.declarations + && find(symbol.declarations, d => isVariableDeclaration(d)); + if ( + textRange && isVariableDeclarationList(textRange.parent) + && textRange.parent.declarations.length === 1 + ) { textRange = textRange.parent.parent; } const propertyAccessRequire = symbol.declarations?.find(isPropertyAccessExpression); - if (propertyAccessRequire && isBinaryExpression(propertyAccessRequire.parent) && isIdentifier(propertyAccessRequire.parent.right) - && type.symbol?.valueDeclaration && isSourceFile(type.symbol.valueDeclaration)) { - const alias = localName === propertyAccessRequire.parent.right.escapedText ? undefined : propertyAccessRequire.parent.right; + if ( + propertyAccessRequire && isBinaryExpression(propertyAccessRequire.parent) + && isIdentifier(propertyAccessRequire.parent.right) + && type.symbol?.valueDeclaration && isSourceFile(type.symbol.valueDeclaration) + ) { + const alias = localName === propertyAccessRequire.parent.right.escapedText ? undefined + : propertyAccessRequire.parent.right; addResult( factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, alias, localName)]) + factory.createNamedExports([ + factory.createExportSpecifier(/*isTypeOnly*/ false, alias, localName), + ]), ), - ModifierFlags.None + ModifierFlags.None, + ); + context.tracker.trackSymbol( + type.symbol, + context.enclosingDeclaration, + SymbolFlags.Value, ); - context.tracker.trackSymbol(type.symbol, context.enclosingDeclaration, SymbolFlags.Value); } else { - const statement = setTextRange(factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([ - factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, serializeTypeForDeclaration(context, type, symbol, enclosingDeclaration, includePrivateSymbol, bundled)) - ], flags)), textRange); - addResult(statement, name !== localName ? modifierFlags & ~ModifierFlags.Export : modifierFlags); + const statement = setTextRange( + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration( + name, + /*exclamationToken*/ undefined, + serializeTypeForDeclaration( + context, + type, + symbol, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), + ), + ], flags), + ), + textRange, + ); + addResult( + statement, + name !== localName ? modifierFlags & ~ModifierFlags.Export : modifierFlags, + ); if (name !== localName && !isPrivate) { // We rename the variable declaration we generate for Property symbols since they may have a name which // conflicts with a local declaration. For example, given input: @@ -8799,9 +11399,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, name, localName)]) + factory.createNamedExports([ + factory.createExportSpecifier(/*isTypeOnly*/ false, name, localName), + ]), ), - ModifierFlags.None + ModifierFlags.None, ); needsExportDeclaration = false; needsPostExportDefault = false; @@ -8814,10 +11416,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { serializeEnum(symbol, symbolName, modifierFlags); } if (symbol.flags & SymbolFlags.Class) { - if (symbol.flags & SymbolFlags.Property + if ( + symbol.flags & SymbolFlags.Property && symbol.valueDeclaration && isBinaryExpression(symbol.valueDeclaration.parent) - && isClassExpression(symbol.valueDeclaration.parent.right)) { + && isClassExpression(symbol.valueDeclaration.parent.right) + ) { // Looks like a `module.exports.Sub = class {}` - if we serialize `symbol` as a class, the result will have no members, // since the classiness is actually from the target of the effective alias the symbol is. yes. A BlockScopedVariable|Class|Property // _really_ acts like an Alias, and none of a BlockScopedVariable, Class, or Property. This is the travesty of JS binding today. @@ -8827,7 +11431,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { serializeAsClass(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags); } } - if ((symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && (!isConstMergedWithNS || isTypeOnlyNamespace(symbol))) || isConstMergedWithNSPrintableAsSignatureMerge) { + if ( + (symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) + && (!isConstMergedWithNS || isTypeOnlyNamespace(symbol))) + || isConstMergedWithNSPrintableAsSignatureMerge + ) { serializeModule(symbol, symbolName, modifierFlags); } // The class meaning serialization should handle serializing all interface members @@ -8845,21 +11453,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Straightforward - only one thing to do - make an export declaration if (symbol.declarations) { for (const node of symbol.declarations) { - const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!); + const resolvedModule = resolveExternalModuleName( + node, + (node as ExportDeclaration).moduleSpecifier!, + ); if (!resolvedModule) continue; - addResult(factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ (node as ExportDeclaration).isTypeOnly, /*exportClause*/ undefined, factory.createStringLiteral(getSpecifierForModuleSymbol(resolvedModule, context))), ModifierFlags.None); + addResult( + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ (node as ExportDeclaration).isTypeOnly, + /*exportClause*/ undefined, + factory.createStringLiteral(getSpecifierForModuleSymbol(resolvedModule, context)), + ), + ModifierFlags.None, + ); } } } if (needsPostExportDefault) { - addResult(factory.createExportAssignment(/*modifiers*/ undefined, /*isExportEquals*/ false, factory.createIdentifier(getInternalSymbolName(symbol, symbolName))), ModifierFlags.None); + addResult( + factory.createExportAssignment( + /*modifiers*/ undefined, + /*isExportEquals*/ false, + factory.createIdentifier(getInternalSymbolName(symbol, symbolName)), + ), + ModifierFlags.None, + ); } else if (needsExportDeclaration) { - addResult(factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, getInternalSymbolName(symbol, symbolName), symbolName)]) - ), ModifierFlags.None); + addResult( + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + getInternalSymbolName(symbol, symbolName), + symbolName, + ), + ]), + ), + ModifierFlags.None, + ); } } @@ -8872,39 +11507,52 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // will throw a wrench in this, since those may have been nested, but we'll need to synthesize them in the outer scope // anyway, as that's the only place the import they translate to is valid. In such a case, we might need to use a unique name // for the moved import; which hopefully the above `getUnusedName` call should produce. - const isExternalImportAlias = !!(symbol.flags & SymbolFlags.Alias) && !some(symbol.declarations, d => - !!findAncestor(d, isExportDeclaration) || - isNamespaceExport(d) || - (isImportEqualsDeclaration(d) && !isExternalModuleReference(d.moduleReference)) + const isExternalImportAlias = !!(symbol.flags & SymbolFlags.Alias) + && !some(symbol.declarations, d => + !!findAncestor(d, isExportDeclaration) + || isNamespaceExport(d) + || (isImportEqualsDeclaration(d) && !isExternalModuleReference(d.moduleReference))); + deferredPrivatesStack[isExternalImportAlias ? 0 : (deferredPrivatesStack.length - 1)].set( + getSymbolId(symbol), + symbol, ); - deferredPrivatesStack[isExternalImportAlias ? 0 : (deferredPrivatesStack.length - 1)].set(getSymbolId(symbol), symbol); } function isExportingScope(enclosingDeclaration: Node) { - return ((isSourceFile(enclosingDeclaration) && (isExternalOrCommonJsModule(enclosingDeclaration) || isJsonSourceFile(enclosingDeclaration))) || - (isAmbientModule(enclosingDeclaration) && !isGlobalScopeAugmentation(enclosingDeclaration))); + return ((isSourceFile(enclosingDeclaration) + && (isExternalOrCommonJsModule(enclosingDeclaration) || isJsonSourceFile(enclosingDeclaration))) + || (isAmbientModule(enclosingDeclaration) && !isGlobalScopeAugmentation(enclosingDeclaration))); } // Prepends a `declare` and/or `export` modifier if the context requires it, and then adds `node` to `result` and returns `node` function addResult(node: Statement, additionalModifierFlags: ModifierFlags) { if (canHaveModifiers(node)) { let newModifierFlags: ModifierFlags = ModifierFlags.None; - const enclosingDeclaration = context.enclosingDeclaration && - (isJSDocTypeAlias(context.enclosingDeclaration) ? getSourceFileOfNode(context.enclosingDeclaration) : context.enclosingDeclaration); - if (additionalModifierFlags & ModifierFlags.Export && - enclosingDeclaration && (isExportingScope(enclosingDeclaration) || isModuleDeclaration(enclosingDeclaration)) && - canHaveExportModifier(node) + const enclosingDeclaration = context.enclosingDeclaration + && (isJSDocTypeAlias(context.enclosingDeclaration) + ? getSourceFileOfNode(context.enclosingDeclaration) : context.enclosingDeclaration); + if ( + additionalModifierFlags & ModifierFlags.Export + && enclosingDeclaration + && (isExportingScope(enclosingDeclaration) || isModuleDeclaration(enclosingDeclaration)) + && canHaveExportModifier(node) ) { // Classes, namespaces, variables, functions, interfaces, and types should all be `export`ed in a module context if not private newModifierFlags |= ModifierFlags.Export; } - if (addingDeclare && !(newModifierFlags & ModifierFlags.Export) && - (!enclosingDeclaration || !(enclosingDeclaration.flags & NodeFlags.Ambient)) && - (isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node) || isModuleDeclaration(node))) { + if ( + addingDeclare && !(newModifierFlags & ModifierFlags.Export) + && (!enclosingDeclaration || !(enclosingDeclaration.flags & NodeFlags.Ambient)) + && (isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) + || isClassDeclaration(node) || isModuleDeclaration(node)) + ) { // Classes, namespaces, variables, enums, and functions all need `declare` modifiers to be valid in a declaration file top-level scope newModifierFlags |= ModifierFlags.Ambient; } - if ((additionalModifierFlags & ModifierFlags.Default) && (isClassDeclaration(node) || isInterfaceDeclaration(node) || isFunctionDeclaration(node))) { + if ( + (additionalModifierFlags & ModifierFlags.Default) + && (isClassDeclaration(node) || isInterfaceDeclaration(node) || isFunctionDeclaration(node)) + ) { newModifierFlags |= ModifierFlags.Default; } if (newModifierFlags) { @@ -8919,19 +11567,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeParams = getSymbolLinks(symbol).typeParameters; const typeParamDecls = map(typeParams, p => typeParameterToDeclaration(p, context)); const jsdocAliasDecl = symbol.declarations?.find(isJSDocTypeAlias); - const commentText = getTextOfJSDocComment(jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined); + const commentText = getTextOfJSDocComment( + jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined, + ); const oldFlags = context.flags; context.flags |= NodeBuilderFlags.InTypeAlias; const oldEnclosingDecl = context.enclosingDeclaration; context.enclosingDeclaration = jsdocAliasDecl; const typeNode = jsdocAliasDecl && jsdocAliasDecl.typeExpression - && isJSDocTypeExpression(jsdocAliasDecl.typeExpression) - && serializeExistingTypeNode(context, jsdocAliasDecl.typeExpression.type, includePrivateSymbol, bundled) + && isJSDocTypeExpression(jsdocAliasDecl.typeExpression) + && serializeExistingTypeNode( + context, + jsdocAliasDecl.typeExpression.type, + includePrivateSymbol, + bundled, + ) || typeToTypeNodeHelper(aliasType, context); - addResult(setSyntheticLeadingComments( - factory.createTypeAliasDeclaration(/*modifiers*/ undefined, getInternalSymbolName(symbol, symbolName), typeParamDecls, typeNode), - !commentText ? [] : [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }] - ), modifierFlags); + addResult( + setSyntheticLeadingComments( + factory.createTypeAliasDeclaration( + /*modifiers*/ undefined, + getInternalSymbolName(symbol, symbolName), + typeParamDecls, + typeNode, + ), + !commentText ? [] + : [{ + kind: SyntaxKind.MultiLineCommentTrivia, + text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }], + ), + modifierFlags, + ); context.flags = oldFlags; context.enclosingDeclaration = oldEnclosingDecl; } @@ -8942,28 +11612,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeParamDecls = map(localParams, p => typeParameterToDeclaration(p, context)); const baseTypes = getBaseTypes(interfaceType); const baseType = length(baseTypes) ? getIntersectionType(baseTypes) : undefined; - const members = flatMap(getPropertiesOfType(interfaceType), p => serializePropertySymbolForInterface(p, baseType)); - const callSignatures = serializeSignatures(SignatureKind.Call, interfaceType, baseType, SyntaxKind.CallSignature) as CallSignatureDeclaration[]; - const constructSignatures = serializeSignatures(SignatureKind.Construct, interfaceType, baseType, SyntaxKind.ConstructSignature) as ConstructSignatureDeclaration[]; + const members = flatMap( + getPropertiesOfType(interfaceType), + p => serializePropertySymbolForInterface(p, baseType), + ); + const callSignatures = serializeSignatures( + SignatureKind.Call, + interfaceType, + baseType, + SyntaxKind.CallSignature, + ) as CallSignatureDeclaration[]; + const constructSignatures = serializeSignatures( + SignatureKind.Construct, + interfaceType, + baseType, + SyntaxKind.ConstructSignature, + ) as ConstructSignatureDeclaration[]; const indexSignatures = serializeIndexSignatures(interfaceType, baseType); - const heritageClauses = !length(baseTypes) ? undefined : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, mapDefined(baseTypes, b => trySerializeAsTypeReference(b, SymbolFlags.Value)))]; - addResult(factory.createInterfaceDeclaration( - /*modifiers*/ undefined, - getInternalSymbolName(symbol, symbolName), - typeParamDecls, - heritageClauses, - [...indexSignatures, ...constructSignatures, ...callSignatures, ...members] - ), modifierFlags); + const heritageClauses = !length(baseTypes) ? undefined + : [factory.createHeritageClause( + SyntaxKind.ExtendsKeyword, + mapDefined(baseTypes, b => trySerializeAsTypeReference(b, SymbolFlags.Value)), + )]; + addResult( + factory.createInterfaceDeclaration( + /*modifiers*/ undefined, + getInternalSymbolName(symbol, symbolName), + typeParamDecls, + heritageClauses, + [...indexSignatures, ...constructSignatures, ...callSignatures, ...members], + ), + modifierFlags, + ); } function getNamespaceMembersForSerialization(symbol: Symbol) { const exports = getExportsOfSymbol(symbol); - return !exports ? [] : filter(arrayFrom(exports.values()), m => isNamespaceMember(m) && isIdentifierText(m.escapedName as string, ScriptTarget.ESNext)); + return !exports ? [] + : filter( + arrayFrom(exports.values()), + m => isNamespaceMember(m) && isIdentifierText(m.escapedName as string, ScriptTarget.ESNext), + ); } function isTypeOnlyNamespace(symbol: Symbol) { - return every(getNamespaceMembersForSerialization(symbol), m => !(getSymbolFlags(resolveSymbol(m)) & SymbolFlags.Value)); + return every( + getNamespaceMembersForSerialization(symbol), + m => !(getSymbolFlags(resolveSymbol(m)) & SymbolFlags.Value), + ); } function serializeModule(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { @@ -8977,7 +11674,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // so we don't even have placeholders to fill in. if (length(realMembers)) { const localName = getInternalSymbolName(symbol, symbolName); - serializeAsNamespaceDeclaration(realMembers, localName, modifierFlags, !!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Assignment))); + serializeAsNamespaceDeclaration( + realMembers, + localName, + modifierFlags, + !!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Assignment)), + ); } if (length(mergedMembers)) { const containingFile = getSourceFileOfNode(context.enclosingDeclaration); @@ -8985,63 +11687,118 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const nsBody = factory.createModuleBlock([factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(mapDefined(filter(mergedMembers, n => n.escapedName !== InternalSymbolName.ExportEquals), s => { - const name = unescapeLeadingUnderscores(s.escapedName); - const localName = getInternalSymbolName(s, name); - const aliasDecl = s.declarations && getDeclarationOfAliasSymbol(s); - if (containingFile && (aliasDecl ? containingFile !== getSourceFileOfNode(aliasDecl) : !some(s.declarations, d => getSourceFileOfNode(d) === containingFile))) { - context.tracker?.reportNonlocalAugmentation?.(containingFile, symbol, s); - return undefined; - } - const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); - includePrivateSymbol(target || s); - const targetName = target ? getInternalSymbolName(target, unescapeLeadingUnderscores(target.escapedName)) : localName; - return factory.createExportSpecifier(/*isTypeOnly*/ false, name === targetName ? undefined : targetName, name); - })) + factory.createNamedExports( + mapDefined( + filter(mergedMembers, n => n.escapedName !== InternalSymbolName.ExportEquals), + s => { + const name = unescapeLeadingUnderscores(s.escapedName); + const localName = getInternalSymbolName(s, name); + const aliasDecl = s.declarations && getDeclarationOfAliasSymbol(s); + if ( + containingFile + && (aliasDecl ? containingFile !== getSourceFileOfNode(aliasDecl) + : !some(s.declarations, d => getSourceFileOfNode(d) === containingFile)) + ) { + context.tracker?.reportNonlocalAugmentation?.(containingFile, symbol, s); + return undefined; + } + const target = aliasDecl + && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); + includePrivateSymbol(target || s); + const targetName = target + ? getInternalSymbolName(target, unescapeLeadingUnderscores(target.escapedName)) + : localName; + return factory.createExportSpecifier( + /*isTypeOnly*/ false, + name === targetName ? undefined : targetName, + name, + ); + }, + ), + ), )]); - addResult(factory.createModuleDeclaration( - /*modifiers*/ undefined, - factory.createIdentifier(localName), - nsBody, - NodeFlags.Namespace - ), ModifierFlags.None); + addResult( + factory.createModuleDeclaration( + /*modifiers*/ undefined, + factory.createIdentifier(localName), + nsBody, + NodeFlags.Namespace, + ), + ModifierFlags.None, + ); } } function serializeEnum(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { - addResult(factory.createEnumDeclaration( - factory.createModifiersFromModifierFlags(isConstEnumSymbol(symbol) ? ModifierFlags.Const : 0), - getInternalSymbolName(symbol, symbolName), - map(filter(getPropertiesOfType(getTypeOfSymbol(symbol)), p => !!(p.flags & SymbolFlags.EnumMember)), p => { - // TODO: Handle computed names - // I hate that to get the initialized value we need to walk back to the declarations here; but there's no - // other way to get the possible const value of an enum member that I'm aware of, as the value is cached - // _on the declaration_, not on the declaration's symbol... - const initializedValue = p.declarations && p.declarations[0] && isEnumMember(p.declarations[0]) ? getConstantValue(p.declarations[0]) : undefined; - return factory.createEnumMember(unescapeLeadingUnderscores(p.escapedName), initializedValue === undefined ? undefined : - typeof initializedValue === "string" ? factory.createStringLiteral(initializedValue) : - factory.createNumericLiteral(initializedValue)); - }) - ), modifierFlags); - } - - function serializeAsFunctionNamespaceMerge(type: Type, symbol: Symbol, localName: string, modifierFlags: ModifierFlags) { + addResult( + factory.createEnumDeclaration( + factory.createModifiersFromModifierFlags(isConstEnumSymbol(symbol) ? ModifierFlags.Const : 0), + getInternalSymbolName(symbol, symbolName), + map( + filter( + getPropertiesOfType(getTypeOfSymbol(symbol)), + p => !!(p.flags & SymbolFlags.EnumMember), + ), + p => { + // TODO: Handle computed names + // I hate that to get the initialized value we need to walk back to the declarations here; but there's no + // other way to get the possible const value of an enum member that I'm aware of, as the value is cached + // _on the declaration_, not on the declaration's symbol... + const initializedValue = + p.declarations && p.declarations[0] && isEnumMember(p.declarations[0]) + ? getConstantValue(p.declarations[0]) : undefined; + return factory.createEnumMember( + unescapeLeadingUnderscores(p.escapedName), + initializedValue === undefined ? undefined + : typeof initializedValue === "string" + ? factory.createStringLiteral(initializedValue) + : factory.createNumericLiteral(initializedValue), + ); + }, + ), + ), + modifierFlags, + ); + } + + function serializeAsFunctionNamespaceMerge( + type: Type, + symbol: Symbol, + localName: string, + modifierFlags: ModifierFlags, + ) { const signatures = getSignaturesOfType(type, SignatureKind.Call); for (const sig of signatures) { // Each overload becomes a separate function declaration, in order - const decl = signatureToSignatureDeclarationHelper(sig, SyntaxKind.FunctionDeclaration, context, { name: factory.createIdentifier(localName), privateSymbolVisitor: includePrivateSymbol, bundledImports: bundled }) as FunctionDeclaration; + const decl = signatureToSignatureDeclarationHelper(sig, SyntaxKind.FunctionDeclaration, context, { + name: factory.createIdentifier(localName), + privateSymbolVisitor: includePrivateSymbol, + bundledImports: bundled, + }) as FunctionDeclaration; addResult(setTextRange(decl, getSignatureTextRangeLocation(sig)), modifierFlags); } // Module symbol emit will take care of module-y members, provided it has exports - if (!(symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && !!symbol.exports && !!symbol.exports.size)) { + if ( + !(symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && !!symbol.exports + && !!symbol.exports.size) + ) { const props = filter(getPropertiesOfType(type), isNamespaceMember); - serializeAsNamespaceDeclaration(props, localName, modifierFlags, /*suppressNewPrivateContext*/ true); + serializeAsNamespaceDeclaration( + props, + localName, + modifierFlags, + /*suppressNewPrivateContext*/ true, + ); } } function getSignatureTextRangeLocation(signature: Signature) { if (signature.declaration && signature.declaration.parent) { - if (isBinaryExpression(signature.declaration.parent) && getAssignmentDeclarationKind(signature.declaration.parent) === AssignmentDeclarationKind.Property) { + if ( + isBinaryExpression(signature.declaration.parent) + && getAssignmentDeclarationKind(signature.declaration.parent) + === AssignmentDeclarationKind.Property + ) { return signature.declaration.parent; } // for expressions assigned to `var`s, use the `var` as the text range @@ -9052,12 +11809,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return signature.declaration; } - function serializeAsNamespaceDeclaration(props: readonly Symbol[], localName: string, modifierFlags: ModifierFlags, suppressNewPrivateContext: boolean) { + function serializeAsNamespaceDeclaration( + props: readonly Symbol[], + localName: string, + modifierFlags: ModifierFlags, + suppressNewPrivateContext: boolean, + ) { if (length(props)) { - const localVsRemoteMap = arrayToMultiMap(props, p => - !length(p.declarations) || some(p.declarations, d => - getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!) - ) ? "local" : "remote" + const localVsRemoteMap = arrayToMultiMap( + props, + p => !length(p.declarations) + || some( + p.declarations, + d => getSourceFileOfNode(d) === getSourceFileOfNode(context.enclosingDeclaration!), + ) ? "local" + : "remote", ); const localProps = localVsRemoteMap.get("local") || emptyArray; // handle remote props first - we need to make an `import` declaration that points at the module containing each remote @@ -9077,7 +11843,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Add a namespace // Create namespace as non-synthetic so it is usable as an enclosing declaration - let fakespace = parseNodeFactory.createModuleDeclaration(/*modifiers*/ undefined, factory.createIdentifier(localName), factory.createModuleBlock([]), NodeFlags.Namespace); + let fakespace = parseNodeFactory.createModuleDeclaration( + /*modifiers*/ undefined, + factory.createIdentifier(localName), + factory.createModuleBlock([]), + NodeFlags.Namespace, + ); setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration); fakespace.locals = createSymbolTable(props); fakespace.symbol = props[0].parent!; @@ -9090,33 +11861,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const oldContext = context; context = subcontext; // TODO: implement handling for the localVsRemoteMap.get("remote") - should be difficult to trigger (see comment above), as only interesting cross-file js merges should make this possible - visitSymbolTable(createSymbolTable(localProps), suppressNewPrivateContext, /*propertyAsAlias*/ true); + visitSymbolTable( + createSymbolTable(localProps), + suppressNewPrivateContext, + /*propertyAsAlias*/ true, + ); context = oldContext; addingDeclare = oldAddingDeclare; const declarations = results; results = oldResults; // replace namespace with synthetic version - const defaultReplaced = map(declarations, d => isExportAssignment(d) && !d.isExportEquals && isIdentifier(d.expression) ? factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, d.expression, factory.createIdentifier(InternalSymbolName.Default))]) - ) : d); - const exportModifierStripped = every(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export)) ? map(defaultReplaced as Extract[], removeExportModifier) : defaultReplaced; + const defaultReplaced = map( + declarations, + d => isExportAssignment(d) && !d.isExportEquals && isIdentifier(d.expression) + ? factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + d.expression, + factory.createIdentifier(InternalSymbolName.Default), + ), + ]), + ) : d, + ); + const exportModifierStripped = every(defaultReplaced, d => + hasSyntacticModifier(d, ModifierFlags.Export)) + ? map(defaultReplaced as Extract[], removeExportModifier) + : defaultReplaced; fakespace = factory.updateModuleDeclaration( fakespace, fakespace.modifiers, fakespace.name, - factory.createModuleBlock(exportModifierStripped)); + factory.createModuleBlock(exportModifierStripped), + ); addResult(fakespace, modifierFlags); // namespaces can never be default exported } } function isNamespaceMember(p: Symbol) { - return !!(p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias)) || - !(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" || p.valueDeclaration && isStatic(p.valueDeclaration) && isClassLike(p.valueDeclaration.parent)); + return !!(p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias)) + || !(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" + || p.valueDeclaration && isStatic(p.valueDeclaration) + && isClassLike(p.valueDeclaration.parent)); } - function sanitizeJSDocImplements(clauses: readonly ExpressionWithTypeArguments[]): ExpressionWithTypeArguments[] | undefined { + function sanitizeJSDocImplements( + clauses: readonly ExpressionWithTypeArguments[], + ): ExpressionWithTypeArguments[] | undefined { const result = mapDefined(clauses, e => { const oldEnclosing = context.enclosingDeclaration; context.enclosingDeclaration = e; @@ -9126,16 +11919,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return cleanup(/*result*/ undefined); // Empty heritage clause, should be an error, but prefer emitting no heritage clauses to reemitting the empty one } let introducesError: boolean; - ({ introducesError, node: expr } = trackExistingEntityName(expr, context, includePrivateSymbol)); + ({ introducesError, node: expr } = trackExistingEntityName( + expr, + context, + includePrivateSymbol, + )); if (introducesError) { return cleanup(/*result*/ undefined); } } - return cleanup(factory.createExpressionWithTypeArguments(expr, + return cleanup(factory.createExpressionWithTypeArguments( + expr, map(e.typeArguments, a => serializeExistingTypeNode(context, a, includePrivateSymbol, bundled) - || typeToTypeNodeHelper(getTypeFromTypeNode(a), context) - ) + || typeToTypeNodeHelper(getTypeFromTypeNode(a), context)), )); function cleanup(result: T): T { @@ -9161,13 +11958,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const implementsExpressions = originalImplements && sanitizeJSDocImplements(originalImplements) || mapDefined(getImplementsTypes(classType), serializeImplementedType); const staticType = getTypeOfSymbol(symbol); - const isClass = !!staticType.symbol?.valueDeclaration && isClassLike(staticType.symbol.valueDeclaration); + const isClass = !!staticType.symbol?.valueDeclaration + && isClassLike(staticType.symbol.valueDeclaration); const staticBaseType = isClass ? getBaseConstructorTypeOfClass(staticType as InterfaceType) : anyType; const heritageClauses = [ - ...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))], - ...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)] + ...!length(baseTypes) ? [] + : [factory.createHeritageClause( + SyntaxKind.ExtendsKeyword, + map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)), + )], + ...!length(implementsExpressions) ? [] + : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)], ]; const symbolProps = getNonInheritedProperties(classType, baseTypes, getPropertiesOfType(classType)); const publicSymbolProps = filter(symbolProps, s => { @@ -9185,40 +11988,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!valueDecl && isNamedDeclaration(valueDecl) && isPrivateIdentifier(valueDecl.name); }); // Boil down all private properties into a single one. - const privateProperties = hasPrivateIdentifier ? - [factory.createPropertyDeclaration( + const privateProperties = hasPrivateIdentifier + ? [factory.createPropertyDeclaration( /*modifiers*/ undefined, factory.createPrivateIdentifier("#private"), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined, - )] : - emptyArray; - const publicProperties = flatMap(publicSymbolProps, p => serializePropertySymbolForClass(p, /*isStatic*/ false, baseTypes[0])); + )] + : emptyArray; + const publicProperties = flatMap( + publicSymbolProps, + p => serializePropertySymbolForClass(p, /*isStatic*/ false, baseTypes[0]), + ); // Consider static members empty if symbol also has function or module meaning - function namespacey emit will handle statics const staticMembers = flatMap( - filter(getPropertiesOfType(staticType), p => !(p.flags & SymbolFlags.Prototype) && p.escapedName !== "prototype" && !isNamespaceMember(p)), - p => serializePropertySymbolForClass(p, /*isStatic*/ true, staticBaseType)); + filter( + getPropertiesOfType(staticType), + p => !(p.flags & SymbolFlags.Prototype) && p.escapedName !== "prototype" + && !isNamespaceMember(p), + ), + p => serializePropertySymbolForClass(p, /*isStatic*/ true, staticBaseType), + ); // When we encounter an `X.prototype.y` assignment in a JS file, we bind `X` as a class regardless as to whether // the value is ever initialized with a class or function-like value. For cases where `X` could never be // created via `new`, we will inject a `private constructor()` declaration to indicate it is not createable. - const isNonConstructableClassLikeInJsFile = - !isClass && - !!symbol.valueDeclaration && - isInJSFile(symbol.valueDeclaration) && - !some(getSignaturesOfType(staticType, SignatureKind.Construct)); - const constructors = isNonConstructableClassLikeInJsFile ? - [factory.createConstructorDeclaration(factory.createModifiersFromModifierFlags(ModifierFlags.Private), [], /*body*/ undefined)] : - serializeSignatures(SignatureKind.Construct, staticType, staticBaseType, SyntaxKind.Constructor) as ConstructorDeclaration[]; + const isNonConstructableClassLikeInJsFile = !isClass + && !!symbol.valueDeclaration + && isInJSFile(symbol.valueDeclaration) + && !some(getSignaturesOfType(staticType, SignatureKind.Construct)); + const constructors = isNonConstructableClassLikeInJsFile + ? [factory.createConstructorDeclaration( + factory.createModifiersFromModifierFlags(ModifierFlags.Private), + [], + /*body*/ undefined, + )] + : serializeSignatures( + SignatureKind.Construct, + staticType, + staticBaseType, + SyntaxKind.Constructor, + ) as ConstructorDeclaration[]; const indexSignatures = serializeIndexSignatures(classType, baseTypes[0]); context.enclosingDeclaration = oldEnclosing; - addResult(setTextRange(factory.createClassDeclaration( - /*modifiers*/ undefined, - localName, - typeParamDecls, - heritageClauses, - [...indexSignatures, ...staticMembers, ...constructors, ...publicProperties, ...privateProperties] - ), symbol.declarations && filter(symbol.declarations, d => isClassDeclaration(d) || isClassExpression(d))[0]), modifierFlags); + addResult( + setTextRange( + factory.createClassDeclaration( + /*modifiers*/ undefined, + localName, + typeParamDecls, + heritageClauses, + [ + ...indexSignatures, + ...staticMembers, + ...constructors, + ...publicProperties, + ...privateProperties, + ], + ), + symbol.declarations + && filter(symbol.declarations, d => isClassDeclaration(d) || isClassExpression(d))[0], + ), + modifierFlags, + ); } function getSomeTargetNameFromDeclarations(declarations: Declaration[] | undefined) { @@ -9255,7 +12087,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // If `target` refers to a shorthand module symbol, the name we're trying to pull out isn;t recoverable from the target symbol // In such a scenario, we must fall back to looking for an alias declaration on `symbol` and pulling the target name from that - let verbatimTargetName = isShorthandAmbientModuleSymbol(target) && getSomeTargetNameFromDeclarations(symbol.declarations) || unescapeLeadingUnderscores(target.escapedName); + let verbatimTargetName = + isShorthandAmbientModuleSymbol(target) && getSomeTargetNameFromDeclarations(symbol.declarations) + || unescapeLeadingUnderscores(target.escapedName); if (verbatimTargetName === InternalSymbolName.ExportEquals && allowSyntheticDefaultImports) { // target refers to an `export=` symbol that was hoisted into a synthetic default - rename here to match verbatimTargetName = InternalSymbolName.Default; @@ -9268,27 +12102,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // const { SomeClass } = require('./lib'); const specifier = getSpecifierForModuleSymbol(target.parent || target, context); // './lib' const { propertyName } = node as BindingElement; - addResult(factory.createImportDeclaration( - /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamedImports([factory.createImportSpecifier( - /*isTypeOnly*/ false, - propertyName && isIdentifier(propertyName) ? factory.createIdentifier(idText(propertyName)) : undefined, - factory.createIdentifier(localName) - )])), - factory.createStringLiteral(specifier), - /*assertClause*/ undefined - ), ModifierFlags.None); + addResult( + factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause( + /*isTypeOnly*/ false, + /*name*/ undefined, + factory.createNamedImports([factory.createImportSpecifier( + /*isTypeOnly*/ false, + propertyName && isIdentifier(propertyName) + ? factory.createIdentifier(idText(propertyName)) : undefined, + factory.createIdentifier(localName), + )]), + ), + factory.createStringLiteral(specifier), + /*assertClause*/ undefined, + ), + ModifierFlags.None, + ); break; } // We don't know how to serialize this (nested?) binding element - Debug.failBadSyntaxKind(node.parent?.parent || node, "Unhandled binding element grandparent kind in declaration serialization"); + Debug.failBadSyntaxKind( + node.parent?.parent || node, + "Unhandled binding element grandparent kind in declaration serialization", + ); break; case SyntaxKind.ShorthandPropertyAssignment: if (node.parent?.parent?.kind === SyntaxKind.BinaryExpression) { // module.exports = { SomeClass } serializeExportSpecifier( unescapeLeadingUnderscores(symbol.escapedName), - targetName + targetName, ); } break; @@ -9300,95 +12145,137 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const uniqueName = factory.createUniqueName(localName); // _x const specifier = getSpecifierForModuleSymbol(target.parent || target, context); // 'y' // import _x = require('y'); - addResult(factory.createImportEqualsDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - uniqueName, - factory.createExternalModuleReference(factory.createStringLiteral(specifier)) - ), ModifierFlags.None); + addResult( + factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + uniqueName, + factory.createExternalModuleReference(factory.createStringLiteral(specifier)), + ), + ModifierFlags.None, + ); // import x = _x.z - addResult(factory.createImportEqualsDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createIdentifier(localName), - factory.createQualifiedName(uniqueName, initializer.name as Identifier), - ), modifierFlags); + addResult( + factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createIdentifier(localName), + factory.createQualifiedName(uniqueName, initializer.name as Identifier), + ), + modifierFlags, + ); break; } // else fall through and treat commonjs require just like import= case SyntaxKind.ImportEqualsDeclaration: // This _specifically_ only exists to handle json declarations - where we make aliases, but since // we emit no declarations for the json document, must not refer to it in the declarations - if (target.escapedName === InternalSymbolName.ExportEquals && some(target.declarations, d => isSourceFile(d) && isJsonSourceFile(d))) { + if ( + target.escapedName === InternalSymbolName.ExportEquals + && some(target.declarations, d => isSourceFile(d) && isJsonSourceFile(d)) + ) { serializeMaybeAliasAssignment(symbol); break; } // Could be a local `import localName = ns.member` or // an external `import localName = require("whatever")` const isLocalImport = !(target.flags & SymbolFlags.ValueModule) && !isVariableDeclaration(node); - addResult(factory.createImportEqualsDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createIdentifier(localName), - isLocalImport - ? symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) - : factory.createExternalModuleReference(factory.createStringLiteral(getSpecifierForModuleSymbol(target, context))) - ), isLocalImport ? modifierFlags : ModifierFlags.None); + addResult( + factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createIdentifier(localName), + isLocalImport + ? symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) + : factory.createExternalModuleReference( + factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)), + ), + ), + isLocalImport ? modifierFlags : ModifierFlags.None, + ); break; case SyntaxKind.NamespaceExportDeclaration: // export as namespace foo // TODO: Not part of a file's local or export symbol tables // Is bound into file.symbol.globalExports instead, which we don't currently traverse - addResult(factory.createNamespaceExportDeclaration(idText((node as NamespaceExportDeclaration).name)), ModifierFlags.None); + addResult( + factory.createNamespaceExportDeclaration(idText((node as NamespaceExportDeclaration).name)), + ModifierFlags.None, + ); break; case SyntaxKind.ImportClause: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects - const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportClause).parent.moduleSpecifier; - addResult(factory.createImportDeclaration( - /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, factory.createIdentifier(localName), /*namedBindings*/ undefined), - specifier, - (node as ImportClause).parent.assertClause - ), ModifierFlags.None); + const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) + : (node as ImportClause).parent.moduleSpecifier; + addResult( + factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause( + /*isTypeOnly*/ false, + factory.createIdentifier(localName), + /*namedBindings*/ undefined, + ), + specifier, + (node as ImportClause).parent.assertClause, + ), + ModifierFlags.None, + ); break; } case SyntaxKind.NamespaceImport: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects - const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as NamespaceImport).parent.parent.moduleSpecifier; - addResult(factory.createImportDeclaration( - /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))), - specifier, - (node as NamespaceImport).parent.parent.assertClause - ), ModifierFlags.None); + const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) + : (node as NamespaceImport).parent.parent.moduleSpecifier; + addResult( + factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause( + /*isTypeOnly*/ false, + /*name*/ undefined, + factory.createNamespaceImport(factory.createIdentifier(localName)), + ), + specifier, + (node as NamespaceImport).parent.parent.assertClause, + ), + ModifierFlags.None, + ); break; } case SyntaxKind.NamespaceExport: - addResult(factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamespaceExport(factory.createIdentifier(localName)), - factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)) - ), ModifierFlags.None); + addResult( + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamespaceExport(factory.createIdentifier(localName)), + factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)), + ), + ModifierFlags.None, + ); break; case SyntaxKind.ImportSpecifier: { const generatedSpecifier = getSpecifierForModuleSymbol(target.parent || target, context); // generate specifier (even though we're reusing and existing one) for ambient module reference include side effects - const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) : (node as ImportSpecifier).parent.parent.parent.moduleSpecifier; - addResult(factory.createImportDeclaration( - /*modifiers*/ undefined, - factory.createImportClause( - /*isTypeOnly*/ false, - /*name*/ undefined, - factory.createNamedImports([ - factory.createImportSpecifier( - /*isTypeOnly*/ false, - localName !== verbatimTargetName ? factory.createIdentifier(verbatimTargetName) : undefined, - factory.createIdentifier(localName) - ) - ])), - specifier, - (node as ImportSpecifier).parent.parent.parent.assertClause, - ), ModifierFlags.None); + const specifier = bundled ? factory.createStringLiteral(generatedSpecifier) + : (node as ImportSpecifier).parent.parent.parent.moduleSpecifier; + addResult( + factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause( + /*isTypeOnly*/ false, + /*name*/ undefined, + factory.createNamedImports([ + factory.createImportSpecifier( + /*isTypeOnly*/ false, + localName !== verbatimTargetName + ? factory.createIdentifier(verbatimTargetName) : undefined, + factory.createIdentifier(localName), + ), + ]), + ), + specifier, + (node as ImportSpecifier).parent.parent.parent.assertClause, + ), + ModifierFlags.None, + ); break; } case SyntaxKind.ExportSpecifier: @@ -9400,7 +12287,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { serializeExportSpecifier( unescapeLeadingUnderscores(symbol.escapedName), specifier ? verbatimTargetName : targetName, - specifier && isStringLiteralLike(specifier) ? factory.createStringLiteral(specifier.text) : undefined + specifier && isStringLiteralLike(specifier) ? factory.createStringLiteral(specifier.text) + : undefined, ); break; case SyntaxKind.ExportAssignment: @@ -9412,7 +12300,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Could be best encoded as though an export specifier or as though an export assignment // If name is default or export=, do an export assignment // Otherwise do an export specifier - if (symbol.escapedName === InternalSymbolName.Default || symbol.escapedName === InternalSymbolName.ExportEquals) { + if ( + symbol.escapedName === InternalSymbolName.Default + || symbol.escapedName === InternalSymbolName.ExportEquals + ) { serializeMaybeAliasAssignment(symbol); } else { @@ -9425,12 +12316,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function serializeExportSpecifier(localName: string, targetName: string, specifier?: Expression) { - addResult(factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, localName !== targetName ? targetName : undefined, localName)]), - specifier - ), ModifierFlags.None); + addResult( + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + localName !== targetName ? targetName : undefined, + localName, + ), + ]), + specifier, + ), + ModifierFlags.None, + ); } /** @@ -9451,13 +12351,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // serialize what the alias points to, preserve the declaration's initializer const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true); // If the target resolves and resolves to a thing defined in this file, emit as an alias, otherwise emit as a const - if (target && length(target.declarations) && some(target.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(enclosingDeclaration))) { + if ( + target && length(target.declarations) + && some( + target.declarations, + d => getSourceFileOfNode(d) === getSourceFileOfNode(enclosingDeclaration), + ) + ) { // In case `target` refers to a namespace member, look at the declaration and serialize the leftmost symbol in it // eg, `namespace A { export class B {} }; exports = A.B;` // Technically, this is all that's required in the case where the assignment is an entity name expression - const expr = aliasDecl && ((isExportAssignment(aliasDecl) || isBinaryExpression(aliasDecl)) ? getExportAssignmentExpression(aliasDecl) : getPropertyAssignmentAliasLikeExpression(aliasDecl as ShorthandPropertyAssignment | PropertyAssignment | PropertyAccessExpression)); - const first = expr && isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) : undefined; - const referenced = first && resolveEntityName(first, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, enclosingDeclaration); + const expr = aliasDecl + && ((isExportAssignment(aliasDecl) || isBinaryExpression(aliasDecl)) + ? getExportAssignmentExpression(aliasDecl) + : getPropertyAssignmentAliasLikeExpression( + aliasDecl as + | ShorthandPropertyAssignment + | PropertyAssignment + | PropertyAccessExpression, + )); + const first = expr && isEntityNameExpression(expr) ? getFirstNonModuleExportsIdentifier(expr) + : undefined; + const referenced = first + && resolveEntityName( + first, + SymbolFlags.All, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + enclosingDeclaration, + ); if (referenced || target) { includePrivateSymbol(referenced || target); } @@ -9473,7 +12395,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { results.push(factory.createExportAssignment( /*modifiers*/ undefined, isExportEquals, - symbolToExpression(target, context, SymbolFlags.All) + symbolToExpression(target, context, SymbolFlags.All), )); } else { @@ -9487,12 +12409,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { // serialize as `import _Ref = t.arg.et; export { _Ref as name }` const varName = getUnusedName(name, symbol); - addResult(factory.createImportEqualsDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createIdentifier(varName), - symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false) - ), ModifierFlags.None); + addResult( + factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createIdentifier(varName), + symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false), + ), + ModifierFlags.None, + ); serializeExportSpecifier(name, varName); } } @@ -9507,24 +12432,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeToSerialize = getWidenedType(getTypeOfSymbol(getMergedSymbol(symbol))); if (isTypeRepresentableAsFunctionNamespaceMerge(typeToSerialize, symbol)) { // If there are no index signatures and `typeToSerialize` is an object type, emit as a namespace instead of a const - serializeAsFunctionNamespaceMerge(typeToSerialize, symbol, varName, isExportAssignmentCompatibleSymbolName ? ModifierFlags.None : ModifierFlags.Export); + serializeAsFunctionNamespaceMerge( + typeToSerialize, + symbol, + varName, + isExportAssignmentCompatibleSymbolName ? ModifierFlags.None : ModifierFlags.Export, + ); } else { - const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([ - factory.createVariableDeclaration(varName, /*exclamationToken*/ undefined, serializeTypeForDeclaration(context, typeToSerialize, symbol, enclosingDeclaration, includePrivateSymbol, bundled)) - ], context.enclosingDeclaration?.kind === SyntaxKind.ModuleDeclaration ? NodeFlags.Let : NodeFlags.Const)); + const statement = factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + varName, + /*exclamationToken*/ undefined, + serializeTypeForDeclaration( + context, + typeToSerialize, + symbol, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), + ), + ], + context.enclosingDeclaration?.kind === SyntaxKind.ModuleDeclaration ? NodeFlags.Let + : NodeFlags.Const, + ), + ); // Inlined JSON types exported with [module.]exports= will already emit an export=, so should use `declare`. // Otherwise, the type itself should be exported. - addResult(statement, - target && target.flags & SymbolFlags.Property && target.escapedName === InternalSymbolName.ExportEquals ? ModifierFlags.Ambient - : name === varName ? ModifierFlags.Export - : ModifierFlags.None); + addResult( + statement, + target && target.flags & SymbolFlags.Property + && target.escapedName === InternalSymbolName.ExportEquals ? ModifierFlags.Ambient + : name === varName ? ModifierFlags.Export + : ModifierFlags.None, + ); } if (isExportAssignmentCompatibleSymbolName) { results.push(factory.createExportAssignment( /*modifiers*/ undefined, isExportEquals, - factory.createIdentifier(varName) + factory.createIdentifier(varName), )); return true; } @@ -9541,40 +12492,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // context source file, and whose property names are all valid identifiers and not late-bound, _and_ // whose input is not type annotated (if the input symbol has an annotation we can reuse, we should prefer it) const ctxSrc = getSourceFileOfNode(context.enclosingDeclaration); - return getObjectFlags(typeToSerialize) & (ObjectFlags.Anonymous | ObjectFlags.Mapped) && - !length(getIndexInfosOfType(typeToSerialize)) && - !isClassInstanceSide(typeToSerialize) && // While a class instance is potentially representable as a NS, prefer printing a reference to the instance type and serializing the class - !!(length(filter(getPropertiesOfType(typeToSerialize), isNamespaceMember)) || length(getSignaturesOfType(typeToSerialize, SignatureKind.Call))) && - !length(getSignaturesOfType(typeToSerialize, SignatureKind.Construct)) && // TODO: could probably serialize as function + ns + class, now that that's OK - !getDeclarationWithTypeAnnotation(hostSymbol, enclosingDeclaration) && - !(typeToSerialize.symbol && some(typeToSerialize.symbol.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) && - !some(getPropertiesOfType(typeToSerialize), p => isLateBoundName(p.escapedName)) && - !some(getPropertiesOfType(typeToSerialize), p => some(p.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) && - every(getPropertiesOfType(typeToSerialize), p => isIdentifierText(symbolName(p), languageVersion)); - } - - function makeSerializePropertySymbol(createProperty: ( - modifiers: readonly Modifier[] | undefined, - name: string | PropertyName, - questionOrExclamationToken: QuestionToken | undefined, - type: TypeNode | undefined, - initializer: Expression | undefined - ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: true): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => (T | AccessorDeclaration | (T | AccessorDeclaration)[]); - function makeSerializePropertySymbol(createProperty: ( - modifiers: readonly Modifier[] | undefined, - name: string | PropertyName, - questionOrExclamationToken: QuestionToken | undefined, - type: TypeNode | undefined, - initializer: Expression | undefined - ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: false): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => (T | T[]); - function makeSerializePropertySymbol(createProperty: ( - modifiers: readonly Modifier[] | undefined, - name: string | PropertyName, - questionOrExclamationToken: QuestionToken | undefined, - type: TypeNode | undefined, - initializer: Expression | undefined - ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: boolean): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => (T | AccessorDeclaration | (T | AccessorDeclaration)[]) { - return function serializePropertySymbol(p: Symbol, isStatic: boolean, baseType: Type | undefined): (T | AccessorDeclaration | (T | AccessorDeclaration)[]) { + return getObjectFlags(typeToSerialize) & (ObjectFlags.Anonymous | ObjectFlags.Mapped) + && !length(getIndexInfosOfType(typeToSerialize)) + && !isClassInstanceSide(typeToSerialize) // While a class instance is potentially representable as a NS, prefer printing a reference to the instance type and serializing the class + && !!(length(filter(getPropertiesOfType(typeToSerialize), isNamespaceMember)) + || length(getSignaturesOfType(typeToSerialize, SignatureKind.Call))) + && !length(getSignaturesOfType(typeToSerialize, SignatureKind.Construct)) // TODO: could probably serialize as function + ns + class, now that that's OK + && !getDeclarationWithTypeAnnotation(hostSymbol, enclosingDeclaration) + && !(typeToSerialize.symbol + && some(typeToSerialize.symbol.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) + && !some(getPropertiesOfType(typeToSerialize), p => isLateBoundName(p.escapedName)) + && !some( + getPropertiesOfType(typeToSerialize), + p => some(p.declarations, d => getSourceFileOfNode(d) !== ctxSrc), + ) + && every( + getPropertiesOfType(typeToSerialize), + p => isIdentifierText(symbolName(p), languageVersion), + ); + } + + function makeSerializePropertySymbol( + createProperty: ( + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) => T, + methodKind: SignatureDeclaration["kind"], + useAccessors: true, + ): ( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined, + ) => T | AccessorDeclaration | (T | AccessorDeclaration)[]; + function makeSerializePropertySymbol( + createProperty: ( + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) => T, + methodKind: SignatureDeclaration["kind"], + useAccessors: false, + ): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => T | T[]; + function makeSerializePropertySymbol( + createProperty: ( + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) => T, + methodKind: SignatureDeclaration["kind"], + useAccessors: boolean, + ): ( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined, + ) => T | AccessorDeclaration | (T | AccessorDeclaration)[] { + return function serializePropertySymbol( + p: Symbol, + isStatic: boolean, + baseType: Type | undefined, + ): T | AccessorDeclaration | (T | AccessorDeclaration)[] { const modifierFlags = getDeclarationModifierFlagsFromSymbol(p); const isPrivate = !!(modifierFlags & ModifierFlags.Private); if (isStatic && (p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias))) { @@ -9582,68 +12565,125 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // need to be merged namespace members return []; } - if (p.flags & SymbolFlags.Prototype || p.escapedName === "constructor" || - (baseType && getPropertyOfType(baseType, p.escapedName) - && isReadonlySymbol(getPropertyOfType(baseType, p.escapedName)!) === isReadonlySymbol(p) - && (p.flags & SymbolFlags.Optional) === (getPropertyOfType(baseType, p.escapedName)!.flags & SymbolFlags.Optional) - && isTypeIdenticalTo(getTypeOfSymbol(p), getTypeOfPropertyOfType(baseType, p.escapedName)!))) { + if ( + p.flags & SymbolFlags.Prototype || p.escapedName === "constructor" + || (baseType && getPropertyOfType(baseType, p.escapedName) + && isReadonlySymbol(getPropertyOfType(baseType, p.escapedName)!) === isReadonlySymbol(p) + && (p.flags & SymbolFlags.Optional) + === (getPropertyOfType(baseType, p.escapedName)!.flags & SymbolFlags.Optional) + && isTypeIdenticalTo(getTypeOfSymbol(p), getTypeOfPropertyOfType(baseType, p.escapedName)!)) + ) { return []; } const flag = (modifierFlags & ~ModifierFlags.Async) | (isStatic ? ModifierFlags.Static : 0); const name = getPropertyNameNodeForSymbol(p, context); - const firstPropertyLikeDecl = p.declarations?.find(or(isPropertyDeclaration, isAccessor, isVariableDeclaration, isPropertySignature, isBinaryExpression, isPropertyAccessExpression)); + const firstPropertyLikeDecl = p.declarations?.find( + or( + isPropertyDeclaration, + isAccessor, + isVariableDeclaration, + isPropertySignature, + isBinaryExpression, + isPropertyAccessExpression, + ), + ); if (p.flags & SymbolFlags.Accessor && useAccessors) { const result: AccessorDeclaration[] = []; if (p.flags & SymbolFlags.SetAccessor) { - result.push(setTextRange(factory.createSetAccessorDeclaration( - factory.createModifiersFromModifierFlags(flag), - name, - [factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - "arg", - /*questionToken*/ undefined, - isPrivate ? undefined : serializeTypeForDeclaration(context, getTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled) - )], - /*body*/ undefined - ), p.declarations?.find(isSetAccessor) || firstPropertyLikeDecl)); + result.push(setTextRange( + factory.createSetAccessorDeclaration( + factory.createModifiersFromModifierFlags(flag), + name, + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "arg", + /*questionToken*/ undefined, + isPrivate ? undefined + : serializeTypeForDeclaration( + context, + getTypeOfSymbol(p), + p, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), + )], + /*body*/ undefined, + ), + p.declarations?.find(isSetAccessor) || firstPropertyLikeDecl, + )); } if (p.flags & SymbolFlags.GetAccessor) { const isPrivate = modifierFlags & ModifierFlags.Private; - result.push(setTextRange(factory.createGetAccessorDeclaration( - factory.createModifiersFromModifierFlags(flag), - name, - [], - isPrivate ? undefined : serializeTypeForDeclaration(context, getTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled), - /*body*/ undefined - ), p.declarations?.find(isGetAccessor) || firstPropertyLikeDecl)); + result.push(setTextRange( + factory.createGetAccessorDeclaration( + factory.createModifiersFromModifierFlags(flag), + name, + [], + isPrivate ? undefined + : serializeTypeForDeclaration( + context, + getTypeOfSymbol(p), + p, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), + /*body*/ undefined, + ), + p.declarations?.find(isGetAccessor) || firstPropertyLikeDecl, + )); } return result; } // This is an else/if as accessors and properties can't merge in TS, but might in JS // If this happens, we assume the accessor takes priority, as it imposes more constraints else if (p.flags & (SymbolFlags.Property | SymbolFlags.Variable | SymbolFlags.Accessor)) { - return setTextRange(createProperty( - factory.createModifiersFromModifierFlags((isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag), - name, - p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - isPrivate ? undefined : serializeTypeForDeclaration(context, getWriteTypeOfSymbol(p), p, enclosingDeclaration, includePrivateSymbol, bundled), - // TODO: https://github.com/microsoft/TypeScript/pull/32372#discussion_r328386357 - // interface members can't have initializers, however class members _can_ - /*initializer*/ undefined - ), p.declarations?.find(or(isPropertyDeclaration, isVariableDeclaration)) || firstPropertyLikeDecl); + return setTextRange( + createProperty( + factory.createModifiersFromModifierFlags( + (isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag, + ), + name, + p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) + : undefined, + isPrivate ? undefined + : serializeTypeForDeclaration( + context, + getWriteTypeOfSymbol(p), + p, + enclosingDeclaration, + includePrivateSymbol, + bundled, + ), + // TODO: https://github.com/microsoft/TypeScript/pull/32372#discussion_r328386357 + // interface members can't have initializers, however class members _can_ + /*initializer*/ undefined, + ), + p.declarations?.find(or(isPropertyDeclaration, isVariableDeclaration)) + || firstPropertyLikeDecl, + ); } if (p.flags & (SymbolFlags.Method | SymbolFlags.Function)) { const type = getTypeOfSymbol(p); const signatures = getSignaturesOfType(type, SignatureKind.Call); if (flag & ModifierFlags.Private) { - return setTextRange(createProperty( - factory.createModifiersFromModifierFlags((isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag), - name, - p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - /*type*/ undefined, - /*initializer*/ undefined - ), p.declarations?.find(isFunctionLikeDeclaration) || signatures[0] && signatures[0].declaration || p.declarations && p.declarations[0]); + return setTextRange( + createProperty( + factory.createModifiersFromModifierFlags( + (isReadonlySymbol(p) ? ModifierFlags.Readonly : 0) | flag, + ), + name, + p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) + : undefined, + /*type*/ undefined, + /*initializer*/ undefined, + ), + p.declarations?.find(isFunctionLikeDeclaration) + || signatures[0] && signatures[0].declaration + || p.declarations && p.declarations[0], + ); } const results = []; @@ -9655,11 +12695,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context, { name, - questionToken: p.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - modifiers: flag ? factory.createModifiersFromModifierFlags(flag) : undefined - } + questionToken: p.flags & SymbolFlags.Optional + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + modifiers: flag ? factory.createModifiersFromModifierFlags(flag) : undefined, + }, ); - const location = sig.declaration && isPrototypePropertyAssignment(sig.declaration.parent) ? sig.declaration.parent : sig.declaration; + const location = sig.declaration && isPrototypePropertyAssignment(sig.declaration.parent) + ? sig.declaration.parent : sig.declaration; results.push(setTextRange(decl, location)); } return results as unknown as T[]; @@ -9673,7 +12715,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return serializePropertySymbolForInterfaceWorker(p, /*isStatic*/ false, baseType); } - function serializeSignatures(kind: SignatureKind, input: Type, baseType: Type | undefined, outputKind: SignatureDeclaration["kind"]) { + function serializeSignatures( + kind: SignatureKind, + input: Type, + baseType: Type | undefined, + outputKind: SignatureDeclaration["kind"], + ) { const signatures = getSignaturesOfType(input, kind); if (kind === SignatureKind.Construct) { if (!baseType && every(signatures, s => length(s.parameters) === 0)) { @@ -9688,7 +12735,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (baseSigs.length === signatures.length) { let failed = false; for (let i = 0; i < baseSigs.length; i++) { - if (!compareSignaturesIdentical(signatures[i], baseSigs[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { + if ( + !compareSignaturesIdentical( + signatures[i], + baseSigs[i], + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true, + compareTypesIdentical, + ) + ) { failed = true; break; } @@ -9701,15 +12757,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let privateProtected: ModifierFlags = 0; for (const s of signatures) { if (s.declaration) { - privateProtected |= getSelectedEffectiveModifierFlags(s.declaration, ModifierFlags.Private | ModifierFlags.Protected); + privateProtected |= getSelectedEffectiveModifierFlags( + s.declaration, + ModifierFlags.Private | ModifierFlags.Protected, + ); } } if (privateProtected) { - return [setTextRange(factory.createConstructorDeclaration( - factory.createModifiersFromModifierFlags(privateProtected), - /*parameters*/ [], - /*body*/ undefined, - ), signatures[0].declaration)]; + return [setTextRange( + factory.createConstructorDeclaration( + factory.createModifiersFromModifierFlags(privateProtected), + /*parameters*/ [], + /*body*/ undefined, + ), + signatures[0].declaration, + )]; } } @@ -9744,11 +12806,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return ref; } const tempName = getUnusedName(`${rootName}_base`); - const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([ - factory.createVariableDeclaration(tempName, /*exclamationToken*/ undefined, typeToTypeNodeHelper(staticType, context)) - ], NodeFlags.Const)); + const statement = factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration( + tempName, + /*exclamationToken*/ undefined, + typeToTypeNodeHelper(staticType, context), + ), + ], NodeFlags.Const), + ); addResult(statement, ModifierFlags.None); - return factory.createExpressionWithTypeArguments(factory.createIdentifier(tempName), /*typeArguments*/ undefined); + return factory.createExpressionWithTypeArguments( + factory.createIdentifier(tempName), + /*typeArguments*/ undefined, + ); } function trySerializeAsTypeReference(t: Type, flags: SymbolFlags) { @@ -9757,7 +12829,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We don't use `isValueSymbolAccessible` below. since that considers alternative containers (like modules) // which we can't write out in a syntactically valid way as an expression - if ((t as TypeReference).target && isSymbolAccessibleByFlags((t as TypeReference).target.symbol, enclosingDeclaration, flags)) { + if ( + (t as TypeReference).target + && isSymbolAccessibleByFlags((t as TypeReference).target.symbol, enclosingDeclaration, flags) + ) { typeArgs = map(getTypeArguments(t as TypeReference), t => typeToTypeNodeHelper(t, context)); reference = symbolToExpression((t as TypeReference).target.symbol, context, SymbolFlags.Type); } @@ -9775,7 +12850,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return ref; } if (t.symbol) { - return factory.createExpressionWithTypeArguments(symbolToExpression(t.symbol, context, SymbolFlags.Type), /*typeArguments*/ undefined); + return factory.createExpressionWithTypeArguments( + symbolToExpression(t.symbol, context, SymbolFlags.Type), + /*typeArguments*/ undefined, + ); } } @@ -9803,12 +12881,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getNameCandidateWorker(symbol: Symbol, localName: string) { - if (localName === InternalSymbolName.Default || localName === InternalSymbolName.Class || localName === InternalSymbolName.Function) { + if ( + localName === InternalSymbolName.Default || localName === InternalSymbolName.Class + || localName === InternalSymbolName.Function + ) { const flags = context.flags; context.flags |= NodeBuilderFlags.InInitialEntityName; const nameCandidate = getNameOfSymbolAsWritten(symbol, context); context.flags = flags; - localName = nameCandidate.length > 0 && isSingleOrDoubleQuote(nameCandidate.charCodeAt(0)) ? stripQuotes(nameCandidate) : nameCandidate; + localName = nameCandidate.length > 0 && isSingleOrDoubleQuote(nameCandidate.charCodeAt(0)) + ? stripQuotes(nameCandidate) : nameCandidate; } if (localName === InternalSymbolName.Default) { localName = "_default"; @@ -9816,7 +12898,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (localName === InternalSymbolName.ExportEquals) { localName = "_exports"; } - localName = isIdentifierText(localName, languageVersion) && !isStringANonContextualKeyword(localName) ? localName : "_" + localName.replace(/[^a-zA-Z0-9]/g, "_"); + localName = isIdentifierText(localName, languageVersion) && !isStringANonContextualKeyword(localName) + ? localName : "_" + localName.replace(/[^a-zA-Z0-9]/g, "_"); return localName; } @@ -9833,14 +12916,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer?: EmitTextWriter): string { - return writer ? typePredicateToStringWorker(writer).getText() : usingSingleLineStringWriter(typePredicateToStringWorker); + function typePredicateToString( + typePredicate: TypePredicate, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer?: EmitTextWriter, + ): string { + return writer ? typePredicateToStringWorker(writer).getText() + : usingSingleLineStringWriter(typePredicateToStringWorker); function typePredicateToStringWorker(writer: EmitTextWriter) { const predicate = factory.createTypePredicateNode( - typePredicate.kind === TypePredicateKind.AssertsThis || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createToken(SyntaxKind.AssertsKeyword) : undefined, - typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createIdentifier(typePredicate.parameterName) : factory.createThisTypeNode(), - typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217 + typePredicate.kind === TypePredicateKind.AssertsThis + || typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? factory.createToken(SyntaxKind.AssertsKeyword) : undefined, + typePredicate.kind === TypePredicateKind.Identifier + || typePredicate.kind === TypePredicateKind.AssertsIdentifier + ? factory.createIdentifier(typePredicate.parameterName) : factory.createThisTypeNode(), + typePredicate.type + && nodeBuilder.typeToTypeNode( + typePredicate.type, + enclosingDeclaration, + toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors + | NodeBuilderFlags.WriteTypeParametersInQualifiedName, + )!, // TODO: GH#18217 ); const printer = createPrinterWithRemoveComments(); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); @@ -9857,10 +12956,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { flags |= t.flags; if (!(t.flags & TypeFlags.Nullable)) { if (t.flags & (TypeFlags.BooleanLiteral | TypeFlags.EnumLike)) { - const baseType = t.flags & TypeFlags.BooleanLiteral ? booleanType : getBaseTypeOfEnumLikeType(t as LiteralType); + const baseType = t.flags & TypeFlags.BooleanLiteral ? booleanType + : getBaseTypeOfEnumLikeType(t as LiteralType); if (baseType.flags & TypeFlags.Union) { const count = (baseType as UnionType).types.length; - if (i + count <= types.length && getRegularTypeOfLiteralType(types[i + count - 1]) === getRegularTypeOfLiteralType((baseType as UnionType).types[count - 1])) { + if ( + i + count <= types.length + && getRegularTypeOfLiteralType(types[i + count - 1]) + === getRegularTypeOfLiteralType((baseType as UnionType).types[count - 1]) + ) { result.push(baseType); i += count - 1; continue; @@ -9896,9 +13000,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTopLevelInExternalModuleAugmentation(node: Node): boolean { - return node && node.parent && - node.parent.kind === SyntaxKind.ModuleBlock && - isExternalModuleAugmentation(node.parent.parent); + return node && node.parent + && node.parent.kind === SyntaxKind.ModuleBlock + && isExternalModuleAugmentation(node.parent.parent); } function isDefaultBindingContext(location: Node) { @@ -9932,13 +13036,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * It will also use a representation of a number as written instead of a decimal form, e.g. `0o11` instead of `9`. */ function getNameOfSymbolAsWritten(symbol: Symbol, context?: NodeBuilderContext): string { - if (context && symbol.escapedName === InternalSymbolName.Default && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) && + if ( + context && symbol.escapedName === InternalSymbolName.Default + && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) // If it's not the first part of an entity name, it must print as `default` - (!(context.flags & NodeBuilderFlags.InInitialEntityName) || - // if the symbol is synthesized, it will only be referenced externally it must print as `default` - !symbol.declarations || - // if not in the same binding context (source file, module declaration), it must print as `default` - (context.enclosingDeclaration && findAncestor(symbol.declarations[0], isDefaultBindingContext) !== findAncestor(context.enclosingDeclaration, isDefaultBindingContext)))) { + && (!(context.flags & NodeBuilderFlags.InInitialEntityName) + // if the symbol is synthesized, it will only be referenced externally it must print as `default` + || !symbol.declarations + // if not in the same binding context (source file, module declaration), it must print as `default` + || (context.enclosingDeclaration + && findAncestor(symbol.declarations[0], isDefaultBindingContext) + !== findAncestor(context.enclosingDeclaration, isDefaultBindingContext))) + ) { return "default"; } if (symbol.declarations && symbol.declarations.length) { @@ -9970,10 +13079,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ClassExpression: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - if (context && !context.encounteredError && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier)) { + if ( + context && !context.encounteredError + && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) + ) { context.encounteredError = true; } - return declaration.kind === SyntaxKind.ClassExpression ? "(Anonymous class)" : "(Anonymous function)"; + return declaration.kind === SyntaxKind.ClassExpression ? "(Anonymous class)" + : "(Anonymous function)"; } } const name = getNameOfSymbolFromNameType(symbol, context); @@ -9998,12 +13111,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocEnumTag: // Top-level jsdoc type aliases are considered exported // First parent is comment node, second is hosting declaration or token; we only care about those tokens or declarations whose parent is a source file - return !!(node.parent && node.parent.parent && node.parent.parent.parent && isSourceFile(node.parent.parent.parent)); + return !!(node.parent && node.parent.parent && node.parent.parent.parent + && isSourceFile(node.parent.parent.parent)); case SyntaxKind.BindingElement: return isDeclarationVisible(node.parent.parent); case SyntaxKind.VariableDeclaration: - if (isBindingPattern((node as VariableDeclaration).name) && - !((node as VariableDeclaration).name as BindingPattern).elements.length) { + if ( + isBindingPattern((node as VariableDeclaration).name) + && !((node as VariableDeclaration).name as BindingPattern).elements.length + ) { // If the binding pattern is empty, this variable declaration is not visible return false; } @@ -10021,8 +13137,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const parent = getDeclarationContainer(node); // If the node is not exported or it is not ambient module element (except import declaration) - if (!(getCombinedModifierFlagsCached(node as Declaration) & ModifierFlags.Export) && - !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && parent.flags & NodeFlags.Ambient)) { + if ( + !(getCombinedModifierFlagsCached(node as Declaration) & ModifierFlags.Export) + && !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile + && parent.flags & NodeFlags.Ambient) + ) { return isGlobalSourceFile(parent); } // Exported members/ambient module elements (exception import declaration) are visible if parent is visible @@ -10088,10 +13207,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined { let exportSymbol: Symbol | undefined; if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) { - exportSymbol = resolveName(node, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, node, /*isUse*/ false); + exportSymbol = resolveName( + node, + node.escapedText, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + node, + /*isUse*/ false, + ); } else if (node.parent.kind === SyntaxKind.ExportSpecifier) { - exportSymbol = getTargetOfExportSpecifier(node.parent as ExportSpecifier, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + exportSymbol = getTargetOfExportSpecifier( + node.parent as ExportSpecifier, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + ); } let result: Node[] | undefined; let visited: Set | undefined; @@ -10117,8 +13246,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Add the referenced top container visible const internalModuleReference = declaration.moduleReference as Identifier | QualifiedName; const firstIdentifier = getFirstIdentifier(internalModuleReference); - const importSymbol = resolveName(declaration, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, - /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + const importSymbol = resolveName( + declaration, + firstIdentifier.escapedText, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); if (importSymbol && visited) { if (tryAddToSet(visited, getSymbolId(importSymbol))) { buildVisibleNodeList(importSymbol.declarations); @@ -10226,7 +13361,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter. // It is an error to explicitly declare a static property member with the name 'prototype'. const classType = getDeclaredTypeOfSymbol(getParentOfSymbol(prototype)!) as InterfaceType; - return classType.typeParameters ? createTypeReference(classType as GenericType, map(classType.typeParameters, _ => anyType)) : classType; + return classType.typeParameters + ? createTypeReference(classType as GenericType, map(classType.typeParameters, _ => anyType)) : classType; } // Return the type of the given property in the given type, or undefined if no such property exists @@ -10246,9 +13382,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function getTypeOfPropertyOrIndexSignatureOfType(type: Type, name: __String): Type | undefined { let propType; - return getTypeOfPropertyOfType(type, name) || - (propType = getApplicableIndexInfoForName(type, name)?.type) && - addOptionality(propType, /*isProperty*/ true, /*isOptional*/ true); + return getTypeOfPropertyOfType(type, name) + || (propType = getApplicableIndexInfoForName(type, name)?.type) + && addOptionality(propType, /*isProperty*/ true, /*isOptional*/ true); } function isTypeAny(type: Type | undefined) { @@ -10268,7 +13404,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); } const symbol = getSymbolOfDeclaration(node); - return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); + return symbol && getSymbolLinks(symbol).type + || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false, checkMode); } function getRestType(source: Type, properties: PropertyName[], symbol: Symbol | undefined): Type { @@ -10287,9 +13424,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const prop of getPropertiesOfType(source)) { const literalTypeFromProperty = getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique); - if (!isTypeAssignableTo(literalTypeFromProperty, omitKeyType) + if ( + !isTypeAssignableTo(literalTypeFromProperty, omitKeyType) && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) - && isSpreadableProperty(prop)) { + && isSpreadableProperty(prop) + ) { spreadableProperties.push(prop); } else { @@ -10325,11 +13464,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isGenericTypeWithUndefinedConstraint(type: Type) { - return !!(type.flags & TypeFlags.Instantiable) && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.Undefined); + return !!(type.flags & TypeFlags.Instantiable) + && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.Undefined); } function getNonUndefinedType(type: Type) { - const typeOrConstraint = someType(type, isGenericTypeWithUndefinedConstraint) ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; + const typeOrConstraint = someType(type, isGenericTypeWithUndefinedConstraint) + ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; return getTypeWithFacts(typeOrConstraint, TypeFacts.NEUndefined); } @@ -10342,18 +13483,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // [ x ] = obj; // Expression // We construct a synthetic element access expression corresponding to 'obj.x' such that the control // flow analyzer doesn't have to handle all the different syntactic forms. - function getFlowTypeOfDestructuring(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, declaredType: Type) { + function getFlowTypeOfDestructuring( + node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, + declaredType: Type, + ) { const reference = getSyntheticElementAccess(node); return reference ? getFlowTypeOfReference(reference, declaredType) : declaredType; } - function getSyntheticElementAccess(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression): ElementAccessExpression | undefined { + function getSyntheticElementAccess( + node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, + ): ElementAccessExpression | undefined { const parentAccess = getParentElementAccess(node); if (parentAccess && canHaveFlowNode(parentAccess) && parentAccess.flowNode) { const propName = getDestructuringPropertyName(node); if (propName) { const literal = setTextRange(parseNodeFactory.createStringLiteral(propName), node); - const lhsExpr = isLeftHandSideExpression(parentAccess) ? parentAccess : parseNodeFactory.createParenthesizedExpression(parentAccess); + const lhsExpr = isLeftHandSideExpression(parentAccess) ? parentAccess + : parseNodeFactory.createParenthesizedExpression(parentAccess); const result = setTextRange(parseNodeFactory.createElementAccessExpression(lhsExpr, literal), node); setParent(literal, result); setParent(result, node); @@ -10366,7 +13513,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getParentElementAccess(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression) { + function getParentElementAccess( + node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, + ) { const ancestor = node.parent.parent; switch (ancestor.kind) { case SyntaxKind.BindingElement: @@ -10381,10 +13530,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getDestructuringPropertyName(node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression) { + function getDestructuringPropertyName( + node: BindingElement | PropertyAssignment | ShorthandPropertyAssignment | Expression, + ) { const parent = node.parent; if (node.kind === SyntaxKind.BindingElement && parent.kind === SyntaxKind.ObjectBindingPattern) { - return getLiteralPropertyNameText((node as BindingElement).propertyName || (node as BindingElement).name as Identifier); + return getLiteralPropertyNameText( + (node as BindingElement).propertyName || (node as BindingElement).name as Identifier, + ); } if (node.kind === SyntaxKind.PropertyAssignment || node.kind === SyntaxKind.ShorthandPropertyAssignment) { return getLiteralPropertyNameText((node as PropertyAssignment | ShorthandPropertyAssignment).name); @@ -10394,7 +13547,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getLiteralPropertyNameText(name: PropertyName) { const type = getLiteralTypeFromPropertyName(name); - return type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) ? "" + (type as StringLiteralType | NumberLiteralType).value : undefined; + return type.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral) + ? "" + (type as StringLiteralType | NumberLiteralType).value : undefined; } /** Return the inferred type for a binding element */ @@ -10415,7 +13569,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { parentType = getNonNullableType(parentType); } // Filter `undefined` from the type we check against if the parent has an initializer and that initializer is not possibly `undefined` - else if (strictNullChecks && pattern.parent.initializer && !(getTypeFacts(getTypeOfInitializer(pattern.parent.initializer)) & TypeFacts.EQUndefined)) { + else if ( + strictNullChecks && pattern.parent.initializer + && !(getTypeFacts(getTypeOfInitializer(pattern.parent.initializer)) & TypeFacts.EQUndefined) + ) { parentType = getTypeWithFacts(parentType, TypeFacts.NEUndefined); } @@ -10447,21 +13604,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This elementType will be used if the specific property corresponding to this index is not // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). - const elementType = checkIteratedTypeOrElementType(IterationUse.Destructuring | (declaration.dotDotDotToken ? 0 : IterationUse.PossiblyOutOfBounds), parentType, undefinedType, pattern); + const elementType = checkIteratedTypeOrElementType( + IterationUse.Destructuring | (declaration.dotDotDotToken ? 0 : IterationUse.PossiblyOutOfBounds), + parentType, + undefinedType, + pattern, + ); const index = pattern.elements.indexOf(declaration); if (declaration.dotDotDotToken) { // If the parent is a tuple type, the rest element has a tuple type of the // remaining tuple element types. Otherwise, the rest element has an array type with same // element type as the parent type. - const baseConstraint = mapType(parentType, t => t.flags & TypeFlags.InstantiableNonPrimitive ? getBaseConstraintOrType(t) : t); - type = everyType(baseConstraint, isTupleType) ? - mapType(baseConstraint, t => sliceTupleType(t as TupleTypeReference, index)) : - createArrayType(elementType); + const baseConstraint = mapType( + parentType, + t => t.flags & TypeFlags.InstantiableNonPrimitive ? getBaseConstraintOrType(t) : t, + ); + type = everyType(baseConstraint, isTupleType) + ? mapType(baseConstraint, t => sliceTupleType(t as TupleTypeReference, index)) + : createArrayType(elementType); } else if (isArrayLikeType(parentType)) { const indexType = getNumberLiteralType(index); - const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0); - const declaredType = getIndexedAccessTypeOrUndefined(parentType, indexType, accessFlags, declaration.name) || errorType; + const accessFlags = AccessFlags.ExpressionPosition + | (hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0); + const declaredType = + getIndexedAccessTypeOrUndefined(parentType, indexType, accessFlags, declaration.name) || errorType; type = getFlowTypeOfDestructuring(declaration, declaredType); } else { @@ -10474,9 +13641,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration))) { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. - return strictNullChecks && !(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined) ? getNonUndefinedType(type) : type; + return strictNullChecks + && !(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) + & TypeFacts.IsUndefined) ? getNonUndefinedType(type) : type; } - return widenTypeInferredFromInitializer(declaration, getUnionType([getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], UnionReduction.Subtype)); + return widenTypeInferredFromInitializer( + declaration, + getUnionType( + [getNonUndefinedType(type), checkDeclarationInitializer(declaration, CheckMode.Normal)], + UnionReduction.Subtype, + ), + ); } function getTypeForDeclarationFromJSDocComment(declaration: Node) { @@ -10489,12 +13664,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isNullOrUndefined(node: Expression) { const expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return expr.kind === SyntaxKind.NullKeyword || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(expr as Identifier) === undefinedSymbol; + return expr.kind === SyntaxKind.NullKeyword + || expr.kind === SyntaxKind.Identifier && getResolvedSymbol(expr as Identifier) === undefinedSymbol; } function isEmptyArrayLiteral(node: Expression) { const expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return expr.kind === SyntaxKind.ArrayLiteralExpression && (expr as ArrayLiteralExpression).elements.length === 0; + return expr.kind === SyntaxKind.ArrayLiteralExpression + && (expr as ArrayLiteralExpression).elements.length === 0; } function addOptionality(type: Type, isProperty = false, isOptional = true): Type { @@ -10503,15 +13680,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return the inferred type for a variable, parameter, or property declaration function getTypeForVariableLikeDeclaration( - declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement | JSDocPropertyLikeTag, + declaration: + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | VariableDeclaration + | BindingElement + | JSDocPropertyLikeTag, includeOptionality: boolean, checkMode: CheckMode, ): Type | undefined { // A variable declared in a for..in statement is of type string, or of type keyof T when the // right hand expression is of a type parameter type. if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForInStatement) { - const indexType = getIndexType(getNonNullableTypeIfNeeded(checkExpression(declaration.parent.parent.expression, /*checkMode*/ checkMode))); - return indexType.flags & (TypeFlags.TypeParameter | TypeFlags.Index) ? getExtractStringType(indexType) : stringType; + const indexType = getIndexType( + getNonNullableTypeIfNeeded( + checkExpression(declaration.parent.parent.expression, /*checkMode*/ checkMode), + ), + ); + return indexType.flags & (TypeFlags.TypeParameter | TypeFlags.Index) ? getExtractStringType(indexType) + : stringType; } if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { @@ -10527,7 +13715,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTypeForBindingElement(declaration as BindingElement); } - const isProperty = (isPropertyDeclaration(declaration) && !hasAccessorModifier(declaration)) || isPropertySignature(declaration) || isJSDocPropertyTag(declaration); + const isProperty = (isPropertyDeclaration(declaration) && !hasAccessorModifier(declaration)) + || isPropertySignature(declaration) || isJSDocPropertyTag(declaration); const isOptional = includeOptionality && isOptionalDeclaration(declaration); // Use type from type annotation if one is present @@ -10545,13 +13734,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return addOptionality(declaredType, isProperty, isOptional); } - if ((noImplicitAny || isInJSFile(declaration)) && - isVariableDeclaration(declaration) && !isBindingPattern(declaration.name) && - !(getCombinedModifierFlagsCached(declaration) & ModifierFlags.Export) && !(declaration.flags & NodeFlags.Ambient)) { + if ( + (noImplicitAny || isInJSFile(declaration)) + && isVariableDeclaration(declaration) && !isBindingPattern(declaration.name) + && !(getCombinedModifierFlagsCached(declaration) & ModifierFlags.Export) + && !(declaration.flags & NodeFlags.Ambient) + ) { // If --noImplicitAny is on or the declaration is in a Javascript file, // use control flow tracked 'any' type for non-ambient, non-exported var or let variables with no // initializer or a 'null' or 'undefined' initializer. - if (!(getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant) && (!declaration.initializer || isNullOrUndefined(declaration.initializer))) { + if ( + !(getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant) + && (!declaration.initializer || isNullOrUndefined(declaration.initializer)) + ) { return autoType; } // Use control flow tracked 'any[]' type for non-ambient, non-exported variables with an empty array @@ -10565,7 +13760,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const func = declaration.parent as FunctionLikeDeclaration; // For a parameter of a set accessor, use the type of the get accessor if one is present if (func.kind === SyntaxKind.SetAccessor && hasBindableName(func)) { - const getter = getDeclarationOfKind(getSymbolOfDeclaration(declaration.parent), SyntaxKind.GetAccessor); + const getter = getDeclarationOfKind( + getSymbolOfDeclaration(declaration.parent), + SyntaxKind.GetAccessor, + ); if (getter) { const getterSignature = getSignatureFromDeclaration(getter); const thisParameter = getAccessorThisParameter(func as AccessorDeclaration); @@ -10580,7 +13778,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parameterTypeOfTypeTag = getParameterTypeOfTypeTag(func, declaration); if (parameterTypeOfTypeTag) return parameterTypeOfTypeTag; // Use contextual parameter type if one is available - const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); + const type = declaration.symbol.escapedName === InternalSymbolName.This + ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); if (type) { return addOptionality(type, /*isProperty*/ false, isOptional); } @@ -10590,12 +13789,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // not a parameter of a contextually typed function if (hasOnlyExpressionInitializer(declaration) && !!declaration.initializer) { if (isInJSFile(declaration) && !isParameter(declaration)) { - const containerObjectType = getJSContainerObjectType(declaration, getSymbolOfDeclaration(declaration), getDeclaredExpandoInitializer(declaration)); + const containerObjectType = getJSContainerObjectType( + declaration, + getSymbolOfDeclaration(declaration), + getDeclaredExpandoInitializer(declaration), + ); if (containerObjectType) { return containerObjectType; } } - const type = widenTypeInferredFromInitializer(declaration, checkDeclarationInitializer(declaration, checkMode)); + const type = widenTypeInferredFromInitializer( + declaration, + checkDeclarationInitializer(declaration, checkMode), + ); return addOptionality(type, isProperty, isOptional); } @@ -10604,16 +13810,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Use control flow analysis of this.xxx assignments in the constructor or static block to determine the type of the property. if (!hasStaticModifier(declaration)) { const constructor = findConstructorDeclaration(declaration.parent); - const type = constructor ? getFlowTypeInConstructor(declaration.symbol, constructor) : - getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) : - undefined; + const type = constructor ? getFlowTypeInConstructor(declaration.symbol, constructor) + : getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient + ? getTypeOfPropertyInBaseClass(declaration.symbol) + : undefined; return type && addOptionality(type, /*isProperty*/ true, isOptional); } else { const staticBlocks = filter(declaration.parent.members, isClassStaticBlockDeclaration); - const type = staticBlocks.length ? getFlowTypeInStaticBlocks(declaration.symbol, staticBlocks) : - getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient ? getTypeOfPropertyInBaseClass(declaration.symbol) : - undefined; + const type = staticBlocks.length ? getFlowTypeInStaticBlocks(declaration.symbol, staticBlocks) + : getEffectiveModifierFlags(declaration) & ModifierFlags.Ambient + ? getTypeOfPropertyInBaseClass(declaration.symbol) + : undefined; return type && addOptionality(type, /*isProperty*/ true, isOptional); } } @@ -10642,11 +13850,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getSymbolLinks(symbol); if (links.isConstructorDeclaredProperty === undefined) { links.isConstructorDeclaredProperty = false; - links.isConstructorDeclaredProperty = !!getDeclaringConstructor(symbol) && every(symbol.declarations, declaration => - isBinaryExpression(declaration) && - isPossiblyAliasedThisProperty(declaration) && - (declaration.left.kind !== SyntaxKind.ElementAccessExpression || isStringOrNumericLiteralLike((declaration.left as ElementAccessExpression).argumentExpression)) && - !getAnnotatedTypeForAssignmentDeclaration(/*declaredType*/ undefined, declaration, symbol, declaration)); + links.isConstructorDeclaredProperty = !!getDeclaringConstructor(symbol) + && every(symbol.declarations, declaration => + isBinaryExpression(declaration) + && isPossiblyAliasedThisProperty(declaration) + && (declaration.left.kind !== SyntaxKind.ElementAccessExpression + || isStringOrNumericLiteralLike( + (declaration.left as ElementAccessExpression).argumentExpression, + )) + && !getAnnotatedTypeForAssignmentDeclaration( + /*declaredType*/ undefined, + declaration, + symbol, + declaration, + )); } return links.isConstructorDeclaredProperty; } @@ -10657,8 +13874,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A property is auto-typed when its declaration has no type annotation or initializer and we're in // noImplicitAny mode or a .js file. const declaration = symbol.valueDeclaration; - return declaration && isPropertyDeclaration(declaration) && !getEffectiveTypeAnnotationNode(declaration) && - !declaration.initializer && (noImplicitAny || isInJSFile(declaration)); + return declaration && isPropertyDeclaration(declaration) && !getEffectiveTypeAnnotationNode(declaration) + && !declaration.initializer && (noImplicitAny || isInJSFile(declaration)); } function getDeclaringConstructor(symbol: Symbol) { @@ -10666,7 +13883,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } for (const declaration of symbol.declarations) { - const container = getThisContainer(declaration, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + declaration, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); if (container && (container.kind === SyntaxKind.Constructor || isJSConstructor(container))) { return container as ConstructorDeclaration; } @@ -10677,9 +13898,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getFlowTypeFromCommonJSExport(symbol: Symbol) { const file = getSourceFileOfNode(symbol.declarations![0]); const accessName = unescapeLeadingUnderscores(symbol.escapedName); - const areAllModuleExports = symbol.declarations!.every(d => isInJSFile(d) && isAccessExpression(d) && isModuleExportsAccessExpression(d.expression)); + const areAllModuleExports = symbol.declarations!.every(d => + isInJSFile(d) && isAccessExpression(d) && isModuleExportsAccessExpression(d.expression) + ); const reference = areAllModuleExports - ? factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createIdentifier("module"), factory.createIdentifier("exports")), accessName) + ? factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("module"), + factory.createIdentifier("exports"), + ), + accessName, + ) : factory.createPropertyAccessExpression(factory.createIdentifier("exports"), accessName); if (areAllModuleExports) { setParent((reference.expression as PropertyAccessExpression).expression, reference.expression); @@ -10701,7 +13930,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reference.flowNode = staticBlock.returnFlowNode; const flowType = getFlowTypeOfProperty(reference, symbol); if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) { - error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + error( + symbol.valueDeclaration, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType), + ); } // We don't infer a type if assignments are only null or undefined. if (everyType(flowType, isNullableType)) { @@ -10721,7 +13955,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reference.flowNode = constructor.returnFlowNode; const flowType = getFlowTypeOfProperty(reference, symbol); if (noImplicitAny && (flowType === autoType || flowType === autoArrayType)) { - error(symbol.valueDeclaration, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + error( + symbol.valueDeclaration, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType), + ); } // We don't infer a type if assignments are only null or undefined. return everyType(flowType, isNullableType) ? undefined : convertAutoToAny(flowType); @@ -10729,8 +13968,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getFlowTypeOfProperty(reference: Node, prop: Symbol | undefined) { const initialType = prop?.valueDeclaration - && (!isAutoTypedProperty(prop) || getEffectiveModifierFlags(prop.valueDeclaration) & ModifierFlags.Ambient) - && getTypeOfPropertyInBaseClass(prop) + && (!isAutoTypedProperty(prop) + || getEffectiveModifierFlags(prop.valueDeclaration) & ModifierFlags.Ambient) + && getTypeOfPropertyInBaseClass(prop) || undefinedType; return getFlowTypeOfReference(reference, autoType, initialType); } @@ -10743,7 +13983,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (tag && tag.typeExpression) { return getTypeFromTypeNode(tag.typeExpression); } - const containerObjectType = symbol.valueDeclaration && getJSContainerObjectType(symbol.valueDeclaration, symbol, container); + const containerObjectType = symbol.valueDeclaration + && getJSContainerObjectType(symbol.valueDeclaration, symbol, container); return containerObjectType || getWidenedLiteralType(checkExpressionCached(container)); } let type; @@ -10759,9 +14000,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol.declarations) { let jsdocType: Type | undefined; for (const declaration of symbol.declarations) { - const expression = (isBinaryExpression(declaration) || isCallExpression(declaration)) ? declaration : - isAccessExpression(declaration) ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration : - undefined; + const expression = (isBinaryExpression(declaration) || isCallExpression(declaration)) ? declaration + : isAccessExpression(declaration) + ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration + : undefined; if (!expression) { continue; // Non-assignment declaration merged in (eg, an Identifier to mark the thing as a namespace) - skip over it and pull type info from elsewhere } @@ -10769,7 +14011,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const kind = isAccessExpression(expression) ? getAssignmentDeclarationPropertyAccessKind(expression) : getAssignmentDeclarationKind(expression); - if (kind === AssignmentDeclarationKind.ThisProperty || isBinaryExpression(expression) && isPossiblyAliasedThisProperty(expression, kind)) { + if ( + kind === AssignmentDeclarationKind.ThisProperty + || isBinaryExpression(expression) && isPossiblyAliasedThisProperty(expression, kind) + ) { if (isDeclarationInConstructor(expression)) { definedInConstructor = true; } @@ -10778,10 +14023,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (!isCallExpression(expression)) { - jsdocType = getAnnotatedTypeForAssignmentDeclaration(jsdocType, expression, symbol, declaration); + jsdocType = getAnnotatedTypeForAssignmentDeclaration( + jsdocType, + expression, + symbol, + declaration, + ); } if (!jsdocType) { - (types || (types = [])).push((isBinaryExpression(expression) || isCallExpression(expression)) ? getInitializerTypeFromAssignmentDeclaration(symbol, resolvedSymbol, expression, kind) : neverType); + (types || (types = [])).push( + (isBinaryExpression(expression) || isCallExpression(expression)) + ? getInitializerTypeFromAssignmentDeclaration(symbol, resolvedSymbol, expression, kind) + : neverType, + ); } } type = jsdocType; @@ -10790,7 +14044,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!length(types)) { return errorType; // No types from any declarations :( } - let constructorTypes = definedInConstructor && symbol.declarations ? getConstructorDefinedThisAssignmentTypes(types!, symbol.declarations) : undefined; + let constructorTypes = definedInConstructor && symbol.declarations + ? getConstructorDefinedThisAssignmentTypes(types!, symbol.declarations) : undefined; // use only the constructor types unless they were only assigned null | undefined (including widening variants) if (definedInMethod) { const propType = getTypeOfPropertyInBaseClass(symbol); @@ -10799,12 +14054,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { definedInConstructor = true; } } - const sourceTypes = some(constructorTypes, t => !!(t.flags & ~TypeFlags.Nullable)) ? constructorTypes : types; // TODO: GH#18217 + const sourceTypes = some(constructorTypes, t => !!(t.flags & ~TypeFlags.Nullable)) ? constructorTypes + : types; // TODO: GH#18217 type = getUnionType(sourceTypes!); } } - const widened = getWidenedType(addOptionality(type, /*isProperty*/ false, definedInMethod && !definedInConstructor)); - if (symbol.valueDeclaration && isInJSFile(symbol.valueDeclaration) && filterType(widened, t => !!(t.flags & ~TypeFlags.Nullable)) === neverType) { + const widened = getWidenedType( + addOptionality(type, /*isProperty*/ false, definedInMethod && !definedInConstructor), + ); + if ( + symbol.valueDeclaration && isInJSFile(symbol.valueDeclaration) + && filterType(widened, t => !!(t.flags & ~TypeFlags.Nullable)) === neverType + ) { reportImplicitAny(symbol.valueDeclaration, anyType); return anyType; } @@ -10832,7 +14093,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function getAnnotatedTypeForAssignmentDeclaration(declaredType: Type | undefined, expression: Expression, symbol: Symbol, declaration: Declaration) { + function getAnnotatedTypeForAssignmentDeclaration( + declaredType: Type | undefined, + expression: Expression, + symbol: Symbol, + declaration: Declaration, + ) { const typeNode = getEffectiveTypeAnnotationNode(expression.parent); if (typeNode) { const type = getWidenedType(getTypeFromTypeNode(typeNode)); @@ -10840,7 +14106,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } else if (!isErrorType(declaredType) && !isErrorType(type) && !isTypeIdenticalTo(declaredType, type)) { - errorNextVariableOrPropertyDeclarationMustHaveSameType(/*firstDeclaration*/ undefined, declaredType, declaration, type); + errorNextVariableOrPropertyDeclarationMustHaveSameType( + /*firstDeclaration*/ undefined, + declaredType, + declaration, + type, + ); } } if (symbol.parent?.valueDeclaration) { @@ -10857,7 +14128,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** If we don't have an explicit JSDoc type, get the type from the initializer. */ - function getInitializerTypeFromAssignmentDeclaration(symbol: Symbol, resolvedSymbol: Symbol | undefined, expression: BinaryExpression | CallExpression, kind: AssignmentDeclarationKind) { + function getInitializerTypeFromAssignmentDeclaration( + symbol: Symbol, + resolvedSymbol: Symbol | undefined, + expression: BinaryExpression | CallExpression, + kind: AssignmentDeclarationKind, + ) { if (isCallExpression(expression)) { if (resolvedSymbol) { return getTypeOfSymbol(resolvedSymbol); // This shouldn't happen except under some hopefully forbidden merges of export assignments and object define assignments @@ -10886,13 +14162,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (containsSameNamedThisProperty(expression.left, expression.right)) { return anyType; } - const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) && (isModuleExportsAccessExpression(expression.left.expression) || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); + const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty + && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) + && (isModuleExportsAccessExpression(expression.left.expression) + || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) : isDirectExport ? getRegularTypeOfLiteralType(checkExpressionCached(expression.right)) : getWidenedLiteralType(checkExpressionCached(expression.right)); - if (type.flags & TypeFlags.Object && - kind === AssignmentDeclarationKind.ModuleExports && - symbol.escapedName === InternalSymbolName.ExportEquals) { + if ( + type.flags & TypeFlags.Object + && kind === AssignmentDeclarationKind.ModuleExports + && symbol.escapedName === InternalSymbolName.ExportEquals + ) { const exportedType = resolveStructuredTypeMembers(type as ObjectType); const members = createSymbolTable(); copyEntries(exportedType.members, members); @@ -10914,15 +14195,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // but we may have a JS file with `module.exports = { a: true }` along with a TypeScript module augmentation // declaring an `export const a: number`. In that case, we issue a duplicate identifier error, because // it's unclear what that's supposed to mean, so it's probably a mistake. - if (s.valueDeclaration && exportedMember.valueDeclaration && getSourceFileOfNode(s.valueDeclaration) !== getSourceFileOfNode(exportedMember.valueDeclaration)) { + if ( + s.valueDeclaration && exportedMember.valueDeclaration + && getSourceFileOfNode(s.valueDeclaration) + !== getSourceFileOfNode(exportedMember.valueDeclaration) + ) { const unescapedName = unescapeLeadingUnderscores(s.escapedName); - const exportedMemberName = tryCast(exportedMember.valueDeclaration, isNamedDeclaration)?.name || exportedMember.valueDeclaration; + const exportedMemberName = + tryCast(exportedMember.valueDeclaration, isNamedDeclaration)?.name + || exportedMember.valueDeclaration; addRelatedInfo( error(s.valueDeclaration, Diagnostics.Duplicate_identifier_0, unescapedName), - createDiagnosticForNode(exportedMemberName, Diagnostics._0_was_also_declared_here, unescapedName)); + createDiagnosticForNode( + exportedMemberName, + Diagnostics._0_was_also_declared_here, + unescapedName, + ), + ); addRelatedInfo( error(exportedMemberName, Diagnostics.Duplicate_identifier_0, unescapedName), - createDiagnosticForNode(s.valueDeclaration, Diagnostics._0_was_also_declared_here, unescapedName)); + createDiagnosticForNode( + s.valueDeclaration, + Diagnostics._0_was_also_declared_here, + unescapedName, + ), + ); } const union = createSymbol(s.flags | exportedMember.flags, name); union.links.type = getUnionType([getTypeOfSymbol(s), getTypeOfSymbol(exportedMember)]); @@ -10943,7 +14240,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { members, exportedType.callSignatures, exportedType.constructSignatures, - exportedType.indexInfos); + exportedType.indexInfos, + ); if (initialSize === members.size) { if (type.aliasSymbol) { result.aliasSymbol = type.aliasSymbol; @@ -10955,8 +14253,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result.aliasTypeArguments = length(args) ? args : undefined; } } - result.objectFlags |= (getObjectFlags(type) & ObjectFlags.JSLiteral); // Propagate JSLiteral flag - if (result.symbol && result.symbol.flags & SymbolFlags.Class && type === getDeclaredTypeOfClassOrInterface(result.symbol)) { + result.objectFlags |= getObjectFlags(type) & ObjectFlags.JSLiteral; // Propagate JSLiteral flag + if ( + result.symbol && result.symbol.flags & SymbolFlags.Class + && type === getDeclaredTypeOfClassOrInterface(result.symbol) + ) { result.objectFlags |= ObjectFlags.IsClassInstanceClone; // Propagate the knowledge that this type is equivalent to the symbol's class instance type } return result; @@ -10975,20 +14276,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isDeclarationInConstructor(expression: Expression) { - const thisContainer = getThisContainer(expression, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const thisContainer = getThisContainer( + expression, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); // Properties defined in a constructor (or base constructor, or javascript constructor function) don't get undefined added. // Function expressions that are assigned to the prototype count as methods. - return thisContainer.kind === SyntaxKind.Constructor || - thisContainer.kind === SyntaxKind.FunctionDeclaration || - (thisContainer.kind === SyntaxKind.FunctionExpression && !isPrototypePropertyAssignment(thisContainer.parent)); + return thisContainer.kind === SyntaxKind.Constructor + || thisContainer.kind === SyntaxKind.FunctionDeclaration + || (thisContainer.kind === SyntaxKind.FunctionExpression + && !isPrototypePropertyAssignment(thisContainer.parent)); } function getConstructorDefinedThisAssignmentTypes(types: Type[], declarations: Declaration[]): Type[] | undefined { Debug.assert(types.length === declarations.length); return types.filter((_, i) => { const declaration = declarations[i]; - const expression = isBinaryExpression(declaration) ? declaration : - isBinaryExpression(declaration.parent) ? declaration.parent : undefined; + const expression = isBinaryExpression(declaration) ? declaration + : isBinaryExpression(declaration.parent) ? declaration.parent : undefined; return expression && isDeclarationInConstructor(expression); }); } @@ -10996,13 +14302,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return the type implied by a binding pattern element. This is the type of the initializer of the element if // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding // pattern. Otherwise, it is the type any. - function getTypeFromBindingElement(element: BindingElement, includePatternInType?: boolean, reportErrors?: boolean): Type { + function getTypeFromBindingElement( + element: BindingElement, + includePatternInType?: boolean, + reportErrors?: boolean, + ): Type { if (element.initializer) { // The type implied by a binding pattern is independent of context, so we check the initializer with no // contextual type or, if the element itself is a binding pattern, with the type implied by that binding // pattern. - const contextualType = isBindingPattern(element.name) ? getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false) : unknownType; - return addOptionality(widenTypeInferredFromInitializer(element, checkDeclarationInitializer(element, CheckMode.Normal, contextualType))); + const contextualType = isBindingPattern(element.name) + ? getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false) + : unknownType; + return addOptionality( + widenTypeInferredFromInitializer( + element, + checkDeclarationInitializer(element, CheckMode.Normal, contextualType), + ), + ); } if (isBindingPattern(element.name)) { return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors); @@ -11018,7 +14335,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Return the type implied by an object binding pattern - function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { + function getTypeFromObjectBindingPattern( + pattern: ObjectBindingPattern, + includePatternInType: boolean, + reportErrors: boolean, + ): Type { const members = createSymbolTable(); let stringIndexInfo: IndexInfo | undefined; let objectFlags = ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; @@ -11042,7 +14363,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { symbol.links.bindingElement = e; members.set(symbol.escapedName, symbol); }); - const result = createAnonymousType(/*symbol*/ undefined, members, emptyArray, emptyArray, stringIndexInfo ? [stringIndexInfo] : emptyArray); + const result = createAnonymousType( + /*symbol*/ undefined, + members, + emptyArray, + emptyArray, + stringIndexInfo ? [stringIndexInfo] : emptyArray, + ); result.objectFlags |= objectFlags; if (includePatternInType) { result.pattern = pattern; @@ -11052,16 +14379,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Return the type implied by an array binding pattern - function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { + function getTypeFromArrayBindingPattern( + pattern: BindingPattern, + includePatternInType: boolean, + reportErrors: boolean, + ): Type { const elements = pattern.elements; const lastElement = lastOrUndefined(elements); - const restElement = lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken ? lastElement : undefined; + const restElement = lastElement && lastElement.kind === SyntaxKind.BindingElement && lastElement.dotDotDotToken + ? lastElement : undefined; if (elements.length === 0 || elements.length === 1 && restElement) { return languageVersion >= ScriptTarget.ES2015 ? createIterableType(anyType) : anyArrayType; } - const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors)); - const minLength = findLastIndex(elements, e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), elements.length - 1) + 1; - const elementFlags = map(elements, (e, i) => e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required); + const elementTypes = map( + elements, + e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors), + ); + const minLength = findLastIndex( + elements, + e => !(e === restElement || isOmittedExpression(e) || hasDefaultValue(e)), + elements.length - 1, + ) + 1; + const elementFlags = map( + elements, + (e, i) => + e === restElement ? ElementFlags.Rest : i >= minLength ? ElementFlags.Optional : ElementFlags.Required, + ); let result = createTupleType(elementTypes, elementFlags) as TypeReference; if (includePatternInType) { result = cloneTypeReference(result); @@ -11078,7 +14421,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of // the parameter. - function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType = false, reportErrors = false): Type { + function getTypeFromBindingPattern( + pattern: BindingPattern, + includePatternInType = false, + reportErrors = false, + ): Type { return pattern.kind === SyntaxKind.ObjectBindingPattern ? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors) : getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors); @@ -11093,8 +14440,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the // binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the // tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string. - function getWidenedTypeForVariableLikeDeclaration(declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement | JSDocPropertyLikeTag, reportErrors?: boolean): Type { - return widenTypeForVariableLikeDeclaration(getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true, CheckMode.Normal), declaration, reportErrors); + function getWidenedTypeForVariableLikeDeclaration( + declaration: + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | VariableDeclaration + | BindingElement + | JSDocPropertyLikeTag, + reportErrors?: boolean, + ): Type { + return widenTypeForVariableLikeDeclaration( + getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true, CheckMode.Normal), + declaration, + reportErrors, + ); } function isGlobalSymbolConstructor(node: Node) { @@ -11114,7 +14474,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // always widen a 'unique symbol' type if the type was created for a different declaration. - if (type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) && type.symbol !== getSymbolOfDeclaration(declaration)) { + if ( + type.flags & TypeFlags.UniqueESSymbol && (isBindingElement(declaration) || !declaration.type) + && type.symbol !== getSymbolOfDeclaration(declaration) + ) { type = esSymbolType; } @@ -11224,15 +14587,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let type: Type; if (declaration.kind === SyntaxKind.ExportAssignment) { - type = widenTypeForVariableLikeDeclaration(tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionCached((declaration as ExportAssignment).expression), declaration); + type = widenTypeForVariableLikeDeclaration( + tryGetTypeFromEffectiveTypeNode(declaration) + || checkExpressionCached((declaration as ExportAssignment).expression), + declaration, + ); } else if ( - isBinaryExpression(declaration) || - (isInJSFile(declaration) && - (isCallExpression(declaration) || (isPropertyAccessExpression(declaration) || isBindableStaticElementAccessExpression(declaration)) && isBinaryExpression(declaration.parent)))) { + isBinaryExpression(declaration) + || (isInJSFile(declaration) + && (isCallExpression(declaration) + || (isPropertyAccessExpression(declaration) || isBindableStaticElementAccessExpression(declaration)) + && isBinaryExpression(declaration.parent))) + ) { type = getWidenedTypeForAssignmentDeclaration(symbol); } - else if (isPropertyAccessExpression(declaration) + else if ( + isPropertyAccessExpression(declaration) || isElementAccessExpression(declaration) || isIdentifier(declaration) || isStringLiteralLike(declaration) @@ -11241,14 +14612,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || isFunctionDeclaration(declaration) || (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration)) || isMethodSignature(declaration) - || isSourceFile(declaration)) { + || isSourceFile(declaration) + ) { // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + if ( + symbol.flags + & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum + | SymbolFlags.ValueModule) + ) { return getTypeOfFuncClassEnumModule(symbol); } - type = isBinaryExpression(declaration.parent) ? - getWidenedTypeForAssignmentDeclaration(symbol) : - tryGetTypeFromEffectiveTypeNode(declaration) || anyType; + type = isBinaryExpression(declaration.parent) + ? getWidenedTypeForAssignmentDeclaration(symbol) + : tryGetTypeFromEffectiveTypeNode(declaration) || anyType; } else if (isPropertyAssignment(declaration)) { type = tryGetTypeFromEffectiveTypeNode(declaration) || checkPropertyAssignment(declaration); @@ -11257,17 +14633,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type = tryGetTypeFromEffectiveTypeNode(declaration) || checkJsxAttribute(declaration); } else if (isShorthandPropertyAssignment(declaration)) { - type = tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal); + type = tryGetTypeFromEffectiveTypeNode(declaration) + || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal); } else if (isObjectLiteralMethod(declaration)) { - type = tryGetTypeFromEffectiveTypeNode(declaration) || checkObjectLiteralMethod(declaration, CheckMode.Normal); - } - else if (isParameter(declaration) - || isPropertyDeclaration(declaration) - || isPropertySignature(declaration) - || isVariableDeclaration(declaration) - || isBindingElement(declaration) - || isJSDocPropertyLikeTag(declaration)) { + type = tryGetTypeFromEffectiveTypeNode(declaration) + || checkObjectLiteralMethod(declaration, CheckMode.Normal); + } + else if ( + isParameter(declaration) + || isPropertyDeclaration(declaration) + || isPropertySignature(declaration) + || isVariableDeclaration(declaration) + || isBindingElement(declaration) + || isJSDocPropertyLikeTag(declaration) + ) { type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true); } // getTypeOfSymbol dispatches some JS merges incorrectly because their symbol flags are not mutually exclusive. @@ -11279,7 +14659,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type = getTypeOfEnumMember(symbol); } else { - return Debug.fail("Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + Debug.formatSymbol(symbol)); + return Debug.fail( + "Unhandled declaration kind! " + Debug.formatSyntaxKind(declaration.kind) + " for " + + Debug.formatSymbol(symbol), + ); } if (!popTypeResolution()) { @@ -11292,7 +14675,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function getAnnotatedAccessorTypeNode(accessor: AccessorDeclaration | PropertyDeclaration | undefined): TypeNode | undefined { + function getAnnotatedAccessorTypeNode( + accessor: AccessorDeclaration | PropertyDeclaration | undefined, + ): TypeNode | undefined { if (accessor) { switch (accessor.kind) { case SyntaxKind.GetAccessor: @@ -11310,7 +14695,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getAnnotatedAccessorType(accessor: AccessorDeclaration | PropertyDeclaration | undefined): Type | undefined { + function getAnnotatedAccessorType( + accessor: AccessorDeclaration | PropertyDeclaration | undefined, + ): Type | undefined { const node = getAnnotatedAccessorTypeNode(accessor); return node && getTypeFromTypeNode(node); } @@ -11332,40 +14719,79 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor); - const accessor = tryCast(getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), isAutoAccessorPropertyDeclaration); + const accessor = tryCast( + getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), + isAutoAccessorPropertyDeclaration, + ); // We try to resolve a getter type annotation, a setter type annotation, or a getter function // body return type inference, in that order. - let type = getter && isInJSFile(getter) && getTypeForDeclarationFromJSDocComment(getter) || - getAnnotatedAccessorType(getter) || - getAnnotatedAccessorType(setter) || - getAnnotatedAccessorType(accessor) || - getter && getter.body && getReturnTypeFromBody(getter) || - accessor && accessor.initializer && getWidenedTypeForVariableLikeDeclaration(accessor, /*reportErrors*/ true); + let type = getter && isInJSFile(getter) && getTypeForDeclarationFromJSDocComment(getter) + || getAnnotatedAccessorType(getter) + || getAnnotatedAccessorType(setter) + || getAnnotatedAccessorType(accessor) + || getter && getter.body && getReturnTypeFromBody(getter) + || accessor && accessor.initializer + && getWidenedTypeForVariableLikeDeclaration(accessor, /*reportErrors*/ true); if (!type) { if (setter && !isPrivateWithinAmbient(setter)) { - errorOrSuggestion(noImplicitAny, setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol)); + errorOrSuggestion( + noImplicitAny, + setter, + Diagnostics + .Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, + symbolToString(symbol), + ); } else if (getter && !isPrivateWithinAmbient(getter)) { - errorOrSuggestion(noImplicitAny, getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol)); + errorOrSuggestion( + noImplicitAny, + getter, + Diagnostics + .Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, + symbolToString(symbol), + ); } else if (accessor && !isPrivateWithinAmbient(accessor)) { - errorOrSuggestion(noImplicitAny, accessor, Diagnostics.Member_0_implicitly_has_an_1_type, symbolToString(symbol), "any"); + errorOrSuggestion( + noImplicitAny, + accessor, + Diagnostics.Member_0_implicitly_has_an_1_type, + symbolToString(symbol), + "any", + ); } type = anyType; } if (!popTypeResolution()) { if (getAnnotatedAccessorTypeNode(getter)) { - error(getter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + getter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); } else if (getAnnotatedAccessorTypeNode(setter)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); } else if (getAnnotatedAccessorTypeNode(accessor)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); } else if (getter && noImplicitAny) { - error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol)); + error( + getter, + Diagnostics + ._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, + symbolToString(symbol), + ); } type = anyType; } @@ -11382,11 +14808,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const setter = getDeclarationOfKind(symbol, SyntaxKind.SetAccessor) - ?? tryCast(getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), isAutoAccessorPropertyDeclaration); + ?? tryCast( + getDeclarationOfKind(symbol, SyntaxKind.PropertyDeclaration), + isAutoAccessorPropertyDeclaration, + ); let writeType = getAnnotatedAccessorType(setter); if (!popTypeResolution()) { if (getAnnotatedAccessorTypeNode(setter)) { - error(setter, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, symbolToString(symbol)); + error( + setter, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); } writeType = anyType; } @@ -11398,16 +14831,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getBaseTypeVariableOfClass(symbol: Symbol) { const baseConstructorType = getBaseConstructorTypeOfClass(getDeclaredTypeOfClassOrInterface(symbol)); - return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType : - baseConstructorType.flags & TypeFlags.Intersection ? find((baseConstructorType as IntersectionType).types, t => !!(t.flags & TypeFlags.TypeVariable)) : - undefined; + return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType + : baseConstructorType.flags & TypeFlags.Intersection + ? find((baseConstructorType as IntersectionType).types, t => !!(t.flags & TypeFlags.TypeVariable)) + : undefined; } function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { let links = getSymbolLinks(symbol); const originalLinks = links; if (!links.type) { - const expando = symbol.valueDeclaration && getSymbolOfExpando(symbol.valueDeclaration, /*allowDeclaration*/ false); + const expando = symbol.valueDeclaration + && getSymbolOfExpando(symbol.valueDeclaration, /*allowDeclaration*/ false); if (expando) { const merged = mergeJSSymbols(symbol, expando); if (merged) { @@ -11426,19 +14861,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) { return anyType; } - else if (declaration && (declaration.kind === SyntaxKind.BinaryExpression || - isAccessExpression(declaration) && - declaration.parent.kind === SyntaxKind.BinaryExpression)) { + else if ( + declaration && (declaration.kind === SyntaxKind.BinaryExpression + || isAccessExpression(declaration) + && declaration.parent.kind === SyntaxKind.BinaryExpression) + ) { return getWidenedTypeForAssignmentDeclaration(symbol); } - else if (symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) && declaration.commonJsModuleIndicator) { + else if ( + symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) + && declaration.commonJsModuleIndicator + ) { const resolvedModule = resolveExternalModuleSymbol(symbol); if (resolvedModule !== symbol) { if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { return errorType; } const exportEquals = getMergedSymbol(symbol.exports!.get(InternalSymbolName.ExportEquals)!); - const type = getWidenedTypeForAssignmentDeclaration(exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule); + const type = getWidenedTypeForAssignmentDeclaration( + exportEquals, + exportEquals === resolvedModule ? undefined : resolvedModule, + ); if (!popTypeResolution()) { return reportCircularityError(symbol); } @@ -11451,7 +14894,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return baseTypeVariable ? getIntersectionType([type, baseTypeVariable]) : type; } else { - return strictNullChecks && symbol.flags & SymbolFlags.Optional ? getOptionalType(type, /*isProperty*/ true) : type; + return strictNullChecks && symbol.flags & SymbolFlags.Optional ? getOptionalType(type, /*isProperty*/ true) + : type; } } @@ -11464,14 +14908,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getSymbolLinks(symbol); if (!links.type) { const targetSymbol = resolveAlias(symbol); - const exportSymbol = symbol.declarations && getTargetOfAliasDeclaration(getDeclarationOfAliasSymbol(symbol)!, /*dontRecursivelyResolve*/ true); - const declaredType = firstDefined(exportSymbol?.declarations, d => isExportAssignment(d) ? tryGetTypeFromEffectiveTypeNode(d) : undefined); + const exportSymbol = symbol.declarations + && getTargetOfAliasDeclaration(getDeclarationOfAliasSymbol(symbol)!, /*dontRecursivelyResolve*/ true); + const declaredType = firstDefined( + exportSymbol?.declarations, + d => isExportAssignment(d) ? tryGetTypeFromEffectiveTypeNode(d) : undefined, + ); // It only makes sense to get the type of a value symbol. If the result of resolving // the alias is not a value, then it has no type. To get the type associated with a // type symbol, call getDeclaredTypeOfSymbol. // This check is important because without it, a call to getTypeOfSymbol could end // up recursively calling getTypeOfAlias, causing a stack overflow. - links.type = exportSymbol?.declarations && isDuplicatedCommonJSExport(exportSymbol.declarations) && symbol.declarations!.length ? getFlowTypeFromCommonJSExport(exportSymbol) + links.type = exportSymbol?.declarations && isDuplicatedCommonJSExport(exportSymbol.declarations) + && symbol.declarations!.length ? getFlowTypeFromCommonJSExport(exportSymbol) : isDuplicatedCommonJSExport(symbol.declarations) ? autoType : declaredType ? declaredType : getSymbolFlags(targetSymbol) & SymbolFlags.Value ? getTypeOfSymbol(targetSymbol) @@ -11487,21 +14936,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getWriteTypeOfInstantiatedSymbol(symbol: Symbol): Type { const links = getSymbolLinks(symbol); - return links.writeType || (links.writeType = instantiateType(getWriteTypeOfSymbol(links.target!), links.mapper)); + return links.writeType + || (links.writeType = instantiateType(getWriteTypeOfSymbol(links.target!), links.mapper)); } function reportCircularityError(symbol: Symbol) { const declaration = symbol.valueDeclaration as VariableLikeDeclaration; // Check if variable has type annotation that circularly references the variable itself if (getEffectiveTypeAnnotationNode(declaration)) { - error(symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, - symbolToString(symbol)); + error( + symbol.valueDeclaration, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_type_annotation, + symbolToString(symbol), + ); return errorType; } // Check if variable has initializer that circularly references the variable itself - if (noImplicitAny && (declaration.kind !== SyntaxKind.Parameter || (declaration as HasInitializer).initializer)) { - error(symbol.valueDeclaration, Diagnostics._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, - symbolToString(symbol)); + if ( + noImplicitAny && (declaration.kind !== SyntaxKind.Parameter || (declaration as HasInitializer).initializer) + ) { + error( + symbol.valueDeclaration, + Diagnostics + ._0_implicitly_has_type_any_because_it_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer, + symbolToString(symbol), + ); } // Circularities could also result from parameters in function expressions that end up // having themselves as contextual types following type argument inference. In those cases @@ -11514,7 +14973,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.type) { Debug.assertIsDefined(links.deferralParent); Debug.assertIsDefined(links.deferralConstituents); - links.type = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralConstituents) : getIntersectionType(links.deferralConstituents); + links.type = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralConstituents) + : getIntersectionType(links.deferralConstituents); } return links.type; } @@ -11524,7 +14984,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.writeType && links.deferralWriteConstituents) { Debug.assertIsDefined(links.deferralParent); Debug.assertIsDefined(links.deferralConstituents); - links.writeType = links.deferralParent.flags & TypeFlags.Union ? getUnionType(links.deferralWriteConstituents) : getIntersectionType(links.deferralWriteConstituents); + links.writeType = links.deferralParent.flags & TypeFlags.Union + ? getUnionType(links.deferralWriteConstituents) : getIntersectionType(links.deferralWriteConstituents); } return links.writeType; } @@ -11537,17 +14998,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getWriteTypeOfSymbol(symbol: Symbol): Type { const checkFlags = getCheckFlags(symbol); if (symbol.flags & SymbolFlags.Property) { - return checkFlags & CheckFlags.SyntheticProperty ? - checkFlags & CheckFlags.DeferredType ? - getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) : + return checkFlags & CheckFlags.SyntheticProperty + ? checkFlags & CheckFlags.DeferredType + ? getWriteTypeOfSymbolWithDeferredType(symbol) || getTypeOfSymbolWithDeferredType(symbol) // NOTE: cast to TransientSymbol should be safe because only TransientSymbols can have CheckFlags.SyntheticProperty - (symbol as TransientSymbol).links.writeType || (symbol as TransientSymbol).links.type! : - removeMissingType(getTypeOfSymbol(symbol), !!(symbol.flags & SymbolFlags.Optional)); + : (symbol as TransientSymbol).links.writeType || (symbol as TransientSymbol).links.type! + : removeMissingType(getTypeOfSymbol(symbol), !!(symbol.flags & SymbolFlags.Optional)); } if (symbol.flags & SymbolFlags.Accessor) { - return checkFlags & CheckFlags.Instantiated ? - getWriteTypeOfInstantiatedSymbol(symbol) : - getWriteTypeOfAccessors(symbol); + return checkFlags & CheckFlags.Instantiated + ? getWriteTypeOfInstantiatedSymbol(symbol) + : getWriteTypeOfAccessors(symbol); } return getTypeOfSymbol(symbol); } @@ -11569,7 +15030,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { return getTypeOfVariableOrParameterOrProperty(symbol); } - if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { + if ( + symbol.flags + & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum + | SymbolFlags.ValueModule) + ) { return getTypeOfFuncClassEnumModule(symbol); } if (symbol.flags & SymbolFlags.EnumMember) { @@ -11617,9 +15082,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Appends the type parameters given by a list of declarations to a set of type parameters and returns the resulting set. // The function allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set // in-place and returns the same array. - function appendTypeParameters(typeParameters: TypeParameter[] | undefined, declarations: readonly TypeParameterDeclaration[]): TypeParameter[] | undefined { + function appendTypeParameters( + typeParameters: TypeParameter[] | undefined, + declarations: readonly TypeParameterDeclaration[], + ): TypeParameter[] | undefined { for (const declaration of declarations) { - typeParameters = appendIfUnique(typeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(declaration))); + typeParameters = appendIfUnique( + typeParameters, + getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(declaration)), + ); } return typeParameters; } @@ -11631,8 +15102,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node && isBinaryExpression(node)) { // prototype assignments get the outer type parameters of their constructor function const assignmentKind = getAssignmentDeclarationKind(node); - if (assignmentKind === AssignmentDeclarationKind.Prototype || assignmentKind === AssignmentDeclarationKind.PrototypeProperty) { - const symbol = getSymbolOfDeclaration(node.left as BindableStaticNameExpression | PropertyAssignment); + if ( + assignmentKind === AssignmentDeclarationKind.Prototype + || assignmentKind === AssignmentDeclarationKind.PrototypeProperty + ) { + const symbol = getSymbolOfDeclaration( + node.left as BindableStaticNameExpression | PropertyAssignment, + ); if (symbol && symbol.parent && !findAncestor(symbol.parent.valueDeclaration, d => node === d)) { node = symbol.parent.valueDeclaration!; } @@ -11664,15 +15140,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ConditionalType: { const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); if (node.kind === SyntaxKind.MappedType) { - return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration((node as MappedTypeNode).typeParameter))); + return append( + outerTypeParameters, + getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration((node as MappedTypeNode).typeParameter), + ), + ); } else if (node.kind === SyntaxKind.ConditionalType) { return concatenate(outerTypeParameters, getInferTypeParameters(node as ConditionalTypeNode)); } - const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters)); - const thisType = includeThisTypes && - (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) && - getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node as ClassLikeDeclaration | InterfaceDeclaration)).thisType; + const outerAndOwnTypeParameters = appendTypeParameters( + outerTypeParameters, + getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters), + ); + const thisType = includeThisTypes + && (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression + || node.kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) + && getDeclaredTypeOfClassOrInterface( + getSymbolOfDeclaration(node as ClassLikeDeclaration | InterfaceDeclaration), + ).thisType; return thisType ? append(outerAndOwnTypeParameters, thisType) : outerAndOwnTypeParameters; } case SyntaxKind.JSDocParameterTag: @@ -11684,7 +15171,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDoc: { const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); return (node as JSDoc).tags - ? appendTypeParameters(outerTypeParameters, flatMap((node as JSDoc).tags, t => isJSDocTemplateTag(t) ? t.typeParameters : undefined)) + ? appendTypeParameters( + outerTypeParameters, + flatMap((node as JSDoc).tags, t => isJSDocTemplateTag(t) ? t.typeParameters : undefined), + ) : outerTypeParameters; } } @@ -11703,7 +15193,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } const initializer = (decl as VariableDeclaration).initializer; - return !!initializer && (initializer.kind === SyntaxKind.FunctionExpression || initializer.kind === SyntaxKind.ArrowFunction); + return !!initializer + && (initializer.kind === SyntaxKind.FunctionExpression + || initializer.kind === SyntaxKind.ArrowFunction); })!; Debug.assert(!!declaration, "Class was missing valueDeclaration -OR- non-class had no interface declarations"); return getOuterTypeParameters(declaration); @@ -11717,12 +15209,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let result: TypeParameter[] | undefined; for (const node of symbol.declarations) { - if (node.kind === SyntaxKind.InterfaceDeclaration || - node.kind === SyntaxKind.ClassDeclaration || - node.kind === SyntaxKind.ClassExpression || - isJSConstructor(node) || - isTypeAlias(node)) { - const declaration = node as InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag; + if ( + node.kind === SyntaxKind.InterfaceDeclaration + || node.kind === SyntaxKind.ClassDeclaration + || node.kind === SyntaxKind.ClassExpression + || isJSConstructor(node) + || isTypeAlias(node) + ) { + const declaration = node as + | InterfaceDeclaration + | TypeAliasDeclaration + | JSDocTypedefTag + | JSDocCallbackTag; result = appendTypeParameters(result, getEffectiveTypeParameterDeclarations(declaration)); } } @@ -11732,7 +15230,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The full set of type parameters for a generic class or interface type consists of its outer type parameters plus // its locally declared type parameters. function getTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] | undefined { - return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol)); + return concatenate( + getOuterTypeParametersOfClassOrInterface(symbol), + getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol), + ); } // A type is a mixin constructor if it has a single construct signature taking no type parameters and a single @@ -11765,17 +15266,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return decl && getEffectiveBaseTypeNode(decl); } - function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: readonly TypeNode[] | undefined, location: Node): readonly Signature[] { + function getConstructorsForTypeArguments( + type: Type, + typeArgumentNodes: readonly TypeNode[] | undefined, + location: Node, + ): readonly Signature[] { const typeArgCount = length(typeArgumentNodes); const isJavascript = isInJSFile(location); - return filter(getSignaturesOfType(type, SignatureKind.Construct), - sig => (isJavascript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) && typeArgCount <= length(sig.typeParameters)); + return filter( + getSignaturesOfType(type, SignatureKind.Construct), + sig => + (isJavascript || typeArgCount >= getMinTypeArgumentCount(sig.typeParameters)) + && typeArgCount <= length(sig.typeParameters), + ); } - function getInstantiatedConstructorsForTypeArguments(type: Type, typeArgumentNodes: readonly TypeNode[] | undefined, location: Node): readonly Signature[] { + function getInstantiatedConstructorsForTypeArguments( + type: Type, + typeArgumentNodes: readonly TypeNode[] | undefined, + location: Node, + ): readonly Signature[] { const signatures = getConstructorsForTypeArguments(type, typeArgumentNodes, location); const typeArguments = map(typeArgumentNodes, getTypeFromTypeNode); - return sameMap(signatures, sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments, isInJSFile(location)) : sig); + return sameMap( + signatures, + sig => some(sig.typeParameters) ? getSignatureInstantiation(sig, typeArguments, isInJSFile(location)) : sig, + ); } /** @@ -11808,11 +15324,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resolveStructuredTypeMembers(baseConstructorType as ObjectType); } if (!popTypeResolution()) { - error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol)); + error( + type.symbol.valueDeclaration, + Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, + symbolToString(type.symbol), + ); return type.resolvedBaseConstructorType = errorType; } - if (!(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== nullWideningType && !isConstructorType(baseConstructorType)) { - const err = error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType)); + if ( + !(baseConstructorType.flags & TypeFlags.Any) && baseConstructorType !== nullWideningType + && !isConstructorType(baseConstructorType) + ) { + const err = error( + baseTypeNode.expression, + Diagnostics.Type_0_is_not_a_constructor_function_type, + typeToString(baseConstructorType), + ); if (baseConstructorType.flags & TypeFlags.TypeParameter) { const constraint = getConstraintFromTypeParameter(baseConstructorType); let ctorReturn: Type = unknownType; @@ -11823,7 +15350,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (baseConstructorType.symbol.declarations) { - addRelatedInfo(err, createDiagnosticForNode(baseConstructorType.symbol.declarations[0], Diagnostics.Did_you_mean_for_0_to_be_constrained_to_type_new_args_Colon_any_1, symbolToString(baseConstructorType.symbol), typeToString(ctorReturn))); + addRelatedInfo( + err, + createDiagnosticForNode( + baseConstructorType.symbol.declarations[0], + Diagnostics.Did_you_mean_for_0_to_be_constrained_to_type_new_args_Colon_any_1, + symbolToString(baseConstructorType.symbol), + typeToString(ctorReturn), + ), + ); } } return type.resolvedBaseConstructorType = errorType; @@ -11856,7 +15391,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function reportCircularBaseType(node: Node, type: Type) { - error(node, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); + error( + node, + Diagnostics.Type_0_recursively_references_itself_as_a_base_type, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), + ); } function getBaseTypes(type: InterfaceType): BaseType[] { @@ -11878,7 +15417,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (!popTypeResolution() && type.symbol.declarations) { for (const declaration of type.symbol.declarations) { - if (declaration.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.InterfaceDeclaration) { + if ( + declaration.kind === SyntaxKind.ClassDeclaration + || declaration.kind === SyntaxKind.InterfaceDeclaration + ) { reportCircularBaseType(declaration, type); } } @@ -11890,7 +15432,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTupleBaseType(type: TupleType) { - const elementTypes = sameMap(type.typeParameters, (t, i) => type.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t); + const elementTypes = sameMap( + type.typeParameters, + (t, i) => type.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t, + ); return createArrayType(getUnionType(elementTypes || emptyArray), type.readonly); } @@ -11902,9 +15447,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const baseTypeNode = getBaseTypeNodeOfClass(type)!; let baseType: Type; - const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined; - if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class && - areAllOuterTypeParametersApplied(originalBaseType!)) { + const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) + : undefined; + if ( + baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class + && areAllOuterTypeParametersApplied(originalBaseType!) + ) { // When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the // class and all return the instance type of the class. There is no need for further checks and we can apply the // type arguments in the same manner as a type reference to get the same error reporting experience. @@ -11917,9 +15465,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The class derives from a "class-like" constructor function, check that we have at least one construct signature // with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere // we check that all instantiated signatures return the same type. - const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments, baseTypeNode); + const constructors = getInstantiatedConstructorsForTypeArguments( + baseConstructorType, + baseTypeNode.typeArguments, + baseTypeNode, + ); if (!constructors.length) { - error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments); + error( + baseTypeNode.expression, + Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments, + ); return type.resolvedBaseTypes = emptyArray; } baseType = getReturnTypeOfSignature(constructors[0]); @@ -11931,13 +15486,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const reducedBaseType = getReducedType(baseType); if (!isValidBaseType(reducedBaseType)) { const elaboration = elaborateNeverIntersection(/*errorInfo*/ undefined, baseType); - const diagnostic = chainDiagnosticMessages(elaboration, Diagnostics.Base_constructor_return_type_0_is_not_an_object_type_or_intersection_of_object_types_with_statically_known_members, typeToString(reducedBaseType)); - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(baseTypeNode.expression), baseTypeNode.expression, diagnostic)); + const diagnostic = chainDiagnosticMessages( + elaboration, + Diagnostics + .Base_constructor_return_type_0_is_not_an_object_type_or_intersection_of_object_types_with_statically_known_members, + typeToString(reducedBaseType), + ); + diagnostics.add( + createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(baseTypeNode.expression), + baseTypeNode.expression, + diagnostic, + ), + ); return type.resolvedBaseTypes = emptyArray; } if (type === reducedBaseType || hasBaseType(reducedBaseType, type)) { - error(type.symbol.valueDeclaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, - typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType)); + error( + type.symbol.valueDeclaration, + Diagnostics.Type_0_recursively_references_itself_as_a_base_type, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), + ); return type.resolvedBaseTypes = emptyArray; } if (type.resolvedBaseTypes === resolvingEmptyArray) { @@ -11972,15 +15541,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // TODO: Given that we allow type parmeters here now, is this `!isGenericMappedType(type)` check really needed? // There's no reason a `T` should be allowed while a `Readonly` should not. - return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && !isGenericMappedType(type) || - type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isValidBaseType)); + return !!(type.flags & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.Any) && !isGenericMappedType(type) + || type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isValidBaseType)); } function resolveBaseTypesOfInterface(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; if (type.symbol.declarations) { for (const declaration of type.symbol.declarations) { - if (declaration.kind === SyntaxKind.InterfaceDeclaration && getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration)) { + if ( + declaration.kind === SyntaxKind.InterfaceDeclaration + && getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration) + ) { for (const node of getInterfaceBaseTypeNodes(declaration as InterfaceDeclaration)!) { const baseType = getReducedType(getTypeFromTypeNode(node)); if (!isErrorType(baseType)) { @@ -11998,7 +15570,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else { - error(node, Diagnostics.An_interface_can_only_extend_an_object_type_or_intersection_of_object_types_with_statically_known_members); + error( + node, + Diagnostics + .An_interface_can_only_extend_an_object_type_or_intersection_of_object_types_with_statically_known_members, + ); } } } @@ -12027,8 +15603,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (baseTypeNodes) { for (const node of baseTypeNodes) { if (isEntityNameExpression(node.expression)) { - const baseSymbol = resolveEntityName(node.expression, SymbolFlags.Type, /*ignoreErrors*/ true); - if (!baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType) { + const baseSymbol = resolveEntityName( + node.expression, + SymbolFlags.Type, + /*ignoreErrors*/ true, + ); + if ( + !baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) + || getDeclaredTypeOfClassOrInterface(baseSymbol).thisType + ) { return false; } } @@ -12044,14 +15627,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const originalLinks = links; if (!links.declaredType) { const kind = symbol.flags & SymbolFlags.Class ? ObjectFlags.Class : ObjectFlags.Interface; - const merged = mergeJSSymbols(symbol, symbol.valueDeclaration && getAssignedClassSymbol(symbol.valueDeclaration)); + const merged = mergeJSSymbols( + symbol, + symbol.valueDeclaration && getAssignedClassSymbol(symbol.valueDeclaration), + ); if (merged) { // note:we overwrite links because we just cloned the symbol symbol = merged; links = merged.links; } - const type = originalLinks.declaredType = links.declaredType = createObjectType(kind, symbol) as InterfaceType; + const type = originalLinks.declaredType = links.declaredType = createObjectType( + kind, + symbol, + ) as InterfaceType; const outerTypeParameters = getOuterTypeParametersOfClassOrInterface(symbol); const localTypeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); // A class or interface is generic if it has type parameters or a "this" type. We always give classes a "this" type @@ -12059,7 +15648,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // property types inferred from initializers and method return types inferred from return statements are very hard // to exhaustively analyze). We give interfaces a "this" type if we can't definitely determine that they are free of // "this" references. - if (outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class || !isThislessInterface(symbol)) { + if ( + outerTypeParameters || localTypeParameters || kind === ObjectFlags.Class || !isThislessInterface(symbol) + ) { type.objectFlags |= ObjectFlags.Reference; type.typeParameters = concatenate(outerTypeParameters, localTypeParameters); type.outerTypeParameters = outerTypeParameters; @@ -12085,7 +15676,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return errorType; } - const declaration = Debug.checkDefined(symbol.declarations?.find(isTypeAlias), "Type alias symbol with no valid declaration found"); + const declaration = Debug.checkDefined( + symbol.declarations?.find(isTypeAlias), + "Type alias symbol with no valid declaration found", + ); const typeNode = isJSDocTypeAlias(declaration) ? declaration.typeExpression : declaration.type; // If typeNode is missing, we will error in checkJSDocTypedefTag. let type = typeNode ? getTypeFromTypeNode(typeNode) : errorType; @@ -12103,10 +15697,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { type = errorType; if (declaration.kind === SyntaxKind.JSDocEnumTag) { - error(declaration.typeExpression.type, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + error( + declaration.typeExpression.type, + Diagnostics.Type_alias_0_circularly_references_itself, + symbolToString(symbol), + ); } else { - error(isNamedDeclaration(declaration) ? declaration.name || declaration : declaration, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + error( + isNamedDeclaration(declaration) ? declaration.name || declaration : declaration, + Diagnostics.Type_alias_0_circularly_references_itself, + symbolToString(symbol), + ); } } links.declaredType = type; @@ -12115,7 +15717,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getBaseTypeOfEnumLikeType(type: Type) { - return type.flags & TypeFlags.EnumLike && type.symbol.flags & SymbolFlags.EnumMember ? getDeclaredTypeOfSymbol(getParentOfSymbol(type.symbol)!) : type; + return type.flags & TypeFlags.EnumLike && type.symbol.flags & SymbolFlags.EnumMember + ? getDeclaredTypeOfSymbol(getParentOfSymbol(type.symbol)!) : type; } function getDeclaredTypeOfEnum(symbol: Symbol): Type { @@ -12129,9 +15732,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (hasBindableName(member)) { const memberSymbol = getSymbolOfDeclaration(member); const value = getEnumMemberValue(member); - const memberType = getFreshTypeOfLiteralType(value !== undefined ? - getEnumLiteralType(value, getSymbolId(symbol), memberSymbol) : - createComputedEnumType(memberSymbol)); + const memberType = getFreshTypeOfLiteralType( + value !== undefined + ? getEnumLiteralType(value, getSymbolId(symbol), memberSymbol) + : createComputedEnumType(memberSymbol), + ); getSymbolLinks(memberSymbol).declaredType = memberType; memberTypeList.push(getRegularTypeOfLiteralType(memberType)); } @@ -12139,9 +15744,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const enumType = memberTypeList.length ? - getUnionType(memberTypeList, UnionReduction.Literal, symbol, /*aliasTypeArguments*/ undefined) : - createComputedEnumType(symbol); + const enumType = memberTypeList.length + ? getUnionType(memberTypeList, UnionReduction.Literal, symbol, /*aliasTypeArguments*/ undefined) + : createComputedEnumType(symbol); if (enumType.flags & TypeFlags.Union) { enumType.flags |= TypeFlags.EnumLiteral; enumType.symbol = symbol; @@ -12231,7 +15836,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ArrayType: return isThislessType((node as ArrayTypeNode).elementType); case SyntaxKind.TypeReference: - return !(node as TypeReferenceNode).typeArguments || (node as TypeReferenceNode).typeArguments!.every(isThislessType); + return !(node as TypeReferenceNode).typeArguments + || (node as TypeReferenceNode).typeArguments!.every(isThislessType); } return false; } @@ -12259,9 +15865,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isThislessFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { const returnType = getEffectiveReturnTypeNode(node); const typeParameters = getEffectiveTypeParameterDeclarations(node); - return (node.kind === SyntaxKind.Constructor || (!!returnType && isThislessType(returnType))) && - node.parameters.every(isThislessVariableLikeDeclaration) && - typeParameters.every(isThislessTypeParameter); + return (node.kind === SyntaxKind.Constructor || (!!returnType && isThislessType(returnType))) + && node.parameters.every(isThislessVariableLikeDeclaration) + && typeParameters.every(isThislessTypeParameter); } /** @@ -12284,7 +15890,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return isThislessFunctionLikeDeclaration(declaration as FunctionLikeDeclaration | AccessorDeclaration); + return isThislessFunctionLikeDeclaration( + declaration as FunctionLikeDeclaration | AccessorDeclaration, + ); } } } @@ -12293,10 +15901,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The mappingThisOnly flag indicates that the only type parameter being mapped is "this". When the flag is true, // we check symbols to see if we can quickly conclude they are free of "this" references, thus needing no instantiation. - function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper, mappingThisOnly: boolean): SymbolTable { + function createInstantiatedSymbolTable( + symbols: Symbol[], + mapper: TypeMapper, + mappingThisOnly: boolean, + ): SymbolTable { const result = createSymbolTable(); for (const symbol of symbols) { - result.set(symbol.escapedName, mappingThisOnly && isThisless(symbol) ? symbol : instantiateSymbol(symbol, mapper)); + result.set( + symbol.escapedName, + mappingThisOnly && isThisless(symbol) ? symbol : instantiateSymbol(symbol, mapper), + ); } return result; } @@ -12307,20 +15922,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { continue; } const derived = symbols.get(base.escapedName); - if (!derived + if ( + !derived // non-constructor/static-block assignment declarations are ignored here; they're not treated as overrides || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration) && !isConstructorDeclaredProperty(derived) - && !getContainingClassStaticBlock(derived.valueDeclaration)) { - symbols.set(base.escapedName, base); + && !getContainingClassStaticBlock(derived.valueDeclaration) + ) { + symbols.set(base.escapedName, base); symbols.set(base.escapedName, base); } } } function isStaticPrivateIdentifierProperty(s: Symbol): boolean { - return !!s.valueDeclaration && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) && isStatic(s.valueDeclaration); + return !!s.valueDeclaration && isPrivateIdentifierClassElementDeclaration(s.valueDeclaration) + && isStatic(s.valueDeclaration); } function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers { @@ -12333,8 +15951,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = emptyArray; (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = emptyArray; - (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.Call)); - (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = getSignaturesOfSymbol(members.get(InternalSymbolName.New)); + (type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = getSignaturesOfSymbol( + members.get(InternalSymbolName.Call), + ); + (type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = getSignaturesOfSymbol( + members.get(InternalSymbolName.New), + ); (type as InterfaceTypeWithDeclaredMembers).declaredIndexInfos = getIndexInfosOfSymbol(symbol); } return type as InterfaceTypeWithDeclaredMembers; @@ -12354,19 +15976,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const expr = isComputedPropertyName(node) ? node.expression : node.argumentExpression; return isEntityNameExpression(expr) - && isTypeUsableAsPropertyName(isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached(expr)); + && isTypeUsableAsPropertyName( + isComputedPropertyName(node) ? checkComputedPropertyName(node) : checkExpressionCached(expr), + ); } function isLateBoundName(name: __String): boolean { - return (name as string).charCodeAt(0) === CharacterCodes._ && - (name as string).charCodeAt(1) === CharacterCodes._ && - (name as string).charCodeAt(2) === CharacterCodes.at; + return (name as string).charCodeAt(0) === CharacterCodes._ + && (name as string).charCodeAt(1) === CharacterCodes._ + && (name as string).charCodeAt(2) === CharacterCodes.at; } /** * Indicates whether a declaration has a late-bindable dynamic name. */ - function hasLateBindableName(node: Declaration): node is LateBoundDeclaration | LateBoundBinaryExpressionDeclaration { + function hasLateBindableName( + node: Declaration, + ): node is LateBoundDeclaration | LateBoundBinaryExpressionDeclaration { const name = getNameOfDeclaration(node); return !!name && isLateBindableName(name); } @@ -12390,14 +16016,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * late-bound members that `addDeclarationToSymbol` in binder.ts performs for early-bound * members. */ - function addDeclarationToLateBoundSymbol(symbol: Symbol, member: LateBoundDeclaration | BinaryExpression, symbolFlags: SymbolFlags) { + function addDeclarationToLateBoundSymbol( + symbol: Symbol, + member: LateBoundDeclaration | BinaryExpression, + symbolFlags: SymbolFlags, + ) { Debug.assert(!!(getCheckFlags(symbol) & CheckFlags.Late), "Expected a late-bound symbol."); symbol.flags |= symbolFlags; getSymbolLinks(member.symbol).lateSymbol = symbol; if (!symbol.declarations) { symbol.declarations = [member]; } - else if(!member.symbol.isReplaceableByMethod) { + else if (!member.symbol.isReplaceableByMethod) { symbol.declarations.push(member); } if (symbolFlags & SymbolFlags.Value) { @@ -12435,7 +16065,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param lateSymbols The late-bound symbols of the parent. * @param decl The member to bind. */ - function lateBindMember(parent: Symbol, earlySymbols: SymbolTable | undefined, lateSymbols: Map<__String, TransientSymbol>, decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration) { + function lateBindMember( + parent: Symbol, + earlySymbols: SymbolTable | undefined, + lateSymbols: Map<__String, TransientSymbol>, + decl: LateBoundDeclaration | LateBoundBinaryExpressionDeclaration, + ) { Debug.assert(!!decl.symbol, "The member is expected to have a symbol."); const links = getNodeLinks(decl); if (!links.resolvedSymbol) { @@ -12443,14 +16078,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // fall back to the early-bound name of this member. links.resolvedSymbol = decl.symbol; const declName = isBinaryExpression(decl) ? decl.left : decl.name; - const type = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) : checkComputedPropertyName(declName); + const type = isElementAccessExpression(declName) ? checkExpressionCached(declName.argumentExpression) + : checkComputedPropertyName(declName); if (isTypeUsableAsPropertyName(type)) { const memberName = getPropertyNameFromType(type); const symbolFlags = decl.symbol.flags; // Get or add a late-bound symbol for the member. This allows us to merge late-bound accessor declarations. let lateSymbol = lateSymbols.get(memberName); - if (!lateSymbol) lateSymbols.set(memberName, lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late)); + if (!lateSymbol) { + lateSymbols.set( + memberName, + lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late), + ); + } // Report an error if a late-bound member has the same name as an early-bound member, // or if we have another early-bound symbol declaration with the same name and @@ -12459,9 +16100,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (lateSymbol.flags & getExcludedSymbolFlags(symbolFlags) || earlySymbol) { // If we have an existing early-bound member, combine its declarations so that we can // report an error at each declaration. - const declarations = earlySymbol ? concatenate(earlySymbol.declarations, lateSymbol.declarations) : lateSymbol.declarations; - const name = !(type.flags & TypeFlags.UniqueESSymbol) && unescapeLeadingUnderscores(memberName) || declarationNameToString(declName); - forEach(declarations, declaration => error(getNameOfDeclaration(declaration) || declaration, Diagnostics.Property_0_was_also_declared_here, name)); + const declarations = earlySymbol ? concatenate(earlySymbol.declarations, lateSymbol.declarations) + : lateSymbol.declarations; + const name = !(type.flags & TypeFlags.UniqueESSymbol) && unescapeLeadingUnderscores(memberName) + || declarationNameToString(declName); + forEach( + declarations, + declaration => + error( + getNameOfDeclaration(declaration) || declaration, + Diagnostics.Property_0_was_also_declared_here, + name, + ), + ); error(declName || decl, Diagnostics.Duplicate_property_0, name); lateSymbol = createSymbol(SymbolFlags.None, memberName, CheckFlags.Late); } @@ -12479,13 +16130,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.resolvedSymbol; } - function getResolvedMembersOrExportsOfSymbol(symbol: Symbol, resolutionKind: MembersOrExportsResolutionKind): Map<__String, Symbol> { + function getResolvedMembersOrExportsOfSymbol( + symbol: Symbol, + resolutionKind: MembersOrExportsResolutionKind, + ): Map<__String, Symbol> { const links = getSymbolLinks(symbol); if (!links[resolutionKind]) { const isStatic = resolutionKind === MembersOrExportsResolutionKind.resolvedExports; - const earlySymbols = !isStatic ? symbol.members : - symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol).exports : - symbol.exports; + const earlySymbols = !isStatic ? symbol.members + : symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol).exports + : symbol.exports; // In the event we recursively resolve the members/exports of the symbol, we // set the initial value of resolvedMembers/resolvedExports to the early-bound @@ -12506,9 +16160,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const assignments = (symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction || symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression) && - getSymbolOfNode(symbol.valueDeclaration.parent)?.assignmentDeclarationMembers || - symbol.assignmentDeclarationMembers; + const assignments = (symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction + || symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression) + && getSymbolOfNode(symbol.valueDeclaration.parent)?.assignmentDeclarationMembers + || symbol.assignmentDeclarationMembers; if (assignments) { const decls = arrayFrom(assignments.values()); @@ -12571,16 +16226,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getObjectFlags(type) & ObjectFlags.Reference) { const target = (type as TypeReference).target; const typeArguments = getTypeArguments(type as TypeReference); - return length(target.typeParameters) === length(typeArguments) ? createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])) : type; + return length(target.typeParameters) === length(typeArguments) + ? createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType!])) : type; } else if (type.flags & TypeFlags.Intersection) { - const types = sameMap((type as IntersectionType).types, t => getTypeWithThisArgument(t, thisArgument, needApparentType)); + const types = sameMap( + (type as IntersectionType).types, + t => getTypeWithThisArgument(t, thisArgument, needApparentType), + ); return types !== (type as IntersectionType).types ? getIntersectionType(types) : type; } return needApparentType ? getApparentType(type) : type; } - function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: readonly TypeParameter[], typeArguments: readonly Type[]) { + function resolveObjectTypeMembers( + type: ObjectType, + source: InterfaceTypeWithDeclaredMembers, + typeParameters: readonly TypeParameter[], + typeArguments: readonly Type[], + ) { let mapper: TypeMapper | undefined; let members: SymbolTable; let callSignatures: readonly Signature[]; @@ -12594,7 +16258,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { mapper = createTypeMapper(typeParameters, typeArguments); - members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1); + members = createInstantiatedSymbolTable( + source.declaredProperties, + mapper, + /*mappingThisOnly*/ typeParameters.length === 1, + ); callSignatures = instantiateSignatures(source.declaredCallSignatures, mapper); constructSignatures = instantiateSignatures(source.declaredConstructSignatures, mapper); indexInfos = instantiateIndexInfos(source.declaredIndexInfos, mapper); @@ -12607,12 +16275,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); const thisArgument = lastOrUndefined(typeArguments); for (const baseType of baseTypes) { - const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType; + const instantiatedBaseType = thisArgument + ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType; addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType)); - callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call)); - constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct)); - const inheritedIndexInfos = instantiatedBaseType !== anyType ? getIndexInfosOfType(instantiatedBaseType) : [createIndexInfo(stringType, anyType, /*isReadonly*/ false)]; - indexInfos = concatenate(indexInfos, filter(inheritedIndexInfos, info => !findIndexInfo(indexInfos, info.keyType))); + callSignatures = concatenate( + callSignatures, + getSignaturesOfType(instantiatedBaseType, SignatureKind.Call), + ); + constructSignatures = concatenate( + constructSignatures, + getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct), + ); + const inheritedIndexInfos = instantiatedBaseType !== anyType ? getIndexInfosOfType(instantiatedBaseType) + : [createIndexInfo(stringType, anyType, /*isReadonly*/ false)]; + indexInfos = concatenate( + indexInfos, + filter(inheritedIndexInfos, info => !findIndexInfo(indexInfos, info.keyType)), + ); } } setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); @@ -12626,7 +16305,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const source = resolveDeclaredMembers(type.target); const typeParameters = concatenate(source.typeParameters!, [source.thisType!]); const typeArguments = getTypeArguments(type); - const paddedTypeArguments = typeArguments.length === typeParameters.length ? typeArguments : concatenate(typeArguments, [type]); + const paddedTypeArguments = typeArguments.length === typeParameters.length ? typeArguments + : concatenate(typeArguments, [type]); resolveObjectTypeMembers(type, source, typeParameters, paddedTypeArguments); } @@ -12638,7 +16318,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resolvedReturnType: Type | undefined, resolvedTypePredicate: TypePredicate | undefined, minArgumentCount: number, - flags: SignatureFlags + flags: SignatureFlags, ): Signature { const sig = new Signature(checker, flags); sig.declaration = declaration; @@ -12657,8 +16337,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function cloneSignature(sig: Signature): Signature { - const result = createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, /*resolvedReturnType*/ undefined, - /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags); + const result = createSignature( + sig.declaration, + sig.typeParameters, + sig.thisParameter, + sig.parameters, + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + sig.minArgumentCount, + sig.flags & SignatureFlags.PropagatingFlags, + ); result.target = sig.target; result.mapper = sig.mapper; result.compositeSignatures = sig.compositeSignatures; @@ -12688,8 +16376,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags) { - Debug.assert(callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain, - "An optional call signature can either be for an inner call chain or an outer call chain, but not both."); + Debug.assert( + callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain, + "An optional call signature can either be for an inner call chain or an outer call chain, but not both.", + ); const result = cloneSignature(signature); result.flags |= callChainFlags; return result; @@ -12703,22 +16393,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isTupleType(restType)) { return [expandSignatureParametersWithTupleMembers(restType, restIndex, restName)]; } - else if (!skipUnionExpanding && restType.flags & TypeFlags.Union && every((restType as UnionType).types, isTupleType)) { - return map((restType as UnionType).types, t => expandSignatureParametersWithTupleMembers(t as TupleTypeReference, restIndex, restName)); + else if ( + !skipUnionExpanding && restType.flags & TypeFlags.Union + && every((restType as UnionType).types, isTupleType) + ) { + return map( + (restType as UnionType).types, + t => expandSignatureParametersWithTupleMembers(t as TupleTypeReference, restIndex, restName), + ); } } return [sig.parameters]; - function expandSignatureParametersWithTupleMembers(restType: TupleTypeReference, restIndex: number, restName: __String) { + function expandSignatureParametersWithTupleMembers( + restType: TupleTypeReference, + restIndex: number, + restName: __String, + ) { const elementTypes = getTypeArguments(restType); const associatedNames = getUniqAssociatedNamesFromTupleType(restType, restName); const restParams = map(elementTypes, (t, i) => { // Lookup the label from the individual tuple passed in before falling back to the signature `rest` parameter name - const name = associatedNames && associatedNames[i] ? associatedNames[i] : - getParameterNameAtPosition(sig, restIndex + i, restType); + const name = associatedNames && associatedNames[i] ? associatedNames[i] + : getParameterNameAtPosition(sig, restIndex + i, restType); const flags = restType.target.elementFlags[i]; - const checkFlags = flags & ElementFlags.Variable ? CheckFlags.RestParameter : - flags & ElementFlags.Optional ? CheckFlags.OptionalParameter : 0; + const checkFlags = flags & ElementFlags.Variable ? CheckFlags.RestParameter + : flags & ElementFlags.Optional ? CheckFlags.OptionalParameter : 0; const symbol = createSymbol(SymbolFlags.FunctionScopedVariable, name, checkFlags); symbol.links.type = flags & ElementFlags.Rest ? createArrayType(t) : t; return symbol; @@ -12749,7 +16449,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const declaration = getClassLikeDeclarationOfSymbol(classType.symbol); const isAbstract = !!declaration && hasSyntacticModifier(declaration, ModifierFlags.Abstract); if (baseSignatures.length === 0) { - return [createSignature(/*declaration*/ undefined, classType.localTypeParameters, /*thisParameter*/ undefined, emptyArray, classType, /*resolvedTypePredicate*/ undefined, 0, isAbstract ? SignatureFlags.Abstract : SignatureFlags.None)]; + return [ + createSignature( + /*declaration*/ undefined, + classType.localTypeParameters, + /*thisParameter*/ undefined, + emptyArray, + classType, + /*resolvedTypePredicate*/ undefined, + 0, + isAbstract ? SignatureFlags.Abstract : SignatureFlags.None, + ), + ]; } const baseTypeNode = getBaseTypeNodeOfClass(classType)!; const isJavaScript = isInJSFile(baseTypeNode); @@ -12760,7 +16471,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const minTypeArgumentCount = getMinTypeArgumentCount(baseSig.typeParameters); const typeParamCount = length(baseSig.typeParameters); if (isJavaScript || typeArgCount >= minTypeArgumentCount && typeArgCount <= typeParamCount) { - const sig = typeParamCount ? createSignatureInstantiation(baseSig, fillMissingTypeArguments(typeArguments, baseSig.typeParameters, minTypeArgumentCount, isJavaScript)) : cloneSignature(baseSig); + const sig = typeParamCount + ? createSignatureInstantiation( + baseSig, + fillMissingTypeArguments( + typeArguments, + baseSig.typeParameters, + minTypeArgumentCount, + isJavaScript, + ), + ) : cloneSignature(baseSig); sig.typeParameters = classType.localTypeParameters; sig.resolvedReturnType = classType; sig.flags = isAbstract ? sig.flags | SignatureFlags.Abstract : sig.flags & ~SignatureFlags.Abstract; @@ -12770,15 +16490,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function findMatchingSignature(signatureList: readonly Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature | undefined { + function findMatchingSignature( + signatureList: readonly Signature[], + signature: Signature, + partialMatch: boolean, + ignoreThisTypes: boolean, + ignoreReturnTypes: boolean, + ): Signature | undefined { for (const s of signatureList) { - if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, partialMatch ? compareTypesSubtypeOf : compareTypesIdentical)) { + if ( + compareSignaturesIdentical( + s, + signature, + partialMatch, + ignoreThisTypes, + ignoreReturnTypes, + partialMatch ? compareTypesSubtypeOf : compareTypesIdentical, + ) + ) { return s; } } } - function findMatchingSignatures(signatureLists: readonly (readonly Signature[])[], signature: Signature, listIndex: number): Signature[] | undefined { + function findMatchingSignatures( + signatureLists: readonly (readonly Signature[])[], + signature: Signature, + listIndex: number, + ): Signature[] | undefined { if (signature.typeParameters) { // We require an exact match for generic signatures, so we only return signatures from the first // signature list and only if they have exact matches in the other signature lists. @@ -12786,7 +16525,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } for (let i = 1; i < signatureLists.length; i++) { - if (!findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false)) { + if ( + !findMatchingSignature( + signatureLists[i], + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false, + ) + ) { return undefined; } } @@ -12796,7 +16543,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < signatureLists.length; i++) { // Allow matching non-generic signatures to have excess parameters and different return types. // Prefer matching this types if possible. - const match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true); + const match = i === listIndex ? signature + : findMatchingSignature( + signatureLists[i], + signature, + /*partialMatch*/ true, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true, + ); if (!match) { return undefined; } @@ -12819,16 +16573,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } for (const signature of signatureLists[i]) { // Only process signatures with parameter lists that aren't already in the result list - if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ true)) { + if ( + !result + || !findMatchingSignature( + result, + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ true, + ) + ) { const unionSignatures = findMatchingSignatures(signatureLists, signature, i); if (unionSignatures) { let s = signature; // Union the result types when more than one signature matches if (unionSignatures.length > 1) { let thisParameter = signature.thisParameter; - const firstThisParameterOfUnionSignatures = forEach(unionSignatures, sig => sig.thisParameter); + const firstThisParameterOfUnionSignatures = forEach( + unionSignatures, + sig => sig.thisParameter, + ); if (firstThisParameterOfUnionSignatures) { - const thisType = getIntersectionType(mapDefined(unionSignatures, sig => sig.thisParameter && getTypeOfSymbol(sig.thisParameter))); + const thisType = getIntersectionType( + mapDefined( + unionSignatures, + sig => sig.thisParameter && getTypeOfSymbol(sig.thisParameter), + ), + ); thisParameter = createSymbolWithType(firstThisParameterOfUnionSignatures, thisType); } s = createUnionSignature(signature, unionSignatures); @@ -12849,8 +16620,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const signatures of signatureLists) { if (signatures !== masterList) { const signature = signatures[0]; - Debug.assert(!!signature, "getUnionSignatures bails early on empty signature lists and should not have empty lists on second pass"); - results = !!signature.typeParameters && some(results, s => !!s.typeParameters && !compareTypeParametersIdentical(signature.typeParameters, s.typeParameters)) ? undefined : map(results, sig => combineSignaturesOfUnionMembers(sig, signature)); + Debug.assert( + !!signature, + "getUnionSignatures bails early on empty signature lists and should not have empty lists on second pass", + ); + results = !!signature.typeParameters && some(results, s => + !!s.typeParameters + && !compareTypeParametersIdentical(signature.typeParameters, s.typeParameters)) ? undefined + : map(results, sig => combineSignaturesOfUnionMembers(sig, signature)); if (!results) { break; } @@ -12861,7 +16638,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result || emptyArray; } - function compareTypeParametersIdentical(sourceParams: readonly TypeParameter[] | undefined, targetParams: readonly TypeParameter[] | undefined): boolean { + function compareTypeParametersIdentical( + sourceParams: readonly TypeParameter[] | undefined, + targetParams: readonly TypeParameter[] | undefined, + ): boolean { if (length(sourceParams) !== length(targetParams)) { return false; } @@ -12875,7 +16655,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const target = targetParams[i]; if (source === target) continue; // We instantiate the target type parameter constraints into the source types so we can recognize `` as the same as `` - if (!isTypeIdenticalTo(getConstraintFromTypeParameter(source) || unknownType, instantiateType(getConstraintFromTypeParameter(target) || unknownType, mapper))) return false; + if ( + !isTypeIdenticalTo( + getConstraintFromTypeParameter(source) || unknownType, + instantiateType(getConstraintFromTypeParameter(target) || unknownType, mapper), + ) + ) return false; // We don't compare defaults - we just use the type parameter defaults from the first signature that seems to match. // It might make sense to combine these defaults in the future, but doing so intelligently requires knowing // if the parameter is used covariantly or contravariantly (so we intersect if it's used like a parameter or union if used like a return type) @@ -12885,7 +16670,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function combineUnionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { + function combineUnionThisParam( + left: Symbol | undefined, + right: Symbol | undefined, + mapper: TypeMapper | undefined, + ): Symbol | undefined { if (!left || !right) { return left || right; } @@ -12902,7 +16691,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const longest = leftCount >= rightCount ? left : right; const shorter = longest === left ? right : left; const longestCount = longest === left ? leftCount : rightCount; - const eitherHasEffectiveRest = (hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right)); + const eitherHasEffectiveRest = hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right); const needsExtraRestElement = eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); const params = new Array(longestCount + (needsExtraRestElement ? 1 : 0)); for (let i = 0; i < longestCount; i++) { @@ -12920,13 +16709,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); - const paramName = leftName === rightName ? leftName : - !leftName ? rightName : - !rightName ? leftName : - undefined; + const paramName = leftName === rightName ? leftName + : !leftName ? rightName + : !rightName ? leftName + : undefined; const paramSymbol = createSymbol( SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), - paramName || `arg${i}` as __String + paramName || `arg${i}` as __String, ); paramSymbol.links.type = isRestParam ? createArrayType(unionParamType) : unionParamType; params[i] = paramSymbol; @@ -12961,12 +16750,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, minArgCount, - (left.flags | right.flags) & SignatureFlags.PropagatingFlags + (left.flags | right.flags) & SignatureFlags.PropagatingFlags, ); result.compositeKind = TypeFlags.Union; - result.compositeSignatures = concatenate(left.compositeKind !== TypeFlags.Intersection && left.compositeSignatures || [left], [right]); + result.compositeSignatures = concatenate( + left.compositeKind !== TypeFlags.Intersection && left.compositeSignatures || [left], + [right], + ); if (paramMapper) { - result.mapper = left.compositeKind !== TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; + result.mapper = left.compositeKind !== TypeFlags.Intersection && left.mapper && left.compositeSignatures + ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; } return result; } @@ -12978,8 +16771,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const info of sourceInfos) { const indexType = info.keyType; if (every(types, t => !!getIndexInfoOfType(t, indexType))) { - result.push(createIndexInfo(indexType, getUnionType(map(types, t => getIndexTypeOfType(t, indexType)!)), - some(types, t => getIndexInfoOfType(t, indexType)!.isReadonly))); + result.push( + createIndexInfo( + indexType, + getUnionType(map(types, t => getIndexTypeOfType(t, indexType)!)), + some(types, t => getIndexInfoOfType(t, indexType)!.isReadonly), + ), + ); } } return result; @@ -12990,8 +16788,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function resolveUnionTypeMembers(type: UnionType) { // The members and properties collections are empty for union types. To get all properties of a union // type use getPropertiesOfType (only the language service uses this). - const callSignatures = getUnionSignatures(map(type.types, t => t === globalFunctionType ? [unknownSignature] : getSignaturesOfType(t, SignatureKind.Call))); - const constructSignatures = getUnionSignatures(map(type.types, t => getSignaturesOfType(t, SignatureKind.Construct))); + const callSignatures = getUnionSignatures( + map( + type.types, + t => t === globalFunctionType ? [unknownSignature] : getSignaturesOfType(t, SignatureKind.Call), + ), + ); + const constructSignatures = getUnionSignatures( + map(type.types, t => getSignaturesOfType(t, SignatureKind.Construct)), + ); const indexInfos = getUnionIndexInfos(type.types); setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, indexInfos); } @@ -13003,9 +16808,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function findMixins(types: readonly Type[]): readonly boolean[] { - const constructorTypeCount = countWhere(types, (t) => getSignaturesOfType(t, SignatureKind.Construct).length > 0); + const constructorTypeCount = countWhere(types, t => getSignaturesOfType(t, SignatureKind.Construct).length > 0); const mixinFlags = map(types, isMixinConstructorType); - if (constructorTypeCount > 0 && constructorTypeCount === countWhere(mixinFlags, (b) => b)) { + if (constructorTypeCount > 0 && constructorTypeCount === countWhere(mixinFlags, b => b)) { const firstMixinIndex = mixinFlags.indexOf(/*searchElement*/ true); mixinFlags[firstMixinIndex] = false; } @@ -13033,7 +16838,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let indexInfos: IndexInfo[] | undefined; const types = type.types; const mixinFlags = findMixins(types); - const mixinCount = countWhere(mixinFlags, (b) => b); + const mixinCount = countWhere(mixinFlags, b => b); for (let i = 0; i < types.length; i++) { const t = type.types[i]; // When an intersection type contains mixin constructor types, the construct signatures from @@ -13053,14 +16858,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { constructSignatures = appendSignatures(constructSignatures, signatures); } callSignatures = appendSignatures(callSignatures, getSignaturesOfType(t, SignatureKind.Call)); - indexInfos = reduceLeft(getIndexInfosOfType(t), (infos, newInfo) => appendIndexInfo(infos, newInfo, /*union*/ false), indexInfos); + indexInfos = reduceLeft( + getIndexInfosOfType(t), + (infos, newInfo) => appendIndexInfo(infos, newInfo, /*union*/ false), + indexInfos, + ); } - setStructuredTypeMembers(type, emptySymbols, callSignatures || emptyArray, constructSignatures || emptyArray, indexInfos || emptyArray); + setStructuredTypeMembers( + type, + emptySymbols, + callSignatures || emptyArray, + constructSignatures || emptyArray, + indexInfos || emptyArray, + ); } function appendSignatures(signatures: Signature[] | undefined, newSignatures: readonly Signature[]) { for (const sig of newSignatures) { - if (!signatures || every(signatures, s => !compareSignaturesIdentical(s, sig, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, compareTypesIdentical))) { + if ( + !signatures || every(signatures, s => + !compareSignaturesIdentical( + s, + sig, + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false, + compareTypesIdentical, + )) + ) { signatures = append(signatures, sig); } } @@ -13072,9 +16897,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < indexInfos.length; i++) { const info = indexInfos[i]; if (info.keyType === newInfo.keyType) { - indexInfos[i] = createIndexInfo(info.keyType, - union ? getUnionType([info.type, newInfo.type]) : getIntersectionType([info.type, newInfo.type]), - union ? info.isReadonly || newInfo.isReadonly : info.isReadonly && newInfo.isReadonly); + indexInfos[i] = createIndexInfo( + info.keyType, + union ? getUnionType([info.type, newInfo.type]) + : getIntersectionType([info.type, newInfo.type]), + union ? info.isReadonly || newInfo.isReadonly : info.isReadonly && newInfo.isReadonly, + ); return indexInfos; } } @@ -13088,9 +16916,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function resolveAnonymousTypeMembers(type: AnonymousType) { if (type.target) { setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, emptyArray); - const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper!, /*mappingThisOnly*/ false); - const callSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper!); - const constructSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper!); + const members = createInstantiatedSymbolTable( + getPropertiesOfObjectType(type.target), + type.mapper!, + /*mappingThisOnly*/ false, + ); + const callSignatures = instantiateSignatures( + getSignaturesOfType(type.target, SignatureKind.Call), + type.mapper!, + ); + const constructSignatures = instantiateSignatures( + getSignaturesOfType(type.target, SignatureKind.Construct), + type.mapper!, + ); const indexInfos = instantiateIndexInfos(getIndexInfosOfType(type.target), type.mapper!); setStructuredTypeMembers(type, members, callSignatures, constructSignatures, indexInfos); return; @@ -13111,7 +16949,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (symbol === globalThisSymbol) { const varsOnly = new Map<__String, Symbol>(); members.forEach(p => { - if (!(p.flags & SymbolFlags.BlockScoped) && !(p.flags & SymbolFlags.ValueModule && p.declarations?.length && every(p.declarations, isAmbientModule))) { + if ( + !(p.flags & SymbolFlags.BlockScoped) + && !(p.flags & SymbolFlags.ValueModule && p.declarations?.length + && every(p.declarations, isAmbientModule)) + ) { varsOnly.set(p.escapedName, p); } }); @@ -13139,8 +16981,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (baseConstructorIndexInfo) { indexInfos = append(indexInfos, baseConstructorIndexInfo); } - if (symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum || - some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike)))) { + if ( + symbol.flags & SymbolFlags.Enum && (getDeclaredTypeOfSymbol(symbol).flags & TypeFlags.Enum + || some(type.properties, prop => !!(getTypeOfSymbol(prop).flags & TypeFlags.NumberLike))) + ) { indexInfos = append(indexInfos, enumNumberIndexInfo); } } @@ -13155,13 +16999,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // And likewise for construct signatures for classes if (symbol.flags & SymbolFlags.Class) { const classType = getDeclaredTypeOfClassOrInterface(symbol); - let constructSignatures = symbol.members ? getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor)) : emptyArray; + let constructSignatures = symbol.members + ? getSignaturesOfSymbol(symbol.members.get(InternalSymbolName.Constructor)) : emptyArray; if (symbol.flags & SymbolFlags.Function) { - constructSignatures = addRange(constructSignatures.slice(), mapDefined( - type.callSignatures, - sig => isJSConstructor(sig.declaration) ? - createSignature(sig.declaration, sig.typeParameters, sig.thisParameter, sig.parameters, classType, /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags) : - undefined)); + constructSignatures = addRange( + constructSignatures.slice(), + mapDefined( + type.callSignatures, + sig => + isJSConstructor(sig.declaration) + ? createSignature( + sig.declaration, + sig.typeParameters, + sig.thisParameter, + sig.parameters, + classType, + /*resolvedTypePredicate*/ undefined, + sig.minArgumentCount, + sig.flags & SignatureFlags.PropagatingFlags, + ) + : undefined, + ), + ); } if (!constructSignatures.length) { constructSignatures = getDefaultConstructSignatures(classType); @@ -13170,12 +17029,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - type ReplaceableIndexedAccessType = IndexedAccessType & { objectType: TypeParameter, indexType: TypeParameter }; + type ReplaceableIndexedAccessType = IndexedAccessType & { objectType: TypeParameter; indexType: TypeParameter; }; function replaceIndexedAccess(instantiable: Type, type: ReplaceableIndexedAccessType, replacement: Type) { // map type.indexType to 0 // map type.objectType to `[TReplacement]` // thus making the indexed access `[TReplacement][0]` or `TReplacement` - return instantiateType(instantiable, createTypeMapper([type.indexType, type.objectType], [getNumberLiteralType(0), createTupleType([replacement])])); + return instantiateType( + instantiable, + createTypeMapper([type.indexType, type.objectType], [ + getNumberLiteralType(0), + createTupleType([replacement]), + ]), + ); } function resolveReverseMappedTypeMembers(type: ReverseMappedType) { @@ -13183,22 +17048,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const modifiers = getMappedTypeModifiers(type.mappedType); const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true; const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional; - const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType), readonlyMask && indexInfo.isReadonly)] : emptyArray; + const indexInfos = indexInfo + ? [createIndexInfo( + stringType, + inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType), + readonlyMask && indexInfo.isReadonly, + )] : emptyArray; const members = createSymbolTable(); for (const prop of getPropertiesOfType(type.source)) { - const checkFlags = CheckFlags.ReverseMapped | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0); - const inferredProp = createSymbol(SymbolFlags.Property | prop.flags & optionalMask, prop.escapedName, checkFlags) as ReverseMappedSymbol; + const checkFlags = CheckFlags.ReverseMapped + | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0); + const inferredProp = createSymbol( + SymbolFlags.Property | prop.flags & optionalMask, + prop.escapedName, + checkFlags, + ) as ReverseMappedSymbol; inferredProp.declarations = prop.declarations; inferredProp.links.nameType = getSymbolLinks(prop).nameType; inferredProp.links.propertyType = getTypeOfSymbol(prop); - if (type.constraintType.type.flags & TypeFlags.IndexedAccess + if ( + type.constraintType.type.flags & TypeFlags.IndexedAccess && (type.constraintType.type as IndexedAccessType).objectType.flags & TypeFlags.TypeParameter - && (type.constraintType.type as IndexedAccessType).indexType.flags & TypeFlags.TypeParameter) { + && (type.constraintType.type as IndexedAccessType).indexType.flags & TypeFlags.TypeParameter + ) { // A reverse mapping of `{[K in keyof T[K_1]]: T[K_1]}` is the same as that of `{[K in keyof T]: T}`, since all we care about is // inferring to the "type parameter" (or indexed access) shared by the constraint and template. So, to reduce the number of // type identities produced, we simplify such indexed access occurences const newTypeParam = (type.constraintType.type as IndexedAccessType).objectType; - const newMappedType = replaceIndexedAccess(type.mappedType, type.constraintType.type as ReplaceableIndexedAccessType, newTypeParam); + const newMappedType = replaceIndexedAccess( + type.mappedType, + type.constraintType.type as ReplaceableIndexedAccessType, + newTypeParam, + ); inferredProp.links.mappedType = newMappedType as MappedType; inferredProp.links.constraintType = getIndexType(newTypeParam) as IndexType; } @@ -13224,7 +17105,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const checkType = (type as ConditionalType).checkType; const constraint = getLowerBoundOfKeyType(checkType); if (constraint !== checkType) { - return getConditionalTypeInstantiation(type as ConditionalType, prependTypeMapping((type as ConditionalType).root.checkType, constraint, (type as ConditionalType).mapper)); + return getConditionalTypeInstantiation( + type as ConditionalType, + prependTypeMapping( + (type as ConditionalType).root.checkType, + constraint, + (type as ConditionalType).mapper, + ), + ); } } return type; @@ -13236,7 +17124,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Similarly to getTypeFromIntersectionTypeNode, we preserve the special string & {}, number & {}, // and bigint & {} intersections that are used to prevent subtype reduction in union types. const types = (type as IntersectionType).types; - if (types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) && types[1] === emptyTypeLiteralType) { + if ( + types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) + && types[1] === emptyTypeLiteralType + ) { return type; } return getIntersectionType(sameMap((type as UnionType).types, getLowerBoundOfKeyType)); @@ -13248,7 +17139,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getCheckFlags(s) & CheckFlags.Late; } - function forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(type: Type, include: TypeFlags, stringsOnly: boolean, cb: (keyType: Type) => void) { + function forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + type: Type, + include: TypeFlags, + stringsOnly: boolean, + cb: (keyType: Type) => void, + ) { for (const prop of getPropertiesOfType(type)) { cb(getLiteralTypeFromProperty(prop, include)); } @@ -13283,7 +17179,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const include = keyofStringsOnly ? TypeFlags.StringLiteral : TypeFlags.StringOrNumberLiteralOrUnique; if (isMappedTypeWithKeyofConstraintDeclaration(type)) { // We have a { [P in keyof T]: X } - forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(modifiersType, include, keyofStringsOnly, addMemberForKeyType); + forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + modifiersType, + include, + keyofStringsOnly, + addMemberForKeyType, + ); } else { forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType); @@ -13291,7 +17192,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos || emptyArray); function addMemberForKeyType(keyType: Type) { - const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; + const propNameType = nameType + ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; forEachType(propNameType, t => addMemberForKeyTypeWorker(keyType, t)); } @@ -13309,15 +17211,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { existingProp.links.keyType = getUnionType([existingProp.links.keyType, keyType]); } else { - const modifiersProp = isTypeUsableAsPropertyName(keyType) ? getPropertyOfType(modifiersType, getPropertyNameFromType(keyType)) : undefined; - const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional || - !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional); - const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly || - !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp)); - const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional; + const modifiersProp = isTypeUsableAsPropertyName(keyType) + ? getPropertyOfType(modifiersType, getPropertyNameFromType(keyType)) : undefined; + const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional + || !(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp + && modifiersProp.flags & SymbolFlags.Optional); + const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly + || !(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp + && isReadonlySymbol(modifiersProp)); + const stripOptional = strictNullChecks && !isOptional && modifiersProp + && modifiersProp.flags & SymbolFlags.Optional; const lateFlag: CheckFlags = modifiersProp ? getIsLateCheckFlag(modifiersProp) : 0; - const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, - lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0)) as MappedSymbol; + const prop = createSymbol( + SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), + propName, + lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) + | (stripOptional ? CheckFlags.StripOptional : 0), + ) as MappedSymbol; prop.links.mappedType = type; prop.links.nameType = propNameType; prop.links.keyType = keyType; @@ -13329,11 +17239,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (isValidIndexKeyType(propNameType) || propNameType.flags & (TypeFlags.Any | TypeFlags.Enum)) { - const indexKeyType = propNameType.flags & (TypeFlags.Any | TypeFlags.String) ? stringType : - propNameType.flags & (TypeFlags.Number | TypeFlags.Enum) ? numberType : - propNameType; + const indexKeyType = propNameType.flags & (TypeFlags.Any | TypeFlags.String) ? stringType + : propNameType.flags & (TypeFlags.Number | TypeFlags.Enum) ? numberType + : propNameType; const propType = instantiateType(templateType, appendTypeMapping(type.mapper, typeParameter, keyType)); - const indexInfo = createIndexInfo(indexKeyType, propType, !!(templateModifiers & MappedTypeModifiers.IncludeReadonly)); + const indexInfo = createIndexInfo( + indexKeyType, + propType, + !!(templateModifiers & MappedTypeModifiers.IncludeReadonly), + ); indexInfos = appendIndexInfo(indexInfos, indexInfo, /*union*/ true); } } @@ -13347,16 +17261,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return errorType; } const templateType = getTemplateTypeFromMappedType(mappedType.target as MappedType || mappedType); - const mapper = appendTypeMapping(mappedType.mapper, getTypeParameterFromMappedType(mappedType), symbol.links.keyType); + const mapper = appendTypeMapping( + mappedType.mapper, + getTypeParameterFromMappedType(mappedType), + symbol.links.keyType, + ); const propType = instantiateType(templateType, mapper); // When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the // type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks // mode, if the underlying property is optional we remove 'undefined' from the type. - let type = strictNullChecks && symbol.flags & SymbolFlags.Optional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType, /*isProperty*/ true) : - symbol.links.checkFlags & CheckFlags.StripOptional ? removeMissingOrUndefinedType(propType) : - propType; + let type = strictNullChecks && symbol.flags & SymbolFlags.Optional + && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) + ? getOptionalType(propType, /*isProperty*/ true) + : symbol.links.checkFlags & CheckFlags.StripOptional ? removeMissingOrUndefinedType(propType) + : propType; if (!popTypeResolution()) { - error(currentNode, Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, symbolToString(symbol), typeToString(mappedType)); + error( + currentNode, + Diagnostics.Type_of_property_0_circularly_references_itself_in_mapped_type_1, + symbolToString(symbol), + typeToString(mappedType), + ); type = errorType; } symbol.links.type = type; @@ -13365,26 +17290,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeParameterFromMappedType(type: MappedType) { - return type.typeParameter || - (type.typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(type.declaration.typeParameter))); + return type.typeParameter + || (type.typeParameter = getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration(type.declaration.typeParameter), + )); } function getConstraintTypeFromMappedType(type: MappedType) { - return type.constraintType || - (type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) || errorType); + return type.constraintType + || (type.constraintType = getConstraintOfTypeParameter(getTypeParameterFromMappedType(type)) || errorType); } function getNameTypeFromMappedType(type: MappedType) { - return type.declaration.nameType ? - type.nameType || (type.nameType = instantiateType(getTypeFromTypeNode(type.declaration.nameType), type.mapper)) : - undefined; + return type.declaration.nameType + ? type.nameType + || (type.nameType = instantiateType(getTypeFromTypeNode(type.declaration.nameType), type.mapper)) + : undefined; } function getTemplateTypeFromMappedType(type: MappedType) { - return type.templateType || - (type.templateType = type.declaration.type ? - instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), /*isProperty*/ true, !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), type.mapper) : - errorType); + return type.templateType + || (type.templateType = type.declaration.type + ? instantiateType( + addOptionality( + getTypeFromTypeNode(type.declaration.type), + /*isProperty*/ true, + !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional), + ), + type.mapper, + ) + : errorType); } function getConstraintDeclarationForMappedType(type: MappedType) { @@ -13393,8 +17328,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isMappedTypeWithKeyofConstraintDeclaration(type: MappedType) { const constraintDeclaration = getConstraintDeclarationForMappedType(type)!; // TODO: GH#18217 - return constraintDeclaration.kind === SyntaxKind.TypeOperator && - (constraintDeclaration as TypeOperatorNode).operator === SyntaxKind.KeyOfKeyword; + return constraintDeclaration.kind === SyntaxKind.TypeOperator + && (constraintDeclaration as TypeOperatorNode).operator === SyntaxKind.KeyOfKeyword; } function getModifiersTypeFromMappedType(type: MappedType) { @@ -13403,7 +17338,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the constraint declaration is a 'keyof T' node, the modifiers type is T. We check // AST nodes here because, when T is a non-generic type, the logic below eagerly resolves // 'keyof T' to a literal union type and we can't recover T from that type. - type.modifiersType = instantiateType(getTypeFromTypeNode((getConstraintDeclarationForMappedType(type) as TypeOperatorNode).type), type.mapper); + type.modifiersType = instantiateType( + getTypeFromTypeNode((getConstraintDeclarationForMappedType(type) as TypeOperatorNode).type), + type.mapper, + ); } else { // Otherwise, get the declared constraint type, and if the constraint type is a type parameter, @@ -13411,8 +17349,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the modifiers type is T. Otherwise, the modifiers type is unknown. const declaredType = getTypeFromMappedTypeNode(type.declaration) as MappedType; const constraint = getConstraintTypeFromMappedType(declaredType); - const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint as TypeParameter) : constraint; - type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint as IndexType).type, type.mapper) : unknownType; + const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter + ? getConstraintOfTypeParameter(constraint as TypeParameter) : constraint; + type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index + ? instantiateType((extendedConstraint as IndexType).type, type.mapper) : unknownType; } } return type.modifiersType; @@ -13420,13 +17360,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers { const declaration = type.declaration; - return (declaration.readonlyToken ? declaration.readonlyToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeReadonly : MappedTypeModifiers.IncludeReadonly : 0) | - (declaration.questionToken ? declaration.questionToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeOptional : MappedTypeModifiers.IncludeOptional : 0); + return (declaration.readonlyToken + ? declaration.readonlyToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeReadonly + : MappedTypeModifiers.IncludeReadonly : 0) + | (declaration.questionToken + ? declaration.questionToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeOptional + : MappedTypeModifiers.IncludeOptional : 0); } function getMappedTypeOptionality(type: MappedType): number { const modifiers = getMappedTypeModifiers(type); - return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0; + return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 + : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0; } function getCombinedMappedTypeOptionality(type: MappedType): number { @@ -13436,7 +17381,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isPartialMappedType(type: Type) { - return !!(getObjectFlags(type) & ObjectFlags.Mapped && getMappedTypeModifiers(type as MappedType) & MappedTypeModifiers.IncludeOptional); + return !!(getObjectFlags(type) & ObjectFlags.Mapped + && getMappedTypeModifiers(type as MappedType) & MappedTypeModifiers.IncludeOptional); } function isGenericMappedType(type: Type): type is MappedType { @@ -13449,7 +17395,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // To determine this, we substitute the constraint type (that we now know isn't generic) for the iteration // type and check whether the resulting type is generic. const nameType = getNameTypeFromMappedType(type as MappedType); - if (nameType && isGenericIndexType(instantiateType(nameType, makeUnaryTypeMapper(getTypeParameterFromMappedType(type as MappedType), constraint)))) { + if ( + nameType + && isGenericIndexType( + instantiateType( + nameType, + makeUnaryTypeMapper(getTypeParameterFromMappedType(type as MappedType), constraint), + ), + ) + ) { return true; } } @@ -13542,9 +17496,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getPropertiesOfType(type: Type): Symbol[] { type = getReducedApparentType(type); - return type.flags & TypeFlags.UnionOrIntersection ? - getPropertiesOfUnionOrIntersectionType(type as UnionType) : - getPropertiesOfObjectType(type); + return type.flags & TypeFlags.UnionOrIntersection + ? getPropertiesOfUnionOrIntersectionType(type as UnionType) + : getPropertiesOfObjectType(type); } function forEachPropertyOfType(type: Type, action: (symbol: Symbol, escapedName: __String) => void): void { @@ -13558,11 +17512,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes): boolean { + function isTypeInvalidDueToUnionDiscriminant( + contextualType: Type, + obj: ObjectLiteralExpression | JsxAttributes, + ): boolean { const list = obj.properties as NodeArray; return list.some(property => { - const nameType = property.name && (isJsxNamespacedName(property.name) ? getStringLiteralType(getTextOfJsxAttributeName(property.name)) : getLiteralTypeFromPropertyName(property.name)); - const name = nameType && isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) : undefined; + const nameType = property.name + && (isJsxNamespacedName(property.name) ? getStringLiteralType(getTextOfJsxAttributeName(property.name)) + : getLiteralTypeFromPropertyName(property.name)); + const name = nameType && isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) + : undefined; const expected = name === undefined ? undefined : getTypeOfPropertyOfType(contextualType, name); return !!expected && isLiteralType(expected) && !isTypeAssignableTo(getTypeOfNode(property), expected); }); @@ -13588,10 +17548,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getConstraintOfType(type: InstantiableType | UnionOrIntersectionType): Type | undefined { - return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type as TypeParameter) : - type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type as IndexedAccessType) : - type.flags & TypeFlags.Conditional ? getConstraintOfConditionalType(type as ConditionalType) : - getBaseConstraintOfType(type); + return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(type as TypeParameter) + : type.flags & TypeFlags.IndexedAccess ? getConstraintOfIndexedAccess(type as IndexedAccessType) + : type.flags & TypeFlags.Conditional ? getConstraintOfConditionalType(type as ConditionalType) + : getBaseConstraintOfType(type); } function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type | undefined { @@ -13600,12 +17560,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isConstTypeVariable(type: Type | undefined, depth = 0): boolean { return depth < 5 && !!(type && ( - type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) || - type.flags & TypeFlags.Union && some((type as UnionType).types, t => isConstTypeVariable(t, depth)) || - type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType, depth + 1) || - type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType), depth + 1) || - type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType, depth) || - isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t, depth)) >= 0)); + type.flags & TypeFlags.TypeParameter + && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) + || type.flags & TypeFlags.Union && some((type as UnionType).types, t => isConstTypeVariable(t, depth)) + || type.flags & TypeFlags.IndexedAccess + && isConstTypeVariable((type as IndexedAccessType).objectType, depth + 1) + || type.flags & TypeFlags.Conditional + && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType), depth + 1) + || type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType, depth) + || isGenericTupleType(type) + && findIndex( + getElementTypes(type), + (t, i) => + !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t, depth), + ) >= 0 + )); } function getConstraintOfIndexedAccess(type: IndexedAccessType) { @@ -13645,7 +17614,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // in effect treating `any` like `never` rather than `unknown` in this location. const trueConstraint = getInferredTrueTypeFromConditionalType(type); const falseConstraint = getFalseTypeFromConditionalType(type); - type.resolvedDefaultConstraint = isTypeAny(trueConstraint) ? falseConstraint : isTypeAny(falseConstraint) ? trueConstraint : getUnionType([trueConstraint, falseConstraint]); + type.resolvedDefaultConstraint = isTypeAny(trueConstraint) ? falseConstraint + : isTypeAny(falseConstraint) ? trueConstraint : getUnionType([trueConstraint, falseConstraint]); } return type.resolvedDefaultConstraint; } @@ -13670,7 +17640,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const simplified = getSimplifiedType(type.checkType, /*writing*/ false); const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified; if (constraint && constraint !== type.checkType) { - const instantiated = getConditionalTypeInstantiation(type, prependTypeMapping(type.root.checkType, constraint, type.mapper)); + const instantiated = getConditionalTypeInstantiation( + type, + prependTypeMapping(type.root.checkType, constraint, type.mapper), + ); if (!(instantiated.flags & TypeFlags.Never)) { type.resolvedConstraintOfDistributive = instantiated; return instantiated; @@ -13697,7 +17670,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We keep following constraints as long as we have an instantiable type that is known // not to be circular or infinite (hence we stop on index access types). let constraint = getConstraintOfType(t); - while (constraint && constraint.flags & (TypeFlags.TypeParameter | TypeFlags.Index | TypeFlags.Conditional)) { + while ( + constraint && constraint.flags & (TypeFlags.TypeParameter | TypeFlags.Index | TypeFlags.Conditional) + ) { constraint = getConstraintOfType(constraint); } if (constraint) { @@ -13730,7 +17705,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getBaseConstraintOfType(type: Type): Type | undefined { - if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || isGenericTupleType(type)) { + if ( + type.flags + & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping) || isGenericTupleType(type) + ) { const constraint = getResolvedBaseConstraint(type as InstantiableType | UnionOrIntersectionType); return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined; } @@ -13783,9 +17762,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (t.flags & TypeFlags.TypeParameter) { const errorNode = getConstraintDeclaration(t as TypeParameter); if (errorNode) { - const diagnostic = error(errorNode, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(t)); - if (currentNode && !isNodeDescendantOf(errorNode, currentNode) && !isNodeDescendantOf(currentNode, errorNode)) { - addRelatedInfo(diagnostic, createDiagnosticForNode(currentNode, Diagnostics.Circularity_originates_in_type_at_this_location)); + const diagnostic = error( + errorNode, + Diagnostics.Type_parameter_0_has_a_circular_constraint, + typeToString(t), + ); + if ( + currentNode && !isNodeDescendantOf(errorNode, currentNode) + && !isNodeDescendantOf(currentNode, errorNode) + ) { + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + currentNode, + Diagnostics.Circularity_originates_in_type_at_this_location, + ), + ); } } } @@ -13804,9 +17796,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function computeBaseConstraint(t: Type): Type | undefined { if (t.flags & TypeFlags.TypeParameter) { const constraint = getConstraintFromTypeParameter(t as TypeParameter); - return (t as TypeParameter).isThisType || !constraint ? - constraint : - getBaseConstraint(constraint); + return (t as TypeParameter).isThisType || !constraint + ? constraint + : getBaseConstraint(constraint); } if (t.flags & TypeFlags.UnionOrIntersection) { const types = (t as UnionOrIntersectionType).types; @@ -13827,9 +17819,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!different) { return t; } - return t.flags & TypeFlags.Union && baseTypes.length === types.length ? getUnionType(baseTypes) : - t.flags & TypeFlags.Intersection && baseTypes.length ? getIntersectionType(baseTypes) : - undefined; + return t.flags & TypeFlags.Union && baseTypes.length === types.length ? getUnionType(baseTypes) + : t.flags & TypeFlags.Intersection && baseTypes.length ? getIntersectionType(baseTypes) + : undefined; } if (t.flags & TypeFlags.Index) { return keyofConstraintType; @@ -13837,21 +17829,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (t.flags & TypeFlags.TemplateLiteral) { const types = (t as TemplateLiteralType).types; const constraints = mapDefined(types, getBaseConstraint); - return constraints.length === types.length ? getTemplateLiteralType((t as TemplateLiteralType).texts, constraints) : stringType; + return constraints.length === types.length + ? getTemplateLiteralType((t as TemplateLiteralType).texts, constraints) : stringType; } if (t.flags & TypeFlags.StringMapping) { const constraint = getBaseConstraint((t as StringMappingType).type); - return constraint && constraint !== (t as StringMappingType).type ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType; + return constraint && constraint !== (t as StringMappingType).type + ? getStringMappingType((t as StringMappingType).symbol, constraint) : stringType; } if (t.flags & TypeFlags.IndexedAccess) { if (isMappedTypeGenericIndexedAccess(t)) { // For indexed access types of the form { [P in K]: E }[X], where K is non-generic and X is generic, // we substitute an instantiation of E where P is replaced with X. - return getBaseConstraint(substituteIndexedMappedType((t as IndexedAccessType).objectType as MappedType, (t as IndexedAccessType).indexType)); + return getBaseConstraint( + substituteIndexedMappedType( + (t as IndexedAccessType).objectType as MappedType, + (t as IndexedAccessType).indexType, + ), + ); } const baseObjectType = getBaseConstraint((t as IndexedAccessType).objectType); const baseIndexType = getBaseConstraint((t as IndexedAccessType).indexType); - const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (t as IndexedAccessType).accessFlags); + const baseIndexedAccess = baseObjectType && baseIndexType + && getIndexedAccessTypeOrUndefined( + baseObjectType, + baseIndexType, + (t as IndexedAccessType).accessFlags, + ); return baseIndexedAccess && getBaseConstraint(baseIndexedAccess); } if (t.flags & TypeFlags.Conditional) { @@ -13865,29 +17869,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We substitute constraints for variadic elements only when the constraints are array types or // non-variadic tuple types as we want to avoid further (possibly unbounded) recursion. const newElements = map(getElementTypes(t), (v, i) => { - const constraint = v.flags & TypeFlags.TypeParameter && t.target.elementFlags[i] & ElementFlags.Variadic && getBaseConstraint(v) || v; - return constraint !== v && everyType(constraint, c => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint : v; + const constraint = + v.flags & TypeFlags.TypeParameter && t.target.elementFlags[i] & ElementFlags.Variadic + && getBaseConstraint(v) || v; + return constraint !== v + && everyType(constraint, c => isArrayOrTupleType(c) && !isGenericTupleType(c)) ? constraint + : v; }); - return createTupleType(newElements, t.target.elementFlags, t.target.readonly, t.target.labeledElementDeclarations); + return createTupleType( + newElements, + t.target.elementFlags, + t.target.readonly, + t.target.labeledElementDeclarations, + ); } return t; } } function getApparentTypeOfIntersectionType(type: IntersectionType, thisArgument: Type) { - return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, thisArgument, /*needApparentType*/ true)); + return type.resolvedApparentType + || (type.resolvedApparentType = getTypeWithThisArgument(type, thisArgument, /*needApparentType*/ true)); } function getResolvedTypeParameterDefault(typeParameter: TypeParameter): Type | undefined { if (!typeParameter.default) { if (typeParameter.target) { const targetDefault = getResolvedTypeParameterDefault(typeParameter.target); - typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) : noConstraintType; + typeParameter.default = targetDefault ? instantiateType(targetDefault, typeParameter.mapper) + : noConstraintType; } else { // To block recursion, set the initial value to the resolvingDefaultType. typeParameter.default = resolvingDefaultType; - const defaultDeclaration = typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default); + const defaultDeclaration = typeParameter.symbol + && forEach( + typeParameter.symbol.declarations, + decl => isTypeParameterDeclaration(decl) && decl.default, + ); const defaultType = defaultDeclaration ? getTypeFromTypeNode(defaultDeclaration) : noConstraintType; if (typeParameter.default === resolvingDefaultType) { // If we have not been called recursively, set the correct default type. @@ -13922,7 +17941,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Indicates whether the declaration of a typeParameter has a default type. */ function hasTypeParameterDefault(typeParameter: TypeParameter): boolean { - return !!(typeParameter.symbol && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default)); + return !!(typeParameter.symbol + && forEach(typeParameter.symbol.declarations, decl => isTypeParameterDeclaration(decl) && decl.default)); } function getApparentTypeOfMappedType(type: MappedType) { @@ -13942,9 +17962,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isMappedTypeGenericIndexedAccess(type: Type) { let objectType; - return !!(type.flags & TypeFlags.IndexedAccess && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped && - !isGenericMappedType(objectType) && isGenericIndexType((type as IndexedAccessType).indexType) && - !(getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.ExcludeOptional) && !(objectType as MappedType).declaration.nameType); + return !!(type.flags & TypeFlags.IndexedAccess + && getObjectFlags(objectType = (type as IndexedAccessType).objectType) & ObjectFlags.Mapped + && !isGenericMappedType(objectType) && isGenericIndexType((type as IndexedAccessType).indexType) + && !(getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.ExcludeOptional) + && !(objectType as MappedType).declaration.nameType); } /** @@ -13955,18 +17977,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getApparentType(type: Type): Type { const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || unknownType : type; const objectFlags = getObjectFlags(t); - return objectFlags & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) : - objectFlags & ObjectFlags.Reference && t !== type ? getTypeWithThisArgument(t, type) : - t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType, type) : - t.flags & TypeFlags.StringLike ? globalStringType : - t.flags & TypeFlags.NumberLike ? globalNumberType : - t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() : - t.flags & TypeFlags.BooleanLike ? globalBooleanType : - t.flags & TypeFlags.ESSymbolLike ? getGlobalESSymbolType() : - t.flags & TypeFlags.NonPrimitive ? emptyObjectType : - t.flags & TypeFlags.Index ? keyofConstraintType : - t.flags & TypeFlags.Unknown && !strictNullChecks ? emptyObjectType : - t; + return objectFlags & ObjectFlags.Mapped ? getApparentTypeOfMappedType(t as MappedType) + : objectFlags & ObjectFlags.Reference && t !== type ? getTypeWithThisArgument(t, type) + : t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(t as IntersectionType, type) + : t.flags & TypeFlags.StringLike ? globalStringType + : t.flags & TypeFlags.NumberLike ? globalNumberType + : t.flags & TypeFlags.BigIntLike ? getGlobalBigIntType() + : t.flags & TypeFlags.BooleanLike ? globalBooleanType + : t.flags & TypeFlags.ESSymbolLike ? getGlobalESSymbolType() + : t.flags & TypeFlags.NonPrimitive ? emptyObjectType + : t.flags & TypeFlags.Index ? keyofConstraintType + : t.flags & TypeFlags.Unknown && !strictNullChecks ? emptyObjectType + : t; } function getReducedApparentType(type: Type): Type { @@ -13977,7 +17999,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getReducedType(getApparentType(getReducedType(type))); } - function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { + function createUnionOrIntersectionProperty( + containingType: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + ): Symbol | undefined { let singleProp: Symbol | undefined; let propSet: Map | undefined; let indexTypes: Type[] | undefined; @@ -13996,7 +18022,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (prop.flags & SymbolFlags.ClassMember) { optionalFlag ??= isUnion ? SymbolFlags.None : SymbolFlags.Optional; if (isUnion) { - optionalFlag |= (prop.flags & SymbolFlags.Optional); + optionalFlag |= prop.flags & SymbolFlags.Optional; } else { optionalFlag &= prop.flags; @@ -14006,15 +18032,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { singleProp = prop; } else if (prop !== singleProp) { - const isInstantiation = (getTargetSymbol(prop) || prop) === (getTargetSymbol(singleProp) || singleProp); + const isInstantiation = + (getTargetSymbol(prop) || prop) === (getTargetSymbol(singleProp) || singleProp); // If the symbols are instances of one another with identical types - consider the symbols // equivalent and just use the first one, which thus allows us to avoid eliding private // members when intersecting a (this-)instantiations of a class with its raw base or another instance - if (isInstantiation && compareProperties(singleProp, prop, (a, b) => a === b ? Ternary.True : Ternary.False) === Ternary.True) { + if ( + isInstantiation + && compareProperties(singleProp, prop, (a, b) => a === b ? Ternary.True : Ternary.False) + === Ternary.True + ) { // If we merged instantiations of a generic type, we replicate the symbol parent resetting behavior we used // to do when we recorded multiple distinct symbols so that we still get, eg, `Array.length` printed // back and not `Array.length` when we're looking at a `.length` access on a `string[] | number[]` - mergedInstantiations = !!singleProp.parent && !!length(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(singleProp.parent)); + mergedInstantiations = !!singleProp.parent + && !!length(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(singleProp.parent)); } else { if (!propSet) { @@ -14033,10 +18065,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (!isUnion && !isReadonlySymbol(prop)) { checkFlags &= ~CheckFlags.Readonly; } - checkFlags |= (!(modifiers & ModifierFlags.NonPublicAccessibilityModifier) ? CheckFlags.ContainsPublic : 0) | - (modifiers & ModifierFlags.Protected ? CheckFlags.ContainsProtected : 0) | - (modifiers & ModifierFlags.Private ? CheckFlags.ContainsPrivate : 0) | - (modifiers & ModifierFlags.Static ? CheckFlags.ContainsStatic : 0); + checkFlags |= + (!(modifiers & ModifierFlags.NonPublicAccessibilityModifier) ? CheckFlags.ContainsPublic : 0) + | (modifiers & ModifierFlags.Protected ? CheckFlags.ContainsProtected : 0) + | (modifiers & ModifierFlags.Private ? CheckFlags.ContainsPrivate : 0) + | (modifiers & ModifierFlags.Static ? CheckFlags.ContainsStatic : 0); if (!isPrototypeProperty(prop)) { syntheticFlag = CheckFlags.SyntheticProperty; } @@ -14045,7 +18078,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const indexInfo = !isLateBoundName(name) && getApplicableIndexInfoForName(type, name); if (indexInfo) { checkFlags |= CheckFlags.WritePartial | (indexInfo.isReadonly ? CheckFlags.Readonly : 0); - indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type); + indexTypes = append( + indexTypes, + isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type, + ); } else if (isObjectLiteralType(type) && !(getObjectFlags(type) & ObjectFlags.ContainsSpread)) { checkFlags |= CheckFlags.WritePartial; @@ -14057,11 +18093,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - if (!singleProp || - isUnion && - (propSet || checkFlags & CheckFlags.Partial) && - checkFlags & (CheckFlags.ContainsPrivate | CheckFlags.ContainsProtected) && - !(propSet && getCommonDeclarationsOfSymbols(propSet.values())) + if ( + !singleProp + || isUnion + && (propSet || checkFlags & CheckFlags.Partial) + && checkFlags & (CheckFlags.ContainsPrivate | CheckFlags.ContainsProtected) + && !(propSet && getCommonDeclarationsOfSymbols(propSet.values())) ) { // No property was found, or, in a union, a property has a private or protected declaration in one // constituent, but is missing or has a different declaration in another constituent. @@ -14154,15 +18191,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // constituents, in which case the isPartial flag is set when the containing type is union type. We need // these partial properties when identifying discriminant properties, but otherwise they are filtered out // and do not appear to be present in the union type. - function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { - let property = type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) || - !skipObjectFunctionPropertyAugment ? type.propertyCache?.get(name) : undefined; + function getUnionOrIntersectionProperty( + type: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + ): Symbol | undefined { + let property = type.propertyCacheWithoutObjectFunctionPropertyAugment?.get(name) + || !skipObjectFunctionPropertyAugment ? type.propertyCache?.get(name) : undefined; if (!property) { property = createUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment); if (property) { - const properties = skipObjectFunctionPropertyAugment ? - type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() : - type.propertyCache ||= createSymbolTable(); + const properties = skipObjectFunctionPropertyAugment + ? type.propertyCacheWithoutObjectFunctionPropertyAugment ||= createSymbolTable() + : type.propertyCache ||= createSymbolTable(); properties.set(name, property); } } @@ -14191,7 +18232,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return commonDeclarations; } - function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { + function getPropertyOfUnionOrIntersectionType( + type: UnionOrIntersectionType, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + ): Symbol | undefined { const property = getUnionOrIntersectionProperty(type, name, skipObjectFunctionPropertyAugment); // We need to filter out partial properties in union types return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined; @@ -14205,12 +18250,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function getReducedType(type: Type): Type { if (type.flags & TypeFlags.Union && (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections) { - return (type as UnionType).resolvedReducedType || ((type as UnionType).resolvedReducedType = getReducedUnionType(type as UnionType)); + return (type as UnionType).resolvedReducedType + || ((type as UnionType).resolvedReducedType = getReducedUnionType(type as UnionType)); } else if (type.flags & TypeFlags.Intersection) { if (!((type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { - (type as IntersectionType).objectFlags |= ObjectFlags.IsNeverIntersectionComputed | - (some(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isNeverReducedProperty) ? ObjectFlags.IsNeverIntersection : 0); + (type as IntersectionType).objectFlags |= ObjectFlags.IsNeverIntersectionComputed + | (some(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isNeverReducedProperty) + ? ObjectFlags.IsNeverIntersection : 0); } return (type as IntersectionType).objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; } @@ -14236,9 +18283,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isDiscriminantWithNeverType(prop: Symbol) { // Return true for a synthetic non-optional property with non-uniform types, where at least one is // a literal type and none is never, that reduces to never. - return !(prop.flags & SymbolFlags.Optional) && - (getCheckFlags(prop) & (CheckFlags.Discriminant | CheckFlags.HasNeverType)) === CheckFlags.Discriminant && - !!(getTypeOfSymbol(prop).flags & TypeFlags.Never); + return !(prop.flags & SymbolFlags.Optional) + && (getCheckFlags(prop) & (CheckFlags.Discriminant | CheckFlags.HasNeverType)) === CheckFlags.Discriminant + && !!(getTypeOfSymbol(prop).flags & TypeFlags.Never); } function isConflictingPrivateProperty(prop: Symbol) { @@ -14254,26 +18301,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * literal-typed properties are reducible). */ function isGenericReducibleType(type: Type): boolean { - return !!(type.flags & TypeFlags.Union && (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections && some((type as UnionType).types, isGenericReducibleType) || - type.flags & TypeFlags.Intersection && isReducibleIntersection(type as IntersectionType)); + return !!(type.flags & TypeFlags.Union && (type as UnionType).objectFlags & ObjectFlags.ContainsIntersections + && some((type as UnionType).types, isGenericReducibleType) + || type.flags & TypeFlags.Intersection && isReducibleIntersection(type as IntersectionType)); } function isReducibleIntersection(type: IntersectionType) { - const uniqueFilled = type.uniqueLiteralFilledInstantiation || (type.uniqueLiteralFilledInstantiation = instantiateType(type, uniqueLiteralMapper)); + const uniqueFilled = type.uniqueLiteralFilledInstantiation + || (type.uniqueLiteralFilledInstantiation = instantiateType(type, uniqueLiteralMapper)); return getReducedType(uniqueFilled) !== uniqueFilled; } function elaborateNeverIntersection(errorInfo: DiagnosticMessageChain | undefined, type: Type) { if (type.flags & TypeFlags.Intersection && getObjectFlags(type) & ObjectFlags.IsNeverIntersection) { - const neverProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isDiscriminantWithNeverType); + const neverProp = find( + getPropertiesOfUnionOrIntersectionType(type as IntersectionType), + isDiscriminantWithNeverType, + ); if (neverProp) { - return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents, - typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(neverProp)); + return chainDiagnosticMessages( + errorInfo, + Diagnostics + .The_intersection_0_was_reduced_to_never_because_property_1_has_conflicting_types_in_some_constituents, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), + symbolToString(neverProp), + ); } - const privateProp = find(getPropertiesOfUnionOrIntersectionType(type as IntersectionType), isConflictingPrivateProperty); + const privateProp = find( + getPropertiesOfUnionOrIntersectionType(type as IntersectionType), + isConflictingPrivateProperty, + ); if (privateProp) { - return chainDiagnosticMessages(errorInfo, Diagnostics.The_intersection_0_was_reduced_to_never_because_property_1_exists_in_multiple_constituents_and_is_private_in_some, - typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), symbolToString(privateProp)); + return chainDiagnosticMessages( + errorInfo, + Diagnostics + .The_intersection_0_was_reduced_to_never_because_property_1_exists_in_multiple_constituents_and_is_private_in_some, + typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTypeReduction), + symbolToString(privateProp), + ); } } return errorInfo; @@ -14287,7 +18352,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param type a type to look up property from * @param name a name of property to look up in a given type */ - function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean, includeTypeOnlyMembers?: boolean): Symbol | undefined { + function getPropertyOfType( + type: Type, + name: __String, + skipObjectFunctionPropertyAugment?: boolean, + includeTypeOnlyMembers?: boolean, + ): Symbol | undefined { type = getReducedApparentType(type); if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); @@ -14296,10 +18366,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbol; } if (skipObjectFunctionPropertyAugment) return undefined; - const functionType = resolved === anyFunctionType ? globalFunctionType : - resolved.callSignatures.length ? globalCallableFunctionType : - resolved.constructSignatures.length ? globalNewableFunctionType : - undefined; + const functionType = resolved === anyFunctionType ? globalFunctionType + : resolved.callSignatures.length ? globalCallableFunctionType + : resolved.constructSignatures.length ? globalNewableFunctionType + : undefined; if (functionType) { const symbol = getPropertyOfObjectType(functionType, name); if (symbol) { @@ -14309,7 +18379,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getPropertyOfObjectType(globalObjectType, name); } if (type.flags & TypeFlags.UnionOrIntersection) { - return getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name, skipObjectFunctionPropertyAugment); + return getPropertyOfUnionOrIntersectionType( + type as UnionOrIntersectionType, + name, + skipObjectFunctionPropertyAugment, + ); } return undefined; } @@ -14334,11 +18408,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // If the union is all different instantiations of a member of the global array type... let memberName: __String; - if (everyType(type, t => !!t.symbol?.parent && isArrayOrTupleSymbol(t.symbol.parent) && (!memberName ? (memberName = t.symbol.escapedName, true) : memberName === t.symbol.escapedName))) { + if ( + everyType(type, t => + !!t.symbol?.parent && isArrayOrTupleSymbol(t.symbol.parent) + && (!memberName ? (memberName = t.symbol.escapedName, true) : memberName === t.symbol.escapedName)) + ) { // Transform the type from `(A[] | B[])["member"]` to `(A | B)[]["member"]` (since we pretend array is covariant anyway) - const arrayArg = mapType(type, t => getMappedType((isReadonlyArraySymbol(t.symbol.parent) ? globalReadonlyArrayType : globalArrayType).typeParameters![0], (t as AnonymousType).mapper!)); - const arrayType = createArrayType(arrayArg, someType(type, t => isReadonlyArraySymbol(t.symbol.parent))); - return (type as UnionType).arrayFallbackSignatures = getSignaturesOfType(getTypeOfPropertyOfType(arrayType, memberName!)!, kind); + const arrayArg = mapType( + type, + t => getMappedType( + (isReadonlyArraySymbol(t.symbol.parent) ? globalReadonlyArrayType : globalArrayType) + .typeParameters![0], + (t as AnonymousType).mapper!, + ), + ); + const arrayType = createArrayType( + arrayArg, + someType(type, t => isReadonlyArraySymbol(t.symbol.parent)), + ); + return (type as UnionType).arrayFallbackSignatures = getSignaturesOfType( + getTypeOfPropertyOfType(arrayType, memberName!)!, + kind, + ); } (type as UnionType).arrayFallbackSignatures = result; } @@ -14349,7 +18440,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!symbol || !globalArrayType.symbol || !globalReadonlyArrayType.symbol) { return false; } - return !!getSymbolIfSameReference(symbol, globalArrayType.symbol) || !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol); + return !!getSymbolIfSameReference(symbol, globalArrayType.symbol) + || !!getSymbolIfSameReference(symbol, globalReadonlyArrayType.symbol); } function isReadonlyArraySymbol(symbol: Symbol | undefined) { @@ -14384,19 +18476,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When more than one index signature is applicable we create a synthetic IndexInfo. Instead of computing // the intersected key type, we just use unknownType for the key type as nothing actually depends on the // keyType property of the returned IndexInfo. - return applicableInfos ? createIndexInfo(unknownType, getIntersectionType(map(applicableInfos, info => info.type)), - reduceLeft(applicableInfos, (isReadonly, info) => isReadonly && info.isReadonly, /*initial*/ true)) : - applicableInfo ? applicableInfo : - stringIndexInfo && isApplicableIndexType(keyType, stringType) ? stringIndexInfo : - undefined; + return applicableInfos + ? createIndexInfo( + unknownType, + getIntersectionType(map(applicableInfos, info => info.type)), + reduceLeft(applicableInfos, (isReadonly, info) => isReadonly && info.isReadonly, /*initial*/ true), + ) + : applicableInfo ? applicableInfo + : stringIndexInfo && isApplicableIndexType(keyType, stringType) ? stringIndexInfo + : undefined; } function isApplicableIndexType(source: Type, target: Type): boolean { // A 'string' index signature applies to types assignable to 'string' or 'number', and a 'number' index // signature applies to types assignable to 'number', `${number}` and numeric string literal types. - return isTypeAssignableTo(source, target) || - target === stringType && isTypeAssignableTo(source, numberType) || - target === numberType && (source === numericStringType || !!(source.flags & TypeFlags.StringLiteral) && isNumericLiteralName((source as StringLiteralType).value)); + return isTypeAssignableTo(source, target) + || target === stringType && isTypeAssignableTo(source, numberType) + || target === numberType + && (source === numericStringType + || !!(source.flags & TypeFlags.StringLiteral) + && isNumericLiteralName((source as StringLiteralType).value)); } function getIndexInfosOfStructuredType(type: Type): readonly IndexInfo[] { @@ -14432,12 +18531,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getApplicableIndexInfoForName(type: Type, name: __String): IndexInfo | undefined { - return getApplicableIndexInfo(type, isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name))); + return getApplicableIndexInfo( + type, + isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name)), + ); } // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual // type checking functions). - function getTypeParametersFromDeclaration(declaration: DeclarationWithTypeParameters): readonly TypeParameter[] | undefined { + function getTypeParametersFromDeclaration( + declaration: DeclarationWithTypeParameters, + ): readonly TypeParameter[] | undefined { let result: TypeParameter[] | undefined; for (const node of getEffectiveTypeParameterDeclarations(declaration)) { result = appendIfUnique(result, getDeclaredTypeOfTypeParameter(node.symbol)); @@ -14478,13 +18582,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Only consider syntactic or instantiated parameters as optional, not `void` parameters as this function is used // in grammar checks and checking for `void` too early results in parameter types widening too early // and causes some noImplicitAny errors to be lost. - return parameterIndex >= getMinArgumentCount(signature, MinArgumentCountFlags.StrongArityForUntypedJS | MinArgumentCountFlags.VoidIsNonOptional); + return parameterIndex + >= getMinArgumentCount( + signature, + MinArgumentCountFlags.StrongArityForUntypedJS | MinArgumentCountFlags.VoidIsNonOptional, + ); } const iife = getImmediatelyInvokedFunctionExpression(node.parent); if (iife) { - return !node.type && - !node.dotDotDotToken && - node.parent.parameters.indexOf(node) >= iife.arguments.length; + return !node.type + && !node.dotDotDotToken + && node.parent.parameters.indexOf(node) >= iife.arguments.length; } return false; @@ -14494,7 +18602,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isPropertyDeclaration(node) && !hasAccessorModifier(node) && node.questionToken; } - function createTypePredicate(kind: TypePredicateKind, parameterName: string | undefined, parameterIndex: number | undefined, type: Type | undefined): TypePredicate { + function createTypePredicate( + kind: TypePredicateKind, + parameterName: string | undefined, + parameterIndex: number | undefined, + type: Type | undefined, + ): TypePredicate { return { kind, parameterName, parameterIndex, type } as TypePredicate; } @@ -14522,15 +18635,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param typeParameters The requested type parameters. * @param minTypeArgumentCount The minimum number of required type arguments. */ - function fillMissingTypeArguments(typeArguments: readonly Type[], typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[]; - function fillMissingTypeArguments(typeArguments: readonly Type[] | undefined, typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean): Type[] | undefined; - function fillMissingTypeArguments(typeArguments: readonly Type[] | undefined, typeParameters: readonly TypeParameter[] | undefined, minTypeArgumentCount: number, isJavaScriptImplicitAny: boolean) { + function fillMissingTypeArguments( + typeArguments: readonly Type[], + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean, + ): Type[]; + function fillMissingTypeArguments( + typeArguments: readonly Type[] | undefined, + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean, + ): Type[] | undefined; + function fillMissingTypeArguments( + typeArguments: readonly Type[] | undefined, + typeParameters: readonly TypeParameter[] | undefined, + minTypeArgumentCount: number, + isJavaScriptImplicitAny: boolean, + ) { const numTypeParameters = length(typeParameters); if (!numTypeParameters) { return []; } const numTypeArguments = length(typeArguments); - if (isJavaScriptImplicitAny || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters)) { + if ( + isJavaScriptImplicitAny + || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters) + ) { const result = typeArguments ? typeArguments.slice() : []; // Map invalid forward references in default types to the error type for (let i = numTypeArguments; i < numTypeParameters; i++) { @@ -14539,10 +18670,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny); for (let i = numTypeArguments; i < numTypeParameters; i++) { let defaultType = getDefaultFromTypeParameter(typeParameters![i]); - if (isJavaScriptImplicitAny && defaultType && (isTypeIdenticalTo(defaultType, unknownType) || isTypeIdenticalTo(defaultType, emptyObjectType))) { + if ( + isJavaScriptImplicitAny && defaultType + && (isTypeIdenticalTo(defaultType, unknownType) || isTypeIdenticalTo(defaultType, emptyObjectType)) + ) { defaultType = anyType; } - result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) : baseDefaultType; + result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) + : baseDefaultType; } result.length = typeParameters!.length; return result; @@ -14560,11 +18695,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let hasThisParameter = false; const iife = getImmediatelyInvokedFunctionExpression(declaration); const isJSConstructSignature = isJSDocConstructSignature(declaration); - const isUntypedSignatureInJSFile = !iife && - isInJSFile(declaration) && - isValueSignatureDeclaration(declaration) && - !hasJSDocParameterTags(declaration) && - !getJSDocType(declaration); + const isUntypedSignatureInJSFile = !iife + && isInJSFile(declaration) + && isValueSignatureDeclaration(declaration) + && !hasJSDocParameterTags(declaration) + && !getJSDocType(declaration); if (isUntypedSignatureInJSFile) { flags |= SignatureFlags.IsUntypedSignatureInJSFile; } @@ -14576,10 +18711,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const param = declaration.parameters[i]; let paramSymbol = param.symbol; - const type = isJSDocParameterTag(param) ? (param.typeExpression && param.typeExpression.type) : param.type; + const type = isJSDocParameterTag(param) ? (param.typeExpression && param.typeExpression.type) + : param.type; // Include parameter symbol instead of property symbol in the signature if (paramSymbol && !!(paramSymbol.flags & SymbolFlags.Property) && !isBindingPattern(param.name)) { - const resolvedSymbol = resolveName(param, paramSymbol.escapedName, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + const resolvedSymbol = resolveName( + param, + paramSymbol.escapedName, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); paramSymbol = resolvedSymbol!; } if (i === 0 && paramSymbol.escapedName === InternalSymbolName.This) { @@ -14595,20 +18738,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Record a new minimum argument count if this is not an optional parameter - const isOptionalParameter = isOptionalJSDocPropertyLikeTag(param) || - param.initializer || param.questionToken || isRestParameter(param) || - iife && parameters.length > iife.arguments.length && !type || - isJSDocOptionalParameter(param); + const isOptionalParameter = isOptionalJSDocPropertyLikeTag(param) + || param.initializer || param.questionToken || isRestParameter(param) + || iife && parameters.length > iife.arguments.length && !type + || isJSDocOptionalParameter(param); if (!isOptionalParameter) { minArgumentCount = parameters.length; } } // If only one accessor includes a this-type annotation, the other behaves as if it had the same type annotation - if ((declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) && - hasBindableName(declaration) && - (!hasThisParameter || !thisParameter)) { - const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; + if ( + (declaration.kind === SyntaxKind.GetAccessor || declaration.kind === SyntaxKind.SetAccessor) + && hasBindableName(declaration) + && (!hasThisParameter || !thisParameter) + ) { + const otherKind = declaration.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor + : SyntaxKind.GetAccessor; const other = getDeclarationOfKind(getSymbolOfDeclaration(declaration), otherKind); if (other) { thisParameter = getAnnotatedAccessorThisParameter(other); @@ -14618,25 +18764,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInJSFile(declaration)) { const thisTag = getJSDocThisTag(declaration); if (thisTag && thisTag.typeExpression) { - thisParameter = createSymbolWithType(createSymbol(SymbolFlags.FunctionScopedVariable, InternalSymbolName.This), getTypeFromTypeNode(thisTag.typeExpression)); + thisParameter = createSymbolWithType( + createSymbol(SymbolFlags.FunctionScopedVariable, InternalSymbolName.This), + getTypeFromTypeNode(thisTag.typeExpression), + ); } } const hostDeclaration = isJSDocSignature(declaration) ? getEffectiveJSDocHost(declaration) : declaration; - const classType = hostDeclaration && isConstructorDeclaration(hostDeclaration) ? - getDeclaredTypeOfClassOrInterface(getMergedSymbol((hostDeclaration.parent as ClassDeclaration).symbol)) + const classType = hostDeclaration && isConstructorDeclaration(hostDeclaration) + ? getDeclaredTypeOfClassOrInterface( + getMergedSymbol((hostDeclaration.parent as ClassDeclaration).symbol), + ) : undefined; - const typeParameters = classType ? classType.localTypeParameters : getTypeParametersFromDeclaration(declaration); - if (hasRestParameter(declaration) || isInJSFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters)) { + const typeParameters = classType ? classType.localTypeParameters + : getTypeParametersFromDeclaration(declaration); + if ( + hasRestParameter(declaration) + || isInJSFile(declaration) && maybeAddJsSyntheticRestParameter(declaration, parameters) + ) { flags |= SignatureFlags.HasRestParameter; } - if (isConstructorTypeNode(declaration) && hasSyntacticModifier(declaration, ModifierFlags.Abstract) || - isConstructorDeclaration(declaration) && hasSyntacticModifier(declaration.parent, ModifierFlags.Abstract)) { + if ( + isConstructorTypeNode(declaration) && hasSyntacticModifier(declaration, ModifierFlags.Abstract) + || isConstructorDeclaration(declaration) + && hasSyntacticModifier(declaration.parent, ModifierFlags.Abstract) + ) { flags |= SignatureFlags.Abstract; } - links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, - /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, - minArgumentCount, flags); + links.resolvedSignature = createSignature( + declaration, + typeParameters, + thisParameter, + parameters, + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + minArgumentCount, + flags, + ); } return links.resolvedSignature; } @@ -14647,14 +18812,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * OR * 2. It has at least one parameter, and the last parameter has a matching `@param` with a type that starts with `...` */ - function maybeAddJsSyntheticRestParameter(declaration: SignatureDeclaration | JSDocSignature, parameters: Symbol[]): boolean { + function maybeAddJsSyntheticRestParameter( + declaration: SignatureDeclaration | JSDocSignature, + parameters: Symbol[], + ): boolean { if (isJSDocSignature(declaration) || !containsArgumentsReference(declaration)) { return false; } const lastParam = lastOrUndefined(declaration.parameters); - const lastParamTags = lastParam ? getJSDocParameterTags(lastParam) : getJSDocTags(declaration).filter(isJSDocParameterTag); - const lastParamVariadicType = firstDefined(lastParamTags, p => - p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined); + const lastParamTags = lastParam ? getJSDocParameterTags(lastParam) + : getJSDocTags(declaration).filter(isJSDocParameterTag); + const lastParamVariadicType = firstDefined( + lastParamTags, + p => p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined, + ); const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args" as __String, CheckFlags.RestParameter); if (lastParamVariadicType) { @@ -14713,7 +18884,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!node) return false; switch (node.kind) { case SyntaxKind.Identifier: - return (node as Identifier).escapedText === argumentsSymbol.escapedName && getReferencedValueSymbol(node as Identifier) === argumentsSymbol; + return (node as Identifier).escapedText === argumentsSymbol.escapedName + && getReferencedValueSymbol(node as Identifier) === argumentsSymbol; case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodDeclaration: @@ -14730,7 +18902,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return traverse((node as PropertyAssignment).initializer); default: - return !nodeStartsNewLexicalEnvironment(node) && !isPartOfTypeNode(node) && !!forEachChild(node, traverse); + return !nodeStartsNewLexicalEnvironment(node) && !isPartOfTypeNode(node) + && !!forEachChild(node, traverse); } } } @@ -14773,10 +18946,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If this is a function or method declaration, get the signature from the @type tag for the sake of optional parameters. // Exclude contextually-typed kinds because we already apply the @type tag to the context, plus applying it here to the initializer would supress checks that the two are compatible. result.push( - (!isFunctionExpressionOrArrowFunction(decl) && - !isObjectLiteralMethod(decl) && - getSignatureOfTypeTag(decl)) || - getSignatureFromDeclaration(decl) + (!isFunctionExpressionOrArrowFunction(decl) + && !isObjectLiteralMethod(decl) + && getSignatureOfTypeTag(decl)) + || getSignatureFromDeclaration(decl), ); } return result; @@ -14804,10 +18977,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!signature.resolvedTypePredicate) { if (signature.target) { const targetTypePredicate = getTypePredicateOfSignature(signature.target); - signature.resolvedTypePredicate = targetTypePredicate ? instantiateTypePredicate(targetTypePredicate, signature.mapper!) : noTypePredicate; + signature.resolvedTypePredicate = targetTypePredicate + ? instantiateTypePredicate(targetTypePredicate, signature.mapper!) : noTypePredicate; } else if (signature.compositeSignatures) { - signature.resolvedTypePredicate = getUnionOrIntersectionTypePredicate(signature.compositeSignatures, signature.compositeKind) || noTypePredicate; + signature.resolvedTypePredicate = + getUnionOrIntersectionTypePredicate(signature.compositeSignatures, signature.compositeKind) + || noTypePredicate; } else { const type = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); @@ -14818,9 +18994,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { jsdocPredicate = getTypePredicateOfSignature(jsdocSignature); } } - signature.resolvedTypePredicate = type && isTypePredicateNode(type) ? - createTypePredicateFromTypePredicateNode(type, signature) : - jsdocPredicate || noTypePredicate; + signature.resolvedTypePredicate = type && isTypePredicateNode(type) + ? createTypePredicateFromTypePredicateNode(type, signature) + : jsdocPredicate || noTypePredicate; } Debug.assert(!!signature.resolvedTypePredicate); } @@ -14830,10 +19006,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createTypePredicateFromTypePredicateNode(node: TypePredicateNode, signature: Signature): TypePredicate { const parameterName = node.parameterName; const type = node.type && getTypeFromTypeNode(node.type); - return parameterName.kind === SyntaxKind.ThisType ? - createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, /*parameterName*/ undefined, /*parameterIndex*/ undefined, type) : - createTypePredicate(node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, parameterName.escapedText as string, - findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type); + return parameterName.kind === SyntaxKind.ThisType + ? createTypePredicate( + node.assertsModifier ? TypePredicateKind.AssertsThis : TypePredicateKind.This, + /*parameterName*/ undefined, + /*parameterIndex*/ undefined, + type, + ) + : createTypePredicate( + node.assertsModifier ? TypePredicateKind.AssertsIdentifier : TypePredicateKind.Identifier, + parameterName.escapedText as string, + findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), + type, + ); } function getUnionOrIntersectionType(types: Type[], kind: TypeFlags | undefined, unionReduction?: UnionReduction) { @@ -14845,10 +19030,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { return errorType; } - let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper) : - signature.compositeSignatures ? instantiateType(getUnionOrIntersectionType(map(signature.compositeSignatures, getReturnTypeOfSignature), signature.compositeKind, UnionReduction.Subtype), signature.mapper) : - getReturnTypeFromAnnotation(signature.declaration!) || - (nodeIsMissing((signature.declaration as FunctionLikeDeclaration).body) ? anyType : getReturnTypeFromBody(signature.declaration as FunctionLikeDeclaration)); + let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper) + : signature.compositeSignatures + ? instantiateType( + getUnionOrIntersectionType( + map(signature.compositeSignatures, getReturnTypeOfSignature), + signature.compositeKind, + UnionReduction.Subtype, + ), + signature.mapper, + ) + : getReturnTypeFromAnnotation(signature.declaration!) + || (nodeIsMissing((signature.declaration as FunctionLikeDeclaration).body) ? anyType + : getReturnTypeFromBody(signature.declaration as FunctionLikeDeclaration)); if (signature.flags & SignatureFlags.IsInnerCallChain) { type = addOptionalTypeMarker(type); } @@ -14865,10 +19059,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const declaration = signature.declaration as Declaration; const name = getNameOfDeclaration(declaration); if (name) { - error(name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, declarationNameToString(name)); + error( + name, + Diagnostics + ._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, + declarationNameToString(name), + ); } else { - error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions); + error( + declaration, + Diagnostics + .Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, + ); } } } @@ -14887,7 +19090,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isJSDocSignature(declaration)) { const root = getJSDocRoot(declaration); if (root && isConstructorDeclaration(root.parent) && !typeNode) { - return getDeclaredTypeOfClassOrInterface(getMergedSymbol((root.parent.parent as ClassDeclaration).symbol)); + return getDeclaredTypeOfClassOrInterface( + getMergedSymbol((root.parent.parent as ClassDeclaration).symbol), + ); } } if (isJSDocConstructSignature(declaration)) { @@ -14901,7 +19106,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (jsDocType) { return jsDocType; } - const setter = getDeclarationOfKind(getSymbolOfDeclaration(declaration), SyntaxKind.SetAccessor); + const setter = getDeclarationOfKind( + getSymbolOfDeclaration(declaration), + SyntaxKind.SetAccessor, + ); const setterType = getAnnotatedAccessorType(setter); if (setterType) { return setterType; @@ -14911,8 +19119,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isResolvingReturnTypeOfSignature(signature: Signature): boolean { - return signature.compositeSignatures && some(signature.compositeSignatures, isResolvingReturnTypeOfSignature) || - !signature.resolvedReturnType && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0; + return signature.compositeSignatures && some(signature.compositeSignatures, isResolvingReturnTypeOfSignature) + || !signature.resolvedReturnType + && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0; } function getRestTypeOfSignature(signature: Signature): Type { @@ -14928,8 +19137,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: readonly TypeParameter[]): Signature { - const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript)); + function getSignatureInstantiation( + signature: Signature, + typeArguments: Type[] | undefined, + isJavascript: boolean, + inferredTypeParameters?: readonly TypeParameter[], + ): Signature { + const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments( + signature, + fillMissingTypeArguments( + typeArguments, + signature.typeParameters, + getMinTypeArgumentCount(signature.typeParameters), + isJavascript, + ), + ); if (inferredTypeParameters) { const returnSignature = getSingleCallOrConstructSignature(getReturnTypeOfSignature(instantiatedSignature)); if (returnSignature) { @@ -14943,7 +19165,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return instantiatedSignature; } - function getSignatureInstantiationWithoutFillingInTypeArguments(signature: Signature, typeArguments: readonly Type[] | undefined): Signature { + function getSignatureInstantiationWithoutFillingInTypeArguments( + signature: Signature, + typeArguments: readonly Type[] | undefined, + ): Signature { const instantiations = signature.instantiations || (signature.instantiations = new Map()); const id = getTypeListId(typeArguments); let instantiation = instantiations.get(id); @@ -14954,7 +19179,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createSignatureInstantiation(signature: Signature, typeArguments: readonly Type[] | undefined): Signature { - return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true); + return instantiateSignature( + signature, + createSignatureTypeMapper(signature, typeArguments), + /*eraseTypeParameters*/ true, + ); } function createSignatureTypeMapper(signature: Signature, typeArguments: readonly Type[] | undefined): TypeMapper { @@ -14962,20 +19191,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getErasedSignature(signature: Signature): Signature { - return signature.typeParameters ? - signature.erasedSignatureCache || (signature.erasedSignatureCache = createErasedSignature(signature)) : - signature; + return signature.typeParameters + ? signature.erasedSignatureCache || (signature.erasedSignatureCache = createErasedSignature(signature)) + : signature; } function createErasedSignature(signature: Signature) { // Create an instantiation of the signature where all type arguments are the any type. - return instantiateSignature(signature, createTypeEraser(signature.typeParameters!), /*eraseTypeParameters*/ true); + return instantiateSignature( + signature, + createTypeEraser(signature.typeParameters!), + /*eraseTypeParameters*/ true, + ); } function getCanonicalSignature(signature: Signature): Signature { - return signature.typeParameters ? - signature.canonicalSignatureCache || (signature.canonicalSignatureCache = createCanonicalSignature(signature)) : - signature; + return signature.typeParameters + ? signature.canonicalSignatureCache + || (signature.canonicalSignatureCache = createCanonicalSignature(signature)) + : signature; } function createCanonicalSignature(signature: Signature) { @@ -14988,7 +19222,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getSignatureInstantiation( signature, map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp), - isInJSFile(signature.declaration)); + isInJSFile(signature.declaration), + ); } function getBaseSignature(signature: Signature) { @@ -14998,8 +19233,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return signature.baseSignatureCache; } const typeEraser = createTypeEraser(typeParameters); - const baseConstraintMapper = createTypeMapper(typeParameters, map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType)); - let baseConstraints: readonly Type[] = map(typeParameters, tp => instantiateType(tp, baseConstraintMapper) || unknownType); + const baseConstraintMapper = createTypeMapper( + typeParameters, + map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType), + ); + let baseConstraints: readonly Type[] = map( + typeParameters, + tp => instantiateType(tp, baseConstraintMapper) || unknownType, + ); // Run N type params thru the immediate constraint mapper up to N times // This way any noncircular interdependent type parameters are definitely resolved to their external dependencies for (let i = 0; i < typeParameters.length - 1; i++) { @@ -15007,7 +19248,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // and then apply a type eraser to remove any remaining circularly dependent type parameters baseConstraints = instantiateTypes(baseConstraints, typeEraser); - return signature.baseSignatureCache = instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true); + return signature.baseSignatureCache = instantiateSignature( + signature, + createTypeMapper(typeParameters, baseConstraints), + /*eraseTypeParameters*/ true, + ); } return signature; } @@ -15021,7 +19266,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const kind = signature.declaration?.kind; // If declaration is undefined, it is likely to be the signature of the default constructor. - const isConstructor = kind === undefined || kind === SyntaxKind.Constructor || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType; + const isConstructor = kind === undefined || kind === SyntaxKind.Constructor + || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType; const type = createObjectType(ObjectFlags.Anonymous); type.members = emptySymbols; @@ -15043,7 +19289,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbolTable.get(InternalSymbolName.Index); } - function createIndexInfo(keyType: Type, type: Type, isReadonly: boolean, declaration?: IndexSignatureDeclaration): IndexInfo { + function createIndexInfo( + keyType: Type, + type: Type, + isReadonly: boolean, + declaration?: IndexSignatureDeclaration, + ): IndexInfo { return { keyType, type, isReadonly, declaration }; } @@ -15061,8 +19312,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (parameter.type) { forEachType(getTypeFromTypeNode(parameter.type), keyType => { if (isValidIndexKeyType(keyType) && !findIndexInfo(indexInfos, keyType)) { - indexInfos.push(createIndexInfo(keyType, declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, - hasEffectiveModifier(declaration, ModifierFlags.Readonly), declaration)); + indexInfos.push( + createIndexInfo( + keyType, + declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, + hasEffectiveModifier(declaration, ModifierFlags.Readonly), + declaration, + ), + ); } }); } @@ -15074,12 +19331,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isValidIndexKeyType(type: Type): boolean { - return !!(type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol)) || isPatternLiteralType(type) || - !!(type.flags & TypeFlags.Intersection) && !isGenericType(type) && some((type as IntersectionType).types, isValidIndexKeyType); + return !!(type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.ESSymbol)) || isPatternLiteralType(type) + || !!(type.flags & TypeFlags.Intersection) && !isGenericType(type) + && some((type as IntersectionType).types, isValidIndexKeyType); } function getConstraintDeclaration(type: TypeParameter): TypeNode | undefined { - return mapDefined(filter(type.symbol && type.symbol.declarations, isTypeParameterDeclaration), getEffectiveConstraintOfTypeParameter)[0]; + return mapDefined( + filter(type.symbol && type.symbol.declarations, isTypeParameterDeclaration), + getEffectiveConstraintOfTypeParameter, + )[0]; } function getInferredTypeParameterConstraint(typeParameter: TypeParameter, omitTypeReferences?: boolean) { @@ -15091,7 +19352,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (such as 'Foo'), T's constraint is inferred from the constraint of the // corresponding type parameter in 'Foo'. When multiple 'infer T' declarations are // present, we form an intersection of the inferred constraint types. - const [childTypeParameter = declaration.parent, grandParent] = walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent); + const [childTypeParameter = declaration.parent, grandParent] = + walkUpParenthesizedTypesAndGetParentAndChild(declaration.parent.parent); if (grandParent.kind === SyntaxKind.TypeReference && !omitTypeReferences) { const typeReference = grandParent as TypeReferenceNode; const typeParameters = getTypeParametersForTypeReferenceOrImport(typeReference); @@ -15106,9 +19368,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // type Foo = [T, U]; // type Bar = T extends Foo ? Foo : T; // the instantiated constraint for U is X, so we discard that inference. - const mapper = makeDeferredTypeMapper(typeParameters, typeParameters.map((_, index) => () => { - return getEffectiveTypeArgumentAtIndex(typeReference, typeParameters, index); - })); + const mapper = makeDeferredTypeMapper( + typeParameters, + typeParameters.map((_, index) => () => { + return getEffectiveTypeArgumentAtIndex( + typeReference, + typeParameters, + index, + ); + }), + ); const constraint = instantiateType(declaredConstraint, mapper); if (constraint !== typeParameter) { inferences = append(inferences, constraint); @@ -15119,9 +19388,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // When an 'infer T' declaration is immediately contained in a rest parameter declaration, a rest type // or a named rest tuple element, we infer an 'unknown[]' constraint. - else if (grandParent.kind === SyntaxKind.Parameter && (grandParent as ParameterDeclaration).dotDotDotToken || - grandParent.kind === SyntaxKind.RestType || - grandParent.kind === SyntaxKind.NamedTupleMember && (grandParent as NamedTupleMember).dotDotDotToken) { + else if ( + grandParent.kind === SyntaxKind.Parameter + && (grandParent as ParameterDeclaration).dotDotDotToken + || grandParent.kind === SyntaxKind.RestType + || grandParent.kind === SyntaxKind.NamedTupleMember + && (grandParent as NamedTupleMember).dotDotDotToken + ) { inferences = append(inferences, createArrayType(unknownType)); } // When an 'infer T' declaration is immediately contained in a string template type, we infer a 'string' @@ -15131,21 +19404,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // When an 'infer T' declaration is in the constraint position of a mapped type, we infer a 'keyof any' // constraint. - else if (grandParent.kind === SyntaxKind.TypeParameter && grandParent.parent.kind === SyntaxKind.MappedType) { + else if ( + grandParent.kind === SyntaxKind.TypeParameter + && grandParent.parent.kind === SyntaxKind.MappedType + ) { inferences = append(inferences, keyofConstraintType); } // When an 'infer T' declaration is the template of a mapped type, and that mapped type is the extends // clause of a conditional whose check type is also a mapped type, give it a constraint equal to the template // of the check type's mapped type - else if (grandParent.kind === SyntaxKind.MappedType && (grandParent as MappedTypeNode).type && - skipParentheses((grandParent as MappedTypeNode).type!) === declaration.parent && grandParent.parent.kind === SyntaxKind.ConditionalType && - (grandParent.parent as ConditionalTypeNode).extendsType === grandParent && (grandParent.parent as ConditionalTypeNode).checkType.kind === SyntaxKind.MappedType && - ((grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode).type) { + else if ( + grandParent.kind === SyntaxKind.MappedType && (grandParent as MappedTypeNode).type + && skipParentheses((grandParent as MappedTypeNode).type!) === declaration.parent + && grandParent.parent.kind === SyntaxKind.ConditionalType + && (grandParent.parent as ConditionalTypeNode).extendsType === grandParent + && (grandParent.parent as ConditionalTypeNode).checkType.kind === SyntaxKind.MappedType + && ((grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode).type + ) { const checkMappedType = (grandParent.parent as ConditionalTypeNode).checkType as MappedTypeNode; const nodeType = getTypeFromTypeNode(checkMappedType.type!); - inferences = append(inferences, instantiateType(nodeType, - makeUnaryTypeMapper(getDeclaredTypeOfTypeParameter(getSymbolOfDeclaration(checkMappedType.typeParameter)), checkMappedType.typeParameter.constraint ? getTypeFromTypeNode(checkMappedType.typeParameter.constraint) : keyofConstraintType) - )); + inferences = append( + inferences, + instantiateType( + nodeType, + makeUnaryTypeMapper( + getDeclaredTypeOfTypeParameter( + getSymbolOfDeclaration(checkMappedType.typeParameter), + ), + checkMappedType.typeParameter.constraint + ? getTypeFromTypeNode(checkMappedType.typeParameter.constraint) + : keyofConstraintType, + ), + ), + ); } } } @@ -15158,7 +19449,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!typeParameter.constraint) { if (typeParameter.target) { const targetConstraint = getConstraintOfTypeParameter(typeParameter.target); - typeParameter.constraint = targetConstraint ? instantiateType(targetConstraint, typeParameter.mapper) : noConstraintType; + typeParameter.constraint = targetConstraint ? instantiateType(targetConstraint, typeParameter.mapper) + : noConstraintType; } else { const constraintDeclaration = getConstraintDeclaration(typeParameter); @@ -15170,7 +19462,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Any && !isErrorType(type)) { // Allow errorType to propegate to keep downstream errors suppressed // use keyofConstraintType as the base constraint for mapped type key constraints (unknown isn;t assignable to that, but `any` was), // use unknown otherwise - type = constraintDeclaration.parent.parent.kind === SyntaxKind.MappedType ? keyofConstraintType : unknownType; + type = constraintDeclaration.parent.parent.kind === SyntaxKind.MappedType ? keyofConstraintType + : unknownType; } typeParameter.constraint = type; } @@ -15210,7 +19503,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getAliasId(aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { - return aliasSymbol ? `@${getSymbolId(aliasSymbol)}` + (aliasTypeArguments ? `:${getTypeListId(aliasTypeArguments)}` : "") : ""; + return aliasSymbol + ? `@${getSymbolId(aliasSymbol)}` + (aliasTypeArguments ? `:${getTypeListId(aliasTypeArguments)}` : "") : ""; } // This function is used to propagate certain flags when creating new object type references and union types. @@ -15256,7 +19550,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function createDeferredTypeReference(target: GenericType, node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): DeferredTypeReference { + function createDeferredTypeReference( + target: GenericType, + node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, + mapper?: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): DeferredTypeReference { if (!aliasSymbol) { aliasSymbol = getAliasSymbolForTypeNode(node); const localAliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); @@ -15277,10 +19577,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type.target.localTypeParameters?.map(() => errorType) || emptyArray; } const node = type.node; - const typeArguments = !node ? emptyArray : - node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) : - node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : - map(node.elements, getTypeFromTypeNode); + const typeArguments = !node ? emptyArray + : node.kind === SyntaxKind.TypeReference + ? concatenate( + type.target.outerTypeParameters, + getEffectiveTypeArguments(node, type.target.localTypeParameters!), + ) + : node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] + : map(node.elements, getTypeFromTypeNode); if (popTypeResolution()) { type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments; } @@ -15288,8 +19592,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type.resolvedTypeArguments = type.target.localTypeParameters?.map(() => errorType) || emptyArray; error( type.node || currentNode, - type.target.symbol ? Diagnostics.Type_arguments_for_0_circularly_reference_themselves : Diagnostics.Tuple_type_arguments_circularly_reference_themselves, - type.target.symbol && symbolToString(type.target.symbol) + type.target.symbol ? Diagnostics.Type_arguments_for_0_circularly_reference_themselves + : Diagnostics.Tuple_type_arguments_circularly_reference_themselves, + type.target.symbol && symbolToString(type.target.symbol), ); } } @@ -15300,7 +19605,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return length(type.target.typeParameters); } - /** * Get type from type-reference that reference to class or interface */ @@ -15312,38 +19616,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); const isJs = isInJSFile(node); const isJsImplicitAny = !noImplicitAny && isJs; - if (!isJsImplicitAny && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length)) { - const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) && !isJSDocAugmentsTag(node.parent); - const diag = minTypeArgumentCount === typeParameters.length ? - missingAugmentsTag ? - Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag : - Diagnostics.Generic_type_0_requires_1_type_argument_s : - missingAugmentsTag ? - Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag : - Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; - - const typeStr = typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType); + if ( + !isJsImplicitAny + && (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) + ) { + const missingAugmentsTag = isJs && isExpressionWithTypeArguments(node) + && !isJSDocAugmentsTag(node.parent); + const diag = minTypeArgumentCount === typeParameters.length + ? missingAugmentsTag + ? Diagnostics.Expected_0_type_arguments_provide_these_with_an_extends_tag + : Diagnostics.Generic_type_0_requires_1_type_argument_s + : missingAugmentsTag + ? Diagnostics.Expected_0_1_type_arguments_provide_these_with_an_extends_tag + : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments; + + const typeStr = typeToString( + type, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.WriteArrayAsGenericType, + ); error(node, diag, typeStr, minTypeArgumentCount, typeParameters.length); if (!isJs) { // TODO: Adopt same permissive behavior in TS as in JS to reduce follow-on editing experience failures (requires editing fillMissingTypeArguments) return errorType; } } - if (node.kind === SyntaxKind.TypeReference && isDeferredTypeReferenceNode(node as TypeReferenceNode, length(node.typeArguments) !== typeParameters.length)) { - return createDeferredTypeReference(type as GenericType, node as TypeReferenceNode, /*mapper*/ undefined); + if ( + node.kind === SyntaxKind.TypeReference + && isDeferredTypeReferenceNode( + node as TypeReferenceNode, + length(node.typeArguments) !== typeParameters.length, + ) + ) { + return createDeferredTypeReference( + type as GenericType, + node as TypeReferenceNode, + /*mapper*/ undefined, + ); } // In a type reference, the outer type parameters of the referenced class or interface are automatically // supplied as type arguments and the type reference only specifies arguments for the local type parameters // of the class or interface. - const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isJs)); + const typeArguments = concatenate( + type.outerTypeParameters, + fillMissingTypeArguments( + typeArgumentsFromTypeReferenceNode(node), + typeParameters, + minTypeArgumentCount, + isJs, + ), + ); return createTypeReference(type as GenericType, typeArguments); } return checkNoTypeArguments(node, symbol) ? type : errorType; } - function getTypeAliasInstantiation(symbol: Symbol, typeArguments: readonly Type[] | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getTypeAliasInstantiation( + symbol: Symbol, + typeArguments: readonly Type[] | undefined, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { const type = getDeclaredTypeOfSymbol(symbol); - if (type === intrinsicMarkerType && intrinsicTypeKinds.has(symbol.escapedName as string) && typeArguments && typeArguments.length === 1) { + if ( + type === intrinsicMarkerType && intrinsicTypeKinds.has(symbol.escapedName as string) && typeArguments + && typeArguments.length === 1 + ) { return getStringMappingType(symbol, typeArguments[0]); } const links = getSymbolLinks(symbol); @@ -15351,9 +19689,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const id = getTypeListId(typeArguments) + getAliasId(aliasSymbol, aliasTypeArguments); let instantiation = links.instantiations!.get(id); if (!instantiation) { - links.instantiations!.set(id, instantiation = instantiateTypeWithAlias(type, - createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters), isInJSFile(symbol.valueDeclaration))), - aliasSymbol, aliasTypeArguments)); + links.instantiations!.set( + id, + instantiation = instantiateTypeWithAlias( + type, + createTypeMapper( + typeParameters, + fillMissingTypeArguments( + typeArguments, + typeParameters, + getMinTypeArgumentCount(typeParameters), + isInJSFile(symbol.valueDeclaration), + ), + ), + aliasSymbol, + aliasTypeArguments, + ), + ); } return instantiation; } @@ -15382,13 +19734,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const numTypeArguments = length(node.typeArguments); const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters); if (numTypeArguments < minTypeArgumentCount || numTypeArguments > typeParameters.length) { - error(node, - minTypeArgumentCount === typeParameters.length ? - Diagnostics.Generic_type_0_requires_1_type_argument_s : - Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments, + error( + node, + minTypeArgumentCount === typeParameters.length + ? Diagnostics.Generic_type_0_requires_1_type_argument_s + : Diagnostics.Generic_type_0_requires_between_1_and_2_type_arguments, symbolToString(symbol), minTypeArgumentCount, - typeParameters.length); + typeParameters.length, + ); return errorType; } // We refrain from associating a local type alias with an instantiation of a top-level type alias @@ -15396,7 +19750,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // accessible--which in turn may lead to a large structural expansion of the type when generating // a .d.ts file. See #43622 for an example. const aliasSymbol = getAliasSymbolForTypeNode(node); - let newAliasSymbol = aliasSymbol && (isLocalTypeAlias(symbol) || !isLocalTypeAlias(aliasSymbol)) ? aliasSymbol : undefined; + let newAliasSymbol = aliasSymbol && (isLocalTypeAlias(symbol) || !isLocalTypeAlias(aliasSymbol)) + ? aliasSymbol : undefined; let aliasTypeArguments: Type[] | undefined; if (newAliasSymbol) { aliasTypeArguments = getTypeArgumentsForAliasSymbol(newAliasSymbol); @@ -15409,11 +19764,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const resolved = resolveAlias(aliasSymbol); if (resolved && resolved.flags & SymbolFlags.TypeAlias) { newAliasSymbol = resolved; - aliasTypeArguments = typeArgumentsFromTypeReferenceNode(node) || (typeParameters ? [] : undefined); + aliasTypeArguments = typeArgumentsFromTypeReferenceNode(node) + || (typeParameters ? [] : undefined); } } } - return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node), newAliasSymbol, aliasTypeArguments); + return getTypeAliasInstantiation( + symbol, + typeArgumentsFromTypeReferenceNode(node), + newAliasSymbol, + aliasTypeArguments, + ); } return checkNoTypeArguments(node, symbol) ? type : errorType; } @@ -15434,7 +19795,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isEntityNameExpression(expr)) { return expr; } - // fall through; + // fall through; } return undefined; @@ -15445,14 +19806,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getUnresolvedSymbolForEntityName(name: EntityNameOrEntityNameExpression) { - const identifier = name.kind === SyntaxKind.QualifiedName ? name.right : - name.kind === SyntaxKind.PropertyAccessExpression ? name.name : - name; + const identifier = name.kind === SyntaxKind.QualifiedName ? name.right + : name.kind === SyntaxKind.PropertyAccessExpression ? name.name + : name; const text = identifier.escapedText; if (text) { - const parentSymbol = name.kind === SyntaxKind.QualifiedName ? getUnresolvedSymbolForEntityName(name.left) : - name.kind === SyntaxKind.PropertyAccessExpression ? getUnresolvedSymbolForEntityName(name.expression) : - undefined; + const parentSymbol = name.kind === SyntaxKind.QualifiedName ? getUnresolvedSymbolForEntityName(name.left) + : name.kind === SyntaxKind.PropertyAccessExpression ? getUnresolvedSymbolForEntityName(name.expression) + : undefined; const path = parentSymbol ? `${getSymbolPath(parentSymbol)}.${text}` : text as string; let result = unresolvedSymbols.get(path); if (!result) { @@ -15471,8 +19832,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return unknownSymbol; } const symbol = resolveEntityName(name, meaning, ignoreErrors); - return symbol && symbol !== unknownSymbol ? symbol : - ignoreErrors ? unknownSymbol : getUnresolvedSymbolForEntityName(name); + return symbol && symbol !== unknownSymbol ? symbol + : ignoreErrors ? unknownSymbol : getUnresolvedSymbolForEntityName(name); } function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type { @@ -15515,7 +19876,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const valueType = getTypeOfSymbol(symbol); let typeType = valueType; if (symbol.valueDeclaration) { - const isImportTypeWithQualifier = node.kind === SyntaxKind.ImportType && (node as ImportTypeNode).qualifier; + const isImportTypeWithQualifier = node.kind === SyntaxKind.ImportType + && (node as ImportTypeNode).qualifier; // valueType might not have a symbol, eg, {import('./b').STRING_LITERAL} if (valueType.symbol && valueType.symbol !== symbol && isImportTypeWithQualifier) { typeType = getTypeReferenceType(node, valueType.symbol); @@ -15551,9 +19913,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getImpliedConstraint(type: Type, checkNode: TypeNode, extendsNode: TypeNode): Type | undefined { - return isUnaryTupleTypeNode(checkNode) && isUnaryTupleTypeNode(extendsNode) ? getImpliedConstraint(type, (checkNode as TupleTypeNode).elements[0], (extendsNode as TupleTypeNode).elements[0]) : - getActualTypeVariable(getTypeFromTypeNode(checkNode)) === getActualTypeVariable(type) ? getTypeFromTypeNode(extendsNode) : - undefined; + return isUnaryTupleTypeNode(checkNode) && isUnaryTupleTypeNode(extendsNode) + ? getImpliedConstraint( + type, + (checkNode as TupleTypeNode).elements[0], + (extendsNode as TupleTypeNode).elements[0], + ) + : getActualTypeVariable(getTypeFromTypeNode(checkNode)) === getActualTypeVariable(type) + ? getTypeFromTypeNode(extendsNode) + : undefined; } function getConditionalFlowTypeOfType(type: Type, node: Node) { @@ -15568,15 +19936,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Always substitute on type parameters, regardless of variance, since even // in contravariant positions, they may rely on substituted constraints to be valid - if ((covariant || type.flags & TypeFlags.TypeVariable) && parent.kind === SyntaxKind.ConditionalType && node === (parent as ConditionalTypeNode).trueType) { - const constraint = getImpliedConstraint(type, (parent as ConditionalTypeNode).checkType, (parent as ConditionalTypeNode).extendsType); + if ( + (covariant || type.flags & TypeFlags.TypeVariable) && parent.kind === SyntaxKind.ConditionalType + && node === (parent as ConditionalTypeNode).trueType + ) { + const constraint = getImpliedConstraint( + type, + (parent as ConditionalTypeNode).checkType, + (parent as ConditionalTypeNode).extendsType, + ); if (constraint) { constraints = append(constraints, constraint); } } // Given a homomorphic mapped type { [K in keyof T]: XXX }, where T is constrained to an array or tuple type, in the // template type XXX, K has an added constraint of number | `${number}`. - else if (type.flags & TypeFlags.TypeParameter && parent.kind === SyntaxKind.MappedType && node === (parent as MappedTypeNode).type) { + else if ( + type.flags & TypeFlags.TypeParameter && parent.kind === SyntaxKind.MappedType + && node === (parent as MappedTypeNode).type + ) { const mappedType = getTypeFromTypeNode(parent as TypeNode) as MappedType; if (getTypeParameterFromMappedType(mappedType) === getActualTypeVariable(type)) { const typeParameter = getHomomorphicTypeVariable(mappedType); @@ -15594,12 +19972,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isJSDocTypeReference(node: Node): node is TypeReferenceNode { - return !!(node.flags & NodeFlags.JSDoc) && (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ImportType); + return !!(node.flags & NodeFlags.JSDoc) + && (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ImportType); } function checkNoTypeArguments(node: NodeWithTypeArguments, symbol?: Symbol) { if (node.typeArguments) { - error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : (node as TypeReferenceNode).typeName ? declarationNameToString((node as TypeReferenceNode).typeName) : anon); + error( + node, + Diagnostics.Type_0_is_not_generic, + symbol ? symbolToString(symbol) + : (node as TypeReferenceNode).typeName + ? declarationNameToString((node as TypeReferenceNode).typeName) : anon, + ); return false; } return true; @@ -15640,8 +20025,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isJSDocIndexSignature(node)) { const indexed = getTypeFromTypeNode(typeArgs[0]); const target = getTypeFromTypeNode(typeArgs[1]); - const indexInfo = indexed === stringType || indexed === numberType ? [createIndexInfo(indexed, target, /*isReadonly*/ false)] : emptyArray; - return createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, indexInfo); + const indexInfo = indexed === stringType || indexed === numberType + ? [createIndexInfo(indexed, target, /*isReadonly*/ false)] : emptyArray; + return createAnonymousType( + /*symbol*/ undefined, + emptySymbols, + emptyArray, + emptyArray, + indexInfo, + ); } return anyType; } @@ -15710,7 +20102,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeOfGlobalSymbol(symbol: Symbol | undefined, arity: number): ObjectType { - function getTypeDeclaration(symbol: Symbol): Declaration | undefined { const declarations = symbol.declarations; if (declarations) { @@ -15730,26 +20121,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const type = getDeclaredTypeOfSymbol(symbol); if (!(type.flags & TypeFlags.Object)) { - error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_be_a_class_or_interface_type, symbolName(symbol)); + error( + getTypeDeclaration(symbol), + Diagnostics.Global_type_0_must_be_a_class_or_interface_type, + symbolName(symbol), + ); return arity ? emptyGenericType : emptyObjectType; } if (length((type as InterfaceType).typeParameters) !== arity) { - error(getTypeDeclaration(symbol), Diagnostics.Global_type_0_must_have_1_type_parameter_s, symbolName(symbol), arity); + error( + getTypeDeclaration(symbol), + Diagnostics.Global_type_0_must_have_1_type_parameter_s, + symbolName(symbol), + arity, + ); return arity ? emptyGenericType : emptyObjectType; } return type as ObjectType; } function getGlobalValueSymbol(name: __String, reportErrors: boolean): Symbol | undefined { - return getGlobalSymbol(name, SymbolFlags.Value, reportErrors ? Diagnostics.Cannot_find_global_value_0 : undefined); + return getGlobalSymbol( + name, + SymbolFlags.Value, + reportErrors ? Diagnostics.Cannot_find_global_value_0 : undefined, + ); } function getGlobalTypeSymbol(name: __String, reportErrors: boolean): Symbol | undefined { - return getGlobalSymbol(name, SymbolFlags.Type, reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined); + return getGlobalSymbol( + name, + SymbolFlags.Type, + reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined, + ); } function getGlobalTypeAliasSymbol(name: __String, arity: number, reportErrors: boolean): Symbol | undefined { - const symbol = getGlobalSymbol(name, SymbolFlags.Type, reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined); + const symbol = getGlobalSymbol( + name, + SymbolFlags.Type, + reportErrors ? Diagnostics.Cannot_find_global_type_0 : undefined, + ); if (symbol) { // Resolve the declared type of the symbol. This resolves type parameters for the type // alias so that we can check arity. @@ -15763,9 +20175,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return symbol; } - function getGlobalSymbol(name: __String, meaning: SymbolFlags, diagnostic: DiagnosticMessage | undefined): Symbol | undefined { + function getGlobalSymbol( + name: __String, + meaning: SymbolFlags, + diagnostic: DiagnosticMessage | undefined, + ): Symbol | undefined { // Don't track references for global symbols anyway, so value if `isReference` is arbitrary - return resolveName(/*location*/ undefined, name, meaning, diagnostic, name, /*isUse*/ false, /*excludeGlobals*/ false, /*getSpellingSuggestions*/ false); + return resolveName( + /*location*/ undefined, + name, + meaning, + diagnostic, + name, + /*isUse*/ false, + /*excludeGlobals*/ false, + /*getSpellingSuggestions*/ false, + ); } function getGlobalType(name: __String, arity: 0, reportErrors: true): ObjectType; @@ -15779,17 +20204,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getGlobalTypedPropertyDescriptorType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalTypedPropertyDescriptorType ||= getGlobalType("TypedPropertyDescriptor" as __String, /*arity*/ 1, /*reportErrors*/ true) || emptyGenericType; + return deferredGlobalTypedPropertyDescriptorType ||= + getGlobalType("TypedPropertyDescriptor" as __String, /*arity*/ 1, /*reportErrors*/ true) + || emptyGenericType; } function getGlobalTemplateStringsArrayType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalTemplateStringsArrayType ||= getGlobalType("TemplateStringsArray" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; + return deferredGlobalTemplateStringsArrayType ||= + getGlobalType("TemplateStringsArray" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; } function getGlobalImportMetaType() { // We always report an error, so store a result in the event we could not resolve the symbol to prevent reporting it multiple times - return deferredGlobalImportMetaType ||= getGlobalType("ImportMeta" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; + return deferredGlobalImportMetaType ||= + getGlobalType("ImportMeta" as __String, /*arity*/ 0, /*reportErrors*/ true) || emptyObjectType; } function getGlobalImportMetaExpressionType() { @@ -15805,13 +20234,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const members = createSymbolTable([metaPropertySymbol]); symbol.members = members; - deferredGlobalImportMetaExpressionType = createAnonymousType(symbol, members, emptyArray, emptyArray, emptyArray); + deferredGlobalImportMetaExpressionType = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + emptyArray, + ); } return deferredGlobalImportMetaExpressionType; } function getGlobalImportCallOptionsType(reportErrors: boolean) { - return (deferredGlobalImportCallOptionsType ||= getGlobalType("ImportCallOptions" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return (deferredGlobalImportCallOptionsType ||= getGlobalType( + "ImportCallOptions" as __String, + /*arity*/ 0, + reportErrors, + )) || emptyObjectType; } function getGlobalESSymbolConstructorSymbol(reportErrors: boolean): Symbol | undefined { @@ -15819,19 +20258,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getGlobalESSymbolConstructorTypeSymbol(reportErrors: boolean): Symbol | undefined { - return deferredGlobalESSymbolConstructorTypeSymbol ||= getGlobalTypeSymbol("SymbolConstructor" as __String, reportErrors); + return deferredGlobalESSymbolConstructorTypeSymbol ||= getGlobalTypeSymbol( + "SymbolConstructor" as __String, + reportErrors, + ); } function getGlobalESSymbolType() { - return (deferredGlobalESSymbolType ||= getGlobalType("Symbol" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType; + return (deferredGlobalESSymbolType ||= getGlobalType("Symbol" as __String, /*arity*/ 0, /*reportErrors*/ false)) + || emptyObjectType; } function getGlobalPromiseType(reportErrors: boolean) { - return (deferredGlobalPromiseType ||= getGlobalType("Promise" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalPromiseType ||= getGlobalType("Promise" as __String, /*arity*/ 1, reportErrors)) + || emptyGenericType; } function getGlobalPromiseLikeType(reportErrors: boolean) { - return (deferredGlobalPromiseLikeType ||= getGlobalType("PromiseLike" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalPromiseLikeType ||= getGlobalType("PromiseLike" as __String, /*arity*/ 1, reportErrors)) + || emptyGenericType; } function getGlobalPromiseConstructorSymbol(reportErrors: boolean): Symbol | undefined { @@ -15839,55 +20284,95 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getGlobalPromiseConstructorLikeType(reportErrors: boolean) { - return (deferredGlobalPromiseConstructorLikeType ||= getGlobalType("PromiseConstructorLike" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return (deferredGlobalPromiseConstructorLikeType ||= getGlobalType( + "PromiseConstructorLike" as __String, + /*arity*/ 0, + reportErrors, + )) || emptyObjectType; } function getGlobalAsyncIterableType(reportErrors: boolean) { - return (deferredGlobalAsyncIterableType ||= getGlobalType("AsyncIterable" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalAsyncIterableType ||= getGlobalType( + "AsyncIterable" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalAsyncIteratorType(reportErrors: boolean) { - return (deferredGlobalAsyncIteratorType ||= getGlobalType("AsyncIterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return (deferredGlobalAsyncIteratorType ||= getGlobalType( + "AsyncIterator" as __String, + /*arity*/ 3, + reportErrors, + )) || emptyGenericType; } function getGlobalAsyncIterableIteratorType(reportErrors: boolean) { - return (deferredGlobalAsyncIterableIteratorType ||= getGlobalType("AsyncIterableIterator" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalAsyncIterableIteratorType ||= getGlobalType( + "AsyncIterableIterator" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalAsyncGeneratorType(reportErrors: boolean) { - return (deferredGlobalAsyncGeneratorType ||= getGlobalType("AsyncGenerator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return (deferredGlobalAsyncGeneratorType ||= getGlobalType( + "AsyncGenerator" as __String, + /*arity*/ 3, + reportErrors, + )) || emptyGenericType; } function getGlobalIterableType(reportErrors: boolean) { - return (deferredGlobalIterableType ||= getGlobalType("Iterable" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalIterableType ||= getGlobalType("Iterable" as __String, /*arity*/ 1, reportErrors)) + || emptyGenericType; } function getGlobalIteratorType(reportErrors: boolean) { - return (deferredGlobalIteratorType ||= getGlobalType("Iterator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return (deferredGlobalIteratorType ||= getGlobalType("Iterator" as __String, /*arity*/ 3, reportErrors)) + || emptyGenericType; } function getGlobalIterableIteratorType(reportErrors: boolean) { - return (deferredGlobalIterableIteratorType ||= getGlobalType("IterableIterator" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalIterableIteratorType ||= getGlobalType( + "IterableIterator" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalGeneratorType(reportErrors: boolean) { - return (deferredGlobalGeneratorType ||= getGlobalType("Generator" as __String, /*arity*/ 3, reportErrors)) || emptyGenericType; + return (deferredGlobalGeneratorType ||= getGlobalType("Generator" as __String, /*arity*/ 3, reportErrors)) + || emptyGenericType; } function getGlobalIteratorYieldResultType(reportErrors: boolean) { - return (deferredGlobalIteratorYieldResultType ||= getGlobalType("IteratorYieldResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalIteratorYieldResultType ||= getGlobalType( + "IteratorYieldResult" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalIteratorReturnResultType(reportErrors: boolean) { - return (deferredGlobalIteratorReturnResultType ||= getGlobalType("IteratorReturnResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; + return (deferredGlobalIteratorReturnResultType ||= getGlobalType( + "IteratorReturnResult" as __String, + /*arity*/ 1, + reportErrors, + )) || emptyGenericType; } function getGlobalDisposableType(reportErrors: boolean) { - return (deferredGlobalDisposableType ||= getGlobalType("Disposable" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return (deferredGlobalDisposableType ||= getGlobalType("Disposable" as __String, /*arity*/ 0, reportErrors)) + || emptyObjectType; } function getGlobalAsyncDisposableType(reportErrors: boolean) { - return (deferredGlobalAsyncDisposableType ||= getGlobalType("AsyncDisposable" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + return (deferredGlobalAsyncDisposableType ||= getGlobalType( + "AsyncDisposable" as __String, + /*arity*/ 0, + reportErrors, + )) || emptyObjectType; } function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType | undefined { @@ -15897,56 +20382,92 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getGlobalExtractSymbol(): Symbol | undefined { // We always report an error, so cache a result in the event we could not resolve the symbol to prevent reporting it multiple times - deferredGlobalExtractSymbol ||= getGlobalTypeAliasSymbol("Extract" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; + deferredGlobalExtractSymbol ||= + getGlobalTypeAliasSymbol("Extract" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; return deferredGlobalExtractSymbol === unknownSymbol ? undefined : deferredGlobalExtractSymbol; } function getGlobalOmitSymbol(): Symbol | undefined { // We always report an error, so cache a result in the event we could not resolve the symbol to prevent reporting it multiple times - deferredGlobalOmitSymbol ||= getGlobalTypeAliasSymbol("Omit" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; + deferredGlobalOmitSymbol ||= getGlobalTypeAliasSymbol("Omit" as __String, /*arity*/ 2, /*reportErrors*/ true) + || unknownSymbol; return deferredGlobalOmitSymbol === unknownSymbol ? undefined : deferredGlobalOmitSymbol; } function getGlobalAwaitedSymbol(reportErrors: boolean): Symbol | undefined { // Only cache `unknownSymbol` if we are reporting errors so that we don't report the error more than once. - deferredGlobalAwaitedSymbol ||= getGlobalTypeAliasSymbol("Awaited" as __String, /*arity*/ 1, reportErrors) || (reportErrors ? unknownSymbol : undefined); + deferredGlobalAwaitedSymbol ||= getGlobalTypeAliasSymbol("Awaited" as __String, /*arity*/ 1, reportErrors) + || (reportErrors ? unknownSymbol : undefined); return deferredGlobalAwaitedSymbol === unknownSymbol ? undefined : deferredGlobalAwaitedSymbol; } function getGlobalBigIntType() { - return (deferredGlobalBigIntType ||= getGlobalType("BigInt" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType; + return (deferredGlobalBigIntType ||= getGlobalType("BigInt" as __String, /*arity*/ 0, /*reportErrors*/ false)) + || emptyObjectType; } function getGlobalClassDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassDecoratorContextType ??= getGlobalType("ClassDecoratorContext" as __String, /*arity*/ 1, reportErrors)) ?? emptyGenericType; + return (deferredGlobalClassDecoratorContextType ??= getGlobalType( + "ClassDecoratorContext" as __String, + /*arity*/ 1, + reportErrors, + )) ?? emptyGenericType; } function getGlobalClassMethodDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassMethodDecoratorContextType ??= getGlobalType("ClassMethodDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return (deferredGlobalClassMethodDecoratorContextType ??= getGlobalType( + "ClassMethodDecoratorContext" as __String, + /*arity*/ 2, + reportErrors, + )) ?? emptyGenericType; } function getGlobalClassGetterDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassGetterDecoratorContextType ??= getGlobalType("ClassGetterDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return (deferredGlobalClassGetterDecoratorContextType ??= getGlobalType( + "ClassGetterDecoratorContext" as __String, + /*arity*/ 2, + reportErrors, + )) ?? emptyGenericType; } function getGlobalClassSetterDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassSetterDecoratorContextType ??= getGlobalType("ClassSetterDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return (deferredGlobalClassSetterDecoratorContextType ??= getGlobalType( + "ClassSetterDecoratorContext" as __String, + /*arity*/ 2, + reportErrors, + )) ?? emptyGenericType; } function getGlobalClassAccessorDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassAccessorDecoratorContextType ??= getGlobalType("ClassAccessorDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return (deferredGlobalClassAccessorDecoratorContextType ??= getGlobalType( + "ClassAccessorDecoratorContext" as __String, + /*arity*/ 2, + reportErrors, + )) ?? emptyGenericType; } function getGlobalClassAccessorDecoratorTargetType(reportErrors: boolean) { - return (deferredGlobalClassAccessorDecoratorTargetType ??= getGlobalType("ClassAccessorDecoratorTarget" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return (deferredGlobalClassAccessorDecoratorTargetType ??= getGlobalType( + "ClassAccessorDecoratorTarget" as __String, + /*arity*/ 2, + reportErrors, + )) ?? emptyGenericType; } function getGlobalClassAccessorDecoratorResultType(reportErrors: boolean) { - return (deferredGlobalClassAccessorDecoratorResultType ??= getGlobalType("ClassAccessorDecoratorResult" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return (deferredGlobalClassAccessorDecoratorResultType ??= getGlobalType( + "ClassAccessorDecoratorResult" as __String, + /*arity*/ 2, + reportErrors, + )) ?? emptyGenericType; } function getGlobalClassFieldDecoratorContextType(reportErrors: boolean) { - return (deferredGlobalClassFieldDecoratorContextType ??= getGlobalType("ClassFieldDecoratorContext" as __String, /*arity*/ 2, reportErrors)) ?? emptyGenericType; + return (deferredGlobalClassFieldDecoratorContextType ??= getGlobalType( + "ClassFieldDecoratorContext" as __String, + /*arity*/ 2, + reportErrors, + )) ?? emptyGenericType; } function getGlobalNaNSymbol(): Symbol | undefined { @@ -15954,15 +20475,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getGlobalRecordSymbol(): Symbol | undefined { - deferredGlobalRecordSymbol ||= getGlobalTypeAliasSymbol("Record" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; + deferredGlobalRecordSymbol ||= + getGlobalTypeAliasSymbol("Record" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol; return deferredGlobalRecordSymbol === unknownSymbol ? undefined : deferredGlobalRecordSymbol; } /** * Instantiates a global type that is generic with some element type, and returns that instantiation. */ - function createTypeFromGenericGlobalType(genericGlobalType: GenericType, typeArguments: readonly Type[]): ObjectType { - return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, typeArguments) : emptyObjectType; + function createTypeFromGenericGlobalType( + genericGlobalType: GenericType, + typeArguments: readonly Type[], + ): ObjectType { + return genericGlobalType !== emptyGenericType ? createTypeReference(genericGlobalType, typeArguments) + : emptyObjectType; } function createTypedPropertyDescriptorType(propertyType: Type): Type { @@ -15984,9 +20510,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.RestType: return getRestTypeElementFlags(node as RestTypeNode); case SyntaxKind.NamedTupleMember: - return (node as NamedTupleMember).questionToken ? ElementFlags.Optional : - (node as NamedTupleMember).dotDotDotToken ? getRestTypeElementFlags(node as NamedTupleMember) : - ElementFlags.Required; + return (node as NamedTupleMember).questionToken ? ElementFlags.Optional + : (node as NamedTupleMember).dotDotDotToken ? getRestTypeElementFlags(node as NamedTupleMember) + : ElementFlags.Required; default: return ElementFlags.Required; } @@ -16003,7 +20529,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return readonly ? globalReadonlyArrayType : globalArrayType; } const elementFlags = map((node as TupleTypeNode).elements, getTupleElementFlags); - return getTupleTargetType(elementFlags, readonly, map((node as TupleTypeNode).elements, memberIfLabeledElementDeclaration)); + return getTupleTargetType( + elementFlags, + readonly, + map((node as TupleTypeNode).elements, memberIfLabeledElementDeclaration), + ); } function memberIfLabeledElementDeclaration(member: Node): NamedTupleMember | ParameterDeclaration | undefined { @@ -16012,11 +20542,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return true if the given type reference node is directly aliased or if it needs to be deferred // because it is possibly contained in a circular chain of eagerly resolved types. - function isDeferredTypeReferenceNode(node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, hasDefaultTypeArguments?: boolean) { + function isDeferredTypeReferenceNode( + node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, + hasDefaultTypeArguments?: boolean, + ) { return !!getAliasSymbolForTypeNode(node) || isResolvedByTypeAlias(node) && ( - node.kind === SyntaxKind.ArrayType ? mayResolveTypeAlias(node.elementType) : - node.kind === SyntaxKind.TupleType ? some(node.elements, mayResolveTypeAlias) : - hasDefaultTypeArguments || some(node.typeArguments, mayResolveTypeAlias)); + node.kind === SyntaxKind.ArrayType ? mayResolveTypeAlias(node.elementType) + : node.kind === SyntaxKind.TupleType ? some(node.elements, mayResolveTypeAlias) + : hasDefaultTypeArguments || some(node.typeArguments, mayResolveTypeAlias) + ); } // Return true when the given node is transitively contained in type constructs that eagerly @@ -16047,11 +20581,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function mayResolveTypeAlias(node: Node): boolean { switch (node.kind) { case SyntaxKind.TypeReference: - return isJSDocTypeReference(node) || !!(resolveTypeReferenceName(node as TypeReferenceNode, SymbolFlags.Type).flags & SymbolFlags.TypeAlias); + return isJSDocTypeReference(node) + || !!(resolveTypeReferenceName(node as TypeReferenceNode, SymbolFlags.Type).flags + & SymbolFlags.TypeAlias); case SyntaxKind.TypeQuery: return true; case SyntaxKind.TypeOperator: - return (node as TypeOperatorNode).operator !== SyntaxKind.UniqueKeyword && mayResolveTypeAlias((node as TypeOperatorNode).type); + return (node as TypeOperatorNode).operator !== SyntaxKind.UniqueKeyword + && mayResolveTypeAlias((node as TypeOperatorNode).type); case SyntaxKind.ParenthesizedType: case SyntaxKind.OptionalType: case SyntaxKind.NamedTupleMember: @@ -16059,17 +20596,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocNullableType: case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocTypeExpression: - return mayResolveTypeAlias((node as ParenthesizedTypeNode | OptionalTypeNode | JSDocTypeReferencingNode | NamedTupleMember).type); + return mayResolveTypeAlias( + (node as ParenthesizedTypeNode | OptionalTypeNode | JSDocTypeReferencingNode | NamedTupleMember) + .type, + ); case SyntaxKind.RestType: - return (node as RestTypeNode).type.kind !== SyntaxKind.ArrayType || mayResolveTypeAlias(((node as RestTypeNode).type as ArrayTypeNode).elementType); + return (node as RestTypeNode).type.kind !== SyntaxKind.ArrayType + || mayResolveTypeAlias(((node as RestTypeNode).type as ArrayTypeNode).elementType); case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: return some((node as UnionOrIntersectionTypeNode).types, mayResolveTypeAlias); case SyntaxKind.IndexedAccessType: - return mayResolveTypeAlias((node as IndexedAccessTypeNode).objectType) || mayResolveTypeAlias((node as IndexedAccessTypeNode).indexType); + return mayResolveTypeAlias((node as IndexedAccessTypeNode).objectType) + || mayResolveTypeAlias((node as IndexedAccessTypeNode).indexType); case SyntaxKind.ConditionalType: - return mayResolveTypeAlias((node as ConditionalTypeNode).checkType) || mayResolveTypeAlias((node as ConditionalTypeNode).extendsType) || - mayResolveTypeAlias((node as ConditionalTypeNode).trueType) || mayResolveTypeAlias((node as ConditionalTypeNode).falseType); + return mayResolveTypeAlias((node as ConditionalTypeNode).checkType) + || mayResolveTypeAlias((node as ConditionalTypeNode).extendsType) + || mayResolveTypeAlias((node as ConditionalTypeNode).trueType) + || mayResolveTypeAlias((node as ConditionalTypeNode).falseType); } return false; } @@ -16081,12 +20625,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (target === emptyGenericType) { links.resolvedType = emptyObjectType; } - else if (!(node.kind === SyntaxKind.TupleType && some(node.elements, e => !!(getTupleElementFlags(e) & ElementFlags.Variadic))) && isDeferredTypeReferenceNode(node)) { - links.resolvedType = node.kind === SyntaxKind.TupleType && node.elements.length === 0 ? target : - createDeferredTypeReference(target, node, /*mapper*/ undefined); + else if ( + !(node.kind === SyntaxKind.TupleType + && some(node.elements, e => !!(getTupleElementFlags(e) & ElementFlags.Variadic))) + && isDeferredTypeReferenceNode(node) + ) { + links.resolvedType = node.kind === SyntaxKind.TupleType && node.elements.length === 0 ? target + : createDeferredTypeReference(target, node, /*mapper*/ undefined); } else { - const elementTypes = node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] : map(node.elements, getTypeFromTypeNode); + const elementTypes = node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] + : map(node.elements, getTypeFromTypeNode); links.resolvedType = createNormalizedTypeReference(target, elementTypes); } } @@ -16097,22 +20646,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isTypeOperatorNode(node) && node.operator === SyntaxKind.ReadonlyKeyword; } - function createTupleType(elementTypes: readonly Type[], elementFlags?: readonly ElementFlags[], readonly = false, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[] = []) { - const tupleTarget = getTupleTargetType(elementFlags || map(elementTypes, _ => ElementFlags.Required), readonly, namedMemberDeclarations); - return tupleTarget === emptyGenericType ? emptyObjectType : - elementTypes.length ? createNormalizedTypeReference(tupleTarget, elementTypes) : - tupleTarget; + function createTupleType( + elementTypes: readonly Type[], + elementFlags?: readonly ElementFlags[], + readonly = false, + namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[] = [], + ) { + const tupleTarget = getTupleTargetType( + elementFlags || map(elementTypes, _ => ElementFlags.Required), + readonly, + namedMemberDeclarations, + ); + return tupleTarget === emptyGenericType ? emptyObjectType + : elementTypes.length ? createNormalizedTypeReference(tupleTarget, elementTypes) + : tupleTarget; } - function getTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]): GenericType { + function getTupleTargetType( + elementFlags: readonly ElementFlags[], + readonly: boolean, + namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[], + ): GenericType { if (elementFlags.length === 1 && elementFlags[0] & ElementFlags.Rest) { // [...X[]] is equivalent to just X[] return readonly ? globalReadonlyArrayType : globalArrayType; } const memberIds = mapDefined(namedMemberDeclarations, node => node ? getNodeId(node) : undefined); - const key = map(elementFlags, f => f & ElementFlags.Required ? "#" : f & ElementFlags.Optional ? "?" : f & ElementFlags.Rest ? "." : "*").join() + - (readonly ? "R" : "") + - (memberIds.length ? "," + memberIds.join(",") : ""); + const key = map( + elementFlags, + f => f & ElementFlags.Required ? "#" + : f & ElementFlags.Optional ? "?" : f & ElementFlags.Rest ? "." : "*", + ).join() + + (readonly ? "R" : "") + + (memberIds.length ? "," + memberIds.join(",") : ""); let type = tupleTypes.get(key); if (!type) { tupleTypes.set(key, type = createTupleTargetType(elementFlags, readonly, namedMemberDeclarations)); @@ -16127,7 +20693,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // // Note that the generic type created by this function has no symbol associated with it. The same // is true for each of the synthesized type parameters. - function createTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]): TupleType { + function createTupleTargetType( + elementFlags: readonly ElementFlags[], + readonly: boolean, + namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[], + ): TupleType { const arity = elementFlags.length; const minLength = countWhere(elementFlags, f => !!(f & (ElementFlags.Required | ElementFlags.Variadic))); let typeParameters: TypeParameter[] | undefined; @@ -16140,8 +20710,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const flags = elementFlags[i]; combinedFlags |= flags; if (!(combinedFlags & ElementFlags.Variable)) { - const property = createSymbol(SymbolFlags.Property | (flags & ElementFlags.Optional ? SymbolFlags.Optional : 0), - "" + i as __String, readonly ? CheckFlags.Readonly : 0); + const property = createSymbol( + SymbolFlags.Property | (flags & ElementFlags.Optional ? SymbolFlags.Optional : 0), + "" + i as __String, + readonly ? CheckFlags.Readonly : 0, + ); property.links.tupleLabelDeclaration = namedMemberDeclarations?.[i]; property.links.type = typeParameter; properties.push(property); @@ -16149,7 +20722,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } const fixedLength = properties.length; - const lengthSymbol = createSymbol(SymbolFlags.Property, "length" as __String, readonly ? CheckFlags.Readonly : 0); + const lengthSymbol = createSymbol( + SymbolFlags.Property, + "length" as __String, + readonly ? CheckFlags.Readonly : 0, + ); if (combinedFlags & ElementFlags.Variable) { lengthSymbol.links.type = numberType; } @@ -16159,7 +20736,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { lengthSymbol.links.type = getUnionType(literalTypes); } properties.push(lengthSymbol); - const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference) as TupleType & InterfaceTypeWithDeclaredMembers; + const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference) as + & TupleType + & InterfaceTypeWithDeclaredMembers; type.typeParameters = typeParameters; type.outerTypeParameters = undefined; type.localTypeParameters = typeParameters; @@ -16185,7 +20764,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createNormalizedTypeReference(target: GenericType, typeArguments: readonly Type[] | undefined) { - return target.objectFlags & ObjectFlags.Tuple ? createNormalizedTupleType(target as TupleType, typeArguments!) : createTypeReference(target, typeArguments); + return target.objectFlags & ObjectFlags.Tuple ? createNormalizedTupleType(target as TupleType, typeArguments!) + : createTypeReference(target, typeArguments); } function createNormalizedTupleType(target: TupleType, elementTypes: readonly Type[]): Type { @@ -16195,11 +20775,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (target.combinedFlags & ElementFlags.Variadic) { // Transform [A, ...(X | Y | Z)] into [A, ...X] | [A, ...Y] | [A, ...Z] - const unionIndex = findIndex(elementTypes, (t, i) => !!(target.elementFlags[i] & ElementFlags.Variadic && t.flags & (TypeFlags.Never | TypeFlags.Union))); + const unionIndex = findIndex( + elementTypes, + (t, i) => + !!(target.elementFlags[i] & ElementFlags.Variadic && t.flags & (TypeFlags.Never | TypeFlags.Union)), + ); if (unionIndex >= 0) { - return checkCrossProductUnion(map(elementTypes, (t, i) => target.elementFlags[i] & ElementFlags.Variadic ? t : unknownType)) ? - mapType(elementTypes[unionIndex], t => createNormalizedTupleType(target, replaceElement(elementTypes, unionIndex, t))) : - errorType; + return checkCrossProductUnion( + map(elementTypes, (t, i) => target.elementFlags[i] & ElementFlags.Variadic ? t : unknownType), + ) + ? mapType( + elementTypes[unionIndex], + t => createNormalizedTupleType(target, replaceElement(elementTypes, unionIndex, t)), + ) + : errorType; } } // We have optional, rest, or variadic elements that may need normalizing. Normalization ensures that all variadic @@ -16224,17 +20813,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (isTupleType(type)) { const elements = getElementTypes(type); if (elements.length + expandedTypes.length >= 10_000) { - error(currentNode, isPartOfTypeNode(currentNode!) - ? Diagnostics.Type_produces_a_tuple_type_that_is_too_large_to_represent - : Diagnostics.Expression_produces_a_tuple_type_that_is_too_large_to_represent); + error( + currentNode, + isPartOfTypeNode(currentNode!) + ? Diagnostics.Type_produces_a_tuple_type_that_is_too_large_to_represent + : Diagnostics.Expression_produces_a_tuple_type_that_is_too_large_to_represent, + ); return errorType; } // Spread variadic elements with tuple types into the resulting tuple. - forEach(elements, (t, n) => addElement(t, type.target.elementFlags[n], type.target.labeledElementDeclarations?.[n])); + forEach( + elements, + (t, n) => + addElement(t, type.target.elementFlags[n], type.target.labeledElementDeclarations?.[n]), + ); } else { // Treat everything else as an array type and create a rest element. - addElement(isArrayLikeType(type) && getIndexTypeOfType(type, numberType) || errorType, ElementFlags.Rest, target.labeledElementDeclarations?.[i]); + addElement( + isArrayLikeType(type) && getIndexTypeOfType(type, numberType) || errorType, + ElementFlags.Rest, + target.labeledElementDeclarations?.[i], + ); } } else { @@ -16248,18 +20848,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (firstRestIndex >= 0 && firstRestIndex < lastOptionalOrRestIndex) { // Turn elements between first rest and last optional/rest into a single rest element - expandedTypes[firstRestIndex] = getUnionType(sameMap(expandedTypes.slice(firstRestIndex, lastOptionalOrRestIndex + 1), - (t, i) => expandedFlags[firstRestIndex + i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t)); + expandedTypes[firstRestIndex] = getUnionType( + sameMap( + expandedTypes.slice(firstRestIndex, lastOptionalOrRestIndex + 1), + (t, i) => + expandedFlags[firstRestIndex + i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) + : t, + ), + ); expandedTypes.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); expandedFlags.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); expandedDeclarations.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); } const tupleTarget = getTupleTargetType(expandedFlags, target.readonly, expandedDeclarations); - return tupleTarget === emptyGenericType ? emptyObjectType : - expandedFlags.length ? createTypeReference(tupleTarget, expandedTypes) : - tupleTarget; - - function addElement(type: Type, flags: ElementFlags, declaration: NamedTupleMember | ParameterDeclaration | undefined) { + return tupleTarget === emptyGenericType ? emptyObjectType + : expandedFlags.length ? createTypeReference(tupleTarget, expandedTypes) + : tupleTarget; + + function addElement( + type: Type, + flags: ElementFlags, + declaration: NamedTupleMember | ParameterDeclaration | undefined, + ) { if (flags & ElementFlags.Required) { lastRequiredIndex = expandedFlags.length; } @@ -16278,14 +20888,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function sliceTupleType(type: TupleTypeReference, index: number, endSkipCount = 0) { const target = type.target; const endIndex = getTypeReferenceArity(type) - endSkipCount; - return index > target.fixedLength ? getRestArrayTypeOfTupleType(type) || createTupleType(emptyArray) : - createTupleType(getTypeArguments(type).slice(index, endIndex), target.elementFlags.slice(index, endIndex), - /*readonly*/ false, target.labeledElementDeclarations && target.labeledElementDeclarations.slice(index, endIndex)); + return index > target.fixedLength ? getRestArrayTypeOfTupleType(type) || createTupleType(emptyArray) + : createTupleType( + getTypeArguments(type).slice(index, endIndex), + target.elementFlags.slice(index, endIndex), + /*readonly*/ false, + target.labeledElementDeclarations && target.labeledElementDeclarations.slice(index, endIndex), + ); } function getKnownKeysOfTupleType(type: TupleTypeReference) { - return getUnionType(append(arrayOf(type.target.fixedLength, i => getStringLiteralType("" + i)), - getIndexType(type.target.readonly ? globalReadonlyArrayType : globalArrayType))); + return getUnionType( + append( + arrayOf(type.target.fixedLength, i => getStringLiteralType("" + i)), + getIndexType(type.target.readonly ? globalReadonlyArrayType : globalArrayType), + ), + ); } // Return count of starting consecutive tuple elements of the given kind(s) @@ -16338,11 +20956,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & TypeFlags.Instantiable) includes |= TypeFlags.IncludesInstantiable; if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; if (!strictNullChecks && flags & TypeFlags.Nullable) { - if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) includes |= TypeFlags.IncludesNonWideningType; + if (!(getObjectFlags(type) & ObjectFlags.ContainsWideningType)) { + includes |= TypeFlags.IncludesNonWideningType; + } } else { const len = typeSet.length; - const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues); + const index = len && type.id > typeSet[len - 1].id ? ~len + : binarySearch(typeSet, type, getTypeId, compareValues); if (index < 0) { typeSet.splice(~index, 0, type); } @@ -16360,9 +20981,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // saves a lot of work for large lists of the same union type, such as when resolving `Record[A]`, // where A and B are large union types. if (type !== lastType) { - includes = type.flags & TypeFlags.Union ? - addTypesToUnion(typeSet, includes | (isNamedUnionType(type) ? TypeFlags.Union : 0), (type as UnionType).types) : - addTypeToUnion(typeSet, includes, type); + includes = type.flags & TypeFlags.Union + ? addTypesToUnion( + typeSet, + includes | (isNamedUnionType(type) ? TypeFlags.Union : 0), + (type as UnionType).types, + ) + : addTypeToUnion(typeSet, includes, type); lastType = type; } } @@ -16384,7 +21009,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We assume that redundant primitive types have already been removed from the types array and that there // are no any and unknown types in the array. Thus, the only possible supertypes for primitive types are empty // object types, and if none of those are present we can exclude primitive types from the subtype check. - const hasEmptyObject = hasObjectTypes && some(types, t => !!(t.flags & TypeFlags.Object) && !isGenericMappedType(t) && isEmptyResolvedType(resolveStructuredTypeMembers(t as ObjectType))); + const hasEmptyObject = hasObjectTypes + && some( + types, + t => !!(t.flags & TypeFlags.Object) && !isGenericMappedType(t) + && isEmptyResolvedType(resolveStructuredTypeMembers(t as ObjectType)), + ); const len = types.length; let i = len; let count = 0; @@ -16397,7 +21027,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // a subtype of just `A` or just `B`. When we encounter such a type parameter, we therefore check if the // type parameter is a subtype of a union of all the other types. if (source.flags & TypeFlags.TypeParameter && getBaseConstraintOrType(source).flags & TypeFlags.Union) { - if (isTypeRelatedTo(source, getUnionType(map(types, t => t === source ? neverType : t)), strictSubtypeRelation)) { + if ( + isTypeRelatedTo( + source, + getUnionType(map(types, t => t === source ? neverType : t)), + strictSubtypeRelation, + ) + ) { orderedRemoveItemAt(types, i); } continue; @@ -16405,9 +21041,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Find the first property with a unit type, if any. When constituents have a property by the same name // but of a different unit type, we can quickly disqualify them from subtype checks. This helps subtype // reduction of large discriminated union types. - const keyProperty = source.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive) ? - find(getPropertiesOfType(source), p => isUnitType(getTypeOfSymbol(p))) : - undefined; + const keyProperty = + source.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive) + ? find(getPropertiesOfType(source), p => isUnitType(getTypeOfSymbol(p))) + : undefined; const keyPropertyType = keyProperty && getRegularTypeOfLiteralType(getTypeOfSymbol(keyProperty)); for (const target of types) { if (source !== target) { @@ -16418,22 +21055,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // caps union types at 1000 unique object types. const estimatedCount = (count / (len - i)) * len; if (estimatedCount > 1000000) { - tracing?.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { typeIds: types.map(t => t.id) }); - error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); + tracing?.instant(tracing.Phase.CheckTypes, "removeSubtypes_DepthLimit", { + typeIds: types.map(t => t.id), + }); + error( + currentNode, + Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent, + ); return undefined; } } count++; - if (keyProperty && target.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive)) { + if ( + keyProperty + && target.flags + & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive) + ) { const t = getTypeOfPropertyOfType(target, keyProperty.escapedName); if (t && isUnitType(t) && getRegularTypeOfLiteralType(t) !== keyPropertyType) { continue; } } - if (isTypeRelatedTo(source, target, strictSubtypeRelation) && ( - !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) || - !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) || - isTypeDerivedFrom(source, target))) { + if ( + isTypeRelatedTo(source, target, strictSubtypeRelation) && ( + !(getObjectFlags(getTargetType(source)) & ObjectFlags.Class) + || !(getObjectFlags(getTargetType(target)) & ObjectFlags.Class) + || isTypeDerivedFrom(source, target) + ) + ) { orderedRemoveItemAt(types, i); break; } @@ -16451,13 +21100,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { i--; const t = types[i]; const flags = t.flags; - const remove = - flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && includes & TypeFlags.String || - flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number || - flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt || - flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol || - reduceVoidUndefined && flags & TypeFlags.Undefined && includes & TypeFlags.Void || - isFreshLiteralType(t) && containsType(types, (t as LiteralType).regularType); + const remove = flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + && includes & TypeFlags.String + || flags & TypeFlags.NumberLiteral && includes & TypeFlags.Number + || flags & TypeFlags.BigIntLiteral && includes & TypeFlags.BigInt + || flags & TypeFlags.UniqueESSymbol && includes & TypeFlags.ESSymbol + || reduceVoidUndefined && flags & TypeFlags.Undefined && includes & TypeFlags.Void + || isFreshLiteralType(t) && containsType(types, (t as LiteralType).regularType); if (remove) { orderedRemoveItemAt(types, i); } @@ -16466,16 +21115,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function removeStringLiteralsMatchedByTemplateLiterals(types: Type[]) { const templates = filter(types, t => - !!(t.flags & TypeFlags.TemplateLiteral) && - isPatternLiteralType(t) && - (t as TemplateLiteralType).types.every(t => !(t.flags & TypeFlags.Intersection) || !areIntersectedTypesAvoidingPrimitiveReduction((t as IntersectionType).types)) - ) as TemplateLiteralType[]; + !!(t.flags & TypeFlags.TemplateLiteral) + && isPatternLiteralType(t) + && (t as TemplateLiteralType).types.every(t => + !(t.flags & TypeFlags.Intersection) + || !areIntersectedTypesAvoidingPrimitiveReduction((t as IntersectionType).types) + )) as TemplateLiteralType[]; if (templates.length) { let i = types.length; while (i > 0) { i--; const t = types[i]; - if (t.flags & TypeFlags.StringLiteral && some(templates, template => isTypeMatchedByTemplateLiteralType(t, template))) { + if ( + t.flags & TypeFlags.StringLiteral + && some(templates, template => isTypeMatchedByTemplateLiteralType(t, template)) + ) { orderedRemoveItemAt(types, i); } } @@ -16513,7 +21167,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // expression constructs such as array literals and the || and ?: operators). Named types can // circularly reference themselves and therefore cannot be subtype reduced during their declaration. // For example, "type Item = string | (() => Item" is a named type that circularly references itself. - function getUnionType(types: readonly Type[], unionReduction: UnionReduction = UnionReduction.Literal, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type { + function getUnionType( + types: readonly Type[], + unionReduction: UnionReduction = UnionReduction.Literal, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + origin?: Type, + ): Type { if (types.length === 0) { return neverType; } @@ -16522,7 +21182,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // We optimize for the common case of unioning a union type with some other type (such as `undefined`). if (types.length === 2 && !origin && (types[0].flags & TypeFlags.Union || types[1].flags & TypeFlags.Union)) { - const infix = unionReduction === UnionReduction.None ? "N" : unionReduction === UnionReduction.Subtype ? "S" : "L"; + const infix = unionReduction === UnionReduction.None ? "N" + : unionReduction === UnionReduction.Subtype ? "S" : "L"; const index = types[0].id < types[1].id ? 0 : 1; const id = types[index].id + infix + types[1 - index].id + getAliasId(aliasSymbol, aliasTypeArguments); let type = unionOfUnionTypes.get(id); @@ -16535,14 +21196,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getUnionTypeWorker(types, unionReduction, aliasSymbol, aliasTypeArguments, origin); } - function getUnionTypeWorker(types: readonly Type[], unionReduction: UnionReduction, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined, origin: Type | undefined): Type { + function getUnionTypeWorker( + types: readonly Type[], + unionReduction: UnionReduction, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + origin: Type | undefined, + ): Type { let typeSet: Type[] | undefined = []; const includes = addTypesToUnion(typeSet, 0 as TypeFlags, types); if (unionReduction !== UnionReduction.None) { if (includes & TypeFlags.AnyOrUnknown) { - return includes & TypeFlags.Any ? - includes & TypeFlags.IncludesWildcard ? wildcardType : anyType : - includes & TypeFlags.Null || containsType(typeSet, unknownType) ? unknownType : nonNullUnknownType; + return includes & TypeFlags.Any + ? includes & TypeFlags.IncludesWildcard ? wildcardType : anyType + : includes & TypeFlags.Null || containsType(typeSet, unknownType) ? unknownType + : nonNullUnknownType; } if (includes & TypeFlags.Undefined) { // If type set contains both undefinedType and missingType, remove missingType @@ -16550,7 +21218,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { orderedRemoveItemAt(typeSet, 1); } } - if (includes & (TypeFlags.Enum | TypeFlags.Literal | TypeFlags.UniqueESSymbol | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || includes & TypeFlags.Void && includes & TypeFlags.Undefined) { + if ( + includes + & (TypeFlags.Enum | TypeFlags.Literal | TypeFlags.UniqueESSymbol | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping) || includes & TypeFlags.Void && includes & TypeFlags.Undefined + ) { removeRedundantLiteralTypes(typeSet, includes, !!(unionReduction & UnionReduction.Subtype)); } if (includes & TypeFlags.StringLiteral && includes & TypeFlags.TemplateLiteral) { @@ -16563,9 +21235,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (typeSet.length === 0) { - return includes & TypeFlags.Null ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType : - includes & TypeFlags.Undefined ? includes & TypeFlags.IncludesNonWideningType ? undefinedType : undefinedWideningType : - neverType; + return includes & TypeFlags.Null + ? includes & TypeFlags.IncludesNonWideningType ? nullType : nullWideningType + : includes & TypeFlags.Undefined + ? includes & TypeFlags.IncludesNonWideningType ? undefinedType : undefinedWideningType + : neverType; } } if (!origin && includes & TypeFlags.Union) { @@ -16590,19 +21264,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { origin = createOriginUnionOrIntersectionType(TypeFlags.Union, reducedTypes); } } - const objectFlags = (includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion) | - (includes & TypeFlags.Intersection ? ObjectFlags.ContainsIntersections : 0); + const objectFlags = (includes & TypeFlags.NotPrimitiveUnion ? 0 : ObjectFlags.PrimitiveUnion) + | (includes & TypeFlags.Intersection ? ObjectFlags.ContainsIntersections : 0); return getUnionTypeFromSortedList(typeSet, objectFlags, aliasSymbol, aliasTypeArguments, origin); } - function getUnionOrIntersectionTypePredicate(signatures: readonly Signature[], kind: TypeFlags | undefined): TypePredicate | undefined { + function getUnionOrIntersectionTypePredicate( + signatures: readonly Signature[], + kind: TypeFlags | undefined, + ): TypePredicate | undefined { let last: TypePredicate | undefined; const types: Type[] = []; for (const sig of signatures) { const pred = getTypePredicateOfSignature(sig); if (pred) { // Constituent type predicates must all have matching kinds. We don't create composite type predicates for assertions. - if (pred.kind !== TypePredicateKind.This && pred.kind !== TypePredicateKind.Identifier || last && !typePredicateKindsMatch(last, pred)) { + if ( + pred.kind !== TypePredicateKind.This && pred.kind !== TypePredicateKind.Identifier + || last && !typePredicateKindsMatch(last, pred) + ) { return undefined; } last = pred; @@ -16628,27 +21308,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // This function assumes the constituent type list is sorted and deduplicated. - function getUnionTypeFromSortedList(types: Type[], precomputedObjectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type { + function getUnionTypeFromSortedList( + types: Type[], + precomputedObjectFlags: ObjectFlags, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + origin?: Type, + ): Type { if (types.length === 0) { return neverType; } if (types.length === 1) { return types[0]; } - const typeKey = !origin ? getTypeListId(types) : - origin.flags & TypeFlags.Union ? `|${getTypeListId((origin as UnionType).types)}` : - origin.flags & TypeFlags.Intersection ? `&${getTypeListId((origin as IntersectionType).types)}` : - `#${(origin as IndexType).type.id}|${getTypeListId(types)}`; // origin type id alone is insufficient, as `keyof x` may resolve to multiple WIP values while `x` is still resolving + const typeKey = !origin ? getTypeListId(types) + : origin.flags & TypeFlags.Union ? `|${getTypeListId((origin as UnionType).types)}` + : origin.flags & TypeFlags.Intersection ? `&${getTypeListId((origin as IntersectionType).types)}` + : `#${(origin as IndexType).type.id}|${getTypeListId(types)}`; // origin type id alone is insufficient, as `keyof x` may resolve to multiple WIP values while `x` is still resolving const id = typeKey + getAliasId(aliasSymbol, aliasTypeArguments); let type = unionTypes.get(id); if (!type) { type = createType(TypeFlags.Union) as UnionType; - type.objectFlags = precomputedObjectFlags | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable); + type.objectFlags = precomputedObjectFlags + | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable); type.types = types; type.origin = origin; type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; - if (types.length === 2 && types[0].flags & TypeFlags.BooleanLiteral && types[1].flags & TypeFlags.BooleanLiteral) { + if ( + types.length === 2 && types[0].flags & TypeFlags.BooleanLiteral + && types[1].flags & TypeFlags.BooleanLiteral + ) { type.flags |= TypeFlags.Boolean; (type as UnionType & IntrinsicType).intrinsicName = "boolean"; } @@ -16661,8 +21351,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getNodeLinks(node); if (!links.resolvedType) { const aliasSymbol = getAliasSymbolForTypeNode(node); - links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), UnionReduction.Literal, - aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol)); + links.resolvedType = getUnionType( + map(node.types, getTypeFromTypeNode), + UnionReduction.Literal, + aliasSymbol, + getTypeArgumentsForAliasSymbol(aliasSymbol), + ); } return links.resolvedType; } @@ -16715,13 +21409,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { while (i > 0) { i--; const t = types[i]; - const remove = - t.flags & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || - t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral || - t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || - t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || - t.flags & TypeFlags.Void && includes & TypeFlags.Undefined || - isEmptyAnonymousObjectType(t) && includes & TypeFlags.DefinitelyNonNullable; + const remove = t.flags & TypeFlags.String + && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + || t.flags & TypeFlags.Number && includes & TypeFlags.NumberLiteral + || t.flags & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral + || t.flags & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol + || t.flags & TypeFlags.Void && includes & TypeFlags.Undefined + || isEmptyAnonymousObjectType(t) && includes & TypeFlags.DefinitelyNonNullable; if (remove) { orderedRemoveItemAt(types, i); } @@ -16734,11 +21428,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function eachUnionContains(unionTypes: UnionType[], type: Type) { for (const u of unionTypes) { if (!containsType(u.types, type)) { - const primitive = type.flags & TypeFlags.StringLiteral ? stringType : - type.flags & (TypeFlags.Enum | TypeFlags.NumberLiteral) ? numberType : - type.flags & TypeFlags.BigIntLiteral ? bigintType : - type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : - undefined; + const primitive = type.flags & TypeFlags.StringLiteral ? stringType + : type.flags & (TypeFlags.Enum | TypeFlags.NumberLiteral) ? numberType + : type.flags & TypeFlags.BigIntLiteral ? bigintType + : type.flags & TypeFlags.UniqueESSymbol ? esSymbolType + : undefined; if (!primitive || !containsType(u.types, primitive)) { return false; } @@ -16841,7 +21535,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // a type alias of the form "type List = T & { next: List }" cannot be reduced during its declaration. // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. - function getIntersectionType(types: readonly Type[], aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], noSupertypeReduction?: boolean): Type { + function getIntersectionType( + types: readonly Type[], + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + noSupertypeReduction?: boolean, + ): Type { const typeMembershipMap = new Map(); const includes = addTypesToIntersection(typeMembershipMap, 0 as TypeFlags, types); const typeSet: Type[] = arrayFrom(typeMembershipMap.values()); @@ -16857,30 +21556,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (includes & TypeFlags.Never) { return contains(typeSet, silentNeverType) ? silentNeverType : neverType; } - if (strictNullChecks && includes & TypeFlags.Nullable && includes & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.IncludesEmptyObject) || - includes & TypeFlags.NonPrimitive && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) || - includes & TypeFlags.StringLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) || - includes & TypeFlags.NumberLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) || - includes & TypeFlags.BigIntLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) || - includes & TypeFlags.ESSymbolLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) || - includes & TypeFlags.VoidLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike)) { + if ( + strictNullChecks && includes & TypeFlags.Nullable + && includes & (TypeFlags.Object | TypeFlags.NonPrimitive | TypeFlags.IncludesEmptyObject) + || includes & TypeFlags.NonPrimitive && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NonPrimitive) + || includes & TypeFlags.StringLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.StringLike) + || includes & TypeFlags.NumberLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.NumberLike) + || includes & TypeFlags.BigIntLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.BigIntLike) + || includes & TypeFlags.ESSymbolLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.ESSymbolLike) + || includes & TypeFlags.VoidLike && includes & (TypeFlags.DisjointDomains & ~TypeFlags.VoidLike) + ) { return neverType; } - if (includes & TypeFlags.TemplateLiteral && includes & TypeFlags.StringLiteral && extractRedundantTemplateLiterals(typeSet)) { + if ( + includes & TypeFlags.TemplateLiteral && includes & TypeFlags.StringLiteral + && extractRedundantTemplateLiterals(typeSet) + ) { return neverType; } if (includes & TypeFlags.Any) { return includes & TypeFlags.IncludesWildcard ? wildcardType : anyType; } if (!strictNullChecks && includes & TypeFlags.Nullable) { - return includes & TypeFlags.IncludesEmptyObject ? neverType : includes & TypeFlags.Undefined ? undefinedType : nullType; - } - if (includes & TypeFlags.String && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || - includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral || - includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral || - includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol || - includes & TypeFlags.Void && includes & TypeFlags.Undefined || - includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.DefinitelyNonNullable) { + return includes & TypeFlags.IncludesEmptyObject ? neverType + : includes & TypeFlags.Undefined ? undefinedType : nullType; + } + if ( + includes & TypeFlags.String + && includes & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) + || includes & TypeFlags.Number && includes & TypeFlags.NumberLiteral + || includes & TypeFlags.BigInt && includes & TypeFlags.BigIntLiteral + || includes & TypeFlags.ESSymbol && includes & TypeFlags.UniqueESSymbol + || includes & TypeFlags.Void && includes & TypeFlags.Undefined + || includes & TypeFlags.IncludesEmptyObject && includes & TypeFlags.DefinitelyNonNullable + ) { if (!noSupertypeReduction) removeRedundantSupertypes(typeSet, includes); } if (includes & TypeFlags.IncludesMissingType) { @@ -16902,14 +21611,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // reduced we'll never reduce again, so this occurs at most once. result = getIntersectionType(typeSet, aliasSymbol, aliasTypeArguments); } - else if (every(typeSet, t => !!(t.flags & TypeFlags.Union && (t as UnionType).types[0].flags & TypeFlags.Undefined))) { + else if ( + every( + typeSet, + t => !!(t.flags & TypeFlags.Union && (t as UnionType).types[0].flags & TypeFlags.Undefined), + ) + ) { const containedUndefinedType = some(typeSet, containsMissingType) ? missingType : undefinedType; removeFromEach(typeSet, TypeFlags.Undefined); - result = getUnionType([getIntersectionType(typeSet), containedUndefinedType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments); + result = getUnionType( + [getIntersectionType(typeSet), containedUndefinedType], + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + ); } - else if (every(typeSet, t => !!(t.flags & TypeFlags.Union && ((t as UnionType).types[0].flags & TypeFlags.Null || (t as UnionType).types[1].flags & TypeFlags.Null)))) { + else if ( + every(typeSet, t => + !!(t.flags & TypeFlags.Union + && ((t as UnionType).types[0].flags & TypeFlags.Null + || (t as UnionType).types[1].flags & TypeFlags.Null))) + ) { removeFromEach(typeSet, TypeFlags.Null); - result = getUnionType([getIntersectionType(typeSet), nullType], UnionReduction.Literal, aliasSymbol, aliasTypeArguments); + result = getUnionType( + [getIntersectionType(typeSet), nullType], + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + ); } else { // We are attempting to construct a type of the form X & (A | B) & (C | D). Transform this into a type of @@ -16922,8 +21651,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We attach a denormalized origin type when at least one constituent of the cross-product union is an // intersection (i.e. when the intersection didn't just reduce one or more unions to smaller unions) and // the denormalized origin has fewer constituents than the union itself. - const origin = some(constituents, t => !!(t.flags & TypeFlags.Intersection)) && getConstituentCountOfTypes(constituents) > getConstituentCountOfTypes(typeSet) ? createOriginUnionOrIntersectionType(TypeFlags.Intersection, typeSet) : undefined; - result = getUnionType(constituents, UnionReduction.Literal, aliasSymbol, aliasTypeArguments, origin); + const origin = some(constituents, t => !!(t.flags & TypeFlags.Intersection)) + && getConstituentCountOfTypes(constituents) > getConstituentCountOfTypes(typeSet) + ? createOriginUnionOrIntersectionType(TypeFlags.Intersection, typeSet) : undefined; + result = getUnionType( + constituents, + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + origin, + ); } } else { @@ -16935,13 +21672,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getCrossProductUnionSize(types: readonly Type[]) { - return reduceLeft(types, (n, t) => t.flags & TypeFlags.Union ? n * (t as UnionType).types.length : t.flags & TypeFlags.Never ? 0 : n, 1); + return reduceLeft( + types, + (n, t) => t.flags & TypeFlags.Union ? n * (t as UnionType).types.length : t.flags & TypeFlags.Never ? 0 : n, + 1, + ); } function checkCrossProductUnion(types: readonly Type[]) { const size = getCrossProductUnionSize(types); if (size >= 100000) { - tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { typeIds: types.map(t => t.id), size }); + tracing?.instant(tracing.Phase.CheckTypes, "checkCrossProductUnion_DepthLimit", { + typeIds: types.map(t => t.id), + size, + }); error(currentNode, Diagnostics.Expression_produces_a_union_type_that_is_too_complex_to_represent); return false; } @@ -16969,21 +21713,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getConstituentCount(type: Type): number { - return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol ? 1 : - type.flags & TypeFlags.Union && (type as UnionType).origin ? getConstituentCount((type as UnionType).origin!) : - getConstituentCountOfTypes((type as UnionOrIntersectionType).types); + return !(type.flags & TypeFlags.UnionOrIntersection) || type.aliasSymbol ? 1 + : type.flags & TypeFlags.Union && (type as UnionType).origin + ? getConstituentCount((type as UnionType).origin!) + : getConstituentCountOfTypes((type as UnionOrIntersectionType).types); } function getConstituentCountOfTypes(types: Type[]): number { return reduceLeft(types, (n, t) => n + getConstituentCount(t), 0); } - function areIntersectedTypesAvoidingPrimitiveReduction(types: Type[], primitiveFlags = TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt): boolean { + function areIntersectedTypesAvoidingPrimitiveReduction( + types: Type[], + primitiveFlags = TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt, + ): boolean { if (types.length !== 2) { return false; } const [t1, t2] = types; - return !!(t1.flags & primitiveFlags) && t2 === emptyTypeLiteralType || !!(t2.flags & primitiveFlags) && t1 === emptyTypeLiteralType; + return !!(t1.flags & primitiveFlags) && t2 === emptyTypeLiteralType + || !!(t2.flags & primitiveFlags) && t1 === emptyTypeLiteralType; } function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type { @@ -16992,7 +21741,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const aliasSymbol = getAliasSymbolForTypeNode(node); const types = map(node.types, getTypeFromTypeNode); const noSupertypeReduction = areIntersectedTypesAvoidingPrimitiveReduction(types); - links.resolvedType = getIntersectionType(types, aliasSymbol, getTypeArgumentsForAliasSymbol(aliasSymbol), noSupertypeReduction); + links.resolvedType = getIntersectionType( + types, + aliasSymbol, + getTypeArgumentsForAliasSymbol(aliasSymbol), + noSupertypeReduction, + ); } return links.resolvedType; } @@ -17011,9 +21765,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType, indexFlags: IndexFlags) { - return indexFlags & IndexFlags.StringsOnly ? - type.resolvedStringIndexType || (type.resolvedStringIndexType = createIndexType(type, IndexFlags.StringsOnly)) : - type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, IndexFlags.None)); + return indexFlags & IndexFlags.StringsOnly + ? type.resolvedStringIndexType + || (type.resolvedStringIndexType = createIndexType(type, IndexFlags.StringsOnly)) + : type.resolvedIndexType || (type.resolvedIndexType = createIndexType(type, IndexFlags.None)); } /** @@ -17040,7 +21795,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // so we only eagerly manifest the keys if the constraint is nongeneric if (!isGenericIndexType(constraintType)) { const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' - forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(modifiersType, TypeFlags.StringOrNumberLiteralOrUnique, !!(indexFlags & IndexFlags.StringsOnly), addMemberForKeyType); + forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType( + modifiersType, + TypeFlags.StringOrNumberLiteralOrUnique, + !!(indexFlags & IndexFlags.StringsOnly), + addMemberForKeyType, + ); } else { // we have a generic index and a homomorphic mapping (but a distributive key remapping) - we need to defer the whole `keyof whatever` for later @@ -17056,14 +21816,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // we had to pick apart the constraintType to potentially map/filter it - compare the final resulting list with the original constraintType, // so we can return the union that preserves aliases/origin data if possible - const result = indexFlags & IndexFlags.NoIndexSignatures ? filterType(getUnionType(keyTypes), t => !(t.flags & (TypeFlags.Any | TypeFlags.String))) : getUnionType(keyTypes); - if (result.flags & TypeFlags.Union && constraintType.flags & TypeFlags.Union && getTypeListId((result as UnionType).types) === getTypeListId((constraintType as UnionType).types)){ + const result = indexFlags & IndexFlags.NoIndexSignatures + ? filterType(getUnionType(keyTypes), t => !(t.flags & (TypeFlags.Any | TypeFlags.String))) + : getUnionType(keyTypes); + if ( + result.flags & TypeFlags.Union && constraintType.flags & TypeFlags.Union + && getTypeListId((result as UnionType).types) === getTypeListId((constraintType as UnionType).types) + ) { return constraintType; } return result; function addMemberForKeyType(keyType: Type) { - const propNameType = nameType ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; + const propNameType = nameType + ? instantiateType(nameType, appendTypeMapping(type.mapper, typeParameter, keyType)) : keyType; // `keyof` currently always returns `string | number` for concrete `string` index signatures - the below ternary keeps that behavior for mapped types // See `getLiteralTypeFromProperties` where there's a similar ternary to cause the same behavior. keyTypes.push(propNameType === stringType ? stringOrNumberType : propNameType); @@ -17079,13 +21845,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeVariable = getTypeParameterFromMappedType(mappedType); return isDistributive(getNameTypeFromMappedType(mappedType) || typeVariable); function isDistributive(type: Type): boolean { - return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.NonPrimitive) ? true : - type.flags & TypeFlags.Conditional ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable : - type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) : - type.flags & TypeFlags.IndexedAccess ? isDistributive((type as IndexedAccessType).objectType) && isDistributive((type as IndexedAccessType).indexType) : - type.flags & TypeFlags.Substitution ? isDistributive((type as SubstitutionType).baseType) && isDistributive((type as SubstitutionType).constraint): - type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) : - false; + return type.flags + & (TypeFlags.AnyOrUnknown | TypeFlags.Primitive | TypeFlags.Never | TypeFlags.TypeParameter + | TypeFlags.Object | TypeFlags.NonPrimitive) ? true + : type.flags & TypeFlags.Conditional + ? (type as ConditionalType).root.isDistributive && (type as ConditionalType).checkType === typeVariable + : type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) + ? every((type as UnionOrIntersectionType | TemplateLiteralType).types, isDistributive) + : type.flags & TypeFlags.IndexedAccess + ? isDistributive((type as IndexedAccessType).objectType) + && isDistributive((type as IndexedAccessType).indexType) + : type.flags & TypeFlags.Substitution + ? isDistributive((type as SubstitutionType).baseType) + && isDistributive((type as SubstitutionType).constraint) + : type.flags & TypeFlags.StringMapping ? isDistributive((type as StringMappingType).type) + : false; } } @@ -17110,12 +21884,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags, includeNonPublic?: boolean) { - if (includeNonPublic || !(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) { + if ( + includeNonPublic + || !(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier) + ) { let type = getSymbolLinks(getLateBoundSymbol(prop)).nameType; if (!type) { const name = getNameOfDeclaration(prop.valueDeclaration) as PropertyName | JsxAttributeName; - type = prop.escapedName === InternalSymbolName.Default ? getStringLiteralType("default") : - name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getStringLiteralType(symbolName(prop)) : undefined); + type = prop.escapedName === InternalSymbolName.Default ? getStringLiteralType("default") + : name && getLiteralTypeFromPropertyName(name) + || (!isKnownSymbol(prop) ? getStringLiteralType(symbolName(prop)) : undefined); } if (type && type.flags & include) { return type; @@ -17125,37 +21903,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isKeyTypeIncluded(keyType: Type, include: TypeFlags): boolean { - return !!(keyType.flags & include || keyType.flags & TypeFlags.Intersection && some((keyType as IntersectionType).types, t => isKeyTypeIncluded(t, include))); + return !!(keyType.flags & include + || keyType.flags & TypeFlags.Intersection + && some((keyType as IntersectionType).types, t => isKeyTypeIncluded(t, include))); } function getLiteralTypeFromProperties(type: Type, include: TypeFlags, includeOrigin: boolean) { - const origin = includeOrigin && (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) || type.aliasSymbol) ? createOriginIndexType(type) : undefined; + const origin = includeOrigin + && (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference) || type.aliasSymbol) + ? createOriginIndexType(type) : undefined; const propertyTypes = map(getPropertiesOfType(type), prop => getLiteralTypeFromProperty(prop, include)); - const indexKeyTypes = map(getIndexInfosOfType(type), info => info !== enumNumberIndexInfo && isKeyTypeIncluded(info.keyType, include) ? - info.keyType === stringType && include & TypeFlags.Number ? stringOrNumberType : info.keyType : neverType); - return getUnionType(concatenate(propertyTypes, indexKeyTypes), UnionReduction.Literal, - /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, origin); + const indexKeyTypes = map( + getIndexInfosOfType(type), + info => + info !== enumNumberIndexInfo && isKeyTypeIncluded(info.keyType, include) + ? info.keyType === stringType && include & TypeFlags.Number ? stringOrNumberType : info.keyType + : neverType, + ); + return getUnionType( + concatenate(propertyTypes, indexKeyTypes), + UnionReduction.Literal, + /*aliasSymbol*/ undefined, + /*aliasTypeArguments*/ undefined, + origin, + ); } function shouldDeferIndexType(type: Type, indexFlags = IndexFlags.None) { - return !!(type.flags & TypeFlags.InstantiableNonPrimitive || - isGenericTupleType(type) || - isGenericMappedType(type) && !hasDistributiveNameType(type) || - type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) && isGenericReducibleType(type) || - type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) && some((type as IntersectionType).types, isEmptyAnonymousObjectType)); + return !!(type.flags & TypeFlags.InstantiableNonPrimitive + || isGenericTupleType(type) + || isGenericMappedType(type) && !hasDistributiveNameType(type) + || type.flags & TypeFlags.Union && !(indexFlags & IndexFlags.NoReducibleCheck) + && isGenericReducibleType(type) + || type.flags & TypeFlags.Intersection && maybeTypeOfKind(type, TypeFlags.Instantiable) + && some((type as IntersectionType).types, isEmptyAnonymousObjectType)); } function getIndexType(type: Type, indexFlags = defaultIndexFlags): Type { type = getReducedType(type); - return shouldDeferIndexType(type, indexFlags) ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) : - type.flags & TypeFlags.Union ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, indexFlags))) : - type.flags & TypeFlags.Intersection ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, indexFlags))) : - getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, indexFlags) : - type === wildcardType ? wildcardType : - type.flags & TypeFlags.Unknown ? neverType : - type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType : - getLiteralTypeFromProperties(type, (indexFlags & IndexFlags.NoIndexSignatures ? TypeFlags.StringLiteral : TypeFlags.StringLike) | (indexFlags & IndexFlags.StringsOnly ? 0 : TypeFlags.NumberLike | TypeFlags.ESSymbolLike), - indexFlags === defaultIndexFlags); + return shouldDeferIndexType(type, indexFlags) + ? getIndexTypeForGenericType(type as InstantiableType | UnionOrIntersectionType, indexFlags) + : type.flags & TypeFlags.Union + ? getIntersectionType(map((type as UnionType).types, t => getIndexType(t, indexFlags))) + : type.flags & TypeFlags.Intersection + ? getUnionType(map((type as IntersectionType).types, t => getIndexType(t, indexFlags))) + : getObjectFlags(type) & ObjectFlags.Mapped ? getIndexTypeForMappedType(type as MappedType, indexFlags) + : type === wildcardType ? wildcardType + : type.flags & TypeFlags.Unknown ? neverType + : type.flags & (TypeFlags.Any | TypeFlags.Never) ? keyofConstraintType + : getLiteralTypeFromProperties( + type, + (indexFlags & IndexFlags.NoIndexSignatures ? TypeFlags.StringLiteral : TypeFlags.StringLike) + | (indexFlags & IndexFlags.StringsOnly ? 0 : TypeFlags.NumberLike | TypeFlags.ESSymbolLike), + indexFlags === defaultIndexFlags, + ); } function getExtractStringType(type: Type) { @@ -17198,7 +21999,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.resolvedType) { links.resolvedType = getTemplateLiteralType( [node.head.text, ...map(node.templateSpans, span => span.literal.text)], - map(node.templateSpans, span => getTypeFromTypeNode(span.type))); + map(node.templateSpans, span => getTypeFromTypeNode(span.type)), + ); } return links.resolvedType; } @@ -17206,9 +22008,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTemplateLiteralType(texts: readonly string[], types: readonly Type[]): Type { const unionIndex = findIndex(types, t => !!(t.flags & (TypeFlags.Never | TypeFlags.Union))); if (unionIndex >= 0) { - return checkCrossProductUnion(types) ? - mapType(types[unionIndex], t => getTemplateLiteralType(texts, replaceElement(types, unionIndex, t))) : - errorType; + return checkCrossProductUnion(types) + ? mapType(types[unionIndex], t => getTemplateLiteralType(texts, replaceElement(types, unionIndex, t))) + : errorType; } if (contains(types, wildcardType)) { return wildcardType; @@ -17265,11 +22067,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTemplateStringForType(type: Type) { - return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value : - type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value : - type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type as BigIntLiteralType).value) : - type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) ? (type as IntrinsicType).intrinsicName : - undefined; + return type.flags & TypeFlags.StringLiteral ? (type as StringLiteralType).value + : type.flags & TypeFlags.NumberLiteral ? "" + (type as NumberLiteralType).value + : type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type as BigIntLiteralType).value) + : type.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) ? (type as IntrinsicType).intrinsicName + : undefined; } function createTemplateLiteralType(texts: readonly string[], types: readonly Type[]) { @@ -17281,33 +22083,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getStringMappingType(symbol: Symbol, type: Type): Type { - return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) : - type.flags & TypeFlags.StringLiteral ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) : - type.flags & TypeFlags.TemplateLiteral ? getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)) : + return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) + : type.flags & TypeFlags.StringLiteral + ? getStringLiteralType(applyStringMapping(symbol, (type as StringLiteralType).value)) + : type.flags & TypeFlags.TemplateLiteral + ? getTemplateLiteralType( + ...applyTemplateStringMapping( + symbol, + (type as TemplateLiteralType).texts, + (type as TemplateLiteralType).types, + ), + ) // Mapping> === Mapping - type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type : - type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.StringMapping) || isGenericIndexType(type) ? getStringMappingTypeForGenericType(symbol, type) : + : type.flags & TypeFlags.StringMapping && symbol === type.symbol ? type + : type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.StringMapping) || isGenericIndexType(type) + ? getStringMappingTypeForGenericType(symbol, type) // This handles Mapping<`${number}`> and Mapping<`${bigint}`> - isPatternLiteralPlaceholderType(type) ? getStringMappingTypeForGenericType(symbol, getTemplateLiteralType(["", ""], [type])) : - type; + : isPatternLiteralPlaceholderType(type) + ? getStringMappingTypeForGenericType(symbol, getTemplateLiteralType(["", ""], [type])) + : type; } function applyStringMapping(symbol: Symbol, str: string) { switch (intrinsicTypeKinds.get(symbol.escapedName as string)) { - case IntrinsicTypeKind.Uppercase: return str.toUpperCase(); - case IntrinsicTypeKind.Lowercase: return str.toLowerCase(); - case IntrinsicTypeKind.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1); - case IntrinsicTypeKind.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1); + case IntrinsicTypeKind.Uppercase: + return str.toUpperCase(); + case IntrinsicTypeKind.Lowercase: + return str.toLowerCase(); + case IntrinsicTypeKind.Capitalize: + return str.charAt(0).toUpperCase() + str.slice(1); + case IntrinsicTypeKind.Uncapitalize: + return str.charAt(0).toLowerCase() + str.slice(1); } return str; } - function applyTemplateStringMapping(symbol: Symbol, texts: readonly string[], types: readonly Type[]): [texts: readonly string[], types: readonly Type[]] { + function applyTemplateStringMapping( + symbol: Symbol, + texts: readonly string[], + types: readonly Type[], + ): [texts: readonly string[], types: readonly Type[]] { switch (intrinsicTypeKinds.get(symbol.escapedName as string)) { - case IntrinsicTypeKind.Uppercase: return [texts.map(t => t.toUpperCase()), types.map(t => getStringMappingType(symbol, t))]; - case IntrinsicTypeKind.Lowercase: return [texts.map(t => t.toLowerCase()), types.map(t => getStringMappingType(symbol, t))]; - case IntrinsicTypeKind.Capitalize: return [texts[0] === "" ? texts : [texts[0].charAt(0).toUpperCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types]; - case IntrinsicTypeKind.Uncapitalize: return [texts[0] === "" ? texts : [texts[0].charAt(0).toLowerCase() + texts[0].slice(1), ...texts.slice(1)], texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types]; + case IntrinsicTypeKind.Uppercase: + return [texts.map(t => t.toUpperCase()), types.map(t => getStringMappingType(symbol, t))]; + case IntrinsicTypeKind.Lowercase: + return [texts.map(t => t.toLowerCase()), types.map(t => getStringMappingType(symbol, t))]; + case IntrinsicTypeKind.Capitalize: + return [ + texts[0] === "" ? texts : [texts[0].charAt(0).toUpperCase() + texts[0].slice(1), ...texts.slice(1)], + texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types, + ]; + case IntrinsicTypeKind.Uncapitalize: + return [ + texts[0] === "" ? texts : [texts[0].charAt(0).toLowerCase() + texts[0].slice(1), ...texts.slice(1)], + texts[0] === "" ? [getStringMappingType(symbol, types[0]), ...types.slice(1)] : types, + ]; } return [texts, types]; } @@ -17327,7 +22157,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function createIndexedAccessType(objectType: Type, indexType: Type, accessFlags: AccessFlags, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { + function createIndexedAccessType( + objectType: Type, + indexType: Type, + accessFlags: AccessFlags, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + ) { const type = createType(TypeFlags.IndexedAccess) as IndexedAccessType; type.objectType = objectType; type.indexType = indexType; @@ -17366,13 +22202,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function getPropertyNameFromIndex(indexType: Type, accessNode: StringLiteral | Identifier | PrivateIdentifier | ObjectBindingPattern | ArrayBindingPattern | ComputedPropertyName | NumericLiteral | IndexedAccessTypeNode | ElementAccessExpression | SyntheticExpression | undefined) { - return isTypeUsableAsPropertyName(indexType) ? - getPropertyNameFromType(indexType) : - accessNode && isPropertyName(accessNode) ? - // late bound names are handled in the first branch, so here we only need to handle normal names - getPropertyNameForPropertyNameNode(accessNode) : - undefined; + function getPropertyNameFromIndex( + indexType: Type, + accessNode: + | StringLiteral + | Identifier + | PrivateIdentifier + | ObjectBindingPattern + | ArrayBindingPattern + | ComputedPropertyName + | NumericLiteral + | IndexedAccessTypeNode + | ElementAccessExpression + | SyntheticExpression + | undefined, + ) { + return isTypeUsableAsPropertyName(indexType) + ? getPropertyNameFromType(indexType) + : accessNode && isPropertyName(accessNode) + // late bound names are handled in the first branch, so here we only need to handle normal names + ? getPropertyNameForPropertyNameNode(accessNode) + : undefined; } function isUncalledFunctionReference(node: Node, symbol: Symbol) { @@ -17386,9 +22236,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) { - const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined; - const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined : getPropertyNameFromIndex(indexType, accessNode); + function getPropertyTypeForIndexType( + originalObjectType: Type, + objectType: Type, + indexType: Type, + fullIndexType: Type, + accessNode: + | ElementAccessExpression + | IndexedAccessTypeNode + | PropertyName + | BindingName + | SyntheticExpression + | undefined, + accessFlags: AccessFlags, + ) { + const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode + : undefined; + const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined + : getPropertyNameFromIndex(indexType, accessNode); if (propName !== undefined) { if (accessFlags & AccessFlags.Contextual) { @@ -17396,14 +22261,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const prop = getPropertyOfType(objectType, propName); if (prop) { - if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && isDeprecatedSymbol(prop) && isUncalledFunctionReference(accessNode, prop)) { - const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); + if ( + accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations + && isDeprecatedSymbol(prop) && isUncalledFunctionReference(accessNode, prop) + ) { + const deprecatedNode = accessExpression?.argumentExpression + ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string); } if (accessExpression) { - markPropertyAsReferenced(prop, accessExpression, isSelfTypeAccess(accessExpression.expression, objectType.symbol)); - if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) { - error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop)); + markPropertyAsReferenced( + prop, + accessExpression, + isSelfTypeAccess(accessExpression.expression, objectType.symbol), + ); + if ( + isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression)) + ) { + error( + accessExpression.argumentExpression, + Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, + symbolToString(prop), + ); return undefined; } if (accessFlags & AccessFlags.CacheSymbol) { @@ -17414,61 +22293,95 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } const propType = getTypeOfSymbol(prop); - return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite ? getFlowTypeOfReference(accessExpression, propType) : - accessNode && isIndexedAccessTypeNode(accessNode) && containsMissingType(propType) ? getUnionType([propType, undefinedType]) : - propType; + return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite + ? getFlowTypeOfReference(accessExpression, propType) + : accessNode && isIndexedAccessTypeNode(accessNode) && containsMissingType(propType) + ? getUnionType([propType, undefinedType]) + : propType; } if (everyType(objectType, isTupleType) && isNumericLiteralName(propName)) { const index = +propName; - if (accessNode && everyType(objectType, t => !(t as TupleTypeReference).target.hasRestElement) && !(accessFlags & AccessFlags.NoTupleBoundsCheck)) { + if ( + accessNode && everyType(objectType, t => !(t as TupleTypeReference).target.hasRestElement) + && !(accessFlags & AccessFlags.NoTupleBoundsCheck) + ) { const indexNode = getIndexNodeForAccessExpression(accessNode); if (isTupleType(objectType)) { if (index < 0) { error(indexNode, Diagnostics.A_tuple_type_cannot_be_indexed_with_a_negative_value); return undefinedType; } - error(indexNode, Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2, - typeToString(objectType), getTypeReferenceArity(objectType), unescapeLeadingUnderscores(propName)); + error( + indexNode, + Diagnostics.Tuple_type_0_of_length_1_has_no_element_at_index_2, + typeToString(objectType), + getTypeReferenceArity(objectType), + unescapeLeadingUnderscores(propName), + ); } else { - error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); + error( + indexNode, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(propName), + typeToString(objectType), + ); } } if (index >= 0) { errorIfWritingToReadonlyIndex(getIndexInfoOfType(objectType, numberType)); - return getTupleElementTypeOutOfStartCount(objectType, index, accessFlags & AccessFlags.IncludeUndefined ? missingType : undefined); + return getTupleElementTypeOutOfStartCount( + objectType, + index, + accessFlags & AccessFlags.IncludeUndefined ? missingType : undefined, + ); } } } - if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) { + if ( + !(indexType.flags & TypeFlags.Nullable) + && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) + ) { if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) { return objectType; } // If no index signature is applicable, we default to the string index signature. In effect, this means the string // index signature applies even when accessing with a symbol-like type. - const indexInfo = getApplicableIndexInfo(objectType, indexType) || getIndexInfoOfType(objectType, stringType); + const indexInfo = getApplicableIndexInfo(objectType, indexType) + || getIndexInfoOfType(objectType, stringType); if (indexInfo) { if (accessFlags & AccessFlags.NoIndexSignatures && indexInfo.keyType !== numberType) { if (accessExpression) { - error(accessExpression, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(originalObjectType)); + error( + accessExpression, + Diagnostics.Type_0_cannot_be_used_to_index_type_1, + typeToString(indexType), + typeToString(originalObjectType), + ); } return undefined; } - if (accessNode && indexInfo.keyType === stringType && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) { + if ( + accessNode && indexInfo.keyType === stringType + && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number) + ) { const indexNode = getIndexNodeForAccessExpression(accessNode); error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); - return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, missingType]) : indexInfo.type; + return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, missingType]) + : indexInfo.type; } errorIfWritingToReadonlyIndex(indexInfo); // When accessing an enum object with its own type, // e.g. E[E.A] for enum E { A }, undefined shouldn't // be included in the result type - if ((accessFlags & AccessFlags.IncludeUndefined) && - !(objectType.symbol && - objectType.symbol.flags & (SymbolFlags.RegularEnum | SymbolFlags.ConstEnum) && - (indexType.symbol && - indexType.flags & TypeFlags.EnumLiteral && - getParentOfSymbol(indexType.symbol) === objectType.symbol))) { + if ( + (accessFlags & AccessFlags.IncludeUndefined) + && !(objectType.symbol + && objectType.symbol.flags & (SymbolFlags.RegularEnum | SymbolFlags.ConstEnum) + && (indexType.symbol + && indexType.flags & TypeFlags.EnumLiteral + && getParentOfSymbol(indexType.symbol) === objectType.symbol)) + ) { return getUnionType([indexInfo.type, missingType]); } return indexInfo.type; @@ -17482,7 +22395,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (accessExpression && !isConstEnumObjectType(objectType)) { if (isObjectLiteralType(objectType)) { if (noImplicitAny && indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { - diagnostics.add(createDiagnosticForNode(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType))); + diagnostics.add( + createDiagnosticForNode( + accessExpression, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as StringLiteralType).value, + typeToString(objectType), + ), + ); return undefinedType; } else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { @@ -17493,53 +22413,132 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) { - error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType)); + if ( + objectType.symbol === globalThisSymbol && propName !== undefined + && globalThisSymbol.exports!.has(propName) + && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped) + ) { + error( + accessExpression, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(propName), + typeToString(objectType), + ); } - else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !(accessFlags & AccessFlags.SuppressNoImplicitAnyError)) { + else if ( + noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors + && !(accessFlags & AccessFlags.SuppressNoImplicitAnyError) + ) { if (propName !== undefined && typeHasStaticProperty(propName, objectType)) { const typeName = typeToString(objectType); - error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName as string, typeName, typeName + "[" + getTextOfNode(accessExpression.argumentExpression) + "]"); + error( + accessExpression, + Diagnostics + .Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, + propName as string, + typeName, + typeName + "[" + getTextOfNode(accessExpression.argumentExpression) + "]", + ); } else if (getIndexTypeOfType(objectType, numberType)) { - error(accessExpression.argumentExpression, Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number); + error( + accessExpression.argumentExpression, + Diagnostics + .Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number, + ); } else { let suggestion: string | undefined; - if (propName !== undefined && (suggestion = getSuggestionForNonexistentProperty(propName as string, objectType))) { + if ( + propName !== undefined + && (suggestion = getSuggestionForNonexistentProperty(propName as string, objectType)) + ) { if (suggestion !== undefined) { - error(accessExpression.argumentExpression, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName as string, typeToString(objectType), suggestion); + error( + accessExpression.argumentExpression, + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, + propName as string, + typeToString(objectType), + suggestion, + ); } } else { - const suggestion = getSuggestionForNonexistentIndexSignature(objectType, accessExpression, indexType); + const suggestion = getSuggestionForNonexistentIndexSignature( + objectType, + accessExpression, + indexType, + ); if (suggestion !== undefined) { - error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, typeToString(objectType), suggestion); + error( + accessExpression, + Diagnostics + .Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, + typeToString(objectType), + suggestion, + ); } else { let errorInfo: DiagnosticMessageChain | undefined; if (indexType.flags & TypeFlags.EnumLiteral) { - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + typeToString(indexType) + "]", typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + "[" + typeToString(indexType) + "]", + typeToString(objectType), + ); } else if (indexType.flags & TypeFlags.UniqueESSymbol) { - const symbolName = getFullyQualifiedName((indexType as UniqueESSymbolType).symbol, accessExpression); - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, "[" + symbolName + "]", typeToString(objectType)); + const symbolName = getFullyQualifiedName( + (indexType as UniqueESSymbolType).symbol, + accessExpression, + ); + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + "[" + symbolName + "]", + typeToString(objectType), + ); } else if (indexType.flags & TypeFlags.StringLiteral) { - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as StringLiteralType).value, typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as StringLiteralType).value, + typeToString(objectType), + ); } else if (indexType.flags & TypeFlags.NumberLiteral) { - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Property_0_does_not_exist_on_type_1, (indexType as NumberLiteralType).value, typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_does_not_exist_on_type_1, + (indexType as NumberLiteralType).value, + typeToString(objectType), + ); } else if (indexType.flags & (TypeFlags.Number | TypeFlags.String)) { - errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, typeToString(indexType), typeToString(objectType)); + errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.No_index_signature_with_a_parameter_of_type_0_was_found_on_type_1, + typeToString(indexType), + typeToString(objectType), + ); } errorInfo = chainDiagnosticMessages( errorInfo, - Diagnostics.Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1, typeToString(fullIndexType), typeToString(objectType) + Diagnostics + .Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1, + typeToString(fullIndexType), + typeToString(objectType), + ); + diagnostics.add( + createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(accessExpression), + accessExpression, + errorInfo, + ), ); - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(accessExpression), accessExpression, errorInfo)); } } } @@ -17553,10 +22552,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (accessNode) { const indexNode = getIndexNodeForAccessExpression(accessNode); if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) { - error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, "" + (indexType as StringLiteralType | NumberLiteralType).value, typeToString(objectType)); + error( + indexNode, + Diagnostics.Property_0_does_not_exist_on_type_1, + "" + (indexType as StringLiteralType | NumberLiteralType).value, + typeToString(objectType), + ); } else if (indexType.flags & (TypeFlags.String | TypeFlags.Number)) { - error(indexNode, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(indexType)); + error( + indexNode, + Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, + typeToString(objectType), + typeToString(indexType), + ); } else { error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); @@ -17568,29 +22577,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; function errorIfWritingToReadonlyIndex(indexInfo: IndexInfo | undefined): void { - if (indexInfo && indexInfo.isReadonly && accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) { - error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); + if ( + indexInfo && indexInfo.isReadonly && accessExpression + && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression)) + ) { + error( + accessExpression, + Diagnostics.Index_signature_in_type_0_only_permits_reading, + typeToString(objectType), + ); } } } - function getIndexNodeForAccessExpression(accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression) { - return accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression : - accessNode.kind === SyntaxKind.IndexedAccessType ? accessNode.indexType : - accessNode.kind === SyntaxKind.ComputedPropertyName ? accessNode.expression : - accessNode; + function getIndexNodeForAccessExpression( + accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, + ) { + return accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression + : accessNode.kind === SyntaxKind.IndexedAccessType ? accessNode.indexType + : accessNode.kind === SyntaxKind.ComputedPropertyName ? accessNode.expression + : accessNode; } function isPatternLiteralPlaceholderType(type: Type): boolean { if (type.flags & TypeFlags.Intersection) { - return some((type as IntersectionType).types, t => !!(t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) || isPatternLiteralPlaceholderType(t)); + return some( + (type as IntersectionType).types, + t => !!(t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) + || isPatternLiteralPlaceholderType(t), + ); } - return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) || isPatternLiteralType(type); + return !!(type.flags & (TypeFlags.Any | TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) + || isPatternLiteralType(type); } function isPatternLiteralType(type: Type) { - return !!(type.flags & TypeFlags.TemplateLiteral) && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) || - !!(type.flags & TypeFlags.StringMapping) && isPatternLiteralPlaceholderType((type as StringMappingType).type); + return !!(type.flags & TypeFlags.TemplateLiteral) + && every((type as TemplateLiteralType).types, isPatternLiteralPlaceholderType) + || !!(type.flags & TypeFlags.StringMapping) + && isPatternLiteralPlaceholderType((type as StringMappingType).type); } function isGenericType(type: Type): boolean { @@ -17607,36 +22632,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getGenericObjectFlags(type: Type): ObjectFlags { if (type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral)) { - if (!((type as UnionOrIntersectionType | TemplateLiteralType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as UnionOrIntersectionType | TemplateLiteralType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - reduceLeft((type as UnionOrIntersectionType | TemplateLiteralType).types, (flags, t) => flags | getGenericObjectFlags(t), 0); + if ( + !((type as UnionOrIntersectionType | TemplateLiteralType).objectFlags + & ObjectFlags.IsGenericTypeComputed) + ) { + (type as UnionOrIntersectionType | TemplateLiteralType).objectFlags |= ObjectFlags.IsGenericTypeComputed + | reduceLeft( + (type as UnionOrIntersectionType | TemplateLiteralType).types, + (flags, t) => flags | getGenericObjectFlags(t), + 0, + ); } return (type as UnionOrIntersectionType | TemplateLiteralType).objectFlags & ObjectFlags.IsGenericType; } if (type.flags & TypeFlags.Substitution) { if (!((type as SubstitutionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { - (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed | - getGenericObjectFlags((type as SubstitutionType).baseType) | getGenericObjectFlags((type as SubstitutionType).constraint); + (type as SubstitutionType).objectFlags |= ObjectFlags.IsGenericTypeComputed + | getGenericObjectFlags((type as SubstitutionType).baseType) + | getGenericObjectFlags((type as SubstitutionType).constraint); } return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; } - return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) | - (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); + return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) + ? ObjectFlags.IsGenericObjectType : 0) + | (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.StringMapping) + && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); } function getSimplifiedType(type: Type, writing: boolean): Type { - return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) : - type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) : - type; + return type.flags & TypeFlags.IndexedAccess ? getSimplifiedIndexedAccessType(type as IndexedAccessType, writing) + : type.flags & TypeFlags.Conditional ? getSimplifiedConditionalType(type as ConditionalType, writing) + : type; } function distributeIndexOverObjectType(objectType: Type, indexType: Type, writing: boolean) { // (T | U)[K] -> T[K] | U[K] (reading) // (T | U)[K] -> T[K] & U[K] (writing) // (T & U)[K] -> T[K] & U[K] - if (objectType.flags & TypeFlags.Union || objectType.flags & TypeFlags.Intersection && !shouldDeferIndexType(objectType)) { - const types = map((objectType as UnionOrIntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType), writing)); - return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) : getUnionType(types); + if ( + objectType.flags & TypeFlags.Union + || objectType.flags & TypeFlags.Intersection && !shouldDeferIndexType(objectType) + ) { + const types = map( + (objectType as UnionOrIntersectionType).types, + t => getSimplifiedType(getIndexedAccessType(t, indexType), writing), + ); + return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) + : getUnionType(types); } } @@ -17644,7 +22686,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // T[A | B] -> T[A] | T[B] (reading) // T[A | B] -> T[A] & T[B] (writing) if (indexType.flags & TypeFlags.Union) { - const types = map((indexType as UnionType).types, t => getSimplifiedType(getIndexedAccessType(objectType, t), writing)); + const types = map( + (indexType as UnionType).types, + t => getSimplifiedType(getIndexedAccessType(objectType, t), writing), + ); return writing ? getIntersectionType(types) : getUnionType(types); } } @@ -17685,7 +22730,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // fixed element. We simplify to either the combined type of all elements (when the index type // the actual number type) or to the combined type of all non-fixed elements. if (isGenericTupleType(objectType) && indexType.flags & TypeFlags.NumberLike) { - const elementType = getElementTypeOfSliceOfTupleType(objectType, indexType.flags & TypeFlags.Number ? 0 : objectType.target.fixedLength, /*endSkipCount*/ 0, writing); + const elementType = getElementTypeOfSliceOfTupleType( + objectType, + indexType.flags & TypeFlags.Number ? 0 : objectType.target.fixedLength, + /*endSkipCount*/ 0, + writing, + ); if (elementType) { return type[cache] = elementType; } @@ -17695,7 +22745,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For example, for an index access { [P in K]: Box }[X], we construct the type Box. if (isGenericMappedType(objectType)) { if (!getNameTypeFromMappedType(objectType) || isFilteringMappedType(objectType)) { - return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t, writing)); + return type[cache] = mapType( + substituteIndexedMappedType(objectType, type.indexType), + t => getSimplifiedType(t, writing), + ); } } return type[cache] = type; @@ -17708,15 +22761,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const falseType = getFalseTypeFromConditionalType(type); // Simplifications for types of the form `T extends U ? T : never` and `T extends U ? never : T`. if (falseType.flags & TypeFlags.Never && getActualTypeVariable(trueType) === getActualTypeVariable(checkType)) { - if (checkType.flags & TypeFlags.Any || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true + if ( + checkType.flags & TypeFlags.Any + || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType)) + ) { // Always true return getSimplifiedType(trueType, writing); } else if (isIntersectionEmpty(checkType, extendsType)) { // Always false return neverType; } } - else if (trueType.flags & TypeFlags.Never && getActualTypeVariable(falseType) === getActualTypeVariable(checkType)) { - if (!(checkType.flags & TypeFlags.Any) && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType))) { // Always true + else if ( + trueType.flags & TypeFlags.Never && getActualTypeVariable(falseType) === getActualTypeVariable(checkType) + ) { + if ( + !(checkType.flags & TypeFlags.Any) + && isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(extendsType)) + ) { // Always true return neverType; } else if (checkType.flags & TypeFlags.Any || isIntersectionEmpty(checkType, extendsType)) { // Always false @@ -17736,11 +22797,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function substituteIndexedMappedType(objectType: MappedType, index: Type) { const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [index]); const templateMapper = combineTypeMappers(objectType.mapper, mapper); - return instantiateType(getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), templateMapper); + return instantiateType( + getTemplateTypeFromMappedType(objectType.target as MappedType || objectType), + templateMapper, + ); } - function getIndexedAccessType(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { - return getIndexedAccessTypeOrUndefined(objectType, indexType, accessFlags, accessNode, aliasSymbol, aliasTypeArguments) || (accessNode ? errorType : unknownType); + function getIndexedAccessType( + objectType: Type, + indexType: Type, + accessFlags = AccessFlags.None, + accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { + return getIndexedAccessTypeOrUndefined( + objectType, + indexType, + accessFlags, + accessNode, + aliasSymbol, + aliasTypeArguments, + ) || (accessNode ? errorType : unknownType); } function indexTypeLessThan(indexType: Type, limit: number) { @@ -17756,37 +22834,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); } - function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined { + function getIndexedAccessTypeOrUndefined( + objectType: Type, + indexType: Type, + accessFlags = AccessFlags.None, + accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type | undefined { if (objectType === wildcardType || indexType === wildcardType) { return wildcardType; } objectType = getReducedType(objectType); // If the object type has a string index signature and no other members we know that the result will // always be the type of that index signature and we can simplify accordingly. - if (isStringIndexSignatureOnlyType(objectType) && !(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) { + if ( + isStringIndexSignatureOnlyType(objectType) && !(indexType.flags & TypeFlags.Nullable) + && isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number) + ) { indexType = stringType; } // In noUncheckedIndexedAccess mode, indexed access operations that occur in an expression in a read position and resolve to // an index signature have 'undefined' included in their type. - if (compilerOptions.noUncheckedIndexedAccess && accessFlags & AccessFlags.ExpressionPosition) accessFlags |= AccessFlags.IncludeUndefined; + if (compilerOptions.noUncheckedIndexedAccess && accessFlags & AccessFlags.ExpressionPosition) { + accessFlags |= AccessFlags.IncludeUndefined; + } // If the index type is generic, or if the object type is generic and doesn't originate in an expression and // the operation isn't exclusively indexing the fixed (non-variadic) portion of a tuple type, we are performing // a higher-order index access where we cannot meaningfully access the properties of the object type. Note that // for a generic T and a non-generic K, we eagerly resolve T[K] if it originates in an expression. This is to // preserve backwards compatibility. For example, an element access 'this["foo"]' has always been resolved // eagerly using the constraint type of 'this' at the given location. - if (isGenericIndexType(indexType) || (accessNode && accessNode.kind !== SyntaxKind.IndexedAccessType ? - isGenericTupleType(objectType) && !indexTypeLessThan(indexType, getTotalFixedElementCount(objectType.target)) : - isGenericObjectType(objectType) && !(isTupleType(objectType) && indexTypeLessThan(indexType, getTotalFixedElementCount(objectType.target))) || isGenericReducibleType(objectType))) { + if ( + isGenericIndexType(indexType) || (accessNode && accessNode.kind !== SyntaxKind.IndexedAccessType + ? isGenericTupleType(objectType) + && !indexTypeLessThan(indexType, getTotalFixedElementCount(objectType.target)) + : isGenericObjectType(objectType) + && !(isTupleType(objectType) + && indexTypeLessThan(indexType, getTotalFixedElementCount(objectType.target))) + || isGenericReducibleType(objectType)) + ) { if (objectType.flags & TypeFlags.AnyOrUnknown) { return objectType; } // Defer the operation by creating an indexed access type. const persistentAccessFlags = accessFlags & AccessFlags.Persistent; - const id = objectType.id + "," + indexType.id + "," + persistentAccessFlags + getAliasId(aliasSymbol, aliasTypeArguments); + const id = objectType.id + "," + indexType.id + "," + persistentAccessFlags + + getAliasId(aliasSymbol, aliasTypeArguments); let type = indexedAccessTypes.get(id); if (!type) { - indexedAccessTypes.set(id, type = createIndexedAccessType(objectType, indexType, persistentAccessFlags, aliasSymbol, aliasTypeArguments)); + indexedAccessTypes.set( + id, + type = createIndexedAccessType( + objectType, + indexType, + persistentAccessFlags, + aliasSymbol, + aliasTypeArguments, + ), + ); } return type; @@ -17799,7 +22905,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const propTypes: Type[] = []; let wasMissingProp = false; for (const t of (indexType as UnionType).types) { - const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, indexType, accessNode, accessFlags | (wasMissingProp ? AccessFlags.SuppressNoImplicitAnyError : 0)); + const propType = getPropertyTypeForIndexType( + objectType, + apparentObjectType, + t, + indexType, + accessNode, + accessFlags | (wasMissingProp ? AccessFlags.SuppressNoImplicitAnyError : 0), + ); if (propType) { propTypes.push(propType); } @@ -17819,7 +22932,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? getIntersectionType(propTypes, aliasSymbol, aliasTypeArguments) : getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments); } - return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated); + return getPropertyTypeForIndexType( + objectType, + apparentObjectType, + indexType, + indexType, + accessNode, + accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated, + ); } function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { @@ -17828,7 +22948,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const objectType = getTypeFromTypeNode(node.objectType); const indexType = getTypeFromTypeNode(node.indexType); const potentialAlias = getAliasSymbolForTypeNode(node); - links.resolvedType = getIndexedAccessType(objectType, indexType, AccessFlags.None, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias)); + links.resolvedType = getIndexedAccessType( + objectType, + indexType, + AccessFlags.None, + node, + potentialAlias, + getTypeArgumentsForAliasSymbol(potentialAlias), + ); } return links.resolvedType; } @@ -17852,29 +22979,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Substitution) { return getActualTypeVariable((type as SubstitutionType).baseType); } - if (type.flags & TypeFlags.IndexedAccess && ( - (type as IndexedAccessType).objectType.flags & TypeFlags.Substitution || - (type as IndexedAccessType).indexType.flags & TypeFlags.Substitution)) { - return getIndexedAccessType(getActualTypeVariable((type as IndexedAccessType).objectType), getActualTypeVariable((type as IndexedAccessType).indexType)); + if ( + type.flags & TypeFlags.IndexedAccess && ( + (type as IndexedAccessType).objectType.flags & TypeFlags.Substitution + || (type as IndexedAccessType).indexType.flags & TypeFlags.Substitution + ) + ) { + return getIndexedAccessType( + getActualTypeVariable((type as IndexedAccessType).objectType), + getActualTypeVariable((type as IndexedAccessType).indexType), + ); } return type; } function maybeCloneTypeParameter(p: TypeParameter) { const constraint = getConstraintOfTypeParameter(p); - return constraint && (isGenericObjectType(constraint) || isGenericIndexType(constraint)) ? cloneTypeParameter(p) : p; + return constraint && (isGenericObjectType(constraint) || isGenericIndexType(constraint)) ? cloneTypeParameter(p) + : p; } function isSimpleTupleType(node: TypeNode) { - return isTupleTypeNode(node) && length(node.elements) > 0 && - !some(node.elements, e => isOptionalTypeNode(e) || isRestTypeNode(e) || isNamedTupleMember(e) && !!(e.questionToken || e.dotDotDotToken)); + return isTupleTypeNode(node) && length(node.elements) > 0 + && !some( + node.elements, + e => isOptionalTypeNode(e) || isRestTypeNode(e) + || isNamedTupleMember(e) && !!(e.questionToken || e.dotDotDotToken), + ); } function isDeferredType(type: Type, checkTuples: boolean) { return isGenericType(type) || checkTuples && isTupleType(type) && some(getElementTypes(type), isGenericType); } - function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getConditionalType( + root: ConditionalRoot, + mapper: TypeMapper | undefined, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { let result; let extraTypes: Type[] | undefined; let tailCount = 0; @@ -17899,8 +23042,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When the check and extends types are simple tuple types of the same arity, we defer resolution of the // conditional type when any tuple elements are generic. This is such that non-distributable conditional // types can be written `[X] extends [Y] ? ...` and be deferred similarly to `X extends Y ? ...`. - const checkTuples = isSimpleTupleType(root.node.checkType) && isSimpleTupleType(root.node.extendsType) && - length((root.node.checkType as TupleTypeNode).elements) === length((root.node.extendsType as TupleTypeNode).elements); + const checkTuples = isSimpleTupleType(root.node.checkType) && isSimpleTupleType(root.node.extendsType) + && length((root.node.checkType as TupleTypeNode).elements) + === length((root.node.extendsType as TupleTypeNode).elements); const checkTypeDeferred = isDeferredType(checkType, checkTuples); let combinedMapper: TypeMapper | undefined; if (root.inferTypeParameters) { @@ -17922,7 +23066,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // * The mapper that maps the old root type parameter to the clone (`freshMapper`) // * The mapper that maps the clone to its inference result (`context.mapper`) const freshParams = sameMap(root.inferTypeParameters, maybeCloneTypeParameter); - const freshMapper = freshParams !== root.inferTypeParameters ? createTypeMapper(root.inferTypeParameters, freshParams) : undefined; + const freshMapper = freshParams !== root.inferTypeParameters + ? createTypeMapper(root.inferTypeParameters, freshParams) : undefined; const context = createInferenceContext(freshParams, /*signature*/ undefined, InferenceFlags.None); if (freshMapper) { const freshCombinedMapper = combineTypeMappers(mapper, freshMapper); @@ -17936,7 +23081,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We don't want inferences from constraints as they may cause us to eagerly resolve the // conditional type instead of deferring resolution. Also, we always want strict function // types rules (i.e. proper contravariance) for inferences. - inferTypes(context.inferences, checkType, instantiateType(extendsType, freshMapper), InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); + inferTypes( + context.inferences, + checkType, + instantiateType(extendsType, freshMapper), + InferencePriority.NoConstraints | InferencePriority.AlwaysStrict, + ); } const innerMapper = combineTypeMappers(freshMapper, context.mapper); // It's possible for 'infer T' type paramteters to be given uninstantiated constraints when the @@ -17945,24 +23095,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { combinedMapper = mapper ? combineTypeMappers(innerMapper, mapper) : innerMapper; } // Instantiate the extends type including inferences for 'infer T' type parameters - const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType; + const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) + : extendsType; // We attempt to resolve the conditional type only when the check and extends types are non-generic if (!checkTypeDeferred && !isDeferredType(inferredExtendsType, checkTuples)) { // Return falseType for a definitely false extends check. We check an instantiations of the two // types with type parameters mapped to the wildcard type, the most permissive instantiations // possible (the wildcard type is assignable to and from all types). If those are not related, // then no instantiations will be and we can just return the false branch type. - if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && (checkType.flags & TypeFlags.Any || !isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType)))) { + if ( + !(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) + && (checkType.flags & TypeFlags.Any + || !isTypeAssignableTo( + getPermissiveInstantiation(checkType), + getPermissiveInstantiation(inferredExtendsType), + )) + ) { // Return union of trueType and falseType for 'any' since it matches anything if (checkType.flags & TypeFlags.Any) { - (extraTypes || (extraTypes = [])).push(instantiateType(getTypeFromTypeNode(root.node.trueType), combinedMapper || mapper)); + (extraTypes || (extraTypes = [])).push( + instantiateType(getTypeFromTypeNode(root.node.trueType), combinedMapper || mapper), + ); } // If falseType is an immediately nested conditional type that isn't distributive or has an // identical checkType, switch to that type and loop. const falseType = getTypeFromTypeNode(root.node.falseType); if (falseType.flags & TypeFlags.Conditional) { const newRoot = (falseType as ConditionalType).root; - if (newRoot.node.parent === root.node && (!newRoot.isDistributive || newRoot.checkType === root.checkType)) { + if ( + newRoot.node.parent === root.node + && (!newRoot.isDistributive || newRoot.checkType === root.checkType) + ) { root = newRoot; continue; } @@ -17978,7 +23141,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // that has no constraint. This ensures that, for example, the type // type Foo = T extends { x: string } ? string : number // doesn't immediately resolve to 'string' instead of being deferred. - if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) { + if ( + inferredExtendsType.flags & TypeFlags.AnyOrUnknown + || isTypeAssignableTo( + getRestrictiveInstantiation(checkType), + getRestrictiveInstantiation(inferredExtendsType), + ) + ) { const trueType = getTypeFromTypeNode(root.node.trueType); const trueMapper = combinedMapper || mapper; if (canTailRecurse(trueType, trueMapper)) { @@ -17996,7 +23165,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result.mapper = mapper; result.combinedMapper = combinedMapper; result.aliasSymbol = aliasSymbol || root.aliasSymbol; - result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217 + result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(root.aliasTypeArguments, mapper!); // TODO: GH#18217 break; } return extraTypes ? getUnionType(append(extraTypes, result)) : result; @@ -18011,8 +23181,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeParamMapper = combineTypeMappers((newType as ConditionalType).mapper, newMapper); const typeArguments = map(newRoot.outerTypeParameters, t => getMappedType(t, typeParamMapper)); const newRootMapper = createTypeMapper(newRoot.outerTypeParameters, typeArguments); - const newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) : undefined; - if (!newCheckType || newCheckType === newRoot.checkType || !(newCheckType.flags & (TypeFlags.Union | TypeFlags.Never))) { + const newCheckType = newRoot.isDistributive ? getMappedType(newRoot.checkType, newRootMapper) + : undefined; + if ( + !newCheckType || newCheckType === newRoot.checkType + || !(newCheckType.flags & (TypeFlags.Union | TypeFlags.Never)) + ) { root = newRoot; mapper = newRootMapper; aliasSymbol = undefined; @@ -18029,15 +23203,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTrueTypeFromConditionalType(type: ConditionalType) { - return type.resolvedTrueType || (type.resolvedTrueType = instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.mapper)); + return type.resolvedTrueType + || (type.resolvedTrueType = instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.mapper)); } function getFalseTypeFromConditionalType(type: ConditionalType) { - return type.resolvedFalseType || (type.resolvedFalseType = instantiateType(getTypeFromTypeNode(type.root.node.falseType), type.mapper)); + return type.resolvedFalseType + || (type.resolvedFalseType = instantiateType(getTypeFromTypeNode(type.root.node.falseType), type.mapper)); } function getInferredTrueTypeFromConditionalType(type: ConditionalType) { - return type.resolvedInferredTrueType || (type.resolvedInferredTrueType = type.combinedMapper ? instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.combinedMapper) : getTrueTypeFromConditionalType(type)); + return type.resolvedInferredTrueType + || (type.resolvedInferredTrueType = type.combinedMapper + ? instantiateType(getTypeFromTypeNode(type.root.node.trueType), type.combinedMapper) + : getTrueTypeFromConditionalType(type)); } function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] | undefined { @@ -18054,8 +23233,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isDistributionDependent(root: ConditionalRoot) { return root.isDistributive && ( - isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.trueType) || - isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.falseType)); + isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.trueType) + || isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.falseType) + ); } function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type { @@ -18065,7 +23245,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const aliasSymbol = getAliasSymbolForTypeNode(node); const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol); const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true); - const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node)); + const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters + : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node)); const root: ConditionalRoot = { node, checkType, @@ -18075,7 +23256,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { outerTypeParameters, instantiations: undefined, aliasSymbol, - aliasTypeArguments + aliasTypeArguments, }; links.resolvedType = getConditionalType(root, /*mapper*/ undefined); if (outerTypeParameters) { @@ -18111,7 +23292,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { links.resolvedSymbol = unknownSymbol; return links.resolvedType = errorType; } - const targetMeaning = node.isTypeOf ? SymbolFlags.Value : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type; + const targetMeaning = node.isTypeOf ? SymbolFlags.Value + : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type; // TODO: Future work: support unions/generics/whatever via a deferred import-type const innerModuleSymbol = resolveExternalModuleName(node, node.argument.literal); if (!innerModuleSymbol) { @@ -18131,12 +23313,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the `exports` lookup process that only looks up namespace members which is used for most type references const mergedResolvedSymbol = getMergedSymbol(resolveSymbol(currentNamespace)); const symbolFromVariable = node.isTypeOf || isInJSFile(node) && isExportEquals - ? getPropertyOfType(getTypeOfSymbol(mergedResolvedSymbol), current.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ true) + ? getPropertyOfType( + getTypeOfSymbol(mergedResolvedSymbol), + current.escapedText, + /*skipObjectFunctionPropertyAugment*/ false, + /*includeTypeOnlyMembers*/ true, + ) : undefined; - const symbolFromModule = node.isTypeOf ? undefined : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); + const symbolFromModule = node.isTypeOf ? undefined + : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); const next = symbolFromModule ?? symbolFromVariable; if (!next) { - error(current, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(currentNamespace), declarationNameToString(current)); + error( + current, + Diagnostics.Namespace_0_has_no_exported_member_1, + getFullyQualifiedName(currentNamespace), + declarationNameToString(current), + ); return links.resolvedType = errorType; } getNodeLinks(current).resolvedSymbol = next; @@ -18152,7 +23345,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { const errorMessage = targetMeaning === SymbolFlags.Value ? Diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here - : Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0; + : Diagnostics + .Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0; error(node, errorMessage, node.argument.literal.text); @@ -18175,7 +23369,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeLiteralNode | FunctionOrConstructorTypeNode | JSDocTypeLiteral | JSDocFunctionType | JSDocSignature): Type { + function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode( + node: TypeLiteralNode | FunctionOrConstructorTypeNode | JSDocTypeLiteral | JSDocFunctionType | JSDocSignature, + ): Type { const links = getNodeLinks(node); if (!links.resolvedType) { // Deferred resolution of members is handled by resolveObjectTypeMembers @@ -18198,7 +23394,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getAliasSymbolForTypeNode(node: Node) { let host = node.parent; - while (isParenthesizedTypeNode(host) || isJSDocTypeExpression(host) || isTypeOperatorNode(host) && host.operator === SyntaxKind.ReadonlyKeyword) { + while ( + isParenthesizedTypeNode(host) || isJSDocTypeExpression(host) + || isTypeOperatorNode(host) && host.operator === SyntaxKind.ReadonlyKeyword + ) { host = host.parent; } return isTypeAlias(host) ? getSymbolOfDeclaration(host) : undefined; @@ -18213,7 +23412,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isEmptyObjectTypeOrSpreadsIntoEmptyObject(type: Type) { - return isEmptyObjectType(type) || !!(type.flags & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)); + return isEmptyObjectType(type) + || !!(type.flags + & (TypeFlags.Null | TypeFlags.Undefined | TypeFlags.BooleanLike | TypeFlags.NumberLike + | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive + | TypeFlags.Index)); } function tryMergeUnionOfObjectTypeAndEmptyObject(type: Type, readonly: boolean): Type { @@ -18227,7 +23430,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!firstType) { return type; } - const secondType = find((type as UnionType).types, t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t)); + const secondType = find( + (type as UnionType).types, + t => t !== firstType && !isEmptyObjectTypeOrSpreadsIntoEmptyObject(t), + ); if (secondType) { return type; } @@ -18241,10 +23447,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // do nothing, skip privates } else if (isSpreadableProperty(prop)) { - const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); + const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor + && !(prop.flags & SymbolFlags.GetAccessor); const flags = SymbolFlags.Property | SymbolFlags.Optional; - const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0)); - result.links.type = isSetonlyAccessor ? undefinedType : addOptionality(getTypeOfSymbol(prop), /*isProperty*/ true); + const result = createSymbol( + flags, + prop.escapedName, + getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0), + ); + result.links.type = isSetonlyAccessor ? undefinedType + : addOptionality(getTypeOfSymbol(prop), /*isProperty*/ true); result.declarations = prop.declarations; result.links.nameType = getSymbolLinks(prop).nameType; result.links.syntheticOrigin = prop; @@ -18262,7 +23474,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, objectFlags: ObjectFlags, readonly: boolean): Type { + function getSpreadType( + left: Type, + right: Type, + symbol: Symbol | undefined, + objectFlags: ObjectFlags, + readonly: boolean, + ): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -18287,7 +23505,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? mapType(right, t => getSpreadType(left, t, symbol, objectFlags, readonly)) : errorType; } - if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { + if ( + right.flags + & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike + | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index) + ) { return left; } @@ -18302,7 +23524,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const types = (left as IntersectionType).types; const lastLeft = types[types.length - 1]; if (isNonGenericObjectType(lastLeft) && isNonGenericObjectType(right)) { - return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, objectFlags, readonly)])); + return getIntersectionType( + concatenate(types.slice(0, types.length - 1), [ + getSpreadType(lastLeft, right, symbol, objectFlags, readonly), + ]), + ); } } return getIntersectionType([left, right]); @@ -18339,7 +23565,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const leftType = getTypeOfSymbol(leftProp); const leftTypeWithoutUndefined = removeMissingOrUndefinedType(leftType); const rightTypeWithoutUndefined = removeMissingOrUndefinedType(rightType); - result.links.type = leftTypeWithoutUndefined === rightTypeWithoutUndefined ? leftType : getUnionType([leftType, rightTypeWithoutUndefined], UnionReduction.Subtype); + result.links.type = leftTypeWithoutUndefined === rightTypeWithoutUndefined ? leftType + : getUnionType([leftType, rightTypeWithoutUndefined], UnionReduction.Subtype); result.links.leftSpread = leftProp; result.links.rightSpread = rightProp; result.declarations = declarations; @@ -18352,16 +23579,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - const spread = createAnonymousType(symbol, members, emptyArray, emptyArray, sameMap(indexInfos, info => getIndexInfoWithReadonly(info, readonly))); - spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral | ObjectFlags.ContainsSpread | objectFlags; + const spread = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + sameMap(indexInfos, info => getIndexInfoWithReadonly(info, readonly)), + ); + spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral + | ObjectFlags.ContainsSpread | objectFlags; return spread; } /** We approximate own properties as non-methods plus methods that are inside the object literal */ function isSpreadableProperty(prop: Symbol): boolean { - return !some(prop.declarations, isPrivateIdentifierClassElementDeclaration) && - (!(prop.flags & (SymbolFlags.Method | SymbolFlags.GetAccessor | SymbolFlags.SetAccessor)) || - !prop.declarations?.some(decl => isClassLike(decl.parent))); + return !some(prop.declarations, isPrivateIdentifierClassElementDeclaration) + && (!(prop.flags & (SymbolFlags.Method | SymbolFlags.GetAccessor | SymbolFlags.SetAccessor)) + || !prop.declarations?.some(decl => isClassLike(decl.parent))); } function getSpreadSymbol(prop: Symbol, readonly: boolean) { @@ -18370,7 +23604,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return prop; } const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional); - const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0)); + const result = createSymbol( + flags, + prop.escapedName, + getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0), + ); result.links.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop); result.declarations = prop.declarations; result.links.nameType = getSymbolLinks(prop).nameType; @@ -18379,10 +23617,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getIndexInfoWithReadonly(info: IndexInfo, readonly: boolean) { - return info.isReadonly !== readonly ? createIndexInfo(info.keyType, info.type, readonly, info.declaration) : info; + return info.isReadonly !== readonly ? createIndexInfo(info.keyType, info.type, readonly, info.declaration) + : info; } - function createLiteralType(flags: TypeFlags, value: string | number | PseudoBigInt, symbol?: Symbol, regularType?: LiteralType) { + function createLiteralType( + flags: TypeFlags, + value: string | number | PseudoBigInt, + symbol?: Symbol, + regularType?: LiteralType, + ) { const type = createTypeWithSymbol(flags, symbol!) as LiteralType; type.value = value; type.regularType = regularType || type; @@ -18392,7 +23636,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getFreshTypeOfLiteralType(type: Type): Type { if (type.flags & TypeFlags.Freshable) { if (!(type as FreshableType).freshType) { - const freshType = createLiteralType(type.flags, (type as LiteralType).value, (type as LiteralType).symbol, type as LiteralType); + const freshType = createLiteralType( + type.flags, + (type as LiteralType).value, + (type as LiteralType).symbol, + type as LiteralType, + ); freshType.freshType = freshType; (type as FreshableType).freshType = freshType; } @@ -18402,9 +23651,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getRegularTypeOfLiteralType(type: Type): Type { - return type.flags & TypeFlags.Freshable ? (type as FreshableType).regularType : - type.flags & TypeFlags.Union ? ((type as UnionType).regularType || ((type as UnionType).regularType = mapType(type, getRegularTypeOfLiteralType) as UnionType)) : - type; + return type.flags & TypeFlags.Freshable ? (type as FreshableType).regularType + : type.flags & TypeFlags.Union + ? ((type as UnionType).regularType + || ((type as UnionType).regularType = mapType(type, getRegularTypeOfLiteralType) as UnionType)) + : type; } function isFreshLiteralType(type: Type) { @@ -18413,29 +23664,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getStringLiteralType(value: string): StringLiteralType { let type; - return stringLiteralTypes.get(value) || - (stringLiteralTypes.set(value, type = createLiteralType(TypeFlags.StringLiteral, value) as StringLiteralType), type); + return stringLiteralTypes.get(value) + || (stringLiteralTypes.set( + value, + type = createLiteralType(TypeFlags.StringLiteral, value) as StringLiteralType, + ), + type); } function getNumberLiteralType(value: number): NumberLiteralType { let type; - return numberLiteralTypes.get(value) || - (numberLiteralTypes.set(value, type = createLiteralType(TypeFlags.NumberLiteral, value) as NumberLiteralType), type); + return numberLiteralTypes.get(value) + || (numberLiteralTypes.set( + value, + type = createLiteralType(TypeFlags.NumberLiteral, value) as NumberLiteralType, + ), + type); } function getBigIntLiteralType(value: PseudoBigInt): BigIntLiteralType { let type; const key = pseudoBigIntToString(value); - return bigIntLiteralTypes.get(key) || - (bigIntLiteralTypes.set(key, type = createLiteralType(TypeFlags.BigIntLiteral, value) as BigIntLiteralType), type); + return bigIntLiteralTypes.get(key) + || (bigIntLiteralTypes.set( + key, + type = createLiteralType(TypeFlags.BigIntLiteral, value) as BigIntLiteralType, + ), + type); } function getEnumLiteralType(value: string | number, enumId: number, symbol: Symbol): LiteralType { let type; const key = `${enumId}${typeof value === "string" ? "@" : "#"}${value}`; - const flags = TypeFlags.EnumLiteral | (typeof value === "string" ? TypeFlags.StringLiteral : TypeFlags.NumberLiteral); - return enumLiteralTypes.get(key) || - (enumLiteralTypes.set(key, type = createLiteralType(flags, value, symbol)), type); + const flags = TypeFlags.EnumLiteral + | (typeof value === "string" ? TypeFlags.StringLiteral : TypeFlags.NumberLiteral); + return enumLiteralTypes.get(key) + || (enumLiteralTypes.set(key, type = createLiteralType(flags, value, symbol)), type); } function getTypeFromLiteralTypeNode(node: LiteralTypeNode): Type { @@ -18457,7 +23721,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getESSymbolLikeTypeForNode(node: Node) { if (isValidESSymbolDeclaration(node)) { - const symbol = isCommonJsExportPropertyAssignment(node) ? getSymbolOfNode((node as BinaryExpression).left) : getSymbolOfNode(node); + const symbol = isCommonJsExportPropertyAssignment(node) ? getSymbolOfNode((node as BinaryExpression).left) + : getSymbolOfNode(node); if (symbol) { const links = getSymbolLinks(symbol); return links.uniqueESSymbolType || (links.uniqueESSymbolType = createUniqueESSymbolType(symbol)); @@ -18467,23 +23732,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getThisType(node: Node): Type { - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); const parent = container && container.parent; if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) { - if (!isStatic(container) && - (!isConstructorDeclaration(container) || isNodeDescendantOf(node, container.body))) { - return getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(parent as ClassLikeDeclaration | InterfaceDeclaration)).thisType!; + if ( + !isStatic(container) + && (!isConstructorDeclaration(container) || isNodeDescendantOf(node, container.body)) + ) { + return getDeclaredTypeOfClassOrInterface( + getSymbolOfDeclaration(parent as ClassLikeDeclaration | InterfaceDeclaration), + ).thisType!; } } // inside x.prototype = { ... } - if (parent && isObjectLiteralExpression(parent) && isBinaryExpression(parent.parent) && getAssignmentDeclarationKind(parent.parent) === AssignmentDeclarationKind.Prototype) { + if ( + parent && isObjectLiteralExpression(parent) && isBinaryExpression(parent.parent) + && getAssignmentDeclarationKind(parent.parent) === AssignmentDeclarationKind.Prototype + ) { return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent.parent.left)!.parent!).thisType!; } // /** @return {this} */ // x.prototype.m = function() { ... } const host = node.flags & NodeFlags.JSDoc ? getHostSignatureFromJSDoc(node) : undefined; - if (host && isFunctionExpression(host) && isBinaryExpression(host.parent) && getAssignmentDeclarationKind(host.parent) === AssignmentDeclarationKind.PrototypeProperty) { + if ( + host && isFunctionExpression(host) && isBinaryExpression(host.parent) + && getAssignmentDeclarationKind(host.parent) === AssignmentDeclarationKind.PrototypeProperty + ) { return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(host.parent.left)!.parent!).thisType!; } // inside constructor function C() { ... } @@ -18513,7 +23792,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.TupleType: if ((node as TupleTypeNode).elements.length === 1) { node = (node as TupleTypeNode).elements[0]; - if (node.kind === SyntaxKind.RestType || node.kind === SyntaxKind.NamedTupleMember && (node as NamedTupleMember).dotDotDotToken) { + if ( + node.kind === SyntaxKind.RestType + || node.kind === SyntaxKind.NamedTupleMember && (node as NamedTupleMember).dotDotDotToken + ) { return getArrayElementTypeNode((node as RestTypeNode | NamedTupleMember).type); } } @@ -18526,9 +23808,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeFromNamedTupleTypeNode(node: NamedTupleMember): Type { const links = getNodeLinks(node); - return links.resolvedType || (links.resolvedType = - node.dotDotDotToken ? getTypeFromRestTypeNode(node) : - addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true, !!node.questionToken)); + return links.resolvedType || (links.resolvedType = node.dotDotDotToken ? getTypeFromRestTypeNode(node) + : addOptionality(getTypeFromTypeNode(node.type), /*isProperty*/ true, !!node.questionToken)); } function getTypeFromTypeNode(node: TypeNode): Type { @@ -18598,7 +23879,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ParenthesizedType: case SyntaxKind.JSDocNonNullableType: case SyntaxKind.JSDocTypeExpression: - return getTypeFromTypeNode((node as ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression | NamedTupleMember).type); + return getTypeFromTypeNode( + (node as ParenthesizedTypeNode | JSDocTypeReferencingNode | JSDocTypeExpression | NamedTupleMember) + .type, + ); case SyntaxKind.RestType: return getTypeFromRestTypeNode(node as RestTypeNode); case SyntaxKind.JSDocVariadicType: @@ -18609,7 +23893,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocTypeLiteral: case SyntaxKind.JSDocFunctionType: case SyntaxKind.JSDocSignature: - return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node as TypeLiteralNode | FunctionOrConstructorTypeNode | JSDocTypeLiteral | JSDocFunctionType | JSDocSignature); + return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode( + node as + | TypeLiteralNode + | FunctionOrConstructorTypeNode + | JSDocTypeLiteral + | JSDocFunctionType + | JSDocSignature, + ); case SyntaxKind.TypeOperator: return getTypeFromTypeOperatorNode(node as TypeOperatorNode); case SyntaxKind.IndexedAccessType: @@ -18637,9 +23928,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function instantiateList(items: readonly T[], mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[]; - function instantiateList(items: readonly T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[] | undefined; - function instantiateList(items: readonly T[] | undefined, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): readonly T[] | undefined { + function instantiateList( + items: readonly T[], + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T, + ): readonly T[]; + function instantiateList( + items: readonly T[] | undefined, + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T, + ): readonly T[] | undefined; + function instantiateList( + items: readonly T[] | undefined, + mapper: TypeMapper, + instantiator: (item: T, mapper: TypeMapper) => T, + ): readonly T[] | undefined { if (items && items.length) { for (let i = 0; i < items.length; i++) { const item = items[i]; @@ -18672,7 +23975,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createTypeMapper(sources: readonly TypeParameter[], targets: readonly Type[] | undefined): TypeMapper { - return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : makeArrayTypeMapper(sources, targets); + return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) + : makeArrayTypeMapper(sources, targets); } function getMappedType(type: Type, mapper: TypeMapper): Type { @@ -18704,7 +24008,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case TypeMapKind.Composite: case TypeMapKind.Merged: const t1 = getMappedType(type, mapper.mapper1); - return t1 !== type && mapper.kind === TypeMapKind.Composite ? instantiateType(t1, mapper.mapper2) : getMappedType(t1, mapper.mapper2); + return t1 !== type && mapper.kind === TypeMapKind.Composite ? instantiateType(t1, mapper.mapper2) + : getMappedType(t1, mapper.mapper2); } } @@ -18717,14 +24022,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function makeFunctionTypeMapper(func: (t: Type) => Type, debugInfo: () => string): TypeMapper { - return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Function, func, debugInfo: Debug.isDebugging ? debugInfo : undefined }); + return Debug.attachDebugPrototypeIfDebug({ + kind: TypeMapKind.Function, + func, + debugInfo: Debug.isDebugging ? debugInfo : undefined, + }); } function makeDeferredTypeMapper(sources: readonly TypeParameter[], targets: (() => Type)[]) { return Debug.attachDebugPrototypeIfDebug({ kind: TypeMapKind.Deferred, sources, targets }); } - function makeCompositeTypeMapper(kind: TypeMapKind.Composite | TypeMapKind.Merged, mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper { + function makeCompositeTypeMapper( + kind: TypeMapKind.Composite | TypeMapKind.Merged, + mapper1: TypeMapper, + mapper2: TypeMapper, + ): TypeMapper { return Debug.attachDebugPrototypeIfDebug({ kind, mapper1, mapper2 }); } @@ -18738,7 +24051,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function createBackreferenceMapper(context: InferenceContext, index: number): TypeMapper { const forwardInferences = context.inferences.slice(index); - return createTypeMapper(map(forwardInferences, i => i.typeParameter), map(forwardInferences, () => unknownType)); + return createTypeMapper( + map(forwardInferences, i => i.typeParameter), + map(forwardInferences, () => unknownType), + ); } function combineTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper { @@ -18750,19 +24066,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function prependTypeMapping(source: Type, target: Type, mapper: TypeMapper | undefined) { - return !mapper ? makeUnaryTypeMapper(source, target) : makeCompositeTypeMapper(TypeMapKind.Merged, makeUnaryTypeMapper(source, target), mapper); + return !mapper ? makeUnaryTypeMapper(source, target) + : makeCompositeTypeMapper(TypeMapKind.Merged, makeUnaryTypeMapper(source, target), mapper); } function appendTypeMapping(mapper: TypeMapper | undefined, source: Type, target: Type) { - return !mapper ? makeUnaryTypeMapper(source, target) : makeCompositeTypeMapper(TypeMapKind.Merged, mapper, makeUnaryTypeMapper(source, target)); + return !mapper ? makeUnaryTypeMapper(source, target) + : makeCompositeTypeMapper(TypeMapKind.Merged, mapper, makeUnaryTypeMapper(source, target)); } function getRestrictiveTypeParameter(tp: TypeParameter) { - return !tp.constraint && !getConstraintDeclaration(tp) || tp.constraint === noConstraintType ? tp : tp.restrictiveInstantiation || ( - tp.restrictiveInstantiation = createTypeParameter(tp.symbol), - (tp.restrictiveInstantiation as TypeParameter).constraint = noConstraintType, - tp.restrictiveInstantiation - ); + return !tp.constraint && !getConstraintDeclaration(tp) || tp.constraint === noConstraintType ? tp + : tp.restrictiveInstantiation || ( + tp.restrictiveInstantiation = createTypeParameter(tp.symbol), + (tp.restrictiveInstantiation as TypeParameter).constraint = noConstraintType, + tp.restrictiveInstantiation + ); } function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter { @@ -18772,7 +24091,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function instantiateTypePredicate(predicate: TypePredicate, mapper: TypeMapper): TypePredicate { - return createTypePredicate(predicate.kind, predicate.parameterName, predicate.parameterIndex, instantiateType(predicate.type, mapper)); + return createTypePredicate( + predicate.kind, + predicate.parameterName, + predicate.parameterIndex, + instantiateType(predicate.type, mapper), + ); } function instantiateSignature(signature: Signature, mapper: TypeMapper, eraseTypeParameters?: boolean): Signature { @@ -18790,13 +24114,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't compute resolvedReturnType and resolvedTypePredicate now, // because using `mapper` now could trigger inferences to become fixed. (See `createInferenceContext`.) // See GH#17600. - const result = createSignature(signature.declaration, freshTypeParameters, + const result = createSignature( + signature.declaration, + freshTypeParameters, signature.thisParameter && instantiateSymbol(signature.thisParameter, mapper), instantiateList(signature.parameters, mapper, instantiateSymbol), /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, signature.minArgumentCount, - signature.flags & SignatureFlags.PropagatingFlags); + signature.flags & SignatureFlags.PropagatingFlags, + ); result.target = signature; result.mapper = mapper; return result; @@ -18818,7 +24145,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Keep the flags from the symbol we're instantiating. Mark that is instantiated, and // also transient so that we can just store data on it directly. - const result = createSymbol(symbol.flags, symbol.escapedName, CheckFlags.Instantiated | getCheckFlags(symbol) & (CheckFlags.Readonly | CheckFlags.Late | CheckFlags.OptionalParameter | CheckFlags.RestParameter)); + const result = createSymbol( + symbol.flags, + symbol.escapedName, + CheckFlags.Instantiated + | getCheckFlags(symbol) + & (CheckFlags.Readonly | CheckFlags.Late | CheckFlags.OptionalParameter | CheckFlags.RestParameter), + ); result.declarations = symbol.declarations; result.parent = symbol.parent; result.links.target = symbol; @@ -18832,13 +24165,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function getObjectTypeInstantiation(type: AnonymousType | DeferredTypeReference, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) { - const declaration = type.objectFlags & ObjectFlags.Reference ? (type as TypeReference).node! : - type.objectFlags & ObjectFlags.InstantiationExpressionType ? (type as InstantiationExpressionType).node : - type.symbol.declarations![0]; + function getObjectTypeInstantiation( + type: AnonymousType | DeferredTypeReference, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ) { + const declaration = type.objectFlags & ObjectFlags.Reference ? (type as TypeReference).node! + : type.objectFlags & ObjectFlags.InstantiationExpressionType ? (type as InstantiationExpressionType).node + : type.symbol.declarations![0]; const links = getNodeLinks(declaration); - const target = type.objectFlags & ObjectFlags.Reference ? links.resolvedType! as DeferredTypeReference : - type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; + const target = type.objectFlags & ObjectFlags.Reference ? links.resolvedType! as DeferredTypeReference + : type.objectFlags & ObjectFlags.Instantiated ? type.target! : type; let typeParameters = links.outerTypeParameters; if (!typeParameters) { // The first time an anonymous type is instantiated we compute and store a list of the type @@ -18847,14 +24185,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // set of type parameters to those that are possibly referenced in the literal. let outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true); if (isJSConstructor(declaration)) { - const templateTagParameters = getTypeParametersFromDeclaration(declaration as DeclarationWithTypeParameters); + const templateTagParameters = getTypeParametersFromDeclaration( + declaration as DeclarationWithTypeParameters, + ); outerTypeParameters = addRange(outerTypeParameters, templateTagParameters); } typeParameters = outerTypeParameters || emptyArray; - const allDeclarations = type.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) ? [declaration] : type.symbol.declarations!; - typeParameters = (target.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) || target.symbol.flags & SymbolFlags.Method || target.symbol.flags & SymbolFlags.TypeLiteral) && !target.aliasTypeArguments ? - filter(typeParameters, tp => some(allDeclarations, d => isTypeParameterPossiblyReferenced(tp, d))) : - typeParameters; + const allDeclarations = type.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) + ? [declaration] : type.symbol.declarations!; + typeParameters = (target.objectFlags & (ObjectFlags.Reference | ObjectFlags.InstantiationExpressionType) + || target.symbol.flags & SymbolFlags.Method || target.symbol.flags & SymbolFlags.TypeLiteral) + && !target.aliasTypeArguments + ? filter(typeParameters, tp => some(allDeclarations, d => isTypeParameterPossiblyReferenced(tp, d))) + : typeParameters; links.outerTypeParameters = typeParameters; } if (typeParameters.length) { @@ -18864,32 +24207,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const combinedMapper = combineTypeMappers(type.mapper, mapper); const typeArguments = map(typeParameters, t => getMappedType(t, combinedMapper)); const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); + const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); const id = getTypeListId(typeArguments) + getAliasId(newAliasSymbol, newAliasTypeArguments); if (!target.instantiations) { target.instantiations = new Map(); - target.instantiations.set(getTypeListId(typeParameters) + getAliasId(target.aliasSymbol, target.aliasTypeArguments), target); + target.instantiations.set( + getTypeListId(typeParameters) + getAliasId(target.aliasSymbol, target.aliasTypeArguments), + target, + ); } let result = target.instantiations.get(id); if (!result) { const newMapper = createTypeMapper(typeParameters, typeArguments); - result = target.objectFlags & ObjectFlags.Reference ? createDeferredTypeReference((type as DeferredTypeReference).target, (type as DeferredTypeReference).node, newMapper, newAliasSymbol, newAliasTypeArguments) : - target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) : - instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments); + result = target.objectFlags & ObjectFlags.Reference + ? createDeferredTypeReference( + (type as DeferredTypeReference).target, + (type as DeferredTypeReference).node, + newMapper, + newAliasSymbol, + newAliasTypeArguments, + ) + : target.objectFlags & ObjectFlags.Mapped + ? instantiateMappedType(target as MappedType, newMapper, newAliasSymbol, newAliasTypeArguments) + : instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments); target.instantiations.set(id, result); // Set cached result early in case we recursively invoke instantiation while eagerly computing type variable visibility below const resultObjectFlags = getObjectFlags(result); - if (result.flags & TypeFlags.ObjectFlagsType && !(resultObjectFlags & ObjectFlags.CouldContainTypeVariablesComputed)) { + if ( + result.flags & TypeFlags.ObjectFlagsType + && !(resultObjectFlags & ObjectFlags.CouldContainTypeVariablesComputed) + ) { const resultCouldContainTypeVariables = some(typeArguments, couldContainTypeVariables); // one of the input type arguments might be or contain the result if (!(getObjectFlags(result) & ObjectFlags.CouldContainTypeVariablesComputed)) { // if `result` is one of the object types we tried to make (it may not be, due to how `instantiateMappedType` works), we can carry forward the type variable containment check from the input type arguments if (resultObjectFlags & (ObjectFlags.Mapped | ObjectFlags.Anonymous | ObjectFlags.Reference)) { - (result as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariables : 0); + (result as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed + | (resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariables : 0); } // If none of the type arguments for the outer type parameters contain type variables, it follows // that the instantiated type doesn't reference type variables. // Intrinsics have `CouldContainTypeVariablesComputed` pre-set, so this should only cover unions and intersections resulting from `instantiateMappedType` else { - (result as ObjectFlagsType).objectFlags |= !resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariablesComputed : 0; + (result as ObjectFlagsType).objectFlags |= !resultCouldContainTypeVariables + ? ObjectFlags.CouldContainTypeVariablesComputed : 0; } } } @@ -18900,8 +24260,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function maybeTypeParameterReference(node: Node) { - return !(node.parent.kind === SyntaxKind.TypeReference && (node.parent as TypeReferenceNode).typeArguments && node === (node.parent as TypeReferenceNode).typeName || - node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments && node === (node.parent as ImportTypeNode).qualifier); + return !(node.parent.kind === SyntaxKind.TypeReference && (node.parent as TypeReferenceNode).typeArguments + && node === (node.parent as TypeReferenceNode).typeName + || node.parent.kind === SyntaxKind.ImportType && (node.parent as ImportTypeNode).typeArguments + && node === (node.parent as ImportTypeNode).qualifier); } function isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node) { @@ -18912,7 +24274,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1) { const container = tp.symbol.declarations[0].parent; for (let n = node; n !== container; n = n.parent) { - if (!n || n.kind === SyntaxKind.Block || n.kind === SyntaxKind.ConditionalType && forEachChild((n as ConditionalTypeNode).extendsType, containsReference)) { + if ( + !n || n.kind === SyntaxKind.Block + || n.kind === SyntaxKind.ConditionalType + && forEachChild((n as ConditionalTypeNode).extendsType, containsReference) + ) { return true; } } @@ -18924,29 +24290,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ThisType: return !!tp.isThisType; case SyntaxKind.Identifier: - return !tp.isThisType && isPartOfTypeNode(node) && maybeTypeParameterReference(node) && - getTypeFromTypeNodeWorker(node as TypeNode) === tp; // use worker because we're looking for === equality + return !tp.isThisType && isPartOfTypeNode(node) && maybeTypeParameterReference(node) + && getTypeFromTypeNodeWorker(node as TypeNode) === tp; // use worker because we're looking for === equality case SyntaxKind.TypeQuery: const entityName = (node as TypeQueryNode).exprName; const firstIdentifier = getFirstIdentifier(entityName); if (!isThisIdentifier(firstIdentifier)) { // Don't attempt to analyze typeof this.xxx const firstIdentifierSymbol = getResolvedSymbol(firstIdentifier); const tpDeclaration = tp.symbol.declarations![0]; // There is exactly one declaration, otherwise `containsReference` is not called - const tpScope = tpDeclaration.kind === SyntaxKind.TypeParameter ? tpDeclaration.parent : // Type parameter is a regular type parameter, e.g. foo - tp.isThisType ? tpDeclaration : // Type parameter is the this type, and its declaration is the class declaration. - undefined; // Type parameter's declaration was unrecognized, e.g. comes from JSDoc annotation. + const tpScope = tpDeclaration.kind === SyntaxKind.TypeParameter ? tpDeclaration.parent // Type parameter is a regular type parameter, e.g. foo + : tp.isThisType ? tpDeclaration // Type parameter is the this type, and its declaration is the class declaration. + : undefined; // Type parameter's declaration was unrecognized, e.g. comes from JSDoc annotation. if (firstIdentifierSymbol.declarations && tpScope) { - return some(firstIdentifierSymbol.declarations, idDecl => isNodeDescendantOf(idDecl, tpScope)) || - some((node as TypeQueryNode).typeArguments, containsReference); + return some( + firstIdentifierSymbol.declarations, + idDecl => isNodeDescendantOf(idDecl, tpScope), + ) + || some((node as TypeQueryNode).typeArguments, containsReference); } } return true; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - return !(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body || - some((node as FunctionLikeDeclaration).typeParameters, containsReference) || - some((node as FunctionLikeDeclaration).parameters, containsReference) || - !!(node as FunctionLikeDeclaration).type && containsReference((node as FunctionLikeDeclaration).type!); + return !(node as FunctionLikeDeclaration).type && !!(node as FunctionLikeDeclaration).body + || some((node as FunctionLikeDeclaration).typeParameters, containsReference) + || some((node as FunctionLikeDeclaration).parameters, containsReference) + || !!(node as FunctionLikeDeclaration).type + && containsReference((node as FunctionLikeDeclaration).type!); } return !!forEachChild(node, containsReference); } @@ -18963,7 +24333,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function instantiateMappedType(type: MappedType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function instantiateMappedType( + type: MappedType, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { // For a homomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping // operation depends on T as follows: // * If T is a primitive type no mapping is performed and the result is simply T. @@ -18978,45 +24353,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeVariable) { const mappedTypeVariable = instantiateType(typeVariable, mapper); if (typeVariable !== mappedTypeVariable) { - return mapTypeWithAlias(getReducedType(mappedTypeVariable), t => { - if (t.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t)) { - if (!type.declaration.nameType) { - let constraint; - if (isArrayType(t) || t.flags & TypeFlags.Any && findResolutionCycleStartIndex(typeVariable, TypeSystemPropertyName.ImmediateBaseConstraint) < 0 && - (constraint = getConstraintOfTypeParameter(typeVariable)) && everyType(constraint, isArrayOrTupleType)) { - return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper)); - } - if (isGenericTupleType(t)) { - return instantiateMappedGenericTupleType(t, type, typeVariable, mapper); - } - if (isTupleType(t)) { - return instantiateMappedTupleType(t, type, prependTypeMapping(typeVariable, t, mapper)); + return mapTypeWithAlias( + getReducedType(mappedTypeVariable), + t => { + if ( + t.flags + & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object + | TypeFlags.Intersection) && t !== wildcardType && !isErrorType(t) + ) { + if (!type.declaration.nameType) { + let constraint; + if ( + isArrayType(t) + || t.flags & TypeFlags.Any + && findResolutionCycleStartIndex( + typeVariable, + TypeSystemPropertyName.ImmediateBaseConstraint, + ) < 0 + && (constraint = getConstraintOfTypeParameter(typeVariable)) + && everyType(constraint, isArrayOrTupleType) + ) { + return instantiateMappedArrayType( + t, + type, + prependTypeMapping(typeVariable, t, mapper), + ); + } + if (isGenericTupleType(t)) { + return instantiateMappedGenericTupleType(t, type, typeVariable, mapper); + } + if (isTupleType(t)) { + return instantiateMappedTupleType( + t, + type, + prependTypeMapping(typeVariable, t, mapper), + ); + } } + return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper)); } - return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper)); - } - return t; - }, aliasSymbol, aliasTypeArguments); + return t; + }, + aliasSymbol, + aliasTypeArguments, + ); } } // If the constraint type of the instantiation is the wildcard type, return the wildcard type. - return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments); + return instantiateType(getConstraintTypeFromMappedType(type), mapper) === wildcardType ? wildcardType + : instantiateAnonymousType(type, mapper, aliasSymbol, aliasTypeArguments); } function getModifiedReadonlyState(state: boolean, modifiers: MappedTypeModifiers) { - return modifiers & MappedTypeModifiers.IncludeReadonly ? true : modifiers & MappedTypeModifiers.ExcludeReadonly ? false : state; + return modifiers & MappedTypeModifiers.IncludeReadonly ? true + : modifiers & MappedTypeModifiers.ExcludeReadonly ? false : state; } - function instantiateMappedGenericTupleType(tupleType: TupleTypeReference, mappedType: MappedType, typeVariable: TypeVariable, mapper: TypeMapper) { + function instantiateMappedGenericTupleType( + tupleType: TupleTypeReference, + mappedType: MappedType, + typeVariable: TypeVariable, + mapper: TypeMapper, + ) { // When a tuple type is generic (i.e. when it contains variadic elements), we want to eagerly map the // non-generic elements and defer mapping the generic elements. In order to facilitate this, we transform // M<[A, B?, ...T, ...C[]] into [...M<[A]>, ...M<[B?]>, ...M, ...M] and then rely on tuple type // normalization to resolve the non-generic parts of the resulting tuple. const elementFlags = tupleType.target.elementFlags; const elementTypes = map(getElementTypes(tupleType), (t, i) => { - const singleton = elementFlags[i] & ElementFlags.Variadic ? t : - elementFlags[i] & ElementFlags.Rest ? createArrayType(t) : - createTupleType([t], [elementFlags[i]]); + const singleton = elementFlags[i] & ElementFlags.Variadic ? t + : elementFlags[i] & ElementFlags.Rest ? createArrayType(t) + : createTupleType([t], [elementFlags[i]]); // avoid infinite recursion, if the singleton is the type variable itself // then we'd just get back here with the same arguments from within instantiateMappedType if (singleton === typeVariable) { @@ -19031,34 +24438,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function instantiateMappedArrayType(arrayType: Type, mappedType: MappedType, mapper: TypeMapper) { const elementType = instantiateMappedTypeTemplate(mappedType, numberType, /*isOptional*/ true, mapper); - return isErrorType(elementType) ? errorType : - createArrayType(elementType, getModifiedReadonlyState(isReadonlyArrayType(arrayType), getMappedTypeModifiers(mappedType))); + return isErrorType(elementType) ? errorType + : createArrayType( + elementType, + getModifiedReadonlyState(isReadonlyArrayType(arrayType), getMappedTypeModifiers(mappedType)), + ); } function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) { const elementFlags = tupleType.target.elementFlags; - const elementTypes = map(getElementTypes(tupleType), (_, i) => - instantiateMappedTypeTemplate(mappedType, getStringLiteralType("" + i), !!(elementFlags[i] & ElementFlags.Optional), mapper)); + const elementTypes = map( + getElementTypes(tupleType), + (_, i) => + instantiateMappedTypeTemplate( + mappedType, + getStringLiteralType("" + i), + !!(elementFlags[i] & ElementFlags.Optional), + mapper, + ), + ); const modifiers = getMappedTypeModifiers(mappedType); - const newTupleModifiers = modifiers & MappedTypeModifiers.IncludeOptional ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) : - modifiers & MappedTypeModifiers.ExcludeOptional ? map(elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) : - elementFlags; + const newTupleModifiers = modifiers & MappedTypeModifiers.IncludeOptional + ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) + : modifiers & MappedTypeModifiers.ExcludeOptional + ? map(elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) + : elementFlags; const newReadonly = getModifiedReadonlyState(tupleType.target.readonly, modifiers); - return contains(elementTypes, errorType) ? errorType : - createTupleType(elementTypes, newTupleModifiers, newReadonly, tupleType.target.labeledElementDeclarations); + return contains(elementTypes, errorType) ? errorType + : createTupleType( + elementTypes, + newTupleModifiers, + newReadonly, + tupleType.target.labeledElementDeclarations, + ); } function instantiateMappedTypeTemplate(type: MappedType, key: Type, isOptional: boolean, mapper: TypeMapper) { const templateMapper = appendTypeMapping(mapper, getTypeParameterFromMappedType(type), key); - const propType = instantiateType(getTemplateTypeFromMappedType(type.target as MappedType || type), templateMapper); + const propType = instantiateType( + getTemplateTypeFromMappedType(type.target as MappedType || type), + templateMapper, + ); const modifiers = getMappedTypeModifiers(type); - return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType, /*isProperty*/ true) : - strictNullChecks && modifiers & MappedTypeModifiers.ExcludeOptional && isOptional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) : - propType; - } - - function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): AnonymousType { - const result = createObjectType(type.objectFlags & ~(ObjectFlags.CouldContainTypeVariablesComputed | ObjectFlags.CouldContainTypeVariables) | ObjectFlags.Instantiated, type.symbol) as AnonymousType; + return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional + && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) + ? getOptionalType(propType, /*isProperty*/ true) + : strictNullChecks && modifiers & MappedTypeModifiers.ExcludeOptional && isOptional + ? getTypeWithFacts(propType, TypeFacts.NEUndefined) + : propType; + } + + function instantiateAnonymousType( + type: AnonymousType, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): AnonymousType { + const result = createObjectType( + type.objectFlags & ~(ObjectFlags.CouldContainTypeVariablesComputed | ObjectFlags.CouldContainTypeVariables) + | ObjectFlags.Instantiated, + type.symbol, + ) as AnonymousType; if (type.objectFlags & ObjectFlags.Mapped) { (result as MappedType).declaration = (type as MappedType).declaration; // C.f. instantiateSignature @@ -19074,12 +24514,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result.target = type; result.mapper = mapper; result.aliasSymbol = aliasSymbol || type.aliasSymbol; - result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); + result.aliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); result.objectFlags |= result.aliasTypeArguments ? getPropagatingFlagsOfTypes(result.aliasTypeArguments) : 0; return result; } - function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { + function getConditionalTypeInstantiation( + type: ConditionalType, + mapper: TypeMapper, + aliasSymbol?: Symbol, + aliasTypeArguments?: readonly Type[], + ): Type { const root = type.root; if (root.outerTypeParameters) { // We are instantiating a conditional type that has one or more type parameters in scope. Apply the @@ -19095,9 +24541,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Distributive conditional types are distributed over union types. For example, when the // distributive conditional type T extends U ? X : Y is instantiated with A | B for T, the // result is (A extends U ? X : Y) | (B extends U ? X : Y). - result = distributionType && checkType !== distributionType && distributionType.flags & (TypeFlags.Union | TypeFlags.Never) ? - mapTypeWithAlias(getReducedType(distributionType), t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper)), aliasSymbol, aliasTypeArguments) : - getConditionalType(root, newMapper, aliasSymbol, aliasTypeArguments); + result = distributionType && checkType !== distributionType + && distributionType.flags & (TypeFlags.Union | TypeFlags.Never) + ? mapTypeWithAlias( + getReducedType(distributionType), + t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper)), + aliasSymbol, + aliasTypeArguments, + ) + : getConditionalType(root, newMapper, aliasSymbol, aliasTypeArguments); root.instantiations!.set(id, result); } return result; @@ -19108,10 +24560,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function instantiateType(type: Type, mapper: TypeMapper | undefined): Type; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { - return type && mapper ? instantiateTypeWithAlias(type, mapper, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined) : type; + return type && mapper + ? instantiateTypeWithAlias(type, mapper, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined) + : type; } - function instantiateTypeWithAlias(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { + function instantiateTypeWithAlias( + type: Type, + mapper: TypeMapper, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + ): Type { if (!couldContainTypeVariables(type)) { return type; } @@ -19119,7 +24578,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We have reached 100 recursive type instantiations, or 5M type instantiations caused by the same statement // or expression. There is a very high likelyhood we're dealing with a combination of infinite generic types // that perpetually generate new type identities, so we stop the recursion here by yielding the error type. - tracing?.instant(tracing.Phase.CheckTypes, "instantiateType_DepthLimit", { typeId: type.id, instantiationDepth, instantiationCount }); + tracing?.instant(tracing.Phase.CheckTypes, "instantiateType_DepthLimit", { + typeId: type.id, + instantiationDepth, + instantiationCount, + }); error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite); return errorType; } @@ -19131,7 +24594,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function instantiateTypeWorker(type: Type, mapper: TypeMapper, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined): Type { + function instantiateTypeWorker( + type: Type, + mapper: TypeMapper, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + ): Type { const flags = type.flags; if (flags & TypeFlags.TypeParameter) { return getMappedType(type, mapper); @@ -19142,44 +24610,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (objectFlags & ObjectFlags.Reference && !(type as TypeReference).node) { const resolvedTypeArguments = (type as TypeReference).resolvedTypeArguments; const newTypeArguments = instantiateTypes(resolvedTypeArguments, mapper); - return newTypeArguments !== resolvedTypeArguments ? createNormalizedTypeReference((type as TypeReference).target, newTypeArguments) : type; + return newTypeArguments !== resolvedTypeArguments + ? createNormalizedTypeReference((type as TypeReference).target, newTypeArguments) : type; } if (objectFlags & ObjectFlags.ReverseMapped) { return instantiateReverseMappedType(type as ReverseMappedType, mapper); } - return getObjectTypeInstantiation(type as TypeReference | AnonymousType | MappedType, mapper, aliasSymbol, aliasTypeArguments); + return getObjectTypeInstantiation( + type as TypeReference | AnonymousType | MappedType, + mapper, + aliasSymbol, + aliasTypeArguments, + ); } return type; } if (flags & TypeFlags.UnionOrIntersection) { const origin = type.flags & TypeFlags.Union ? (type as UnionType).origin : undefined; - const types = origin && origin.flags & TypeFlags.UnionOrIntersection ? (origin as UnionOrIntersectionType).types : (type as UnionOrIntersectionType).types; + const types = origin && origin.flags & TypeFlags.UnionOrIntersection + ? (origin as UnionOrIntersectionType).types : (type as UnionOrIntersectionType).types; const newTypes = instantiateTypes(types, mapper); if (newTypes === types && aliasSymbol === type.aliasSymbol) { return type; } const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - return flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection ? - getIntersectionType(newTypes, newAliasSymbol, newAliasTypeArguments) : - getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments); + const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); + return flags & TypeFlags.Intersection || origin && origin.flags & TypeFlags.Intersection + ? getIntersectionType(newTypes, newAliasSymbol, newAliasTypeArguments) + : getUnionType(newTypes, UnionReduction.Literal, newAliasSymbol, newAliasTypeArguments); } if (flags & TypeFlags.Index) { return getIndexType(instantiateType((type as IndexType).type, mapper)); } if (flags & TypeFlags.TemplateLiteral) { - return getTemplateLiteralType((type as TemplateLiteralType).texts, instantiateTypes((type as TemplateLiteralType).types, mapper)); + return getTemplateLiteralType( + (type as TemplateLiteralType).texts, + instantiateTypes((type as TemplateLiteralType).types, mapper), + ); } if (flags & TypeFlags.StringMapping) { - return getStringMappingType((type as StringMappingType).symbol, instantiateType((type as StringMappingType).type, mapper)); + return getStringMappingType( + (type as StringMappingType).symbol, + instantiateType((type as StringMappingType).type, mapper), + ); } if (flags & TypeFlags.IndexedAccess) { const newAliasSymbol = aliasSymbol || type.aliasSymbol; - const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper); - return getIndexedAccessType(instantiateType((type as IndexedAccessType).objectType, mapper), instantiateType((type as IndexedAccessType).indexType, mapper), (type as IndexedAccessType).accessFlags, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments); + const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments + : instantiateTypes(type.aliasTypeArguments, mapper); + return getIndexedAccessType( + instantiateType((type as IndexedAccessType).objectType, mapper), + instantiateType((type as IndexedAccessType).indexType, mapper), + (type as IndexedAccessType).accessFlags, + /*accessNode*/ undefined, + newAliasSymbol, + newAliasTypeArguments, + ); } if (flags & TypeFlags.Conditional) { - return getConditionalTypeInstantiation(type as ConditionalType, combineTypeMappers((type as ConditionalType).mapper, mapper), aliasSymbol, aliasTypeArguments); + return getConditionalTypeInstantiation( + type as ConditionalType, + combineTypeMappers((type as ConditionalType).mapper, mapper), + aliasSymbol, + aliasTypeArguments, + ); } if (flags & TypeFlags.Substitution) { const newBaseType = instantiateType((type as SubstitutionType).baseType, mapper); @@ -19190,10 +24685,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (newBaseType.flags & TypeFlags.TypeVariable && isGenericType(newConstraint)) { return getSubstitutionType(newBaseType, newConstraint); } - if (newConstraint.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(newBaseType), getRestrictiveInstantiation(newConstraint))) { + if ( + newConstraint.flags & TypeFlags.AnyOrUnknown + || isTypeAssignableTo( + getRestrictiveInstantiation(newBaseType), + getRestrictiveInstantiation(newConstraint), + ) + ) { return newBaseType; } - return newBaseType.flags & TypeFlags.TypeVariable ? getSubstitutionType(newBaseType, newConstraint) : getIntersectionType([newConstraint, newBaseType]); + return newBaseType.flags & TypeFlags.TypeVariable ? getSubstitutionType(newBaseType, newConstraint) + : getIntersectionType([newConstraint, newBaseType]); } return type; } @@ -19210,7 +24712,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const instantiated = inferTypeForHomomorphicMappedType( instantiateType(type.source, mapper), innerMappedType as MappedType, - innerIndexType as IndexType + innerIndexType as IndexType, ); if (instantiated) { return instantiated; @@ -19219,8 +24721,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getPermissiveInstantiation(type: Type) { - return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type : - type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper)); + return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type + : type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper)); } function getRestrictiveInstantiation(type: Type) { @@ -19246,30 +24748,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Returns true if the given expression contains (at any level of nesting) a function or arrow expression // that is subject to contextual typing. - function isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike | JsxChild): boolean { + function isContextSensitive( + node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike | JsxChild, + ): boolean { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); switch (node.kind) { case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: case SyntaxKind.MethodDeclaration: case SyntaxKind.FunctionDeclaration: // Function declarations can have context when annotated with a jsdoc @type - return isContextSensitiveFunctionLikeDeclaration(node as FunctionExpression | ArrowFunction | MethodDeclaration); + return isContextSensitiveFunctionLikeDeclaration( + node as FunctionExpression | ArrowFunction | MethodDeclaration, + ); case SyntaxKind.ObjectLiteralExpression: return some((node as ObjectLiteralExpression).properties, isContextSensitive); case SyntaxKind.ArrayLiteralExpression: return some((node as ArrayLiteralExpression).elements, isContextSensitive); case SyntaxKind.ConditionalExpression: - return isContextSensitive((node as ConditionalExpression).whenTrue) || - isContextSensitive((node as ConditionalExpression).whenFalse); + return isContextSensitive((node as ConditionalExpression).whenTrue) + || isContextSensitive((node as ConditionalExpression).whenFalse); case SyntaxKind.BinaryExpression: - return ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken || (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken) && - (isContextSensitive((node as BinaryExpression).left) || isContextSensitive((node as BinaryExpression).right)); + return ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken + || (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken) + && (isContextSensitive((node as BinaryExpression).left) + || isContextSensitive((node as BinaryExpression).right)); case SyntaxKind.PropertyAssignment: return isContextSensitive((node as PropertyAssignment).initializer); case SyntaxKind.ParenthesizedExpression: return isContextSensitive((node as ParenthesizedExpression).expression); case SyntaxKind.JsxAttributes: - return some((node as JsxAttributes).properties, isContextSensitive) || isJsxOpeningElement(node.parent) && some(node.parent.parent.children, isContextSensitive); + return some((node as JsxAttributes).properties, isContextSensitive) + || isJsxOpeningElement(node.parent) && some(node.parent.parent.children, isContextSensitive); case SyntaxKind.JsxAttribute: { // If there is no initializer, JSX attribute has a boolean value of true which is not context sensitive. const { initializer } = node as JsxAttribute; @@ -19296,12 +24805,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.body.kind !== SyntaxKind.Block) { return isContextSensitive(node.body); } - return !!forEachReturnStatement(node.body as Block, (statement) => !!statement.expression && isContextSensitive(statement.expression)); + return !!forEachReturnStatement( + node.body as Block, + statement => !!statement.expression && isContextSensitive(statement.expression), + ); } - function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { - return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && - isContextSensitiveFunctionLikeDeclaration(func); + function isContextSensitiveFunctionOrObjectLiteralMethod( + func: Node, + ): func is FunctionExpression | ArrowFunction | MethodDeclaration { + return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) + && isContextSensitiveFunctionLikeDeclaration(func); } function getTypeWithoutSignatures(type: Type): Type { @@ -19364,14 +24878,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Note that this check ignores type parameters and only considers the // inheritance hierarchy. function isTypeDerivedFrom(source: Type, target: Type): boolean { - return source.flags & TypeFlags.Union ? every((source as UnionType).types, t => isTypeDerivedFrom(t, target)) : - target.flags & TypeFlags.Union ? some((target as UnionType).types, t => isTypeDerivedFrom(source, t)) : - source.flags & TypeFlags.Intersection ? some((source as IntersectionType).types, t => isTypeDerivedFrom(t, target)) : - source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) : - isEmptyAnonymousObjectType(target) ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) : - target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) && !isEmptyAnonymousObjectType(source) : - target === globalFunctionType ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) : - hasBaseType(source, getTargetType(target)) || (isArrayType(target) && !isReadonlyArrayType(target) && isTypeDerivedFrom(source, globalReadonlyArrayType)); + return source.flags & TypeFlags.Union ? every((source as UnionType).types, t => isTypeDerivedFrom(t, target)) + : target.flags & TypeFlags.Union ? some((target as UnionType).types, t => isTypeDerivedFrom(source, t)) + : source.flags & TypeFlags.Intersection + ? some((source as IntersectionType).types, t => isTypeDerivedFrom(t, target)) + : source.flags & TypeFlags.InstantiableNonPrimitive + ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) + : isEmptyAnonymousObjectType(target) ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) + : target === globalObjectType + ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) && !isEmptyAnonymousObjectType(source) + : target === globalFunctionType + ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) + : hasBaseType(source, getTargetType(target)) + || (isArrayType(target) && !isReadonlyArrayType(target) + && isTypeDerivedFrom(source, globalReadonlyArrayType)); } /** @@ -19392,16 +24912,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isTypeComparableTo(type1, type2) || isTypeComparableTo(type2, type1); } - function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined, errorOutputObject?: { errors?: Diagnostic[] }): boolean { - return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain, errorOutputObject); + function checkTypeAssignableTo( + source: Type, + target: Type, + errorNode: Node | undefined, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined, + errorOutputObject?: { errors?: Diagnostic[]; }, + ): boolean { + return checkTypeRelatedTo( + source, + target, + assignableRelation, + errorNode, + headMessage, + containingMessageChain, + errorOutputObject, + ); } /** * Like `checkTypeAssignableTo`, but if it would issue an error, instead performs structural comparisons of the types using the given expression node to * attempt to issue more specific errors on, for example, specific object literal properties or tuple members. */ - function checkTypeAssignableToAndOptionallyElaborate(source: Type, target: Type, errorNode: Node | undefined, expr: Expression | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean { - return checkTypeRelatedToAndOptionallyElaborate(source, target, assignableRelation, errorNode, expr, headMessage, containingMessageChain, /*errorOutputContainer*/ undefined); + function checkTypeAssignableToAndOptionallyElaborate( + source: Type, + target: Type, + errorNode: Node | undefined, + expr: Expression | undefined, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined, + ): boolean { + return checkTypeRelatedToAndOptionallyElaborate( + source, + target, + assignableRelation, + errorNode, + expr, + headMessage, + containingMessageChain, + /*errorOutputContainer*/ undefined, + ); } function checkTypeRelatedToAndOptionallyElaborate( @@ -19412,17 +24963,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { expr: Expression | undefined, headMessage: DiagnosticMessage | undefined, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ): boolean { if (isTypeRelatedTo(source, target, relation)) return true; - if (!errorNode || !elaborateError(expr, source, target, relation, headMessage, containingMessageChain, errorOutputContainer)) { - return checkTypeRelatedTo(source, target, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer); + if ( + !errorNode + || !elaborateError( + expr, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer, + ) + ) { + return checkTypeRelatedTo( + source, + target, + relation, + errorNode, + headMessage, + containingMessageChain, + errorOutputContainer, + ); } return false; } function isOrHasGenericConditional(type: Type): boolean { - return !!(type.flags & TypeFlags.Conditional || (type.flags & TypeFlags.Intersection && some((type as IntersectionType).types, isOrHasGenericConditional))); + return !!(type.flags & TypeFlags.Conditional + || (type.flags & TypeFlags.Intersection + && some((type as IntersectionType).types, isOrHasGenericConditional))); } function elaborateError( @@ -19432,11 +25004,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { relation: Map, headMessage: DiagnosticMessage | undefined, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ): boolean { if (!node || isOrHasGenericConditional(target)) return false; - if (!checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined) - && elaborateDidYouMeanToCallOrConstruct(node, source, target, relation, headMessage, containingMessageChain, errorOutputContainer)) { + if ( + !checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined) + && elaborateDidYouMeanToCallOrConstruct( + node, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer, + ) + ) { return true; } switch (node.kind) { @@ -19447,22 +25029,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // fallthrough case SyntaxKind.JsxExpression: case SyntaxKind.ParenthesizedExpression: - return elaborateError((node as AsExpression | ParenthesizedExpression | JsxExpression).expression, source, target, relation, headMessage, containingMessageChain, errorOutputContainer); + return elaborateError( + (node as AsExpression | ParenthesizedExpression | JsxExpression).expression, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer, + ); case SyntaxKind.BinaryExpression: switch ((node as BinaryExpression).operatorToken.kind) { case SyntaxKind.EqualsToken: case SyntaxKind.CommaToken: - return elaborateError((node as BinaryExpression).right, source, target, relation, headMessage, containingMessageChain, errorOutputContainer); + return elaborateError( + (node as BinaryExpression).right, + source, + target, + relation, + headMessage, + containingMessageChain, + errorOutputContainer, + ); } break; case SyntaxKind.ObjectLiteralExpression: - return elaborateObjectLiteral(node as ObjectLiteralExpression, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateObjectLiteral( + node as ObjectLiteralExpression, + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); case SyntaxKind.ArrayLiteralExpression: - return elaborateArrayLiteral(node as ArrayLiteralExpression, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateArrayLiteral( + node as ArrayLiteralExpression, + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); case SyntaxKind.JsxAttributes: - return elaborateJsxComponents(node as JsxAttributes, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateJsxComponents( + node as JsxAttributes, + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); case SyntaxKind.ArrowFunction: - return elaborateArrowFunction(node as ArrowFunction, source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateArrowFunction( + node as ArrowFunction, + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); } return false; } @@ -19474,22 +25100,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { relation: Map, headMessage: DiagnosticMessage | undefined, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ): boolean { const callSignatures = getSignaturesOfType(source, SignatureKind.Call); const constructSignatures = getSignaturesOfType(source, SignatureKind.Construct); for (const signatures of [constructSignatures, callSignatures]) { - if (some(signatures, s => { - const returnType = getReturnTypeOfSignature(s); - return !(returnType.flags & (TypeFlags.Any | TypeFlags.Never)) && checkTypeRelatedTo(returnType, target, relation, /*errorNode*/ undefined); - })) { - const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {}; + if ( + some(signatures, s => { + const returnType = getReturnTypeOfSignature(s); + return !(returnType.flags & (TypeFlags.Any | TypeFlags.Never)) + && checkTypeRelatedTo(returnType, target, relation, /*errorNode*/ undefined); + }) + ) { + const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; checkTypeAssignableTo(source, target, node, headMessage, containingMessageChain, resultObj); const diagnostic = resultObj.errors![resultObj.errors!.length - 1]; - addRelatedInfo(diagnostic, createDiagnosticForNode( - node, - signatures === constructSignatures ? Diagnostics.Did_you_mean_to_use_new_with_this_expression : Diagnostics.Did_you_mean_to_call_this_expression - )); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + node, + signatures === constructSignatures ? Diagnostics.Did_you_mean_to_use_new_with_this_expression + : Diagnostics.Did_you_mean_to_call_this_expression, + ), + ); return true; } } @@ -19502,7 +25135,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: Type, relation: Map, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ): boolean { // Don't elaborate blocks if (isBlock(node.body)) { @@ -19524,29 +25157,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceReturn = getReturnTypeOfSignature(sourceSig); const targetReturn = getUnionType(map(targetSignatures, getReturnTypeOfSignature)); if (!checkTypeRelatedTo(sourceReturn, targetReturn, relation, /*errorNode*/ undefined)) { - const elaborated = returnExpression && elaborateError(returnExpression, sourceReturn, targetReturn, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + const elaborated = returnExpression + && elaborateError( + returnExpression, + sourceReturn, + targetReturn, + relation, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer, + ); if (elaborated) { return elaborated; } - const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {}; - checkTypeRelatedTo(sourceReturn, targetReturn, relation, returnExpression, /*headMessage*/ undefined, containingMessageChain, resultObj); + const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; + checkTypeRelatedTo( + sourceReturn, + targetReturn, + relation, + returnExpression, + /*headMessage*/ undefined, + containingMessageChain, + resultObj, + ); if (resultObj.errors) { if (target.symbol && length(target.symbol.declarations)) { - addRelatedInfo(resultObj.errors[resultObj.errors.length - 1], createDiagnosticForNode( - target.symbol.declarations![0], - Diagnostics.The_expected_type_comes_from_the_return_type_of_this_signature, - )); + addRelatedInfo( + resultObj.errors[resultObj.errors.length - 1], + createDiagnosticForNode( + target.symbol.declarations![0], + Diagnostics.The_expected_type_comes_from_the_return_type_of_this_signature, + ), + ); } - if ((getFunctionFlags(node) & FunctionFlags.Async) === 0 + if ( + (getFunctionFlags(node) & FunctionFlags.Async) === 0 // exclude cases where source itself is promisy - this way we don't make a suggestion when relating // an IPromise and a Promise that are slightly different && !getTypeOfPropertyOfType(sourceReturn, "then" as __String) - && checkTypeRelatedTo(createPromiseType(sourceReturn), targetReturn, relation, /*errorNode*/ undefined) + && checkTypeRelatedTo( + createPromiseType(sourceReturn), + targetReturn, + relation, + /*errorNode*/ undefined, + ) ) { - addRelatedInfo(resultObj.errors[resultObj.errors.length - 1], createDiagnosticForNode( - node, - Diagnostics.Did_you_mean_to_mark_this_function_as_async - )); + addRelatedInfo( + resultObj.errors[resultObj.errors.length - 1], + createDiagnosticForNode( + node, + Diagnostics.Did_you_mean_to_mark_this_function_as_async, + ), + ); } return true; } @@ -19574,7 +25236,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - type ElaborationIterator = IterableIterator<{ errorNode: Node, innerExpression: Expression | undefined, nameType: Type, errorMessage?: DiagnosticMessage | undefined }>; + type ElaborationIterator = IterableIterator< + { + errorNode: Node; + innerExpression: Expression | undefined; + nameType: Type; + errorMessage?: DiagnosticMessage | undefined; + } + >; /** * For every element returned from the iterator, checks that element to issue an error on a property of that element's type * If that element would issue an error, we first attempt to dive into that element's inner expression and issue a more specific error by recuring into `elaborateError` @@ -19586,7 +25255,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: Type, relation: Map, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ) { // Assignability failure - check each prop individually, and if that fails, fall back on the bad error span let reportedError = false; @@ -19598,52 +25267,107 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!sourcePropType) continue; const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined); if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) { - const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + const elaborated = next + && elaborateError( + next, + sourcePropType, + targetPropType, + relation, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer, + ); reportedError = true; if (!elaborated) { // Issue error on the prop itself, since the prop couldn't elaborate the error - const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {}; + const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; // Use the expression type, if available - const specificSource = next ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType; + const specificSource = next + ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType; if (exactOptionalPropertyTypes && isExactOptionalPropertyMismatch(specificSource, targetPropType)) { - const diag = createDiagnosticForNode(prop, Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, typeToString(specificSource), typeToString(targetPropType)); + const diag = createDiagnosticForNode( + prop, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, + typeToString(specificSource), + typeToString(targetPropType), + ); diagnostics.add(diag); resultObj.errors = [diag]; } else { - const targetIsOptional = !!(propName && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional); - const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); + const targetIsOptional = !!(propName + && (getPropertyOfType(target, propName) || unknownSymbol).flags & SymbolFlags.Optional); + const sourceIsOptional = !!(propName + && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); targetPropType = removeMissingType(targetPropType, targetIsOptional); sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional); - const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + const result = checkTypeRelatedTo( + specificSource, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj, + ); if (result && specificSource !== sourcePropType) { // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType - checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + checkTypeRelatedTo( + sourcePropType, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj, + ); } } if (resultObj.errors) { const reportedDiag = resultObj.errors[resultObj.errors.length - 1]; - const propertyName = isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) : undefined; - const targetProp = propertyName !== undefined ? getPropertyOfType(target, propertyName) : undefined; + const propertyName = isTypeUsableAsPropertyName(nameType) ? getPropertyNameFromType(nameType) + : undefined; + const targetProp = propertyName !== undefined ? getPropertyOfType(target, propertyName) + : undefined; let issuedElaboration = false; if (!targetProp) { const indexInfo = getApplicableIndexInfo(target, nameType); - if (indexInfo && indexInfo.declaration && !getSourceFileOfNode(indexInfo.declaration).hasNoDefaultLib) { + if ( + indexInfo && indexInfo.declaration + && !getSourceFileOfNode(indexInfo.declaration).hasNoDefaultLib + ) { issuedElaboration = true; - addRelatedInfo(reportedDiag, createDiagnosticForNode(indexInfo.declaration, Diagnostics.The_expected_type_comes_from_this_index_signature)); + addRelatedInfo( + reportedDiag, + createDiagnosticForNode( + indexInfo.declaration, + Diagnostics.The_expected_type_comes_from_this_index_signature, + ), + ); } } - if (!issuedElaboration && (targetProp && length(targetProp.declarations) || target.symbol && length(target.symbol.declarations))) { - const targetNode = targetProp && length(targetProp.declarations) ? targetProp.declarations![0] : target.symbol.declarations![0]; + if ( + !issuedElaboration + && (targetProp && length(targetProp.declarations) + || target.symbol && length(target.symbol.declarations)) + ) { + const targetNode = targetProp && length(targetProp.declarations) + ? targetProp.declarations![0] : target.symbol.declarations![0]; if (!getSourceFileOfNode(targetNode).hasNoDefaultLib) { - addRelatedInfo(reportedDiag, createDiagnosticForNode( - targetNode, - Diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1, - propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType), - typeToString(target) - )); + addRelatedInfo( + reportedDiag, + createDiagnosticForNode( + targetNode, + Diagnostics + .The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1, + propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) + ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType), + typeToString(target), + ), + ); } } } @@ -19663,49 +25387,91 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: Type, relation: Map, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ) { const tupleOrArrayLikeTargetParts = filterType(target, isArrayOrTupleLikeType); const nonTupleOrArrayLikeTargetParts = filterType(target, t => !isArrayOrTupleLikeType(t)); // If `nonTupleOrArrayLikeTargetParts` is not `never`, then that should mean `Iterable` is defined. const iterationType = nonTupleOrArrayLikeTargetParts !== neverType - ? getIterationTypeOfIterable(IterationUse.ForOf, IterationTypeKind.Yield, nonTupleOrArrayLikeTargetParts, /*errorNode*/ undefined) + ? getIterationTypeOfIterable( + IterationUse.ForOf, + IterationTypeKind.Yield, + nonTupleOrArrayLikeTargetParts, + /*errorNode*/ undefined, + ) : undefined; let reportedError = false; for (let status = iterator.next(); !status.done; status = iterator.next()) { const { errorNode: prop, innerExpression: next, nameType, errorMessage } = status.value; let targetPropType = iterationType; - const targetIndexedPropType = tupleOrArrayLikeTargetParts !== neverType ? getBestMatchIndexedAccessTypeOrUndefined(source, tupleOrArrayLikeTargetParts, nameType) : undefined; - if (targetIndexedPropType && !(targetIndexedPropType.flags & TypeFlags.IndexedAccess)) { // Don't elaborate on indexes on generic variables - targetPropType = iterationType ? getUnionType([iterationType, targetIndexedPropType]) : targetIndexedPropType; + const targetIndexedPropType = tupleOrArrayLikeTargetParts !== neverType + ? getBestMatchIndexedAccessTypeOrUndefined(source, tupleOrArrayLikeTargetParts, nameType) : undefined; + if (targetIndexedPropType && !(targetIndexedPropType.flags & TypeFlags.IndexedAccess)) { // Don't elaborate on indexes on generic variables + targetPropType = iterationType ? getUnionType([iterationType, targetIndexedPropType]) + : targetIndexedPropType; } if (!targetPropType) continue; let sourcePropType = getIndexedAccessTypeOrUndefined(source, nameType); if (!sourcePropType) continue; const propName = getPropertyNameFromIndex(nameType, /*accessNode*/ undefined); if (!checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) { - const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined, containingMessageChain, errorOutputContainer); + const elaborated = next + && elaborateError( + next, + sourcePropType, + targetPropType, + relation, + /*headMessage*/ undefined, + containingMessageChain, + errorOutputContainer, + ); reportedError = true; if (!elaborated) { // Issue error on the prop itself, since the prop couldn't elaborate the error - const resultObj: { errors?: Diagnostic[] } = errorOutputContainer || {}; + const resultObj: { errors?: Diagnostic[]; } = errorOutputContainer || {}; // Use the expression type, if available - const specificSource = next ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType; + const specificSource = next + ? checkExpressionForMutableLocationWithContextualType(next, sourcePropType) : sourcePropType; if (exactOptionalPropertyTypes && isExactOptionalPropertyMismatch(specificSource, targetPropType)) { - const diag = createDiagnosticForNode(prop, Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, typeToString(specificSource), typeToString(targetPropType)); + const diag = createDiagnosticForNode( + prop, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target, + typeToString(specificSource), + typeToString(targetPropType), + ); diagnostics.add(diag); resultObj.errors = [diag]; } else { - const targetIsOptional = !!(propName && (getPropertyOfType(tupleOrArrayLikeTargetParts, propName) || unknownSymbol).flags & SymbolFlags.Optional); - const sourceIsOptional = !!(propName && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); + const targetIsOptional = !!(propName + && (getPropertyOfType(tupleOrArrayLikeTargetParts, propName) || unknownSymbol).flags + & SymbolFlags.Optional); + const sourceIsOptional = !!(propName + && (getPropertyOfType(source, propName) || unknownSymbol).flags & SymbolFlags.Optional); targetPropType = removeMissingType(targetPropType, targetIsOptional); sourcePropType = removeMissingType(sourcePropType, targetIsOptional && sourceIsOptional); - const result = checkTypeRelatedTo(specificSource, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + const result = checkTypeRelatedTo( + specificSource, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj, + ); if (result && specificSource !== sourcePropType) { // If for whatever reason the expression type doesn't yield an error, make sure we still issue an error on the sourcePropType - checkTypeRelatedTo(sourcePropType, targetPropType, relation, prop, errorMessage, containingMessageChain, resultObj); + checkTypeRelatedTo( + sourcePropType, + targetPropType, + relation, + prop, + errorMessage, + containingMessageChain, + resultObj, + ); } } } @@ -19714,16 +25480,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return reportedError; } - - function *generateJsxAttributes(node: JsxAttributes): ElaborationIterator { + function* generateJsxAttributes(node: JsxAttributes): ElaborationIterator { if (!length(node.properties)) return; for (const prop of node.properties) { if (isJsxSpreadAttribute(prop) || isHyphenatedJsxName(getTextOfJsxAttributeName(prop.name))) continue; - yield { errorNode: prop.name, innerExpression: prop.initializer, nameType: getStringLiteralType(getTextOfJsxAttributeName(prop.name)) }; + yield { + errorNode: prop.name, + innerExpression: prop.initializer, + nameType: getStringLiteralType(getTextOfJsxAttributeName(prop.name)), + }; } } - function *generateJsxChildren(node: JsxElement, getInvalidTextDiagnostic: () => DiagnosticMessage): ElaborationIterator { + function* generateJsxChildren( + node: JsxElement, + getInvalidTextDiagnostic: () => DiagnosticMessage, + ): ElaborationIterator { if (!length(node.children)) return; let memberOffset = 0; for (let i = 0; i < node.children.length; i++) { @@ -19739,7 +25511,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getElaborationElementForJsxChild(child: JsxChild, nameType: LiteralType, getInvalidTextDiagnostic: () => DiagnosticMessage) { + function getElaborationElementForJsxChild( + child: JsxChild, + nameType: LiteralType, + getInvalidTextDiagnostic: () => DiagnosticMessage, + ) { switch (child.kind) { case SyntaxKind.JsxExpression: // child is of the type of the expression @@ -19749,7 +25525,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; // Whitespace only jsx text isn't real jsx text } // child is a string - return { errorNode: child, innerExpression: undefined, nameType, errorMessage: getInvalidTextDiagnostic() }; + return { + errorNode: child, + innerExpression: undefined, + nameType, + errorMessage: getInvalidTextDiagnostic(), + }; case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxFragment: @@ -19766,14 +25547,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: Type, relation: Map, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ) { - let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation, containingMessageChain, errorOutputContainer); + let result = elaborateElementwise( + generateJsxAttributes(node), + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); let invalidTextDiagnostic: DiagnosticMessage | undefined; if (isJsxOpeningElement(node.parent) && isJsxElement(node.parent.parent)) { const containingElement = node.parent.parent; const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName); + const childrenPropName = childPropName === undefined ? "children" + : unescapeLeadingUnderscores(childPropName); const childrenNameType = getStringLiteralType(childrenPropName); const childrenTargetType = getIndexedAccessType(target, childrenNameType); const validChildren = getSemanticJsxChildren(containingElement.children); @@ -19797,16 +25586,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (arrayLikeTargetParts !== neverType) { const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal)); const children = generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic); - result = elaborateIterableOrArrayLikeTargetElementwise(children, realSource, arrayLikeTargetParts, relation, containingMessageChain, errorOutputContainer) || result; - } - else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) { + result = elaborateIterableOrArrayLikeTargetElementwise( + children, + realSource, + arrayLikeTargetParts, + relation, + containingMessageChain, + errorOutputContainer, + ) || result; + } + else if ( + !isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation) + ) { // arity mismatch result = true; const diag = error( containingElement.openingElement.tagName, - Diagnostics.This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided, + Diagnostics + .This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided, childrenPropName, - typeToString(childrenTargetType) + typeToString(childrenTargetType), ); if (errorOutputContainer && errorOutputContainer.skipLogging) { (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); @@ -19816,26 +25615,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { if (nonArrayLikeTargetParts !== neverType) { const child = validChildren[0]; - const elem = getElaborationElementForJsxChild(child, childrenNameType, getInvalidTextualChildDiagnostic); + const elem = getElaborationElementForJsxChild( + child, + childrenNameType, + getInvalidTextualChildDiagnostic, + ); if (elem) { result = elaborateElementwise( - (function*() { yield elem; })(), + (function* () { + yield elem; + })(), source, target, relation, containingMessageChain, - errorOutputContainer + errorOutputContainer, ) || result; } } - else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) { + else if ( + !isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation) + ) { // arity mismatch result = true; const diag = error( containingElement.openingElement.tagName, - Diagnostics.This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided, + Diagnostics + .This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided, childrenPropName, - typeToString(childrenTargetType) + typeToString(childrenTargetType), ); if (errorOutputContainer && errorOutputContainer.skipLogging) { (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); @@ -19849,16 +25657,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!invalidTextDiagnostic) { const tagNameText = getTextOfNode(node.parent.tagName); const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName); + const childrenPropName = childPropName === undefined ? "children" + : unescapeLeadingUnderscores(childPropName); const childrenTargetType = getIndexedAccessType(target, getStringLiteralType(childrenPropName)); - const diagnostic = Diagnostics._0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2; - invalidTextDiagnostic = { ...diagnostic, key: "!!ALREADY FORMATTED!!", message: formatMessage(diagnostic, tagNameText, childrenPropName, typeToString(childrenTargetType)) }; + const diagnostic = Diagnostics + ._0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2; + invalidTextDiagnostic = { + ...diagnostic, + key: "!!ALREADY FORMATTED!!", + message: formatMessage(diagnostic, tagNameText, childrenPropName, typeToString(childrenTargetType)), + }; } return invalidTextDiagnostic; } } - function *generateLimitedTupleElements(node: ArrayLiteralExpression, target: Type): ElaborationIterator { + function* generateLimitedTupleElements(node: ArrayLiteralExpression, target: Type): ElaborationIterator { const len = length(node.elements); if (!len) return; for (let i = 0; i < len; i++) { @@ -19877,11 +25691,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: Type, relation: Map, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ) { if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false; if (isTupleLikeType(source)) { - return elaborateElementwise(generateLimitedTupleElements(node, target), source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateElementwise( + generateLimitedTupleElements(node, target), + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); } // recreate a tuple from the elements, if possible // Since we're re-doing the expression type, we need to reapply the contextual type @@ -19889,16 +25710,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true); popContextualType(); if (isTupleLikeType(tupleizedType)) { - return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, containingMessageChain, errorOutputContainer); + return elaborateElementwise( + generateLimitedTupleElements(node, target), + tupleizedType, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); } return false; } - function *generateObjectLiteralElements(node: ObjectLiteralExpression): ElaborationIterator { + function* generateObjectLiteralElements(node: ObjectLiteralExpression): ElaborationIterator { if (!length(node.properties)) return; for (const prop of node.properties) { if (isSpreadAssignment(prop)) continue; - const type = getLiteralTypeFromProperty(getSymbolOfDeclaration(prop), TypeFlags.StringOrNumberLiteralOrUnique); + const type = getLiteralTypeFromProperty( + getSymbolOfDeclaration(prop), + TypeFlags.StringOrNumberLiteralOrUnique, + ); if (!type || (type.flags & TypeFlags.Never)) { continue; } @@ -19910,7 +25741,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { yield { errorNode: prop.name, innerExpression: undefined, nameType: type }; break; case SyntaxKind.PropertyAssignment: - yield { errorNode: prop.name, innerExpression: prop.initializer, nameType: type, errorMessage: isComputedNonLiteralName(prop.name) ? Diagnostics.Type_of_computed_property_s_value_is_0_which_is_not_assignable_to_type_1 : undefined }; + yield { + errorNode: prop.name, + innerExpression: prop.initializer, + nameType: type, + errorMessage: isComputedNonLiteralName(prop.name) + ? Diagnostics.Type_of_computed_property_s_value_is_0_which_is_not_assignable_to_type_1 + : undefined, + }; break; default: Debug.assertNever(prop); @@ -19924,25 +25762,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: Type, relation: Map, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } | undefined + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } | undefined, ) { if (target.flags & (TypeFlags.Primitive | TypeFlags.Never)) return false; - return elaborateElementwise(generateObjectLiteralElements(node), source, target, relation, containingMessageChain, errorOutputContainer); + return elaborateElementwise( + generateObjectLiteralElements(node), + source, + target, + relation, + containingMessageChain, + errorOutputContainer, + ); } /** * This is *not* a bi-directional relationship. * If one needs to check both directions for comparability, use a second call to this function or 'isTypeComparableTo'. */ - function checkTypeComparableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined): boolean { + function checkTypeComparableTo( + source: Type, + target: Type, + errorNode: Node, + headMessage?: DiagnosticMessage, + containingMessageChain?: () => DiagnosticMessageChain | undefined, + ): boolean { return checkTypeRelatedTo(source, target, comparableRelation, errorNode, headMessage, containingMessageChain); } - function isSignatureAssignableTo(source: Signature, - target: Signature, - ignoreReturnTypes: boolean): boolean { - return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : SignatureCheckMode.None, /*reportErrors*/ false, - /*errorReporter*/ undefined, /*incompatibleErrorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False; + function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean { + return compareSignaturesRelated( + source, + target, + ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : SignatureCheckMode.None, + /*reportErrors*/ false, + /*errorReporter*/ undefined, + /*incompatibleErrorReporter*/ undefined, + compareTypesAssignable, + /*reportUnreliableMarkers*/ undefined, + ) !== Ternary.False; } type ErrorReporter = (message: DiagnosticMessage, ...args: DiagnosticArguments) => void; @@ -19951,10 +25808,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Returns true if `s` is `(...args: A) => R` where `A` is `any`, `any[]`, `never`, or `never[]`, and `R` is `any` or `unknown`. */ function isTopSignature(s: Signature) { - if (!s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) && s.parameters.length === 1 && signatureHasRestParameter(s)) { + if ( + !s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) + && s.parameters.length === 1 && signatureHasRestParameter(s) + ) { const paramType = getTypeOfParameter(s.parameters[0]); const restType = isArrayType(paramType) ? getTypeArguments(paramType)[0] : paramType; - return !!(restType.flags & (TypeFlags.Any | TypeFlags.Never) && getReturnTypeOfSignature(s).flags & TypeFlags.AnyOrUnknown); + return !!(restType.flags & (TypeFlags.Any | TypeFlags.Never) + && getReturnTypeOfSignature(s).flags & TypeFlags.AnyOrUnknown); } return false; } @@ -19962,14 +25823,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * See signatureRelatedTo, compareSignaturesIdentical */ - function compareSignaturesRelated(source: Signature, + function compareSignaturesRelated( + source: Signature, target: Signature, checkMode: SignatureCheckMode, reportErrors: boolean, errorReporter: ErrorReporter | undefined, incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined, compareTypes: TypeComparer, - reportUnreliableMarkers: TypeMapper | undefined): Ternary { + reportUnreliableMarkers: TypeMapper | undefined, + ): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -19983,13 +25846,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const targetCount = getParameterCount(target); - const sourceHasMoreParameters = !hasEffectiveRestParameter(target) && - (checkMode & SignatureCheckMode.StrictArity ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount : getMinArgumentCount(source) > targetCount); + const sourceHasMoreParameters = !hasEffectiveRestParameter(target) + && (checkMode & SignatureCheckMode.StrictArity + ? hasEffectiveRestParameter(source) || getParameterCount(source) > targetCount + : getMinArgumentCount(source) > targetCount); if (sourceHasMoreParameters) { if (reportErrors && !(checkMode & SignatureCheckMode.StrictArity)) { // the second condition should be redundant, because there is no error reporting when comparing signatures by strict arity // since it is only done for subtype reduction - errorReporter!(Diagnostics.Target_signature_provides_too_few_arguments_Expected_0_or_more_but_got_1, getMinArgumentCount(source), targetCount); + errorReporter!( + Diagnostics.Target_signature_provides_too_few_arguments_Expected_0_or_more_but_got_1, + getMinArgumentCount(source), + targetCount, + ); } return Ternary.False; } @@ -20007,8 +25876,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; - const strictVariance = !(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration && - kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor; + const strictVariance = !(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes + && kind !== SyntaxKind.MethodDeclaration + && kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor; let result = Ternary.True; const sourceThisType = getThisTypeOfSignature(source); @@ -20028,7 +25898,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - const paramCount = sourceRestType || targetRestType ? Math.min(sourceCount, targetCount) : Math.max(sourceCount, targetCount); + const paramCount = sourceRestType || targetRestType ? Math.min(sourceCount, targetCount) + : Math.max(sourceCount, targetCount); const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1; for (let i = 0; i < paramCount; i++) { @@ -20043,22 +25914,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // similar to return values, callback parameters are output positions. This means that a Promise, // where T is used only in callback parameter positions, will be co-variant (as opposed to bi-variant) // with respect to T. - const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); - const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType)); - const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && - (getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull); - let related = callbacks ? - compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : - !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); + const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined + : getSingleCallSignature(getNonNullableType(sourceType)); + const targetSig = checkMode & SignatureCheckMode.Callback ? undefined + : getSingleCallSignature(getNonNullableType(targetType)); + const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) + && !getTypePredicateOfSignature(targetSig) + && (getTypeFacts(sourceType) & TypeFacts.IsUndefinedOrNull) + === (getTypeFacts(targetType) & TypeFacts.IsUndefinedOrNull); + let related = callbacks + ? compareSignaturesRelated( + targetSig, + sourceSig, + (checkMode & SignatureCheckMode.StrictArity) + | (strictVariance ? SignatureCheckMode.StrictCallback + : SignatureCheckMode.BivariantCallback), + reportErrors, + errorReporter, + incompatibleErrorReporter, + compareTypes, + reportUnreliableMarkers, + ) + : !(checkMode & SignatureCheckMode.Callback) && !strictVariance + && compareTypes(sourceType, targetType, /*reportErrors*/ false) + || compareTypes(targetType, sourceType, reportErrors); // With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void - if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) { + if ( + related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) + && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false) + ) { related = Ternary.False; } if (!related) { if (reportErrors) { - errorReporter!(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, + errorReporter!( + Diagnostics.Types_of_parameters_0_and_1_are_incompatible, unescapeLeadingUnderscores(getParameterNameAtPosition(source, i)), - unescapeLeadingUnderscores(getParameterNameAtPosition(target, i))); + unescapeLeadingUnderscores(getParameterNameAtPosition(target, i)), + ); } return Ternary.False; } @@ -20070,13 +25963,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If a signature resolution is already in-flight, skip issuing a circularity error // here and just use the `any` type directly const targetReturnType = isResolvingReturnTypeOfSignature(target) ? anyType - : target.declaration && isJSConstructor(target.declaration) ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(target.declaration.symbol)) + : target.declaration && isJSConstructor(target.declaration) + ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(target.declaration.symbol)) : getReturnTypeOfSignature(target); if (targetReturnType === voidType || targetReturnType === anyType) { return result; } const sourceReturnType = isResolvingReturnTypeOfSignature(source) ? anyType - : source.declaration && isJSConstructor(source.declaration) ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(source.declaration.symbol)) + : source.declaration && isJSConstructor(source.declaration) + ? getDeclaredTypeOfClassOrInterface(getMergedSymbol(source.declaration.symbol)) : getReturnTypeOfSignature(source); // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions @@ -20084,7 +25979,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (targetTypePredicate) { const sourceTypePredicate = getTypePredicateOfSignature(source); if (sourceTypePredicate) { - result &= compareTypePredicateRelatedTo(sourceTypePredicate, targetTypePredicate, reportErrors, errorReporter, compareTypes); + result &= compareTypePredicateRelatedTo( + sourceTypePredicate, + targetTypePredicate, + reportErrors, + errorReporter, + compareTypes, + ); } else if (isIdentifierTypePredicate(targetTypePredicate)) { if (reportErrors) { @@ -20097,13 +25998,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When relating callback signatures, we still need to relate return types bi-variantly as otherwise // the containing type wouldn't be co-variant. For example, interface Foo { add(cb: () => T): void } // wouldn't be co-variant for T without this rule. - result &= checkMode & SignatureCheckMode.BivariantCallback && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) || - compareTypes(sourceReturnType, targetReturnType, reportErrors); + result &= checkMode & SignatureCheckMode.BivariantCallback + && compareTypes(targetReturnType, sourceReturnType, /*reportErrors*/ false) + || compareTypes(sourceReturnType, targetReturnType, reportErrors); if (!result && reportErrors && incompatibleErrorReporter) { incompatibleErrorReporter(sourceReturnType, targetReturnType); } } - } return result; @@ -20114,11 +26015,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target: TypePredicate, reportErrors: boolean, errorReporter: ErrorReporter | undefined, - compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { + compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary, + ): Ternary { if (source.kind !== target.kind) { if (reportErrors) { errorReporter!(Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard); - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target), + ); } return Ternary.False; } @@ -20126,18 +26032,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.kind === TypePredicateKind.Identifier || source.kind === TypePredicateKind.AssertsIdentifier) { if (source.parameterIndex !== (target as IdentifierTypePredicate).parameterIndex) { if (reportErrors) { - errorReporter!(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, source.parameterName, (target as IdentifierTypePredicate).parameterName); - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, + source.parameterName, + (target as IdentifierTypePredicate).parameterName, + ); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target), + ); } return Ternary.False; } } - const related = source.type === target.type ? Ternary.True : - source.type && target.type ? compareTypes(source.type, target.type, reportErrors) : - Ternary.False; + const related = source.type === target.type ? Ternary.True + : source.type && target.type ? compareTypes(source.type, target.type, reportErrors) + : Ternary.False; if (related === Ternary.False && reportErrors) { - errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target)); + errorReporter!( + Diagnostics.Type_predicate_0_is_not_assignable_to_1, + typePredicateToString(source), + typePredicateToString(target), + ); } return related; } @@ -20149,10 +26067,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // First see if the return types are compatible in either direction. const sourceReturnType = getReturnTypeOfSignature(erasedSource); const targetReturnType = getReturnTypeOfSignature(erasedTarget); - if (targetReturnType === voidType + if ( + targetReturnType === voidType || isTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation) - || isTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation)) { - + || isTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation) + ) { return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true); } @@ -20160,33 +26079,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isEmptyResolvedType(t: ResolvedType) { - return t !== anyFunctionType && - t.properties.length === 0 && - t.callSignatures.length === 0 && - t.constructSignatures.length === 0 && - t.indexInfos.length === 0; + return t !== anyFunctionType + && t.properties.length === 0 + && t.callSignatures.length === 0 + && t.constructSignatures.length === 0 + && t.indexInfos.length === 0; } function isEmptyObjectType(type: Type): boolean { - return type.flags & TypeFlags.Object ? !isGenericMappedType(type) && isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType)) : - type.flags & TypeFlags.NonPrimitive ? true : - type.flags & TypeFlags.Union ? some((type as UnionType).types, isEmptyObjectType) : - type.flags & TypeFlags.Intersection ? every((type as UnionType).types, isEmptyObjectType) : - false; + return type.flags & TypeFlags.Object + ? !isGenericMappedType(type) && isEmptyResolvedType(resolveStructuredTypeMembers(type as ObjectType)) + : type.flags & TypeFlags.NonPrimitive ? true + : type.flags & TypeFlags.Union ? some((type as UnionType).types, isEmptyObjectType) + : type.flags & TypeFlags.Intersection ? every((type as UnionType).types, isEmptyObjectType) + : false; } function isEmptyAnonymousObjectType(type: Type) { return !!(getObjectFlags(type) & ObjectFlags.Anonymous && ( - (type as ResolvedType).members && isEmptyResolvedType(type as ResolvedType) || - type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && getMembersOfSymbol(type.symbol).size === 0)); + (type as ResolvedType).members && isEmptyResolvedType(type as ResolvedType) + || type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral && getMembersOfSymbol(type.symbol).size === 0 + )); } function isUnknownLikeUnionType(type: Type) { if (strictNullChecks && type.flags & TypeFlags.Union) { if (!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnionComputed)) { const types = (type as UnionType).types; - (type as UnionType).objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed | (types.length >= 3 && types[0].flags & TypeFlags.Undefined && - types[1].flags & TypeFlags.Null && some(types, isEmptyAnonymousObjectType) ? ObjectFlags.IsUnknownLikeUnion : 0); + (type as UnionType).objectFlags |= ObjectFlags.IsUnknownLikeUnionComputed + | (types.length >= 3 && types[0].flags & TypeFlags.Undefined + && types[1].flags & TypeFlags.Null && some(types, isEmptyAnonymousObjectType) + ? ObjectFlags.IsUnknownLikeUnion : 0); } return !!((type as UnionType).objectFlags & ObjectFlags.IsUnknownLikeUnion); } @@ -20198,9 +26121,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isStringIndexSignatureOnlyType(type: Type): boolean { - return type.flags & TypeFlags.Object && !isGenericMappedType(type) && getPropertiesOfType(type).length === 0 && getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, stringType) || - type.flags & TypeFlags.UnionOrIntersection && every((type as UnionOrIntersectionType).types, isStringIndexSignatureOnlyType) || - false; + return type.flags & TypeFlags.Object && !isGenericMappedType(type) && getPropertiesOfType(type).length === 0 + && getIndexInfosOfType(type).length === 1 && !!getIndexInfoOfType(type, stringType) + || type.flags & TypeFlags.UnionOrIntersection + && every((type as UnionOrIntersectionType).types, isStringIndexSignatureOnlyType) + || false; } function isEnumTypeRelatedTo(source: Symbol, target: Symbol, errorReporter?: ErrorReporter) { @@ -20209,12 +26134,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sourceSymbol === targetSymbol) { return true; } - if (sourceSymbol.escapedName !== targetSymbol.escapedName || !(sourceSymbol.flags & SymbolFlags.RegularEnum) || !(targetSymbol.flags & SymbolFlags.RegularEnum)) { + if ( + sourceSymbol.escapedName !== targetSymbol.escapedName || !(sourceSymbol.flags & SymbolFlags.RegularEnum) + || !(targetSymbol.flags & SymbolFlags.RegularEnum) + ) { return false; } const id = getSymbolId(sourceSymbol) + "," + getSymbolId(targetSymbol); const entry = enumRelation.get(id); - if (entry !== undefined && !(!(entry & RelationComparisonResult.Reported) && entry & RelationComparisonResult.Failed && errorReporter)) { + if ( + entry !== undefined + && !(!(entry & RelationComparisonResult.Reported) && entry & RelationComparisonResult.Failed + && errorReporter) + ) { return !!(entry & RelationComparisonResult.Succeeded); } const targetEnumType = getTypeOfSymbol(targetSymbol); @@ -20223,8 +26155,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetProperty = getPropertyOfType(targetEnumType, property.escapedName); if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) { if (errorReporter) { - errorReporter(Diagnostics.Property_0_is_missing_in_type_1, symbolName(property), - typeToString(getDeclaredTypeOfSymbol(targetSymbol), /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType)); + errorReporter( + Diagnostics.Property_0_is_missing_in_type_1, + symbolName(property), + typeToString( + getDeclaredTypeOfSymbol(targetSymbol), + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.UseFullyQualifiedType, + ), + ); enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported); } else { @@ -20238,44 +26177,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { + function isSimpleTypeRelatedTo( + source: Type, + target: Type, + relation: Map, + errorReporter?: ErrorReporter, + ) { const s = source.flags; const t = target.flags; if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true; if (t & TypeFlags.Unknown && !(relation === strictSubtypeRelation && s & TypeFlags.Any)) return true; if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; - if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && - t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) && - (source as StringLiteralType).value === (target as StringLiteralType).value) return true; + if ( + s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral + && t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) + && (source as StringLiteralType).value === (target as StringLiteralType).value + ) return true; if (s & TypeFlags.NumberLike && t & TypeFlags.Number) return true; - if (s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral && - t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) && - (source as NumberLiteralType).value === (target as NumberLiteralType).value) return true; + if ( + s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral + && t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) + && (source as NumberLiteralType).value === (target as NumberLiteralType).value + ) return true; if (s & TypeFlags.BigIntLike && t & TypeFlags.BigInt) return true; if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true; if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true; - if (s & TypeFlags.Enum && t & TypeFlags.Enum && source.symbol.escapedName === target.symbol.escapedName && - isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; + if ( + s & TypeFlags.Enum && t & TypeFlags.Enum && source.symbol.escapedName === target.symbol.escapedName + && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter) + ) return true; if (s & TypeFlags.EnumLiteral && t & TypeFlags.EnumLiteral) { - if (s & TypeFlags.Union && t & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; - if (s & TypeFlags.Literal && t & TypeFlags.Literal && (source as LiteralType).value === (target as LiteralType).value && - isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true; + if ( + s & TypeFlags.Union && t & TypeFlags.Union + && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter) + ) return true; + if ( + s & TypeFlags.Literal && t & TypeFlags.Literal + && (source as LiteralType).value === (target as LiteralType).value + && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter) + ) return true; } // In non-strictNullChecks mode, `undefined` and `null` are assignable to anything except `never`. // Since unions and intersections may reduce to `never`, we exclude them here. - if (s & TypeFlags.Undefined && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & (TypeFlags.Undefined | TypeFlags.Void))) return true; - if (s & TypeFlags.Null && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & TypeFlags.Null)) return true; - if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source) && !(getObjectFlags(source) & ObjectFlags.FreshLiteral))) return true; + if ( + s & TypeFlags.Undefined + && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & (TypeFlags.Undefined | TypeFlags.Void)) + ) return true; + if (s & TypeFlags.Null && (!strictNullChecks && !(t & TypeFlags.UnionOrIntersection) || t & TypeFlags.Null)) { + return true; + } + if ( + s & TypeFlags.Object && t & TypeFlags.NonPrimitive + && !(relation === strictSubtypeRelation && isEmptyAnonymousObjectType(source) + && !(getObjectFlags(source) & ObjectFlags.FreshLiteral)) + ) return true; if (relation === assignableRelation || relation === comparableRelation) { if (s & TypeFlags.Any) return true; // Type number is assignable to any computed numeric enum type or any numeric enum literal type, and // a numeric literal type is assignable any computed numeric enum type or any numeric enum literal type // with a matching value. These rules exist such that enums can be used for bit-flag purposes. - if (s & TypeFlags.Number && (t & TypeFlags.Enum || t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return true; - if (s & TypeFlags.NumberLiteral && !(s & TypeFlags.EnumLiteral) && (t & TypeFlags.Enum || - t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral && - (source as NumberLiteralType).value === (target as NumberLiteralType).value)) return true; + if ( + s & TypeFlags.Number && (t & TypeFlags.Enum || t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral) + ) return true; + if ( + s & TypeFlags.NumberLiteral && !(s & TypeFlags.EnumLiteral) && (t & TypeFlags.Enum + || t & TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral + && (source as NumberLiteralType).value === (target as NumberLiteralType).value) + ) return true; // Anything is assignable to a union containing undefined, null, and {} if (isUnknownLikeUnionType(target)) return true; } @@ -20293,17 +26262,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } if (relation !== identityRelation) { - if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || isSimpleTypeRelatedTo(source, target, relation)) { + if ( + relation === comparableRelation && !(target.flags & TypeFlags.Never) + && isSimpleTypeRelatedTo(target, source, relation) + || isSimpleTypeRelatedTo(source, target, relation) + ) { return true; } } - else if (!((source.flags | target.flags) & (TypeFlags.UnionOrIntersection | TypeFlags.IndexedAccess | TypeFlags.Conditional | TypeFlags.Substitution))) { + else if ( + !((source.flags | target.flags) + & (TypeFlags.UnionOrIntersection | TypeFlags.IndexedAccess | TypeFlags.Conditional + | TypeFlags.Substitution)) + ) { // We have excluded types that may simplify to other forms, so types must have identical flags if (source.flags !== target.flags) return false; if (source.flags & TypeFlags.Singleton) return true; } if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) { - const related = relation.get(getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false)); + const related = relation.get( + getRelationKey(source, target, IntersectionState.None, relation, /*ignoreConstraints*/ false), + ); if (related !== undefined) { return !!(related & RelationComparisonResult.Succeeded); } @@ -20320,13 +26299,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getNormalizedType(type: Type, writing: boolean): Type { while (true) { - const t = isFreshLiteralType(type) ? (type as FreshableType).regularType : - isGenericTupleType(type) ? getNormalizedTupleType(type, writing) : - getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).node ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) : getSingleBaseForNonAugmentingSubtype(type) || type : - type.flags & TypeFlags.UnionOrIntersection ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) : - type.flags & TypeFlags.Substitution ? writing ? (type as SubstitutionType).baseType : getSubstitutionIntersection(type as SubstitutionType) : - type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) : - type; + const t = isFreshLiteralType(type) ? (type as FreshableType).regularType + : isGenericTupleType(type) ? getNormalizedTupleType(type, writing) + : getObjectFlags(type) & ObjectFlags.Reference + ? (type as TypeReference).node + ? createTypeReference((type as TypeReference).target, getTypeArguments(type as TypeReference)) + : getSingleBaseForNonAugmentingSubtype(type) || type + : type.flags & TypeFlags.UnionOrIntersection + ? getNormalizedUnionOrIntersectionType(type as UnionOrIntersectionType, writing) + : type.flags & TypeFlags.Substitution + ? writing ? (type as SubstitutionType).baseType : getSubstitutionIntersection(type as SubstitutionType) + : type.flags & TypeFlags.Simplifiable ? getSimplifiedType(type, writing) + : type; if (t === type) return t; type = t; } @@ -20348,7 +26332,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getNormalizedTupleType(type: TupleTypeReference, writing: boolean): Type { const elements = getElementTypes(type); - const normalizedElements = sameMap(elements, t => t.flags & TypeFlags.Simplifiable ? getSimplifiedType(t, writing) : t); + const normalizedElements = sameMap( + elements, + t => t.flags & TypeFlags.Simplifiable ? getSimplifiedType(t, writing) : t, + ); return elements !== normalizedElements ? createNormalizedTupleType(type.target, normalizedElements) : type; } @@ -20370,9 +26357,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { errorNode: Node | undefined, headMessage?: DiagnosticMessage, containingMessageChain?: () => DiagnosticMessageChain | undefined, - errorOutputContainer?: { errors?: Diagnostic[], skipLogging?: boolean }, + errorOutputContainer?: { errors?: Diagnostic[]; skipLogging?: boolean; }, ): boolean { - let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined; let maybeKeys: string[]; @@ -20396,8 +26382,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reportIncompatibleStack(); } if (overflow) { - tracing?.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth: sourceDepth, targetDepth }); - const diag = error(errorNode || currentNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target)); + tracing?.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { + sourceId: source.id, + targetId: target.id, + depth: sourceDepth, + targetDepth, + }); + const diag = error( + errorNode || currentNode, + Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, + typeToString(source), + typeToString(target), + ); if (errorOutputContainer) { (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); } @@ -20416,15 +26412,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (headMessage && errorNode && !result && source.symbol) { const links = getSymbolLinks(source.symbol); if (links.originatingImport && !isImportCall(links.originatingImport)) { - const helpfulRetry = checkTypeRelatedTo(getTypeOfSymbol(links.target!), target, relation, /*errorNode*/ undefined); + const helpfulRetry = checkTypeRelatedTo( + getTypeOfSymbol(links.target!), + target, + relation, + /*errorNode*/ undefined, + ); if (helpfulRetry) { // Likely an incorrect import. Issue a helpful diagnostic to produce a quickfix to change the import - const diag = createDiagnosticForNode(links.originatingImport, Diagnostics.Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead); + const diag = createDiagnosticForNode( + links.originatingImport, + Diagnostics + .Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead, + ); relatedInformation = append(relatedInformation, diag); // Cause the error to appear with the error that triggered it } } } - const diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode!), errorNode!, errorInfo, relatedInformation); + const diag = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorNode!), + errorNode!, + errorInfo, + relatedInformation, + ); if (relatedInfo) { addRelatedInfo(diag, ...relatedInfo); } @@ -20439,7 +26449,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error."); } - return result !== Ternary.False; function resetErrorInfo(saved: ReturnType) { @@ -20458,7 +26467,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { incompatibleStack: incompatibleStack?.slice(), overrideNextErrorInfo, skipParentCounter, - relatedInfo: relatedInfo?.slice() as [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined, + relatedInfo: relatedInfo?.slice() as + | [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] + | undefined, }; } @@ -20515,38 +26526,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case Diagnostics.Call_signature_return_types_0_and_1_are_incompatible.code: case Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code: case Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code: - case Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code: { + case Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code: { if (path.length === 0) { // Don't flatten signature compatability errors at the start of a chain - instead prefer // to unify (the with no arguments bit is excessive for printback) and print them back let mappedMsg = msg; - if (msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) { + if ( + msg.code + === Diagnostics + .Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code + ) { mappedMsg = Diagnostics.Call_signature_return_types_0_and_1_are_incompatible; } - else if (msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) { + else if ( + msg.code + === Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + ) { mappedMsg = Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible; } secondaryRootErrors.unshift([mappedMsg, args[0], args[1]]); } else { - const prefix = (msg.code === Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code || - msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) + const prefix = + (msg.code === Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible.code + || msg.code + === Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code) ? "new " : ""; - const params = (msg.code === Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code || - msg.code === Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1.code) - ? "" - : "..."; + const params = (msg.code + === Diagnostics + .Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code + || msg.code + === Diagnostics + .Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1 + .code) + ? "" + : "..."; path = `${prefix}${path}(${params})`; } break; } - case Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target.code: { - secondaryRootErrors.unshift([Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, args[0], args[1]]); + case Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target + .code: { + secondaryRootErrors.unshift([ + Diagnostics + .Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, + args[0], + args[1], + ]); break; } - case Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target.code: { - secondaryRootErrors.unshift([Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, args[0], args[1], args[2]]); + case Diagnostics + .Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target + .code: { + secondaryRootErrors.unshift([ + Diagnostics + .Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, + args[0], + args[1], + args[2], + ]); break; } default: @@ -20554,10 +26599,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (path) { - reportError(path[path.length - 1] === ")" - ? Diagnostics.The_types_returned_by_0_are_incompatible_between_these_types - : Diagnostics.The_types_of_0_are_incompatible_between_these_types, - path + reportError( + path[path.length - 1] === ")" + ? Diagnostics.The_types_returned_by_0_are_incompatible_between_these_types + : Diagnostics.The_types_of_0_are_incompatible_between_these_types, + path, ); } else { @@ -20611,75 +26657,107 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isLiteralType(source) && !typeCouldHaveTopLevelSingletonTypes(target)) { generalizedSource = getBaseTypeOfLiteralType(source); - Debug.assert(!isTypeAssignableTo(generalizedSource, target), "generalized source shouldn't be assignable"); + Debug.assert( + !isTypeAssignableTo(generalizedSource, target), + "generalized source shouldn't be assignable", + ); generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource); } - // If `target` is of indexed access type (And `source` it is not), we use the object type of `target` for better error reporting - const targetFlags = target.flags & TypeFlags.IndexedAccess && !(source.flags & TypeFlags.IndexedAccess) ? - (target as IndexedAccessType).objectType.flags : - target.flags; + // If `target` is of indexed access type (And `source` it is not), we use the object type of `target` for better error reporting + const targetFlags = target.flags & TypeFlags.IndexedAccess && !(source.flags & TypeFlags.IndexedAccess) + ? (target as IndexedAccessType).objectType.flags + : target.flags; - if (targetFlags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck && target !== markerSubTypeForCheck) { - const constraint = getBaseConstraintOfType(target); - let needsOriginalSource; - if (constraint && (isTypeAssignableTo(generalizedSource, constraint) || (needsOriginalSource = isTypeAssignableTo(source, constraint)))) { - reportError( - Diagnostics._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2, - needsOriginalSource ? sourceType : generalizedSourceType, - targetType, - typeToString(constraint), - ); - } - else { - errorInfo = undefined; - reportError( - Diagnostics._0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1, - targetType, - generalizedSourceType - ); - } + if ( + targetFlags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck + && target !== markerSubTypeForCheck + ) { + const constraint = getBaseConstraintOfType(target); + let needsOriginalSource; + if ( + constraint + && (isTypeAssignableTo(generalizedSource, constraint) + || (needsOriginalSource = isTypeAssignableTo(source, constraint))) + ) { + reportError( + Diagnostics + ._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2, + needsOriginalSource ? sourceType : generalizedSourceType, + targetType, + typeToString(constraint), + ); + } + else { + errorInfo = undefined; + reportError( + Diagnostics._0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1, + targetType, + generalizedSourceType, + ); } + } if (!message) { if (relation === comparableRelation) { message = Diagnostics.Type_0_is_not_comparable_to_type_1; } else if (sourceType === targetType) { - message = Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated; + message = Diagnostics + .Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated; } else if (exactOptionalPropertyTypes && getExactOptionalUnassignableProperties(source, target).length) { - message = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; + message = Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; } else { if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.Union) { - const suggestedType = getSuggestedTypeForNonexistentStringLiteralType(source as StringLiteralType, target as UnionType); + const suggestedType = getSuggestedTypeForNonexistentStringLiteralType( + source as StringLiteralType, + target as UnionType, + ); if (suggestedType) { - reportError(Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, generalizedSourceType, targetType, typeToString(suggestedType)); + reportError( + Diagnostics.Type_0_is_not_assignable_to_type_1_Did_you_mean_2, + generalizedSourceType, + targetType, + typeToString(suggestedType), + ); return; } } message = Diagnostics.Type_0_is_not_assignable_to_type_1; } } - else if (message === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 + else if ( + message === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 && exactOptionalPropertyTypes - && getExactOptionalUnassignableProperties(source, target).length) { - message = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; + && getExactOptionalUnassignableProperties(source, target).length + ) { + message = Diagnostics + .Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties; } reportError(message, generalizedSourceType, targetType); } function tryElaborateErrorsForPrimitivesAndObjects(source: Type, target: Type) { - const sourceType = symbolValueDeclarationIsContextSensitive(source.symbol) ? typeToString(source, source.symbol.valueDeclaration) : typeToString(source); - const targetType = symbolValueDeclarationIsContextSensitive(target.symbol) ? typeToString(target, target.symbol.valueDeclaration) : typeToString(target); + const sourceType = symbolValueDeclarationIsContextSensitive(source.symbol) + ? typeToString(source, source.symbol.valueDeclaration) : typeToString(source); + const targetType = symbolValueDeclarationIsContextSensitive(target.symbol) + ? typeToString(target, target.symbol.valueDeclaration) : typeToString(target); - if ((globalStringType === source && stringType === target) || - (globalNumberType === source && numberType === target) || - (globalBooleanType === source && booleanType === target) || - (getGlobalESSymbolType() === source && esSymbolType === target)) { - reportError(Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, targetType, sourceType); + if ( + (globalStringType === source && stringType === target) + || (globalNumberType === source && numberType === target) + || (globalBooleanType === source && booleanType === target) + || (getGlobalESSymbolType() === source && esSymbolType === target) + ) { + reportError( + Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, + targetType, + sourceType, + ); } } @@ -20700,7 +26778,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isTupleType(source)) { if (source.target.readonly && isMutableArrayOrTuple(target)) { if (reportErrors) { - reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target)); + reportError( + Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, + typeToString(source), + typeToString(target), + ); } return false; } @@ -20708,7 +26790,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isReadonlyArrayType(source) && isMutableArrayOrTuple(target)) { if (reportErrors) { - reportError(Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, typeToString(source), typeToString(target)); + reportError( + Diagnostics.The_type_0_is_readonly_and_cannot_be_assigned_to_the_mutable_type_1, + typeToString(source), + typeToString(target), + ); } return false; } @@ -20728,14 +26814,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * Ternary.Maybe if they are related with assumptions of other relationships, or * * Ternary.False if they are not related. */ - function isRelatedTo(originalSource: Type, originalTarget: Type, recursionFlags: RecursionFlags = RecursionFlags.Both, reportErrors = false, headMessage?: DiagnosticMessage, intersectionState = IntersectionState.None): Ternary { + function isRelatedTo( + originalSource: Type, + originalTarget: Type, + recursionFlags: RecursionFlags = RecursionFlags.Both, + reportErrors = false, + headMessage?: DiagnosticMessage, + intersectionState = IntersectionState.None, + ): Ternary { if (originalSource === originalTarget) return Ternary.True; // Before normalization: if `source` is type an object type, and `target` is primitive, // skip all the checks we don't need and just return `isSimpleTypeRelatedTo` result if (originalSource.flags & TypeFlags.Object && originalTarget.flags & TypeFlags.Primitive) { - if (relation === comparableRelation && !(originalTarget.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(originalTarget, originalSource, relation) || - isSimpleTypeRelatedTo(originalSource, originalTarget, relation, reportErrors ? reportError : undefined)) { + if ( + relation === comparableRelation && !(originalTarget.flags & TypeFlags.Never) + && isSimpleTypeRelatedTo(originalTarget, originalSource, relation) + || isSimpleTypeRelatedTo( + originalSource, + originalTarget, + relation, + reportErrors ? reportError : undefined, + ) + ) { return Ternary.True; } if (reportErrors) { @@ -20757,7 +26858,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.flags !== target.flags) return Ternary.False; if (source.flags & TypeFlags.Singleton) return Ternary.True; traceUnionsOrIntersectionsTooLarge(source, target); - return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false, IntersectionState.None, recursionFlags); + return recursiveTypeRelatedTo( + source, + target, + /*reportErrors*/ false, + IntersectionState.None, + recursionFlags, + ); } // We fastpath comparing a type parameter to exactly its constraint, as this is _super_ common, @@ -20773,47 +26880,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // plus a single non-nullable type. If so, remove null and/or undefined from the target type. if (source.flags & TypeFlags.DefinitelyNonNullable && target.flags & TypeFlags.Union) { const types = (target as UnionType).types; - const candidate = types.length === 2 && types[0].flags & TypeFlags.Nullable ? types[1] : - types.length === 3 && types[0].flags & TypeFlags.Nullable && types[1].flags & TypeFlags.Nullable ? types[2] : - undefined; + const candidate = types.length === 2 && types[0].flags & TypeFlags.Nullable ? types[1] + : types.length === 3 && types[0].flags & TypeFlags.Nullable && types[1].flags & TypeFlags.Nullable + ? types[2] + : undefined; if (candidate && !(candidate.flags & TypeFlags.Nullable)) { target = getNormalizedType(candidate, /*writing*/ true); if (source === target) return Ternary.True; } } - if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) || - isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; + if ( + relation === comparableRelation && !(target.flags & TypeFlags.Never) + && isSimpleTypeRelatedTo(target, source, relation) + || isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined) + ) return Ternary.True; - if (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable) { - const isPerformingExcessPropertyChecks = !(intersectionState & IntersectionState.Target) && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); + if ( + source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable + ) { + const isPerformingExcessPropertyChecks = !(intersectionState & IntersectionState.Target) + && (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral); if (isPerformingExcessPropertyChecks) { if (hasExcessProperties(source as FreshObjectLiteralType, target, reportErrors)) { if (reportErrors) { - reportRelationError(headMessage, source, originalTarget.aliasSymbol ? originalTarget : target); + reportRelationError( + headMessage, + source, + originalTarget.aliasSymbol ? originalTarget : target, + ); } return Ternary.False; } } - const isPerformingCommonPropertyChecks = (relation !== comparableRelation || isUnitType(source)) && - !(intersectionState & IntersectionState.Target) && - source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType && - target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) && - (getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source)); + const isPerformingCommonPropertyChecks = (relation !== comparableRelation || isUnitType(source)) + && !(intersectionState & IntersectionState.Target) + && source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) + && source !== globalObjectType + && target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) + && (getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source)); const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); - if (isPerformingCommonPropertyChecks && !hasCommonProperties(source, target, isComparingJsxAttributes)) { + if ( + isPerformingCommonPropertyChecks && !hasCommonProperties(source, target, isComparingJsxAttributes) + ) { if (reportErrors) { const sourceString = typeToString(originalSource.aliasSymbol ? originalSource : source); const targetString = typeToString(originalTarget.aliasSymbol ? originalTarget : target); const calls = getSignaturesOfType(source, SignatureKind.Call); const constructs = getSignaturesOfType(source, SignatureKind.Construct); - if (calls.length > 0 && isRelatedTo(getReturnTypeOfSignature(calls[0]), target, RecursionFlags.Source, /*reportErrors*/ false) || - constructs.length > 0 && isRelatedTo(getReturnTypeOfSignature(constructs[0]), target, RecursionFlags.Source, /*reportErrors*/ false)) { - reportError(Diagnostics.Value_of_type_0_has_no_properties_in_common_with_type_1_Did_you_mean_to_call_it, sourceString, targetString); + if ( + calls.length > 0 + && isRelatedTo( + getReturnTypeOfSignature(calls[0]), + target, + RecursionFlags.Source, + /*reportErrors*/ false, + ) + || constructs.length > 0 + && isRelatedTo( + getReturnTypeOfSignature(constructs[0]), + target, + RecursionFlags.Source, + /*reportErrors*/ false, + ) + ) { + reportError( + Diagnostics + .Value_of_type_0_has_no_properties_in_common_with_type_1_Did_you_mean_to_call_it, + sourceString, + targetString, + ); } else { - reportError(Diagnostics.Type_0_has_no_properties_in_common_with_type_1, sourceString, targetString); + reportError( + Diagnostics.Type_0_has_no_properties_in_common_with_type_1, + sourceString, + targetString, + ); } } return Ternary.False; @@ -20821,11 +26965,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { traceUnionsOrIntersectionsTooLarge(source, target); - const skipCaching = source.flags & TypeFlags.Union && (source as UnionType).types.length < 4 && !(target.flags & TypeFlags.Union) || - target.flags & TypeFlags.Union && (target as UnionType).types.length < 4 && !(source.flags & TypeFlags.StructuredOrInstantiable); - const result = skipCaching ? - unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState) : - recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags); + const skipCaching = source.flags & TypeFlags.Union && (source as UnionType).types.length < 4 + && !(target.flags & TypeFlags.Union) + || target.flags & TypeFlags.Union && (target as UnionType).types.length < 4 + && !(source.flags & TypeFlags.StructuredOrInstantiable); + const result = skipCaching + ? unionOrIntersectionRelatedTo(source, target, reportErrors, intersectionState) + : recursiveTypeRelatedTo(source, target, reportErrors, intersectionState, recursionFlags); if (result) { return result; } @@ -20837,7 +26983,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.False; } - function reportErrorResults(originalSource: Type, originalTarget: Type, source: Type, target: Type, headMessage: DiagnosticMessage | undefined) { + function reportErrorResults( + originalSource: Type, + originalTarget: Type, + source: Type, + target: Type, + headMessage: DiagnosticMessage | undefined, + ) { const sourceHasBase = !!getSingleBaseForNonAugmentingSubtype(originalSource); const targetHasBase = !!getSingleBaseForNonAugmentingSubtype(originalTarget); source = (originalSource.aliasSymbol || sourceHasBase) ? originalSource : source; @@ -20857,14 +27009,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { tryElaborateErrorsForPrimitivesAndObjects(source, target); } else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) { - reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead); + reportError( + Diagnostics + .The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead, + ); } else if (getObjectFlags(source) & ObjectFlags.JsxAttributes && target.flags & TypeFlags.Intersection) { const targetTypes = (target as IntersectionType).types; const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode); const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode); - if (!isErrorType(intrinsicAttributes) && !isErrorType(intrinsicClassAttributes) && - (contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes))) { + if ( + !isErrorType(intrinsicAttributes) && !isErrorType(intrinsicClassAttributes) + && (contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes)) + ) { // do not report top error return; } @@ -20878,12 +27035,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } reportRelationError(headMessage, source, target); - if (source.flags & TypeFlags.TypeParameter && source.symbol?.declarations?.[0] && !getConstraintOfType(source as TypeVariable)) { + if ( + source.flags & TypeFlags.TypeParameter && source.symbol?.declarations?.[0] + && !getConstraintOfType(source as TypeVariable) + ) { const syntheticParam = cloneTypeParameter(source as TypeParameter); syntheticParam.constraint = instantiateType(target, makeUnaryTypeMapper(source, syntheticParam)); if (hasNonCircularBaseConstraint(syntheticParam)) { const targetConstraintString = typeToString(target, source.symbol.declarations[0]); - associateRelatedInfo(createDiagnosticForNode(source.symbol.declarations[0], Diagnostics.This_type_parameter_might_need_an_extends_0_constraint, targetConstraintString)); + associateRelatedInfo( + createDiagnosticForNode( + source.symbol.declarations[0], + Diagnostics.This_type_parameter_might_need_an_extends_0_constraint, + targetConstraintString, + ), + ); } } } @@ -20897,7 +27063,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceUnionOrIntersection = source as UnionOrIntersectionType; const targetUnionOrIntersection = target as UnionOrIntersectionType; - if (sourceUnionOrIntersection.objectFlags & targetUnionOrIntersection.objectFlags & ObjectFlags.PrimitiveUnion) { + if ( + sourceUnionOrIntersection.objectFlags & targetUnionOrIntersection.objectFlags + & ObjectFlags.PrimitiveUnion + ) { // There's a fast path for comparing primitive unions return; } @@ -20911,7 +27080,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { targetId: target.id, targetSize, pos: errorNode?.pos, - end: errorNode?.end + end: errorNode?.end, }); } } @@ -20920,27 +27089,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeOfPropertyInTypes(types: Type[], name: __String) { const appendPropType = (propTypes: Type[] | undefined, type: Type) => { type = getApparentType(type); - const prop = type.flags & TypeFlags.UnionOrIntersection ? getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name) : getPropertyOfObjectType(type, name); - const propType = prop && getTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type || undefinedType; + const prop = type.flags & TypeFlags.UnionOrIntersection + ? getPropertyOfUnionOrIntersectionType(type as UnionOrIntersectionType, name) + : getPropertyOfObjectType(type, name); + const propType = prop && getTypeOfSymbol(prop) || getApplicableIndexInfoForName(type, name)?.type + || undefinedType; return append(propTypes, propType); }; return getUnionType(reduceLeft(types, appendPropType, /*initial*/ undefined) || emptyArray); } function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { - if (!isExcessPropertyCheckTarget(target) || !noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) { + if ( + !isExcessPropertyCheckTarget(target) || !noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral + ) { return false; // Disable excess property checks on JS literals to simulate having an implicit "index signature" - but only outside of noImplicitAny } const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes); - if ((relation === assignableRelation || relation === comparableRelation) && - (isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) { + if ( + (relation === assignableRelation || relation === comparableRelation) + && (isTypeSubsetOf(globalObjectType, target) + || (!isComparingJsxAttributes && isEmptyObjectType(target))) + ) { return false; } let reducedTarget = target; let checkTypes: Type[] | undefined; if (target.flags & TypeFlags.Union) { - reducedTarget = findMatchingDiscriminantType(source, target as UnionType, isRelatedTo) || filterPrimitivesIfContainsNonPrimitive(target as UnionType); - checkTypes = reducedTarget.flags & TypeFlags.Union ? (reducedTarget as UnionType).types : [reducedTarget]; + reducedTarget = findMatchingDiscriminantType(source, target as UnionType, isRelatedTo) + || filterPrimitivesIfContainsNonPrimitive(target as UnionType); + checkTypes = reducedTarget.flags & TypeFlags.Union ? (reducedTarget as UnionType).types + : [reducedTarget]; } for (const prop of getPropertiesOfType(source)) { if (shouldCheckAsExcessProperty(prop, source.symbol) && !isIgnoredJsxProperty(source, prop)) { @@ -20953,29 +27132,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Use this property as the error node as this will be more helpful in // reasoning about what went wrong. if (!errorNode) return Debug.fail(); - if (isJsxAttributes(errorNode) || isJsxOpeningLikeElement(errorNode) || isJsxOpeningLikeElement(errorNode.parent)) { + if ( + isJsxAttributes(errorNode) || isJsxOpeningLikeElement(errorNode) + || isJsxOpeningLikeElement(errorNode.parent) + ) { // JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal. // However, using an object-literal error message will be very confusing to the users so we give different a message. - if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) && getSourceFileOfNode(errorNode) === getSourceFileOfNode(prop.valueDeclaration.name)) { + if ( + prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) + && getSourceFileOfNode(errorNode) + === getSourceFileOfNode(prop.valueDeclaration.name) + ) { // Note that extraneous children (as in `extra`) don't pass this check, // since `children` is a SyntaxKind.PropertySignature instead of a SyntaxKind.JsxAttribute. errorNode = prop.valueDeclaration.name; } const propName = symbolToString(prop); - const suggestionSymbol = getSuggestedSymbolForNonexistentJSXAttribute(propName, errorTarget); + const suggestionSymbol = getSuggestedSymbolForNonexistentJSXAttribute( + propName, + errorTarget, + ); const suggestion = suggestionSymbol ? symbolToString(suggestionSymbol) : undefined; if (suggestion) { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName, typeToString(errorTarget), suggestion); + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, + propName, + typeToString(errorTarget), + suggestion, + ); } else { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1, propName, typeToString(errorTarget)); + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1, + propName, + typeToString(errorTarget), + ); } } else { // use the property's value declaration if the property is assigned inside the literal itself - const objectLiteralDeclaration = source.symbol?.declarations && firstOrUndefined(source.symbol.declarations); + const objectLiteralDeclaration = source.symbol?.declarations + && firstOrUndefined(source.symbol.declarations); let suggestion: string | undefined; - if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration) && getSourceFileOfNode(objectLiteralDeclaration) === getSourceFileOfNode(errorNode)) { + if ( + prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => + d === objectLiteralDeclaration) + && getSourceFileOfNode(objectLiteralDeclaration) === getSourceFileOfNode(errorNode) + ) { const propDeclaration = prop.valueDeclaration as ObjectLiteralElementLike; Debug.assertNode(propDeclaration, isObjectLiteralElementLike); @@ -20987,20 +27190,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (suggestion !== undefined) { - reportParentSkippedError(Diagnostics.Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2, - symbolToString(prop), typeToString(errorTarget), suggestion); + reportParentSkippedError( + Diagnostics + .Object_literal_may_only_specify_known_properties_but_0_does_not_exist_in_type_1_Did_you_mean_to_write_2, + symbolToString(prop), + typeToString(errorTarget), + suggestion, + ); } else { - reportParentSkippedError(Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, - symbolToString(prop), typeToString(errorTarget)); + reportParentSkippedError( + Diagnostics + .Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, + symbolToString(prop), + typeToString(errorTarget), + ); } } } return true; } - if (checkTypes && !isRelatedTo(getTypeOfSymbol(prop), getTypeOfPropertyInTypes(checkTypes, prop.escapedName), RecursionFlags.Both, reportErrors)) { + if ( + checkTypes + && !isRelatedTo( + getTypeOfSymbol(prop), + getTypeOfPropertyInTypes(checkTypes, prop.escapedName), + RecursionFlags.Both, + reportErrors, + ) + ) { if (reportErrors) { - reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(prop)); + reportIncompatibleError( + Diagnostics.Types_of_property_0_are_incompatible, + symbolToString(prop), + ); } return true; } @@ -21010,23 +27233,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function shouldCheckAsExcessProperty(prop: Symbol, container: Symbol) { - return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent === container.valueDeclaration; + return prop.valueDeclaration && container.valueDeclaration + && prop.valueDeclaration.parent === container.valueDeclaration; } - function unionOrIntersectionRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function unionOrIntersectionRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { // Note that these checks are specifically ordered to produce correct results. In particular, // we need to deconstruct unions before intersections (because unions are always at the top), // and we need to handle "each" relations before "some" relations for the same kind of type. if (source.flags & TypeFlags.Union) { - return relation === comparableRelation ? - someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState) : - eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), intersectionState); + return relation === comparableRelation + ? someTypeRelatedToType( + source as UnionType, + target, + reportErrors && !(source.flags & TypeFlags.Primitive), + intersectionState, + ) + : eachTypeRelatedToType( + source as UnionType, + target, + reportErrors && !(source.flags & TypeFlags.Primitive), + intersectionState, + ); } if (target.flags & TypeFlags.Union) { - return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target as UnionType, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive)); + return typeRelatedToSomeType( + getRegularTypeOfObjectLiteral(source), + target as UnionType, + reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive), + ); } if (target.flags & TypeFlags.Intersection) { - return typeRelatedToEachType(source, target as IntersectionType, reportErrors, IntersectionState.Target); + return typeRelatedToEachType( + source, + target as IntersectionType, + reportErrors, + IntersectionState.Target, + ); } // Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the // constraints of all non-primitive types in the source into a new intersection. We do this because the @@ -21034,15 +27282,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // parameter 'T extends 1 | 2', the intersection 'T & 1' should be reduced to '1' such that it doesn't // appear to be comparable to '2'. if (relation === comparableRelation && target.flags & TypeFlags.Primitive) { - const constraints = sameMap((source as IntersectionType).types, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t); + const constraints = sameMap( + (source as IntersectionType).types, + t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(t) || unknownType : t, + ); if (constraints !== (source as IntersectionType).types) { source = getIntersectionType(constraints); if (source.flags & TypeFlags.Never) { return Ternary.False; } if (!(source.flags & TypeFlags.Intersection)) { - return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false) || - isRelatedTo(target, source, RecursionFlags.Source, /*reportErrors*/ false); + return isRelatedTo(source, target, RecursionFlags.Source, /*reportErrors*/ false) + || isRelatedTo(target, source, RecursionFlags.Source, /*reportErrors*/ false); } } } @@ -21050,7 +27301,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't report errors though. Elaborating on whether a source constituent is related to the target is // not actually useful and leads to some confusing error messages. Instead, we rely on the caller // checking whether the full intersection viewed as an object is related to the target. - return someTypeRelatedToType(source as IntersectionType, target, /*reportErrors*/ false, IntersectionState.Source); + return someTypeRelatedToType( + source as IntersectionType, + target, + /*reportErrors*/ false, + IntersectionState.Source, + ); } function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary { @@ -21072,21 +27328,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (containsType(targetTypes, source)) { return Ternary.True; } - if (relation !== comparableRelation && getObjectFlags(target) & ObjectFlags.PrimitiveUnion && !(source.flags & TypeFlags.EnumLiteral) && ( - source.flags & (TypeFlags.StringLiteral | TypeFlags.BooleanLiteral | TypeFlags.BigIntLiteral) || - (relation === subtypeRelation || relation === strictSubtypeRelation) && source.flags & TypeFlags.NumberLiteral)) { + if ( + relation !== comparableRelation && getObjectFlags(target) & ObjectFlags.PrimitiveUnion + && !(source.flags & TypeFlags.EnumLiteral) && ( + source.flags & (TypeFlags.StringLiteral | TypeFlags.BooleanLiteral | TypeFlags.BigIntLiteral) + || (relation === subtypeRelation || relation === strictSubtypeRelation) + && source.flags & TypeFlags.NumberLiteral + ) + ) { // When relating a literal type to a union of primitive types, we know the relation is false unless // the union contains the base primitive type or the literal type in one of its fresh/regular forms. // We exclude numeric literals for non-subtype relations because numeric literals are assignable to // numeric enum literals with the same value. Similarly, we exclude enum literal types because // identically named enum types are related (see isEnumTypeRelatedTo). We exclude the comparable // relation in entirety because it needs to be checked in both directions. - const alternateForm = source === (source as StringLiteralType).regularType ? (source as StringLiteralType).freshType : (source as StringLiteralType).regularType; - const primitive = source.flags & TypeFlags.StringLiteral ? stringType : - source.flags & TypeFlags.NumberLiteral ? numberType : - source.flags & TypeFlags.BigIntLiteral ? bigintType : - undefined; - return primitive && containsType(targetTypes, primitive) || alternateForm && containsType(targetTypes, alternateForm) ? Ternary.True : Ternary.False; + const alternateForm = source === (source as StringLiteralType).regularType + ? (source as StringLiteralType).freshType : (source as StringLiteralType).regularType; + const primitive = source.flags & TypeFlags.StringLiteral ? stringType + : source.flags & TypeFlags.NumberLiteral ? numberType + : source.flags & TypeFlags.BigIntLiteral ? bigintType + : undefined; + return primitive && containsType(targetTypes, primitive) + || alternateForm && containsType(targetTypes, alternateForm) ? Ternary.True : Ternary.False; } const match = getMatchingUnionConstituentForType(target as UnionType, source); if (match) { @@ -21112,11 +27375,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.False; } - function typeRelatedToEachType(source: Type, target: IntersectionType, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeRelatedToEachType( + source: Type, + target: IntersectionType, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { let result = Ternary.True; const targetTypes = target.types; for (const targetType of targetTypes) { - const related = isRelatedTo(source, targetType, RecursionFlags.Target, reportErrors, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + source, + targetType, + RecursionFlags.Target, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (!related) { return Ternary.False; } @@ -21125,14 +27400,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function someTypeRelatedToType( + source: UnionOrIntersectionType, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { const sourceTypes = source.types; if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) { return Ternary.True; } const len = sourceTypes.length; for (let i = 0; i < len; i++) { - const related = isRelatedTo(sourceTypes[i], target, RecursionFlags.Source, reportErrors && i === len - 1, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceTypes[i], + target, + RecursionFlags.Source, + reportErrors && i === len - 1, + /*headMessage*/ undefined, + intersectionState, + ); if (related) { return related; } @@ -21141,14 +27428,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getUndefinedStrippedTargetIfNeeded(source: Type, target: Type) { - if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union && - !((source as UnionType).types[0].flags & TypeFlags.Undefined) && (target as UnionType).types[0].flags & TypeFlags.Undefined) { + if ( + source.flags & TypeFlags.Union && target.flags & TypeFlags.Union + && !((source as UnionType).types[0].flags & TypeFlags.Undefined) + && (target as UnionType).types[0].flags & TypeFlags.Undefined + ) { return extractTypesOfKind(target, ~TypeFlags.Undefined); } return target; } - function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function eachTypeRelatedToType( + source: UnionOrIntersectionType, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { let result = Ternary.True; const sourceTypes = source.types; // We strip `undefined` from the target if the `source` trivially doesn't contain it for our correspondence-checking fastpath @@ -21156,19 +27451,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const undefinedStrippedTarget = getUndefinedStrippedTargetIfNeeded(source, target as UnionType); for (let i = 0; i < sourceTypes.length; i++) { const sourceType = sourceTypes[i]; - if (undefinedStrippedTarget.flags & TypeFlags.Union && sourceTypes.length >= (undefinedStrippedTarget as UnionType).types.length && sourceTypes.length % (undefinedStrippedTarget as UnionType).types.length === 0) { + if ( + undefinedStrippedTarget.flags & TypeFlags.Union + && sourceTypes.length >= (undefinedStrippedTarget as UnionType).types.length + && sourceTypes.length % (undefinedStrippedTarget as UnionType).types.length === 0 + ) { // many unions are mappings of one another; in such cases, simply comparing members at the same index can shortcut the comparison // such unions will have identical lengths, and their corresponding elements will match up. Another common scenario is where a large // union has a union of objects intersected with it. In such cases, if the input was, eg `("a" | "b" | "c") & (string | boolean | {} | {whatever})`, // the result will have the structure `"a" | "b" | "c" | "a" & {} | "b" & {} | "c" & {} | "a" & {whatever} | "b" & {whatever} | "c" & {whatever}` // - the resulting union has a length which is a multiple of the original union, and the elements correspond modulo the length of the original union - const related = isRelatedTo(sourceType, (undefinedStrippedTarget as UnionType).types[i % (undefinedStrippedTarget as UnionType).types.length], RecursionFlags.Both, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceType, + (undefinedStrippedTarget as UnionType) + .types[i % (undefinedStrippedTarget as UnionType).types.length], + RecursionFlags.Both, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ); if (related) { result &= related; continue; } } - const related = isRelatedTo(sourceType, target, RecursionFlags.Source, reportErrors, /*headMessage*/ undefined, intersectionState); + const related = isRelatedTo( + sourceType, + target, + RecursionFlags.Source, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (!related) { return Ternary.False; } @@ -21177,7 +27491,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function typeArgumentsRelatedTo(sources: readonly Type[] = emptyArray, targets: readonly Type[] = emptyArray, variances: readonly VarianceFlags[] = emptyArray, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeArgumentsRelatedTo( + sources: readonly Type[] = emptyArray, + targets: readonly Type[] = emptyArray, + variances: readonly VarianceFlags[] = emptyArray, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { if (sources.length !== targets.length && relation === identityRelation) { return Ternary.False; } @@ -21198,13 +27518,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Even an `Unmeasurable` variance works out without a structural check if the source and target are _identical_. // We can't simply assume invariance, because `Unmeasurable` marks nonlinear relations, for example, a relation tained by // the `-?` modifier in a mapped type (where, no matter how the inputs are related, the outputs still might not be) - related = relation === identityRelation ? isRelatedTo(s, t, RecursionFlags.Both, /*reportErrors*/ false) : compareTypesIdentical(s, t); + related = relation === identityRelation + ? isRelatedTo(s, t, RecursionFlags.Both, /*reportErrors*/ false) + : compareTypesIdentical(s, t); } else if (variance === VarianceFlags.Covariant) { - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } else if (variance === VarianceFlags.Contravariant) { - related = isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + t, + s, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } else if (variance === VarianceFlags.Bivariant) { // In the bivariant case we first compare contravariantly without reporting @@ -21213,16 +27549,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // which is generally easier to reason about. related = isRelatedTo(t, s, RecursionFlags.Both, /*reportErrors*/ false); if (!related) { - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } } else { // In the invariant case we first compare covariantly, and only when that // succeeds do we proceed to compare contravariantly. Thus, error elaboration // will typically be based on the covariant check. - related = isRelatedTo(s, t, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related = isRelatedTo( + s, + t, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (related) { - related &= isRelatedTo(t, s, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + related &= isRelatedTo( + t, + s, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } } if (!related) { @@ -21239,14 +27596,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are // equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion // and issue an error. Otherwise, actually compare the structure of the two types. - function recursiveTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, recursionFlags: RecursionFlags): Ternary { + function recursiveTypeRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + recursionFlags: RecursionFlags, + ): Ternary { if (overflow) { return Ternary.False; } const id = getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ false); const entry = relation.get(id); if (entry !== undefined) { - if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) { + if ( + reportErrors && entry & RelationComparisonResult.Failed + && !(entry & RelationComparisonResult.Reported) + ) { // We are elaborating errors and the cached result is an unreported failure. The result will be reported // as a failure, and should be updated as a reported failure by the bottom of this function. } @@ -21279,7 +27645,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A key that starts with "*" is an indication that we have type references that reference constrained // type parameters. For such keys we also check against the key we would have gotten if all type parameters // were unconstrained. - const broadestEquivalentId = id.startsWith("*") ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) : undefined; + const broadestEquivalentId = id.startsWith("*") + ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) + : undefined; if (broadestEquivalentId && maybeKeysSet.has(broadestEquivalentId)) { return Ternary.Maybe; } @@ -21297,19 +27665,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (recursionFlags & RecursionFlags.Source) { sourceStack[sourceDepth] = source; sourceDepth++; - if (!(expandingFlags & ExpandingFlags.Source) && isDeeplyNestedType(source, sourceStack, sourceDepth)) expandingFlags |= ExpandingFlags.Source; + if (!(expandingFlags & ExpandingFlags.Source) && isDeeplyNestedType(source, sourceStack, sourceDepth)) { + expandingFlags |= ExpandingFlags.Source; + } } if (recursionFlags & RecursionFlags.Target) { targetStack[targetDepth] = target; targetDepth++; - if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, targetDepth)) expandingFlags |= ExpandingFlags.Target; + if (!(expandingFlags & ExpandingFlags.Target) && isDeeplyNestedType(target, targetStack, targetDepth)) { + expandingFlags |= ExpandingFlags.Target; + } } let originalHandler: typeof outofbandVarianceMarkerHandler; let propagatingVarianceFlags = 0 as RelationComparisonResult; if (outofbandVarianceMarkerHandler) { originalHandler = outofbandVarianceMarkerHandler; outofbandVarianceMarkerHandler = onlyUnreliable => { - propagatingVarianceFlags |= onlyUnreliable ? RelationComparisonResult.ReportsUnreliable : RelationComparisonResult.ReportsUnmeasurable; + propagatingVarianceFlags |= onlyUnreliable ? RelationComparisonResult.ReportsUnreliable + : RelationComparisonResult.ReportsUnmeasurable; return originalHandler!(onlyUnreliable); }; } @@ -21322,12 +27695,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { targetId: target.id, targetIdStack: targetStack.map(t => t.id), depth: sourceDepth, - targetDepth + targetDepth, }); result = Ternary.Maybe; } else { - tracing?.push(tracing.Phase.CheckTypes, "structuredTypeRelatedTo", { sourceId: source.id, targetId: target.id }); + tracing?.push(tracing.Phase.CheckTypes, "structuredTypeRelatedTo", { + sourceId: source.id, + targetId: target.id, + }); result = structuredTypeRelatedTo(source, target, reportErrors, intersectionState); tracing?.pop(); } @@ -21360,7 +27736,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { // A false result goes straight into global cache (when something is false under // assumptions it will also be false without assumptions) - relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags); + relation.set( + id, + (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed + | propagatingVarianceFlags, + ); resetMaybeStack(/*markAllAsSucceeded*/ false); } return result; @@ -21376,7 +27756,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function structuredTypeRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { const saveErrorInfo = captureErrorCalculationState(); let result = structuredTypeRelatedToWorker(source, target, reportErrors, intersectionState, saveErrorInfo); if (relation !== identityRelation) { @@ -21393,11 +27778,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // needs to have its constraint hoisted into an intersection with said type parameter, this way // the type param can be compared with itself in the target (with the influence of its constraint to match other parts) // For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)` - if (!result && (source.flags & TypeFlags.Intersection || source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.Union)) { - const constraint = getEffectiveConstraintOfIntersection(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types: [source], !!(target.flags & TypeFlags.Union)); + if ( + !result + && (source.flags & TypeFlags.Intersection + || source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.Union) + ) { + const constraint = getEffectiveConstraintOfIntersection( + source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], + !!(target.flags & TypeFlags.Union), + ); if (constraint && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself // TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this - result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ); } } // When the target is an intersection we need an extra property check in order to detect nested excess @@ -21409,11 +27808,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // declare let wrong: { a: { y: string } }; // let weak: { a?: { x?: number } } & { c?: string } = wrong; // Nested weak object type // - if (result && !(intersectionState & IntersectionState.Target) && target.flags & TypeFlags.Intersection && - !isGenericObjectType(target) && source.flags & (TypeFlags.Object | TypeFlags.Intersection)) { - result &= propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, /*optionalsOnly*/ false, IntersectionState.None); + if ( + result && !(intersectionState & IntersectionState.Target) && target.flags & TypeFlags.Intersection + && !isGenericObjectType(target) && source.flags & (TypeFlags.Object | TypeFlags.Intersection) + ) { + result &= propertiesRelatedTo( + source, + target, + reportErrors, + /*excludedProperties*/ undefined, + /*optionalsOnly*/ false, + IntersectionState.None, + ); if (result && isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral) { - result &= indexSignaturesRelatedTo(source, target, /*sourceIsPrimitive*/ false, reportErrors, IntersectionState.None); + result &= indexSignaturesRelatedTo( + source, + target, + /*sourceIsPrimitive*/ false, + reportErrors, + IntersectionState.None, + ); } } // When the source is an intersection we need an extra check of any optional properties in the target to @@ -21423,10 +27837,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // x = y; // Mismatched property in source intersection // } // - else if (result && isNonGenericObjectType(target) && !isArrayOrTupleType(target) && - source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType && - !some((source as IntersectionType).types, t => t === target || !!(getObjectFlags(t) & ObjectFlags.NonInferrableType))) { - result &= propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined, /*optionalsOnly*/ true, intersectionState); + else if ( + result && isNonGenericObjectType(target) && !isArrayOrTupleType(target) + && source.flags & TypeFlags.Intersection && getApparentType(source).flags & TypeFlags.StructuredType + && !some( + (source as IntersectionType).types, + t => t === target || !!(getObjectFlags(t) & ObjectFlags.NonInferrableType), + ) + ) { + result &= propertiesRelatedTo( + source, + target, + reportErrors, + /*excludedProperties*/ undefined, + /*optionalsOnly*/ true, + intersectionState, + ); } } if (result) { @@ -21435,7 +27861,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function structuredTypeRelatedToWorker(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState, saveErrorInfo: ReturnType): Ternary { + function structuredTypeRelatedToWorker( + source: Type, + target: Type, + reportErrors: boolean, + intersectionState: IntersectionState, + saveErrorInfo: ReturnType, + ): Ternary { let result: Ternary; let originalErrorInfo: DiagnosticMessageChain | undefined; let varianceCheckFailed = false; @@ -21444,28 +27876,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (relation === identityRelation) { // We've already checked that source.flags and target.flags are identical if (sourceFlags & TypeFlags.UnionOrIntersection) { - let result = eachTypeRelatedToSomeType(source as UnionOrIntersectionType, target as UnionOrIntersectionType); + let result = eachTypeRelatedToSomeType( + source as UnionOrIntersectionType, + target as UnionOrIntersectionType, + ); if (result) { - result &= eachTypeRelatedToSomeType(target as UnionOrIntersectionType, source as UnionOrIntersectionType); + result &= eachTypeRelatedToSomeType( + target as UnionOrIntersectionType, + source as UnionOrIntersectionType, + ); } return result; } if (sourceFlags & TypeFlags.Index) { - return isRelatedTo((source as IndexType).type, (target as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false); + return isRelatedTo( + (source as IndexType).type, + (target as IndexType).type, + RecursionFlags.Both, + /*reportErrors*/ false, + ); } if (sourceFlags & TypeFlags.IndexedAccess) { - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + result = isRelatedTo( + (source as IndexedAccessType).objectType, + (target as IndexedAccessType).objectType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + (source as IndexedAccessType).indexType, + (target as IndexedAccessType).indexType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { return result; } } } if (sourceFlags & TypeFlags.Conditional) { - if ((source as ConditionalType).root.isDistributive === (target as ConditionalType).root.isDistributive) { - if (result = isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as ConditionalType).extendsType, (target as ConditionalType).extendsType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + (source as ConditionalType).root.isDistributive + === (target as ConditionalType).root.isDistributive + ) { + if ( + result = isRelatedTo( + (source as ConditionalType).checkType, + (target as ConditionalType).checkType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + (source as ConditionalType).extendsType, + (target as ConditionalType).extendsType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + getTrueTypeFromConditionalType(source as ConditionalType), + getTrueTypeFromConditionalType(target as ConditionalType), + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + getFalseTypeFromConditionalType(source as ConditionalType), + getFalseTypeFromConditionalType(target as ConditionalType), + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { return result; } } @@ -21474,8 +27962,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (sourceFlags & TypeFlags.Substitution) { - if (result = isRelatedTo((source as SubstitutionType).baseType, (target as SubstitutionType).baseType, RecursionFlags.Both, /*reportErrors*/ false)) { - if (result &= isRelatedTo((source as SubstitutionType).constraint, (target as SubstitutionType).constraint, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + result = isRelatedTo( + (source as SubstitutionType).baseType, + (target as SubstitutionType).baseType, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { + if ( + result &= isRelatedTo( + (source as SubstitutionType).constraint, + (target as SubstitutionType).constraint, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { return result; } } @@ -21494,9 +27996,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Source is an intersection, target is an object (e.g. { a } & { b } <=> { a, b }). // Source is an intersection, target is a union (e.g. { a } & { b: boolean } <=> { a, b: true } | { a, b: false }). // Source is an intersection, target instantiable (e.g. string & { tag } <=> T["a"] constrained to string & { tag }). - if (!(sourceFlags & TypeFlags.Instantiable || - sourceFlags & TypeFlags.Object && targetFlags & TypeFlags.Union || - sourceFlags & TypeFlags.Intersection && targetFlags & (TypeFlags.Object | TypeFlags.Union | TypeFlags.Instantiable))) { + if ( + !(sourceFlags & TypeFlags.Instantiable + || sourceFlags & TypeFlags.Object && targetFlags & TypeFlags.Union + || sourceFlags & TypeFlags.Intersection + && targetFlags & (TypeFlags.Object | TypeFlags.Union | TypeFlags.Instantiable)) + ) { return Ternary.False; } } @@ -21504,16 +28009,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We limit alias variance probing to only object and conditional types since their alias behavior // is more predictable than other, interned types, which may or may not have an alias depending on // the order in which things were checked. - if (sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol && source.aliasTypeArguments && - source.aliasSymbol === target.aliasSymbol && !(isMarkerType(source) || isMarkerType(target))) { + if ( + sourceFlags & (TypeFlags.Object | TypeFlags.Conditional) && source.aliasSymbol + && source.aliasTypeArguments + && source.aliasSymbol === target.aliasSymbol && !(isMarkerType(source) || isMarkerType(target)) + ) { const variances = getAliasVariances(source.aliasSymbol); if (variances === emptyArray) { return Ternary.Unknown; } const params = getSymbolLinks(source.aliasSymbol).typeParameters!; const minParams = getMinTypeArgumentCount(params); - const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); - const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); + const sourceTypes = fillMissingTypeArguments( + source.aliasTypeArguments, + params, + minParams, + isInJSFile(source.aliasSymbol.valueDeclaration), + ); + const targetTypes = fillMissingTypeArguments( + target.aliasTypeArguments, + params, + minParams, + isInJSFile(source.aliasSymbol.valueDeclaration), + ); const varianceResult = relateVariances(sourceTypes, targetTypes, variances, intersectionState); if (varianceResult !== undefined) { return varianceResult; @@ -21522,18 +28040,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For a generic type T and a type U that is assignable to T, [...U] is assignable to T, U is assignable to readonly [...T], // and U is assignable to [...T] when U is constrained to a mutable array or tuple type. - if (isSingleElementGenericTupleType(source) && !source.target.readonly && (result = isRelatedTo(getTypeArguments(source)[0], target, RecursionFlags.Source)) || - isSingleElementGenericTupleType(target) && (target.target.readonly || isMutableArrayOrTuple(getBaseConstraintOfType(source) || source)) && (result = isRelatedTo(source, getTypeArguments(target)[0], RecursionFlags.Target))) { + if ( + isSingleElementGenericTupleType(source) && !source.target.readonly + && (result = isRelatedTo(getTypeArguments(source)[0], target, RecursionFlags.Source)) + || isSingleElementGenericTupleType(target) + && (target.target.readonly || isMutableArrayOrTuple(getBaseConstraintOfType(source) || source)) + && (result = isRelatedTo(source, getTypeArguments(target)[0], RecursionFlags.Target)) + ) { return result; } if (targetFlags & TypeFlags.TypeParameter) { // A source type { [P in Q]: X } is related to a target type T if keyof T is related to Q and X is related to T[Q]. - if (getObjectFlags(source) & ObjectFlags.Mapped && !(source as MappedType).declaration.nameType && isRelatedTo(getIndexType(target), getConstraintTypeFromMappedType(source as MappedType), RecursionFlags.Both)) { - + if ( + getObjectFlags(source) & ObjectFlags.Mapped && !(source as MappedType).declaration.nameType + && isRelatedTo( + getIndexType(target), + getConstraintTypeFromMappedType(source as MappedType), + RecursionFlags.Both, + ) + ) { if (!(getMappedTypeModifiers(source as MappedType) & MappedTypeModifiers.IncludeOptional)) { const templateType = getTemplateTypeFromMappedType(source as MappedType); - const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(source as MappedType)); + const indexedAccessType = getIndexedAccessType( + target, + getTypeParameterFromMappedType(source as MappedType), + ); if (result = isRelatedTo(templateType, indexedAccessType, RecursionFlags.Both, reportErrors)) { return result; } @@ -21545,7 +28077,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let constraint = getConstraintOfTypeParameter(source); if (constraint && hasNonCircularBaseConstraint(source)) { while (constraint && someType(constraint, c => !!(c.flags & TypeFlags.TypeParameter))) { - if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false)) { + if ( + result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false) + ) { return result; } constraint = getConstraintOfTypeParameter(constraint); @@ -21558,14 +28092,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetType = (target as IndexType).type; // A keyof S is related to a keyof T if T is related to S. if (sourceFlags & TypeFlags.Index) { - if (result = isRelatedTo(targetType, (source as IndexType).type, RecursionFlags.Both, /*reportErrors*/ false)) { + if ( + result = isRelatedTo( + targetType, + (source as IndexType).type, + RecursionFlags.Both, + /*reportErrors*/ false, + ) + ) { return result; } } if (isTupleType(targetType)) { // An index type can have a tuple type target when the tuple type contains variadic elements. // Check if the source is related to the known keys of the tuple type. - if (result = isRelatedTo(source, getKnownKeysOfTupleType(targetType), RecursionFlags.Target, reportErrors)) { + if ( + result = isRelatedTo( + source, + getKnownKeysOfTupleType(targetType), + RecursionFlags.Target, + reportErrors, + ) + ) { return result; } } @@ -21578,7 +28126,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // false positives. For example, given 'T extends { [K in keyof T]: string }', // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when // related to other types. - if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).indexFlags | IndexFlags.NoReducibleCheck), RecursionFlags.Target, reportErrors) === Ternary.True) { + if ( + isRelatedTo( + source, + getIndexType( + constraint, + (target as IndexType).indexFlags | IndexFlags.NoReducibleCheck, + ), + RecursionFlags.Target, + reportErrors, + ) === Ternary.True + ) { return Ternary.True; } } @@ -21599,7 +28157,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { modifiersType, TypeFlags.StringOrNumberLiteralOrUnique, /*stringsOnly*/ false, - t => void mappedKeys.push(instantiateType(nameType, appendTypeMapping(targetType.mapper, getTypeParameterFromMappedType(targetType), t))) + t => void mappedKeys.push( + instantiateType( + nameType, + appendTypeMapping( + targetType.mapper, + getTypeParameterFromMappedType(targetType), + t, + ), + ), + ), ); // We still need to include the non-apparent (and thus still generic) keys in the target side of the comparison (in case they're in the source side) targetKeys = getUnionType([...mappedKeys, nameType]); @@ -21617,8 +28184,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sourceFlags & TypeFlags.IndexedAccess) { // Relate components directly before falling back to constraint relationships // A type S[K] is related to a type T[J] if S is related to T and K is related to J. - if (result = isRelatedTo((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType, RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo((source as IndexedAccessType).indexType, (target as IndexedAccessType).indexType, RecursionFlags.Both, reportErrors); + if ( + result = isRelatedTo( + (source as IndexedAccessType).objectType, + (target as IndexedAccessType).objectType, + RecursionFlags.Both, + reportErrors, + ) + ) { + result &= isRelatedTo( + (source as IndexedAccessType).indexType, + (target as IndexedAccessType).indexType, + RecursionFlags.Both, + reportErrors, + ); } if (result) { return result; @@ -21635,19 +28214,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseObjectType = getBaseConstraintOfType(objectType) || objectType; const baseIndexType = getBaseConstraintOfType(indexType) || indexType; if (!isGenericObjectType(baseObjectType) && !isGenericIndexType(baseIndexType)) { - const accessFlags = AccessFlags.Writing | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0); + const accessFlags = AccessFlags.Writing + | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0); const constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, accessFlags); if (constraint) { if (reportErrors && originalErrorInfo) { // create a new chain for the constraint error resetErrorInfo(saveErrorInfo); } - if (result = isRelatedTo(source, constraint, RecursionFlags.Target, reportErrors, /*headMessage*/ undefined, intersectionState)) { + if ( + result = isRelatedTo( + source, + constraint, + RecursionFlags.Target, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ) + ) { return result; } // prefer the shorter chain of the constraint comparison chain, and the direct comparison chain if (reportErrors && originalErrorInfo && errorInfo) { - errorInfo = countMessageChainBreadth([originalErrorInfo]) <= countMessageChainBreadth([errorInfo]) ? originalErrorInfo : errorInfo; + errorInfo = countMessageChainBreadth([originalErrorInfo]) + <= countMessageChainBreadth([errorInfo]) ? originalErrorInfo : errorInfo; } } } @@ -21664,33 +28254,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) { // If the mapped type has shape `{ [P in Q]: T[P] }`, // source `S` is related to target if `T` = `S`, i.e. `S` is related to `{ [P in Q]: S[P] }`. - if (!keysRemapped && templateType.flags & TypeFlags.IndexedAccess && (templateType as IndexedAccessType).objectType === source && - (templateType as IndexedAccessType).indexType === getTypeParameterFromMappedType(target)) { + if ( + !keysRemapped && templateType.flags & TypeFlags.IndexedAccess + && (templateType as IndexedAccessType).objectType === source + && (templateType as IndexedAccessType).indexType === getTypeParameterFromMappedType(target) + ) { return Ternary.True; } if (!isGenericMappedType(source)) { // If target has shape `{ [P in Q as R]: T}`, then its keys have type `R`. // If target has shape `{ [P in Q]: T }`, then its keys have type `Q`. - const targetKeys = keysRemapped ? getNameTypeFromMappedType(target)! : getConstraintTypeFromMappedType(target); + const targetKeys = keysRemapped ? getNameTypeFromMappedType(target)! + : getConstraintTypeFromMappedType(target); // Type of the keys of source type `S`, i.e. `keyof S`. const sourceKeys = getIndexType(source, IndexFlags.NoIndexSignatures); const includeOptional = modifiers & MappedTypeModifiers.IncludeOptional; - const filteredByApplicability = includeOptional ? intersectTypes(targetKeys, sourceKeys) : undefined; + const filteredByApplicability = includeOptional ? intersectTypes(targetKeys, sourceKeys) + : undefined; // A source type `S` is related to a target type `{ [P in Q]: T }` if `Q` is related to `keyof S` and `S[Q]` is related to `T`. // A source type `S` is related to a target type `{ [P in Q as R]: T }` if `R` is related to `keyof S` and `S[R]` is related to `T. // A source type `S` is related to a target type `{ [P in Q]?: T }` if some constituent `Q'` of `Q` is related to `keyof S` and `S[Q']` is related to `T`. // A source type `S` is related to a target type `{ [P in Q as R]?: T }` if some constituent `R'` of `R` is related to `keyof S` and `S[R']` is related to `T`. - if (includeOptional - ? !(filteredByApplicability!.flags & TypeFlags.Never) - : isRelatedTo(targetKeys, sourceKeys, RecursionFlags.Both)) { + if ( + includeOptional + ? !(filteredByApplicability!.flags & TypeFlags.Never) + : isRelatedTo(targetKeys, sourceKeys, RecursionFlags.Both) + ) { const templateType = getTemplateTypeFromMappedType(target); const typeParameter = getTypeParameterFromMappedType(target); // Fastpath: When the template type has the form `Obj[P]` where `P` is the mapped type parameter, directly compare source `S` with `Obj` // to avoid creating the (potentially very large) number of new intermediate types made by manufacturing `S[P]`. const nonNullComponent = extractTypesOfKind(templateType, ~TypeFlags.Nullable); - if (!keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter) { - if (result = isRelatedTo(source, (nonNullComponent as IndexedAccessType).objectType, RecursionFlags.Target, reportErrors)) { + if ( + !keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess + && (nonNullComponent as IndexedAccessType).indexType === typeParameter + ) { + if ( + result = isRelatedTo( + source, + (nonNullComponent as IndexedAccessType).objectType, + RecursionFlags.Target, + reportErrors, + ) + ) { return result; } } @@ -21707,11 +28314,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const indexingType = keysRemapped ? (filteredByApplicability || targetKeys) : filteredByApplicability - ? getIntersectionType([filteredByApplicability, typeParameter]) - : typeParameter; + ? getIntersectionType([filteredByApplicability, typeParameter]) + : typeParameter; const indexedAccessType = getIndexedAccessType(source, indexingType); // Compare `S[indexingType]` to `T`, where `T` is the type of a property of the target type. - if (result = isRelatedTo(indexedAccessType, templateType, RecursionFlags.Both, reportErrors)) { + if ( + result = isRelatedTo( + indexedAccessType, + templateType, + RecursionFlags.Both, + reportErrors, + ) + ) { return result; } } @@ -21732,13 +28346,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 'infer' positions, is not distributive or is distributive but doesn't reference the check type // parameter in either of the result types, and the source isn't an instantiation of the same // conditional type (as happens when computing variance). - if (!c.root.inferTypeParameters && !isDistributionDependent(c.root) && !(source.flags & TypeFlags.Conditional && (source as ConditionalType).root === c.root)) { + if ( + !c.root.inferTypeParameters && !isDistributionDependent(c.root) + && !(source.flags & TypeFlags.Conditional && (source as ConditionalType).root === c.root) + ) { // Check if the conditional is always true or always false but still deferred for distribution purposes. - const skipTrue = !isTypeAssignableTo(getPermissiveInstantiation(c.checkType), getPermissiveInstantiation(c.extendsType)); - const skipFalse = !skipTrue && isTypeAssignableTo(getRestrictiveInstantiation(c.checkType), getRestrictiveInstantiation(c.extendsType)); + const skipTrue = !isTypeAssignableTo( + getPermissiveInstantiation(c.checkType), + getPermissiveInstantiation(c.extendsType), + ); + const skipFalse = !skipTrue + && isTypeAssignableTo( + getRestrictiveInstantiation(c.checkType), + getRestrictiveInstantiation(c.extendsType), + ); // TODO: Find a nice way to include potential conditional type breakdowns in error output, if they seem good (they usually don't) - if (result = skipTrue ? Ternary.True : isRelatedTo(source, getTrueTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { - result &= skipFalse ? Ternary.True : isRelatedTo(source, getFalseTypeFromConditionalType(c), RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState); + if ( + result = skipTrue ? Ternary.True + : isRelatedTo( + source, + getTrueTypeFromConditionalType(c), + RecursionFlags.Target, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ) + ) { + result &= skipFalse ? Ternary.True + : isRelatedTo( + source, + getFalseTypeFromConditionalType(c), + RecursionFlags.Target, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ); if (result) { return result; } @@ -21748,7 +28390,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (targetFlags & TypeFlags.TemplateLiteral) { if (sourceFlags & TypeFlags.TemplateLiteral) { if (relation === comparableRelation) { - return templateLiteralTypesDefinitelyUnrelated(source as TemplateLiteralType, target as TemplateLiteralType) ? Ternary.False : Ternary.True; + return templateLiteralTypesDefinitelyUnrelated( + source as TemplateLiteralType, + target as TemplateLiteralType, + ) ? Ternary.False : Ternary.True; } // Report unreliable variance for type variables referenced in template literal type placeholders. // For example, `foo-${number}` is related to `foo-${string}` even though number isn't related to string. @@ -21771,11 +28416,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(sourceFlags & TypeFlags.IndexedAccess && targetFlags & TypeFlags.IndexedAccess)) { const constraint = getConstraintOfType(source as TypeVariable) || unknownType; // hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed - if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) { + if ( + result = isRelatedTo( + constraint, + target, + RecursionFlags.Source, + /*reportErrors*/ false, + /*headMessage*/ undefined, + intersectionState, + ) + ) { return result; } // slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example - else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, RecursionFlags.Source, reportErrors && constraint !== unknownType && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), /*headMessage*/ undefined, intersectionState)) { + else if ( + result = isRelatedTo( + getTypeWithThisArgument(constraint, source), + target, + RecursionFlags.Source, + reportErrors && constraint !== unknownType + && !(targetFlags & sourceFlags & TypeFlags.TypeParameter), + /*headMessage*/ undefined, + intersectionState, + ) + ) { return result; } if (isMappedTypeGenericIndexedAccess(source)) { @@ -21783,7 +28447,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // substituted for P. We also want to explore type { [P in K]: E }[C], where C is the constraint of X. const indexConstraint = getConstraintOfType((source as IndexedAccessType).indexType); if (indexConstraint) { - if (result = isRelatedTo(getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint), target, RecursionFlags.Source, reportErrors)) { + if ( + result = isRelatedTo( + getIndexedAccessType((source as IndexedAccessType).objectType, indexConstraint), + target, + RecursionFlags.Source, + reportErrors, + ) + ) { return result; } } @@ -21798,7 +28469,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (sourceFlags & TypeFlags.TemplateLiteral && !(targetFlags & TypeFlags.Object)) { if (!(targetFlags & TypeFlags.TemplateLiteral)) { const constraint = getBaseConstraintOfType(source); - if (constraint && constraint !== source && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors))) { + if ( + constraint && constraint !== source + && (result = isRelatedTo(constraint, target, RecursionFlags.Source, reportErrors)) + ) { return result; } } @@ -21808,7 +28482,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ((source as StringMappingType).symbol !== (target as StringMappingType).symbol) { return Ternary.False; } - if (result = isRelatedTo((source as StringMappingType).type, (target as StringMappingType).type, RecursionFlags.Both, reportErrors)) { + if ( + result = isRelatedTo( + (source as StringMappingType).type, + (target as StringMappingType).type, + RecursionFlags.Both, + reportErrors, + ) + ) { return result; } } @@ -21834,15 +28515,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let mapper: TypeMapper | undefined; if (sourceParams) { // If the source has infer type parameters, we instantiate them in the context of the target - const ctx = createInferenceContext(sourceParams, /*signature*/ undefined, InferenceFlags.None, isRelatedToWorker); - inferTypes(ctx.inferences, (target as ConditionalType).extendsType, sourceExtends, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict); + const ctx = createInferenceContext( + sourceParams, + /*signature*/ undefined, + InferenceFlags.None, + isRelatedToWorker, + ); + inferTypes( + ctx.inferences, + (target as ConditionalType).extendsType, + sourceExtends, + InferencePriority.NoConstraints | InferencePriority.AlwaysStrict, + ); sourceExtends = instantiateType(sourceExtends, ctx.mapper); mapper = ctx.mapper; } - if (isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) && - (isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both) || isRelatedTo((target as ConditionalType).checkType, (source as ConditionalType).checkType, RecursionFlags.Both))) { - if (result = isRelatedTo(instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors); + if ( + isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) + && (isRelatedTo( + (source as ConditionalType).checkType, + (target as ConditionalType).checkType, + RecursionFlags.Both, + ) + || isRelatedTo( + (target as ConditionalType).checkType, + (source as ConditionalType).checkType, + RecursionFlags.Both, + )) + ) { + if ( + result = isRelatedTo( + instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper), + getTrueTypeFromConditionalType(target as ConditionalType), + RecursionFlags.Both, + reportErrors, + ) + ) { + result &= isRelatedTo( + getFalseTypeFromConditionalType(source as ConditionalType), + getFalseTypeFromConditionalType(target as ConditionalType), + RecursionFlags.Both, + reportErrors, + ); } if (result) { return result; @@ -21852,7 +28566,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { // conditionals aren't related to one another via distributive constraint as it is much too inaccurate and allows way // more assignments than are desirable (since it maps the source check type to its constraint, it loses information) - const distributiveConstraint = hasNonCircularBaseConstraint(source) ? getConstraintOfDistributiveConditionalType(source as ConditionalType) : undefined; + const distributiveConstraint = hasNonCircularBaseConstraint(source) + ? getConstraintOfDistributiveConditionalType(source as ConditionalType) : undefined; if (distributiveConstraint) { if (result = isRelatedTo(distributiveConstraint, target, RecursionFlags.Source, reportErrors)) { return result; @@ -21871,7 +28586,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { // An empty object type is related to any mapped type that includes a '?' modifier. - if (relation !== subtypeRelation && relation !== strictSubtypeRelation && isPartialMappedType(target) && isEmptyObjectType(source)) { + if ( + relation !== subtypeRelation && relation !== strictSubtypeRelation && isPartialMappedType(target) + && isEmptyObjectType(source) + ) { return Ternary.True; } if (isGenericMappedType(target)) { @@ -21890,8 +28608,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (isGenericMappedType(source)) { return Ternary.False; } - if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target && - !isTupleType(source) && !(isMarkerType(source) || isMarkerType(target))) { + if ( + getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference + && (source as TypeReference).target === (target as TypeReference).target + && !isTupleType(source) && !(isMarkerType(source) || isMarkerType(target)) + ) { // When strictNullChecks is disabled, the element type of the empty array literal is undefinedWideningType, // and an empty array literal wouldn't be assignable to a `never[]` without this check. if (isEmptyArrayLiteralType(source)) { @@ -21907,14 +28628,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (variances === emptyArray) { return Ternary.Unknown; } - const varianceResult = relateVariances(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), variances, intersectionState); + const varianceResult = relateVariances( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + variances, + intersectionState, + ); if (varianceResult !== undefined) { return varianceResult; } } - else if (isReadonlyArrayType(target) ? everyType(source, isArrayOrTupleType) : isArrayType(target) && everyType(source, t => isTupleType(t) && !t.target.readonly)) { + else if ( + isReadonlyArrayType(target) ? everyType(source, isArrayOrTupleType) + : isArrayType(target) && everyType(source, t => isTupleType(t) && !t.target.readonly) + ) { if (relation !== identityRelation) { - return isRelatedTo(getIndexTypeOfType(source, numberType) || anyType, getIndexTypeOfType(target, numberType) || anyType, RecursionFlags.Both, reportErrors); + return isRelatedTo( + getIndexTypeOfType(source, numberType) || anyType, + getIndexTypeOfType(target, numberType) || anyType, + RecursionFlags.Both, + reportErrors, + ); } else { // By flags alone, we know that the `target` is a readonly array while the source is a normal array or tuple @@ -21930,7 +28664,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // A fresh empty object type is never a subtype of a non-empty object type. This ensures fresh({}) <: { [x: string]: xxx } // but not vice-versa. Without this rule, those types would be mutual subtypes. - else if ((relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) { + else if ( + (relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) + && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source) + ) { return Ternary.False; } // Even if relationship doesn't hold for unions, intersections, or generic type references, @@ -21940,14 +28677,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // relates to X. Thus, we include intersection types on the source side here. if (sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && targetFlags & TypeFlags.Object) { // Report structural errors only if we haven't reported any errors yet - const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo && !sourceIsPrimitive; - result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined, /*optionalsOnly*/ false, intersectionState); + const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo.errorInfo + && !sourceIsPrimitive; + result = propertiesRelatedTo( + source, + target, + reportStructuralErrors, + /*excludedProperties*/ undefined, + /*optionalsOnly*/ false, + intersectionState, + ); if (result) { - result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors, intersectionState); + result &= signaturesRelatedTo( + source, + target, + SignatureKind.Call, + reportStructuralErrors, + intersectionState, + ); if (result) { - result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportStructuralErrors, intersectionState); + result &= signaturesRelatedTo( + source, + target, + SignatureKind.Construct, + reportStructuralErrors, + intersectionState, + ); if (result) { - result &= indexSignaturesRelatedTo(source, target, sourceIsPrimitive, reportStructuralErrors, intersectionState); + result &= indexSignaturesRelatedTo( + source, + target, + sourceIsPrimitive, + reportStructuralErrors, + intersectionState, + ); } } } @@ -21963,7 +28726,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // with respect to T. We do not report errors here, as we will use the existing // error result from checking each constituent of the union. if (sourceFlags & (TypeFlags.Object | TypeFlags.Intersection) && targetFlags & TypeFlags.Union) { - const objectOnlyTarget = extractTypesOfKind(target, TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Substitution); + const objectOnlyTarget = extractTypesOfKind( + target, + TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Substitution, + ); if (objectOnlyTarget.flags & TypeFlags.Union) { const result = typeRelatedToDiscriminatedType(source, objectOnlyTarget as UnionType); if (result) { @@ -21979,8 +28745,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return reduceLeft(info, (value, chain) => value + 1 + countMessageChainBreadth(chain.next), 0); } - function relateVariances(sourceTypeArguments: readonly Type[] | undefined, targetTypeArguments: readonly Type[] | undefined, variances: VarianceFlags[], intersectionState: IntersectionState) { - if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors, intersectionState)) { + function relateVariances( + sourceTypeArguments: readonly Type[] | undefined, + targetTypeArguments: readonly Type[] | undefined, + variances: VarianceFlags[], + intersectionState: IntersectionState, + ) { + if ( + result = typeArgumentsRelatedTo( + sourceTypeArguments, + targetTypeArguments, + variances, + reportErrors, + intersectionState, + ) + ) { return result; } if (some(variances, v => !!(v & VarianceFlags.AllowsStructuralFallback))) { @@ -21992,7 +28771,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resetErrorInfo(saveErrorInfo); return undefined; } - const allowStructuralFallback = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances); + const allowStructuralFallback = targetTypeArguments + && hasCovariantVoidArgument(targetTypeArguments, variances); varianceCheckFailed = !allowStructuralFallback; // The type arguments did not relate appropriately, but it may be because we have no variance // information (in which case typeArgumentsRelatedTo defaulted to covariance for all type @@ -22010,7 +28790,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // reveal the reason). // We can switch on `reportErrors` here, since varianceCheckFailed guarantees we return `False`, // we can return `False` early here to skip calculating the structural error message we don't need. - if (varianceCheckFailed && !(reportErrors && some(variances, v => (v & VarianceFlags.VarianceMask) === VarianceFlags.Invariant))) { + if ( + varianceCheckFailed + && !(reportErrors + && some(variances, v => (v & VarianceFlags.VarianceMask) === VarianceFlags.Invariant)) + ) { return Ternary.False; } // We remember the original error information so we can restore it in case the structural @@ -22026,16 +28810,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary { - const modifiersRelated = relation === comparableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) : - getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); + const modifiersRelated = relation === comparableRelation + || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) + : getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); if (modifiersRelated) { let result: Ternary; const targetConstraint = getConstraintTypeFromMappedType(target); - const sourceConstraint = instantiateType(getConstraintTypeFromMappedType(source), getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMapper : reportUnreliableMapper); + const sourceConstraint = instantiateType( + getConstraintTypeFromMappedType(source), + getCombinedMappedTypeOptionality(source) < 0 ? reportUnmeasurableMapper : reportUnreliableMapper, + ); if (result = isRelatedTo(targetConstraint, sourceConstraint, RecursionFlags.Both, reportErrors)) { - const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [getTypeParameterFromMappedType(target)]); - if (instantiateType(getNameTypeFromMappedType(source), mapper) === instantiateType(getNameTypeFromMappedType(target), mapper)) { - return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(source), mapper), getTemplateTypeFromMappedType(target), RecursionFlags.Both, reportErrors); + const mapper = createTypeMapper([getTypeParameterFromMappedType(source)], [ + getTypeParameterFromMappedType(target), + ]); + if ( + instantiateType(getNameTypeFromMappedType(source), mapper) + === instantiateType(getNameTypeFromMappedType(target), mapper) + ) { + return result + & isRelatedTo( + instantiateType(getTemplateTypeFromMappedType(source), mapper), + getTemplateTypeFromMappedType(target), + RecursionFlags.Both, + reportErrors, + ); } } } @@ -22067,7 +28866,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { numCombinations *= countTypes(getNonMissingTypeOfSymbol(sourceProperty)); if (numCombinations > 25) { // We've reached the complexity limit. - tracing?.instant(tracing.Phase.CheckTypes, "typeRelatedToDiscriminatedType_DepthLimit", { sourceId: source.id, targetId: target.id, numCombinations }); + tracing?.instant(tracing.Phase.CheckTypes, "typeRelatedToDiscriminatedType_DepthLimit", { + sourceId: source.id, + targetId: target.id, + numCombinations, + }); return Ternary.False; } } @@ -22090,14 +28893,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const matchingTypes: Type[] = []; for (const combination of discriminantCombinations) { let hasMatch = false; - outer: for (const type of target.types) { + outer: + for (const type of target.types) { for (let i = 0; i < sourcePropertiesFiltered.length; i++) { const sourceProperty = sourcePropertiesFiltered[i]; const targetProperty = getPropertyOfType(type, sourceProperty.escapedName); if (!targetProperty) continue outer; if (sourceProperty === targetProperty) continue; // We compare the source property to the target in the context of a single discriminant type. - const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false, IntersectionState.None, /*skipOptional*/ strictNullChecks || relation === comparableRelation); + const related = propertyRelatedTo( + source, + target, + sourceProperty, + targetProperty, + _ => combination[i], + /*reportErrors*/ false, + IntersectionState.None, + /*skipOptional*/ strictNullChecks || relation === comparableRelation, + ); // If the target property could not be found, or if the properties were not related, // then this constituent is not a match. if (!related) { @@ -22116,17 +28929,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Compare the remaining non-discriminant properties of each match. let result = Ternary.True; for (const type of matchingTypes) { - result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties, /*optionalsOnly*/ false, IntersectionState.None); + result &= propertiesRelatedTo( + source, + type, + /*reportErrors*/ false, + excludedProperties, + /*optionalsOnly*/ false, + IntersectionState.None, + ); if (result) { - result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportErrors*/ false, IntersectionState.None); + result &= signaturesRelatedTo( + source, + type, + SignatureKind.Call, + /*reportErrors*/ false, + IntersectionState.None, + ); if (result) { - result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportErrors*/ false, IntersectionState.None); + result &= signaturesRelatedTo( + source, + type, + SignatureKind.Construct, + /*reportErrors*/ false, + IntersectionState.None, + ); if (result && !(isTupleType(source) && isTupleType(type))) { // Comparing numeric index types when both `source` and `type` are tuples is unnecessary as the // element types should be sufficiently covered by `propertiesRelatedTo`. It also causes problems // with index type assignability as the types for the excluded discriminants are still included // in the index type. - result &= indexSignaturesRelatedTo(source, type, /*sourceIsPrimitive*/ false, /*reportErrors*/ false, IntersectionState.None); + result &= indexSignaturesRelatedTo( + source, + type, + /*sourceIsPrimitive*/ false, + /*reportErrors*/ false, + IntersectionState.None, + ); } } } @@ -22153,26 +28991,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result || properties; } - function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function isPropertySymbolTypeRelated( + sourceProp: Symbol, + targetProp: Symbol, + getTypeOfSourceProperty: (sym: Symbol) => Type, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial); - const effectiveTarget = addOptionality(getNonMissingTypeOfSymbol(targetProp), /*isProperty*/ false, targetIsOptional); + const effectiveTarget = addOptionality( + getNonMissingTypeOfSymbol(targetProp), + /*isProperty*/ false, + targetIsOptional, + ); const effectiveSource = getTypeOfSourceProperty(sourceProp); - return isRelatedTo(effectiveSource, effectiveTarget, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + return isRelatedTo( + effectiveSource, + effectiveTarget, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } - function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean, intersectionState: IntersectionState, skipOptional: boolean): Ternary { + function propertyRelatedTo( + source: Type, + target: Type, + sourceProp: Symbol, + targetProp: Symbol, + getTypeOfSourceProperty: (sym: Symbol) => Type, + reportErrors: boolean, + intersectionState: IntersectionState, + skipOptional: boolean, + ): Ternary { const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp); const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp); if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) { if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) { if (reportErrors) { if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) { - reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp)); + reportError( + Diagnostics.Types_have_separate_declarations_of_a_private_property_0, + symbolToString(targetProp), + ); } else { - reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp), + reportError( + Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, + symbolToString(targetProp), typeToString(sourcePropFlags & ModifierFlags.Private ? source : target), - typeToString(sourcePropFlags & ModifierFlags.Private ? target : source)); + typeToString(sourcePropFlags & ModifierFlags.Private ? target : source), + ); } } return Ternary.False; @@ -22181,16 +29051,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (targetPropFlags & ModifierFlags.Protected) { if (!isValidOverrideOf(sourceProp, targetProp)) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, symbolToString(targetProp), - typeToString(getDeclaringClass(sourceProp) || source), typeToString(getDeclaringClass(targetProp) || target)); + reportError( + Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, + symbolToString(targetProp), + typeToString(getDeclaringClass(sourceProp) || source), + typeToString(getDeclaringClass(targetProp) || target), + ); } return Ternary.False; } } else if (sourcePropFlags & ModifierFlags.Protected) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, - symbolToString(targetProp), typeToString(source), typeToString(target)); + reportError( + Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, + symbolToString(targetProp), + typeToString(source), + typeToString(target), + ); } return Ternary.False; } @@ -22202,21 +29080,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // They're still assignable to one another, since `readonly` doesn't affect assignability. // This is only applied during the strictSubtypeRelation -- currently used in subtype reduction if ( - relation === strictSubtypeRelation && - isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp) + relation === strictSubtypeRelation + && isReadonlySymbol(sourceProp) && !isReadonlySymbol(targetProp) ) { return Ternary.False; } // If the target comes from a partial union prop, allow `undefined` in the target type - const related = isPropertySymbolTypeRelated(sourceProp, targetProp, getTypeOfSourceProperty, reportErrors, intersectionState); + const related = isPropertySymbolTypeRelated( + sourceProp, + targetProp, + getTypeOfSourceProperty, + reportErrors, + intersectionState, + ); if (!related) { if (reportErrors) { - reportIncompatibleError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp)); + reportIncompatibleError( + Diagnostics.Types_of_property_0_are_incompatible, + symbolToString(targetProp), + ); } return Ternary.False; } // When checking for comparability, be more lenient with optional properties. - if (!skipOptional && sourceProp.flags & SymbolFlags.Optional && targetProp.flags & SymbolFlags.ClassMember && !(targetProp.flags & SymbolFlags.Optional)) { + if ( + !skipOptional && sourceProp.flags & SymbolFlags.Optional && targetProp.flags & SymbolFlags.ClassMember + && !(targetProp.flags & SymbolFlags.Optional) + ) { // TypeScript 1.0 spec (April 2014): 3.8.3 // S is a subtype of a type T, and T is a supertype of S if ... // S' and T are object types and, for each member M in T.. @@ -22225,45 +29115,85 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (M - property in T) // (N - property in S) if (reportErrors) { - reportError(Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, - symbolToString(targetProp), typeToString(source), typeToString(target)); + reportError( + Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2, + symbolToString(targetProp), + typeToString(source), + typeToString(target), + ); } return Ternary.False; } return related; } - function reportUnmatchedProperty(source: Type, target: Type, unmatchedProperty: Symbol, requireOptionalProperties: boolean) { + function reportUnmatchedProperty( + source: Type, + target: Type, + unmatchedProperty: Symbol, + requireOptionalProperties: boolean, + ) { let shouldSkipElaboration = false; // give specific error in case where private names have the same description - if (unmatchedProperty.valueDeclaration + if ( + unmatchedProperty.valueDeclaration && isNamedDeclaration(unmatchedProperty.valueDeclaration) && isPrivateIdentifier(unmatchedProperty.valueDeclaration.name) && source.symbol - && source.symbol.flags & SymbolFlags.Class) { + && source.symbol.flags & SymbolFlags.Class + ) { const privateIdentifierDescription = unmatchedProperty.valueDeclaration.name.escapedText; const symbolTableKey = getSymbolNameForPrivateIdentifier(source.symbol, privateIdentifierDescription); if (symbolTableKey && getPropertyOfType(source, symbolTableKey)) { const sourceName = factory.getDeclarationName(source.symbol.valueDeclaration); const targetName = factory.getDeclarationName(target.symbol.valueDeclaration); reportError( - Diagnostics.Property_0_in_type_1_refers_to_a_different_member_that_cannot_be_accessed_from_within_type_2, + Diagnostics + .Property_0_in_type_1_refers_to_a_different_member_that_cannot_be_accessed_from_within_type_2, diagnosticName(privateIdentifierDescription), diagnosticName(sourceName.escapedText === "" ? anon : sourceName), - diagnosticName(targetName.escapedText === "" ? anon : targetName)); + diagnosticName(targetName.escapedText === "" ? anon : targetName), + ); return; } } - const props = arrayFrom(getUnmatchedProperties(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false)); - if (!headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code && - headMessage.code !== Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code)) { + const props = arrayFrom( + getUnmatchedProperties( + source, + target, + requireOptionalProperties, + /*matchDiscriminantProperties*/ false, + ), + ); + if ( + !headMessage || (headMessage.code !== Diagnostics.Class_0_incorrectly_implements_interface_1.code + && headMessage.code + !== Diagnostics + .Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass + .code) + ) { shouldSkipElaboration = true; // Retain top-level error for interface implementing issues, otherwise omit it } if (props.length === 1) { - const propName = symbolToString(unmatchedProperty, /*enclosingDeclaration*/ undefined, SymbolFlags.None, SymbolFormatFlags.AllowAnyNodeKind | SymbolFormatFlags.WriteComputedProps); - reportError(Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, propName, ...getTypeNamesForErrorDisplay(source, target)); + const propName = symbolToString( + unmatchedProperty, + /*enclosingDeclaration*/ undefined, + SymbolFlags.None, + SymbolFormatFlags.AllowAnyNodeKind | SymbolFormatFlags.WriteComputedProps, + ); + reportError( + Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2, + propName, + ...getTypeNamesForErrorDisplay(source, target), + ); if (length(unmatchedProperty.declarations)) { - associateRelatedInfo(createDiagnosticForNode(unmatchedProperty.declarations![0], Diagnostics._0_is_declared_here, propName)); + associateRelatedInfo( + createDiagnosticForNode( + unmatchedProperty.declarations![0], + Diagnostics._0_is_declared_here, + propName, + ), + ); } if (shouldSkipElaboration && errorInfo) { overrideNextErrorInfo++; @@ -22271,10 +29201,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (tryElaborateArrayLikeErrors(source, target, /*reportErrors*/ false)) { if (props.length > 5) { // arbitrary cutoff for too-long list form - reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, typeToString(source), typeToString(target), map(props.slice(0, 4), p => symbolToString(p)).join(", "), props.length - 4); + reportError( + Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more, + typeToString(source), + typeToString(target), + map(props.slice(0, 4), p => symbolToString(p)).join(", "), + props.length - 4, + ); } else { - reportError(Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, typeToString(source), typeToString(target), map(props, p => symbolToString(p)).join(", ")); + reportError( + Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2, + typeToString(source), + typeToString(target), + map(props, p => symbolToString(p)).join(", "), + ); } if (shouldSkipElaboration && errorInfo) { overrideNextErrorInfo++; @@ -22283,41 +29224,66 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // No array like or unmatched property error - just issue top level error (errorInfo = undefined) } - function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean, excludedProperties: Set<__String> | undefined, optionalsOnly: boolean, intersectionState: IntersectionState): Ternary { + function propertiesRelatedTo( + source: Type, + target: Type, + reportErrors: boolean, + excludedProperties: Set<__String> | undefined, + optionalsOnly: boolean, + intersectionState: IntersectionState, + ): Ternary { if (relation === identityRelation) { return propertiesIdenticalTo(source, target, excludedProperties); } let result = Ternary.True; if (isTupleType(target)) { if (isArrayOrTupleType(source)) { - if (!target.target.readonly && (isReadonlyArrayType(source) || isTupleType(source) && source.target.readonly)) { + if ( + !target.target.readonly + && (isReadonlyArrayType(source) || isTupleType(source) && source.target.readonly) + ) { return Ternary.False; } const sourceArity = getTypeReferenceArity(source); const targetArity = getTypeReferenceArity(target); - const sourceRestFlag = isTupleType(source) ? source.target.combinedFlags & ElementFlags.Rest : ElementFlags.Rest; + const sourceRestFlag = isTupleType(source) ? source.target.combinedFlags & ElementFlags.Rest + : ElementFlags.Rest; const targetRestFlag = target.target.combinedFlags & ElementFlags.Rest; const sourceMinLength = isTupleType(source) ? source.target.minLength : 0; const targetMinLength = target.target.minLength; if (!sourceRestFlag && sourceArity < targetMinLength) { if (reportErrors) { - reportError(Diagnostics.Source_has_0_element_s_but_target_requires_1, sourceArity, targetMinLength); + reportError( + Diagnostics.Source_has_0_element_s_but_target_requires_1, + sourceArity, + targetMinLength, + ); } return Ternary.False; } if (!targetRestFlag && targetArity < sourceMinLength) { if (reportErrors) { - reportError(Diagnostics.Source_has_0_element_s_but_target_allows_only_1, sourceMinLength, targetArity); + reportError( + Diagnostics.Source_has_0_element_s_but_target_allows_only_1, + sourceMinLength, + targetArity, + ); } return Ternary.False; } if (!targetRestFlag && (sourceRestFlag || targetArity < sourceArity)) { if (reportErrors) { if (sourceMinLength < targetMinLength) { - reportError(Diagnostics.Target_requires_0_element_s_but_source_may_have_fewer, targetMinLength); + reportError( + Diagnostics.Target_requires_0_element_s_but_source_may_have_fewer, + targetMinLength, + ); } else { - reportError(Diagnostics.Target_allows_only_0_element_s_but_source_may_have_more, targetArity); + reportError( + Diagnostics.Target_allows_only_0_element_s_but_source_may_have_more, + targetArity, + ); } } return Ternary.False; @@ -22329,7 +29295,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetHasRestElement = target.target.hasRestElement; let canExcludeDiscriminants = !!excludedProperties; for (let sourcePosition = 0; sourcePosition < sourceArity; sourcePosition++) { - const sourceFlags = isTupleType(source) ? source.target.elementFlags[sourcePosition] : ElementFlags.Rest; + const sourceFlags = isTupleType(source) ? source.target.elementFlags[sourcePosition] + : ElementFlags.Rest; const sourcePositionFromEnd = sourceArity - 1 - sourcePosition; const targetPosition = targetHasRestElement && sourcePosition >= targetStartCount @@ -22340,19 +29307,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (targetFlags & ElementFlags.Variadic && !(sourceFlags & ElementFlags.Variadic)) { if (reportErrors) { - reportError(Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, targetPosition); + reportError( + Diagnostics.Source_provides_no_match_for_variadic_element_at_position_0_in_target, + targetPosition, + ); } return Ternary.False; } if (sourceFlags & ElementFlags.Variadic && !(targetFlags & ElementFlags.Variable)) { if (reportErrors) { - reportError(Diagnostics.Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, sourcePosition, targetPosition); + reportError( + Diagnostics + .Variadic_element_at_position_0_in_source_does_not_match_element_at_position_1_in_target, + sourcePosition, + targetPosition, + ); } return Ternary.False; } if (targetFlags & ElementFlags.Required && !(sourceFlags & ElementFlags.Required)) { if (reportErrors) { - reportError(Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, targetPosition); + reportError( + Diagnostics.Source_provides_no_match_for_required_element_at_position_0_in_target, + targetPosition, + ); } return Ternary.False; } @@ -22366,19 +29344,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - const sourceType = removeMissingType(sourceTypeArguments[sourcePosition], !!(sourceFlags & targetFlags & ElementFlags.Optional)); + const sourceType = removeMissingType( + sourceTypeArguments[sourcePosition], + !!(sourceFlags & targetFlags & ElementFlags.Optional), + ); const targetType = targetTypeArguments[targetPosition]; - const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest ? createArrayType(targetType) : - removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional)); - const related = isRelatedTo(sourceType, targetCheckType, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + const targetCheckType = sourceFlags & ElementFlags.Variadic && targetFlags & ElementFlags.Rest + ? createArrayType(targetType) + : removeMissingType(targetType, !!(targetFlags & ElementFlags.Optional)); + const related = isRelatedTo( + sourceType, + targetCheckType, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (!related) { if (reportErrors && (targetArity > 1 || sourceArity > 1)) { - if (targetHasRestElement && sourcePosition >= targetStartCount && sourcePositionFromEnd >= targetEndCount && targetStartCount !== sourceArity - targetEndCount - 1) { - reportIncompatibleError(Diagnostics.Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, targetStartCount, sourceArity - targetEndCount - 1, targetPosition); + if ( + targetHasRestElement && sourcePosition >= targetStartCount + && sourcePositionFromEnd >= targetEndCount + && targetStartCount !== sourceArity - targetEndCount - 1 + ) { + reportIncompatibleError( + Diagnostics + .Type_at_positions_0_through_1_in_source_is_not_compatible_with_type_at_position_2_in_target, + targetStartCount, + sourceArity - targetEndCount - 1, + targetPosition, + ); } else { - reportIncompatibleError(Diagnostics.Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, sourcePosition, targetPosition); + reportIncompatibleError( + Diagnostics + .Type_at_position_0_in_source_is_not_compatible_with_type_at_position_1_in_target, + sourcePosition, + targetPosition, + ); } } return Ternary.False; @@ -22391,8 +29395,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.False; } } - const requireOptionalProperties = (relation === subtypeRelation || relation === strictSubtypeRelation) && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source); - const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false); + const requireOptionalProperties = (relation === subtypeRelation || relation === strictSubtypeRelation) + && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source); + const unmatchedProperty = getUnmatchedProperty( + source, + target, + requireOptionalProperties, + /*matchDiscriminantProperties*/ false, + ); if (unmatchedProperty) { if (reportErrors && shouldReportUnmatchedPropertyError(source, target)) { reportUnmatchedProperty(source, target, unmatchedProperty, requireOptionalProperties); @@ -22405,7 +29415,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceType = getTypeOfSymbol(sourceProp); if (!(sourceType.flags & TypeFlags.Undefined)) { if (reportErrors) { - reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target)); + reportError( + Diagnostics.Property_0_does_not_exist_on_type_1, + symbolToString(sourceProp), + typeToString(target), + ); } return Ternary.False; } @@ -22418,10 +29432,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const numericNamesOnly = isTupleType(source) && isTupleType(target); for (const targetProp of excludeProperties(properties, excludedProperties)) { const name = targetProp.escapedName; - if (!(targetProp.flags & SymbolFlags.Prototype) && (!numericNamesOnly || isNumericLiteralName(name) || name === "length") && (!optionalsOnly || targetProp.flags & SymbolFlags.Optional)) { + if ( + !(targetProp.flags & SymbolFlags.Prototype) + && (!numericNamesOnly || isNumericLiteralName(name) || name === "length") + && (!optionalsOnly || targetProp.flags & SymbolFlags.Optional) + ) { const sourceProp = getPropertyOfType(source, name); if (sourceProp && sourceProp !== targetProp) { - const related = propertyRelatedTo(source, target, sourceProp, targetProp, getNonMissingTypeOfSymbol, reportErrors, intersectionState, relation === comparableRelation); + const related = propertyRelatedTo( + source, + target, + sourceProp, + targetProp, + getNonMissingTypeOfSymbol, + reportErrors, + intersectionState, + relation === comparableRelation, + ); if (!related) { return Ternary.False; } @@ -22432,7 +29459,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function propertiesIdenticalTo(source: Type, target: Type, excludedProperties: Set<__String> | undefined): Ternary { + function propertiesIdenticalTo( + source: Type, + target: Type, + excludedProperties: Set<__String> | undefined, + ): Ternary { if (!(source.flags & TypeFlags.Object && target.flags & TypeFlags.Object)) { return Ternary.False; } @@ -22456,7 +29487,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function signaturesRelatedTo( + source: Type, + target: Type, + kind: SignatureKind, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { if (relation === identityRelation) { return signaturesIdenticalTo(source, target, kind); } @@ -22467,10 +29504,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceIsJSConstructor = source.symbol && isJSConstructor(source.symbol.valueDeclaration); const targetIsJSConstructor = target.symbol && isJSConstructor(target.symbol.valueDeclaration); - const sourceSignatures = getSignaturesOfType(source, (sourceIsJSConstructor && kind === SignatureKind.Construct) ? - SignatureKind.Call : kind); - const targetSignatures = getSignaturesOfType(target, (targetIsJSConstructor && kind === SignatureKind.Construct) ? - SignatureKind.Call : kind); + const sourceSignatures = getSignaturesOfType( + source, + (sourceIsJSConstructor && kind === SignatureKind.Construct) + ? SignatureKind.Call : kind, + ); + const targetSignatures = getSignaturesOfType( + target, + (targetIsJSConstructor && kind === SignatureKind.Construct) + ? SignatureKind.Call : kind, + ); if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) { const sourceIsAbstract = !!(sourceSignatures[0].flags & SignatureFlags.Abstract); @@ -22481,7 +29524,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // check we perform for an extends clause excludes construct signatures from the target, // so this check never proceeds. if (reportErrors) { - reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type); + reportError( + Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type, + ); } return Ternary.False; } @@ -22491,17 +29536,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let result = Ternary.True; - const incompatibleReporter = kind === SignatureKind.Construct ? reportIncompatibleConstructSignatureReturn : reportIncompatibleCallSignatureReturn; + const incompatibleReporter = kind === SignatureKind.Construct ? reportIncompatibleConstructSignatureReturn + : reportIncompatibleCallSignatureReturn; const sourceObjectFlags = getObjectFlags(source); const targetObjectFlags = getObjectFlags(target); - if (sourceObjectFlags & ObjectFlags.Instantiated && targetObjectFlags & ObjectFlags.Instantiated && source.symbol === target.symbol || - sourceObjectFlags & ObjectFlags.Reference && targetObjectFlags & ObjectFlags.Reference && (source as TypeReference).target === (target as TypeReference).target) { + if ( + sourceObjectFlags & ObjectFlags.Instantiated && targetObjectFlags & ObjectFlags.Instantiated + && source.symbol === target.symbol + || sourceObjectFlags & ObjectFlags.Reference && targetObjectFlags & ObjectFlags.Reference + && (source as TypeReference).target === (target as TypeReference).target + ) { // We have instantiations of the same anonymous type (which typically will be the type of a // method). Simply do a pairwise comparison of the signatures in the two signature lists instead // of the much more expensive N * M comparison matrix we explore below. We erase type parameters // as they are known to always be the same. for (let i = 0; i < targetSignatures.length; i++) { - const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, intersectionState, incompatibleReporter(sourceSignatures[i], targetSignatures[i])); + const related = signatureRelatedTo( + sourceSignatures[i], + targetSignatures[i], + /*erase*/ true, + reportErrors, + intersectionState, + incompatibleReporter(sourceSignatures[i], targetSignatures[i]), + ); if (!related) { return Ternary.False; } @@ -22517,23 +29574,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks; const sourceSignature = first(sourceSignatures); const targetSignature = first(targetSignatures); - result = signatureRelatedTo(sourceSignature, targetSignature, eraseGenerics, reportErrors, intersectionState, incompatibleReporter(sourceSignature, targetSignature)); - if (!result && reportErrors && kind === SignatureKind.Construct && (sourceObjectFlags & targetObjectFlags) && - (targetSignature.declaration?.kind === SyntaxKind.Constructor || sourceSignature.declaration?.kind === SyntaxKind.Constructor)) { + result = signatureRelatedTo( + sourceSignature, + targetSignature, + eraseGenerics, + reportErrors, + intersectionState, + incompatibleReporter(sourceSignature, targetSignature), + ); + if ( + !result && reportErrors && kind === SignatureKind.Construct + && (sourceObjectFlags & targetObjectFlags) + && (targetSignature.declaration?.kind === SyntaxKind.Constructor + || sourceSignature.declaration?.kind === SyntaxKind.Constructor) + ) { const constructSignatureToString = (signature: Signature) => - signatureToString(signature, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrowStyleSignature, kind); - reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, constructSignatureToString(sourceSignature), constructSignatureToString(targetSignature)); + signatureToString( + signature, + /*enclosingDeclaration*/ undefined, + TypeFormatFlags.WriteArrowStyleSignature, + kind, + ); + reportError( + Diagnostics.Type_0_is_not_assignable_to_type_1, + constructSignatureToString(sourceSignature), + constructSignatureToString(targetSignature), + ); reportError(Diagnostics.Types_of_construct_signatures_are_incompatible); return result; } } else { - outer: for (const t of targetSignatures) { + outer: + for (const t of targetSignatures) { const saveErrorInfo = captureErrorCalculationState(); // Only elaborate errors from the first failure let shouldElaborateErrors = reportErrors; for (const s of sourceSignatures) { - const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, intersectionState, incompatibleReporter(s, t)); + const related = signatureRelatedTo( + s, + t, + /*erase*/ true, + shouldElaborateErrors, + intersectionState, + incompatibleReporter(s, t), + ); if (related) { result &= related; resetErrorInfo(saveErrorInfo); @@ -22542,9 +29627,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { shouldElaborateErrors = false; } if (shouldElaborateErrors) { - reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1, + reportError( + Diagnostics.Type_0_provides_no_match_for_the_signature_1, typeToString(source), - signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind)); + signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind), + ); } return Ternary.False; } @@ -22557,8 +29644,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeConstructSignatures = getSignaturesOfStructuredType(source, SignatureKind.Construct); const typeProperties = getPropertiesOfObjectType(source); if ((typeCallSignatures.length || typeConstructSignatures.length) && !typeProperties.length) { - if ((getSignaturesOfType(target, SignatureKind.Call).length && typeCallSignatures.length) || - (getSignaturesOfType(target, SignatureKind.Construct).length && typeConstructSignatures.length)) { + if ( + (getSignaturesOfType(target, SignatureKind.Call).length && typeCallSignatures.length) + || (getSignaturesOfType(target, SignatureKind.Construct).length && typeConstructSignatures.length) + ) { return true; // target has similar signature kinds to source, still focus on the unmatched property } return false; @@ -22568,29 +29657,72 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function reportIncompatibleCallSignatureReturn(siga: Signature, sigb: Signature) { if (siga.parameters.length === 0 && sigb.parameters.length === 0) { - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Call_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, + typeToString(source), + typeToString(target), + ); } - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Call_signature_return_types_0_and_1_are_incompatible, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Call_signature_return_types_0_and_1_are_incompatible, + typeToString(source), + typeToString(target), + ); } function reportIncompatibleConstructSignatureReturn(siga: Signature, sigb: Signature) { if (siga.parameters.length === 0 && sigb.parameters.length === 0) { - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Construct_signatures_with_no_arguments_have_incompatible_return_types_0_and_1, + typeToString(source), + typeToString(target), + ); } - return (source: Type, target: Type) => reportIncompatibleError(Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible, typeToString(source), typeToString(target)); + return (source: Type, target: Type) => + reportIncompatibleError( + Diagnostics.Construct_signature_return_types_0_and_1_are_incompatible, + typeToString(source), + typeToString(target), + ); } /** * See signatureAssignableTo, compareSignaturesIdentical */ - function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, intersectionState: IntersectionState, incompatibleReporter: (source: Type, target: Type) => void): Ternary { - const checkMode = relation === subtypeRelation ? SignatureCheckMode.StrictTopSignature : - relation === strictSubtypeRelation ? SignatureCheckMode.StrictTopSignature | SignatureCheckMode.StrictArity : - SignatureCheckMode.None; - return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target, - checkMode, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper); + function signatureRelatedTo( + source: Signature, + target: Signature, + erase: boolean, + reportErrors: boolean, + intersectionState: IntersectionState, + incompatibleReporter: (source: Type, target: Type) => void, + ): Ternary { + const checkMode = relation === subtypeRelation ? SignatureCheckMode.StrictTopSignature + : relation === strictSubtypeRelation + ? SignatureCheckMode.StrictTopSignature | SignatureCheckMode.StrictArity + : SignatureCheckMode.None; + return compareSignaturesRelated( + erase ? getErasedSignature(source) : source, + erase ? getErasedSignature(target) : target, + checkMode, + reportErrors, + reportError, + incompatibleReporter, + isRelatedToWorker, + reportUnreliableMapper, + ); function isRelatedToWorker(source: Type, target: Type, reportErrors?: boolean) { - return isRelatedTo(source, target, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + return isRelatedTo( + source, + target, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); } } @@ -22602,7 +29734,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let result = Ternary.True; for (let i = 0; i < sourceSignatures.length; i++) { - const related = compareSignaturesIdentical(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, isRelatedTo); + const related = compareSignaturesIdentical( + sourceSignatures[i], + targetSignatures[i], + /*partialMatch*/ false, + /*ignoreThisTypes*/ false, + /*ignoreReturnTypes*/ false, + isRelatedTo, + ); if (!related) { return Ternary.False; } @@ -22611,24 +29750,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function membersRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function membersRelatedToIndexInfo( + source: Type, + targetInfo: IndexInfo, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { let result = Ternary.True; const keyType = targetInfo.keyType; - const props = source.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(source as IntersectionType) : getPropertiesOfObjectType(source); + const props = source.flags & TypeFlags.Intersection + ? getPropertiesOfUnionOrIntersectionType(source as IntersectionType) + : getPropertiesOfObjectType(source); for (const prop of props) { // Skip over ignored JSX and symbol-named members if (isIgnoredJsxProperty(source, prop)) { continue; } - if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), keyType)) { + if ( + isApplicableIndexType( + getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), + keyType, + ) + ) { const propType = getNonMissingTypeOfSymbol(prop); - const type = exactOptionalPropertyTypes || propType.flags & TypeFlags.Undefined || keyType === numberType || !(prop.flags & SymbolFlags.Optional) - ? propType - : getTypeWithFacts(propType, TypeFacts.NEUndefined); - const related = isRelatedTo(type, targetInfo.type, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + const type = + exactOptionalPropertyTypes || propType.flags & TypeFlags.Undefined || keyType === numberType + || !(prop.flags & SymbolFlags.Optional) + ? propType + : getTypeWithFacts(propType, TypeFacts.NEUndefined); + const related = isRelatedTo( + type, + targetInfo.type, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (!related) { if (reportErrors) { - reportError(Diagnostics.Property_0_is_incompatible_with_index_signature, symbolToString(prop)); + reportError( + Diagnostics.Property_0_is_incompatible_with_index_signature, + symbolToString(prop), + ); } return Ternary.False; } @@ -22647,20 +29810,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function indexInfoRelatedTo(sourceInfo: IndexInfo, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState) { - const related = isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState); + function indexInfoRelatedTo( + sourceInfo: IndexInfo, + targetInfo: IndexInfo, + reportErrors: boolean, + intersectionState: IntersectionState, + ) { + const related = isRelatedTo( + sourceInfo.type, + targetInfo.type, + RecursionFlags.Both, + reportErrors, + /*headMessage*/ undefined, + intersectionState, + ); if (!related && reportErrors) { if (sourceInfo.keyType === targetInfo.keyType) { reportError(Diagnostics._0_index_signatures_are_incompatible, typeToString(sourceInfo.keyType)); } else { - reportError(Diagnostics._0_and_1_index_signatures_are_incompatible, typeToString(sourceInfo.keyType), typeToString(targetInfo.keyType)); + reportError( + Diagnostics._0_and_1_index_signatures_are_incompatible, + typeToString(sourceInfo.keyType), + typeToString(targetInfo.keyType), + ); } } return related; } - function indexSignaturesRelatedTo(source: Type, target: Type, sourceIsPrimitive: boolean, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function indexSignaturesRelatedTo( + source: Type, + target: Type, + sourceIsPrimitive: boolean, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { if (relation === identityRelation) { return indexSignaturesIdenticalTo(source, target); } @@ -22668,9 +29853,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetHasStringIndex = some(indexInfos, info => info.keyType === stringType); let result = Ternary.True; for (const targetInfo of indexInfos) { - const related = relation !== strictSubtypeRelation && !sourceIsPrimitive && targetHasStringIndex && targetInfo.type.flags & TypeFlags.Any ? Ternary.True : - isGenericMappedType(source) && targetHasStringIndex ? isRelatedTo(getTemplateTypeFromMappedType(source), targetInfo.type, RecursionFlags.Both, reportErrors) : - typeRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); + const related = relation !== strictSubtypeRelation && !sourceIsPrimitive && targetHasStringIndex + && targetInfo.type.flags & TypeFlags.Any ? Ternary.True + : isGenericMappedType(source) && targetHasStringIndex + ? isRelatedTo( + getTemplateTypeFromMappedType(source), + targetInfo.type, + RecursionFlags.Both, + reportErrors, + ) + : typeRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); if (!related) { return Ternary.False; } @@ -22679,7 +29871,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result; } - function typeRelatedToIndexInfo(source: Type, targetInfo: IndexInfo, reportErrors: boolean, intersectionState: IntersectionState): Ternary { + function typeRelatedToIndexInfo( + source: Type, + targetInfo: IndexInfo, + reportErrors: boolean, + intersectionState: IntersectionState, + ): Ternary { const sourceInfo = getApplicableIndexInfo(source, targetInfo.keyType); if (sourceInfo) { return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors, intersectionState); @@ -22687,11 +29884,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Intersection constituents are never considered to have an inferred index signature. Also, in the strict subtype relation, // only fresh object literals are considered to have inferred index signatures. This ensures { [x: string]: xxx } <: {} but // not vice-versa. Without this rule, those types would be mutual strict subtypes. - if (!(intersectionState & IntersectionState.Source) && (relation !== strictSubtypeRelation || getObjectFlags(source) & ObjectFlags.FreshLiteral) && isObjectTypeWithInferableIndex(source)) { + if ( + !(intersectionState & IntersectionState.Source) + && (relation !== strictSubtypeRelation || getObjectFlags(source) & ObjectFlags.FreshLiteral) + && isObjectTypeWithInferableIndex(source) + ) { return membersRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState); } if (reportErrors) { - reportError(Diagnostics.Index_signature_for_type_0_is_missing_in_type_1, typeToString(targetInfo.keyType), typeToString(source)); + reportError( + Diagnostics.Index_signature_for_type_0_is_missing_in_type_1, + typeToString(targetInfo.keyType), + typeToString(source), + ); } return Ternary.False; } @@ -22704,20 +29909,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } for (const targetInfo of targetInfos) { const sourceInfo = getIndexInfoOfType(source, targetInfo.keyType); - if (!(sourceInfo && isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both) && sourceInfo.isReadonly === targetInfo.isReadonly)) { + if ( + !(sourceInfo && isRelatedTo(sourceInfo.type, targetInfo.type, RecursionFlags.Both) + && sourceInfo.isReadonly === targetInfo.isReadonly) + ) { return Ternary.False; } } return Ternary.True; } - function constructorVisibilitiesAreCompatible(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) { + function constructorVisibilitiesAreCompatible( + sourceSignature: Signature, + targetSignature: Signature, + reportErrors: boolean, + ) { if (!sourceSignature.declaration || !targetSignature.declaration) { return true; } - const sourceAccessibility = getSelectedEffectiveModifierFlags(sourceSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier); - const targetAccessibility = getSelectedEffectiveModifierFlags(targetSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier); + const sourceAccessibility = getSelectedEffectiveModifierFlags( + sourceSignature.declaration, + ModifierFlags.NonPublicAccessibilityModifier, + ); + const targetAccessibility = getSelectedEffectiveModifierFlags( + targetSignature.declaration, + ModifierFlags.NonPublicAccessibilityModifier, + ); // A public, protected and private signature is assignable to a private signature. if (targetAccessibility === ModifierFlags.Private) { @@ -22735,7 +29953,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (reportErrors) { - reportError(Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, visibilityToString(sourceAccessibility), visibilityToString(targetAccessibility)); + reportError( + Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, + visibilityToString(sourceAccessibility), + visibilityToString(targetAccessibility), + ); } return false; @@ -22761,13 +29983,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) || !!(type.flags & TypeFlags.StringMapping); + return isUnitType(type) || !!(type.flags & TypeFlags.TemplateLiteral) + || !!(type.flags & TypeFlags.StringMapping); } function getExactOptionalUnassignableProperties(source: Type, target: Type) { if (isTupleType(source) && isTupleType(target)) return emptyArray; return getPropertiesOfType(target) - .filter(targetProp => isExactOptionalPropertyMismatch(getTypeOfPropertyOfType(source, targetProp.escapedName), getTypeOfSymbol(targetProp))); + .filter(targetProp => + isExactOptionalPropertyMismatch( + getTypeOfPropertyOfType(source, targetProp.escapedName), + getTypeOfSymbol(targetProp), + ) + ); } function isExactOptionalPropertyMismatch(source: Type | undefined, target: Type | undefined) { @@ -22779,14 +30007,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getBestMatchingType(source: Type, target: UnionOrIntersectionType, isRelatedTo = compareTypesAssignable) { - return findMatchingDiscriminantType(source, target, isRelatedTo) || - findMatchingTypeReferenceOrTypeAliasReference(source, target) || - findBestTypeForObjectLiteral(source, target) || - findBestTypeForInvokable(source, target) || - findMostOverlappyType(source, target); + return findMatchingDiscriminantType(source, target, isRelatedTo) + || findMatchingTypeReferenceOrTypeAliasReference(source, target) + || findBestTypeForObjectLiteral(source, target) + || findBestTypeForInvokable(source, target) + || findMostOverlappyType(source, target); } - function discriminateTypeByDiscriminableItems(target: UnionType, discriminators: (readonly [() => Type, __String])[], related: (source: Type, target: Type) => boolean | Ternary) { + function discriminateTypeByDiscriminableItems( + target: UnionType, + discriminators: (readonly [() => Type, __String])[], + related: (source: Type, target: Type) => boolean | Ternary, + ) { const types = target.types; const include: Ternary[] = types.map(t => t.flags & TypeFlags.Primitive ? Ternary.False : Ternary.True); for (const [getDiscriminatingType, propertyName] of discriminators) { @@ -22812,7 +30044,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const filtered = contains(include, Ternary.False) ? getUnionType(types.filter((_, i) => include[i]), UnionReduction.None) : target; + const filtered = contains(include, Ternary.False) + ? getUnionType(types.filter((_, i) => include[i]), UnionReduction.None) : target; return filtered.flags & TypeFlags.Never ? target : filtered; } @@ -22823,8 +30056,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isWeakType(type: Type): boolean { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); - return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 && resolved.indexInfos.length === 0 && - resolved.properties.length > 0 && every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional)); + return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 + && resolved.indexInfos.length === 0 + && resolved.properties.length > 0 && every(resolved.properties, p => + !!(p.flags & SymbolFlags.Optional)); } if (type.flags & TypeFlags.Intersection) { return every((type as IntersectionType).types, isWeakType); @@ -22843,9 +30078,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getVariances(type: GenericType): VarianceFlags[] { // Arrays and tuples are known to be covariant, no need to spend time computing this. - return type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple ? - arrayVariances : - getVariancesWorker(type.symbol, type.typeParameters); + return type === globalArrayType || type === globalReadonlyArrayType || type.objectFlags & ObjectFlags.Tuple + ? arrayVariances + : getVariancesWorker(type.symbol, type.typeParameters); } function getAliasVariances(symbol: Symbol) { @@ -22857,10 +30092,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // generic type are structurally compared. We infer the variance information by comparing // instantiations of the generic type for type arguments with known relations. The function // returns the emptyArray singleton when invoked recursively for the given generic type. - function getVariancesWorker(symbol: Symbol, typeParameters: readonly TypeParameter[] = emptyArray): VarianceFlags[] { + function getVariancesWorker( + symbol: Symbol, + typeParameters: readonly TypeParameter[] = emptyArray, + ): VarianceFlags[] { const links = getSymbolLinks(symbol); if (!links.variances) { - tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { arity: typeParameters.length, id: getTypeId(getDeclaredTypeOfSymbol(symbol)) }); + tracing?.push(tracing.Phase.CheckTypes, "getVariancesWorker", { + arity: typeParameters.length, + id: getTypeId(getDeclaredTypeOfSymbol(symbol)), + }); const oldVarianceComputation = inVarianceComputation; if (!inVarianceComputation) { inVarianceComputation = true; @@ -22870,26 +30111,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const variances = []; for (const tp of typeParameters) { const modifiers = getTypeParameterModifiers(tp); - let variance = modifiers & ModifierFlags.Out ? - modifiers & ModifierFlags.In ? VarianceFlags.Invariant : VarianceFlags.Covariant : - modifiers & ModifierFlags.In ? VarianceFlags.Contravariant : undefined; + let variance = modifiers & ModifierFlags.Out + ? modifiers & ModifierFlags.In ? VarianceFlags.Invariant : VarianceFlags.Covariant + : modifiers & ModifierFlags.In ? VarianceFlags.Contravariant : undefined; if (variance === undefined) { let unmeasurable = false; let unreliable = false; const oldHandler = outofbandVarianceMarkerHandler; - outofbandVarianceMarkerHandler = (onlyUnreliable) => onlyUnreliable ? unreliable = true : unmeasurable = true; + outofbandVarianceMarkerHandler = onlyUnreliable => + onlyUnreliable ? unreliable = true : unmeasurable = true; // We first compare instantiations where the type parameter is replaced with // marker types that have a known subtype relationship. From this we can infer // invariance, covariance, contravariance or bivariance. const typeWithSuper = createMarkerType(symbol, tp, markerSuperType); const typeWithSub = createMarkerType(symbol, tp, markerSubType); - variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) | - (isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0); + variance = (isTypeAssignableTo(typeWithSub, typeWithSuper) ? VarianceFlags.Covariant : 0) + | (isTypeAssignableTo(typeWithSuper, typeWithSub) ? VarianceFlags.Contravariant : 0); // If the instantiations appear to be related bivariantly it may be because the // type parameter is independent (i.e. it isn't witnessed anywhere in the generic // type). To determine this we compare instantiations where the type parameter is // replaced with marker types that are known to be unrelated. - if (variance === VarianceFlags.Bivariant && isTypeAssignableTo(createMarkerType(symbol, tp, markerOtherType), typeWithSuper)) { + if ( + variance === VarianceFlags.Bivariant + && isTypeAssignableTo(createMarkerType(symbol, tp, markerOtherType), typeWithSuper) + ) { variance = VarianceFlags.Independent; } outofbandVarianceMarkerHandler = oldHandler; @@ -22920,9 +30165,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isErrorType(type)) { return type; } - const result = symbol.flags & SymbolFlags.TypeAlias ? - getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, mapper)) : - createTypeReference(type as GenericType, instantiateTypes((type as GenericType).typeParameters, mapper)); + const result = symbol.flags & SymbolFlags.TypeAlias + ? getTypeAliasInstantiation(symbol, instantiateTypes(getSymbolLinks(symbol).typeParameters!, mapper)) + : createTypeReference(type as GenericType, instantiateTypes((type as GenericType).typeParameters, mapper)); markerTypes.add(getTypeId(result)); return result; } @@ -22932,14 +30177,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeParameterModifiers(tp: TypeParameter): ModifierFlags { - return reduceLeft(tp.symbol?.declarations, (modifiers, d) => modifiers | getEffectiveModifierFlags(d), ModifierFlags.None) & (ModifierFlags.In | ModifierFlags.Out | ModifierFlags.Const); + return reduceLeft( + tp.symbol?.declarations, + (modifiers, d) => modifiers | getEffectiveModifierFlags(d), + ModifierFlags.None, + ) & (ModifierFlags.In | ModifierFlags.Out | ModifierFlags.Const); } // Return true if the given type reference has a 'void' type argument for a covariant type parameter. // See comment at call in recursiveTypeRelatedTo for when this case matters. function hasCovariantVoidArgument(typeArguments: readonly Type[], variances: VarianceFlags[]): boolean { for (let i = 0; i < variances.length; i++) { - if ((variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Covariant && typeArguments[i].flags & TypeFlags.Void) { + if ( + (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Covariant + && typeArguments[i].flags & TypeFlags.Void + ) { return true; } } @@ -22955,10 +30207,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTypeReferenceWithGenericArguments(type: Type): boolean { - return isNonDeferredTypeReference(type) && some(getTypeArguments(type), t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t)); + return isNonDeferredTypeReference(type) + && some( + getTypeArguments(type), + t => !!(t.flags & TypeFlags.TypeParameter) || isTypeReferenceWithGenericArguments(t), + ); } - function getGenericTypeReferenceRelationKey(source: TypeReference, target: TypeReference, postFix: string, ignoreConstraints: boolean) { + function getGenericTypeReferenceRelationKey( + source: TypeReference, + target: TypeReference, + postFix: string, + ignoreConstraints: boolean, + ) { const typeParameters: Type[] = []; let constraintMarker = ""; const sourceId = getTypeReferenceId(source, 0); @@ -22997,16 +30258,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters. * For other cases, the types ids are used. */ - function getRelationKey(source: Type, target: Type, intersectionState: IntersectionState, relation: Map, ignoreConstraints: boolean) { + function getRelationKey( + source: Type, + target: Type, + intersectionState: IntersectionState, + relation: Map, + ignoreConstraints: boolean, + ) { if (relation === identityRelation && source.id > target.id) { const temp = source; source = target; target = temp; } const postFix = intersectionState ? ":" + intersectionState : ""; - return isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target) ? - getGenericTypeReferenceRelationKey(source as TypeReference, target as TypeReference, postFix, ignoreConstraints) : - `${source.id},${target.id}${postFix}`; + return isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target) + ? getGenericTypeReferenceRelationKey( + source as TypeReference, + target as TypeReference, + postFix, + ignoreConstraints, + ) + : `${source.id},${target.id}${postFix}`; } // Invoke the callback for each underlying property symbol of the given symbol and return the first @@ -23028,7 +30300,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return the declaring class type of a property or undefined if property not declared in class function getDeclaringClass(prop: Symbol) { - return prop.parent && prop.parent.flags & SymbolFlags.Class ? getDeclaredTypeOfSymbol(getParentOfSymbol(prop)!) as InterfaceType : undefined; + return prop.parent && prop.parent.flags & SymbolFlags.Class + ? getDeclaredTypeOfSymbol(getParentOfSymbol(prop)!) as InterfaceType : undefined; } // Return the inherited type of the given property or undefined if property doesn't exist in a base class. @@ -23049,15 +30322,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return true if source property is a valid override of protected parts of target property. function isValidOverrideOf(sourceProp: Symbol, targetProp: Symbol) { - return !forEachProperty(targetProp, tp => getDeclarationModifierFlagsFromSymbol(tp) & ModifierFlags.Protected ? - !isPropertyInClassDerivedFrom(sourceProp, getDeclaringClass(tp)) : false); + return !forEachProperty(targetProp, tp => + getDeclarationModifierFlagsFromSymbol(tp) & ModifierFlags.Protected + ? !isPropertyInClassDerivedFrom(sourceProp, getDeclaringClass(tp)) : false); } // Return true if the given class derives from each of the declaring classes of the protected // constituents of the given property. function isClassDerivedFromDeclaringClasses(checkClass: T, prop: Symbol, writing: boolean) { - return forEachProperty(prop, p => getDeclarationModifierFlagsFromSymbol(p, writing) & ModifierFlags.Protected ? - !hasBaseType(checkClass, getDeclaringClass(p)) : false) ? undefined : checkClass; + return forEachProperty(prop, p => + getDeclarationModifierFlagsFromSymbol(p, writing) & ModifierFlags.Protected + ? !hasBaseType(checkClass, getDeclaringClass(p)) : false) ? undefined : checkClass; } // Return true if the given type is deeply nested. We consider this to be the case when structural type comparisons @@ -23084,7 +30359,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let lastTypeId = 0; for (let i = 0; i < depth; i++) { const t = stack[i]; - if (t.flags & TypeFlags.Intersection ? some((t as IntersectionType).types, u => getRecursionIdentity(u) === identity) : getRecursionIdentity(t) === identity) { + if ( + t.flags & TypeFlags.Intersection ? some((t as IntersectionType).types, u => + getRecursionIdentity(u) === identity) : getRecursionIdentity(t) === identity + ) { // We only count occurrences with a higher type id than the previous occurrence, since higher // type ids are an indicator of newer instantiations caused by recursion. if (t.id >= lastTypeId) { @@ -23115,7 +30393,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // unique AST node. return (type as TypeReference).node!; } - if (type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) { + if ( + type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class) + ) { // We track all object types that have an associated symbol (representing the origin of the type), but // exclude the static side of classes from this check since it shares its symbol with the instance side. return type.symbol; @@ -23131,7 +30411,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P][Q] it is A do { type = (type as IndexedAccessType).objectType; - } while (type.flags & TypeFlags.IndexedAccess); + } + while (type.flags & TypeFlags.IndexedAccess); return type; } if (type.flags & TypeFlags.Conditional) { @@ -23145,15 +30426,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False; } - function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary { + function compareProperties( + sourceProp: Symbol, + targetProp: Symbol, + compareTypes: (source: Type, target: Type) => Ternary, + ): Ternary { // Two members are considered identical when // - they are public properties with identical names, optionality, and types, // - they are private or protected properties originating in the same declaration and having identical types if (sourceProp === targetProp) { return Ternary.True; } - const sourcePropAccessibility = getDeclarationModifierFlagsFromSymbol(sourceProp) & ModifierFlags.NonPublicAccessibilityModifier; - const targetPropAccessibility = getDeclarationModifierFlagsFromSymbol(targetProp) & ModifierFlags.NonPublicAccessibilityModifier; + const sourcePropAccessibility = getDeclarationModifierFlagsFromSymbol(sourceProp) + & ModifierFlags.NonPublicAccessibilityModifier; + const targetPropAccessibility = getDeclarationModifierFlagsFromSymbol(targetProp) + & ModifierFlags.NonPublicAccessibilityModifier; if (sourcePropAccessibility !== targetPropAccessibility) { return Ternary.False; } @@ -23182,9 +30469,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetHasRestParameter = hasEffectiveRestParameter(target); // A source signature matches a target signature if the two signatures have the same number of required, // optional, and rest parameters. - if (sourceParameterCount === targetParameterCount && - sourceMinArgumentCount === targetMinArgumentCount && - sourceHasRestParameter === targetHasRestParameter) { + if ( + sourceParameterCount === targetParameterCount + && sourceMinArgumentCount === targetMinArgumentCount + && sourceHasRestParameter === targetHasRestParameter + ) { return true; } // A source signature partially matches a target signature if the target signature has no fewer required @@ -23198,7 +30487,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * See signatureRelatedTo, compareSignaturesIdentical */ - function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary { + function compareSignaturesIdentical( + source: Signature, + target: Signature, + partialMatch: boolean, + ignoreThisTypes: boolean, + ignoreReturnTypes: boolean, + compareTypes: (s: Type, t: Type) => Ternary, + ): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -23217,8 +30513,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < target.typeParameters.length; i++) { const s = source.typeParameters![i]; const t = target.typeParameters[i]; - if (!(s === t || compareTypes(instantiateType(getConstraintFromTypeParameter(s), mapper) || unknownType, getConstraintFromTypeParameter(t) || unknownType) && - compareTypes(instantiateType(getDefaultFromTypeParameter(s), mapper) || unknownType, getDefaultFromTypeParameter(t) || unknownType))) { + if ( + !(s === t + || compareTypes( + instantiateType(getConstraintFromTypeParameter(s), mapper) || unknownType, + getConstraintFromTypeParameter(t) || unknownType, + ) + && compareTypes( + instantiateType(getDefaultFromTypeParameter(s), mapper) || unknownType, + getDefaultFromTypeParameter(t) || unknownType, + )) + ) { return Ternary.False; } } @@ -23251,18 +30556,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!ignoreReturnTypes) { const sourceTypePredicate = getTypePredicateOfSignature(source); const targetTypePredicate = getTypePredicateOfSignature(target); - result &= sourceTypePredicate || targetTypePredicate ? - compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) : - compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); + result &= sourceTypePredicate || targetTypePredicate + ? compareTypePredicatesIdentical(sourceTypePredicate, targetTypePredicate, compareTypes) + : compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target)); } return result; } - function compareTypePredicatesIdentical(source: TypePredicate | undefined, target: TypePredicate | undefined, compareTypes: (s: Type, t: Type) => Ternary): Ternary { - return !(source && target && typePredicateKindsMatch(source, target)) ? Ternary.False : - source.type === target.type ? Ternary.True : - source.type && target.type ? compareTypes(source.type, target.type) : - Ternary.False; + function compareTypePredicatesIdentical( + source: TypePredicate | undefined, + target: TypePredicate | undefined, + compareTypes: (s: Type, t: Type) => Ternary, + ): Ternary { + return !(source && target && typePredicateKindsMatch(source, target)) ? Ternary.False + : source.type === target.type ? Ternary.True + : source.type && target.type ? compareTypes(source.type, target.type) + : Ternary.False; } function literalTypesWithSameBaseType(types: Type[]): boolean { @@ -23280,7 +30589,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getCombinedTypeFlags(types: Type[]): TypeFlags { - return reduceLeft(types, (flags, t) => flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), 0 as TypeFlags); + return reduceLeft( + types, + (flags, t) => flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), + 0 as TypeFlags, + ); } function getCommonSupertype(types: Type[]): Type { @@ -23288,15 +30601,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return types[0]; } // Remove nullable types from each of the candidates. - const primaryTypes = strictNullChecks ? sameMap(types, t => filterType(t, u => !(u.flags & TypeFlags.Nullable))) : types; + const primaryTypes = strictNullChecks ? sameMap(types, t => filterType(t, u => !(u.flags & TypeFlags.Nullable))) + : types; // When the candidate types are all literal types with the same base type, return a union // of those literal types. Otherwise, return the leftmost type for which no type to the // right is a supertype. - const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) ? - getUnionType(primaryTypes) : - reduceLeft(primaryTypes, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!; + const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) + ? getUnionType(primaryTypes) + : reduceLeft(primaryTypes, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!; // Add any nullable types that occurred in the candidates back to the result. - return primaryTypes === types ? superTypeOrUnion : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); + return primaryTypes === types ? superTypeOrUnion + : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable); } // Return the leftmost type for which no type to the right is a subtype. @@ -23305,11 +30620,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isArrayType(type: Type): type is TypeReference { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && ((type as TypeReference).target === globalArrayType || (type as TypeReference).target === globalReadonlyArrayType); + return !!(getObjectFlags(type) & ObjectFlags.Reference) + && ((type as TypeReference).target === globalArrayType + || (type as TypeReference).target === globalReadonlyArrayType); } function isReadonlyArrayType(type: Type): boolean { - return !!(getObjectFlags(type) & ObjectFlags.Reference) && (type as TypeReference).target === globalReadonlyArrayType; + return !!(getObjectFlags(type) & ObjectFlags.Reference) + && (type as TypeReference).target === globalReadonlyArrayType; } function isArrayOrTupleType(type: Type): type is TypeReference { @@ -23327,15 +30645,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isArrayLikeType(type: Type): boolean { // A type is array-like if it is a reference to the global Array or global ReadonlyArray type, // or if it is not the undefined or null type and if it is assignable to ReadonlyArray - return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); + return isArrayType(type) + || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); } function getSingleBaseForNonAugmentingSubtype(type: Type) { - if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) { + if ( + !(getObjectFlags(type) & ObjectFlags.Reference) + || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface) + ) { return undefined; } if (getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeCalculated) { - return getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeExists ? (type as TypeReference).cachedEquivalentBaseType : undefined; + return getObjectFlags(type) & ObjectFlags.IdenticalBaseTypeExists + ? (type as TypeReference).cachedEquivalentBaseType : undefined; } (type as TypeReference).objectFlags |= ObjectFlags.IdenticalBaseTypeCalculated; const target = (type as TypeReference).target as InterfaceType; @@ -23343,7 +30666,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseTypeNode = getBaseTypeNodeOfClass(target); // A base type expression may circularly reference the class itself (e.g. as an argument to function call), so we only // check for base types specified as simple qualified names. - if (baseTypeNode && baseTypeNode.expression.kind !== SyntaxKind.Identifier && baseTypeNode.expression.kind !== SyntaxKind.PropertyAccessExpression) { + if ( + baseTypeNode && baseTypeNode.expression.kind !== SyntaxKind.Identifier + && baseTypeNode.expression.kind !== SyntaxKind.PropertyAccessExpression + ) { return undefined; } } @@ -23354,7 +30680,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getMembersOfSymbol(type.symbol).size) { return undefined; // If the interface has any members, they may subtype members in the base, so we should do a full structural comparison } - let instantiatedBase = !length(target.typeParameters) ? bases[0] : instantiateType(bases[0], createTypeMapper(target.typeParameters!, getTypeArguments(type as TypeReference).slice(0, target.typeParameters!.length))); + let instantiatedBase = !length(target.typeParameters) ? bases[0] + : instantiateType( + bases[0], + createTypeMapper( + target.typeParameters!, + getTypeArguments(type as TypeReference).slice(0, target.typeParameters!.length), + ), + ); if (length(getTypeArguments(type as TypeReference)) > length(target.typeParameters)) { instantiatedBase = getTypeWithThisArgument(instantiatedBase, last(getTypeArguments(type as TypeReference))); } @@ -23373,9 +30706,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isTupleLikeType(type: Type): boolean { let lengthType; - return isTupleType(type) || - !!getPropertyOfType(type, "0" as __String) || - isArrayLikeType(type) && !!(lengthType = getTypeOfPropertyOfType(type, "length" as __String)) && everyType(lengthType, t => !!(t.flags & TypeFlags.NumberLiteral)); + return isTupleType(type) + || !!getPropertyOfType(type, "0" as __String) + || isArrayLikeType(type) && !!(lengthType = getTypeOfPropertyOfType(type, "length" as __String)) + && everyType(lengthType, t => !!(t.flags & TypeFlags.NumberLiteral)); } function isArrayOrTupleLikeType(type: Type): boolean { @@ -23388,7 +30722,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return propType; } if (everyType(type, isTupleType)) { - return getTupleElementTypeOutOfStartCount(type, index, compilerOptions.noUncheckedIndexedAccess ? undefinedType : undefined); + return getTupleElementTypeOutOfStartCount( + type, + index, + compilerOptions.noUncheckedIndexedAccess ? undefinedType : undefined, + ); } return undefined; } @@ -23413,19 +30751,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isLiteralType(type: Type): boolean { - return type.flags & TypeFlags.Boolean ? true : - type.flags & TypeFlags.Union ? type.flags & TypeFlags.EnumLiteral ? true : every((type as UnionType).types, isUnitType) : - isUnitType(type); + return type.flags & TypeFlags.Boolean ? true + : type.flags & TypeFlags.Union + ? type.flags & TypeFlags.EnumLiteral ? true : every((type as UnionType).types, isUnitType) + : isUnitType(type); } function getBaseTypeOfLiteralType(type: Type): Type { - return type.flags & TypeFlags.EnumLike ? getBaseTypeOfEnumLikeType(type as LiteralType) : - type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType : - type.flags & TypeFlags.NumberLiteral ? numberType : - type.flags & TypeFlags.BigIntLiteral ? bigintType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.Union ? getBaseTypeOfLiteralTypeUnion(type as UnionType) : - type; + return type.flags & TypeFlags.EnumLike ? getBaseTypeOfEnumLikeType(type as LiteralType) + : type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType + : type.flags & TypeFlags.NumberLiteral ? numberType + : type.flags & TypeFlags.BigIntLiteral ? bigintType + : type.flags & TypeFlags.BooleanLiteral ? booleanType + : type.flags & TypeFlags.Union ? getBaseTypeOfLiteralTypeUnion(type as UnionType) + : type; } function getBaseTypeOfLiteralTypeUnion(type: UnionType) { @@ -23436,28 +30775,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This like getBaseTypeOfLiteralType, but instead treats enum literals as strings/numbers instead // of returning their enum base type (which depends on the types of other literals in the enum). function getBaseTypeOfLiteralTypeForComparison(type: Type): Type { - return type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType : - type.flags & (TypeFlags.NumberLiteral | TypeFlags.Enum) ? numberType : - type.flags & TypeFlags.BigIntLiteral ? bigintType : - type.flags & TypeFlags.BooleanLiteral ? booleanType : - type.flags & TypeFlags.Union ? mapType(type, getBaseTypeOfLiteralTypeForComparison) : - type; + return type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? stringType + : type.flags & (TypeFlags.NumberLiteral | TypeFlags.Enum) ? numberType + : type.flags & TypeFlags.BigIntLiteral ? bigintType + : type.flags & TypeFlags.BooleanLiteral ? booleanType + : type.flags & TypeFlags.Union ? mapType(type, getBaseTypeOfLiteralTypeForComparison) + : type; } function getWidenedLiteralType(type: Type): Type { - return type.flags & TypeFlags.EnumLike && isFreshLiteralType(type) ? getBaseTypeOfEnumLikeType(type as LiteralType) : - type.flags & TypeFlags.StringLiteral && isFreshLiteralType(type) ? stringType : - type.flags & TypeFlags.NumberLiteral && isFreshLiteralType(type) ? numberType : - type.flags & TypeFlags.BigIntLiteral && isFreshLiteralType(type) ? bigintType : - type.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(type) ? booleanType : - type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedLiteralType) : - type; + return type.flags & TypeFlags.EnumLike && isFreshLiteralType(type) + ? getBaseTypeOfEnumLikeType(type as LiteralType) + : type.flags & TypeFlags.StringLiteral && isFreshLiteralType(type) ? stringType + : type.flags & TypeFlags.NumberLiteral && isFreshLiteralType(type) ? numberType + : type.flags & TypeFlags.BigIntLiteral && isFreshLiteralType(type) ? bigintType + : type.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(type) ? booleanType + : type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedLiteralType) + : type; } function getWidenedUniqueESSymbolType(type: Type): Type { - return type.flags & TypeFlags.UniqueESSymbol ? esSymbolType : - type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedUniqueESSymbolType) : - type; + return type.flags & TypeFlags.UniqueESSymbol ? esSymbolType + : type.flags & TypeFlags.Union ? mapType(type as UnionType, getWidenedUniqueESSymbolType) + : type; } function getWidenedLiteralLikeTypeForContextualType(type: Type, contextualType: Type | undefined) { @@ -23467,20 +30807,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getRegularTypeOfLiteralType(type); } - function getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(type: Type | undefined, contextualSignatureReturnType: Type | undefined, isAsync: boolean) { + function getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded( + type: Type | undefined, + contextualSignatureReturnType: Type | undefined, + isAsync: boolean, + ) { if (type && isUnitType(type)) { - const contextualType = !contextualSignatureReturnType ? undefined : - isAsync ? getPromisedTypeOfPromise(contextualSignatureReturnType) : - contextualSignatureReturnType; + const contextualType = !contextualSignatureReturnType ? undefined + : isAsync ? getPromisedTypeOfPromise(contextualSignatureReturnType) + : contextualSignatureReturnType; type = getWidenedLiteralLikeTypeForContextualType(type, contextualType); } return type; } - function getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(type: Type | undefined, contextualSignatureReturnType: Type | undefined, kind: IterationTypeKind, isAsyncGenerator: boolean) { + function getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + type: Type | undefined, + contextualSignatureReturnType: Type | undefined, + kind: IterationTypeKind, + isAsyncGenerator: boolean, + ) { if (type && isUnitType(type)) { - const contextualType = !contextualSignatureReturnType ? undefined : - getIterationTypeOfGeneratorFunctionReturnType(kind, contextualSignatureReturnType, isAsyncGenerator); + const contextualType = !contextualSignatureReturnType ? undefined + : getIterationTypeOfGeneratorFunctionReturnType(kind, contextualSignatureReturnType, isAsyncGenerator); type = getWidenedLiteralLikeTypeForContextualType(type, contextualType); } return type; @@ -23491,7 +30840,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Prefer using isTupleLikeType() unless the use of `elementTypes`/`getTypeArguments` is required. */ function isTupleType(type: Type): type is TupleTypeReference { - return !!(getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target.objectFlags & ObjectFlags.Tuple); + return !!(getObjectFlags(type) & ObjectFlags.Reference + && (type as TypeReference).target.objectFlags & ObjectFlags.Tuple); } function isGenericTupleType(type: Type): type is TupleTypeReference { @@ -23525,26 +30875,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return restType && createArrayType(restType); } - function getElementTypeOfSliceOfTupleType(type: TupleTypeReference, index: number, endSkipCount = 0, writing = false, noReductions = false) { + function getElementTypeOfSliceOfTupleType( + type: TupleTypeReference, + index: number, + endSkipCount = 0, + writing = false, + noReductions = false, + ) { const length = getTypeReferenceArity(type) - endSkipCount; if (index < length) { const typeArguments = getTypeArguments(type); const elementTypes: Type[] = []; for (let i = index; i < length; i++) { const t = typeArguments[i]; - elementTypes.push(type.target.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t); + elementTypes.push( + type.target.elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t, + ); } - return writing ? getIntersectionType(elementTypes) : getUnionType(elementTypes, noReductions ? UnionReduction.None : UnionReduction.Literal); + return writing ? getIntersectionType(elementTypes) + : getUnionType(elementTypes, noReductions ? UnionReduction.None : UnionReduction.Literal); } return undefined; } function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference) { - return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) && - every(t1.target.elementFlags, (f, i) => (f & ElementFlags.Variable) === (t2.target.elementFlags[i] & ElementFlags.Variable)); + return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) + && every( + t1.target.elementFlags, + (f, i) => (f & ElementFlags.Variable) === (t2.target.elementFlags[i] & ElementFlags.Variable), + ); } - function isZeroBigInt({value}: BigIntLiteralType) { + function isZeroBigInt({ value }: BigIntLiteralType) { return value.base10Value === "0"; } @@ -23557,16 +30919,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getDefinitelyFalsyPartOfType(type: Type): Type { - return type.flags & TypeFlags.String ? emptyStringType : - type.flags & TypeFlags.Number ? zeroType : - type.flags & TypeFlags.BigInt ? zeroBigIntType : - type === regularFalseType || - type === falseType || - type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.AnyOrUnknown) || - type.flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === "" || - type.flags & TypeFlags.NumberLiteral && (type as NumberLiteralType).value === 0 || - type.flags & TypeFlags.BigIntLiteral && isZeroBigInt(type as BigIntLiteralType) ? type : - neverType; + return type.flags & TypeFlags.String ? emptyStringType + : type.flags & TypeFlags.Number ? zeroType + : type.flags & TypeFlags.BigInt ? zeroBigIntType + : type === regularFalseType + || type === falseType + || type.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.AnyOrUnknown) + || type.flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === "" + || type.flags & TypeFlags.NumberLiteral && (type as NumberLiteralType).value === 0 + || type.flags & TypeFlags.BigIntLiteral && isZeroBigInt(type as BigIntLiteralType) ? type + : neverType; } /** @@ -23576,25 +30938,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function getNullableType(type: Type, flags: TypeFlags): Type { const missing = (flags & ~type.flags) & (TypeFlags.Undefined | TypeFlags.Null); - return missing === 0 ? type : - missing === TypeFlags.Undefined ? getUnionType([type, undefinedType]) : - missing === TypeFlags.Null ? getUnionType([type, nullType]) : - getUnionType([type, undefinedType, nullType]); + return missing === 0 ? type + : missing === TypeFlags.Undefined ? getUnionType([type, undefinedType]) + : missing === TypeFlags.Null ? getUnionType([type, nullType]) + : getUnionType([type, undefinedType, nullType]); } function getOptionalType(type: Type, isProperty = false): Type { Debug.assert(strictNullChecks); const missingOrUndefined = isProperty ? undefinedOrMissingType : undefinedType; - return type === missingOrUndefined || type.flags & TypeFlags.Union && (type as UnionType).types[0] === missingOrUndefined ? type : getUnionType([type, missingOrUndefined]); + return type === missingOrUndefined + || type.flags & TypeFlags.Union && (type as UnionType).types[0] === missingOrUndefined ? type + : getUnionType([type, missingOrUndefined]); } function getGlobalNonNullableTypeInstantiation(type: Type) { if (!deferredGlobalNonNullableTypeAlias) { - deferredGlobalNonNullableTypeAlias = getGlobalSymbol("NonNullable" as __String, SymbolFlags.TypeAlias, /*diagnostic*/ undefined) || unknownSymbol; + deferredGlobalNonNullableTypeAlias = + getGlobalSymbol("NonNullable" as __String, SymbolFlags.TypeAlias, /*diagnostic*/ undefined) + || unknownSymbol; } - return deferredGlobalNonNullableTypeAlias !== unknownSymbol ? - getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]) : - getIntersectionType([type, emptyObjectType]); + return deferredGlobalNonNullableTypeAlias !== unknownSymbol + ? getTypeAliasInstantiation(deferredGlobalNonNullableTypeAlias, [type]) + : getIntersectionType([type, emptyObjectType]); } function getNonNullableType(type: Type): Type { @@ -23610,13 +30976,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) { - return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type; + return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) + : type; } function getOptionalExpressionType(exprType: Type, expression: Expression) { - return isExpressionOfOptionalChainRoot(expression) ? getNonNullableType(exprType) : - isOptionalChain(expression) ? removeOptionalTypeMarker(exprType) : - exprType; + return isExpressionOfOptionalChainRoot(expression) ? getNonNullableType(exprType) + : isOptionalChain(expression) ? removeOptionalTypeMarker(exprType) + : exprType; } function removeMissingType(type: Type, isOptional: boolean) { @@ -23628,7 +30995,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function removeMissingOrUndefinedType(type: Type): Type { - return exactOptionalPropertyTypes ? removeType(type, missingType) : getTypeWithFacts(type, TypeFacts.NEUndefined); + return exactOptionalPropertyTypes ? removeType(type, missingType) + : getTypeWithFacts(type, TypeFacts.NEUndefined); } /** @@ -23666,12 +31034,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? every((type as IntersectionType).types, isObjectTypeWithInferableIndex) : !!( type.symbol - && (type.symbol.flags & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum | SymbolFlags.ValueModule)) !== 0 + && (type.symbol.flags + & (SymbolFlags.ObjectLiteral | SymbolFlags.TypeLiteral | SymbolFlags.Enum + | SymbolFlags.ValueModule)) !== 0 && !(type.symbol.flags & SymbolFlags.Class) && !typeHasCallOrConstructSignatures(type) ) || !!( objectFlags & ObjectFlags.ObjectRestType - ) || !!(objectFlags & ObjectFlags.ReverseMapped && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); + ) + || !!(objectFlags & ObjectFlags.ReverseMapped + && isObjectTypeWithInferableIndex((type as ReverseMappedType).source)); } function createSymbolWithType(source: Symbol, type: Type | undefined) { @@ -23695,7 +31067,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const property of getPropertiesOfObjectType(type)) { const original = getTypeOfSymbol(property); const updated = f(original); - members.set(property.escapedName, updated === original ? property : createSymbolWithType(property, updated)); + members.set( + property.escapedName, + updated === original ? property : createSymbolWithType(property, updated), + ); } return members; } @@ -23716,14 +31091,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const resolved = type as ResolvedType; const members = transformTypeOfMembers(type, getRegularTypeOfObjectLiteral); - const regularNew = createAnonymousType(resolved.symbol, members, resolved.callSignatures, resolved.constructSignatures, resolved.indexInfos); + const regularNew = createAnonymousType( + resolved.symbol, + members, + resolved.callSignatures, + resolved.constructSignatures, + resolved.indexInfos, + ); regularNew.flags = resolved.flags; regularNew.objectFlags |= resolved.objectFlags & ~ObjectFlags.FreshLiteral; (type as FreshObjectLiteralType).regularType = regularNew; return regularNew; } - function createWideningContext(parent: WideningContext | undefined, propertyName: __String | undefined, siblings: Type[] | undefined): WideningContext { + function createWideningContext( + parent: WideningContext | undefined, + propertyName: __String | undefined, + siblings: Type[] | undefined, + ): WideningContext { return { parent, propertyName, siblings, resolvedProperties: undefined }; } @@ -23795,9 +31180,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray, - sameMap(getIndexInfosOfType(type), info => createIndexInfo(info.keyType, getWidenedType(info.type), info.isReadonly))); - result.objectFlags |= (getObjectFlags(type) & (ObjectFlags.JSLiteral | ObjectFlags.NonInferrableType)); // Retain js literal flag through widening + const result = createAnonymousType( + type.symbol, + members, + emptyArray, + emptyArray, + sameMap( + getIndexInfosOfType(type), + info => createIndexInfo(info.keyType, getWidenedType(info.type), info.isReadonly), + ), + ); + result.objectFlags |= getObjectFlags(type) & (ObjectFlags.JSLiteral | ObjectFlags.NonInferrableType); // Retain js literal flag through widening return result; } @@ -23818,12 +31211,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { result = getWidenedTypeOfObjectLiteral(type, context); } else if (type.flags & TypeFlags.Union) { - const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (type as UnionType).types); - const widenedTypes = sameMap((type as UnionType).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext)); + const unionContext = context + || createWideningContext( + /*parent*/ undefined, + /*propertyName*/ undefined, + (type as UnionType).types, + ); + const widenedTypes = sameMap( + (type as UnionType).types, + t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext), + ); // Widening an empty object literal transitions from a highly restrictive type to // a highly inclusive one. For that reason we perform subtype reduction here if the // union includes empty object types (e.g. reducing {} | string to just {}). - result = getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal); + result = getUnionType( + widenedTypes, + some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal, + ); } else if (type.flags & TypeFlags.Intersection) { result = getIntersectionType(sameMap((type as IntersectionType).types, getWidenedType)); @@ -23877,7 +31281,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const t = getTypeOfSymbol(p); if (getObjectFlags(t) & ObjectFlags.ContainsWideningType) { if (!reportWideningErrorsInType(t)) { - error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolToString(p), typeToString(getWidenedType(t))); + error( + p.valueDeclaration, + Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, + symbolToString(p), + typeToString(getWidenedType(t)), + ); } errorReported = true; } @@ -23898,25 +31307,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.BinaryExpression: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - diagnostic = noImplicitAny ? Diagnostics.Member_0_implicitly_has_an_1_type : Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; + diagnostic = noImplicitAny ? Diagnostics.Member_0_implicitly_has_an_1_type + : Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; break; case SyntaxKind.Parameter: const param = declaration as ParameterDeclaration; if (isIdentifier(param.name)) { const originalKeywordKind = identifierToKeywordKind(param.name); - if ((isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && - param.parent.parameters.indexOf(param) > -1 && - (resolveName(param, param.name.escapedText, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, param.name.escapedText, /*isUse*/ true) || - originalKeywordKind && isTypeNodeKind(originalKeywordKind))) { + if ( + (isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) + || isFunctionTypeNode(param.parent)) + && param.parent.parameters.indexOf(param) > -1 + && (resolveName( + param, + param.name.escapedText, + SymbolFlags.Type, + /*nameNotFoundMessage*/ undefined, + param.name.escapedText, + /*isUse*/ true, + ) + || originalKeywordKind && isTypeNodeKind(originalKeywordKind)) + ) { const newName = "arg" + param.parent.parameters.indexOf(param); const typeName = declarationNameToString(param.name) + (param.dotDotDotToken ? "[]" : ""); - errorOrSuggestion(noImplicitAny, declaration, Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, typeName); + errorOrSuggestion( + noImplicitAny, + declaration, + Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, + newName, + typeName, + ); return; } } - diagnostic = (declaration as ParameterDeclaration).dotDotDotToken ? - noImplicitAny ? Diagnostics.Rest_parameter_0_implicitly_has_an_any_type : Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage : - noImplicitAny ? Diagnostics.Parameter_0_implicitly_has_an_1_type : Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; + diagnostic = (declaration as ParameterDeclaration).dotDotDotToken + ? noImplicitAny ? Diagnostics.Rest_parameter_0_implicitly_has_an_any_type + : Diagnostics + .Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage + : noImplicitAny ? Diagnostics.Parameter_0_implicitly_has_an_1_type + : Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; break; case SyntaxKind.BindingElement: diagnostic = Diagnostics.Binding_element_0_implicitly_has_an_1_type; @@ -23926,11 +31355,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } break; case SyntaxKind.JSDocFunctionType: - error(declaration, Diagnostics.Function_type_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + error( + declaration, + Diagnostics.Function_type_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, + typeAsString, + ); return; case SyntaxKind.JSDocSignature: if (noImplicitAny && isJSDocOverloadTag(declaration.parent)) { - error(declaration.parent.tagName, Diagnostics.This_overload_implicitly_returns_the_type_0_because_it_lacks_a_return_type_annotation, typeAsString); + error( + declaration.parent.tagName, + Diagnostics + .This_overload_implicitly_returns_the_type_0_because_it_lacks_a_return_type_annotation, + typeAsString, + ); } return; case SyntaxKind.FunctionDeclaration: @@ -23942,16 +31380,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ArrowFunction: if (noImplicitAny && !(declaration as NamedDeclaration).name) { if (wideningKind === WideningKind.GeneratorYield) { - error(declaration, Diagnostics.Generator_implicitly_has_yield_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type_annotation, typeAsString); + error( + declaration, + Diagnostics + .Generator_implicitly_has_yield_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_type_annotation, + typeAsString, + ); } else { - error(declaration, Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeAsString); + error( + declaration, + Diagnostics + .Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, + typeAsString, + ); } return; } - diagnostic = !noImplicitAny ? Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage : - wideningKind === WideningKind.GeneratorYield ? Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_yield_type : - Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; + diagnostic = !noImplicitAny + ? Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage + : wideningKind === WideningKind.GeneratorYield + ? Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_yield_type + : Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type; break; case SyntaxKind.MappedType: if (noImplicitAny) { @@ -23959,14 +31409,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return; default: - diagnostic = noImplicitAny ? Diagnostics.Variable_0_implicitly_has_an_1_type : Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; + diagnostic = noImplicitAny ? Diagnostics.Variable_0_implicitly_has_an_1_type + : Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage; } - errorOrSuggestion(noImplicitAny, declaration, diagnostic, declarationNameToString(getNameOfDeclaration(declaration)), typeAsString); + errorOrSuggestion( + noImplicitAny, + declaration, + diagnostic, + declarationNameToString(getNameOfDeclaration(declaration)), + typeAsString, + ); } function reportErrorsFromWidening(declaration: Declaration, type: Type, wideningKind?: WideningKind) { addLazyDiagnostic(() => { - if (noImplicitAny && getObjectFlags(type) & ObjectFlags.ContainsWideningType && (!wideningKind || !getContextualSignatureForFunctionLikeDeclaration(declaration as FunctionLikeDeclaration))) { + if ( + noImplicitAny && getObjectFlags(type) & ObjectFlags.ContainsWideningType + && (!wideningKind + || !getContextualSignatureForFunctionLikeDeclaration(declaration as FunctionLikeDeclaration)) + ) { // Report implicit any error within type if possible, otherwise report error on declaration if (!reportWideningErrorsInType(type)) { reportImplicitAny(declaration, type, wideningKind); @@ -24000,7 +31461,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function applyToReturnTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) { const sourceTypePredicate = getTypePredicateOfSignature(source); const targetTypePredicate = getTypePredicateOfSignature(target); - if (sourceTypePredicate && targetTypePredicate && typePredicateKindsMatch(sourceTypePredicate, targetTypePredicate) && sourceTypePredicate.type && targetTypePredicate.type) { + if ( + sourceTypePredicate && targetTypePredicate + && typePredicateKindsMatch(sourceTypePredicate, targetTypePredicate) && sourceTypePredicate.type + && targetTypePredicate.type + ) { callback(sourceTypePredicate.type, targetTypePredicate.type); } else { @@ -24008,15 +31473,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function createInferenceContext(typeParameters: readonly TypeParameter[], signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer): InferenceContext { - return createInferenceContextWorker(typeParameters.map(createInferenceInfo), signature, flags, compareTypes || compareTypesAssignable); + function createInferenceContext( + typeParameters: readonly TypeParameter[], + signature: Signature | undefined, + flags: InferenceFlags, + compareTypes?: TypeComparer, + ): InferenceContext { + return createInferenceContextWorker( + typeParameters.map(createInferenceInfo), + signature, + flags, + compareTypes || compareTypesAssignable, + ); } - function cloneInferenceContext(context: T, extraFlags: InferenceFlags = 0): InferenceContext | T & undefined { - return context && createInferenceContextWorker(map(context.inferences, cloneInferenceInfo), context.signature, context.flags | extraFlags, context.compareTypes); + function cloneInferenceContext( + context: T, + extraFlags: InferenceFlags = 0, + ): InferenceContext | T & undefined { + return context + && createInferenceContextWorker( + map(context.inferences, cloneInferenceInfo), + context.signature, + context.flags | extraFlags, + context.compareTypes, + ); } - function createInferenceContextWorker(inferences: InferenceInfo[], signature: Signature | undefined, flags: InferenceFlags, compareTypes: TypeComparer): InferenceContext { + function createInferenceContextWorker( + inferences: InferenceInfo[], + signature: Signature | undefined, + flags: InferenceFlags, + compareTypes: TypeComparer, + ): InferenceContext { const context: InferenceContext = { inferences, signature, @@ -24031,22 +31520,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function makeFixingMapperForContext(context: InferenceContext) { - return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (inference, i) => () => { - if (!inference.isFixed) { - // Before we commit to a particular inference (and thus lock out any further inferences), - // we infer from any intra-expression inference sites we have collected. - inferFromIntraExpressionSites(context); - clearCachedInferences(context.inferences); - inference.isFixed = true; - } - return getInferredType(context, i); - })); + return makeDeferredTypeMapper( + map(context.inferences, i => i.typeParameter), + map(context.inferences, (inference, i) => () => { + if (!inference.isFixed) { + // Before we commit to a particular inference (and thus lock out any further inferences), + // we infer from any intra-expression inference sites we have collected. + inferFromIntraExpressionSites(context); + clearCachedInferences(context.inferences); + inference.isFixed = true; + } + return getInferredType(context, i); + }), + ); } function makeNonFixingMapperForContext(context: InferenceContext) { - return makeDeferredTypeMapper(map(context.inferences, i => i.typeParameter), map(context.inferences, (_, i) => () => { - return getInferredType(context, i); - })); + return makeDeferredTypeMapper( + map(context.inferences, i => i.typeParameter), + map(context.inferences, (_, i) => () => { + return getInferredType(context, i); + }), + ); } function clearCachedInferences(inferences: InferenceInfo[]) { @@ -24057,7 +31552,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function addIntraExpressionInferenceSite(context: InferenceContext, node: Expression | MethodDeclaration, type: Type) { + function addIntraExpressionInferenceSite( + context: InferenceContext, + node: Expression | MethodDeclaration, + type: Type, + ) { (context.intraExpressionInferenceSites ??= []).push({ node, type }); } @@ -24077,9 +31576,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function inferFromIntraExpressionSites(context: InferenceContext) { if (context.intraExpressionInferenceSites) { for (const { node, type } of context.intraExpressionInferenceSites) { - const contextualType = node.kind === SyntaxKind.MethodDeclaration ? - getContextualTypeForObjectLiteralMethod(node as MethodDeclaration, ContextFlags.NoConstraints) : - getContextualType(node, ContextFlags.NoConstraints); + const contextualType = node.kind === SyntaxKind.MethodDeclaration + ? getContextualTypeForObjectLiteralMethod(node as MethodDeclaration, ContextFlags.NoConstraints) + : getContextualType(node, ContextFlags.NoConstraints); if (contextualType) { inferTypes(context.inferences, type, contextualType); } @@ -24097,7 +31596,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { priority: undefined, topLevel: true, isFixed: false, - impliedArity: undefined + impliedArity: undefined, }; } @@ -24110,15 +31609,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { priority: inference.priority, topLevel: inference.topLevel, isFixed: inference.isFixed, - impliedArity: inference.impliedArity + impliedArity: inference.impliedArity, }; } function cloneInferredPartOfContext(context: InferenceContext): InferenceContext | undefined { const inferences = filter(context.inferences, hasInferenceCandidates); - return inferences.length ? - createInferenceContextWorker(map(inferences, cloneInferenceInfo), context.signature, context.flags, context.compareTypes) : - undefined; + return inferences.length + ? createInferenceContextWorker( + map(inferences, cloneInferenceInfo), + context.signature, + context.flags, + context.compareTypes, + ) + : undefined; } function getMapperFromContext(context: T): TypeMapper | T & undefined { @@ -24133,14 +31637,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (objectFlags & ObjectFlags.CouldContainTypeVariablesComputed) { return !!(objectFlags & ObjectFlags.CouldContainTypeVariables); } - const result = !!(type.flags & TypeFlags.Instantiable || - type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && ( - objectFlags & ObjectFlags.Reference && ((type as TypeReference).node || some(getTypeArguments(type as TypeReference), couldContainTypeVariables)) || - objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations || - objectFlags & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType | ObjectFlags.InstantiationExpressionType)) || - type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) && some((type as UnionOrIntersectionType | TemplateLiteralType).types, couldContainTypeVariables)); + const result = !!(type.flags & TypeFlags.Instantiable + || type.flags & TypeFlags.Object && !isNonGenericTopLevelType(type) && ( + objectFlags & ObjectFlags.Reference + && ((type as TypeReference).node + || some(getTypeArguments(type as TypeReference), couldContainTypeVariables)) + || objectFlags & ObjectFlags.Anonymous && type.symbol + && type.symbol.flags + & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral + | SymbolFlags.ObjectLiteral) + && type.symbol.declarations + || objectFlags + & (ObjectFlags.Mapped | ObjectFlags.ReverseMapped | ObjectFlags.ObjectRestType + | ObjectFlags.InstantiationExpressionType) + ) + || type.flags & (TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral) + && !(type.flags & TypeFlags.EnumLiteral) && !isNonGenericTopLevelType(type) + && some((type as UnionOrIntersectionType | TemplateLiteralType).types, couldContainTypeVariables)); if (type.flags & TypeFlags.ObjectFlagsType) { - (type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (result ? ObjectFlags.CouldContainTypeVariables : 0); + (type as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed + | (result ? ObjectFlags.CouldContainTypeVariables : 0); } return result; } @@ -24148,23 +31664,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isNonGenericTopLevelType(type: Type) { if (type.aliasSymbol && !type.aliasTypeArguments) { const declaration = getDeclarationOfKind(type.aliasSymbol, SyntaxKind.TypeAliasDeclaration); - return !!(declaration && findAncestor(declaration.parent, n => n.kind === SyntaxKind.SourceFile ? true : n.kind === SyntaxKind.ModuleDeclaration ? false : "quit")); + return !!(declaration + && findAncestor( + declaration.parent, + n => n.kind === SyntaxKind.SourceFile ? true + : n.kind === SyntaxKind.ModuleDeclaration ? false : "quit", + )); } return false; } function isTypeParameterAtTopLevel(type: Type, tp: TypeParameter, depth = 0): boolean { - return !!(type === tp || - type.flags & TypeFlags.UnionOrIntersection && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, tp, depth)) || - depth < 3 && type.flags & TypeFlags.Conditional && ( - isTypeParameterAtTopLevel(getTrueTypeFromConditionalType(type as ConditionalType), tp, depth + 1) || - isTypeParameterAtTopLevel(getFalseTypeFromConditionalType(type as ConditionalType), tp, depth + 1))); + return !!(type === tp + || type.flags & TypeFlags.UnionOrIntersection + && some((type as UnionOrIntersectionType).types, t => isTypeParameterAtTopLevel(t, tp, depth)) + || depth < 3 && type.flags & TypeFlags.Conditional && ( + isTypeParameterAtTopLevel(getTrueTypeFromConditionalType(type as ConditionalType), tp, depth + 1) + || isTypeParameterAtTopLevel( + getFalseTypeFromConditionalType(type as ConditionalType), + tp, + depth + 1, + ) + )); } function isTypeParameterAtTopLevelInReturnType(signature: Signature, typeParameter: TypeParameter) { const typePredicate = getTypePredicateOfSignature(signature); - return typePredicate ? !!typePredicate.type && isTypeParameterAtTopLevel(typePredicate.type, typeParameter) : - isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), typeParameter); + return typePredicate ? !!typePredicate.type && isTypeParameterAtTopLevel(typePredicate.type, typeParameter) + : isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), typeParameter); } /** Create an object with properties named in the string literal type. Every property has type `any` */ @@ -24183,7 +31710,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } members.set(name, literalProp); }); - const indexInfos = type.flags & TypeFlags.String ? [createIndexInfo(stringType, emptyObjectType, /*isReadonly*/ false)] : emptyArray; + const indexInfos = type.flags & TypeFlags.String + ? [createIndexInfo(stringType, emptyObjectType, /*isReadonly*/ false)] : emptyArray; return createAnonymousType(/*symbol*/ undefined, members, emptyArray, emptyArray, indexInfos); } @@ -24193,7 +31721,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * property is computed by inferring from the source property type to X for the type * variable T[P] (i.e. we treat the type T[P] as the type variable we're inferring for). */ - function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined { + function inferTypeForHomomorphicMappedType( + source: Type, + target: MappedType, + constraint: IndexType, + ): Type | undefined { const cacheKey = source.id + "," + target.id + "," + constraint.id; if (reverseMappedCache.has(cacheKey)) { return reverseMappedCache.get(cacheKey); @@ -24214,32 +31746,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // literal { a: 123, b: x => true } is marked non-inferable because it contains a context sensitive // arrow function, but is considered partially inferable because property 'a' has an inferable type. function isPartiallyInferableType(type: Type): boolean { - return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) || - isObjectLiteralType(type) && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) || - isTupleType(type) && some(getElementTypes(type), isPartiallyInferableType); + return !(getObjectFlags(type) & ObjectFlags.NonInferrableType) + || isObjectLiteralType(type) + && some(getPropertiesOfType(type), prop => isPartiallyInferableType(getTypeOfSymbol(prop))) + || isTupleType(type) && some(getElementTypes(type), isPartiallyInferableType); } function createReverseMappedType(source: Type, target: MappedType, constraint: IndexType) { // We consider a source type reverse mappable if it has a string index signature or if // it has one or more properties and is of a partially inferable type. - if (!(getIndexInfoOfType(source, stringType) || getPropertiesOfType(source).length !== 0 && isPartiallyInferableType(source))) { + if ( + !(getIndexInfoOfType(source, stringType) + || getPropertiesOfType(source).length !== 0 && isPartiallyInferableType(source)) + ) { return undefined; } // For arrays and tuples we infer new arrays and tuples where the reverse mapping has been // applied to the element type(s). if (isArrayType(source)) { - return createArrayType(inferReverseMappedType(getTypeArguments(source)[0], target, constraint), isReadonlyArrayType(source)); + return createArrayType( + inferReverseMappedType(getTypeArguments(source)[0], target, constraint), + isReadonlyArrayType(source), + ); } if (isTupleType(source)) { const elementTypes = map(getElementTypes(source), t => inferReverseMappedType(t, target, constraint)); - const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ? - sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) : - source.target.elementFlags; - return createTupleType(elementTypes, elementFlags, source.target.readonly, source.target.labeledElementDeclarations); + const elementFlags = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional + ? sameMap(source.target.elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) + : source.target.elementFlags; + return createTupleType( + elementTypes, + elementFlags, + source.target.readonly, + source.target.labeledElementDeclarations, + ); } // For all other object types we infer a new object type where the reverse mapping has been // applied to the type of each property. - const reversed = createObjectType(ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, /*symbol*/ undefined) as ReverseMappedType; + const reversed = createObjectType( + ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, + /*symbol*/ undefined, + ) as ReverseMappedType; reversed.source = source; reversed.mappedType = target; reversed.constraintType = constraint; @@ -24249,27 +31796,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeOfReverseMappedSymbol(symbol: ReverseMappedSymbol) { const links = getSymbolLinks(symbol); if (!links.type) { - links.type = inferReverseMappedType(symbol.links.propertyType, symbol.links.mappedType, symbol.links.constraintType); + links.type = inferReverseMappedType( + symbol.links.propertyType, + symbol.links.mappedType, + symbol.links.constraintType, + ); } return links.type; } function inferReverseMappedType(sourceType: Type, target: MappedType, constraint: IndexType): Type { - const typeParameter = getIndexedAccessType(constraint.type, getTypeParameterFromMappedType(target)) as TypeParameter; + const typeParameter = getIndexedAccessType( + constraint.type, + getTypeParameterFromMappedType(target), + ) as TypeParameter; const templateType = getTemplateTypeFromMappedType(target); const inference = createInferenceInfo(typeParameter); inferTypes([inference], sourceType, templateType); return getTypeFromInference(inference) || unknownType; } - function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator { + function* getUnmatchedProperties( + source: Type, + target: Type, + requireOptionalProperties: boolean, + matchDiscriminantProperties: boolean, + ): IterableIterator { const properties = getPropertiesOfType(target); for (const targetProp of properties) { // TODO: remove this when we support static private identifier fields and find other solutions to get privateNamesAndStaticFields test to pass if (isStaticPrivateIdentifierProperty(targetProp)) { continue; } - if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial)) { + if ( + requireOptionalProperties + || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial) + ) { const sourceProp = getPropertyOfType(source, targetProp.escapedName); if (!sourceProp) { yield targetProp; @@ -24278,7 +31840,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetType = getTypeOfSymbol(targetProp); if (targetType.flags & TypeFlags.Unit) { const sourceType = getTypeOfSymbol(sourceProp); - if (!(sourceType.flags & TypeFlags.Any || getRegularTypeOfLiteralType(sourceType) === getRegularTypeOfLiteralType(targetType))) { + if ( + !(sourceType.flags & TypeFlags.Any + || getRegularTypeOfLiteralType(sourceType) === getRegularTypeOfLiteralType(targetType)) + ) { yield targetProp; } } @@ -24287,27 +31852,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): Symbol | undefined { - return firstOrUndefinedIterator(getUnmatchedProperties(source, target, requireOptionalProperties, matchDiscriminantProperties)); + function getUnmatchedProperty( + source: Type, + target: Type, + requireOptionalProperties: boolean, + matchDiscriminantProperties: boolean, + ): Symbol | undefined { + return firstOrUndefinedIterator( + getUnmatchedProperties(source, target, requireOptionalProperties, matchDiscriminantProperties), + ); } function tupleTypesDefinitelyUnrelated(source: TupleTypeReference, target: TupleTypeReference) { - return !(target.target.combinedFlags & ElementFlags.Variadic) && target.target.minLength > source.target.minLength || - !target.target.hasRestElement && (source.target.hasRestElement || target.target.fixedLength < source.target.fixedLength); + return !(target.target.combinedFlags & ElementFlags.Variadic) + && target.target.minLength > source.target.minLength + || !target.target.hasRestElement + && (source.target.hasRestElement || target.target.fixedLength < source.target.fixedLength); } function typesDefinitelyUnrelated(source: Type, target: Type) { // Two tuple types with incompatible arities are definitely unrelated. // Two object types that each have a property that is unmatched in the other are definitely unrelated. - return isTupleType(source) && isTupleType(target) ? tupleTypesDefinitelyUnrelated(source, target) : - !!getUnmatchedProperty(source, target, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ true) && - !!getUnmatchedProperty(target, source, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false); + return isTupleType(source) && isTupleType(target) ? tupleTypesDefinitelyUnrelated(source, target) + : !!getUnmatchedProperty( + source, + target, + /*requireOptionalProperties*/ false, + /*matchDiscriminantProperties*/ true, + ) + && !!getUnmatchedProperty( + target, + source, + /*requireOptionalProperties*/ false, + /*matchDiscriminantProperties*/ false, + ); } function getTypeFromInference(inference: InferenceInfo) { - return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : - inference.contraCandidates ? getIntersectionType(inference.contraCandidates) : - undefined; + return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) + : inference.contraCandidates ? getIntersectionType(inference.contraCandidates) + : undefined; } function hasSkipDirectInferenceFlag(node: Node) { @@ -24326,8 +31910,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetEnd = target.texts[target.texts.length - 1]; const startLen = Math.min(sourceStart.length, targetStart.length); const endLen = Math.min(sourceEnd.length, targetEnd.length); - return sourceStart.slice(0, startLen) !== targetStart.slice(0, startLen) || - sourceEnd.slice(sourceEnd.length - endLen) !== targetEnd.slice(targetEnd.length - endLen); + return sourceStart.slice(0, startLen) !== targetStart.slice(0, startLen) + || sourceEnd.slice(sourceEnd.length - endLen) !== targetEnd.slice(targetEnd.length - endLen); } /** @@ -24379,34 +31963,48 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } if (target.flags & TypeFlags.Intersection) { - return every((target as IntersectionType).types, t => t === emptyTypeLiteralType || isValidTypeForTemplateLiteralPlaceholder(source, t)); + return every( + (target as IntersectionType).types, + t => t === emptyTypeLiteralType || isValidTypeForTemplateLiteralPlaceholder(source, t), + ); } if (source.flags & TypeFlags.StringLiteral) { const value = (source as StringLiteralType).value; - return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) || - target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) || - target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) && value === (target as IntrinsicType).intrinsicName || - target.flags & TypeFlags.StringMapping && isMemberOfStringMapping(getStringLiteralType(value), target) || - target.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, target as TemplateLiteralType)); + return !!(target.flags & TypeFlags.Number && isValidNumberString(value, /*roundTripOnly*/ false) + || target.flags & TypeFlags.BigInt && isValidBigIntString(value, /*roundTripOnly*/ false) + || target.flags & (TypeFlags.BooleanLiteral | TypeFlags.Nullable) + && value === (target as IntrinsicType).intrinsicName + || target.flags & TypeFlags.StringMapping + && isMemberOfStringMapping(getStringLiteralType(value), target) + || target.flags & TypeFlags.TemplateLiteral + && isTypeMatchedByTemplateLiteralType(source, target as TemplateLiteralType)); } if (source.flags & TypeFlags.TemplateLiteral) { const texts = (source as TemplateLiteralType).texts; - return texts.length === 2 && texts[0] === "" && texts[1] === "" && isTypeAssignableTo((source as TemplateLiteralType).types[0], target); + return texts.length === 2 && texts[0] === "" && texts[1] === "" + && isTypeAssignableTo((source as TemplateLiteralType).types[0], target); } return isTypeAssignableTo(source, target); } function inferTypesFromTemplateLiteralType(source: Type, target: TemplateLiteralType): Type[] | undefined { - return source.flags & TypeFlags.StringLiteral ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) : - source.flags & TypeFlags.TemplateLiteral ? - arraysEqual((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, getStringLikeTypeForType) : - inferFromLiteralPartsToTemplateLiteral((source as TemplateLiteralType).texts, (source as TemplateLiteralType).types, target) : - undefined; + return source.flags & TypeFlags.StringLiteral + ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) + : source.flags & TypeFlags.TemplateLiteral + ? arraysEqual((source as TemplateLiteralType).texts, target.texts) + ? map((source as TemplateLiteralType).types, getStringLikeTypeForType) + : inferFromLiteralPartsToTemplateLiteral( + (source as TemplateLiteralType).texts, + (source as TemplateLiteralType).types, + target, + ) + : undefined; } function isTypeMatchedByTemplateLiteralType(source: Type, target: TemplateLiteralType): boolean { const inferences = inferTypesFromTemplateLiteralType(source, target); - return !!inferences && every(inferences, (r, i) => isValidTypeForTemplateLiteralPlaceholder(r, target.types[i])); + return !!inferences + && every(inferences, (r, i) => isValidTypeForTemplateLiteralPlaceholder(r, target.types[i])); } function getStringLikeTypeForType(type: Type) { @@ -24432,7 +32030,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the source. The first match for the '.' in target occurs at character 1 in the source text part at index 1, and thus // the first inference is the template literal type `<${string}>`. The remainder of the source makes up the second // inference, the template literal type `<${number}-${number}>`. - function inferFromLiteralPartsToTemplateLiteral(sourceTexts: readonly string[], sourceTypes: readonly Type[], target: TemplateLiteralType): Type[] | undefined { + function inferFromLiteralPartsToTemplateLiteral( + sourceTexts: readonly string[], + sourceTypes: readonly Type[], + target: TemplateLiteralType, + ): Type[] | undefined { const lastSourceIndex = sourceTexts.length - 1; const sourceStartText = sourceTexts[0]; const sourceEndText = sourceTexts[lastSourceIndex]; @@ -24440,8 +32042,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const lastTargetIndex = targetTexts.length - 1; const targetStartText = targetTexts[0]; const targetEndText = targetTexts[lastTargetIndex]; - if (lastSourceIndex === 0 && sourceStartText.length < targetStartText.length + targetEndText.length || - !sourceStartText.startsWith(targetStartText) || !sourceEndText.endsWith(targetEndText)) return undefined; + if ( + lastSourceIndex === 0 && sourceStartText.length < targetStartText.length + targetEndText.length + || !sourceStartText.startsWith(targetStartText) || !sourceEndText.endsWith(targetEndText) + ) return undefined; const remainingEndText = sourceEndText.slice(0, sourceEndText.length - targetEndText.length); const matches: Type[] = []; let seg = 0; @@ -24477,18 +32081,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return index < lastSourceIndex ? sourceTexts[index] : remainingEndText; } function addMatch(s: number, p: number) { - const matchType = s === seg ? - getStringLiteralType(getSourceText(s).slice(pos, p)) : - getTemplateLiteralType( + const matchType = s === seg + ? getStringLiteralType(getSourceText(s).slice(pos, p)) + : getTemplateLiteralType( [sourceTexts[seg].slice(pos), ...sourceTexts.slice(seg + 1, s), getSourceText(s).slice(0, p)], - sourceTypes.slice(seg, s)); + sourceTypes.slice(seg, s), + ); matches.push(matchType); seg = s; pos = p; } } - function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority = InferencePriority.None, contravariant = false) { + function inferTypes( + inferences: InferenceInfo[], + originalSource: Type, + originalTarget: Type, + priority = InferencePriority.None, + contravariant = false, + ) { let bivariant = false; let propagationType: Type; let inferencePriority: number = InferencePriority.MaxValue; @@ -24518,8 +32129,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Simply infer from source type arguments to target type arguments, with defaults applied. const params = getSymbolLinks(source.aliasSymbol).typeParameters!; const minParams = getMinTypeArgumentCount(params); - const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); - const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); + const sourceTypes = fillMissingTypeArguments( + source.aliasTypeArguments, + params, + minParams, + isInJSFile(source.aliasSymbol.valueDeclaration), + ); + const targetTypes = fillMissingTypeArguments( + target.aliasTypeArguments, + params, + minParams, + isInJSFile(source.aliasSymbol.valueDeclaration), + ); inferFromTypeArguments(sourceTypes, targetTypes!, getAliasVariances(source.aliasSymbol)); } // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. @@ -24536,7 +32157,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (target.flags & TypeFlags.Union) { // First, infer between identically matching source and target constituents and remove the // matching types. - const [tempSources, tempTargets] = inferFromMatchingTypes(source.flags & TypeFlags.Union ? (source as UnionType).types : [source], (target as UnionType).types, isTypeOrBaseIdenticalTo); + const [tempSources, tempTargets] = inferFromMatchingTypes( + source.flags & TypeFlags.Union ? (source as UnionType).types : [source], + (target as UnionType).types, + isTypeOrBaseIdenticalTo, + ); // Next, infer between closely matching source and target constituents and remove // the matching types. Types closely match when they are instantiations of the same // object type or instantiations of the same type alias. @@ -24556,14 +32181,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } source = getUnionType(sources); } - else if (target.flags & TypeFlags.Intersection && !every((target as IntersectionType).types, isNonGenericObjectType)) { + else if ( + target.flags & TypeFlags.Intersection + && !every((target as IntersectionType).types, isNonGenericObjectType) + ) { // We reduce intersection types unless they're simple combinations of object types. For example, // when inferring from 'string[] & { extra: any }' to 'string[] & T' we want to remove string[] and // infer { extra: any } for T. But when inferring to 'string[] & Iterable' we want to keep the // string[] on the source side and infer string for T. if (!(source.flags & TypeFlags.Union)) { // Infer between identically matching source and target constituents and remove the matching types. - const [sources, targets] = inferFromMatchingTypes(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], (target as IntersectionType).types, isTypeIdenticalTo); + const [sources, targets] = inferFromMatchingTypes( + source.flags & TypeFlags.Intersection ? (source as IntersectionType).types : [source], + (target as IntersectionType).types, + isTypeIdenticalTo, + ); if (sources.length === 0 || targets.length === 0) { return; } @@ -24623,7 +32255,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { clearCachedInferences(inferences); } } - if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && inference.topLevel && !isTypeParameterAtTopLevel(originalTarget, target as TypeParameter)) { + if ( + !(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter + && inference.topLevel && !isTypeParameterAtTopLevel(originalTarget, target as TypeParameter) + ) { inference.topLevel = false; clearCachedInferences(inferences); } @@ -24641,25 +32276,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Generally simplifications of instantiable indexes are avoided to keep relationship checking correct, however if our target is an access, we can consider // that key of that access to be "instantiated", since we're looking to find the infernce goal in any way we can. if (indexType.flags & TypeFlags.Instantiable) { - const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false); + const simplified = distributeIndexOverObjectType( + getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), + indexType, + /*writing*/ false, + ); if (simplified && simplified !== target) { inferFromTypes(source, simplified); } } } } - if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( - (source as TypeReference).target === (target as TypeReference).target || isArrayType(source) && isArrayType(target)) && - !((source as TypeReference).node && (target as TypeReference).node)) { + if ( + getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( + (source as TypeReference).target === (target as TypeReference).target + || isArrayType(source) && isArrayType(target) + ) + && !((source as TypeReference).node && (target as TypeReference).node) + ) { // If source and target are references to the same generic type, infer from type arguments - inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); + inferFromTypeArguments( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + getVariances((source as TypeReference).target), + ); } else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) { inferFromContravariantTypes((source as IndexType).type, (target as IndexType).type); } else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) { const empty = createEmptyObjectTypeFromStringLiteral(source); - inferFromContravariantTypesWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof); + inferFromContravariantTypesWithPriority( + empty, + (target as IndexType).type, + InferencePriority.LiteralKeyof, + ); } else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) { inferFromTypes((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType); @@ -24672,10 +32323,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (source.flags & TypeFlags.Substitution) { inferFromTypes((source as SubstitutionType).baseType, target); - inferWithPriority(getSubstitutionIntersection(source as SubstitutionType), target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority + inferWithPriority( + getSubstitutionIntersection(source as SubstitutionType), + target, + InferencePriority.SubstituteSource, + ); // Make substitute inference at a lower priority } else if (target.flags & TypeFlags.Conditional) { - invokeOnce(source, (target as ConditionalType), inferToConditionalType); + invokeOnce(source, target as ConditionalType, inferToConditionalType); } else if (target.flags & TypeFlags.UnionOrIntersection) { inferToMultipleTypes(source, (target as UnionOrIntersectionType).types, target.flags); @@ -24692,12 +32347,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { source = getReducedType(source); - if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) { + if ( + !(priority & InferencePriority.NoConstraints + && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable)) + ) { const apparentSource = getApparentType(source); // getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type. // If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes` // with the simplified source. - if (apparentSource !== source && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) { + if ( + apparentSource !== source + && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection)) + ) { return inferFromTypes(apparentSource, target); } source = apparentSource; @@ -24722,14 +32383,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { priority = savePriority; } - function inferToMultipleTypesWithPriority(source: Type, targets: Type[], targetFlags: TypeFlags, newPriority: InferencePriority) { + function inferToMultipleTypesWithPriority( + source: Type, + targets: Type[], + targetFlags: TypeFlags, + newPriority: InferencePriority, + ) { const savePriority = priority; priority |= newPriority; inferToMultipleTypes(source, targets, targetFlags); priority = savePriority; } - function invokeOnce(source: Source, target: Target, action: (source: Source, target: Target) => void) { + function invokeOnce( + source: Source, + target: Target, + action: (source: Source, target: Target) => void, + ) { const key = source.id + "," + target.id; const status = visited && visited.get(key); if (status !== undefined) { @@ -24759,7 +32429,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferencePriority = Math.min(inferencePriority, saveInferencePriority); } - function inferFromMatchingTypes(sources: Type[], targets: Type[], matches: (s: Type, t: Type) => boolean): [Type[], Type[]] { + function inferFromMatchingTypes( + sources: Type[], + targets: Type[], + matches: (s: Type, t: Type) => boolean, + ): [Type[], Type[]] { let matchedSources: Type[] | undefined; let matchedTargets: Type[] | undefined; for (const t of targets) { @@ -24777,10 +32451,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ]; } - function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) { + function inferFromTypeArguments( + sourceTypes: readonly Type[], + targetTypes: readonly Type[], + variances: readonly VarianceFlags[], + ) { const count = sourceTypes.length < targetTypes.length ? sourceTypes.length : targetTypes.length; for (let i = 0; i < count; i++) { - if (i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant) { + if ( + i < variances.length && (variances[i] & VarianceFlags.VarianceMask) === VarianceFlags.Contravariant + ) { inferFromContravariantTypes(sourceTypes[i], targetTypes[i]); } else { @@ -24818,7 +32498,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getSingleTypeVariableFromIntersectionTypes(types: Type[]) { let typeVariable: Type | undefined; for (const type of types) { - const t = type.flags & TypeFlags.Intersection && find((type as IntersectionType).types, t => !!getInferenceInfoForType(t)); + const t = type.flags & TypeFlags.Intersection + && find((type as IntersectionType).types, t => !!getInferenceInfoForType(t)); if (!t || typeVariable && t !== typeVariable) { return undefined; } @@ -24849,7 +32530,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferencePriority = InferencePriority.MaxValue; inferFromTypes(sources[i], t); if (inferencePriority === priority) matched[i] = true; - inferenceCircularity = inferenceCircularity || inferencePriority === InferencePriority.Circularity; + inferenceCircularity = inferenceCircularity + || inferencePriority === InferencePriority.Circularity; inferencePriority = Math.min(inferencePriority, saveInferencePriority); } } @@ -24922,10 +32604,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We assign a lower priority to inferences made from types containing non-inferrable // types because we may only have a partial result (i.e. we may have failed to make // reverse inferences for some properties). - inferWithPriority(inferredType, inference.typeParameter, - getObjectFlags(source) & ObjectFlags.NonInferrableType ? - InferencePriority.PartialHomomorphicMappedType : - InferencePriority.HomomorphicMappedType); + inferWithPriority( + inferredType, + inference.typeParameter, + getObjectFlags(source) & ObjectFlags.NonInferrableType + ? InferencePriority.PartialHomomorphicMappedType + : InferencePriority.HomomorphicMappedType, + ); } } return true; @@ -24933,7 +32618,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (constraintType.flags & TypeFlags.TypeParameter) { // We're inferring from some source type S to a mapped type { [P in K]: X }, where K is a type // parameter. First infer from 'keyof S' to K. - inferWithPriority(getIndexType(source, /*indexFlags*/ !!source.pattern ? IndexFlags.NoIndexSignatures : IndexFlags.None), constraintType, InferencePriority.MappedTypeConstraint); + inferWithPriority( + getIndexType( + source, + /*indexFlags*/ !!source.pattern ? IndexFlags.NoIndexSignatures : IndexFlags.None, + ), + constraintType, + InferencePriority.MappedTypeConstraint, + ); // If K is constrained to a type C, also infer to C. Thus, for a mapped type { [P in K]: X }, // where K extends keyof T, we make the same inferences as for a homomorphic mapped type // { [P in keyof T]: X }. This enables us to make meaningful inferences when the target is a @@ -24945,7 +32637,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If no inferences can be made to K's constraint, infer from a union of the property types // in the source to the template type X. const propTypes = map(getPropertiesOfType(source), getTypeOfSymbol); - const indexTypes = map(getIndexInfosOfType(source), info => info !== enumNumberIndexInfo ? info.type : neverType); + const indexTypes = map( + getIndexInfosOfType(source), + info => info !== enumNumberIndexInfo ? info.type : neverType, + ); inferFromTypes(getUnionType(concatenate(propTypes, indexTypes)), getTemplateTypeFromMappedType(target)); return true; } @@ -24956,12 +32651,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.flags & TypeFlags.Conditional) { inferFromTypes((source as ConditionalType).checkType, target.checkType); inferFromTypes((source as ConditionalType).extendsType, target.extendsType); - inferFromTypes(getTrueTypeFromConditionalType(source as ConditionalType), getTrueTypeFromConditionalType(target)); - inferFromTypes(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target)); + inferFromTypes( + getTrueTypeFromConditionalType(source as ConditionalType), + getTrueTypeFromConditionalType(target), + ); + inferFromTypes( + getFalseTypeFromConditionalType(source as ConditionalType), + getFalseTypeFromConditionalType(target), + ); } else { const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; - inferToMultipleTypesWithPriority(source, targetTypes, target.flags, contravariant ? InferencePriority.ContravariantConditional : 0); + inferToMultipleTypesWithPriority( + source, + targetTypes, + target.flags, + contravariant ? InferencePriority.ContravariantConditional : 0, + ); } } @@ -24983,43 +32689,84 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // allowed template literal placeholder types, infer from a literal type corresponding to the constraint. if (source.flags & TypeFlags.StringLiteral && target.flags & TypeFlags.TypeVariable) { const inferenceContext = getInferenceInfoForType(target); - const constraint = inferenceContext ? getBaseConstraintOfType(inferenceContext.typeParameter) : undefined; + const constraint = inferenceContext ? getBaseConstraintOfType(inferenceContext.typeParameter) + : undefined; if (constraint && !isTypeAny(constraint)) { - const constraintTypes = constraint.flags & TypeFlags.Union ? (constraint as UnionType).types : [constraint]; - let allTypeFlags: TypeFlags = reduceLeft(constraintTypes, (flags, t) => flags | t.flags, 0 as TypeFlags); + const constraintTypes = constraint.flags & TypeFlags.Union ? (constraint as UnionType).types + : [constraint]; + let allTypeFlags: TypeFlags = reduceLeft( + constraintTypes, + (flags, t) => flags | t.flags, + 0 as TypeFlags, + ); // If the constraint contains `string`, we don't need to look for a more preferred type if (!(allTypeFlags & TypeFlags.String)) { const str = (source as StringLiteralType).value; // If the type contains `number` or a number literal and the string isn't a valid number, exclude numbers - if (allTypeFlags & TypeFlags.NumberLike && !isValidNumberString(str, /*roundTripOnly*/ true)) { + if ( + allTypeFlags & TypeFlags.NumberLike + && !isValidNumberString(str, /*roundTripOnly*/ true) + ) { allTypeFlags &= ~TypeFlags.NumberLike; } // If the type contains `bigint` or a bigint literal and the string isn't a valid bigint, exclude bigints - if (allTypeFlags & TypeFlags.BigIntLike && !isValidBigIntString(str, /*roundTripOnly*/ true)) { + if ( + allTypeFlags & TypeFlags.BigIntLike + && !isValidBigIntString(str, /*roundTripOnly*/ true) + ) { allTypeFlags &= ~TypeFlags.BigIntLike; } // for each type in the constraint, find the highest priority matching type - const matchingType = reduceLeft(constraintTypes, (left, right) => - !(right.flags & allTypeFlags) ? left : - left.flags & TypeFlags.String ? left : right.flags & TypeFlags.String ? source : - left.flags & TypeFlags.TemplateLiteral ? left : right.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, right as TemplateLiteralType) ? source : - left.flags & TypeFlags.StringMapping ? left : right.flags & TypeFlags.StringMapping && str === applyStringMapping(right.symbol, str) ? source : - left.flags & TypeFlags.StringLiteral ? left : right.flags & TypeFlags.StringLiteral && (right as StringLiteralType).value === str ? right : - left.flags & TypeFlags.Number ? left : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) : - left.flags & TypeFlags.Enum ? left : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) : - left.flags & TypeFlags.NumberLiteral ? left : right.flags & TypeFlags.NumberLiteral && (right as NumberLiteralType).value === +str ? right : - left.flags & TypeFlags.BigInt ? left : right.flags & TypeFlags.BigInt ? parseBigIntLiteralType(str) : - left.flags & TypeFlags.BigIntLiteral ? left : right.flags & TypeFlags.BigIntLiteral && pseudoBigIntToString((right as BigIntLiteralType).value) === str ? right : - left.flags & TypeFlags.Boolean ? left : right.flags & TypeFlags.Boolean ? str === "true" ? trueType : str === "false" ? falseType : booleanType : - left.flags & TypeFlags.BooleanLiteral ? left : right.flags & TypeFlags.BooleanLiteral && (right as IntrinsicType).intrinsicName === str ? right : - left.flags & TypeFlags.Undefined ? left : right.flags & TypeFlags.Undefined && (right as IntrinsicType).intrinsicName === str ? right : - left.flags & TypeFlags.Null ? left : right.flags & TypeFlags.Null && (right as IntrinsicType).intrinsicName === str ? right : - left, - neverType as Type); + const matchingType = reduceLeft( + constraintTypes, + (left, right) => + !(right.flags & allTypeFlags) ? left + : left.flags & TypeFlags.String ? left + : right.flags & TypeFlags.String ? source + : left.flags & TypeFlags.TemplateLiteral ? left + : right.flags & TypeFlags.TemplateLiteral + && isTypeMatchedByTemplateLiteralType( + source, + right as TemplateLiteralType, + ) ? source + : left.flags & TypeFlags.StringMapping ? left + : right.flags & TypeFlags.StringMapping + && str === applyStringMapping(right.symbol, str) ? source + : left.flags & TypeFlags.StringLiteral ? left + : right.flags & TypeFlags.StringLiteral + && (right as StringLiteralType).value === str ? right + : left.flags & TypeFlags.Number ? left + : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) + : left.flags & TypeFlags.Enum ? left + : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) + : left.flags & TypeFlags.NumberLiteral ? left + : right.flags & TypeFlags.NumberLiteral + && (right as NumberLiteralType).value === +str ? right + : left.flags & TypeFlags.BigInt ? left + : right.flags & TypeFlags.BigInt ? parseBigIntLiteralType(str) + : left.flags & TypeFlags.BigIntLiteral ? left + : right.flags & TypeFlags.BigIntLiteral + && pseudoBigIntToString((right as BigIntLiteralType).value) === str + ? right + : left.flags & TypeFlags.Boolean ? left + : right.flags & TypeFlags.Boolean + ? str === "true" ? trueType : str === "false" ? falseType : booleanType + : left.flags & TypeFlags.BooleanLiteral ? left + : right.flags & TypeFlags.BooleanLiteral + && (right as IntrinsicType).intrinsicName === str ? right + : left.flags & TypeFlags.Undefined ? left + : right.flags & TypeFlags.Undefined + && (right as IntrinsicType).intrinsicName === str ? right + : left.flags & TypeFlags.Null ? left + : right.flags & TypeFlags.Null + && (right as IntrinsicType).intrinsicName === str ? right + : left, + neverType as Type, + ); if (!(matchingType.flags & TypeFlags.Never)) { inferFromTypes(matchingType, target); @@ -25035,10 +32782,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function inferFromObjectTypes(source: Type, target: Type) { - if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( - (source as TypeReference).target === (target as TypeReference).target || isArrayType(source) && isArrayType(target))) { + if ( + getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( + (source as TypeReference).target === (target as TypeReference).target + || isArrayType(source) && isArrayType(target) + ) + ) { // If source and target are references to the same generic type, infer from type arguments - inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target)); + inferFromTypeArguments( + getTypeArguments(source as TypeReference), + getTypeArguments(target as TypeReference), + getVariances((source as TypeReference).target), + ); return; } if (isGenericMappedType(source) && isGenericMappedType(target)) { @@ -25072,18 +32827,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return; } - const startLength = isTupleType(source) ? Math.min(source.target.fixedLength, target.target.fixedLength) : 0; - const endLength = Math.min(isTupleType(source) ? getEndElementCount(source.target, ElementFlags.Fixed) : 0, - target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) : 0); + const startLength = isTupleType(source) + ? Math.min(source.target.fixedLength, target.target.fixedLength) : 0; + const endLength = Math.min( + isTupleType(source) ? getEndElementCount(source.target, ElementFlags.Fixed) : 0, + target.target.hasRestElement ? getEndElementCount(target.target, ElementFlags.Fixed) : 0, + ); // Infer between starting fixed elements. for (let i = 0; i < startLength; i++) { inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); } - if (!isTupleType(source) || sourceArity - startLength - endLength === 1 && source.target.elementFlags[startLength] & ElementFlags.Rest) { + if ( + !isTupleType(source) + || sourceArity - startLength - endLength === 1 + && source.target.elementFlags[startLength] & ElementFlags.Rest + ) { // Single rest element remains in source, infer from that to every element in target const restType = getTypeArguments(source)[startLength]; for (let i = startLength; i < targetArity - endLength; i++) { - inferFromTypes(elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, elementTypes[i]); + inferFromTypes( + elementFlags[i] & ElementFlags.Variadic ? createArrayType(restType) : restType, + elementTypes[i], + ); } } else { @@ -25094,34 +32859,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetInfo = getInferenceInfoForType(elementTypes[startLength]); if (targetInfo && targetInfo.impliedArity !== undefined) { // Infer slices from source based on implied arity of T. - inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]); - inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); + inferFromTypes( + sliceTupleType( + source, + startLength, + endLength + sourceArity - targetInfo.impliedArity, + ), + elementTypes[startLength], + ); + inferFromTypes( + sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), + elementTypes[startLength + 1], + ); } } - else if (elementFlags[startLength] & ElementFlags.Variadic && elementFlags[startLength + 1] & ElementFlags.Rest) { + else if ( + elementFlags[startLength] & ElementFlags.Variadic + && elementFlags[startLength + 1] & ElementFlags.Rest + ) { // Middle of target is [...T, ...rest] and source is tuple type // if T is constrained by a fixed-size tuple we might be able to use its arity to infer T const param = getInferenceInfoForType(elementTypes[startLength])?.typeParameter; const constraint = param && getBaseConstraintOfType(param); if (constraint && isTupleType(constraint) && !constraint.target.hasRestElement) { const impliedArity = constraint.target.fixedLength; - inferFromTypes(sliceTupleType(source, startLength, sourceArity - (startLength + impliedArity)), elementTypes[startLength]); - inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength + impliedArity, endLength)!, elementTypes[startLength + 1]); + inferFromTypes( + sliceTupleType( + source, + startLength, + sourceArity - (startLength + impliedArity), + ), + elementTypes[startLength], + ); + inferFromTypes( + getElementTypeOfSliceOfTupleType( + source, + startLength + impliedArity, + endLength, + )!, + elementTypes[startLength + 1], + ); } } - else if (elementFlags[startLength] & ElementFlags.Rest && elementFlags[startLength + 1] & ElementFlags.Variadic) { + else if ( + elementFlags[startLength] & ElementFlags.Rest + && elementFlags[startLength + 1] & ElementFlags.Variadic + ) { // Middle of target is [...rest, ...T] and source is tuple type // if T is constrained by a fixed-size tuple we might be able to use its arity to infer T const param = getInferenceInfoForType(elementTypes[startLength + 1])?.typeParameter; const constraint = param && getBaseConstraintOfType(param); if (constraint && isTupleType(constraint) && !constraint.target.hasRestElement) { const impliedArity = constraint.target.fixedLength; - const endIndex = sourceArity - getEndElementCount(target.target, ElementFlags.Fixed); + const endIndex = sourceArity + - getEndElementCount(target.target, ElementFlags.Fixed); const startIndex = endIndex - impliedArity; - const trailingSlice = createTupleType(getTypeArguments(source).slice(startIndex, endIndex), source.target.elementFlags.slice(startIndex, endIndex), - /*readonly*/ false, source.target.labeledElementDeclarations && source.target.labeledElementDeclarations.slice(startIndex, endIndex)); - - inferFromTypes(getElementTypeOfSliceOfTupleType(source, startLength, endLength + impliedArity)!, elementTypes[startLength]); + const trailingSlice = createTupleType( + getTypeArguments(source).slice(startIndex, endIndex), + source.target.elementFlags.slice(startIndex, endIndex), + /*readonly*/ false, + source.target.labeledElementDeclarations + && source.target.labeledElementDeclarations.slice(startIndex, endIndex), + ); + + inferFromTypes( + getElementTypeOfSliceOfTupleType( + source, + startLength, + endLength + impliedArity, + )!, + elementTypes[startLength], + ); inferFromTypes(trailingSlice, elementTypes[startLength + 1]); } } @@ -25129,9 +32937,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Variadic) { // Middle of target is exactly one variadic element. Infer the slice between the fixed parts in the source. // If target ends in optional element(s), make a lower priority a speculative inference. - const endsInOptional = target.target.elementFlags[targetArity - 1] & ElementFlags.Optional; + const endsInOptional = target.target.elementFlags[targetArity - 1] + & ElementFlags.Optional; const sourceSlice = sliceTupleType(source, startLength, endLength); - inferWithPriority(sourceSlice, elementTypes[startLength], endsInOptional ? InferencePriority.SpeculativeTuple : 0); + inferWithPriority( + sourceSlice, + elementTypes[startLength], + endsInOptional ? InferencePriority.SpeculativeTuple : 0, + ); } else if (middleLength === 1 && elementFlags[startLength] & ElementFlags.Rest) { // Middle of target is exactly one rest element. If middle of source is not empty, infer union of middle element types. @@ -25143,7 +32956,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Infer between ending fixed elements for (let i = 0; i < endLength; i++) { - inferFromTypes(getTypeArguments(source)[sourceArity - i - 1], elementTypes[targetArity - i - 1]); + inferFromTypes( + getTypeArguments(source)[sourceArity - i - 1], + elementTypes[targetArity - i - 1], + ); } return; } @@ -25176,7 +32992,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetLen = targetSignatures.length; const len = sourceLen < targetLen ? sourceLen : targetLen; for (let i = 0; i < len; i++) { - inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i])); + inferFromSignature( + getBaseSignature(sourceSignatures[sourceLen - len + i]), + getErasedSignature(targetSignatures[targetLen - len + i]), + ); } } @@ -25185,7 +33004,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const saveBivariant = bivariant; const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; // Once we descend into a bivariant signature we remain bivariant for all nested inferences - bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor; + bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature + || kind === SyntaxKind.Constructor; applyToParameterTypes(source, target, inferFromContravariantTypesIfStrictFunctionTypes); bivariant = saveBivariant; } @@ -25194,15 +33014,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function inferFromIndexTypes(source: Type, target: Type) { // Inferences across mapped type index signatures are pretty much the same a inferences to homomorphic variables - const priority = (getObjectFlags(source) & getObjectFlags(target) & ObjectFlags.Mapped) ? InferencePriority.HomomorphicMappedType : 0; + const priority = (getObjectFlags(source) & getObjectFlags(target) & ObjectFlags.Mapped) + ? InferencePriority.HomomorphicMappedType : 0; const indexInfos = getIndexInfosOfType(target); if (isObjectTypeWithInferableIndex(source)) { for (const targetInfo of indexInfos) { const propTypes: Type[] = []; for (const prop of getPropertiesOfType(source)) { - if (isApplicableIndexType(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), targetInfo.keyType)) { + if ( + isApplicableIndexType( + getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), + targetInfo.keyType, + ) + ) { const propType = getTypeOfSymbol(prop); - propTypes.push(prop.flags & SymbolFlags.Optional ? removeMissingOrUndefinedType(propType) : propType); + propTypes.push( + prop.flags & SymbolFlags.Optional ? removeMissingOrUndefinedType(propType) : propType, + ); } } for (const info of getIndexInfosOfType(source)) { @@ -25225,18 +33053,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTypeOrBaseIdenticalTo(s: Type, t: Type) { - return t === missingType ? s === t : - (isTypeIdenticalTo(s, t) || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral)); + return t === missingType ? s === t + : (isTypeIdenticalTo(s, t) + || !!(t.flags & TypeFlags.String && s.flags & TypeFlags.StringLiteral + || t.flags & TypeFlags.Number && s.flags & TypeFlags.NumberLiteral)); } function isTypeCloselyMatchedBy(s: Type, t: Type) { - return !!(s.flags & TypeFlags.Object && t.flags & TypeFlags.Object && s.symbol && s.symbol === t.symbol || - s.aliasSymbol && s.aliasTypeArguments && s.aliasSymbol === t.aliasSymbol); + return !!(s.flags & TypeFlags.Object && t.flags & TypeFlags.Object && s.symbol && s.symbol === t.symbol + || s.aliasSymbol && s.aliasTypeArguments && s.aliasSymbol === t.aliasSymbol); } function hasPrimitiveConstraint(type: TypeParameter): boolean { const constraint = getConstraintOfTypeParameter(type); - return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); + return !!constraint + && maybeTypeOfKind( + constraint.flags & TypeFlags.Conditional + ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, + TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping, + ); } function isObjectLiteralType(type: Type) { @@ -25259,7 +33094,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getContravariantInference(inference: InferenceInfo) { - return inference.priority! & InferencePriority.PriorityImpliesCombination ? getIntersectionType(inference.contraCandidates!) : getCommonSubtype(inference.contraCandidates!); + return inference.priority! & InferencePriority.PriorityImpliesCombination + ? getIntersectionType(inference.contraCandidates!) : getCommonSubtype(inference.contraCandidates!); } function getCovariantInference(inference: InferenceInfo, signature: Signature) { @@ -25269,17 +33105,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // all inferences were made to top-level occurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and // the type parameter was fixed during inference or does not occur at top-level in the return type. - const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter) || isConstTypeVariable(inference.typeParameter); - const widenLiteralTypes = !primitiveConstraint && inference.topLevel && - (inference.isFixed || !isTypeParameterAtTopLevelInReturnType(signature, inference.typeParameter)); - const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) : - widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : - candidates; + const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter) + || isConstTypeVariable(inference.typeParameter); + const widenLiteralTypes = !primitiveConstraint && inference.topLevel + && (inference.isFixed || !isTypeParameterAtTopLevelInReturnType(signature, inference.typeParameter)); + const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) + : widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) + : candidates; // If all inferences were made from a position that implies a combined result, infer a union type. // Otherwise, infer a common supertype. - const unwidenedType = inference.priority! & InferencePriority.PriorityImpliesCombination ? - getUnionType(baseCandidates, UnionReduction.Subtype) : - getCommonSupertype(baseCandidates); + const unwidenedType = inference.priority! & InferencePriority.PriorityImpliesCombination + ? getUnionType(baseCandidates, UnionReduction.Subtype) + : getCommonSupertype(baseCandidates); return getWidenedType(unwidenedType); } @@ -25289,19 +33126,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let inferredType: Type | undefined; let fallbackType: Type | undefined; if (context.signature) { - const inferredCovariantType = inference.candidates ? getCovariantInference(inference, context.signature) : undefined; - const inferredContravariantType = inference.contraCandidates ? getContravariantInference(inference) : undefined; + const inferredCovariantType = inference.candidates ? getCovariantInference(inference, context.signature) + : undefined; + const inferredContravariantType = inference.contraCandidates ? getContravariantInference(inference) + : undefined; if (inferredCovariantType || inferredContravariantType) { // If we have both co- and contra-variant inferences, we prefer the co-variant inference if it is not 'never', // all co-variant inferences are subtypes of it (i.e. it isn't one of a conflicting set of candidates), it is // a subtype of some contra-variant inference, and no other type parameter is constrained to this type parameter // and has inferences that would conflict. Otherwise, we prefer the contra-variant inference. - const preferCovariantType = inferredCovariantType && (!inferredContravariantType || - !(inferredCovariantType.flags & TypeFlags.Never) && - some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) && - every(context.inferences, other => - other !== inference && getConstraintOfTypeParameter(other.typeParameter) !== inference.typeParameter || - every(other.candidates, t => isTypeSubtypeOf(t, inferredCovariantType)))); + const preferCovariantType = inferredCovariantType && (!inferredContravariantType + || !(inferredCovariantType.flags & TypeFlags.Never) + && some(inference.contraCandidates, t => isTypeSubtypeOf(inferredCovariantType, t)) + && every( + context.inferences, + other => + other !== inference + && getConstraintOfTypeParameter(other.typeParameter) !== inference.typeParameter + || every(other.candidates, t => isTypeSubtypeOf(t, inferredCovariantType)), + )); inferredType = preferCovariantType ? inferredCovariantType : inferredContravariantType; fallbackType = preferCovariantType ? inferredContravariantType : inferredCovariantType; } @@ -25319,7 +33162,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (defaultType) { // Instantiate the default type. Any forward reference to a type // parameter should be instantiated to the empty object type. - inferredType = instantiateType(defaultType, mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper)); + inferredType = instantiateType( + defaultType, + mergeTypeMappers(createBackreferenceMapper(context, index), context.nonFixingMapper), + ); } } } @@ -25327,14 +33173,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferredType = getTypeFromInference(inference); } - inference.inferredType = inferredType || getDefaultTypeArgumentType(!!(context.flags & InferenceFlags.AnyDefault)); + inference.inferredType = inferredType + || getDefaultTypeArgumentType(!!(context.flags & InferenceFlags.AnyDefault)); const constraint = getConstraintOfTypeParameter(inference.typeParameter); if (constraint) { const instantiatedConstraint = instantiateType(constraint, context.nonFixingMapper); - if (!inferredType || inferredType === wildcardType || !context.compareTypes(inferredType, getTypeWithThisArgument(instantiatedConstraint, inferredType))) { + if ( + !inferredType || inferredType === wildcardType + || !context.compareTypes( + inferredType, + getTypeWithThisArgument(instantiatedConstraint, inferredType), + ) + ) { // If the fallback type satisfies the constraint, we pick it. Otherwise, we pick the constraint. - inference.inferredType = fallbackType && context.compareTypes(fallbackType, getTypeWithThisArgument(instantiatedConstraint, fallbackType)) ? fallbackType : instantiatedConstraint; + inference.inferredType = fallbackType + && context.compareTypes( + fallbackType, + getTypeWithThisArgument(instantiatedConstraint, fallbackType), + ) ? fallbackType : instantiatedConstraint; } } } @@ -25360,25 +33217,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (node.escapedText) { case "document": case "console": - return Diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_include_dom; + return Diagnostics + .Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_include_dom; case "$": return compilerOptions.types - ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery_and_then_add_jquery_to_the_types_field_in_your_tsconfig - : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery; + ? Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery_and_then_add_jquery_to_the_types_field_in_your_tsconfig + : Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slashjquery; case "describe": case "suite": case "it": case "test": return compilerOptions.types - ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha_and_then_add_jest_or_mocha_to_the_types_field_in_your_tsconfig - : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha; + ? Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha_and_then_add_jest_or_mocha_to_the_types_field_in_your_tsconfig + : Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_save_dev_types_Slashjest_or_npm_i_save_dev_types_Slashmocha; case "process": case "require": case "Buffer": case "module": return compilerOptions.types - ? Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode_and_then_add_node_to_the_types_field_in_your_tsconfig - : Diagnostics.Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode; + ? Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode_and_then_add_node_to_the_types_field_in_your_tsconfig + : Diagnostics + .Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_save_dev_types_Slashnode; case "Map": case "Set": case "Promise": @@ -25397,7 +33261,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case "Reflect": case "BigInt64Array": case "BigUint64Array": - return Diagnostics.Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_1_or_later; + return Diagnostics + .Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_1_or_later; case "await": if (isCallExpression(node.parent)) { return Diagnostics.Cannot_find_name_0_Did_you_mean_to_write_this_in_an_async_function; @@ -25405,7 +33270,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // falls through default: if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { - return Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer; + return Diagnostics + .No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer; } else { return Diagnostics.Cannot_find_name_0; @@ -25416,40 +33282,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getResolvedSymbol(node: Identifier): Symbol { const links = getNodeLinks(node); if (!links.resolvedSymbol) { - links.resolvedSymbol = !nodeIsMissing(node) && - resolveName( - node, - node.escapedText, - SymbolFlags.Value | SymbolFlags.ExportValue, - getCannotFindNameDiagnosticForName(node), - node, - !isWriteOnlyAccess(node), - /*excludeGlobals*/ false) || unknownSymbol; + links.resolvedSymbol = !nodeIsMissing(node) + && resolveName( + node, + node.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue, + getCannotFindNameDiagnosticForName(node), + node, + !isWriteOnlyAccess(node), + /*excludeGlobals*/ false, + ) || unknownSymbol; } return links.resolvedSymbol; } function isInAmbientOrTypeNode(node: Node): boolean { - return !!(node.flags & NodeFlags.Ambient || findAncestor(node, n => isInterfaceDeclaration(n) || isTypeAliasDeclaration(n) || isTypeLiteralNode(n))); + return !!(node.flags & NodeFlags.Ambient + || findAncestor(node, n => isInterfaceDeclaration(n) || isTypeAliasDeclaration(n) || isTypeLiteralNode(n))); } // Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers // separated by dots). The key consists of the id of the symbol referenced by the // leftmost identifier followed by zero or more property names separated by dots. // The result is undefined if the reference isn't a dotted name. - function getFlowCacheKey(node: Node, declaredType: Type, initialType: Type, flowContainer: Node | undefined): string | undefined { + function getFlowCacheKey( + node: Node, + declaredType: Type, + initialType: Type, + flowContainer: Node | undefined, + ): string | undefined { switch (node.kind) { case SyntaxKind.Identifier: if (!isThisInTypeQuery(node)) { const symbol = getResolvedSymbol(node as Identifier); - return symbol !== unknownSymbol ? `${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}|${getSymbolId(symbol)}` : undefined; + return symbol !== unknownSymbol + ? `${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${ + getTypeId(initialType) + }|${getSymbolId(symbol)}` : undefined; } // falls through case SyntaxKind.ThisKeyword: - return `0|${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}`; + return `0|${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${ + getTypeId(initialType) + }`; case SyntaxKind.NonNullExpression: case SyntaxKind.ParenthesizedExpression: - return getFlowCacheKey((node as NonNullExpression | ParenthesizedExpression).expression, declaredType, initialType, flowContainer); + return getFlowCacheKey( + (node as NonNullExpression | ParenthesizedExpression).expression, + declaredType, + initialType, + flowContainer, + ); case SyntaxKind.QualifiedName: const left = getFlowCacheKey((node as QualifiedName).left, declaredType, initialType, flowContainer); return left && left + "." + (node as QualifiedName).right.escapedText; @@ -25457,7 +33340,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ElementAccessExpression: const propName = getAccessedPropertyName(node as AccessExpression); if (propName !== undefined) { - const key = getFlowCacheKey((node as AccessExpression).expression, declaredType, initialType, flowContainer); + const key = getFlowCacheKey( + (node as AccessExpression).expression, + declaredType, + initialType, + flowContainer, + ); return key && key + "." + propName; } break; @@ -25479,8 +33367,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NonNullExpression: return isMatchingReference(source, (target as NonNullExpression | ParenthesizedExpression).expression); case SyntaxKind.BinaryExpression: - return (isAssignmentExpression(target) && isMatchingReference(source, target.left)) || - (isBinaryExpression(target) && target.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source, target.right)); + return (isAssignmentExpression(target) && isMatchingReference(source, target.left)) + || (isBinaryExpression(target) && target.operatorToken.kind === SyntaxKind.CommaToken + && isMatchingReference(source, target.right)); } switch (source.kind) { case SyntaxKind.MetaProperty: @@ -25489,11 +33378,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { && (source as MetaProperty).name.escapedText === (target as MetaProperty).name.escapedText; case SyntaxKind.Identifier: case SyntaxKind.PrivateIdentifier: - return isThisInTypeQuery(source) ? - target.kind === SyntaxKind.ThisKeyword : - target.kind === SyntaxKind.Identifier && getResolvedSymbol(source as Identifier) === getResolvedSymbol(target as Identifier) || - (isVariableDeclaration(target) || isBindingElement(target)) && - getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) === getSymbolOfDeclaration(target); + return isThisInTypeQuery(source) + ? target.kind === SyntaxKind.ThisKeyword + : target.kind === SyntaxKind.Identifier + && getResolvedSymbol(source as Identifier) === getResolvedSymbol(target as Identifier) + || (isVariableDeclaration(target) || isBindingElement(target)) + && getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(source as Identifier)) + === getSymbolOfDeclaration(target); case SyntaxKind.ThisKeyword: return target.kind === SyntaxKind.ThisKeyword; case SyntaxKind.SuperKeyword: @@ -25505,19 +33396,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ElementAccessExpression: const sourcePropertyName = getAccessedPropertyName(source as AccessExpression); const targetPropertyName = isAccessExpression(target) ? getAccessedPropertyName(target) : undefined; - return sourcePropertyName !== undefined && targetPropertyName !== undefined && targetPropertyName === sourcePropertyName && - isMatchingReference((source as AccessExpression).expression, (target as AccessExpression).expression); + return sourcePropertyName !== undefined && targetPropertyName !== undefined + && targetPropertyName === sourcePropertyName + && isMatchingReference( + (source as AccessExpression).expression, + (target as AccessExpression).expression, + ); case SyntaxKind.QualifiedName: - return isAccessExpression(target) && - (source as QualifiedName).right.escapedText === getAccessedPropertyName(target) && - isMatchingReference((source as QualifiedName).left, target.expression); + return isAccessExpression(target) + && (source as QualifiedName).right.escapedText === getAccessedPropertyName(target) + && isMatchingReference((source as QualifiedName).left, target.expression); case SyntaxKind.BinaryExpression: - return (isBinaryExpression(source) && source.operatorToken.kind === SyntaxKind.CommaToken && isMatchingReference(source.right, target)); + return (isBinaryExpression(source) && source.operatorToken.kind === SyntaxKind.CommaToken + && isMatchingReference(source.right, target)); } return false; } - function getAccessedPropertyName(access: AccessExpression | BindingElement | ParameterDeclaration): __String | undefined { + function getAccessedPropertyName( + access: AccessExpression | BindingElement | ParameterDeclaration, + ): __String | undefined { if (isPropertyAccessExpression(access)) { return access.name.escapedText; } @@ -25535,13 +33433,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function tryGetNameFromType(type: Type) { - return type.flags & TypeFlags.UniqueESSymbol ? (type as UniqueESSymbolType).escapedName : - type.flags & TypeFlags.StringOrNumberLiteral ? escapeLeadingUnderscores("" + (type as StringLiteralType | NumberLiteralType).value) : undefined; + return type.flags & TypeFlags.UniqueESSymbol ? (type as UniqueESSymbolType).escapedName + : type.flags & TypeFlags.StringOrNumberLiteral + ? escapeLeadingUnderscores("" + (type as StringLiteralType | NumberLiteralType).value) : undefined; } function tryGetElementAccessExpressionName(node: ElementAccessExpression) { - return isStringOrNumericLiteralLike(node.argumentExpression) ? escapeLeadingUnderscores(node.argumentExpression.text) : - isEntityNameExpression(node.argumentExpression) ? tryGetNameFromEntityNameExpression(node.argumentExpression) : undefined; + return isStringOrNumericLiteralLike(node.argumentExpression) + ? escapeLeadingUnderscores(node.argumentExpression.text) + : isEntityNameExpression(node.argumentExpression) + ? tryGetNameFromEntityNameExpression(node.argumentExpression) : undefined; } function tryGetNameFromEntityNameExpression(node: EntityNameOrEntityNameExpression) { @@ -25597,8 +33498,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // NOTE: cast to TransientSymbol should be safe because only TransientSymbols can have CheckFlags.SyntheticProperty if ((prop as TransientSymbol).links.isDiscriminantProperty === undefined) { (prop as TransientSymbol).links.isDiscriminantProperty = - ((prop as TransientSymbol).links.checkFlags & CheckFlags.Discriminant) === CheckFlags.Discriminant && - !isGenericType(getTypeOfSymbol(prop)); + ((prop as TransientSymbol).links.checkFlags & CheckFlags.Discriminant) + === CheckFlags.Discriminant + && !isGenericType(getTypeOfSymbol(prop)); } return !!(prop as TransientSymbol).links.isDiscriminantProperty; } @@ -25658,17 +33560,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getKeyPropertyName(unionType: UnionType): __String | undefined { const types = unionType.types; // We only construct maps for unions with many non-primitive constituents. - if (types.length < 10 || getObjectFlags(unionType) & ObjectFlags.PrimitiveUnion || - countWhere(types, t => !!(t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive))) < 10) { + if ( + types.length < 10 || getObjectFlags(unionType) & ObjectFlags.PrimitiveUnion + || countWhere(types, t => !!(t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive))) < 10 + ) { return undefined; } if (unionType.keyPropertyName === undefined) { // The candidate key property name is the name of the first property with a unit type in one of the // constituent types. - const keyPropertyName = forEach(types, t => - t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) ? - forEach(getPropertiesOfType(t), p => isUnitType(getTypeOfSymbol(p)) ? p.escapedName : undefined) : - undefined); + const keyPropertyName = forEach( + types, + t => t.flags & (TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) + ? forEach(getPropertiesOfType(t), p => isUnitType(getTypeOfSymbol(p)) ? p.escapedName : undefined) + : undefined, + ); const mapByKeyProperty = keyPropertyName && mapTypesByKeyProperty(types, keyPropertyName); unionType.keyPropertyName = mapByKeyProperty ? keyPropertyName : "" as __String; unionType.constituentMap = mapByKeyProperty; @@ -25691,8 +33597,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getMatchingUnionConstituentForObjectLiteral(unionType: UnionType, node: ObjectLiteralExpression) { const keyPropertyName = getKeyPropertyName(unionType); - const propNode = keyPropertyName && find(node.properties, p => p.symbol && p.kind === SyntaxKind.PropertyAssignment && - p.symbol.escapedName === keyPropertyName && isPossiblyDiscriminantValue(p.initializer)); + const propNode = keyPropertyName + && find(node.properties, p => + p.symbol && p.kind === SyntaxKind.PropertyAssignment + && p.symbol.escapedName === keyPropertyName && isPossiblyDiscriminantValue(p.initializer)); const propType = propNode && getContextFreeTypeOfExpression((propNode as PropertyAssignment).initializer); return propType && getConstituentTypeForKeyType(unionType, propType); } @@ -25709,8 +33617,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - if (expression.expression.kind === SyntaxKind.PropertyAccessExpression && - isOrContainsMatchingReference(reference, (expression.expression as PropertyAccessExpression).expression)) { + if ( + expression.expression.kind === SyntaxKind.PropertyAccessExpression + && isOrContainsMatchingReference(reference, (expression.expression as PropertyAccessExpression).expression) + ) { return true; } return false; @@ -25753,7 +33663,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getAssignmentReducedTypeWorker(declaredType: UnionType, assignedType: Type) { const filteredType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t)); // Ensure that we narrow to fresh types if the assignment is a fresh boolean literal type. - const reducedType = assignedType.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(assignedType) ? mapType(filteredType, getFreshTypeOfLiteralType) : filteredType; + const reducedType = assignedType.flags & TypeFlags.BooleanLiteral && isFreshLiteralType(assignedType) + ? mapType(filteredType, getFreshTypeOfLiteralType) : filteredType; // Our crude heuristic produces an invalid result in some cases: see GH#26130. // For now, when that happens, we give up and don't narrow at all. (This also // means we'll never narrow for erroneous assignments where the assigned type @@ -25765,8 +33676,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We do a quick check for a "bind" property before performing the more expensive subtype // check. This gives us a quicker out in the common case where an object type is not a function. const resolved = resolveStructuredTypeMembers(type); - return !!(resolved.callSignatures.length || resolved.constructSignatures.length || - resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType)); + return !!(resolved.callSignatures.length || resolved.constructSignatures.length + || resolved.members.get("bind" as __String) && isTypeSubtypeOf(type, globalFunctionType)); } function getTypeFacts(type: Type): TypeFacts { @@ -25779,42 +33690,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral)) { const isEmpty = flags & TypeFlags.StringLiteral && (type as StringLiteralType).value === ""; - return strictNullChecks ? - isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts : - isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; + return strictNullChecks + ? isEmpty ? TypeFacts.EmptyStringStrictFacts : TypeFacts.NonEmptyStringStrictFacts + : isEmpty ? TypeFacts.EmptyStringFacts : TypeFacts.NonEmptyStringFacts; } if (flags & (TypeFlags.Number | TypeFlags.Enum)) { return strictNullChecks ? TypeFacts.NumberStrictFacts : TypeFacts.NumberFacts; } if (flags & TypeFlags.NumberLiteral) { const isZero = (type as NumberLiteralType).value === 0; - return strictNullChecks ? - isZero ? TypeFacts.ZeroNumberStrictFacts : TypeFacts.NonZeroNumberStrictFacts : - isZero ? TypeFacts.ZeroNumberFacts : TypeFacts.NonZeroNumberFacts; + return strictNullChecks + ? isZero ? TypeFacts.ZeroNumberStrictFacts : TypeFacts.NonZeroNumberStrictFacts + : isZero ? TypeFacts.ZeroNumberFacts : TypeFacts.NonZeroNumberFacts; } if (flags & TypeFlags.BigInt) { return strictNullChecks ? TypeFacts.BigIntStrictFacts : TypeFacts.BigIntFacts; } if (flags & TypeFlags.BigIntLiteral) { const isZero = isZeroBigInt(type as BigIntLiteralType); - return strictNullChecks ? - isZero ? TypeFacts.ZeroBigIntStrictFacts : TypeFacts.NonZeroBigIntStrictFacts : - isZero ? TypeFacts.ZeroBigIntFacts : TypeFacts.NonZeroBigIntFacts; + return strictNullChecks + ? isZero ? TypeFacts.ZeroBigIntStrictFacts : TypeFacts.NonZeroBigIntStrictFacts + : isZero ? TypeFacts.ZeroBigIntFacts : TypeFacts.NonZeroBigIntFacts; } if (flags & TypeFlags.Boolean) { return strictNullChecks ? TypeFacts.BooleanStrictFacts : TypeFacts.BooleanFacts; } if (flags & TypeFlags.BooleanLike) { - return strictNullChecks ? - (type === falseType || type === regularFalseType) ? TypeFacts.FalseStrictFacts : TypeFacts.TrueStrictFacts : - (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; + return strictNullChecks + ? (type === falseType || type === regularFalseType) ? TypeFacts.FalseStrictFacts + : TypeFacts.TrueStrictFacts + : (type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts; } if (flags & TypeFlags.Object) { - return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) ? - strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts : - isFunctionObjectType(type as ObjectType) ? - strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts : - strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; + return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(type as ObjectType) + ? strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts + : isFunctionObjectType(type as ObjectType) + ? strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts + : strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; } if (flags & TypeFlags.Void) { return TypeFacts.VoidFacts; @@ -25869,16 +33781,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // unknown with the union {} | null | undefined (and reduces that accordingly), and it intersects remaining // instantiable types with {}, {} | null, or {} | undefined in order to remove null and/or undefined. function getAdjustedTypeWithFacts(type: Type, facts: TypeFacts) { - const reduced = recombineUnknownType(getTypeWithFacts(strictNullChecks && type.flags & TypeFlags.Unknown ? unknownUnionType : type, facts)); + const reduced = recombineUnknownType( + getTypeWithFacts(strictNullChecks && type.flags & TypeFlags.Unknown ? unknownUnionType : type, facts), + ); if (strictNullChecks) { switch (facts) { case TypeFacts.NEUndefined: - return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefined ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQNull && !maybeTypeOfKind(reduced, TypeFlags.Null) ? getUnionType([emptyObjectType, nullType]) : emptyObjectType]): t); + return mapType( + reduced, + t => getTypeFacts(t) & TypeFacts.EQUndefined + ? getIntersectionType([ + t, + getTypeFacts(t) & TypeFacts.EQNull && !maybeTypeOfKind(reduced, TypeFlags.Null) + ? getUnionType([emptyObjectType, nullType]) : emptyObjectType, + ]) : t, + ); case TypeFacts.NENull: - return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQNull ? getIntersectionType([t, getTypeFacts(t) & TypeFacts.EQUndefined && !maybeTypeOfKind(reduced, TypeFlags.Undefined) ? getUnionType([emptyObjectType, undefinedType]) : emptyObjectType]): t); + return mapType( + reduced, + t => getTypeFacts(t) & TypeFacts.EQNull + ? getIntersectionType([ + t, + getTypeFacts(t) & TypeFacts.EQUndefined + && !maybeTypeOfKind(reduced, TypeFlags.Undefined) + ? getUnionType([emptyObjectType, undefinedType]) : emptyObjectType, + ]) : t, + ); case TypeFacts.NEUndefinedOrNull: case TypeFacts.Truthy: - return mapType(reduced, t => getTypeFacts(t) & TypeFacts.EQUndefinedOrNull ? getGlobalNonNullableTypeInstantiation(t): t); + return mapType( + reduced, + t => getTypeFacts(t) & TypeFacts.EQUndefinedOrNull ? getGlobalNonNullableTypeInstantiation(t) + : t, + ); } } return reduced; @@ -25889,47 +33824,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTypeWithDefault(type: Type, defaultExpression: Expression) { - return defaultExpression ? - getUnionType([getNonUndefinedType(type), getTypeOfExpression(defaultExpression)]) : - type; + return defaultExpression + ? getUnionType([getNonUndefinedType(type), getTypeOfExpression(defaultExpression)]) + : type; } function getTypeOfDestructuredProperty(type: Type, name: PropertyName) { const nameType = getLiteralTypeFromPropertyName(name); if (!isTypeUsableAsPropertyName(nameType)) return errorType; const text = getPropertyNameFromType(nameType); - return getTypeOfPropertyOfType(type, text) || includeUndefinedInIndexSignature(getApplicableIndexInfoForName(type, text)?.type) || errorType; + return getTypeOfPropertyOfType(type, text) + || includeUndefinedInIndexSignature(getApplicableIndexInfoForName(type, text)?.type) || errorType; } function getTypeOfDestructuredArrayElement(type: Type, index: number) { - return everyType(type, isTupleLikeType) && getTupleElementType(type, index) || - includeUndefinedInIndexSignature(checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined)) || - errorType; + return everyType(type, isTupleLikeType) && getTupleElementType(type, index) + || includeUndefinedInIndexSignature( + checkIteratedTypeOrElementType( + IterationUse.Destructuring, + type, + undefinedType, + /*errorNode*/ undefined, + ), + ) + || errorType; } function includeUndefinedInIndexSignature(type: Type | undefined): Type | undefined { if (!type) return type; - return compilerOptions.noUncheckedIndexedAccess ? - getUnionType([type, missingType]) : - type; + return compilerOptions.noUncheckedIndexedAccess + ? getUnionType([type, missingType]) + : type; } function getTypeOfDestructuredSpreadExpression(type: Type) { - return createArrayType(checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined) || errorType); + return createArrayType( + checkIteratedTypeOrElementType(IterationUse.Destructuring, type, undefinedType, /*errorNode*/ undefined) + || errorType, + ); } function getAssignedTypeOfBinaryExpression(node: BinaryExpression): Type { const isDestructuringDefaultAssignment = - node.parent.kind === SyntaxKind.ArrayLiteralExpression && isDestructuringAssignmentTarget(node.parent) || - node.parent.kind === SyntaxKind.PropertyAssignment && isDestructuringAssignmentTarget(node.parent.parent); - return isDestructuringDefaultAssignment ? - getTypeWithDefault(getAssignedType(node), node.right) : - getTypeOfExpression(node.right); + node.parent.kind === SyntaxKind.ArrayLiteralExpression && isDestructuringAssignmentTarget(node.parent) + || node.parent.kind === SyntaxKind.PropertyAssignment + && isDestructuringAssignmentTarget(node.parent.parent); + return isDestructuringDefaultAssignment + ? getTypeWithDefault(getAssignedType(node), node.right) + : getTypeOfExpression(node.right); } function isDestructuringAssignmentTarget(parent: Node) { - return parent.parent.kind === SyntaxKind.BinaryExpression && (parent.parent as BinaryExpression).left === parent || - parent.parent.kind === SyntaxKind.ForOfStatement && (parent.parent as ForOfStatement).initializer === parent; + return parent.parent.kind === SyntaxKind.BinaryExpression && (parent.parent as BinaryExpression).left === parent + || parent.parent.kind === SyntaxKind.ForOfStatement + && (parent.parent as ForOfStatement).initializer === parent; } function getAssignedTypeOfArrayLiteralElement(node: ArrayLiteralExpression, element: Expression): Type { @@ -25974,11 +33922,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getInitialTypeOfBindingElement(node: BindingElement): Type { const pattern = node.parent; const parentType = getInitialType(pattern.parent as VariableDeclaration | BindingElement); - const type = pattern.kind === SyntaxKind.ObjectBindingPattern ? - getTypeOfDestructuredProperty(parentType, node.propertyName || node.name as Identifier) : - !node.dotDotDotToken ? - getTypeOfDestructuredArrayElement(parentType, pattern.elements.indexOf(node)) : - getTypeOfDestructuredSpreadExpression(parentType); + const type = pattern.kind === SyntaxKind.ObjectBindingPattern + ? getTypeOfDestructuredProperty(parentType, node.propertyName || node.name as Identifier) + : !node.dotDotDotToken + ? getTypeOfDestructuredArrayElement(parentType, pattern.elements.indexOf(node)) + : getTypeOfDestructuredSpreadExpression(parentType); return getTypeWithDefault(type, node.initializer!); } @@ -26004,16 +33952,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getInitialType(node: VariableDeclaration | BindingElement) { - return node.kind === SyntaxKind.VariableDeclaration ? - getInitialTypeOfVariableDeclaration(node) : - getInitialTypeOfBindingElement(node); + return node.kind === SyntaxKind.VariableDeclaration + ? getInitialTypeOfVariableDeclaration(node) + : getInitialTypeOfBindingElement(node); } function isEmptyArrayAssignment(node: VariableDeclaration | BindingElement | Expression) { - return node.kind === SyntaxKind.VariableDeclaration && (node as VariableDeclaration).initializer && - isEmptyArrayLiteral((node as VariableDeclaration).initializer!) || - node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression && - isEmptyArrayLiteral((node.parent as BinaryExpression).right); + return node.kind === SyntaxKind.VariableDeclaration && (node as VariableDeclaration).initializer + && isEmptyArrayLiteral((node as VariableDeclaration).initializer!) + || node.kind !== SyntaxKind.BindingElement && node.parent.kind === SyntaxKind.BinaryExpression + && isEmptyArrayLiteral((node.parent as BinaryExpression).right); } function getReferenceCandidate(node: Expression): Expression { @@ -26036,10 +33984,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getReferenceRoot(node: Node): Node { const { parent } = node; - return parent.kind === SyntaxKind.ParenthesizedExpression || - parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && (parent as BinaryExpression).left === node || - parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken && (parent as BinaryExpression).right === node ? - getReferenceRoot(parent) : node; + return parent.kind === SyntaxKind.ParenthesizedExpression + || parent.kind === SyntaxKind.BinaryExpression + && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + && (parent as BinaryExpression).left === node + || parent.kind === SyntaxKind.BinaryExpression + && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken + && (parent as BinaryExpression).right === node + ? getReferenceRoot(parent) : node; } function getTypeOfSwitchClause(clause: CaseClause | DefaultClause) { @@ -26063,23 +34015,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Get the type names from all cases in a switch on `typeof`. The default clause and/or duplicate type names are // represented as undefined. Return undefined if one or more case clause expressions are not string literals. function getSwitchClauseTypeOfWitnesses(switchStatement: SwitchStatement): (string | undefined)[] | undefined { - if (some(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.CaseClause && !isStringLiteralLike(clause.expression))) { + if ( + some( + switchStatement.caseBlock.clauses, + clause => clause.kind === SyntaxKind.CaseClause && !isStringLiteralLike(clause.expression), + ) + ) { return undefined; } const witnesses: (string | undefined)[] = []; for (const clause of switchStatement.caseBlock.clauses) { - const text = clause.kind === SyntaxKind.CaseClause ? (clause.expression as StringLiteralLike).text : undefined; + const text = clause.kind === SyntaxKind.CaseClause ? (clause.expression as StringLiteralLike).text + : undefined; witnesses.push(text && !contains(witnesses, text) ? text : undefined); } return witnesses; } function eachTypeContainedIn(source: Type, types: Type[]) { - return source.flags & TypeFlags.Union ? !forEach((source as UnionType).types, t => !contains(types, t)) : contains(types, source); + return source.flags & TypeFlags.Union ? !forEach((source as UnionType).types, t => !contains(types, t)) + : contains(types, source); } function isTypeSubsetOf(source: Type, target: Type) { - return !!(source === target || source.flags & TypeFlags.Never || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, target as UnionType)); + return !!(source === target || source.flags & TypeFlags.Never + || target.flags & TypeFlags.Union && isTypeSubsetOfUnion(source, target as UnionType)); } function isTypeSubsetOfUnion(source: Type, target: UnionType) { @@ -26139,7 +34099,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // filtering could remove intersections so `ContainsIntersections` might be forwarded "incorrectly" // it is purely an optimization hint so there is no harm in accidentally forwarding it - return getUnionTypeFromSortedList(filtered, (type as UnionType).objectFlags & (ObjectFlags.PrimitiveUnion | ObjectFlags.ContainsIntersections), /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin); + return getUnionTypeFromSortedList( + filtered, + (type as UnionType).objectFlags & (ObjectFlags.PrimitiveUnion | ObjectFlags.ContainsIntersections), + /*aliasSymbol*/ undefined, + /*aliasTypeArguments*/ undefined, + newOrigin, + ); } return type.flags & TypeFlags.Never || f(type) ? type : neverType; } @@ -26165,7 +34131,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return mapper(type); } const origin = (type as UnionType).origin; - const types = origin && origin.flags & TypeFlags.Union ? (origin as UnionType).types : (type as UnionType).types; + const types = origin && origin.flags & TypeFlags.Union ? (origin as UnionType).types + : (type as UnionType).types; let mappedTypes: Type[] | undefined; let changed = false; for (const t of types) { @@ -26180,13 +34147,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - return changed ? mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) : type; + return changed + ? mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) + : type; } - function mapTypeWithAlias(type: Type, mapper: (t: Type) => Type, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { - return type.flags & TypeFlags.Union && aliasSymbol ? - getUnionType(map((type as UnionType).types, mapper), UnionReduction.Literal, aliasSymbol, aliasTypeArguments) : - mapType(type, mapper); + function mapTypeWithAlias( + type: Type, + mapper: (t: Type) => Type, + aliasSymbol: Symbol | undefined, + aliasTypeArguments: readonly Type[] | undefined, + ) { + return type.flags & TypeFlags.Union && aliasSymbol + ? getUnionType( + map((type as UnionType).types, mapper), + UnionReduction.Literal, + aliasSymbol, + aliasTypeArguments, + ) + : mapType(type, mapper); } function extractTypesOfKind(type: Type, kind: TypeFlags) { @@ -26199,13 +34178,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // true intersection because it is more costly and, when applied to union types, generates a large number of // types we don't actually care about. function replacePrimitivesWithLiterals(typeWithPrimitives: Type, typeWithLiterals: Type) { - if (maybeTypeOfKind(typeWithPrimitives, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.Number | TypeFlags.BigInt) && - maybeTypeOfKind(typeWithLiterals, TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.NumberLiteral | TypeFlags.BigIntLiteral)) { - return mapType(typeWithPrimitives, t => - t.flags & TypeFlags.String ? extractTypesOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) : - isPatternLiteralType(t) && !maybeTypeOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) ? extractTypesOfKind(typeWithLiterals, TypeFlags.StringLiteral) : - t.flags & TypeFlags.Number ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) : - t.flags & TypeFlags.BigInt ? extractTypesOfKind(typeWithLiterals, TypeFlags.BigInt | TypeFlags.BigIntLiteral) : t); + if ( + maybeTypeOfKind( + typeWithPrimitives, + TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.Number | TypeFlags.BigInt, + ) + && maybeTypeOfKind( + typeWithLiterals, + TypeFlags.StringLiteral | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.NumberLiteral + | TypeFlags.BigIntLiteral, + ) + ) { + return mapType( + typeWithPrimitives, + t => t.flags & TypeFlags.String + ? extractTypesOfKind( + typeWithLiterals, + TypeFlags.String | TypeFlags.StringLiteral | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping, + ) + : isPatternLiteralType(t) + && !maybeTypeOfKind( + typeWithLiterals, + TypeFlags.String | TypeFlags.TemplateLiteral | TypeFlags.StringMapping, + ) ? extractTypesOfKind(typeWithLiterals, TypeFlags.StringLiteral) + : t.flags & TypeFlags.Number + ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) + : t.flags & TypeFlags.BigInt + ? extractTypesOfKind(typeWithLiterals, TypeFlags.BigInt | TypeFlags.BigIntLiteral) : t, + ); } return typeWithPrimitives; } @@ -26233,28 +34234,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getEvolvingArrayType(elementType: Type): EvolvingArrayType { - return evolvingArrayTypes[elementType.id] || (evolvingArrayTypes[elementType.id] = createEvolvingArrayType(elementType)); + return evolvingArrayTypes[elementType.id] + || (evolvingArrayTypes[elementType.id] = createEvolvingArrayType(elementType)); } // When adding evolving array element types we do not perform subtype reduction. Instead, // we defer subtype reduction until the evolving array type is finalized into a manifest // array type. function addEvolvingArrayElementType(evolvingArrayType: EvolvingArrayType, node: Expression): EvolvingArrayType { - const elementType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(getContextFreeTypeOfExpression(node))); - return isTypeSubsetOf(elementType, evolvingArrayType.elementType) ? evolvingArrayType : getEvolvingArrayType(getUnionType([evolvingArrayType.elementType, elementType])); + const elementType = getRegularTypeOfObjectLiteral( + getBaseTypeOfLiteralType(getContextFreeTypeOfExpression(node)), + ); + return isTypeSubsetOf(elementType, evolvingArrayType.elementType) ? evolvingArrayType + : getEvolvingArrayType(getUnionType([evolvingArrayType.elementType, elementType])); } function createFinalArrayType(elementType: Type) { - return elementType.flags & TypeFlags.Never ? - autoArrayType : - createArrayType(elementType.flags & TypeFlags.Union ? - getUnionType((elementType as UnionType).types, UnionReduction.Subtype) : - elementType); + return elementType.flags & TypeFlags.Never + ? autoArrayType + : createArrayType( + elementType.flags & TypeFlags.Union + ? getUnionType((elementType as UnionType).types, UnionReduction.Subtype) + : elementType, + ); } // We perform subtype reduction upon obtaining the final array type from an evolving array type. function getFinalArrayType(evolvingArrayType: EvolvingArrayType): Type { - return evolvingArrayType.finalArrayType || (evolvingArrayType.finalArrayType = createFinalArrayType(evolvingArrayType.elementType)); + return evolvingArrayType.finalArrayType + || (evolvingArrayType.finalArrayType = createFinalArrayType(evolvingArrayType.elementType)); } function finalizeEvolvingArrayType(type: Type): Type { @@ -26284,24 +34292,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const root = getReferenceRoot(node); const parent = root.parent; const isLengthPushOrUnshift = isPropertyAccessExpression(parent) && ( - parent.name.escapedText === "length" || - parent.parent.kind === SyntaxKind.CallExpression - && isIdentifier(parent.name) - && isPushOrUnshiftIdentifier(parent.name)); - const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression && - (parent as ElementAccessExpression).expression === root && - parent.parent.kind === SyntaxKind.BinaryExpression && - (parent.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && - (parent.parent as BinaryExpression).left === parent && - !isAssignmentTarget(parent.parent) && - isTypeAssignableToKind(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression), TypeFlags.NumberLike); + parent.name.escapedText === "length" + || parent.parent.kind === SyntaxKind.CallExpression + && isIdentifier(parent.name) + && isPushOrUnshiftIdentifier(parent.name) + ); + const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression + && (parent as ElementAccessExpression).expression === root + && parent.parent.kind === SyntaxKind.BinaryExpression + && (parent.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + && (parent.parent as BinaryExpression).left === parent + && !isAssignmentTarget(parent.parent) + && isTypeAssignableToKind( + getTypeOfExpression((parent as ElementAccessExpression).argumentExpression), + TypeFlags.NumberLike, + ); return isLengthPushOrUnshift || isElementAssignment; } function isDeclarationWithExplicitTypeAnnotation(node: Declaration) { - return (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isParameter(node)) && - !!(getEffectiveTypeAnnotationNode(node) || - isInJSFile(node) && hasInitializer(node) && node.initializer && isFunctionExpressionOrArrowFunction(node.initializer) && getEffectiveReturnTypeNode(node.initializer)); + return (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) + || isParameter(node)) + && !!(getEffectiveTypeAnnotationNode(node) + || isInJSFile(node) && hasInitializer(node) && node.initializer + && isFunctionExpressionOrArrowFunction(node.initializer) + && getEffectiveReturnTypeNode(node.initializer)); } function getExplicitTypeOfSymbol(symbol: Symbol, diagnostic?: Diagnostic) { @@ -26321,16 +34336,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isDeclarationWithExplicitTypeAnnotation(declaration)) { return getTypeOfSymbol(symbol); } - if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { + if ( + isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement + ) { const statement = declaration.parent.parent; const expressionType = getTypeOfDottedName(statement.expression, /*diagnostic*/ undefined); if (expressionType) { const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf; - return checkIteratedTypeOrElementType(use, expressionType, undefinedType, /*errorNode*/ undefined); + return checkIteratedTypeOrElementType( + use, + expressionType, + undefinedType, + /*errorNode*/ undefined, + ); } } if (diagnostic) { - addRelatedInfo(diagnostic, createDiagnosticForNode(declaration, Diagnostics._0_needs_an_explicit_type_annotation, symbolToString(symbol))); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + declaration, + Diagnostics._0_needs_an_explicit_type_annotation, + symbolToString(symbol), + ), + ); } } } @@ -26359,7 +34388,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!type.symbol) { return undefined; } - prop = getPropertyOfType(type, getSymbolNameForPrivateIdentifier(type.symbol, name.escapedText)); + prop = getPropertyOfType( + type, + getSymbolNameForPrivateIdentifier(type.symbol, name.escapedText), + ); } else { prop = getPropertyOfType(type, name.escapedText); @@ -26390,25 +34422,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isOptionalChain(node)) { funcType = checkNonNullType( getOptionalExpressionType(checkExpression(node.expression), node.expression), - node.expression + node.expression, ); } else { funcType = checkNonNullExpression(node.expression); } } - const signatures = getSignaturesOfType(funcType && getApparentType(funcType) || unknownType, SignatureKind.Call); - const candidate = signatures.length === 1 && !signatures[0].typeParameters ? signatures[0] : - some(signatures, hasTypePredicateOrNeverReturnType) ? getResolvedSignature(node) : - undefined; - signature = links.effectsSignature = candidate && hasTypePredicateOrNeverReturnType(candidate) ? candidate : unknownSignature; + const signatures = getSignaturesOfType( + funcType && getApparentType(funcType) || unknownType, + SignatureKind.Call, + ); + const candidate = signatures.length === 1 && !signatures[0].typeParameters ? signatures[0] + : some(signatures, hasTypePredicateOrNeverReturnType) ? getResolvedSignature(node) + : undefined; + signature = links.effectsSignature = candidate && hasTypePredicateOrNeverReturnType(candidate) ? candidate + : unknownSignature; } return signature === unknownSignature ? undefined : signature; } function hasTypePredicateOrNeverReturnType(signature: Signature) { - return !!(getTypePredicateOfSignature(signature) || - signature.declaration && (getReturnTypeFromAnnotation(signature.declaration) || unknownType).flags & TypeFlags.Never); + return !!(getTypePredicateOfSignature(signature) + || signature.declaration + && (getReturnTypeFromAnnotation(signature.declaration) || unknownType).flags & TypeFlags.Never); } function getTypePredicateArgument(predicate: TypePredicate, callExpression: CallExpression) { @@ -26423,7 +34460,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const block = findAncestor(node, isFunctionOrModuleBlock) as Block | ModuleBlock | SourceFile; const sourceFile = getSourceFileOfNode(node); const span = getSpanOfTokenAtPosition(sourceFile, block.statements.pos); - diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis)); + diagnostics.add( + createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics.The_containing_function_or_module_body_is_too_large_for_control_flow_analysis, + ), + ); } function isReachableFlowNode(flow: FlowNode) { @@ -26436,8 +34480,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isFalseExpression(expr: Expression): boolean { const node = skipParentheses(expr, /*excludeJSDocTypeAssertions*/ true); return node.kind === SyntaxKind.FalseKeyword || node.kind === SyntaxKind.BinaryExpression && ( - (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken && (isFalseExpression((node as BinaryExpression).left) || isFalseExpression((node as BinaryExpression).right)) || - (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken && isFalseExpression((node as BinaryExpression).left) && isFalseExpression((node as BinaryExpression).right)); + (node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken + && (isFalseExpression((node as BinaryExpression).left) + || isFalseExpression((node as BinaryExpression).right)) + || (node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken + && isFalseExpression((node as BinaryExpression).left) + && isFalseExpression((node as BinaryExpression).right) + ); } function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck: boolean): boolean { @@ -26450,7 +34499,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!noCacheCheck) { const id = getFlowNodeId(flow); const reachable = flowNodeReachable[id]; - return reachable !== undefined ? reachable : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*noCacheCheck*/ true)); + return reachable !== undefined ? reachable + : (flowNodeReachable[id] = isReachableFlowNodeWorker(flow, /*noCacheCheck*/ true)); } noCacheCheck = false; } @@ -26488,7 +34538,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (flags & FlowFlags.SwitchClause) { // The control flow path representing an unmatched value in a switch statement with // no default clause is unreachable if the switch statement is exhaustive. - if ((flow as FlowSwitchClause).clauseStart === (flow as FlowSwitchClause).clauseEnd && isExhaustiveSwitchStatement((flow as FlowSwitchClause).switchStatement)) { + if ( + (flow as FlowSwitchClause).clauseStart === (flow as FlowSwitchClause).clauseEnd + && isExhaustiveSwitchStatement((flow as FlowSwitchClause).switchStatement) + ) { return false; } flow = (flow as FlowSwitchClause).antecedent; @@ -26518,11 +34571,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!noCacheCheck) { const id = getFlowNodeId(flow); const postSuper = flowNodePostSuper[id]; - return postSuper !== undefined ? postSuper : (flowNodePostSuper[id] = isPostSuperFlowNode(flow, /*noCacheCheck*/ true)); + return postSuper !== undefined ? postSuper + : (flowNodePostSuper[id] = isPostSuperFlowNode(flow, /*noCacheCheck*/ true)); } noCacheCheck = false; } - if (flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation | FlowFlags.SwitchClause)) { + if ( + flags & (FlowFlags.Assignment | FlowFlags.Condition | FlowFlags.ArrayMutation | FlowFlags.SwitchClause) + ) { flow = (flow as FlowAssignment | FlowCondition | FlowArrayMutation | FlowSwitchClause).antecedent; } else if (flags & FlowFlags.Call) { @@ -26561,18 +34617,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Identifier: if (!isThisInTypeQuery(node)) { const symbol = getResolvedSymbol(node as Identifier); - return isConstantVariable(symbol) || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol); + return isConstantVariable(symbol) + || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol); } break; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: // The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here. - return isConstantReference((node as AccessExpression).expression) && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol); + return isConstantReference((node as AccessExpression).expression) + && isReadonlySymbol(getNodeLinks(node).resolvedSymbol || unknownSymbol); } return false; } - function getFlowTypeOfReference(reference: Node, declaredType: Type, initialType = declaredType, flowContainer?: Node, flowNode = tryCast(reference, canHaveFlowNode)?.flowNode) { + function getFlowTypeOfReference( + reference: Node, + declaredType: Type, + initialType = declaredType, + flowContainer?: Node, + flowNode = tryCast(reference, canHaveFlowNode)?.flowNode, + ) { let key: string | undefined; let isKeySet = false; let flowDepth = 0; @@ -26590,8 +34654,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // we give type 'any[]' to 'x' instead of using the type determined by control flow analysis such that operations // on empty arrays are possible without implicit any errors and new element types can be inferred without // type mismatch errors. - const resultType = getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) ? autoArrayType : finalizeEvolvingArrayType(evolvedType); - if (resultType === unreachableNeverType || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression && !(resultType.flags & TypeFlags.Never) && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never) { + const resultType = + getObjectFlags(evolvedType) & ObjectFlags.EvolvingArray && isEvolvingArrayOperationTarget(reference) + ? autoArrayType : finalizeEvolvingArrayType(evolvedType); + if ( + resultType === unreachableNeverType + || reference.parent && reference.parent.kind === SyntaxKind.NonNullExpression + && !(resultType.flags & TypeFlags.Never) + && getTypeWithFacts(resultType, TypeFacts.NEUndefinedOrNull).flags & TypeFlags.Never + ) { return declaredType; } // The non-null unknown type should never escape control flow analysis. @@ -26656,9 +34727,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { flow = (flow as FlowLabel).antecedents![0]; continue; } - type = flags & FlowFlags.BranchLabel ? - getTypeAtFlowBranchLabel(flow as FlowLabel) : - getTypeAtFlowLoopLabel(flow as FlowLabel); + type = flags & FlowFlags.BranchLabel + ? getTypeAtFlowBranchLabel(flow as FlowLabel) + : getTypeAtFlowLoopLabel(flow as FlowLabel); } else if (flags & FlowFlags.ArrayMutation) { type = getTypeAtFlowArrayMutation(flow as FlowArrayMutation); @@ -26677,10 +34748,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (flags & FlowFlags.Start) { // Check if we should continue with the control flow of the containing function. const container = (flow as FlowStart).node; - if (container && container !== flowContainer && - reference.kind !== SyntaxKind.PropertyAccessExpression && - reference.kind !== SyntaxKind.ElementAccessExpression && - !(reference.kind === SyntaxKind.ThisKeyword && container.kind !== SyntaxKind.ArrowFunction) + if ( + container && container !== flowContainer + && reference.kind !== SyntaxKind.PropertyAccessExpression + && reference.kind !== SyntaxKind.ElementAccessExpression + && !(reference.kind === SyntaxKind.ThisKeyword && container.kind !== SyntaxKind.ArrowFunction) ) { flow = container.flowNode!; continue; @@ -26706,9 +34778,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getInitialOrAssignedType(flow: FlowAssignment) { const node = flow.node; - return getNarrowableTypeForReference(node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement ? - getInitialType(node as VariableDeclaration | BindingElement) : - getAssignedType(node), reference); + return getNarrowableTypeForReference( + node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement + ? getInitialType(node as VariableDeclaration | BindingElement) + : getAssignedType(node), + reference, + ); } function getTypeAtFlowAssignment(flow: FlowAssignment) { @@ -26721,7 +34796,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (getAssignmentTargetKind(node) === AssignmentKind.Compound) { const flowType = getTypeAtFlowNode(flow.antecedent); - return createFlowType(getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), isIncomplete(flowType)); + return createFlowType( + getBaseTypeOfLiteralType(getTypeFromFlowType(flowType)), + isIncomplete(flowType), + ); } if (declaredType === autoType || declaredType === autoArrayType) { if (isEmptyArrayAssignment(node)) { @@ -26748,7 +34826,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // in which case we continue control flow analysis back to the function's declaration if (isVariableDeclaration(node) && (isInJSFile(node) || isVarConstLike(node))) { const init = getDeclaredExpandoInitializer(node); - if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) { + if ( + init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction) + ) { return getTypeAtFlowNode(flow.antecedent); } } @@ -26756,11 +34836,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // for (const _ in ref) acts as a nonnull on ref if ( - isVariableDeclaration(node) && - node.parent.parent.kind === SyntaxKind.ForInStatement && - (isMatchingReference(reference, node.parent.parent.expression) || optionalChainContainsReference(node.parent.parent.expression, reference)) + isVariableDeclaration(node) + && node.parent.parent.kind === SyntaxKind.ForInStatement + && (isMatchingReference(reference, node.parent.parent.expression) + || optionalChainContainsReference(node.parent.parent.expression, reference)) ) { - return getNonNullableTypeIfNeeded(finalizeEvolvingArrayType(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent)))); + return getNonNullableTypeIfNeeded( + finalizeEvolvingArrayType(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent))), + ); } // Assignment doesn't affect reference return undefined; @@ -26773,10 +34856,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (node.kind === SyntaxKind.BinaryExpression) { if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { - return narrowTypeByAssertion(narrowTypeByAssertion(type, (node as BinaryExpression).left), (node as BinaryExpression).right); + return narrowTypeByAssertion( + narrowTypeByAssertion(type, (node as BinaryExpression).left), + (node as BinaryExpression).right, + ); } if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.BarBarToken) { - return getUnionType([narrowTypeByAssertion(type, (node as BinaryExpression).left), narrowTypeByAssertion(type, (node as BinaryExpression).right)]); + return getUnionType([ + narrowTypeByAssertion(type, (node as BinaryExpression).left), + narrowTypeByAssertion(type, (node as BinaryExpression).right), + ]); } } return narrowType(type, node, /*assumeTrue*/ true); @@ -26786,12 +34875,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const signature = getEffectsSignature(flow.node); if (signature) { const predicate = getTypePredicateOfSignature(signature); - if (predicate && (predicate.kind === TypePredicateKind.AssertsThis || predicate.kind === TypePredicateKind.AssertsIdentifier)) { + if ( + predicate + && (predicate.kind === TypePredicateKind.AssertsThis + || predicate.kind === TypePredicateKind.AssertsIdentifier) + ) { const flowType = getTypeAtFlowNode(flow.antecedent); const type = finalizeEvolvingArrayType(getTypeFromFlowType(flowType)); - const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : - predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex >= 0 && predicate.parameterIndex < flow.node.arguments.length ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : - type; + const narrowedType = predicate.type + ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) + : predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex >= 0 + && predicate.parameterIndex < flow.node.arguments.length + ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) + : type; return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); } if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { @@ -26804,9 +34900,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeAtFlowArrayMutation(flow: FlowArrayMutation): FlowType | undefined { if (declaredType === autoType || declaredType === autoArrayType) { const node = flow.node; - const expr = node.kind === SyntaxKind.CallExpression ? - (node.expression as PropertyAccessExpression).expression : - (node.left as ElementAccessExpression).expression; + const expr = node.kind === SyntaxKind.CallExpression + ? (node.expression as PropertyAccessExpression).expression + : (node.left as ElementAccessExpression).expression; if (isMatchingReference(reference, getReferenceCandidate(expr))) { const flowType = getTypeAtFlowNode(flow.antecedent); const type = getTypeFromFlowType(flowType); @@ -26819,7 +34915,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { // We must get the context free expression type so as to not recur in an uncached fashion on the LHS (which causes exponential blowup in compile time) - const indexType = getContextFreeTypeOfExpression((node.left as ElementAccessExpression).argumentExpression); + const indexType = getContextFreeTypeOfExpression( + (node.left as ElementAccessExpression).argumentExpression, + ); if (isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) { evolvedType = addEvolvingArrayElementType(evolvedType, node.right); } @@ -26861,23 +34959,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isMatchingReference(reference, expr)) { type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd); } - else if (expr.kind === SyntaxKind.TypeOfExpression && isMatchingReference(reference, (expr as TypeOfExpression).expression)) { + else if ( + expr.kind === SyntaxKind.TypeOfExpression + && isMatchingReference(reference, (expr as TypeOfExpression).expression) + ) { type = narrowTypeBySwitchOnTypeOf(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd); } else { if (strictNullChecks) { if (optionalChainContainsReference(expr, reference)) { - type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd, - t => !(t.flags & (TypeFlags.Undefined | TypeFlags.Never))); + type = narrowTypeBySwitchOptionalChainContainment( + type, + flow.switchStatement, + flow.clauseStart, + flow.clauseEnd, + t => !(t.flags & (TypeFlags.Undefined | TypeFlags.Never)), + ); } - else if (expr.kind === SyntaxKind.TypeOfExpression && optionalChainContainsReference((expr as TypeOfExpression).expression, reference)) { - type = narrowTypeBySwitchOptionalChainContainment(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd, - t => !(t.flags & TypeFlags.Never || t.flags & TypeFlags.StringLiteral && (t as StringLiteralType).value === "undefined")); + else if ( + expr.kind === SyntaxKind.TypeOfExpression + && optionalChainContainsReference((expr as TypeOfExpression).expression, reference) + ) { + type = narrowTypeBySwitchOptionalChainContainment( + type, + flow.switchStatement, + flow.clauseStart, + flow.clauseEnd, + t => !(t.flags & TypeFlags.Never + || t.flags & TypeFlags.StringLiteral && (t as StringLiteralType).value === "undefined"), + ); } } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - type = narrowTypeBySwitchOnDiscriminantProperty(type, access, flow.switchStatement, flow.clauseStart, flow.clauseEnd); + type = narrowTypeBySwitchOnDiscriminantProperty( + type, + access, + flow.switchStatement, + flow.clauseStart, + flow.clauseEnd, + ); } } return createFlowType(type, isIncomplete(flowType)); @@ -26889,7 +35010,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let seenIncomplete = false; let bypassFlow: FlowSwitchClause | undefined; for (const antecedent of flow.antecedents!) { - if (!bypassFlow && antecedent.flags & FlowFlags.SwitchClause && (antecedent as FlowSwitchClause).clauseStart === (antecedent as FlowSwitchClause).clauseEnd) { + if ( + !bypassFlow && antecedent.flags & FlowFlags.SwitchClause + && (antecedent as FlowSwitchClause).clauseStart === (antecedent as FlowSwitchClause).clauseEnd + ) { // The antecedent is the bypass branch of a potentially exhaustive switch statement. bypassFlow = antecedent as FlowSwitchClause; continue; @@ -26920,7 +35044,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the bypass flow contributes a type we haven't seen yet and the switch statement // isn't exhaustive, process the bypass flow type. Since exhaustiveness checks increase // the risk of circularities, we only want to perform them when they make a difference. - if (!(type.flags & TypeFlags.Never) && !contains(antecedentTypes, type) && !isExhaustiveSwitchStatement(bypassFlow.switchStatement)) { + if ( + !(type.flags & TypeFlags.Never) && !contains(antecedentTypes, type) + && !isExhaustiveSwitchStatement(bypassFlow.switchStatement) + ) { if (type === declaredType && declaredType === initialType) { return type; } @@ -26933,7 +35060,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete); + return createFlowType( + getUnionOrEvolvingArrayType( + antecedentTypes, + subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal, + ), + seenIncomplete, + ); } function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType { @@ -26960,7 +35093,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // path that leads to the top. for (let i = flowLoopStart; i < flowLoopCount; i++) { if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key && flowLoopTypes[i].length) { - return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], UnionReduction.Literal), /*incomplete*/ true); + return createFlowType( + getUnionOrEvolvingArrayType(flowLoopTypes[i], UnionReduction.Literal), + /*incomplete*/ true, + ); } } // Add the flow loop junction and reference to the in-process stack and analyze @@ -27012,7 +35148,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // The result is incomplete if the first antecedent (the non-looping control flow path) // is incomplete. - const result = getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal); + const result = getUnionOrEvolvingArrayType( + antecedentTypes, + subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal, + ); if (isIncomplete(firstAntecedentType!)) { return createFlowType(result, /*incomplete*/ true); } @@ -27027,22 +35166,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isEvolvingArrayTypeList(types)) { return getEvolvingArrayType(getUnionType(map(types, getElementTypeOfEvolvingArrayType))); } - const result = recombineUnknownType(getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction)); - if (result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union && arraysEqual((result as UnionType).types, (declaredType as UnionType).types)) { + const result = recombineUnknownType( + getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction), + ); + if ( + result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union + && arraysEqual((result as UnionType).types, (declaredType as UnionType).types) + ) { return declaredType; } return result; } function getCandidateDiscriminantPropertyAccess(expr: Expression) { - if (isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) || isObjectLiteralMethod(reference)) { + if ( + isBindingPattern(reference) || isFunctionExpressionOrArrowFunction(reference) + || isObjectLiteralMethod(reference) + ) { // When the reference is a binding pattern or function or arrow expression, we are narrowing a pesudo-reference in // getNarrowedTypeOfSymbol. An identifier for a destructuring variable declared in the same binding pattern or // parameter declared in the same parameter list is a candidate. if (isIdentifier(expr)) { const symbol = getResolvedSymbol(expr); const declaration = symbol.valueDeclaration; - if (declaration && (isBindingElement(declaration) || isParameter(declaration)) && reference === declaration.parent && !declaration.initializer && !declaration.dotDotDotToken) { + if ( + declaration && (isBindingElement(declaration) || isParameter(declaration)) + && reference === declaration.parent && !declaration.initializer && !declaration.dotDotDotToken + ) { return declaration; } } @@ -27058,15 +35208,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isConstantVariable(symbol)) { const declaration = symbol.valueDeclaration!; // Given 'const x = obj.kind', allow 'x' as an alias for 'obj.kind' - if (isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isAccessExpression(declaration.initializer) && - isMatchingReference(reference, declaration.initializer.expression)) { + if ( + isVariableDeclaration(declaration) && !declaration.type && declaration.initializer + && isAccessExpression(declaration.initializer) + && isMatchingReference(reference, declaration.initializer.expression) + ) { return declaration.initializer; } // Given 'const { kind: x } = obj', allow 'x' as an alias for 'obj.kind' if (isBindingElement(declaration) && !declaration.initializer) { const parent = declaration.parent.parent; - if (isVariableDeclaration(parent) && !parent.type && parent.initializer && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) && - isMatchingReference(reference, parent.initializer)) { + if ( + isVariableDeclaration(parent) && !parent.type && parent.initializer + && (isIdentifier(parent.initializer) || isAccessExpression(parent.initializer)) + && isMatchingReference(reference, parent.initializer) + ) { return declaration; } } @@ -27089,14 +35245,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function narrowTypeByDiscriminant(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, narrowType: (t: Type) => Type): Type { + function narrowTypeByDiscriminant( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + narrowType: (t: Type) => Type, + ): Type { const propName = getAccessedPropertyName(access); if (propName === undefined) { return type; } const optionalChain = isOptionalChain(access); - const removeNullable = strictNullChecks && (optionalChain || isNonNullAccess(access)) && maybeTypeOfKind(type, TypeFlags.Nullable); - let propType = getTypeOfPropertyOfType(removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type, propName); + const removeNullable = strictNullChecks && (optionalChain || isNonNullAccess(access)) + && maybeTypeOfKind(type, TypeFlags.Nullable); + let propType = getTypeOfPropertyOfType( + removeNullable ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type, + propName, + ); if (!propType) { return type; } @@ -27104,34 +35268,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const narrowedPropType = narrowType(propType); return filterType(type, t => { const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName); - return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType); + return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) + && areTypesComparable(narrowedPropType, discriminantType); }); } - function narrowTypeByDiscriminantProperty(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, operator: SyntaxKind, value: Expression, assumeTrue: boolean) { - if ((operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) && type.flags & TypeFlags.Union) { + function narrowTypeByDiscriminantProperty( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + operator: SyntaxKind, + value: Expression, + assumeTrue: boolean, + ) { + if ( + (operator === SyntaxKind.EqualsEqualsEqualsToken + || operator === SyntaxKind.ExclamationEqualsEqualsToken) && type.flags & TypeFlags.Union + ) { const keyPropertyName = getKeyPropertyName(type as UnionType); if (keyPropertyName && keyPropertyName === getAccessedPropertyName(access)) { const candidate = getConstituentTypeForKeyType(type as UnionType, getTypeOfExpression(value)); if (candidate) { - return operator === (assumeTrue ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken) ? candidate : - isUnitType(getTypeOfPropertyOfType(candidate, keyPropertyName) || unknownType) ? removeType(type, candidate) : - type; + return operator + === (assumeTrue ? SyntaxKind.EqualsEqualsEqualsToken + : SyntaxKind.ExclamationEqualsEqualsToken) ? candidate + : isUnitType(getTypeOfPropertyOfType(candidate, keyPropertyName) || unknownType) + ? removeType(type, candidate) + : type; } } } return narrowTypeByDiscriminant(type, access, t => narrowTypeByEquality(t, operator, value, assumeTrue)); } - function narrowTypeBySwitchOnDiscriminantProperty(type: Type, access: AccessExpression | BindingElement | ParameterDeclaration, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number) { - if (clauseStart < clauseEnd && type.flags & TypeFlags.Union && getKeyPropertyName(type as UnionType) === getAccessedPropertyName(access)) { + function narrowTypeBySwitchOnDiscriminantProperty( + type: Type, + access: AccessExpression | BindingElement | ParameterDeclaration, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + ) { + if ( + clauseStart < clauseEnd && type.flags & TypeFlags.Union + && getKeyPropertyName(type as UnionType) === getAccessedPropertyName(access) + ) { const clauseTypes = getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd); - const candidate = getUnionType(map(clauseTypes, t => getConstituentTypeForKeyType(type as UnionType, t) || unknownType)); + const candidate = getUnionType( + map(clauseTypes, t => getConstituentTypeForKeyType(type as UnionType, t) || unknownType), + ); if (candidate !== unknownType) { return candidate; } } - return narrowTypeByDiscriminant(type, access, t => narrowTypeBySwitchOnDiscriminant(t, switchStatement, clauseStart, clauseEnd)); + return narrowTypeByDiscriminant( + type, + access, + t => narrowTypeBySwitchOnDiscriminant(t, switchStatement, clauseStart, clauseEnd), + ); } function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { @@ -27143,19 +35335,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - return narrowTypeByDiscriminant(type, access, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy)); + return narrowTypeByDiscriminant( + type, + access, + t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy), + ); } return type; } function isTypePresencePossible(type: Type, propName: __String, assumeTrue: boolean) { const prop = getPropertyOfType(type, propName); - return prop ? - !!(prop.flags & SymbolFlags.Optional || getCheckFlags(prop) & CheckFlags.Partial) || assumeTrue : - !!getApplicableIndexInfoForName(type, propName) || !assumeTrue; + return prop + ? !!(prop.flags & SymbolFlags.Optional || getCheckFlags(prop) & CheckFlags.Partial) || assumeTrue + : !!getApplicableIndexInfoForName(type, propName) || !assumeTrue; } - function narrowTypeByInKeyword(type: Type, nameType: StringLiteralType | NumberLiteralType | UniqueESSymbolType, assumeTrue: boolean) { + function narrowTypeByInKeyword( + type: Type, + nameType: StringLiteralType | NumberLiteralType | UniqueESSymbolType, + assumeTrue: boolean, + ) { const name = getPropertyNameFromType(nameType); const isKnownProperty = someType(type, t => isTypePresencePossible(t, name, /*assumeTrue*/ true)); if (isKnownProperty) { @@ -27168,7 +35368,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // where X is the name of the property. const recordSymbol = getGlobalRecordSymbol(); if (recordSymbol) { - return getIntersectionType([type, getTypeAliasInstantiation(recordSymbol, [nameType, unknownType])]); + return getIntersectionType([ + type, + getTypeAliasInstantiation(recordSymbol, [nameType, unknownType]), + ]); } } return type; @@ -27230,9 +35433,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return narrowTypeByPrivateIdentifierInInExpression(type, expr, assumeTrue); } const target = getReferenceCandidate(expr.right); - if (containsMissingType(type) && isAccessExpression(reference) && isMatchingReference(reference.expression, target)) { + if ( + containsMissingType(type) && isAccessExpression(reference) + && isMatchingReference(reference.expression, target) + ) { const leftType = getTypeOfExpression(expr.left); - if (isTypeUsableAsPropertyName(leftType) && getAccessedPropertyName(reference) === getPropertyNameFromType(leftType)) { + if ( + isTypeUsableAsPropertyName(leftType) + && getAccessedPropertyName(reference) === getPropertyNameFromType(leftType) + ) { return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); } } @@ -27249,18 +35458,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // expressions down to individual conditional control flows. However, we may encounter them when analyzing // aliased conditional expressions. case SyntaxKind.AmpersandAmpersandToken: - return assumeTrue ? - narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ true) : - getUnionType([narrowType(type, expr.left, /*assumeTrue*/ false), narrowType(type, expr.right, /*assumeTrue*/ false)]); + return assumeTrue + ? narrowType(narrowType(type, expr.left, /*assumeTrue*/ true), expr.right, /*assumeTrue*/ true) + : getUnionType([ + narrowType(type, expr.left, /*assumeTrue*/ false), + narrowType(type, expr.right, /*assumeTrue*/ false), + ]); case SyntaxKind.BarBarToken: - return assumeTrue ? - getUnionType([narrowType(type, expr.left, /*assumeTrue*/ true), narrowType(type, expr.right, /*assumeTrue*/ true)]) : - narrowType(narrowType(type, expr.left, /*assumeTrue*/ false), expr.right, /*assumeTrue*/ false); + return assumeTrue + ? getUnionType([ + narrowType(type, expr.left, /*assumeTrue*/ true), + narrowType(type, expr.right, /*assumeTrue*/ true), + ]) + : narrowType( + narrowType(type, expr.left, /*assumeTrue*/ false), + expr.right, + /*assumeTrue*/ false, + ); } return type; } - function narrowTypeByPrivateIdentifierInInExpression(type: Type, expr: BinaryExpression, assumeTrue: boolean): Type { + function narrowTypeByPrivateIdentifierInInExpression( + type: Type, + expr: BinaryExpression, + assumeTrue: boolean, + ): Type { const target = getReferenceCandidate(expr.right); if (!isMatchingReference(reference, target)) { return type; @@ -27272,13 +35495,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } const classSymbol = symbol.parent!; - const targetType = hasStaticModifier(Debug.checkDefined(symbol.valueDeclaration, "should always have a declaration")) - ? getTypeOfSymbol(classSymbol) as InterfaceType - : getDeclaredTypeOfSymbol(classSymbol); + const targetType = + hasStaticModifier(Debug.checkDefined(symbol.valueDeclaration, "should always have a declaration")) + ? getTypeOfSymbol(classSymbol) as InterfaceType + : getDeclaredTypeOfSymbol(classSymbol); return getNarrowedType(type, targetType, assumeTrue, /*checkDerived*/ true); } - function narrowTypeByOptionalChainContainment(type: Type, operator: SyntaxKind, value: Expression, assumeTrue: boolean): Type { + function narrowTypeByOptionalChainContainment( + type: Type, + operator: SyntaxKind, + value: Expression, + assumeTrue: boolean, + ): Type { // We are in a branch of obj?.foo === value (or any one of the other equality operators). We narrow obj as follows: // When operator is === and type of value excludes undefined, null and undefined is removed from type of obj in true branch. // When operator is !== and type of value excludes undefined, null and undefined is removed from type of obj in false branch. @@ -27288,12 +35517,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When operator is !== and type of value is undefined, null and undefined is removed from type of obj in true branch. // When operator is == and type of value is null or undefined, null and undefined is removed from type of obj in false branch. // When operator is != and type of value is null or undefined, null and undefined is removed from type of obj in true branch. - const equalsOperator = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; - const nullableFlags = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? TypeFlags.Nullable : TypeFlags.Undefined; + const equalsOperator = operator === SyntaxKind.EqualsEqualsToken + || operator === SyntaxKind.EqualsEqualsEqualsToken; + const nullableFlags = + operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken + ? TypeFlags.Nullable : TypeFlags.Undefined; const valueType = getTypeOfExpression(value); // Note that we include any and unknown in the exclusion test because their domain includes null and undefined. - const removeNullable = equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) || - equalsOperator === assumeTrue && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); + const removeNullable = + equalsOperator !== assumeTrue && everyType(valueType, t => !!(t.flags & nullableFlags)) + || equalsOperator === assumeTrue + && everyType(valueType, t => !(t.flags & (TypeFlags.AnyOrUnknown | nullableFlags))); return removeNullable ? getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } @@ -27301,32 +35535,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Any) { return type; } - if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { + if ( + operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken + ) { assumeTrue = !assumeTrue; } const valueType = getTypeOfExpression(value); - const doubleEquals = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken; + const doubleEquals = operator === SyntaxKind.EqualsEqualsToken + || operator === SyntaxKind.ExclamationEqualsToken; if (valueType.flags & TypeFlags.Nullable) { if (!strictNullChecks) { return type; } - const facts = doubleEquals ? - assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull : - valueType.flags & TypeFlags.Null ? - assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull : - assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; + const facts = doubleEquals + ? assumeTrue ? TypeFacts.EQUndefinedOrNull : TypeFacts.NEUndefinedOrNull + : valueType.flags & TypeFlags.Null + ? assumeTrue ? TypeFacts.EQNull : TypeFacts.NENull + : assumeTrue ? TypeFacts.EQUndefined : TypeFacts.NEUndefined; return getAdjustedTypeWithFacts(type, facts); } if (assumeTrue) { if (!doubleEquals && (type.flags & TypeFlags.Unknown || someType(type, isEmptyAnonymousObjectType))) { - if (valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) || isEmptyAnonymousObjectType(valueType)) { + if ( + valueType.flags & (TypeFlags.Primitive | TypeFlags.NonPrimitive) + || isEmptyAnonymousObjectType(valueType) + ) { return valueType; } if (valueType.flags & TypeFlags.Object) { return nonPrimitiveType; } } - const filteredType = filterType(type, t => areTypesComparable(t, valueType) || doubleEquals && isCoercibleUnderDoubleEquals(t, valueType)); + const filteredType = filterType( + type, + t => areTypesComparable(t, valueType) || doubleEquals && isCoercibleUnderDoubleEquals(t, valueType), + ); return replacePrimitivesWithLiterals(filteredType, valueType); } if (isUnitType(valueType)) { @@ -27335,19 +35578,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function narrowTypeByTypeof(type: Type, typeOfExpr: TypeOfExpression, operator: SyntaxKind, literal: LiteralExpression, assumeTrue: boolean): Type { + function narrowTypeByTypeof( + type: Type, + typeOfExpr: TypeOfExpression, + operator: SyntaxKind, + literal: LiteralExpression, + assumeTrue: boolean, + ): Type { // We have '==', '!=', '===', or !==' operator with 'typeof xxx' and string literal operands - if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) { + if ( + operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken + ) { assumeTrue = !assumeTrue; } const target = getReferenceCandidate(typeOfExpr.expression); if (!isMatchingReference(reference, target)) { - if (strictNullChecks && optionalChainContainsReference(target, reference) && assumeTrue === (literal.text !== "undefined")) { + if ( + strictNullChecks && optionalChainContainsReference(target, reference) + && assumeTrue === (literal.text !== "undefined") + ) { type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } const propertyAccess = getDiscriminantPropertyAccess(target, type); if (propertyAccess) { - return narrowTypeByDiscriminant(type, propertyAccess, t => narrowTypeByLiteralExpression(t, literal, assumeTrue)); + return narrowTypeByDiscriminant( + type, + propertyAccess, + t => narrowTypeByLiteralExpression(t, literal, assumeTrue), + ); } return type; } @@ -27355,17 +35613,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function narrowTypeByLiteralExpression(type: Type, literal: LiteralExpression, assumeTrue: boolean) { - return assumeTrue ? - narrowTypeByTypeName(type, literal.text) : - getAdjustedTypeWithFacts(type, typeofNEFacts.get(literal.text) || TypeFacts.TypeofNEHostObject); + return assumeTrue + ? narrowTypeByTypeName(type, literal.text) + : getAdjustedTypeWithFacts(type, typeofNEFacts.get(literal.text) || TypeFacts.TypeofNEHostObject); } - function narrowTypeBySwitchOptionalChainContainment(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number, clauseCheck: (type: Type) => boolean) { - const everyClauseChecks = clauseStart !== clauseEnd && every(getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd), clauseCheck); + function narrowTypeBySwitchOptionalChainContainment( + type: Type, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + clauseCheck: (type: Type) => boolean, + ) { + const everyClauseChecks = clauseStart !== clauseEnd + && every(getSwitchClauseTypes(switchStatement).slice(clauseStart, clauseEnd), clauseCheck); return everyClauseChecks ? getTypeWithFacts(type, TypeFacts.NEUndefinedOrNull) : type; } - function narrowTypeBySwitchOnDiscriminant(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number) { + function narrowTypeBySwitchOnDiscriminant( + type: Type, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + ) { // We only narrow if all case expressions specify // values with unit types, except for the case where // `type` is unknown. In this instance we map object @@ -27398,26 +35668,44 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getUnionType(groundClauseTypes === undefined ? clauseTypes : groundClauseTypes); } const discriminantType = getUnionType(clauseTypes); - const caseType = - discriminantType.flags & TypeFlags.Never ? neverType : - replacePrimitivesWithLiterals(filterType(type, t => areTypesComparable(discriminantType, t)), discriminantType); + const caseType = discriminantType.flags & TypeFlags.Never ? neverType + : replacePrimitivesWithLiterals( + filterType(type, t => areTypesComparable(discriminantType, t)), + discriminantType, + ); if (!hasDefaultClause) { return caseType; } - const defaultType = filterType(type, t => !(isUnitLikeType(t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t))))); + const defaultType = filterType( + type, + t => !(isUnitLikeType(t) && contains(switchTypes, getRegularTypeOfLiteralType(extractUnitType(t)))), + ); return caseType.flags & TypeFlags.Never ? defaultType : getUnionType([caseType, defaultType]); } function narrowTypeByTypeName(type: Type, typeName: string) { switch (typeName) { - case "string": return narrowTypeByTypeFacts(type, stringType, TypeFacts.TypeofEQString); - case "number": return narrowTypeByTypeFacts(type, numberType, TypeFacts.TypeofEQNumber); - case "bigint": return narrowTypeByTypeFacts(type, bigintType, TypeFacts.TypeofEQBigInt); - case "boolean": return narrowTypeByTypeFacts(type, booleanType, TypeFacts.TypeofEQBoolean); - case "symbol": return narrowTypeByTypeFacts(type, esSymbolType, TypeFacts.TypeofEQSymbol); - case "object": return type.flags & TypeFlags.Any ? type : getUnionType([narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQObject), narrowTypeByTypeFacts(type, nullType, TypeFacts.EQNull)]); - case "function": return type.flags & TypeFlags.Any ? type : narrowTypeByTypeFacts(type, globalFunctionType, TypeFacts.TypeofEQFunction); - case "undefined": return narrowTypeByTypeFacts(type, undefinedType, TypeFacts.EQUndefined); + case "string": + return narrowTypeByTypeFacts(type, stringType, TypeFacts.TypeofEQString); + case "number": + return narrowTypeByTypeFacts(type, numberType, TypeFacts.TypeofEQNumber); + case "bigint": + return narrowTypeByTypeFacts(type, bigintType, TypeFacts.TypeofEQBigInt); + case "boolean": + return narrowTypeByTypeFacts(type, booleanType, TypeFacts.TypeofEQBoolean); + case "symbol": + return narrowTypeByTypeFacts(type, esSymbolType, TypeFacts.TypeofEQSymbol); + case "object": + return type.flags & TypeFlags.Any ? type + : getUnionType([ + narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQObject), + narrowTypeByTypeFacts(type, nullType, TypeFacts.EQNull), + ]); + case "function": + return type.flags & TypeFlags.Any ? type + : narrowTypeByTypeFacts(type, globalFunctionType, TypeFacts.TypeofEQFunction); + case "undefined": + return narrowTypeByTypeFacts(type, undefinedType, TypeFacts.EQUndefined); } return narrowTypeByTypeFacts(type, nonPrimitiveType, TypeFacts.TypeofEQHostObject); } @@ -27428,25 +35716,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the constituent based on its type facts. We use the strict subtype relation because it treats `object` // as a subtype of `{}`, and we need the type facts check because function types are subtypes of `object`, // but are classified as "function" according to `typeof`. - isTypeRelatedTo(t, impliedType, strictSubtypeRelation) ? getTypeFacts(t) & facts ? t : neverType : - // We next check if the consituent is a supertype of the implied type. If so, we substitute the implied - // type. This handles top types like `unknown` and `{}`, and supertypes like `{ toString(): string }`. - isTypeSubtypeOf(impliedType, t) ? impliedType : - // Neither the constituent nor the implied type is a subtype of the other, however their domains may still - // overlap. For example, an unconstrained type parameter and type `string`. If the type facts indicate - // possible overlap, we form an intersection. Otherwise, we eliminate the constituent. - getTypeFacts(t) & facts ? getIntersectionType([t, impliedType]) : - neverType); - } - - function narrowTypeBySwitchOnTypeOf(type: Type, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): Type { + isTypeRelatedTo(t, impliedType, strictSubtypeRelation) ? getTypeFacts(t) & facts ? t : neverType + // We next check if the consituent is a supertype of the implied type. If so, we substitute the implied + // type. This handles top types like `unknown` and `{}`, and supertypes like `{ toString(): string }`. + : isTypeSubtypeOf(impliedType, t) ? impliedType + // Neither the constituent nor the implied type is a subtype of the other, however their domains may still + // overlap. For example, an unconstrained type parameter and type `string`. If the type facts indicate + // possible overlap, we form an intersection. Otherwise, we eliminate the constituent. + : getTypeFacts(t) & facts ? getIntersectionType([t, impliedType]) + : neverType); + } + + function narrowTypeBySwitchOnTypeOf( + type: Type, + switchStatement: SwitchStatement, + clauseStart: number, + clauseEnd: number, + ): Type { const witnesses = getSwitchClauseTypeOfWitnesses(switchStatement); if (!witnesses) { return type; } // Equal start and end denotes implicit fallthrough; undefined marks explicit default clause. - const defaultIndex = findIndex(switchStatement.caseBlock.clauses, clause => clause.kind === SyntaxKind.DefaultClause); - const hasDefaultClause = clauseStart === clauseEnd || (defaultIndex >= clauseStart && defaultIndex < clauseEnd); + const defaultIndex = findIndex( + switchStatement.caseBlock.clauses, + clause => clause.kind === SyntaxKind.DefaultClause, + ); + const hasDefaultClause = clauseStart === clauseEnd + || (defaultIndex >= clauseStart && defaultIndex < clauseEnd); if (hasDefaultClause) { // In the default clause we filter constituents down to those that are not-equal to all handled cases. const notEqualFacts = getNotEqualFactsFromTypeofSwitch(clauseStart, clauseEnd, witnesses); @@ -27458,14 +35755,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isMatchingConstructorReference(expr: Expression) { - return (isPropertyAccessExpression(expr) && idText(expr.name) === "constructor" || - isElementAccessExpression(expr) && isStringLiteralLike(expr.argumentExpression) && expr.argumentExpression.text === "constructor") && - isMatchingReference(reference, expr.expression); - } - - function narrowTypeByConstructor(type: Type, operator: SyntaxKind, identifier: Expression, assumeTrue: boolean): Type { + return (isPropertyAccessExpression(expr) && idText(expr.name) === "constructor" + || isElementAccessExpression(expr) && isStringLiteralLike(expr.argumentExpression) + && expr.argumentExpression.text === "constructor") + && isMatchingReference(reference, expr.expression); + } + + function narrowTypeByConstructor( + type: Type, + operator: SyntaxKind, + identifier: Expression, + assumeTrue: boolean, + ): Type { // Do not narrow when checking inequality. - if (assumeTrue ? (operator !== SyntaxKind.EqualsEqualsToken && operator !== SyntaxKind.EqualsEqualsEqualsToken) : (operator !== SyntaxKind.ExclamationEqualsToken && operator !== SyntaxKind.ExclamationEqualsEqualsToken)) { + if ( + assumeTrue + ? (operator !== SyntaxKind.EqualsEqualsToken && operator !== SyntaxKind.EqualsEqualsEqualsToken) + : (operator !== SyntaxKind.ExclamationEqualsToken + && operator !== SyntaxKind.ExclamationEqualsEqualsToken) + ) { return type; } @@ -27501,8 +35809,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This is because you may have a class `A` that defines some set of properties, and another class `B` // that defines the same set of properties as class `A`, in that case they are structurally the same // type, but when you do something like `instanceOfA.constructor === B` it will return false. - if (source.flags & TypeFlags.Object && getObjectFlags(source) & ObjectFlags.Class || - target.flags & TypeFlags.Object && getObjectFlags(target) & ObjectFlags.Class) { + if ( + source.flags & TypeFlags.Object && getObjectFlags(source) & ObjectFlags.Class + || target.flags & TypeFlags.Object && getObjectFlags(target) & ObjectFlags.Class + ) { return source.symbol === target.symbol; } @@ -27526,8 +35836,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const instanceType = mapType(rightType, getInstanceType); // Don't narrow from `any` if the target type is exactly `Object` or `Function`, and narrow // in the false branch only if the target is a non-empty object type. - if (isTypeAny(type) && (instanceType === globalObjectType || instanceType === globalFunctionType) || - !assumeTrue && !(instanceType.flags & TypeFlags.Object && !isEmptyAnonymousObjectType(instanceType))) { + if ( + isTypeAny(type) && (instanceType === globalObjectType || instanceType === globalFunctionType) + || !assumeTrue && !(instanceType.flags & TypeFlags.Object && !isEmptyAnonymousObjectType(instanceType)) + ) { return type; } return getNarrowedType(type, instanceType, assumeTrue, /*checkDerived*/ true); @@ -27540,7 +35852,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const constructSignatures = getSignaturesOfType(constructorType, SignatureKind.Construct); if (constructSignatures.length) { - return getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature)))); + return getUnionType( + map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature))), + ); } // We use the empty object type to indicate we don't know the type of objects created by // this constructor function. @@ -27548,8 +35862,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean): Type { - const key = type.flags & TypeFlags.Union ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` : undefined; - return getCachedType(key) ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived)); + const key = type.flags & TypeFlags.Union + ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` + : undefined; + return getCachedType(key) + ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived)); } function getNarrowedTypeWorker(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) { @@ -27575,38 +35892,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // specific of the two. When t and c are related in both directions, we prefer c for type predicates // because that is the asserted type, but t for `instanceof` because generics aren't reflected in // prototype object types. - const directlyRelated = mapType(matching || type, checkDerived ? - t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType : - t => isTypeStrictSubtypeOf(t, c) ? t : isTypeStrictSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : isTypeSubtypeOf(c, t) ? c : neverType); + const directlyRelated = mapType( + matching || type, + checkDerived + ? t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType + : t => + isTypeStrictSubtypeOf(t, c) ? t + : isTypeStrictSubtypeOf(c, t) ? c + : isTypeSubtypeOf(t, c) ? t : isTypeSubtypeOf(c, t) ? c : neverType, + ); // If no constituents are directly related, create intersections for any generic constituents that // are related by constraint. - return directlyRelated.flags & TypeFlags.Never ? - mapType(type, t => maybeTypeOfKind(t, TypeFlags.Instantiable) && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) : neverType) : - directlyRelated; + return directlyRelated.flags & TypeFlags.Never + ? mapType( + type, + t => maybeTypeOfKind(t, TypeFlags.Instantiable) + && isRelated(c, getBaseConstraintOfType(t) || unknownType) ? getIntersectionType([t, c]) + : neverType, + ) + : directlyRelated; }); // If filtering produced a non-empty type, return that. Otherwise, pick the most specific of the two // based on assignability, or as a last resort produce an intersection. - return !(narrowedType.flags & TypeFlags.Never) ? narrowedType : - isTypeSubtypeOf(candidate, type) ? candidate : - isTypeAssignableTo(type, candidate) ? type : - isTypeAssignableTo(candidate, type) ? candidate : - getIntersectionType([type, candidate]); + return !(narrowedType.flags & TypeFlags.Never) ? narrowedType + : isTypeSubtypeOf(candidate, type) ? candidate + : isTypeAssignableTo(type, candidate) ? type + : isTypeAssignableTo(candidate, type) ? candidate + : getIntersectionType([type, candidate]); } function narrowTypeByCallExpression(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { if (hasMatchingArgument(callExpression, reference)) { - const signature = assumeTrue || !isCallChain(callExpression) ? getEffectsSignature(callExpression) : undefined; + const signature = assumeTrue || !isCallChain(callExpression) ? getEffectsSignature(callExpression) + : undefined; const predicate = signature && getTypePredicateOfSignature(signature); - if (predicate && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier)) { + if ( + predicate + && (predicate.kind === TypePredicateKind.This || predicate.kind === TypePredicateKind.Identifier) + ) { return narrowTypeByTypePredicate(type, predicate, callExpression, assumeTrue); } } - if (containsMissingType(type) && isAccessExpression(reference) && isPropertyAccessExpression(callExpression.expression)) { + if ( + containsMissingType(type) && isAccessExpression(reference) + && isPropertyAccessExpression(callExpression.expression) + ) { const callAccess = callExpression.expression; - if (isMatchingReference(reference.expression, getReferenceCandidate(callAccess.expression)) && - isIdentifier(callAccess.name) && callAccess.name.escapedText === "hasOwnProperty" && callExpression.arguments.length === 1) { + if ( + isMatchingReference(reference.expression, getReferenceCandidate(callAccess.expression)) + && isIdentifier(callAccess.name) && callAccess.name.escapedText === "hasOwnProperty" + && callExpression.arguments.length === 1 + ) { const argument = callExpression.arguments[0]; - if (isStringLiteralLike(argument) && getAccessedPropertyName(reference) === escapeLeadingUnderscores(argument.text)) { + if ( + isStringLiteralLike(argument) + && getAccessedPropertyName(reference) === escapeLeadingUnderscores(argument.text) + ) { return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined); } } @@ -27614,21 +35955,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function narrowTypeByTypePredicate(type: Type, predicate: TypePredicate, callExpression: CallExpression, assumeTrue: boolean): Type { + function narrowTypeByTypePredicate( + type: Type, + predicate: TypePredicate, + callExpression: CallExpression, + assumeTrue: boolean, + ): Type { // Don't narrow from 'any' if the predicate type is exactly 'Object' or 'Function' - if (predicate.type && !(isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType))) { + if ( + predicate.type + && !(isTypeAny(type) && (predicate.type === globalObjectType || predicate.type === globalFunctionType)) + ) { const predicateArgument = getTypePredicateArgument(predicate, callExpression); if (predicateArgument) { if (isMatchingReference(reference, predicateArgument)) { return getNarrowedType(type, predicate.type, assumeTrue, /*checkDerived*/ false); } - if (strictNullChecks && assumeTrue && optionalChainContainsReference(predicateArgument, reference) && - !(getTypeFacts(predicate.type) & TypeFacts.EQUndefined)) { + if ( + strictNullChecks && assumeTrue && optionalChainContainsReference(predicateArgument, reference) + && !(getTypeFacts(predicate.type) & TypeFacts.EQUndefined) + ) { type = getAdjustedTypeWithFacts(type, TypeFacts.NEUndefinedOrNull); } const access = getDiscriminantPropertyAccess(predicateArgument, type); if (access) { - return narrowTypeByDiscriminant(type, access, t => getNarrowedType(t, predicate.type!, assumeTrue, /*checkDerived*/ false)); + return narrowTypeByDiscriminant( + type, + access, + t => getNarrowedType(t, predicate.type!, assumeTrue, /*checkDerived*/ false), + ); } } } @@ -27639,8 +35994,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // will be a subtype or the same type as the argument. function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type { // for `a?.b`, we emulate a synthetic `a !== null && a !== undefined` condition for `a` - if (isExpressionOfOptionalChainRoot(expr) || - isBinaryExpression(expr.parent) && (expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken || expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionEqualsToken) && expr.parent.left === expr) { + if ( + isExpressionOfOptionalChainRoot(expr) + || isBinaryExpression(expr.parent) + && (expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken + || expr.parent.operatorToken.kind === SyntaxKind.QuestionQuestionEqualsToken) + && expr.parent.left === expr + ) { return narrowTypeByOptionality(type, expr, assumeTrue); } switch (expr.kind) { @@ -27651,7 +36011,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getResolvedSymbol(expr as Identifier); if (isConstantVariable(symbol)) { const declaration = symbol.valueDeclaration; - if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && isConstantReference(reference)) { + if ( + declaration && isVariableDeclaration(declaration) && !declaration.type + && declaration.initializer && isConstantReference(reference) + ) { inlineLevel++; const result = narrowType(type, declaration.initializer, assumeTrue); inlineLevel--; @@ -27669,7 +36032,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return narrowTypeByCallExpression(type, expr as CallExpression, assumeTrue); case SyntaxKind.ParenthesizedExpression: case SyntaxKind.NonNullExpression: - return narrowType(type, (expr as ParenthesizedExpression | NonNullExpression).expression, assumeTrue); + return narrowType( + type, + (expr as ParenthesizedExpression | NonNullExpression).expression, + assumeTrue, + ); case SyntaxKind.BinaryExpression: return narrowTypeByBinaryExpression(type, expr as BinaryExpression, assumeTrue); case SyntaxKind.PrefixUnaryExpression: @@ -27683,11 +36050,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function narrowTypeByOptionality(type: Type, expr: Expression, assumePresent: boolean): Type { if (isMatchingReference(reference, expr)) { - return getAdjustedTypeWithFacts(type, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull); + return getAdjustedTypeWithFacts( + type, + assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull, + ); } const access = getDiscriminantPropertyAccess(expr, type); if (access) { - return narrowTypeByDiscriminant(type, access, t => getTypeWithFacts(t, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull)); + return narrowTypeByDiscriminant( + type, + access, + t => getTypeWithFacts(t, assumePresent ? TypeFacts.NEUndefinedOrNull : TypeFacts.EQUndefinedOrNull), + ); } return type; } @@ -27706,16 +36080,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isExpressionNode(location) && (!isAssignmentTarget(location) || isWriteAccess(location))) { const type = removeOptionalTypeMarker( - isWriteAccess(location) && location.kind === SyntaxKind.PropertyAccessExpression ? - checkPropertyAccessExpression(location as PropertyAccessExpression, /*checkMode*/ undefined, /*writeOnly*/ true) : - getTypeOfExpression(location as Expression) + isWriteAccess(location) && location.kind === SyntaxKind.PropertyAccessExpression + ? checkPropertyAccessExpression( + location as PropertyAccessExpression, + /*checkMode*/ undefined, + /*writeOnly*/ true, + ) + : getTypeOfExpression(location as Expression), ); if (getExportSymbolOfValueSymbolIfExported(getNodeLinks(location).resolvedSymbol) === symbol) { return type; } } } - if (isDeclarationName(location) && isSetAccessor(location.parent) && getAnnotatedAccessorTypeNode(location.parent)) { + if ( + isDeclarationName(location) && isSetAccessor(location.parent) + && getAnnotatedAccessorTypeNode(location.parent) + ) { return getWriteTypeOfAccessors(location.parent.symbol); } // The location isn't a reference to the given symbol, meaning we're being asked @@ -27728,10 +36109,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getControlFlowContainer(node: Node): Node { return findAncestor(node.parent, node => - isFunctionLike(node) && !getImmediatelyInvokedFunctionExpression(node) || - node.kind === SyntaxKind.ModuleBlock || - node.kind === SyntaxKind.SourceFile || - node.kind === SyntaxKind.PropertyDeclaration)!; + isFunctionLike(node) && !getImmediatelyInvokedFunctionExpression(node) + || node.kind === SyntaxKind.ModuleBlock + || node.kind === SyntaxKind.SourceFile + || node.kind === SyntaxKind.PropertyDeclaration)!; } // Check if a parameter or catch variable is assigned anywhere @@ -27751,8 +36132,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function hasParentWithAssignmentsMarked(node: Node) { - return !!findAncestor(node.parent, node => - (isFunctionLike(node) || isCatchClause(node)) && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked)); + return !!findAncestor( + node.parent, + node => + (isFunctionLike(node) || isCatchClause(node)) + && !!(getNodeLinks(node).flags & NodeCheckFlags.AssignmentsMarked), + ); } function markNodeAssignments(node: Node) { @@ -27770,7 +36155,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isConstantVariable(symbol: Symbol) { - return symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant) !== 0; + return symbol.flags & SymbolFlags.Variable + && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant) !== 0; } function parameterInitializerContainsUndefined(declaration: ParameterDeclaration): boolean { @@ -27782,7 +36168,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - const containsUndefined = !!(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined); + const containsUndefined = + !!(getTypeFacts(checkDeclarationInitializer(declaration, CheckMode.Normal)) & TypeFacts.IsUndefined); if (!popTypeResolution()) { reportCircularityError(declaration.symbol); @@ -27797,11 +36184,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */ function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type { - const removeUndefined = strictNullChecks && - declaration.kind === SyntaxKind.Parameter && - declaration.initializer && - getTypeFacts(declaredType) & TypeFacts.IsUndefined && - !parameterInitializerContainsUndefined(declaration); + const removeUndefined = strictNullChecks + && declaration.kind === SyntaxKind.Parameter + && declaration.initializer + && getTypeFacts(declaredType) & TypeFacts.IsUndefined + && !parameterInitializerContainsUndefined(declaration); return removeUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType; } @@ -27811,23 +36198,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In an element access obj[x], we consider obj to be in a constraint position, except when obj is of // a generic type without a nullable constraint and x is a generic type. This is because when both obj // and x are of generic types T and K, we want the resulting type to be T[K]. - return parent.kind === SyntaxKind.PropertyAccessExpression || - parent.kind === SyntaxKind.QualifiedName || - parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node || - parent.kind === SyntaxKind.ElementAccessExpression && (parent as ElementAccessExpression).expression === node && - !(someType(type, isGenericTypeWithoutNullableConstraint) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression))); + return parent.kind === SyntaxKind.PropertyAccessExpression + || parent.kind === SyntaxKind.QualifiedName + || parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node + || parent.kind === SyntaxKind.ElementAccessExpression + && (parent as ElementAccessExpression).expression === node + && !(someType(type, isGenericTypeWithoutNullableConstraint) + && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression))); } function isGenericTypeWithUnionConstraint(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? - some((type as IntersectionType).types, isGenericTypeWithUnionConstraint) : - !!(type.flags & TypeFlags.Instantiable && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); + return type.flags & TypeFlags.Intersection + ? some((type as IntersectionType).types, isGenericTypeWithUnionConstraint) + : !!(type.flags & TypeFlags.Instantiable + && getBaseConstraintOrType(type).flags & (TypeFlags.Nullable | TypeFlags.Union)); } function isGenericTypeWithoutNullableConstraint(type: Type): boolean { - return type.flags & TypeFlags.Intersection ? - some((type as IntersectionType).types, isGenericTypeWithoutNullableConstraint) : - !!(type.flags & TypeFlags.Instantiable && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); + return type.flags & TypeFlags.Intersection + ? some((type as IntersectionType).types, isGenericTypeWithoutNullableConstraint) + : !!(type.flags & TypeFlags.Instantiable + && !maybeTypeOfKind(getBaseConstraintOrType(type), TypeFlags.Nullable)); } function hasContextualTypeWithNoGenericTypes(node: Node, checkMode: CheckMode | undefined) { @@ -27835,10 +36226,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // element's tag name, so we exclude that here to avoid circularities. // If check mode has `CheckMode.RestBindingElement`, we skip binding pattern contextual types, // as we want the type of a rest element to be generic when possible. - const contextualType = (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) && - !((isJsxOpeningElement(node.parent) || isJsxSelfClosingElement(node.parent)) && node.parent.tagName === node) && - (checkMode && checkMode & CheckMode.RestBindingElement ? - getContextualType(node, ContextFlags.SkipBindingPatterns) + const contextualType = + (isIdentifier(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node)) + && !((isJsxOpeningElement(node.parent) || isJsxSelfClosingElement(node.parent)) + && node.parent.tagName === node) + && (checkMode && checkMode & CheckMode.RestBindingElement + ? getContextualType(node, ContextFlags.SkipBindingPatterns) : getContextualType(node, /*contextFlags*/ undefined)); return contextualType && !isGenericType(contextualType); } @@ -27851,9 +36244,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // control flow analysis an opportunity to narrow it further. For example, for a reference of a type // parameter type 'T extends string | undefined' with a contextual type 'string', we substitute // 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'. - const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) && - someType(type, isGenericTypeWithUnionConstraint) && - (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); + const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) + && someType(type, isGenericTypeWithUnionConstraint) + && (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); return substituteConstraints ? mapType(type, getBaseConstraintOrType) : type; } @@ -27879,13 +36272,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location)) { const target = resolveAlias(symbol); - if (getSymbolFlags(symbol, /*excludeTypeOnlyMeanings*/ true) & (SymbolFlags.Value | SymbolFlags.ExportValue)) { + if ( + getSymbolFlags(symbol, /*excludeTypeOnlyMeanings*/ true) & (SymbolFlags.Value | SymbolFlags.ExportValue) + ) { // An alias resolving to a const enum cannot be elided if (1) 'isolatedModules' is enabled // (because the const enum value will not be inlined), or if (2) the alias is an export // of a const enum declaration that will be preserved. - if (getIsolatedModules(compilerOptions) || - shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location) || - !isConstEnumOrConstEnumOnlyModule(getExportSymbolOfValueSymbolIfExported(target)) + if ( + getIsolatedModules(compilerOptions) + || shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location) + || !isConstEnumOrConstEnumOnlyModule(getExportSymbolOfValueSymbolIfExported(target)) ) { markAliasSymbolAsReferenced(symbol); } @@ -27923,18 +36319,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the binding pattern AST instance for '{ kind, payload }' as a pseudo-reference and narrow this reference // as if it occurred in the specified location. We then recompute the narrowed binding element type by // destructuring from the narrowed parent type. - if (isBindingElement(declaration) && !declaration.initializer && !declaration.dotDotDotToken && declaration.parent.elements.length >= 2) { + if ( + isBindingElement(declaration) && !declaration.initializer && !declaration.dotDotDotToken + && declaration.parent.elements.length >= 2 + ) { const parent = declaration.parent.parent; - if (parent.kind === SyntaxKind.VariableDeclaration && getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || parent.kind === SyntaxKind.Parameter) { + if ( + parent.kind === SyntaxKind.VariableDeclaration + && getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant + || parent.kind === SyntaxKind.Parameter + ) { const links = getNodeLinks(parent); if (!(links.flags & NodeCheckFlags.InCheckIdentifier)) { links.flags |= NodeCheckFlags.InCheckIdentifier; const parentType = getTypeForBindingElementParent(parent, CheckMode.Normal); const parentTypeConstraint = parentType && mapType(parentType, getBaseConstraintOrType); links.flags &= ~NodeCheckFlags.InCheckIdentifier; - if (parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union && !(parent.kind === SyntaxKind.Parameter && isSymbolAssigned(symbol))) { + if ( + parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union + && !(parent.kind === SyntaxKind.Parameter && isSymbolAssigned(symbol)) + ) { const pattern = declaration.parent; - const narrowedType = getFlowTypeOfReference(pattern, parentTypeConstraint, parentTypeConstraint, /*flowContainer*/ undefined, location.flowNode); + const narrowedType = getFlowTypeOfReference( + pattern, + parentTypeConstraint, + parentTypeConstraint, + /*flowContainer*/ undefined, + location.flowNode, + ); if (narrowedType.flags & TypeFlags.Never) { return neverType; } @@ -27963,14 +36375,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the arrow function AST node for '(kind, payload) => ...' as a pseudo-reference and narrow this reference as // if it occurred in the specified location. We then recompute the narrowed parameter type by indexing into the // narrowed tuple type. - if (isParameter(declaration) && !declaration.type && !declaration.initializer && !declaration.dotDotDotToken) { + if ( + isParameter(declaration) && !declaration.type && !declaration.initializer && !declaration.dotDotDotToken + ) { const func = declaration.parent; if (func.parameters.length >= 2 && isContextSensitiveFunctionOrObjectLiteralMethod(func)) { const contextualSignature = getContextualSignature(func); - if (contextualSignature && contextualSignature.parameters.length === 1 && signatureHasRestParameter(contextualSignature)) { - const restType = getReducedApparentType(instantiateType(getTypeOfSymbol(contextualSignature.parameters[0]), getInferenceContext(func)?.nonFixingMapper)); - if (restType.flags & TypeFlags.Union && everyType(restType, isTupleType) && !isSymbolAssigned(symbol)) { - const narrowedType = getFlowTypeOfReference(func, restType, restType, /*flowContainer*/ undefined, location.flowNode); + if ( + contextualSignature && contextualSignature.parameters.length === 1 + && signatureHasRestParameter(contextualSignature) + ) { + const restType = getReducedApparentType( + instantiateType( + getTypeOfSymbol(contextualSignature.parameters[0]), + getInferenceContext(func)?.nonFixingMapper, + ), + ); + if ( + restType.flags & TypeFlags.Union && everyType(restType, isTupleType) + && !isSymbolAssigned(symbol) + ) { + const narrowedType = getFlowTypeOfReference( + func, + restType, + restType, + /*flowContainer*/ undefined, + location.flowNode, + ); const index = func.parameters.indexOf(declaration) - (getThisParameter(func) ? 1 : 0); return getIndexedAccessType(narrowedType, getNumberLiteralType(index)); } @@ -28006,10 +36437,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const container = getContainingFunction(node)!; if (languageVersion < ScriptTarget.ES2015) { if (container.kind === SyntaxKind.ArrowFunction) { - error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression); + error( + node, + Diagnostics + .The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression, + ); } else if (hasSyntacticModifier(container, ModifierFlags.Async)) { - error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_async_function_or_method_in_ES3_and_ES5_Consider_using_a_standard_function_or_method); + error( + node, + Diagnostics + .The_arguments_object_cannot_be_referenced_in_an_async_function_or_method_in_ES3_and_ES5_Consider_using_a_standard_function_or_method, + ); } } @@ -28023,7 +36462,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); const targetSymbol = resolveAliasWithDeprecationCheck(localOrExportSymbol, node); - if (isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) { + if ( + isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) + && targetSymbol.declarations + ) { addDeprecatedSuggestion(node, targetSymbol.declarations, node.escapedText as string); } @@ -28033,9 +36475,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // class name is double-bound, we must ensure we mark references to the class name so that we can // emit an alias to the class later. if (isClassLike(declaration) && declaration.name !== node) { - let container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + let container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); while (container.kind !== SyntaxKind.SourceFile && container.parent !== declaration) { - container = getThisContainer(container, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + container = getThisContainer( + container, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); } if (container.kind !== SyntaxKind.SourceFile) { @@ -28052,13 +36502,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const assignmentKind = getAssignmentTargetKind(node); if (assignmentKind) { - if (!(localOrExportSymbol.flags & SymbolFlags.Variable) && - !(isInJSFile(node) && localOrExportSymbol.flags & SymbolFlags.ValueModule)) { - const assignmentError = localOrExportSymbol.flags & SymbolFlags.Enum ? Diagnostics.Cannot_assign_to_0_because_it_is_an_enum - : localOrExportSymbol.flags & SymbolFlags.Class ? Diagnostics.Cannot_assign_to_0_because_it_is_a_class - : localOrExportSymbol.flags & SymbolFlags.Module ? Diagnostics.Cannot_assign_to_0_because_it_is_a_namespace - : localOrExportSymbol.flags & SymbolFlags.Function ? Diagnostics.Cannot_assign_to_0_because_it_is_a_function - : localOrExportSymbol.flags & SymbolFlags.Alias ? Diagnostics.Cannot_assign_to_0_because_it_is_an_import + if ( + !(localOrExportSymbol.flags & SymbolFlags.Variable) + && !(isInJSFile(node) && localOrExportSymbol.flags & SymbolFlags.ValueModule) + ) { + const assignmentError = localOrExportSymbol.flags & SymbolFlags.Enum + ? Diagnostics.Cannot_assign_to_0_because_it_is_an_enum + : localOrExportSymbol.flags & SymbolFlags.Class + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_class + : localOrExportSymbol.flags & SymbolFlags.Module + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_namespace + : localOrExportSymbol.flags & SymbolFlags.Function + ? Diagnostics.Cannot_assign_to_0_because_it_is_a_function + : localOrExportSymbol.flags & SymbolFlags.Alias + ? Diagnostics.Cannot_assign_to_0_because_it_is_an_import : Diagnostics.Cannot_assign_to_0_because_it_is_not_a_variable; error(node, assignmentError, symbolToString(symbol)); @@ -28069,7 +36526,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_constant, symbolToString(symbol)); } else { - error(node, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(symbol)); + error( + node, + Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, + symbolToString(symbol), + ); } return errorType; } @@ -28104,40 +36565,62 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const declarationContainer = getControlFlowContainer(declaration); let flowContainer = getControlFlowContainer(node); const isOuterVariable = flowContainer !== declarationContainer; - const isSpreadDestructuringAssignmentTarget = node.parent && node.parent.parent && isSpreadAssignment(node.parent) && isDestructuringAssignmentTarget(node.parent.parent); + const isSpreadDestructuringAssignmentTarget = node.parent && node.parent.parent + && isSpreadAssignment(node.parent) && isDestructuringAssignmentTarget(node.parent.parent); const isModuleExports = symbol.flags & SymbolFlags.ModuleExports; const typeIsAutomatic = type === autoType || type === autoArrayType; const isAutomaticTypeInNonNull = typeIsAutomatic && node.parent.kind === SyntaxKind.NonNullExpression; // When the control flow originates in a function expression or arrow function and we are referencing // a const variable or parameter from an outer function, we extend the origin of the control flow // analysis to include the immediately enclosing function. - while (flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression || - flowContainer.kind === SyntaxKind.ArrowFunction || isObjectLiteralOrClassExpressionMethodOrAccessor(flowContainer)) && - (isConstantVariable(localOrExportSymbol) && type !== autoArrayType || isParameter && !isSymbolAssigned(localOrExportSymbol))) { + while ( + flowContainer !== declarationContainer && (flowContainer.kind === SyntaxKind.FunctionExpression + || flowContainer.kind === SyntaxKind.ArrowFunction + || isObjectLiteralOrClassExpressionMethodOrAccessor(flowContainer)) + && (isConstantVariable(localOrExportSymbol) && type !== autoArrayType + || isParameter && !isSymbolAssigned(localOrExportSymbol)) + ) { flowContainer = getControlFlowContainer(flowContainer); } // We only look for uninitialized variables in strict null checking mode, and only when we can analyze // the entire control flow graph from the variable's declaration (i.e. when the flow container and // declaration container are the same). - const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) || - type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 || - isInTypeQuery(node) || isInAmbientOrTypeNode(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || - node.parent.kind === SyntaxKind.NonNullExpression || - declaration.kind === SyntaxKind.VariableDeclaration && (declaration as VariableDeclaration).exclamationToken || - declaration.flags & NodeFlags.Ambient; - const initialType = isAutomaticTypeInNonNull ? undefinedType : - assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) : - typeIsAutomatic ? undefinedType : getOptionalType(type); - const flowType = isAutomaticTypeInNonNull ? getNonNullableType(getFlowTypeOfReference(node, type, initialType, flowContainer)) : - getFlowTypeOfReference(node, type, initialType, flowContainer); + const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget + || isModuleExports || isSameScopedBindingElement(node, declaration) + || type !== autoType && type !== autoArrayType + && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 + || isInTypeQuery(node) || isInAmbientOrTypeNode(node) + || node.parent.kind === SyntaxKind.ExportSpecifier) + || node.parent.kind === SyntaxKind.NonNullExpression + || declaration.kind === SyntaxKind.VariableDeclaration + && (declaration as VariableDeclaration).exclamationToken + || declaration.flags & NodeFlags.Ambient; + const initialType = isAutomaticTypeInNonNull ? undefinedType + : assumeInitialized + ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) + : typeIsAutomatic ? undefinedType : getOptionalType(type); + const flowType = isAutomaticTypeInNonNull + ? getNonNullableType(getFlowTypeOfReference(node, type, initialType, flowContainer)) + : getFlowTypeOfReference(node, type, initialType, flowContainer); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph // from declaration to use, and when the variable's declared type doesn't include undefined but the // control flow based type does include undefined. if (!isEvolvingArrayOperationTarget(node) && (type === autoType || type === autoArrayType)) { if (flowType === autoType || flowType === autoArrayType) { if (noImplicitAny) { - error(getNameOfDeclaration(declaration), Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, symbolToString(symbol), typeToString(flowType)); - error(node, Diagnostics.Variable_0_implicitly_has_an_1_type, symbolToString(symbol), typeToString(flowType)); + error( + getNameOfDeclaration(declaration), + Diagnostics + .Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined, + symbolToString(symbol), + typeToString(flowType), + ); + error( + node, + Diagnostics.Variable_0_implicitly_has_an_1_type, + symbolToString(symbol), + typeToString(flowType), + ); } return convertAutoToAny(flowType); } @@ -28177,25 +36660,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isInsideFunctionOrInstancePropertyInitializer(node: Node, threshold: Node): boolean { - return !!findAncestor(node, n => n === threshold ? "quit" : isFunctionLike(n) || ( - n.parent && isPropertyDeclaration(n.parent) && !hasStaticModifier(n.parent) && n.parent.initializer === n - )); + return !!findAncestor(node, n => + n === threshold ? "quit" : isFunctionLike(n) || ( + n.parent && isPropertyDeclaration(n.parent) && !hasStaticModifier(n.parent) + && n.parent.initializer === n + )); } function getPartOfForStatementContainingNode(node: Node, container: ForStatement) { - return findAncestor(node, n => n === container ? "quit" : n === container.initializer || n === container.condition || n === container.incrementor || n === container.statement); + return findAncestor( + node, + n => n === container ? "quit" + : n === container.initializer || n === container.condition || n === container.incrementor + || n === container.statement, + ); } function getEnclosingIterationStatement(node: Node): Node | undefined { - return findAncestor(node, n => (!n || nodeStartsNewLexicalEnvironment(n)) ? "quit" : isIterationStatement(n, /*lookInLabeledStatements*/ false)); + return findAncestor( + node, + n => (!n || nodeStartsNewLexicalEnvironment(n)) ? "quit" + : isIterationStatement(n, /*lookInLabeledStatements*/ false), + ); } function checkNestedBlockScopedBinding(node: Identifier, symbol: Symbol): void { - if (languageVersion >= ScriptTarget.ES2015 || - (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 || - !symbol.valueDeclaration || - isSourceFile(symbol.valueDeclaration) || - symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause) { + if ( + languageVersion >= ScriptTarget.ES2015 + || (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.Class)) === 0 + || !symbol.valueDeclaration + || isSourceFile(symbol.valueDeclaration) + || symbol.valueDeclaration.parent.kind === SyntaxKind.CatchClause + ) { return; } @@ -28220,7 +36716,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getNodeLinks(part); links.flags |= NodeCheckFlags.ContainsCapturedBlockScopeBinding; - const capturedBindings = links.capturedBlockScopeBindings || (links.capturedBlockScopeBindings = []); + const capturedBindings = links.capturedBlockScopeBindings + || (links.capturedBlockScopeBindings = []); pushIfUnique(capturedBindings, symbol); if (part === container.initializer) { @@ -28230,7 +36727,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (capturesBlockScopeBindingInLoopBody) { - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; } } @@ -28238,7 +36736,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // if body of ForStatement will be converted to function then we'll need a extra machinery to propagate reassigned values back. if (isForStatement(container)) { const varDeclList = getAncestor(symbol.valueDeclaration, SyntaxKind.VariableDeclarationList); - if (varDeclList && varDeclList.parent === container && isAssignedInBodyOfForStatement(node, container)) { + if ( + varDeclList && varDeclList.parent === container && isAssignedInBodyOfForStatement(node, container) + ) { getNodeLinks(symbol.valueDeclaration).flags |= NodeCheckFlags.NeedsLoopOutParameter; } } @@ -28269,7 +36769,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isAssignmentTarget(current)) { isAssigned = true; } - else if ((current.parent.kind === SyntaxKind.PrefixUnaryExpression || current.parent.kind === SyntaxKind.PostfixUnaryExpression)) { + else if ( + (current.parent.kind === SyntaxKind.PrefixUnaryExpression + || current.parent.kind === SyntaxKind.PostfixUnaryExpression) + ) { const expr = current.parent as PrefixUnaryExpression | PostfixUnaryExpression; isAssigned = expr.operator === SyntaxKind.PlusPlusToken || expr.operator === SyntaxKind.MinusMinusToken; } @@ -28295,9 +36798,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function findFirstSuperCall(node: Node): SuperCall | undefined { - return isSuperCall(node) ? node : - isFunctionLike(node) ? undefined : - forEachChild(node, findFirstSuperCall); + return isSuperCall(node) ? node + : isFunctionLike(node) ? undefined + : forEachChild(node, findFirstSuperCall); } /** @@ -28327,9 +36830,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkThisInStaticClassFieldInitializerInDecoratedClass(thisExpression: Node, container: Node) { - if (isPropertyDeclaration(container) && hasStaticModifier(container) && legacyDecorators && - container.initializer && textRangeContainsPositionInclusive(container.initializer, thisExpression.pos) && hasDecorators(container.parent)) { - error(thisExpression, Diagnostics.Cannot_use_this_in_a_static_property_initializer_of_a_decorated_class); + if ( + isPropertyDeclaration(container) && hasStaticModifier(container) && legacyDecorators + && container.initializer && textRangeContainsPositionInclusive(container.initializer, thisExpression.pos) + && hasDecorators(container.parent) + ) { + error(thisExpression, Diagnostics.Cannot_use_this_in_a_static_property_initializer_of_a_decorated_class); } } @@ -28337,12 +36843,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isNodeInTypeQuery = isInTypeQuery(node); // Stop at the first arrow function so that we can // tell whether 'this' needs to be captured. - let container = getThisContainer(node, /*includeArrowFunctions*/ true, /*includeClassComputedPropertyName*/ true); + let container = getThisContainer( + node, + /*includeArrowFunctions*/ true, + /*includeClassComputedPropertyName*/ true, + ); let capturedByArrowFunction = false; let thisInComputedPropertyName = false; if (container.kind === SyntaxKind.Constructor) { - checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class); + checkThisBeforeSuper( + node, + container, + Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class, + ); } while (true) { @@ -28353,7 +36867,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (container.kind === SyntaxKind.ComputedPropertyName) { - container = getThisContainer(container, !capturedByArrowFunction, /*includeClassComputedPropertyName*/ false); + container = getThisContainer( + container, + !capturedByArrowFunction, + /*includeClassComputedPropertyName*/ false, + ); thisInComputedPropertyName = true; continue; } @@ -28397,11 +36915,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (!type) { // With noImplicitThis, functions may not reference 'this' if it has type 'any' - const diag = error(node, Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation); + const diag = error( + node, + Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation, + ); if (!isSourceFile(container)) { const outsideThis = tryGetThisTypeAt(container); if (outsideThis && outsideThis !== globalThisType) { - addRelatedInfo(diag, createDiagnosticForNode(container, Diagnostics.An_outer_value_of_this_is_shadowed_by_this_container)); + addRelatedInfo( + diag, + createDiagnosticForNode( + container, + Diagnostics.An_outer_value_of_this_is_shadowed_by_this_container, + ), + ); } } } @@ -28409,11 +36936,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type || anyType; } - function tryGetThisTypeAt(node: Node, includeGlobalThis = true, container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false)): Type | undefined { + function tryGetThisTypeAt( + node: Node, + includeGlobalThis = true, + container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false), + ): Type | undefined { const isInJS = isInJSFile(node); - if (isFunctionLike(container) && - (!isInParameterInitializerBeforeContainingFunction(node) || getThisParameter(container))) { - let thisType = getThisTypeOfDeclaration(container) || isInJS && getTypeForThisExpressionFromJSDoc(container); + if ( + isFunctionLike(container) + && (!isInParameterInitializerBeforeContainingFunction(node) || getThisParameter(container)) + ) { + let thisType = getThisTypeOfDeclaration(container) + || isInJS && getTypeForThisExpressionFromJSDoc(container); // Note: a parameter initializer should refer to class-this unless function-this is explicitly annotated. // If this is a function in a JS file, it might be a class method. if (!thisType) { @@ -28437,7 +36971,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isClassLike(container.parent)) { const symbol = getSymbolOfDeclaration(container.parent); - const type = isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; + const type = isStatic(container) ? getTypeOfSymbol(symbol) + : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; return getFlowTypeOfReference(node, type); } @@ -28458,7 +36993,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getExplicitThisType(node: Expression) { - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); if (isFunctionLike(container)) { const signature = getSignatureFromDeclaration(container); if (signature.thisParameter) { @@ -28467,59 +37006,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isClassLike(container.parent)) { const symbol = getSymbolOfDeclaration(container.parent); - return isStatic(container) ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; + return isStatic(container) ? getTypeOfSymbol(symbol) + : (getDeclaredTypeOfSymbol(symbol) as InterfaceType).thisType!; } } function getClassNameFromPrototypeMethod(container: Node) { // Check if it's the RHS of a x.prototype.y = function [name]() { .... } - if (container.kind === SyntaxKind.FunctionExpression && - isBinaryExpression(container.parent) && - getAssignmentDeclarationKind(container.parent) === AssignmentDeclarationKind.PrototypeProperty) { + if ( + container.kind === SyntaxKind.FunctionExpression + && isBinaryExpression(container.parent) + && getAssignmentDeclarationKind(container.parent) === AssignmentDeclarationKind.PrototypeProperty + ) { // Get the 'x' of 'x.prototype.y = container' - return ((container.parent // x.prototype.y = container - .left as PropertyAccessExpression) // x.prototype.y + return ((container.parent // x.prototype.y = container + .left as PropertyAccessExpression) // x.prototype.y .expression as PropertyAccessExpression) // x.prototype - .expression; // x + .expression; // x } // x.prototype = { method() { } } - else if (container.kind === SyntaxKind.MethodDeclaration && - container.parent.kind === SyntaxKind.ObjectLiteralExpression && - isBinaryExpression(container.parent.parent) && - getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.Prototype) { + else if ( + container.kind === SyntaxKind.MethodDeclaration + && container.parent.kind === SyntaxKind.ObjectLiteralExpression + && isBinaryExpression(container.parent.parent) + && getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.Prototype + ) { return (container.parent.parent.left as PropertyAccessExpression).expression; } // x.prototype = { method: function() { } } - else if (container.kind === SyntaxKind.FunctionExpression && - container.parent.kind === SyntaxKind.PropertyAssignment && - container.parent.parent.kind === SyntaxKind.ObjectLiteralExpression && - isBinaryExpression(container.parent.parent.parent) && - getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.Prototype) { + else if ( + container.kind === SyntaxKind.FunctionExpression + && container.parent.kind === SyntaxKind.PropertyAssignment + && container.parent.parent.kind === SyntaxKind.ObjectLiteralExpression + && isBinaryExpression(container.parent.parent.parent) + && getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.Prototype + ) { return (container.parent.parent.parent.left as PropertyAccessExpression).expression; } // Object.defineProperty(x, "method", { value: function() { } }); // Object.defineProperty(x, "method", { set: (x: () => void) => void }); // Object.defineProperty(x, "method", { get: () => function() { }) }); - else if (container.kind === SyntaxKind.FunctionExpression && - isPropertyAssignment(container.parent) && - isIdentifier(container.parent.name) && - (container.parent.name.escapedText === "value" || container.parent.name.escapedText === "get" || container.parent.name.escapedText === "set") && - isObjectLiteralExpression(container.parent.parent) && - isCallExpression(container.parent.parent.parent) && - container.parent.parent.parent.arguments[2] === container.parent.parent && - getAssignmentDeclarationKind(container.parent.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty) { + else if ( + container.kind === SyntaxKind.FunctionExpression + && isPropertyAssignment(container.parent) + && isIdentifier(container.parent.name) + && (container.parent.name.escapedText === "value" || container.parent.name.escapedText === "get" + || container.parent.name.escapedText === "set") + && isObjectLiteralExpression(container.parent.parent) + && isCallExpression(container.parent.parent.parent) + && container.parent.parent.parent.arguments[2] === container.parent.parent + && getAssignmentDeclarationKind(container.parent.parent.parent) + === AssignmentDeclarationKind.ObjectDefinePrototypeProperty + ) { return (container.parent.parent.parent.arguments[0] as PropertyAccessExpression).expression; } // Object.defineProperty(x, "method", { value() { } }); // Object.defineProperty(x, "method", { set(x: () => void) {} }); // Object.defineProperty(x, "method", { get() { return () => {} } }); - else if (isMethodDeclaration(container) && - isIdentifier(container.name) && - (container.name.escapedText === "value" || container.name.escapedText === "get" || container.name.escapedText === "set") && - isObjectLiteralExpression(container.parent) && - isCallExpression(container.parent.parent) && - container.parent.parent.arguments[2] === container.parent && - getAssignmentDeclarationKind(container.parent.parent) === AssignmentDeclarationKind.ObjectDefinePrototypeProperty) { + else if ( + isMethodDeclaration(container) + && isIdentifier(container.name) + && (container.name.escapedText === "value" || container.name.escapedText === "get" + || container.name.escapedText === "set") + && isObjectLiteralExpression(container.parent) + && isCallExpression(container.parent.parent) + && container.parent.parent.arguments[2] === container.parent + && getAssignmentDeclarationKind(container.parent.parent) + === AssignmentDeclarationKind.ObjectDefinePrototypeProperty + ) { return (container.parent.parent.arguments[0] as PropertyAccessExpression).expression; } } @@ -28536,11 +37090,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean { - return !!findAncestor(node, n => isFunctionLikeDeclaration(n) ? "quit" : n.kind === SyntaxKind.Parameter && n.parent === constructorDecl); + return !!findAncestor( + node, + n => isFunctionLikeDeclaration(n) ? "quit" + : n.kind === SyntaxKind.Parameter && n.parent === constructorDecl, + ); } function checkSuperExpression(node: Node): Type { - const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (node.parent as CallExpression).expression === node; + const isCallExpression = node.parent.kind === SyntaxKind.CallExpression + && (node.parent as CallExpression).expression === node; const immediateContainer = getSuperContainer(node, /*stopOnFunctions*/ true); let container = immediateContainer; @@ -28565,31 +37124,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // class B { // [super.foo()]() {} // } - const current = findAncestor(node, n => n === container ? "quit" : n.kind === SyntaxKind.ComputedPropertyName); + const current = findAncestor( + node, + n => n === container ? "quit" : n.kind === SyntaxKind.ComputedPropertyName, + ); if (current && current.kind === SyntaxKind.ComputedPropertyName) { error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name); } else if (isCallExpression) { - error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors); + error( + node, + Diagnostics + .Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors, + ); } - else if (!container || !container.parent || !(isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression)) { - error(node, Diagnostics.super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions); + else if ( + !container || !container.parent + || !(isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) + ) { + error( + node, + Diagnostics + .super_can_only_be_referenced_in_members_of_derived_classes_or_object_literal_expressions, + ); } else { - error(node, Diagnostics.super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class); + error( + node, + Diagnostics + .super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class, + ); } return errorType; } if (!isCallExpression && immediateContainer!.kind === SyntaxKind.Constructor) { - checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class); + checkThisBeforeSuper( + node, + container, + Diagnostics + .super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class, + ); } if (isStatic(container) || isCallExpression) { nodeCheckFlag = NodeCheckFlags.SuperStatic; - if (!isCallExpression && - languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 && - (isPropertyDeclaration(container) || isClassStaticBlockDeclaration(container))) { + if ( + !isCallExpression + && languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 + && (isPropertyDeclaration(container) || isClassStaticBlockDeclaration(container)) + ) { // for `super.x` or `super[x]` in a static initializer, mark all enclosing // block scope containers so that we can report potential collisions with // `Reflect`. @@ -28683,7 +37267,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (container.parent.kind === SyntaxKind.ObjectLiteralExpression) { if (languageVersion < ScriptTarget.ES2015) { - error(node, Diagnostics.super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher); + error( + node, + Diagnostics + .super_is_only_allowed_in_members_of_object_literal_expressions_when_option_target_is_ES2015_or_higher, + ); return errorType; } else { @@ -28730,21 +37318,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // topmost container must be something that is directly nested in the class declaration\object literal expression if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) { if (isStatic(container)) { - return container.kind === SyntaxKind.MethodDeclaration || - container.kind === SyntaxKind.MethodSignature || - container.kind === SyntaxKind.GetAccessor || - container.kind === SyntaxKind.SetAccessor || - container.kind === SyntaxKind.PropertyDeclaration || - container.kind === SyntaxKind.ClassStaticBlockDeclaration; + return container.kind === SyntaxKind.MethodDeclaration + || container.kind === SyntaxKind.MethodSignature + || container.kind === SyntaxKind.GetAccessor + || container.kind === SyntaxKind.SetAccessor + || container.kind === SyntaxKind.PropertyDeclaration + || container.kind === SyntaxKind.ClassStaticBlockDeclaration; } else { - return container.kind === SyntaxKind.MethodDeclaration || - container.kind === SyntaxKind.MethodSignature || - container.kind === SyntaxKind.GetAccessor || - container.kind === SyntaxKind.SetAccessor || - container.kind === SyntaxKind.PropertyDeclaration || - container.kind === SyntaxKind.PropertySignature || - container.kind === SyntaxKind.Constructor; + return container.kind === SyntaxKind.MethodDeclaration + || container.kind === SyntaxKind.MethodSignature + || container.kind === SyntaxKind.GetAccessor + || container.kind === SyntaxKind.SetAccessor + || container.kind === SyntaxKind.PropertyDeclaration + || container.kind === SyntaxKind.PropertySignature + || container.kind === SyntaxKind.Constructor; } } } @@ -28754,24 +37342,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getContainingObjectLiteral(func: SignatureDeclaration): ObjectLiteralExpression | undefined { - return (func.kind === SyntaxKind.MethodDeclaration || - func.kind === SyntaxKind.GetAccessor || - func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? func.parent : - func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment ? func.parent.parent as ObjectLiteralExpression : - undefined; + return (func.kind === SyntaxKind.MethodDeclaration + || func.kind === SyntaxKind.GetAccessor + || func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression + ? func.parent + : func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment + ? func.parent.parent as ObjectLiteralExpression + : undefined; } function getThisTypeArgument(type: Type): Type | undefined { - return getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target === globalThisType ? getTypeArguments(type as TypeReference)[0] : undefined; + return getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).target === globalThisType + ? getTypeArguments(type as TypeReference)[0] : undefined; } function getThisTypeFromContextualType(type: Type): Type | undefined { return mapType(type, t => { - return t.flags & TypeFlags.Intersection ? forEach((t as IntersectionType).types, getThisTypeArgument) : getThisTypeArgument(t); + return t.flags & TypeFlags.Intersection ? forEach((t as IntersectionType).types, getThisTypeArgument) + : getThisTypeArgument(t); }); } - function getThisTypeOfObjectLiteralFromContextualType(containingLiteral: ObjectLiteralExpression, contextualType: Type | undefined) { + function getThisTypeOfObjectLiteralFromContextualType( + containingLiteral: ObjectLiteralExpression, + contextualType: Type | undefined, + ) { let literal = containingLiteral; let type = contextualType; while (type) { @@ -28815,12 +37410,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // There was no contextual ThisType for the containing object literal, so the contextual type // for 'this' is the non-null form of the contextual type for the containing object literal or // the type of the object literal itself. - return getWidenedType(contextualType ? getNonNullableType(contextualType) : checkExpressionCached(containingLiteral)); + return getWidenedType( + contextualType ? getNonNullableType(contextualType) : checkExpressionCached(containingLiteral), + ); } // In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the // contextual type for 'this' is 'obj'. const parent = walkUpParenthesizedExpressions(func.parent); - if (parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + parent.kind === SyntaxKind.BinaryExpression + && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { const target = (parent as BinaryExpression).left; if (isAccessExpression(target)) { const { expression } = target; @@ -28850,28 +37450,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const args = getEffectiveCallArguments(iife); const indexOfParameter = func.parameters.indexOf(parameter); if (parameter.dotDotDotToken) { - return getSpreadArgumentType(args, indexOfParameter, args.length, anyType, /*context*/ undefined, CheckMode.Normal); + return getSpreadArgumentType( + args, + indexOfParameter, + args.length, + anyType, + /*context*/ undefined, + CheckMode.Normal, + ); } const links = getNodeLinks(iife); const cached = links.resolvedSignature; links.resolvedSignature = anySignature; - const type = indexOfParameter < args.length ? - getWidenedLiteralType(checkExpression(args[indexOfParameter])) : - parameter.initializer ? undefined : undefinedWideningType; + const type = indexOfParameter < args.length + ? getWidenedLiteralType(checkExpression(args[indexOfParameter])) + : parameter.initializer ? undefined : undefinedWideningType; links.resolvedSignature = cached; return type; } const contextualSignature = getContextualSignature(func); if (contextualSignature) { const index = func.parameters.indexOf(parameter) - (getThisParameter(func) ? 1 : 0); - return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter ? - getRestTypeAtPosition(contextualSignature, index) : - tryGetTypeAtPosition(contextualSignature, index); + return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter + ? getRestTypeAtPosition(contextualSignature, index) + : tryGetTypeAtPosition(contextualSignature, index); } } - function getContextualTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { - const typeNode = getEffectiveTypeAnnotationNode(declaration) || (isInJSFile(declaration) ? tryGetJSDocSatisfiesTypeNode(declaration) : undefined); + function getContextualTypeForVariableLikeDeclaration( + declaration: VariableLikeDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { + const typeNode = getEffectiveTypeAnnotationNode(declaration) + || (isInJSFile(declaration) ? tryGetJSDocSatisfiesTypeNode(declaration) : undefined); if (typeNode) { return getTypeFromTypeNode(typeNode); } @@ -28884,15 +37495,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isStatic(declaration)) { return getContextualTypeForStaticPropertyDeclaration(declaration, contextFlags); } - // By default, do nothing and return undefined - only the above cases have context implied by a parent + // By default, do nothing and return undefined - only the above cases have context implied by a parent } } - function getContextualTypeForBindingElement(declaration: BindingElement, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForBindingElement( + declaration: BindingElement, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const parent = declaration.parent.parent; const name = declaration.propertyName || declaration.name; - const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) || - parent.kind !== SyntaxKind.BindingElement && parent.initializer && checkDeclarationInitializer(parent, declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal); + const parentType = getContextualTypeForVariableLikeDeclaration(parent, contextFlags) + || parent.kind !== SyntaxKind.BindingElement && parent.initializer + && checkDeclarationInitializer( + parent, + declaration.dotDotDotToken ? CheckMode.RestBindingElement : CheckMode.Normal, + ); if (!parentType || isBindingPattern(name) || isComputedNonLiteralName(name)) return undefined; if (parent.name.kind === SyntaxKind.ArrayBindingPattern) { const index = indexOfNode(declaration.parent.elements, declaration); @@ -28906,7 +37524,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getContextualTypeForStaticPropertyDeclaration(declaration: PropertyDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForStaticPropertyDeclaration( + declaration: PropertyDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const parentType = isExpression(declaration.parent) && getContextualType(declaration.parent, contextFlags); if (!parentType) return undefined; return getTypeOfPropertyOfContextualType(parentType, getSymbolOfDeclaration(declaration).escapedName); @@ -28920,21 +37541,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the contextual type of an initializer expression is the type implied by the binding pattern. // Otherwise, in a binding pattern inside a variable or parameter declaration, // the contextual type of an initializer expression is the type annotation of the containing declaration, if present. - function getContextualTypeForInitializerExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForInitializerExpression( + node: Expression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const declaration = node.parent as VariableLikeDeclaration; if (hasInitializer(declaration) && node === declaration.initializer) { const result = getContextualTypeForVariableLikeDeclaration(declaration, contextFlags); if (result) { return result; } - if (!(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name) && declaration.name.elements.length > 0) { - return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false); + if ( + !(contextFlags! & ContextFlags.SkipBindingPatterns) && isBindingPattern(declaration.name) + && declaration.name.elements.length > 0 + ) { + return getTypeFromBindingPattern( + declaration.name, + /*includePatternInType*/ true, + /*reportErrors*/ false, + ); } } return undefined; } - function getContextualTypeForReturnExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForReturnExpression( + node: Expression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const func = getContainingFunction(node); if (func) { let contextualReturnType = getContextualReturnType(func, contextFlags); @@ -28943,9 +37577,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; if (contextualReturnType.flags & TypeFlags.Union) { - contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator)); + contextualReturnType = filterType( + contextualReturnType, + type => + !!getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + type, + isAsyncGenerator, + ), + ); } - const iterationReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, contextualReturnType, (functionFlags & FunctionFlags.Async) !== 0); + const iterationReturnType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + contextualReturnType, + (functionFlags & FunctionFlags.Async) !== 0, + ); if (!iterationReturnType) { return undefined; } @@ -28956,7 +37602,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (functionFlags & FunctionFlags.Async) { // Async function or AsyncGenerator function // Get the awaited type without the `Awaited` alias const contextualAwaitedType = mapType(contextualReturnType, getAwaitedTypeNoAlias); - return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); + return contextualAwaitedType + && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); } return contextualReturnType; // Regular function or Generator function @@ -28965,16 +37612,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getContextualTypeForAwaitOperand(node: AwaitExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForAwaitOperand( + node: AwaitExpression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const contextualType = getContextualType(node, contextFlags); if (contextualType) { const contextualAwaitedType = getAwaitedTypeNoAlias(contextualType); - return contextualAwaitedType && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); + return contextualAwaitedType + && getUnionType([contextualAwaitedType, createPromiseLikeType(contextualAwaitedType)]); } return undefined; } - function getContextualTypeForYieldOperand(node: YieldExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForYieldOperand( + node: YieldExpression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const func = getContainingFunction(node); if (func) { const functionFlags = getFunctionFlags(func); @@ -28982,11 +37636,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (contextualReturnType) { const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; if (!node.asteriskToken && contextualReturnType.flags & TypeFlags.Union) { - contextualReturnType = filterType(contextualReturnType, type => !!getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator)); + contextualReturnType = filterType( + contextualReturnType, + type => + !!getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + type, + isAsyncGenerator, + ), + ); } return node.asteriskToken ? contextualReturnType - : getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, contextualReturnType, isAsyncGenerator); + : getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Yield, + contextualReturnType, + isAsyncGenerator, + ); } } @@ -29020,7 +37686,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getContextualReturnType(functionDecl: SignatureDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualReturnType( + functionDecl: SignatureDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { // If the containing function has a return type annotation, is a constructor, or is a get accessor whose // corresponding set accessor has a type annotation, return statements in the function are contextually typed const returnType = getReturnTypeFromAnnotation(functionDecl); @@ -29049,22 +37718,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getContextualTypeForArgumentAtIndex(callTarget: CallLikeExpression, argIndex: number): Type { if (isImportCall(callTarget)) { - return argIndex === 0 ? stringType : - argIndex === 1 ? getGlobalImportCallOptionsType(/*reportErrors*/ false) : - anyType; + return argIndex === 0 ? stringType + : argIndex === 1 ? getGlobalImportCallOptionsType(/*reportErrors*/ false) + : anyType; } // If we're already in the process of resolving the given signature, don't resolve again as // that could cause infinite recursion. Instead, return anySignature. - const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget); + const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature + : getResolvedSignature(callTarget); if (isJsxOpeningLikeElement(callTarget) && argIndex === 0) { return getEffectiveFirstArgumentForJsxSignature(signature, callTarget); } const restIndex = signature.parameters.length - 1; - return signatureHasRestParameter(signature) && argIndex >= restIndex ? - getIndexedAccessType(getTypeOfSymbol(signature.parameters[restIndex]), getNumberLiteralType(argIndex - restIndex), AccessFlags.Contextual) : - getTypeAtPosition(signature, argIndex); + return signatureHasRestParameter(signature) && argIndex >= restIndex + ? getIndexedAccessType( + getTypeOfSymbol(signature.parameters[restIndex]), + getNumberLiteralType(argIndex - restIndex), + AccessFlags.Contextual, + ) + : getTypeAtPosition(signature, argIndex); } function getContextualTypeForDecorator(decorator: Decorator): Type | undefined { @@ -29072,7 +37746,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return signature ? getOrCreateTypeFromSignature(signature) : undefined; } - function getContextualTypeForSubstitutionExpression(template: TemplateExpression, substitutionExpression: Expression) { + function getContextualTypeForSubstitutionExpression( + template: TemplateExpression, + substitutionExpression: Expression, + ) { if (template.parent.kind === SyntaxKind.TaggedTemplateExpression) { return getContextualTypeForArgument(template.parent as TaggedTemplateExpression, substitutionExpression); } @@ -29080,7 +37757,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getContextualTypeForBinaryOperand(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForBinaryOperand( + node: Expression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const binaryExpression = node.parent as BinaryExpression; const { left, operatorToken, right } = binaryExpression; switch (operatorToken.kind) { @@ -29097,8 +37777,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // by the type of the left operand, except for the special case of Javascript declarations of the form // `namespace.prop = namespace.prop || {}`. const type = getContextualType(binaryExpression, contextFlags); - return node === right && (type && type.pattern || !type && !isDefaultedExpandoInitializer(binaryExpression)) ? - getTypeOfExpression(left) : type; + return node === right + && (type && type.pattern || !type && !isDefaultedExpandoInitializer(binaryExpression)) + ? getTypeOfExpression(left) : type; case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.CommaToken: return node === right ? getContextualType(binaryExpression, contextFlags) : undefined; @@ -29111,7 +37792,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Try to find a resolved symbol for an expression without also resolving its type, as * getSymbolAtLocation would (as that could be reentrant into contextual typing) */ - function getSymbolForExpression(e: Expression) { + function getSymbolForExpression(e: Expression) { if (canHaveSymbol(e) && e.symbol) { return e.symbol; } @@ -29120,7 +37801,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isPropertyAccessExpression(e)) { const lhsType = getTypeOfExpression(e.expression); - return isPrivateIdentifier(e.name) ? tryGetPrivateIdentifierPropertyOfType(lhsType, e.name) : getPropertyOfType(lhsType, e.name.escapedText); + return isPrivateIdentifier(e.name) ? tryGetPrivateIdentifierPropertyOfType(lhsType, e.name) + : getPropertyOfType(lhsType, e.name.escapedText); } if (isElementAccessExpression(e)) { const propType = checkExpressionCached(e.argumentExpression); @@ -29151,8 +37833,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We avoid calling back into `getTypeOfExpression` and reentering contextual typing to avoid a bogus circularity error in that case. if (decl && (isPropertyDeclaration(decl) || isPropertySignature(decl))) { const overallAnnotation = getEffectiveTypeAnnotationNode(decl); - return (overallAnnotation && instantiateType(getTypeFromTypeNode(overallAnnotation), getSymbolLinks(lhsSymbol).mapper)) || - (isPropertyDeclaration(decl) ? decl.initializer && getTypeOfExpression(binaryExpression.left) : undefined); + return (overallAnnotation + && instantiateType(getTypeFromTypeNode(overallAnnotation), getSymbolLinks(lhsSymbol).mapper)) + || (isPropertyDeclaration(decl) ? decl.initializer && getTypeOfExpression(binaryExpression.left) + : undefined); } if (kind === AssignmentDeclarationKind.None) { return getTypeOfExpression(binaryExpression.left); @@ -29179,9 +37863,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (isIdentifier(lhs.expression)) { const id = lhs.expression; - const parentSymbol = resolveName(id, id.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, id.escapedText, /*isUse*/ true); + const parentSymbol = resolveName( + id, + id.escapedText, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + id.escapedText, + /*isUse*/ true, + ); if (parentSymbol) { - const annotated = parentSymbol.valueDeclaration && getEffectiveTypeAnnotationNode(parentSymbol.valueDeclaration); + const annotated = parentSymbol.valueDeclaration + && getEffectiveTypeAnnotationNode(parentSymbol.valueDeclaration); if (annotated) { const nameStr = getElementOrPropertyAccessName(lhs); if (nameStr !== undefined) { @@ -29191,7 +37883,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } } - return isInJSFile(decl) || decl === binaryExpression.left ? undefined : getTypeOfExpression(binaryExpression.left); + return isInJSFile(decl) || decl === binaryExpression.left ? undefined + : getTypeOfExpression(binaryExpression.left); } case AssignmentDeclarationKind.ExportsProperty: case AssignmentDeclarationKind.Prototype: @@ -29199,7 +37892,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case AssignmentDeclarationKind.ModuleExports: let valueDeclaration: Declaration | undefined; if (kind !== AssignmentDeclarationKind.ModuleExports) { - valueDeclaration = canHaveSymbol(binaryExpression.left) ? binaryExpression.left.symbol?.valueDeclaration : undefined; + valueDeclaration = canHaveSymbol(binaryExpression.left) + ? binaryExpression.left.symbol?.valueDeclaration : undefined; } valueDeclaration ||= binaryExpression.symbol?.valueDeclaration; const annotated = valueDeclaration && getEffectiveTypeAnnotationNode(valueDeclaration); @@ -29213,15 +37907,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function isPossiblyAliasedThisProperty(declaration: BinaryExpression, kind = getAssignmentDeclarationKind(declaration)) { + function isPossiblyAliasedThisProperty( + declaration: BinaryExpression, + kind = getAssignmentDeclarationKind(declaration), + ) { if (kind === AssignmentDeclarationKind.ThisProperty) { return true; } - if (!isInJSFile(declaration) || kind !== AssignmentDeclarationKind.Property || !isIdentifier((declaration.left as AccessExpression).expression)) { + if ( + !isInJSFile(declaration) || kind !== AssignmentDeclarationKind.Property + || !isIdentifier((declaration.left as AccessExpression).expression) + ) { return false; } const name = ((declaration.left as AccessExpression).expression as Identifier).escapedText; - const symbol = resolveName(declaration.left, name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true, /*excludeGlobals*/ true); + const symbol = resolveName( + declaration.left, + name, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + /*excludeGlobals*/ true, + ); return isThisInitializedDeclaration(symbol?.valueDeclaration); } @@ -29237,17 +37945,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } const thisAccess = cast(binaryExpression.left, isAccessExpression); - if (!isObjectLiteralMethod(getThisContainer(thisAccess.expression, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false))) { + if ( + !isObjectLiteralMethod( + getThisContainer( + thisAccess.expression, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ), + ) + ) { return undefined; } const thisType = checkThisExpression(thisAccess.expression); const nameStr = getElementOrPropertyAccessName(thisAccess); return nameStr !== undefined && getTypeOfPropertyOfContextualType(thisType, nameStr) || undefined; - } function isCircularMappedProperty(symbol: Symbol) { - return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(symbol as MappedSymbol).links.type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0); + return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(symbol as MappedSymbol).links.type + && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0); } function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { @@ -29263,15 +37979,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (t.flags & TypeFlags.StructuredType) { const prop = getPropertyOfType(t, name); if (prop) { - return isCircularMappedProperty(prop) ? undefined : removeMissingType(getTypeOfSymbol(prop), !!(prop && prop.flags & SymbolFlags.Optional)); + return isCircularMappedProperty(prop) ? undefined + : removeMissingType(getTypeOfSymbol(prop), !!(prop && prop.flags & SymbolFlags.Optional)); } if (isTupleType(t) && isNumericLiteralName(name) && +name >= 0) { - const restType = getElementTypeOfSliceOfTupleType(t, t.target.fixedLength, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true); + const restType = getElementTypeOfSliceOfTupleType( + t, + t.target.fixedLength, + /*endSkipCount*/ 0, + /*writing*/ false, + /*noReductions*/ true, + ); if (restType) { return restType; } } - return findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType || getStringLiteralType(unescapeLeadingUnderscores(name)))?.type; + return findApplicableIndexInfo( + getIndexInfosOfStructuredType(t), + nameType || getStringLiteralType(unescapeLeadingUnderscores(name)), + )?.type; } return undefined; }, /*noReductions*/ true); @@ -29280,7 +38006,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of // the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one // exists. Otherwise, it is the type of the string index signature in T, if one exists. - function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForObjectLiteralMethod( + node: MethodDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { Debug.assert(isObjectLiteralMethod(node)); if (node.flags & NodeFlags.InWithStatement) { // We cannot answer semantic questions within a with block, do not proceed any further @@ -29289,9 +38018,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getContextualTypeForObjectLiteralElement(node, contextFlags); } - function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike, contextFlags: ContextFlags | undefined) { + function getContextualTypeForObjectLiteralElement( + element: ObjectLiteralElementLike, + contextFlags: ContextFlags | undefined, + ) { const objectLiteral = element.parent as ObjectLiteralExpression; - const propertyAssignmentType = isPropertyAssignment(element) && getContextualTypeForVariableLikeDeclaration(element, contextFlags); + const propertyAssignmentType = isPropertyAssignment(element) + && getContextualTypeForVariableLikeDeclaration(element, contextFlags); if (propertyAssignmentType) { return propertyAssignmentType; } @@ -29308,7 +38041,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const name = getNameOfDeclaration(element); if (name && isComputedPropertyName(name)) { const exprType = checkExpression(name.expression); - const propType = isTypeUsableAsPropertyName(exprType) && getTypeOfPropertyOfContextualType(type, getPropertyNameFromType(exprType)); + const propType = isTypeUsableAsPropertyName(exprType) + && getTypeOfPropertyOfContextualType(type, getPropertyNameFromType(exprType)); if (propType) { return propType; } @@ -29317,7 +38051,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (element.name) { const nameType = getLiteralTypeFromPropertyName(element.name); // We avoid calling getApplicableIndexInfo here because it performs potentially expensive intersection reduction. - return mapType(type, t => findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType)?.type, /*noReductions*/ true); + return mapType( + type, + t => findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType)?.type, + /*noReductions*/ true, + ); } } return undefined; @@ -29334,47 +38072,80 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return { first, last }; } - function getContextualTypeForElementExpression(type: Type | undefined, index: number, length?: number, firstSpreadIndex?: number, lastSpreadIndex?: number): Type | undefined { + function getContextualTypeForElementExpression( + type: Type | undefined, + index: number, + length?: number, + firstSpreadIndex?: number, + lastSpreadIndex?: number, + ): Type | undefined { return type && mapType(type, t => { if (isTupleType(t)) { // If index is before any spread element and within the fixed part of the contextual tuple type, return // the type of the contextual tuple element. if ((firstSpreadIndex === undefined || index < firstSpreadIndex) && index < t.target.fixedLength) { - return removeMissingType(getTypeArguments(t)[index], !!(t.target.elementFlags[index] && ElementFlags.Optional)); + return removeMissingType( + getTypeArguments(t)[index], + !!(t.target.elementFlags[index] && ElementFlags.Optional), + ); } // When the length is known and the index is after all spread elements we compute the offset from the element // to the end and the number of ending fixed elements in the contextual tuple type. - const offset = length !== undefined && (lastSpreadIndex === undefined || index > lastSpreadIndex) ? length - index : 0; - const fixedEndLength = offset > 0 && t.target.hasRestElement ? getEndElementCount(t.target, ElementFlags.Fixed) : 0; + const offset = length !== undefined && (lastSpreadIndex === undefined || index > lastSpreadIndex) + ? length - index : 0; + const fixedEndLength = offset > 0 && t.target.hasRestElement + ? getEndElementCount(t.target, ElementFlags.Fixed) : 0; // If the offset is within the ending fixed part of the contextual tuple type, return the type of the contextual // tuple element. if (offset > 0 && offset <= fixedEndLength) { return getTypeArguments(t)[getTypeReferenceArity(t) - offset]; } // Return a union of the possible contextual element types with no subtype reduction. - return getElementTypeOfSliceOfTupleType(t, - firstSpreadIndex === undefined ? t.target.fixedLength : Math.min(t.target.fixedLength, firstSpreadIndex), - length === undefined || lastSpreadIndex === undefined ? fixedEndLength : Math.min(fixedEndLength, length - lastSpreadIndex), - /*writing*/ false, /*noReductions*/ true); + return getElementTypeOfSliceOfTupleType( + t, + firstSpreadIndex === undefined ? t.target.fixedLength + : Math.min(t.target.fixedLength, firstSpreadIndex), + length === undefined || lastSpreadIndex === undefined ? fixedEndLength + : Math.min(fixedEndLength, length - lastSpreadIndex), + /*writing*/ false, + /*noReductions*/ true, + ); } // If element index is known and a contextual property with that name exists, return it. Otherwise return the // iterated or element type of the contextual type. - return (!firstSpreadIndex || index < firstSpreadIndex) && getTypeOfPropertyOfContextualType(t, "" + index as __String) || - getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false); + return (!firstSpreadIndex || index < firstSpreadIndex) + && getTypeOfPropertyOfContextualType(t, "" + index as __String) + || getIteratedTypeOrElementType( + IterationUse.Element, + t, + undefinedType, + /*errorNode*/ undefined, + /*checkAssignability*/ false, + ); }, /*noReductions*/ true); } // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. - function getContextualTypeForConditionalOperand(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForConditionalOperand( + node: Expression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const conditional = node.parent as ConditionalExpression; - return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional, contextFlags) : undefined; + return node === conditional.whenTrue || node === conditional.whenFalse + ? getContextualType(conditional, contextFlags) : undefined; } - function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild, contextFlags: ContextFlags | undefined) { + function getContextualTypeForChildJsxExpression( + node: JsxElement, + child: JsxChild, + contextFlags: ContextFlags | undefined, + ) { const attributesType = getApparentTypeOfContextualType(node.openingElement.attributes, contextFlags); // JSX expression is in children of JSX Element, we will look for an "children" attribute (we get the name from JSX.ElementAttributesProperty) const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - if (!(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "")) { + if ( + !(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "") + ) { return undefined; } const realChildren = getSemanticJsxChildren(node.children); @@ -29390,16 +38161,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }, /*noReductions*/ true)); } - function getContextualTypeForJsxExpression(node: JsxExpression, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForJsxExpression( + node: JsxExpression, + contextFlags: ContextFlags | undefined, + ): Type | undefined { const exprParent = node.parent; return isJsxAttributeLike(exprParent) ? getContextualType(node, contextFlags) : isJsxElement(exprParent) - ? getContextualTypeForChildJsxExpression(exprParent, node, contextFlags) - : undefined; + ? getContextualTypeForChildJsxExpression(exprParent, node, contextFlags) + : undefined; } - function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute, contextFlags: ContextFlags | undefined): Type | undefined { + function getContextualTypeForJsxAttribute( + attribute: JsxAttribute | JsxSpreadAttribute, + contextFlags: ContextFlags | undefined, + ): Type | undefined { // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type // which is a type of the parameter of the signature we are trying out. // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName @@ -29433,47 +38210,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ParenthesizedExpression: - return isPossiblyDiscriminantValue((node as PropertyAccessExpression | ParenthesizedExpression).expression); + return isPossiblyDiscriminantValue( + (node as PropertyAccessExpression | ParenthesizedExpression).expression, + ); case SyntaxKind.JsxExpression: - return !(node as JsxExpression).expression || isPossiblyDiscriminantValue((node as JsxExpression).expression!); + return !(node as JsxExpression).expression + || isPossiblyDiscriminantValue((node as JsxExpression).expression!); } return false; } function discriminateContextualTypeByObjectMembers(node: ObjectLiteralExpression, contextualType: UnionType) { - return getMatchingUnionConstituentForObjectLiteral(contextualType, node) || discriminateTypeByDiscriminableItems(contextualType, - concatenate( - map( - filter(node.properties, (p): p is PropertyAssignment | ShorthandPropertyAssignment => { - if (!p.symbol) { + return getMatchingUnionConstituentForObjectLiteral(contextualType, node) + || discriminateTypeByDiscriminableItems( + contextualType, + concatenate( + map( + filter(node.properties, (p): p is PropertyAssignment | ShorthandPropertyAssignment => { + if (!p.symbol) { + return false; + } + if (p.kind === SyntaxKind.PropertyAssignment) { + return isPossiblyDiscriminantValue(p.initializer) + && isDiscriminantProperty(contextualType, p.symbol.escapedName); + } + if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { + return isDiscriminantProperty(contextualType, p.symbol.escapedName); + } return false; - } - if (p.kind === SyntaxKind.PropertyAssignment) { - return isPossiblyDiscriminantValue(p.initializer) && isDiscriminantProperty(contextualType, p.symbol.escapedName); - } - if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { - return isDiscriminantProperty(contextualType, p.symbol.escapedName); - } - return false; - }), - prop => ([() => getContextFreeTypeOfExpression(prop.kind === SyntaxKind.PropertyAssignment ? prop.initializer : prop.name), prop.symbol.escapedName] as const) + }), + prop => ([ + () => + getContextFreeTypeOfExpression( + prop.kind === SyntaxKind.PropertyAssignment ? prop.initializer : prop.name, + ), + prop.symbol.escapedName, + ] as const), + ), + map( + filter( + getPropertiesOfType(contextualType), + s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members + && !node.symbol.members.has(s.escapedName) + && isDiscriminantProperty(contextualType, s.escapedName), + ), + s => [() => undefinedType, s.escapedName] as const, + ), ), - map( - filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)), - s => [() => undefinedType, s.escapedName] as const - ) - ), - isTypeAssignableTo - ); + isTypeAssignableTo, + ); } function discriminateContextualTypeByJSXAttributes(node: JsxAttributes, contextualType: UnionType) { const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); - return discriminateTypeByDiscriminableItems(contextualType, + return discriminateTypeByDiscriminableItems( + contextualType, concatenate( map( - filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute && isDiscriminantProperty(contextualType, p.symbol.escapedName) && (!p.initializer || isPossiblyDiscriminantValue(p.initializer))), - prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as const) + filter( + node.properties, + p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute + && isDiscriminantProperty(contextualType, p.symbol.escapedName) + && (!p.initializer || isPossiblyDiscriminantValue(p.initializer)), + ), + prop => ([ + !(prop as JsxAttribute).initializer ? (() => trueType) + : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), + prop.symbol.escapedName, + ] as const), ), map( filter(getPropertiesOfType(contextualType), s => { @@ -29481,26 +38285,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } const element = node.parent.parent; - if (s.escapedName === jsxChildrenPropertyName && isJsxElement(element) && getSemanticJsxChildren(element.children).length) { + if ( + s.escapedName === jsxChildrenPropertyName && isJsxElement(element) + && getSemanticJsxChildren(element.children).length + ) { return false; } - return !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName); + return !node.symbol.members.has(s.escapedName) + && isDiscriminantProperty(contextualType, s.escapedName); }), - s => [() => undefinedType, s.escapedName] as const - ) + s => [() => undefinedType, s.escapedName] as const, + ), ), - isTypeAssignableTo + isTypeAssignableTo, ); } // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily // be "pushed" onto a node using the contextualType property. - function getApparentTypeOfContextualType(node: Expression | MethodDeclaration, contextFlags: ContextFlags | undefined): Type | undefined { - const contextualType = isObjectLiteralMethod(node) ? - getContextualTypeForObjectLiteralMethod(node, contextFlags) : - getContextualType(node, contextFlags); + function getApparentTypeOfContextualType( + node: Expression | MethodDeclaration, + contextFlags: ContextFlags | undefined, + ): Type | undefined { + const contextualType = isObjectLiteralMethod(node) + ? getContextualTypeForObjectLiteralMethod(node, contextFlags) + : getContextualType(node, contextFlags); const instantiatedType = instantiateContextualType(contextualType, node, contextFlags); - if (instantiatedType && !(contextFlags && contextFlags & ContextFlags.NoConstraints && instantiatedType.flags & TypeFlags.TypeVariable)) { + if ( + instantiatedType + && !(contextFlags && contextFlags & ContextFlags.NoConstraints + && instantiatedType.flags & TypeFlags.TypeVariable) + ) { const apparentType = mapType( instantiatedType, // When obtaining apparent type of *contextual* type we don't want to get apparent type of mapped types. @@ -29508,23 +38323,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and thus it would prevent `getTypeOfPropertyOfContextualType` from obtaining per-position contextual type for elements of array literal expressions. // Apparent type of other mapped types is already the mapped type itself so we can just avoid calling `getApparentType` here for all mapped types. t => getObjectFlags(t) & ObjectFlags.Mapped ? t : getApparentType(t), - /*noReductions*/ true + /*noReductions*/ true, ); - return apparentType.flags & TypeFlags.Union && isObjectLiteralExpression(node) ? discriminateContextualTypeByObjectMembers(node, apparentType as UnionType) : - apparentType.flags & TypeFlags.Union && isJsxAttributes(node) ? discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType) : - apparentType; + return apparentType.flags & TypeFlags.Union && isObjectLiteralExpression(node) + ? discriminateContextualTypeByObjectMembers(node, apparentType as UnionType) + : apparentType.flags & TypeFlags.Union && isJsxAttributes(node) + ? discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType) + : apparentType; } } // If the given contextual type contains instantiable types and if a mapper representing // return type inferences is available, instantiate those types using that mapper. - function instantiateContextualType(contextualType: Type | undefined, node: Node, contextFlags: ContextFlags | undefined): Type | undefined { + function instantiateContextualType( + contextualType: Type | undefined, + node: Node, + contextFlags: ContextFlags | undefined, + ): Type | undefined { if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) { const inferenceContext = getInferenceContext(node); // If no inferences have been made, and none of the type parameters for which we are inferring // specify default types, nothing is gained from instantiating as type parameters would just be // replaced with their constraints similar to the apparent type. - if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { + if ( + inferenceContext && contextFlags! & ContextFlags.Signature + && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault) + ) { // For contextual signatures we incorporate all inferences made so far, e.g. from return // types as well as arguments to the left in a function call. return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); @@ -29535,9 +38359,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the 'boolean' type from the contextual type such that contextually typed boolean // literals actually end up widening to 'boolean' (see #48363). const type = instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper); - return type.flags & TypeFlags.Union && containsType((type as UnionType).types, regularFalseType) && containsType((type as UnionType).types, regularTrueType) ? - filterType(type, t => t !== regularFalseType && t !== regularTrueType) : - type; + return type.flags & TypeFlags.Union && containsType((type as UnionType).types, regularFalseType) + && containsType((type as UnionType).types, regularTrueType) + ? filterType(type, t => t !== regularFalseType && t !== regularTrueType) + : type; } } return contextualType; @@ -29551,10 +38376,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return instantiateType(type, mapper); } if (type.flags & TypeFlags.Union) { - return getUnionType(map((type as UnionType).types, t => instantiateInstantiableTypes(t, mapper)), UnionReduction.None); + return getUnionType( + map((type as UnionType).types, t => instantiateInstantiableTypes(t, mapper)), + UnionReduction.None, + ); } if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(map((type as IntersectionType).types, t => instantiateInstantiableTypes(t, mapper))); + return getIntersectionType( + map((type as IntersectionType).types, t => instantiateInstantiableTypes(t, mapper)), + ); } return type; } @@ -29609,20 +38439,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getContextualTypeForDecorator(parent as Decorator); case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: - return isConstTypeReference((parent as AssertionExpression).type) ? getContextualType(parent as AssertionExpression, contextFlags) : getTypeFromTypeNode((parent as AssertionExpression).type); + return isConstTypeReference((parent as AssertionExpression).type) + ? getContextualType(parent as AssertionExpression, contextFlags) + : getTypeFromTypeNode((parent as AssertionExpression).type); case SyntaxKind.BinaryExpression: return getContextualTypeForBinaryOperand(node, contextFlags); case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - return getContextualTypeForObjectLiteralElement(parent as PropertyAssignment | ShorthandPropertyAssignment, contextFlags); + return getContextualTypeForObjectLiteralElement( + parent as PropertyAssignment | ShorthandPropertyAssignment, + contextFlags, + ); case SyntaxKind.SpreadAssignment: return getContextualType(parent.parent as ObjectLiteralExpression, contextFlags); case SyntaxKind.ArrayLiteralExpression: { const arrayLiteral = parent as ArrayLiteralExpression; const type = getApparentTypeOfContextualType(arrayLiteral, contextFlags); const elementIndex = indexOfNode(arrayLiteral.elements, node); - const spreadIndices = getNodeLinks(arrayLiteral).spreadIndices ??= getSpreadIndices(arrayLiteral.elements); - return getContextualTypeForElementExpression(type, elementIndex, arrayLiteral.elements.length, spreadIndices.first, spreadIndices.last); + const spreadIndices = getNodeLinks(arrayLiteral).spreadIndices ??= getSpreadIndices( + arrayLiteral.elements, + ); + return getContextualTypeForElementExpression( + type, + elementIndex, + arrayLiteral.elements.length, + spreadIndices.first, + spreadIndices.last, + ); } case SyntaxKind.ConditionalExpression: return getContextualTypeForConditionalOperand(node, contextFlags); @@ -29702,7 +38545,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) { + function getContextualJsxElementAttributesType( + node: JsxOpeningLikeElement, + contextFlags: ContextFlags | undefined, + ) { if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) { const index = findContextualNode(node.parent, /*includeCaches*/ !contextFlags); if (index >= 0) { @@ -29774,11 +38620,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return tagType; } - function getJsxManagedAttributesFromLocatedAttributes(context: JsxOpeningLikeElement, ns: Symbol, attributesType: Type) { + function getJsxManagedAttributesFromLocatedAttributes( + context: JsxOpeningLikeElement, + ns: Symbol, + attributesType: Type, + ) { const managedSym = getJsxLibraryManagedAttributes(ns); if (managedSym) { const ctorType = getStaticTypeOfReferencedJsxConstructor(context); - const result = instantiateAliasOrInterfaceWithDefaults(managedSym, isInJSFile(context), ctorType, attributesType); + const result = instantiateAliasOrInterfaceWithDefaults( + managedSym, + isInJSFile(context), + ctorType, + attributesType, + ); if (result) { return result; } @@ -29793,15 +38648,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If there is no type ElementAttributesProperty, return the type of the first parameter of the signature, which should be the props type ? getTypeOfFirstParameterOfSignatureWithFallback(sig, unknownType) : forcedLookupLocation === "" - // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead - ? getReturnTypeOfSignature(sig) - // Otherwise get the type of the property on the signature return type - : getJsxPropsTypeForSignatureFromMember(sig, forcedLookupLocation); + // If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead + ? getReturnTypeOfSignature(sig) + // Otherwise get the type of the property on the signature return type + : getJsxPropsTypeForSignatureFromMember(sig, forcedLookupLocation); if (!attributesType) { // There is no property named 'props' on this instance type if (!!forcedLookupLocation && !!length(context.attributes.properties)) { - error(context, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(forcedLookupLocation)); + error( + context, + Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, + unescapeLeadingUnderscores(forcedLookupLocation), + ); } return unknownType; } @@ -29822,8 +38681,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let libraryManagedAttributeType: Type; if (typeParams) { // apply JSX.IntrinsicClassElements - const inferredArgs = fillMissingTypeArguments([hostClassType], typeParams, getMinTypeArgumentCount(typeParams), isInJSFile(context)); - libraryManagedAttributeType = instantiateType(intrinsicClassAttribs, createTypeMapper(typeParams, inferredArgs)); + const inferredArgs = fillMissingTypeArguments( + [hostClassType], + typeParams, + getMinTypeArgumentCount(typeParams), + isInJSFile(context), + ); + libraryManagedAttributeType = instantiateType( + intrinsicClassAttribs, + createTypeMapper(typeParams, inferredArgs), + ); } // or JSX.IntrinsicClassElements has no generics. else libraryManagedAttributeType = intrinsicClassAttribs; @@ -29845,12 +38712,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { signatures, (left: Signature | undefined, right) => left === right || !left ? left - : compareTypeParametersIdentical(left.typeParameters, right!.typeParameters) ? combineSignaturesOfIntersectionMembers(left, right!) - : undefined) + : compareTypeParametersIdentical(left.typeParameters, right!.typeParameters) + ? combineSignaturesOfIntersectionMembers(left, right!) + : undefined, + ) : undefined; } - function combineIntersectionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { + function combineIntersectionThisParam( + left: Symbol | undefined, + right: Symbol | undefined, + mapper: TypeMapper | undefined, + ): Symbol | undefined { if (!left || !right) { return left || right; } @@ -29867,7 +38740,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const longest = leftCount >= rightCount ? left : right; const shorter = longest === left ? right : left; const longestCount = longest === left ? leftCount : rightCount; - const eitherHasEffectiveRest = (hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right)); + const eitherHasEffectiveRest = hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right); const needsExtraRestElement = eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); const params = new Array(longestCount + (needsExtraRestElement ? 1 : 0)); for (let i = 0; i < longestCount; i++) { @@ -29885,13 +38758,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); - const paramName = leftName === rightName ? leftName : - !leftName ? rightName : - !rightName ? leftName : - undefined; + const paramName = leftName === rightName ? leftName + : !leftName ? rightName + : !rightName ? leftName + : undefined; const paramSymbol = createSymbol( SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), - paramName || `arg${i}` as __String + paramName || `arg${i}` as __String, ); paramSymbol.links.type = isRestParam ? createArrayType(unionParamType) : unionParamType; params[i] = paramSymbol; @@ -29926,12 +38799,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*resolvedReturnType*/ undefined, /*resolvedTypePredicate*/ undefined, minArgCount, - (left.flags | right.flags) & SignatureFlags.PropagatingFlags + (left.flags | right.flags) & SignatureFlags.PropagatingFlags, ); result.compositeKind = TypeFlags.Intersection; - result.compositeSignatures = concatenate(left.compositeKind === TypeFlags.Intersection && left.compositeSignatures || [left], [right]); + result.compositeSignatures = concatenate( + left.compositeKind === TypeFlags.Intersection && left.compositeSignatures || [left], + [right], + ); if (paramMapper) { - result.mapper = left.compositeKind === TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; + result.mapper = left.compositeKind === TypeFlags.Intersection && left.mapper && left.compositeSignatures + ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; } return result; } @@ -29971,7 +38848,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If the contextual type is a union type, get the signature from each type possible and if they are // all identical ignoring their return type, the result is same signature but with return type as // union type of return types from these signatures - function getContextualSignature(node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature | undefined { + function getContextualSignature( + node: FunctionExpression | ArrowFunction | MethodDeclaration, + ): Signature | undefined { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); const typeTagSignature = getSignatureOfTypeTag(node); if (typeTagSignature) { @@ -29993,7 +38872,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This signature will contribute to contextual union signature signatureList = [signature]; } - else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreThisTypes*/ true, /*ignoreReturnTypes*/ true, compareTypesIdentical)) { + else if ( + !compareSignaturesIdentical( + signatureList[0], + signature, + /*partialMatch*/ false, + /*ignoreThisTypes*/ true, + /*ignoreReturnTypes*/ true, + compareTypesIdentical, + ) + ) { // Signatures aren't identical, do not use return undefined; } @@ -30005,13 +38893,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Result is union of signatures collected (return type is union of return types of this signature set) if (signatureList) { - return signatureList.length === 1 ? signatureList[0] : createUnionSignature(signatureList[0], signatureList); + return signatureList.length === 1 ? signatureList[0] + : createUnionSignature(signatureList[0], signatureList); } } function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type { if (languageVersion < ScriptTarget.ES2015) { - checkExternalEmitHelpers(node, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); + checkExternalEmitHelpers( + node, + compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes + : ExternalEmitHelpers.SpreadArray, + ); } const arrayOrIterableType = checkExpression(node.expression, checkMode); @@ -30023,8 +38916,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function hasDefaultValue(node: BindingElement | Expression): boolean { - return (node.kind === SyntaxKind.BindingElement && !!(node as BindingElement).initializer) || - (node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken); + return (node.kind === SyntaxKind.BindingElement && !!(node as BindingElement).initializer) + || (node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken); } function isSpreadIntoCallOrNew(node: ArrayLiteralExpression) { @@ -30032,7 +38926,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isSpreadElement(parent) && isCallOrNewExpression(parent.parent); } - function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined, forceTuple: boolean | undefined): Type { + function checkArrayLiteral( + node: ArrayLiteralExpression, + checkMode: CheckMode | undefined, + forceTuple: boolean | undefined, + ): Type { const elements = node.elements; const elementCount = elements.length; const elementTypes: Type[] = []; @@ -30041,13 +38939,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const inDestructuringPattern = isAssignmentTarget(node); const inConstContext = isConstContext(node); const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); - const inTupleContext = isSpreadIntoCallOrNew(node) || !!contextualType && someType(contextualType, isTupleLikeType); + const inTupleContext = isSpreadIntoCallOrNew(node) + || !!contextualType && someType(contextualType, isTupleLikeType); let hasOmittedExpression = false; for (let i = 0; i < elementCount; i++) { const e = elements[i]; if (e.kind === SyntaxKind.SpreadElement) { if (languageVersion < ScriptTarget.ES2015) { - checkExternalEmitHelpers(e, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); + checkExternalEmitHelpers( + e, + compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes + : ExternalEmitHelpers.SpreadArray, + ); } const spreadType = checkExpression((e as SpreadElement).expression, checkMode, forceTuple); if (isArrayLikeType(spreadType)) { @@ -30067,14 +38970,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // get the contextual element type from it. So we do something similar to // getContextualTypeForElementExpression, which will crucially not error // if there is no index type / iterated type. - const restElementType = getIndexTypeOfType(spreadType, numberType) || - getIteratedTypeOrElementType(IterationUse.Destructuring, spreadType, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false) || - unknownType; + const restElementType = getIndexTypeOfType(spreadType, numberType) + || getIteratedTypeOrElementType( + IterationUse.Destructuring, + spreadType, + undefinedType, + /*errorNode*/ undefined, + /*checkAssignability*/ false, + ) + || unknownType; elementTypes.push(restElementType); elementFlags.push(ElementFlags.Rest); } else { - elementTypes.push(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, (e as SpreadElement).expression)); + elementTypes.push( + checkIteratedTypeOrElementType( + IterationUse.Spread, + spreadType, + undefinedType, + (e as SpreadElement).expression, + ), + ); elementFlags.push(ElementFlags.Rest); } } @@ -30087,9 +39003,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const type = checkExpressionForMutableLocation(e, checkMode, forceTuple); elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression)); elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required); - if (inTupleContext && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) { + if ( + inTupleContext && checkMode && checkMode & CheckMode.Inferential + && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e) + ) { const inferenceContext = getInferenceContext(node); - Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context + Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context addIntraExpressionInferenceSite(inferenceContext, e, type); } } @@ -30101,9 +39020,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (forceTuple || inConstContext || inTupleContext) { return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext)); } - return createArrayLiteralType(createArrayType(elementTypes.length ? - getUnionType(sameMap(elementTypes, (t, i) => elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessTypeOrUndefined(t, numberType) || anyType : t), UnionReduction.Subtype) : - strictNullChecks ? implicitNeverType : undefinedWideningType, inConstContext)); + return createArrayLiteralType(createArrayType( + elementTypes.length + ? getUnionType( + sameMap(elementTypes, (t, i) => + elementFlags[i] & ElementFlags.Variadic + ? getIndexedAccessTypeOrUndefined(t, numberType) || anyType : t), + UnionReduction.Subtype, + ) + : strictNullChecks ? implicitNeverType : undefinedWideningType, + inConstContext, + )); } function createArrayLiteralType(type: Type) { @@ -30141,20 +39068,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkComputedPropertyName(node: ComputedPropertyName): Type { const links = getNodeLinks(node.expression); if (!links.resolvedType) { - if ((isTypeLiteralNode(node.parent.parent) || isClassLike(node.parent.parent) || isInterfaceDeclaration(node.parent.parent)) + if ( + (isTypeLiteralNode(node.parent.parent) || isClassLike(node.parent.parent) + || isInterfaceDeclaration(node.parent.parent)) && isBinaryExpression(node.expression) && node.expression.operatorToken.kind === SyntaxKind.InKeyword - && node.parent.kind !== SyntaxKind.GetAccessor && node.parent.kind !== SyntaxKind.SetAccessor) { + && node.parent.kind !== SyntaxKind.GetAccessor && node.parent.kind !== SyntaxKind.SetAccessor + ) { return links.resolvedType = errorType; } links.resolvedType = checkExpression(node.expression); // The computed property name of a non-static class field within a loop must be stored in a block-scoped binding. // (It needs to be bound at class evaluation time.) - if (isPropertyDeclaration(node.parent) && !hasStaticModifier(node.parent) && isClassExpression(node.parent.parent)) { + if ( + isPropertyDeclaration(node.parent) && !hasStaticModifier(node.parent) + && isClassExpression(node.parent.parent) + ) { const container = getEnclosingBlockScopeContainer(node.parent.parent); const enclosingIterationStatement = getEnclosingIterationStatement(container); if (enclosingIterationStatement) { // The computed field name will use a block scoped binding which can be unique for each iteration of the loop. - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; // The generated variable which stores the computed field name must be block-scoped. getNodeLinks(node).flags |= NodeCheckFlags.BlockScopedBindingInLoop; // The generated variable which stores the class must be block-scoped. @@ -30163,9 +39097,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // This will allow types number, string, symbol or any. It will also allow enums, the unknown // type, and any union of these types (like string | number). - if (links.resolvedType.flags & TypeFlags.Nullable || - !isTypeAssignableToKind(links.resolvedType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) && - !isTypeAssignableTo(links.resolvedType, stringNumberSymbolType)) { + if ( + links.resolvedType.flags & TypeFlags.Nullable + || !isTypeAssignableToKind( + links.resolvedType, + TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike, + ) + && !isTypeAssignableTo(links.resolvedType, stringNumberSymbolType) + ) { error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any); } } @@ -30175,22 +39114,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isSymbolWithNumericName(symbol: Symbol) { const firstDecl = symbol.declarations?.[0]; - return isNumericLiteralName(symbol.escapedName) || (firstDecl && isNamedDeclaration(firstDecl) && isNumericName(firstDecl.name)); + return isNumericLiteralName(symbol.escapedName) + || (firstDecl && isNamedDeclaration(firstDecl) && isNumericName(firstDecl.name)); } function isSymbolWithSymbolName(symbol: Symbol) { const firstDecl = symbol.declarations?.[0]; - return isKnownSymbol(symbol) || (firstDecl && isNamedDeclaration(firstDecl) && isComputedPropertyName(firstDecl.name) && - isTypeAssignableToKind(checkComputedPropertyName(firstDecl.name), TypeFlags.ESSymbol)); + return isKnownSymbol(symbol) + || (firstDecl && isNamedDeclaration(firstDecl) && isComputedPropertyName(firstDecl.name) + && isTypeAssignableToKind(checkComputedPropertyName(firstDecl.name), TypeFlags.ESSymbol)); } - function getObjectLiteralIndexInfo(node: ObjectLiteralExpression, offset: number, properties: Symbol[], keyType: Type): IndexInfo { + function getObjectLiteralIndexInfo( + node: ObjectLiteralExpression, + offset: number, + properties: Symbol[], + keyType: Type, + ): IndexInfo { const propTypes: Type[] = []; for (let i = offset; i < properties.length; i++) { const prop = properties[i]; - if (keyType === stringType && !isSymbolWithSymbolName(prop) || - keyType === numberType && isSymbolWithNumericName(prop) || - keyType === esSymbolType && isSymbolWithSymbolName(prop)) { + if ( + keyType === stringType && !isSymbolWithSymbolName(prop) + || keyType === numberType && isSymbolWithNumericName(prop) + || keyType === esSymbolType && isSymbolWithSymbolName(prop) + ) { propTypes.push(getTypeOfSymbol(properties[i])); } } @@ -30222,8 +39170,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { pushCachedContextualType(node); const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); - const contextualTypeHasPattern = contextualType && contextualType.pattern && - (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); + const contextualTypeHasPattern = contextualType && contextualType.pattern + && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern + || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); const inConstContext = isConstContext(node); const checkFlags = inConstContext ? CheckFlags.Readonly : 0; const isInJavascript = isInJSFile(node) && !isInJsonFile(node); @@ -30247,17 +39196,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let offset = 0; for (const memberDecl of node.properties) { let member = getSymbolOfDeclaration(memberDecl); - const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName ? - checkComputedPropertyName(memberDecl.name) : undefined; - if (memberDecl.kind === SyntaxKind.PropertyAssignment || - memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment || - isObjectLiteralMethod(memberDecl)) { - let type = memberDecl.kind === SyntaxKind.PropertyAssignment ? checkPropertyAssignment(memberDecl, checkMode) : + const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName + ? checkComputedPropertyName(memberDecl.name) : undefined; + if ( + memberDecl.kind === SyntaxKind.PropertyAssignment + || memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment + || isObjectLiteralMethod(memberDecl) + ) { + let type = memberDecl.kind === SyntaxKind.PropertyAssignment + ? checkPropertyAssignment(memberDecl, checkMode) // avoid resolving the left side of the ShorthandPropertyAssignment outside of the destructuring // for error recovery purposes. For example, if a user wrote `{ a = 100 }` instead of `{ a: 100 }`. // we don't want to say "could not find 'a'". - memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ? checkExpressionForMutableLocation(!inDestructuringPattern && memberDecl.objectAssignmentInitializer ? memberDecl.objectAssignmentInitializer : memberDecl.name, checkMode) : - checkObjectLiteralMethod(memberDecl, checkMode); + : memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment + ? checkExpressionForMutableLocation( + !inDestructuringPattern && memberDecl.objectAssignmentInitializer + ? memberDecl.objectAssignmentInitializer : memberDecl.name, + checkMode, + ) + : checkObjectLiteralMethod(memberDecl, checkMode); if (isInJavascript) { const jsDocType = getTypeForDeclarationFromJSDocComment(memberDecl); if (jsDocType) { @@ -30269,10 +39226,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } objectFlags |= getObjectFlags(type) & ObjectFlags.PropagatingFlags; - const nameType = computedNameType && isTypeUsableAsPropertyName(computedNameType) ? computedNameType : undefined; - const prop = nameType ? - createSymbol(SymbolFlags.Property | member.flags, getPropertyNameFromType(nameType), checkFlags | CheckFlags.Late) : - createSymbol(SymbolFlags.Property | member.flags, member.escapedName, checkFlags); + const nameType = computedNameType && isTypeUsableAsPropertyName(computedNameType) ? computedNameType + : undefined; + const prop = nameType + ? createSymbol( + SymbolFlags.Property | member.flags, + getPropertyNameFromType(nameType), + checkFlags | CheckFlags.Late, + ) + : createSymbol(SymbolFlags.Property | member.flags, member.escapedName, checkFlags); if (nameType) { prop.links.nameType = nameType; } @@ -30281,23 +39243,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If object literal is an assignment pattern and if the assignment pattern specifies a default value // for the property, make the property optional. const isOptional = - (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue(memberDecl.initializer)) || - (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && memberDecl.objectAssignmentInitializer); + (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue(memberDecl.initializer)) + || (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment + && memberDecl.objectAssignmentInitializer); if (isOptional) { prop.flags |= SymbolFlags.Optional; } } - else if (contextualTypeHasPattern && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) { + else if ( + contextualTypeHasPattern + && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) + ) { // If object literal is contextually typed by the implied type of a binding pattern, and if the // binding pattern specifies a default value for the property, make the property optional. const impliedProp = getPropertyOfType(contextualType, member.escapedName); if (impliedProp) { prop.flags |= impliedProp.flags & SymbolFlags.Optional; } - - else if (!compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, stringType)) { - error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, - symbolToString(member), typeToString(contextualType)); + else if ( + !compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, stringType) + ) { + error( + memberDecl.name, + Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, + symbolToString(member), + typeToString(contextualType), + ); } } @@ -30312,11 +39283,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { member = prop; allPropertiesTable?.set(prop.escapedName, prop); - if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && - (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl)) { + if ( + contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) + && (memberDecl.kind === SyntaxKind.PropertyAssignment + || memberDecl.kind === SyntaxKind.MethodDeclaration) + && isContextSensitive(memberDecl) + ) { const inferenceContext = getInferenceContext(node); - Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context - const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer : memberDecl; + Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context + const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer + : memberDecl; addIntraExpressionInferenceSite(inferenceContext, inferenceNode, type); } } @@ -30391,22 +39367,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // It's not possible to check if the immediate parent node is a spread assignment // since the type flows in non-obvious ways through conditional expressions, IIFEs and more. if (contextualTypeHasPattern) { - const rootPatternParent = findAncestor(contextualType.pattern!.parent, n => - n.kind === SyntaxKind.VariableDeclaration || - n.kind === SyntaxKind.BinaryExpression || - n.kind === SyntaxKind.Parameter + const rootPatternParent = findAncestor( + contextualType.pattern!.parent, + n => n.kind === SyntaxKind.VariableDeclaration + || n.kind === SyntaxKind.BinaryExpression + || n.kind === SyntaxKind.Parameter, ); const spreadOrOutsideRootObject = findAncestor(node, n => - n === rootPatternParent || - n.kind === SyntaxKind.SpreadAssignment - )!; + n === rootPatternParent + || n.kind === SyntaxKind.SpreadAssignment)!; if (spreadOrOutsideRootObject.kind !== SyntaxKind.SpreadAssignment) { for (const prop of getPropertiesOfType(contextualType)) { if (!propertiesTable.get(prop.escapedName) && !getPropertyOfType(spread, prop.escapedName)) { if (!(prop.flags & SymbolFlags.Optional)) { - error(prop.valueDeclaration || tryCast(prop, isTransientSymbol)?.links.bindingElement, - Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); + error( + prop.valueDeclaration || tryCast(prop, isTransientSymbol)?.links.bindingElement, + Diagnostics + .Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value, + ); } propertiesTable.set(prop.escapedName, prop); propertiesArray.push(prop); @@ -30435,9 +39414,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createObjectLiteralType() { const indexInfos = []; - if (hasComputedStringProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, stringType)); - if (hasComputedNumberProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, numberType)); - if (hasComputedSymbolProperty) indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, esSymbolType)); + if (hasComputedStringProperty) { + indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, stringType)); + } + if (hasComputedNumberProperty) { + indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, numberType)); + } + if (hasComputedSymbolProperty) { + indexInfos.push(getObjectLiteralIndexInfo(node, offset, propertiesArray, esSymbolType)); + } const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, indexInfos); result.objectFlags |= objectFlags | ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral; if (isJSObjectLiteral) { @@ -30455,8 +39440,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isValidSpreadType(type: Type): boolean { const t = removeDefinitelyFalsyTypes(mapType(type, getBaseConstraintOrType)); - return !!(t.flags & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) || - t.flags & TypeFlags.UnionOrIntersection && every((t as UnionOrIntersectionType).types, isValidSpreadType)); + return !!(t.flags + & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) + || t.flags & TypeFlags.UnionOrIntersection + && every((t as UnionOrIntersectionType).types, isValidSpreadType)); } function checkJsxSelfClosingElementDeferred(node: JsxSelfClosingElement) { @@ -30495,11 +39482,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // by default, jsx:'react' will use jsxFactory = React.createElement and jsxFragmentFactory = React.Fragment // if jsxFactory compiler option is provided, ensure jsxFragmentFactory compiler option or @jsxFrag pragma is provided too const nodeSourceFile = getSourceFileOfNode(node); - if (getJSXTransformEnabled(compilerOptions) && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx")) - && !compilerOptions.jsxFragmentFactory && !nodeSourceFile.pragmas.has("jsxfrag")) { - error(node, compilerOptions.jsxFactory - ? Diagnostics.The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option - : Diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments); + if ( + getJSXTransformEnabled(compilerOptions) && (compilerOptions.jsxFactory || nodeSourceFile.pragmas.has("jsx")) + && !compilerOptions.jsxFragmentFactory && !nodeSourceFile.pragmas.has("jsxfrag") + ) { + error( + node, + compilerOptions.jsxFactory + ? Diagnostics + .The_jsxFragmentFactory_compiler_option_must_be_provided_to_use_JSX_fragments_with_the_jsxFactory_compiler_option + : Diagnostics.An_jsxFrag_pragma_is_required_when_using_an_jsx_pragma_with_JSX_fragments, + ); } checkJsxChildren(node); @@ -30520,7 +39513,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJsxAttribute(node: JsxAttribute, checkMode?: CheckMode) { return node.initializer ? checkExpressionForMutableLocation(node.initializer, checkMode) - : trueType; // is sugar for + : trueType; // is sugar for } /** @@ -30532,7 +39525,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral, * which also calls getSpreadType. */ - function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode = CheckMode.Normal) { + function createJsxAttributesTypeFromAttributesProperty( + openingLikeElement: JsxOpeningLikeElement, + checkMode: CheckMode = CheckMode.Normal, + ) { const attributes = openingLikeElement.attributes; const contextualType = getContextualType(attributes, ContextFlags.None); const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined; @@ -30566,12 +39562,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (contextualType) { const prop = getPropertyOfType(contextualType, member.escapedName); if (prop && prop.declarations && isDeprecatedSymbol(prop) && isIdentifier(attributeDecl.name)) { - addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string); + addDeprecatedSuggestion( + attributeDecl.name, + prop.declarations, + attributeDecl.name.escapedText as string, + ); } } - if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) { + if ( + contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) + && isContextSensitive(attributeDecl) + ) { const inferenceContext = getInferenceContext(attributes); - Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context + Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context const inferenceNode = (attributeDecl.initializer as JsxExpression).expression!; addIntraExpressionInferenceSite(inferenceContext, inferenceNode, exprType); } @@ -30579,10 +39582,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + createJsxAttributesType(), + attributes.symbol, + objectFlags, + /*readonly*/ false, + ); attributesTable = createSymbolTable(); } - const exprType = getReducedType(checkExpression(attributeDecl.expression, checkMode & CheckMode.Inferential)); + const exprType = getReducedType( + checkExpression(attributeDecl.expression, checkMode & CheckMode.Inferential), + ); if (isTypeAny(exprType)) { hasSpreadAnyType = true; } @@ -30601,12 +39612,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, objectFlags, /*readonly*/ false); + spread = getSpreadType( + spread, + createJsxAttributesType(), + attributes.symbol, + objectFlags, + /*readonly*/ false, + ); } } // Handle children attribute - const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined; + const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement + ? openingLikeElement.parent as JsxElement : undefined; // We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement if (parent && parent.openingElement === openingLikeElement && parent.children.length > 0) { const childrenTypes: Type[] = checkJsxChildren(parent, checkMode); @@ -30616,25 +39634,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This is because children element will overwrite the value from attributes. // Note: we will not warn "children" attribute overwritten if "children" attribute is specified in object spread. if (explicitlySpecifyChildrenAttribute) { - error(attributes, Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, unescapeLeadingUnderscores(jsxChildrenPropertyName)); + error( + attributes, + Diagnostics._0_are_specified_twice_The_attribute_named_0_will_be_overwritten, + unescapeLeadingUnderscores(jsxChildrenPropertyName), + ); } - const contextualType = getApparentTypeOfContextualType(openingLikeElement.attributes, /*contextFlags*/ undefined); - const childrenContextualType = contextualType && getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName); + const contextualType = getApparentTypeOfContextualType( + openingLikeElement.attributes, + /*contextFlags*/ undefined, + ); + const childrenContextualType = contextualType + && getTypeOfPropertyOfContextualType(contextualType, jsxChildrenPropertyName); // If there are children in the body of JSX element, create dummy attribute "children" with the union of children types so that it will pass the attribute checking process const childrenPropSymbol = createSymbol(SymbolFlags.Property, jsxChildrenPropertyName); - childrenPropSymbol.links.type = childrenTypes.length === 1 ? childrenTypes[0] : - childrenContextualType && someType(childrenContextualType, isTupleLikeType) ? createTupleType(childrenTypes) : - createArrayType(getUnionType(childrenTypes)); + childrenPropSymbol.links.type = childrenTypes.length === 1 ? childrenTypes[0] + : childrenContextualType && someType(childrenContextualType, isTupleLikeType) + ? createTupleType(childrenTypes) + : createArrayType(getUnionType(childrenTypes)); // Fake up a property declaration for the children - childrenPropSymbol.valueDeclaration = factory.createPropertySignature(/*modifiers*/ undefined, unescapeLeadingUnderscores(jsxChildrenPropertyName), /*questionToken*/ undefined, /*type*/ undefined); + childrenPropSymbol.valueDeclaration = factory.createPropertySignature( + /*modifiers*/ undefined, + unescapeLeadingUnderscores(jsxChildrenPropertyName), + /*questionToken*/ undefined, + /*type*/ undefined, + ); setParent(childrenPropSymbol.valueDeclaration, attributes); childrenPropSymbol.valueDeclaration.symbol = childrenPropSymbol; const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); - spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, emptyArray), - attributes.symbol, objectFlags, /*readonly*/ false); - + spread = getSpreadType( + spread, + createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, emptyArray), + attributes.symbol, + objectFlags, + /*readonly*/ false, + ); } } @@ -30684,8 +39720,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(right.flags & SymbolFlags.Optional)) { const left = props.get(right.escapedName); if (left) { - const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName)); - addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property)); + const diagnostic = error( + left.valueDeclaration, + Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, + unescapeLeadingUnderscores(left.escapedName), + ); + addRelatedInfo( + diagnostic, + createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property), + ); } } } @@ -30720,7 +39763,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isErrorType(intrinsicElementsType)) { // Property case if (!isIdentifier(node.tagName) && !isJsxNamespacedName(node.tagName)) return Debug.fail(); - const propName = isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) : node.tagName.escapedText; + const propName = isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) + : node.tagName.escapedText; const intrinsicProp = getPropertyOfType(intrinsicElementsType, propName); if (intrinsicProp) { links.jsxFlags |= JsxFlags.IntrinsicNamedElement; @@ -30728,7 +39772,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Intrinsic string indexer case - const indexSymbol = getApplicableIndexSymbol(intrinsicElementsType, getStringLiteralType(unescapeLeadingUnderscores(propName))); + const indexSymbol = getApplicableIndexSymbol( + intrinsicElementsType, + getStringLiteralType(unescapeLeadingUnderscores(propName)), + ); if (indexSymbol) { links.jsxFlags |= JsxFlags.IntrinsicIndexedElement; return links.resolvedSymbol = indexSymbol; @@ -30740,12 +39787,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Wasn't found - error(node, Diagnostics.Property_0_does_not_exist_on_type_1, intrinsicTagNameToString(node.tagName), "JSX." + JsxNames.IntrinsicElements); + error( + node, + Diagnostics.Property_0_does_not_exist_on_type_1, + intrinsicTagNameToString(node.tagName), + "JSX." + JsxNames.IntrinsicElements, + ); return links.resolvedSymbol = unknownSymbol; } else { if (noImplicitAny) { - error(node, Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, unescapeLeadingUnderscores(JsxNames.IntrinsicElements)); + error( + node, + Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, + unescapeLeadingUnderscores(JsxNames.IntrinsicElements), + ); } return links.resolvedSymbol = unknownSymbol; } @@ -30762,14 +39818,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (links && links.jsxImplicitImportContainer) { return links.jsxImplicitImportContainer; } - const runtimeImportSpecifier = getJSXRuntimeImport(getJSXImplicitImportBase(compilerOptions, file), compilerOptions); + const runtimeImportSpecifier = getJSXRuntimeImport( + getJSXImplicitImportBase(compilerOptions, file), + compilerOptions, + ); if (!runtimeImportSpecifier) { return undefined; } const isClassic = getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic; 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; + ? 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 mod = resolveExternalModule(location!, runtimeImportSpecifier, errorMessage, location!); const result = mod && mod !== unknownSymbol ? getMergedSymbol(resolveSymbol(mod)) : undefined; if (links) { @@ -30788,11 +39848,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!resolvedNamespace || resolvedNamespace === unknownSymbol) { const namespaceName = getJsxNamespace(location); - resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*nameNotFoundMessage*/ undefined, namespaceName, /*isUse*/ false); + resolvedNamespace = resolveName( + location, + namespaceName, + SymbolFlags.Namespace, + /*nameNotFoundMessage*/ undefined, + namespaceName, + /*isUse*/ false, + ); } if (resolvedNamespace) { - const candidate = resolveSymbol(getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace)); + const candidate = resolveSymbol( + getSymbol( + getExportsOfSymbol(resolveSymbol(resolvedNamespace)), + JsxNames.JSX, + SymbolFlags.Namespace, + ), + ); if (candidate && candidate !== unknownSymbol) { if (links) { links.jsxNamespace = candidate; @@ -30819,13 +39892,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param nameOfAttribPropContainer a string of value JsxNames.ElementAttributesPropertyNameContainer or JsxNames.ElementChildrenAttributeNameContainer * if other string is given or the container doesn't exist, return undefined. */ - function getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer: __String, jsxNamespace: Symbol): __String | undefined { + function getNameFromJsxElementAttributesContainer( + nameOfAttribPropContainer: __String, + jsxNamespace: Symbol, + ): __String | undefined { // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [symbol] - const jsxElementAttribPropInterfaceSym = jsxNamespace && getSymbol(jsxNamespace.exports!, nameOfAttribPropContainer, SymbolFlags.Type); + const jsxElementAttribPropInterfaceSym = jsxNamespace + && getSymbol(jsxNamespace.exports!, nameOfAttribPropContainer, SymbolFlags.Type); // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [type] - const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym); + const jsxElementAttribPropInterfaceType = jsxElementAttribPropInterfaceSym + && getDeclaredTypeOfSymbol(jsxElementAttribPropInterfaceSym); // The properties of JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute - const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType && getPropertiesOfType(jsxElementAttribPropInterfaceType); + const propertiesOfJsxElementAttribPropInterface = jsxElementAttribPropInterfaceType + && getPropertiesOfType(jsxElementAttribPropInterfaceType); if (propertiesOfJsxElementAttribPropInterface) { // Element Attributes has zero properties, so the element attributes type will be the class instance type if (propertiesOfJsxElementAttribPropInterface.length === 0) { @@ -30836,9 +39915,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (propertiesOfJsxElementAttribPropInterface.length === 1) { return propertiesOfJsxElementAttribPropInterface[0].escapedName; } - else if (propertiesOfJsxElementAttribPropInterface.length > 1 && jsxElementAttribPropInterfaceSym.declarations) { + else if ( + propertiesOfJsxElementAttribPropInterface.length > 1 && jsxElementAttribPropInterfaceSym.declarations + ) { // More than one property on ElementAttributesProperty is an error - error(jsxElementAttribPropInterfaceSym.declarations[0], Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, unescapeLeadingUnderscores(nameOfAttribPropContainer)); + error( + jsxElementAttribPropInterfaceSym.declarations[0], + Diagnostics.The_global_type_JSX_0_may_not_have_more_than_one_property, + unescapeLeadingUnderscores(nameOfAttribPropContainer), + ); } } return undefined; @@ -30867,14 +39952,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace); } - function getUninstantiatedJsxSignaturesOfType(elementType: Type, caller: JsxOpeningLikeElement): readonly Signature[] { + function getUninstantiatedJsxSignaturesOfType( + elementType: Type, + caller: JsxOpeningLikeElement, + ): readonly Signature[] { if (elementType.flags & TypeFlags.String) { return [anySignature]; } else if (elementType.flags & TypeFlags.StringLiteral) { - const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType(elementType as StringLiteralType, caller); + const intrinsicType = getIntrinsicAttributesTypeFromStringLiteralType( + elementType as StringLiteralType, + caller, + ); if (!intrinsicType) { - error(caller, Diagnostics.Property_0_does_not_exist_on_type_1, (elementType as StringLiteralType).value, "JSX." + JsxNames.IntrinsicElements); + error( + caller, + Diagnostics.Property_0_does_not_exist_on_type_1, + (elementType as StringLiteralType).value, + "JSX." + JsxNames.IntrinsicElements, + ); return emptyArray; } else { @@ -30891,12 +39987,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (signatures.length === 0 && apparentElemType.flags & TypeFlags.Union) { // If each member has some combination of new/call signatures; make a union signature list for those - signatures = getUnionSignatures(map((apparentElemType as UnionType).types, t => getUninstantiatedJsxSignaturesOfType(t, caller))); + signatures = getUnionSignatures( + map((apparentElemType as UnionType).types, t => getUninstantiatedJsxSignaturesOfType(t, caller)), + ); } return signatures; } - function getIntrinsicAttributesTypeFromStringLiteralType(type: StringLiteralType, location: Node): Type | undefined { + function getIntrinsicAttributesTypeFromStringLiteralType( + type: StringLiteralType, + location: Node, + ): Type | undefined { // If the elemType is a stringLiteral type, we can then provide a check to make sure that the string literal type is one of the Jsx intrinsic element type // For example: // var CustomTag: "h1" = "h1"; @@ -30904,7 +40005,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, location); if (!isErrorType(intrinsicElementsType)) { const stringLiteralTypeName = type.value; - const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); + const intrinsicProp = getPropertyOfType( + intrinsicElementsType, + escapeLeadingUnderscores(stringLiteralTypeName), + ); if (intrinsicProp) { return getTypeOfSymbol(intrinsicProp); } @@ -30918,18 +40022,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return anyType; } - function checkJsxReturnAssignableToAppropriateBound(refKind: JsxReferenceKind, elemInstanceType: Type, openingLikeElement: JsxOpeningLikeElement) { + function checkJsxReturnAssignableToAppropriateBound( + refKind: JsxReferenceKind, + elemInstanceType: Type, + openingLikeElement: JsxOpeningLikeElement, + ) { if (refKind === JsxReferenceKind.Function) { const sfcReturnConstraint = getJsxStatelessElementTypeAt(openingLikeElement); if (sfcReturnConstraint) { - checkTypeRelatedTo(elemInstanceType, sfcReturnConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + checkTypeRelatedTo( + elemInstanceType, + sfcReturnConstraint, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_return_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain, + ); } } else if (refKind === JsxReferenceKind.Component) { const classConstraint = getJsxElementClassTypeAt(openingLikeElement); if (classConstraint) { // Issue an error if this return type isn't assignable to JSX.ElementClass, failing that - checkTypeRelatedTo(elemInstanceType, classConstraint, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + checkTypeRelatedTo( + elemInstanceType, + classConstraint, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_instance_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain, + ); } } else { // Mixed @@ -30939,12 +40061,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } const combined = getUnionType([sfcReturnConstraint, classConstraint]); - checkTypeRelatedTo(elemInstanceType, combined, assignableRelation, openingLikeElement.tagName, Diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, generateInitialErrorChain); + checkTypeRelatedTo( + elemInstanceType, + combined, + assignableRelation, + openingLikeElement.tagName, + Diagnostics.Its_element_type_0_is_not_a_valid_JSX_element, + generateInitialErrorChain, + ); } function generateInitialErrorChain(): DiagnosticMessageChain { const componentName = getTextOfNode(openingLikeElement.tagName); - return chainDiagnosticMessages(/*details*/ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); + return chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics._0_cannot_be_used_as_a_JSX_component, + componentName, + ); } } @@ -30962,9 +40095,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.resolvedJsxElementAttributesType = getTypeOfSymbol(symbol) || errorType; } else if (links.jsxFlags & JsxFlags.IntrinsicIndexedElement) { - const propName = isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) : node.tagName.escapedText; + const propName = isJsxNamespacedName(node.tagName) ? getEscapedTextOfJsxNamespacedName(node.tagName) + : node.tagName.escapedText; return links.resolvedJsxElementAttributesType = - getApplicableIndexInfoForName(getJsxType(JsxNames.IntrinsicElements, node), propName)?.type || errorType; + getApplicableIndexInfoForName(getJsxType(JsxNames.IntrinsicElements, node), propName)?.type + || errorType; } else { return links.resolvedJsxElementAttributesType = errorType; @@ -31010,8 +40145,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (length((declaredManagedType as GenericType).typeParameters) >= typeArguments.length) { - const args = fillMissingTypeArguments(typeArguments, (declaredManagedType as GenericType).typeParameters, typeArguments.length, inJs); - return createTypeReference((declaredManagedType as GenericType), args); + const args = fillMissingTypeArguments( + typeArguments, + (declaredManagedType as GenericType).typeParameters, + typeArguments.length, + inJs, + ); + return createTypeReference(declaredManagedType as GenericType, args); } return undefined; } @@ -31032,7 +40172,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getJsxElementTypeAt(errorNode) === undefined) { if (noImplicitAny) { - error(errorNode, Diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist); + error( + errorNode, + Diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist, + ); } } } @@ -31049,14 +40192,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!getJsxNamespaceContainerForImplicitImport(node)) { // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. - const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; + const jsxFactoryRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React + ? Diagnostics.Cannot_find_name_0 : undefined; const jsxFactoryNamespace = getJsxNamespace(node); const jsxFactoryLocation = isNodeOpeningLikeElement ? node.tagName : node; // allow null as jsxFragmentFactory let jsxFactorySym: Symbol | undefined; if (!(isJsxOpeningFragment(node) && jsxFactoryNamespace === "null")) { - jsxFactorySym = resolveName(jsxFactoryLocation, jsxFactoryNamespace, SymbolFlags.Value, jsxFactoryRefErr, jsxFactoryNamespace, /*isUse*/ true); + jsxFactorySym = resolveName( + jsxFactoryLocation, + jsxFactoryNamespace, + SymbolFlags.Value, + jsxFactoryRefErr, + jsxFactoryNamespace, + /*isUse*/ true, + ); } if (jsxFactorySym) { @@ -31065,7 +40216,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { jsxFactorySym.isReferenced = SymbolFlags.All; // If react/jsxFactory symbol is alias, mark it as refereced - if (canCollectSymbolAliasAccessabilityData && jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) { + if ( + canCollectSymbolAliasAccessabilityData && jsxFactorySym.flags & SymbolFlags.Alias + && !getTypeOnlyAliasDeclaration(jsxFactorySym) + ) { markAliasSymbolAsReferenced(jsxFactorySym); } } @@ -31075,13 +40229,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const file = getSourceFileOfNode(node); const localJsxNamespace = getLocalJsxNamespace(file); if (localJsxNamespace) { - resolveName(jsxFactoryLocation, localJsxNamespace, SymbolFlags.Value, jsxFactoryRefErr, localJsxNamespace, /*isUse*/ true); + resolveName( + jsxFactoryLocation, + localJsxNamespace, + SymbolFlags.Value, + jsxFactoryRefErr, + localJsxNamespace, + /*isUse*/ true, + ); } } } if (isNodeOpeningLikeElement) { - const jsxOpeningLikeNode = node ; + const jsxOpeningLikeNode = node; const sig = getResolvedSignature(jsxOpeningLikeNode); checkDeprecatedSignature(sig, node); @@ -31091,13 +40252,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const tagType = isJsxIntrinsicTagName(tagName) ? getStringLiteralType(intrinsicTagNameToString(tagName)) : checkExpression(tagName); - checkTypeRelatedTo(tagType, elementTypeConstraint, assignableRelation, tagName, Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, () => { - const componentName = getTextOfNode(tagName); - return chainDiagnosticMessages(/*details*/ undefined, Diagnostics._0_cannot_be_used_as_a_JSX_component, componentName); - }); + checkTypeRelatedTo( + tagType, + elementTypeConstraint, + assignableRelation, + tagName, + Diagnostics.Its_type_0_is_not_a_valid_JSX_element_type, + () => { + const componentName = getTextOfNode(tagName); + return chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics._0_cannot_be_used_as_a_JSX_component, + componentName, + ); + }, + ); } else { - checkJsxReturnAssignableToAppropriateBound(getJsxReferenceKind(jsxOpeningLikeNode), getReturnTypeOfSignature(sig), jsxOpeningLikeNode); + checkJsxReturnAssignableToAppropriateBound( + getJsxReferenceKind(jsxOpeningLikeNode), + getReturnTypeOfSignature(sig), + jsxOpeningLikeNode, + ); } } } @@ -31120,10 +40296,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For backwards compatibility a symbol-named property is satisfied by a string index signature. This // is incorrect and inconsistent with element access expressions, where it is an error, so eventually // we should remove this exception. - if (getPropertyOfObjectType(targetType, name) || - getApplicableIndexInfoForName(targetType, name) || - isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) || - isComparingJsxAttributes && isHyphenatedJsxName(name)) { + if ( + getPropertyOfObjectType(targetType, name) + || getApplicableIndexInfoForName(targetType, name) + || isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) + || isComparingJsxAttributes && isHyphenatedJsxName(name) + ) { // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. return true; } @@ -31139,10 +40317,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isExcessPropertyCheckTarget(type: Type): boolean { - return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) || - type.flags & TypeFlags.NonPrimitive || - type.flags & TypeFlags.Union && some((type as UnionType).types, isExcessPropertyCheckTarget) || - type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isExcessPropertyCheckTarget)); + return !!(type.flags & TypeFlags.Object + && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) + || type.flags & TypeFlags.NonPrimitive + || type.flags & TypeFlags.Union && some((type as UnionType).types, isExcessPropertyCheckTarget) + || type.flags & TypeFlags.Intersection + && every((type as IntersectionType).types, isExcessPropertyCheckTarget)); } function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) { @@ -31173,8 +40353,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isInJSFile(symbol.valueDeclaration)) { const parent = symbol.valueDeclaration!.parent; - return parent && isBinaryExpression(parent) && - getAssignmentDeclarationKind(parent) === AssignmentDeclarationKind.PrototypeProperty; + return parent && isBinaryExpression(parent) + && getAssignmentDeclarationKind(parent) === AssignmentDeclarationKind.PrototypeProperty; } } @@ -31187,13 +40367,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param prop The symbol for the property being accessed. */ function checkPropertyAccessibility( - node: PropertyAccessExpression | QualifiedName | PropertyAccessExpression | VariableDeclaration | ParameterDeclaration | ImportTypeNode | PropertyAssignment | ShorthandPropertyAssignment | BindingElement, - isSuper: boolean, writing: boolean, type: Type, prop: Symbol, reportError = true): boolean { - - const errorNode = !reportError ? undefined : - node.kind === SyntaxKind.QualifiedName ? node.right : - node.kind === SyntaxKind.ImportType ? node : - node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name; + node: + | PropertyAccessExpression + | QualifiedName + | PropertyAccessExpression + | VariableDeclaration + | ParameterDeclaration + | ImportTypeNode + | PropertyAssignment + | ShorthandPropertyAssignment + | BindingElement, + isSuper: boolean, + writing: boolean, + type: Type, + prop: Symbol, + reportError = true, + ): boolean { + const errorNode = !reportError ? undefined + : node.kind === SyntaxKind.QualifiedName ? node.right + : node.kind === SyntaxKind.ImportType ? node + : node.kind === SyntaxKind.BindingElement && node.propertyName ? node.propertyName : node.name; return checkPropertyAccessibilityAtLocation(node, isSuper, writing, type, prop, errorNode); } @@ -31208,10 +40401,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param prop The symbol for the property being accessed. * @param errorNode The node where we should report an invalid property access error, or undefined if we should not report errors. */ - function checkPropertyAccessibilityAtLocation(location: Node, - isSuper: boolean, writing: boolean, - containingType: Type, prop: Symbol, errorNode?: Node): boolean { - + function checkPropertyAccessibilityAtLocation( + location: Node, + isSuper: boolean, + writing: boolean, + containingType: Type, + prop: Symbol, + errorNode?: Node, + ): boolean { const flags = getDeclarationModifierFlagsFromSymbol(prop, writing); if (isSuper) { @@ -31225,7 +40422,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (languageVersion < ScriptTarget.ES2015) { if (symbolHasNonMethodDeclaration(prop)) { if (errorNode) { - error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword); + error( + errorNode, + Diagnostics + .Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword, + ); } return false; } @@ -31236,25 +40437,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // cannot simultaneously be private and abstract, so this will trigger an // additional error elsewhere. if (errorNode) { - error(errorNode, + error( + errorNode, Diagnostics.Abstract_method_0_in_class_1_cannot_be_accessed_via_super_expression, symbolToString(prop), - typeToString(getDeclaringClass(prop)!)); + typeToString(getDeclaringClass(prop)!), + ); } return false; } } // Referencing abstract properties within their own constructors is not allowed - if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop) && - (isThisProperty(location) || isThisInitializedObjectBindingExpression(location) || isObjectBindingPattern(location.parent) && isThisInitializedDeclaration(location.parent.parent))) { + if ( + (flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop) + && (isThisProperty(location) || isThisInitializedObjectBindingExpression(location) + || isObjectBindingPattern(location.parent) && isThisInitializedDeclaration(location.parent.parent)) + ) { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!); if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(location)) { if (errorNode) { - error(errorNode, + error( + errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), - getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); + getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!), + ); } return false; } @@ -31272,10 +40480,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!)!; if (!isNodeWithinClass(location, declaringClassDeclaration)) { if (errorNode) { - error(errorNode, + error( + errorNode, Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), - typeToString(getDeclaringClass(prop)!)); + typeToString(getDeclaringClass(prop)!), + ); } return false; } @@ -31292,7 +40502,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Find the first enclosing class that has the declaring classes of the protected constituents // of the property as base classes let enclosingClass = forEachEnclosingClass(location, enclosingDeclaration => { - const enclosingClass = getDeclaredTypeOfSymbol(getSymbolOfDeclaration(enclosingDeclaration)!) as InterfaceType; + const enclosingClass = getDeclaredTypeOfSymbol( + getSymbolOfDeclaration(enclosingDeclaration)!, + ) as InterfaceType; return isClassDerivedFromDeclaringClasses(enclosingClass, prop, writing); }); // A protected property is accessible if the property is within the declaring class or classes derived from it @@ -31303,10 +40515,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { enclosingClass = enclosingClass && isClassDerivedFromDeclaringClasses(enclosingClass, prop, writing); if (flags & ModifierFlags.Static || !enclosingClass) { if (errorNode) { - error(errorNode, + error( + errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), - typeToString(getDeclaringClass(prop) || containingType)); + typeToString(getDeclaringClass(prop) || containingType), + ); } return false; } @@ -31317,13 +40531,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (containingType.flags & TypeFlags.TypeParameter) { // get the original type -- represented as the type constraint of the 'this' type - containingType = (containingType as TypeParameter).isThisType ? getConstraintOfTypeParameter(containingType as TypeParameter)! : getBaseConstraintOfType(containingType as TypeParameter)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined + containingType = (containingType as TypeParameter).isThisType + ? getConstraintOfTypeParameter(containingType as TypeParameter)! + : getBaseConstraintOfType(containingType as TypeParameter)!; // TODO: GH#18217 Use a different variable that's allowed to be undefined } if (!containingType || !hasBaseType(containingType, enclosingClass)) { if (errorNode) { - error(errorNode, - Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1_This_is_an_instance_of_class_2, - symbolToString(prop), typeToString(enclosingClass), typeToString(containingType)); + error( + errorNode, + Diagnostics + .Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1_This_is_an_instance_of_class_2, + symbolToString(prop), + typeToString(enclosingClass), + typeToString(containingType), + ); } return false; } @@ -31343,7 +40564,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getThisParameterFromNodeContext(node: Node) { - const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const thisContainer = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); return thisContainer && isFunctionLike(thisContainer) ? getThisParameter(thisContainer) : undefined; } @@ -31374,34 +40599,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(node, Diagnostics.The_value_0_cannot_be_used_here, "undefined"); return; } - error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics._0_is_possibly_null_or_undefined : - Diagnostics._0_is_possibly_undefined : - Diagnostics._0_is_possibly_null, - nodeText + error( + node, + facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull + ? Diagnostics._0_is_possibly_null_or_undefined + : Diagnostics._0_is_possibly_undefined + : Diagnostics._0_is_possibly_null, + nodeText, ); } else { - error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics.Object_is_possibly_null_or_undefined : - Diagnostics.Object_is_possibly_undefined : - Diagnostics.Object_is_possibly_null + error( + node, + facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull + ? Diagnostics.Object_is_possibly_null_or_undefined + : Diagnostics.Object_is_possibly_undefined + : Diagnostics.Object_is_possibly_null, ); } } function reportCannotInvokePossiblyNullOrUndefinedError(node: Node, facts: TypeFacts) { - error(node, facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull ? - Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined : - Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined : - Diagnostics.Cannot_invoke_an_object_which_is_possibly_null + error( + node, + facts & TypeFacts.IsUndefined ? facts & TypeFacts.IsNull + ? Diagnostics.Cannot_invoke_an_object_which_is_possibly_null_or_undefined + : Diagnostics.Cannot_invoke_an_object_which_is_possibly_undefined + : Diagnostics.Cannot_invoke_an_object_which_is_possibly_null, ); } function checkNonNullTypeWithReporter( type: Type, node: Node, - reportError: (node: Node, facts: TypeFacts) => void + reportError: (node: Node, facts: TypeFacts) => void, ): Type { if (strictNullChecks && type.flags & TypeFlags.Unknown) { if (isEntityNameExpression(node)) { @@ -31446,19 +40677,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return nonNullType; } - function checkPropertyAccessExpression(node: PropertyAccessExpression, checkMode: CheckMode | undefined, writeOnly?: boolean) { - return node.flags & NodeFlags.OptionalChain ? checkPropertyAccessChain(node as PropertyAccessChain, checkMode) : - checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullExpression(node.expression), node.name, checkMode, writeOnly); + function checkPropertyAccessExpression( + node: PropertyAccessExpression, + checkMode: CheckMode | undefined, + writeOnly?: boolean, + ) { + return node.flags & NodeFlags.OptionalChain ? checkPropertyAccessChain(node as PropertyAccessChain, checkMode) + : checkPropertyAccessExpressionOrQualifiedName( + node, + node.expression, + checkNonNullExpression(node.expression), + node.name, + checkMode, + writeOnly, + ); } function checkPropertyAccessChain(node: PropertyAccessChain, checkMode: CheckMode | undefined) { const leftType = checkExpression(node.expression); const nonOptionalType = getOptionalExpressionType(leftType, node.expression); - return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name, checkMode), node, nonOptionalType !== leftType); + return propagateOptionalTypeMarker( + checkPropertyAccessExpressionOrQualifiedName( + node, + node.expression, + checkNonNullType(nonOptionalType, node.expression), + node.name, + checkMode, + ), + node, + nonOptionalType !== leftType, + ); } function checkQualifiedName(node: QualifiedName, checkMode: CheckMode | undefined) { - const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) ? checkNonNullType(checkThisExpression(node.left), node.left) : checkNonNullExpression(node.left); + const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) + ? checkNonNullType(checkThisExpression(node.left), node.left) : checkNonNullExpression(node.left); return checkPropertyAccessExpressionOrQualifiedName(node, node.left, leftType, node.right, checkMode); } @@ -31471,7 +40724,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Lookup the private identifier lexically. function lookupSymbolForPrivateIdentifierDeclaration(propName: __String, location: Node): Symbol | undefined { - for (let containingClass = getContainingClassExcludingClassDecorators(location); !!containingClass; containingClass = getContainingClass(containingClass)) { + for ( + let containingClass = getContainingClassExcludingClassDecorators(location); + !!containingClass; + containingClass = getContainingClass(containingClass) + ) { const { symbol } = containingClass; const name = getSymbolNameForPrivateIdentifier(symbol, propName); const prop = (symbol.members && symbol.members.get(name)) || (symbol.exports && symbol.exports.get(name)); @@ -31488,10 +40745,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isForInStatement(privId.parent)) { if (!isExpressionNode(privId)) { - return grammarErrorOnNode(privId, Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression); + return grammarErrorOnNode( + privId, + Diagnostics + .Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression, + ); } - const isInOperation = isBinaryExpression(privId.parent) && privId.parent.operatorToken.kind === SyntaxKind.InKeyword; + const isInOperation = isBinaryExpression(privId.parent) + && privId.parent.operatorToken.kind === SyntaxKind.InKeyword; if (!getSymbolForPrivateIdentifierExpression(privId) && !isInOperation) { return grammarErrorOnNode(privId, Diagnostics.Cannot_find_name_0, idText(privId)); } @@ -31525,7 +40787,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getPropertyOfType(leftType, lexicallyScopedIdentifier.escapedName); } - function checkPrivateIdentifierPropertyAccess(leftType: Type, right: PrivateIdentifier, lexicallyScopedIdentifier: Symbol | undefined): boolean { + function checkPrivateIdentifierPropertyAccess( + leftType: Type, + right: PrivateIdentifier, + lexicallyScopedIdentifier: Symbol | undefined, + ): boolean { // Either the identifier could not be looked up in the lexical scope OR the lexically scoped identifier did not exist on the type. // Find a private identifier with the same description on the type. let propertyOnType: Symbol | undefined; @@ -31533,7 +40799,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (properties) { forEach(properties, (symbol: Symbol) => { const decl = symbol.valueDeclaration; - if (decl && isNamedDeclaration(decl) && isPrivateIdentifier(decl.name) && decl.name.escapedText === right.escapedText) { + if ( + decl && isNamedDeclaration(decl) && isPrivateIdentifier(decl.name) + && decl.name.escapedText === right.escapedText + ) { propertyOnType = symbol; return true; } @@ -31554,9 +40823,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (findAncestor(lexicalClass, n => typeClass === n)) { const diagnostic = error( right, - Diagnostics.The_property_0_cannot_be_accessed_on_type_1_within_this_class_because_it_is_shadowed_by_another_private_identifier_with_the_same_spelling, + Diagnostics + .The_property_0_cannot_be_accessed_on_type_1_within_this_class_because_it_is_shadowed_by_another_private_identifier_with_the_same_spelling, diagName, - typeToString(leftType) + typeToString(leftType), ); addRelatedInfo( @@ -31564,13 +40834,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { createDiagnosticForNode( lexicalValueDecl, Diagnostics.The_shadowing_declaration_of_0_is_defined_here, - diagName + diagName, ), createDiagnosticForNode( typeValueDecl, Diagnostics.The_declaration_of_0_that_you_probably_intended_to_use_is_defined_here, - diagName - ) + diagName, + ), ); return true; } @@ -31579,22 +40849,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { right, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_identifier, diagName, - diagnosticName(typeClass.name || anon) + diagnosticName(typeClass.name || anon), ); return true; } return false; } - function isThisPropertyAccessInConstructor(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol) { + function isThisPropertyAccessInConstructor( + node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, + prop: Symbol, + ) { return (isConstructorDeclaredProperty(prop) || isThisProperty(node) && isAutoTypedProperty(prop)) - && getThisContainer(node, /*includeArrowFunctions*/ true, /*includeClassComputedPropertyName*/ false) === getDeclaringConstructor(prop); + && getThisContainer(node, /*includeArrowFunctions*/ true, /*includeClassComputedPropertyName*/ false) + === getDeclaringConstructor(prop); } - function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, leftType: Type, right: Identifier | PrivateIdentifier, checkMode: CheckMode | undefined, writeOnly?: boolean) { + function checkPropertyAccessExpressionOrQualifiedName( + node: PropertyAccessExpression | QualifiedName, + left: Expression | QualifiedName, + leftType: Type, + right: Identifier | PrivateIdentifier, + checkMode: CheckMode | undefined, + writeOnly?: boolean, + ) { const parentSymbol = getNodeLinks(left).resolvedSymbol; const assignmentKind = getAssignmentTargetKind(node); - const apparentType = getApparentType(assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType); + const apparentType = getApparentType( + assignmentKind !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(leftType) : leftType, + ); const isAnyLike = isTypeAny(apparentType) || apparentType === silentNeverType; let prop: Symbol | undefined; if (isPrivateIdentifier(right)) { @@ -31608,8 +40891,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const lexicallyScopedSymbol = lookupSymbolForPrivateIdentifierDeclaration(right.escapedText, right); - if (assignmentKind && lexicallyScopedSymbol && lexicallyScopedSymbol.valueDeclaration && isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration)) { - grammarErrorOnNode(right, Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, idText(right)); + if ( + assignmentKind && lexicallyScopedSymbol && lexicallyScopedSymbol.valueDeclaration + && isMethodDeclaration(lexicallyScopedSymbol.valueDeclaration) + ) { + grammarErrorOnNode( + right, + Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable, + idText(right), + ); } if (isAnyLike) { if (lexicallyScopedSymbol) { @@ -31629,11 +40919,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const containingClass = getContainingClassExcludingClassDecorators(right); if (containingClass && isPlainJsFile(getSourceFileOfNode(containingClass), compilerOptions.checkJs)) { - grammarErrorOnNode(right, Diagnostics.Private_field_0_must_be_declared_in_an_enclosing_class, idText(right)); + grammarErrorOnNode( + right, + Diagnostics.Private_field_0_must_be_declared_in_an_enclosing_class, + idText(right), + ); } } else { - const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); + const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor + && !(prop.flags & SymbolFlags.GetAccessor); if (isSetonlyAccessor && assignmentKind !== AssignmentKind.Definite) { error(node, Diagnostics.Private_accessor_was_defined_without_a_getter); } @@ -31646,7 +40941,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return isErrorType(apparentType) ? errorType : apparentType; } - prop = getPropertyOfType(apparentType, right.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ node.kind === SyntaxKind.QualifiedName); + prop = getPropertyOfType( + apparentType, + right.escapedText, + /*skipObjectFunctionPropertyAugment*/ false, + /*includeTypeOnlyMembers*/ node.kind === SyntaxKind.QualifiedName, + ); } // In `Foo.Bar.Baz`, 'Foo' is not referenced if 'Bar' is a const enum or a module containing only const enums. // `Foo` is also not referenced in `enum FooCopy { Bar = Foo.Bar }`, because the enum member value gets inlined @@ -31655,34 +40955,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The exceptions are: // 1. if 'isolatedModules' is enabled, because the const enum value will not be inlined, and // 2. if 'preserveConstEnums' is enabled and the expression is itself an export, e.g. `export = Foo.Bar.Baz`. - if (isIdentifier(left) && parentSymbol && ( - getIsolatedModules(compilerOptions) || - !(prop && (isConstEnumOrConstEnumOnlyModule(prop) || prop.flags & SymbolFlags.EnumMember && node.parent.kind === SyntaxKind.EnumMember)) || - shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(node) - )) { + if ( + isIdentifier(left) && parentSymbol && ( + getIsolatedModules(compilerOptions) + || !(prop + && (isConstEnumOrConstEnumOnlyModule(prop) + || prop.flags & SymbolFlags.EnumMember && node.parent.kind === SyntaxKind.EnumMember)) + || shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(node) + ) + ) { markAliasReferenced(parentSymbol, node); } let propType: Type; if (!prop) { - const indexInfo = !isPrivateIdentifier(right) && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) || isThisTypeParameter(leftType)) ? - getApplicableIndexInfoForName(apparentType, right.escapedText) : undefined; + const indexInfo = !isPrivateIdentifier(right) + && (assignmentKind === AssignmentKind.None || !isGenericObjectType(leftType) + || isThisTypeParameter(leftType)) + ? getApplicableIndexInfoForName(apparentType, right.escapedText) : undefined; if (!(indexInfo && indexInfo.type)) { const isUncheckedJS = isUncheckedJSSuggestion(node, leftType.symbol, /*excludeClasses*/ true); if (!isUncheckedJS && isJSLiteralType(leftType)) { return anyType; } if (leftType.symbol === globalThisSymbol) { - if (globalThisSymbol.exports!.has(right.escapedText) && (globalThisSymbol.exports!.get(right.escapedText)!.flags & SymbolFlags.BlockScoped)) { - error(right, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(right.escapedText), typeToString(leftType)); + if ( + globalThisSymbol.exports!.has(right.escapedText) + && (globalThisSymbol.exports!.get(right.escapedText)!.flags & SymbolFlags.BlockScoped) + ) { + error( + right, + Diagnostics.Property_0_does_not_exist_on_type_1, + unescapeLeadingUnderscores(right.escapedText), + typeToString(leftType), + ); } else if (noImplicitAny) { - error(right, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(leftType)); + error( + right, + Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, + typeToString(leftType), + ); } return anyType; } if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) { - reportNonexistentProperty(right, isThisTypeParameter(leftType) ? apparentType : leftType, isUncheckedJS); + reportNonexistentProperty( + right, + isThisTypeParameter(leftType) ? apparentType : leftType, + isUncheckedJS, + ); } return errorType; } @@ -31690,9 +41012,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType)); } - propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) ? getUnionType([indexInfo.type, missingType]) : indexInfo.type; + propType = (compilerOptions.noUncheckedIndexedAccess && !isAssignmentTarget(node)) + ? getUnionType([indexInfo.type, missingType]) : indexInfo.type; if (compilerOptions.noPropertyAccessFromIndexSignature && isPropertyAccessExpression(node)) { - error(right, Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, unescapeLeadingUnderscores(right.escapedText)); + error( + right, + Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0, + unescapeLeadingUnderscores(right.escapedText), + ); } if (indexInfo.declaration && isDeprecatedDeclaration(indexInfo.declaration)) { addDeprecatedSuggestion(right, [indexInfo.declaration], right.escapedText as string); @@ -31700,19 +41027,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { const targetPropSymbol = resolveAliasWithDeprecationCheck(prop, right); - if (isDeprecatedSymbol(targetPropSymbol) && isUncalledFunctionReference(node, targetPropSymbol) && targetPropSymbol.declarations) { + if ( + isDeprecatedSymbol(targetPropSymbol) && isUncalledFunctionReference(node, targetPropSymbol) + && targetPropSymbol.declarations + ) { addDeprecatedSuggestion(right, targetPropSymbol.declarations, right.escapedText as string); } checkPropertyNotUsedBeforeDeclaration(prop, node, right); markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol)); getNodeLinks(node).resolvedSymbol = prop; - checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, isWriteAccess(node), apparentType, prop); + checkPropertyAccessibility( + node, + left.kind === SyntaxKind.SuperKeyword, + isWriteAccess(node), + apparentType, + prop, + ); if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) { error(right, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, idText(right)); return errorType; } - propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : writeOnly || isWriteOnlyAccess(node) ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); + propType = isThisPropertyAccessInConstructor(node, prop) ? autoType + : writeOnly || isWriteOnlyAccess(node) ? getWriteTypeOfSymbol(prop) : getTypeOfSymbol(prop); } return getFlowTypeOfAccessExpression(node, prop, propType, right, checkMode); @@ -31725,20 +41062,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * - Is from a global file that is different from the reference file, or * - (optionally) Is a class, or is a this.x property access expression */ - function isUncheckedJSSuggestion(node: Node | undefined, suggestion: Symbol | undefined, excludeClasses: boolean): boolean { + function isUncheckedJSSuggestion( + node: Node | undefined, + suggestion: Symbol | undefined, + excludeClasses: boolean, + ): boolean { const file = getSourceFileOfNode(node); if (file) { - if (compilerOptions.checkJs === undefined && file.checkJsDirective === undefined && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX)) { + if ( + compilerOptions.checkJs === undefined && file.checkJsDirective === undefined + && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX) + ) { const declarationFile = forEach(suggestion?.declarations, getSourceFileOfNode); return !(file !== declarationFile && !!declarationFile && isGlobalSourceFile(declarationFile)) && !(excludeClasses && suggestion && suggestion.flags & SymbolFlags.Class) - && !(!!node && excludeClasses && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword); + && !(!!node && excludeClasses && isPropertyAccessExpression(node) + && node.expression.kind === SyntaxKind.ThisKeyword); } } return false; } - function getFlowTypeOfAccessExpression(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol | undefined, propType: Type, errorNode: Node, checkMode: CheckMode | undefined) { + function getFlowTypeOfAccessExpression( + node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, + prop: Symbol | undefined, + propType: Type, + errorNode: Node, + checkMode: CheckMode | undefined, + ) { // Only compute control flow type if this is a property access expression that isn't an // assignment target, and the referenced property was declared as a variable, property, // accessor, or optional method. @@ -31746,10 +41097,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (assignmentKind === AssignmentKind.Definite) { return removeMissingType(propType, !!(prop && prop.flags & SymbolFlags.Optional)); } - if (prop && - !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) + if ( + prop + && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union) - && !isDuplicatedCommonJSExport(prop.declarations)) { + && !isDuplicatedCommonJSExport(prop.declarations) + ) { return propType; } if (propType === autoType) { @@ -31761,24 +41114,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and if we are in a constructor of the same class as the property declaration, assume that // the property is uninitialized at the top of the control flow. let assumeUninitialized = false; - if (strictNullChecks && strictPropertyInitialization && isAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword) { + if ( + strictNullChecks && strictPropertyInitialization && isAccessExpression(node) + && node.expression.kind === SyntaxKind.ThisKeyword + ) { const declaration = prop && prop.valueDeclaration; if (declaration && isPropertyWithoutInitializer(declaration)) { if (!isStatic(declaration)) { const flowContainer = getControlFlowContainer(node); - if (flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent && !(declaration.flags & NodeFlags.Ambient)) { + if ( + flowContainer.kind === SyntaxKind.Constructor && flowContainer.parent === declaration.parent + && !(declaration.flags & NodeFlags.Ambient) + ) { assumeUninitialized = true; } } } } - else if (strictNullChecks && prop && prop.valueDeclaration && - isPropertyAccessExpression(prop.valueDeclaration) && - getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration) && - getControlFlowContainer(node) === getControlFlowContainer(prop.valueDeclaration)) { + else if ( + strictNullChecks && prop && prop.valueDeclaration + && isPropertyAccessExpression(prop.valueDeclaration) + && getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration) + && getControlFlowContainer(node) === getControlFlowContainer(prop.valueDeclaration) + ) { assumeUninitialized = true; } - const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType); + const flowType = getFlowTypeOfReference( + node, + propType, + assumeUninitialized ? getOptionalType(propType) : propType, + ); if (assumeUninitialized && !containsUndefinedType(propType) && containsUndefinedType(flowType)) { error(errorNode, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 // Return the declared type to reduce follow-on errors @@ -31787,7 +41152,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; } - function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier | PrivateIdentifier): void { + function checkPropertyNotUsedBeforeDeclaration( + prop: Symbol, + node: PropertyAccessExpression | QualifiedName, + right: Identifier | PrivateIdentifier, + ): void { const { valueDeclaration } = prop; if (!valueDeclaration || getSourceFileOfNode(node).isDeclarationFile) { return; @@ -31795,24 +41164,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let diagnosticMessage; const declarationName = idText(right); - if (isInPropertyInitializerOrClassStaticBlock(node) + if ( + isInPropertyInitializerOrClassStaticBlock(node) && !isOptionalPropertyDeclaration(valueDeclaration) && !(isAccessExpression(node) && isAccessExpression(node.expression)) && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) - && !(isMethodDeclaration(valueDeclaration) && getCombinedModifierFlagsCached(valueDeclaration) & ModifierFlags.Static) - && (useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop))) { + && !(isMethodDeclaration(valueDeclaration) + && getCombinedModifierFlagsCached(valueDeclaration) & ModifierFlags.Static) + && (useDefineForClassFields || !isPropertyDeclaredInAncestorClass(prop)) + ) { diagnosticMessage = error(right, Diagnostics.Property_0_is_used_before_its_initialization, declarationName); } - else if (valueDeclaration.kind === SyntaxKind.ClassDeclaration && - node.parent.kind !== SyntaxKind.TypeReference && - !(valueDeclaration.flags & NodeFlags.Ambient) && - !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right)) { + else if ( + valueDeclaration.kind === SyntaxKind.ClassDeclaration + && node.parent.kind !== SyntaxKind.TypeReference + && !(valueDeclaration.flags & NodeFlags.Ambient) + && !isBlockScopedNameDeclaredBeforeUse(valueDeclaration, right) + ) { diagnosticMessage = error(right, Diagnostics.Class_0_used_before_its_declaration, declarationName); } if (diagnosticMessage) { - addRelatedInfo(diagnosticMessage, - createDiagnosticForNode(valueDeclaration, Diagnostics._0_is_declared_here, declarationName) + addRelatedInfo( + diagnosticMessage, + createDiagnosticForNode(valueDeclaration, Diagnostics._0_is_declared_here, declarationName), ); } } @@ -31875,13 +41250,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getIntersectionType(x); } - function reportNonexistentProperty(propNode: Identifier | PrivateIdentifier, containingType: Type, isUncheckedJS: boolean) { + function reportNonexistentProperty( + propNode: Identifier | PrivateIdentifier, + containingType: Type, + isUncheckedJS: boolean, + ) { let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: Diagnostic | undefined; - if (!isPrivateIdentifier(propNode) && containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) { + if ( + !isPrivateIdentifier(propNode) && containingType.flags & TypeFlags.Union + && !(containingType.flags & TypeFlags.Primitive) + ) { for (const subtype of (containingType as UnionType).types) { - if (!getPropertyOfType(subtype, propNode.escapedText) && !getApplicableIndexInfoForName(subtype, propNode.escapedText)) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(subtype)); + if ( + !getPropertyOfType(subtype, propNode.escapedText) + && !getApplicableIndexInfoForName(subtype, propNode.escapedText) + ) { + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Property_0_does_not_exist_on_type_1, + declarationNameToString(propNode), + typeToString(subtype), + ); break; } } @@ -31889,12 +41279,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeHasStaticProperty(propNode.escapedText, containingType)) { const propName = declarationNameToString(propNode); const typeName = typeToString(containingType); - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName, typeName, typeName + "." + propName); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, + propName, + typeName, + typeName + "." + propName, + ); } else { const promisedType = getPromisedTypeOfPromise(containingType); if (promisedType && getPropertyOfType(promisedType, propNode.escapedText)) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType)); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Property_0_does_not_exist_on_type_1, + declarationNameToString(propNode), + typeToString(containingType), + ); relatedInfo = createDiagnosticForNode(propNode, Diagnostics.Did_you_forget_to_use_await); } else { @@ -31902,36 +41303,75 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const container = typeToString(containingType); const libSuggestion = getSuggestedLibForNonExistentProperty(missingProperty, containingType); if (libSuggestion !== undefined) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_2_or_later, missingProperty, container, libSuggestion); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics + .Property_0_does_not_exist_on_type_1_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_2_or_later, + missingProperty, + container, + libSuggestion, + ); } else { const suggestion = getSuggestedSymbolForNonexistentProperty(propNode, containingType); if (suggestion !== undefined) { const suggestedName = symbolName(suggestion); - const message = isUncheckedJS ? Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2 : Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2; - errorInfo = chainDiagnosticMessages(errorInfo, message, missingProperty, container, suggestedName); - relatedInfo = suggestion.valueDeclaration && createDiagnosticForNode(suggestion.valueDeclaration, Diagnostics._0_is_declared_here, suggestedName); + const message = isUncheckedJS ? Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2 + : Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2; + errorInfo = chainDiagnosticMessages( + errorInfo, + message, + missingProperty, + container, + suggestedName, + ); + relatedInfo = suggestion.valueDeclaration + && createDiagnosticForNode( + suggestion.valueDeclaration, + Diagnostics._0_is_declared_here, + suggestedName, + ); } else { const diagnostic = containerSeemsToBeEmptyDomElement(containingType) - ? Diagnostics.Property_0_does_not_exist_on_type_1_Try_changing_the_lib_compiler_option_to_include_dom + ? Diagnostics + .Property_0_does_not_exist_on_type_1_Try_changing_the_lib_compiler_option_to_include_dom : Diagnostics.Property_0_does_not_exist_on_type_1; - errorInfo = chainDiagnosticMessages(elaborateNeverIntersection(errorInfo, containingType), diagnostic, missingProperty, container); + errorInfo = chainDiagnosticMessages( + elaborateNeverIntersection(errorInfo, containingType), + diagnostic, + missingProperty, + container, + ); } } } } - const resultDiagnostic = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(propNode), propNode, errorInfo); + const resultDiagnostic = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(propNode), + propNode, + errorInfo, + ); if (relatedInfo) { addRelatedInfo(resultDiagnostic, relatedInfo); } - addErrorOrSuggestion(!isUncheckedJS || errorInfo.code !== Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2.code, resultDiagnostic); + addErrorOrSuggestion( + !isUncheckedJS || errorInfo.code !== Diagnostics.Property_0_may_not_exist_on_type_1_Did_you_mean_2.code, + resultDiagnostic, + ); } function containerSeemsToBeEmptyDomElement(containingType: Type) { - return (compilerOptions.lib && !compilerOptions.lib.includes("dom")) && - everyContainedType(containingType, type => type.symbol && /^(EventTarget|Node|((HTML[a-zA-Z]*)?Element))$/.test(unescapeLeadingUnderscores(type.symbol.escapedName))) && - isEmptyObjectType(containingType); + return (compilerOptions.lib && !compilerOptions.lib.includes("dom")) + && everyContainedType( + containingType, + type => + type.symbol + && /^(EventTarget|Node|((HTML[a-zA-Z]*)?Element))$/.test( + unescapeLeadingUnderscores(type.symbol.escapedName), + ), + ) + && isEmptyObjectType(containingType); } function typeHasStaticProperty(propName: __String, containingType: Type): boolean { @@ -31967,7 +41407,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getSpellingSuggestionForName(name, getPropertiesOfType(baseType), SymbolFlags.ClassMember); } - function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { + function getSuggestedSymbolForNonexistentProperty( + name: Identifier | PrivateIdentifier | string, + containingType: Type, + ): Symbol | undefined { let props = getPropertiesOfType(containingType); if (typeof name !== "string") { const parent = name.parent; @@ -31979,7 +41422,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getSpellingSuggestionForName(name, props, SymbolFlags.Value); } - function getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { + function getSuggestedSymbolForNonexistentJSXAttribute( + name: Identifier | PrivateIdentifier | string, + containingType: Type, + ): Symbol | undefined { const strName = isString(name) ? name : idText(name); const properties = getPropertiesOfType(containingType); const jsxSpecific = strName === "for" ? find(properties, x => symbolName(x) === "htmlFor") @@ -31988,44 +41434,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return jsxSpecific ?? getSpellingSuggestionForName(strName, properties, SymbolFlags.Value); } - function getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined { + function getSuggestionForNonexistentProperty( + name: Identifier | PrivateIdentifier | string, + containingType: Type, + ): string | undefined { const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType); return suggestion && symbolName(suggestion); } - function getSuggestedSymbolForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): Symbol | undefined { + function getSuggestedSymbolForNonexistentSymbol( + location: Node | undefined, + outerName: __String, + meaning: SymbolFlags, + ): Symbol | undefined { Debug.assert(outerName !== undefined, "outername should always be defined"); - const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, /*excludeGlobals*/ false, /*getSpellingSuggestions*/ true, (symbols, name, meaning) => { - Debug.assertEqual(outerName, name, "name should equal outerName"); - const symbol = getSymbol(symbols, name, meaning); - // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function - // So the table *contains* `x` but `x` isn't actually in scope. - // However, resolveNameHelper will continue and call this callback again, so we'll eventually get a correct suggestion. - if (symbol) return symbol; - let candidates: Symbol[]; - if (symbols === globals) { - const primitives = mapDefined( - ["string", "number", "boolean", "object", "bigint", "symbol"], - s => symbols.has((s.charAt(0).toUpperCase() + s.slice(1)) as __String) - ? createSymbol(SymbolFlags.TypeAlias, s as __String) as Symbol - : undefined); - candidates = primitives.concat(arrayFrom(symbols.values())); - } - else { - candidates = arrayFrom(symbols.values()); - } - return getSpellingSuggestionForName(unescapeLeadingUnderscores(name), candidates, meaning); - }); + const result = resolveNameHelper( + location, + outerName, + meaning, + /*nameNotFoundMessage*/ undefined, + outerName, + /*isUse*/ false, + /*excludeGlobals*/ false, + /*getSpellingSuggestions*/ true, + (symbols, name, meaning) => { + Debug.assertEqual(outerName, name, "name should equal outerName"); + const symbol = getSymbol(symbols, name, meaning); + // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function + // So the table *contains* `x` but `x` isn't actually in scope. + // However, resolveNameHelper will continue and call this callback again, so we'll eventually get a correct suggestion. + if (symbol) return symbol; + let candidates: Symbol[]; + if (symbols === globals) { + const primitives = mapDefined( + ["string", "number", "boolean", "object", "bigint", "symbol"], + s => symbols.has((s.charAt(0).toUpperCase() + s.slice(1)) as __String) + ? createSymbol(SymbolFlags.TypeAlias, s as __String) as Symbol + : undefined, + ); + candidates = primitives.concat(arrayFrom(symbols.values())); + } + else { + candidates = arrayFrom(symbols.values()); + } + return getSpellingSuggestionForName(unescapeLeadingUnderscores(name), candidates, meaning); + }, + ); return result; } - function getSuggestionForNonexistentSymbol(location: Node | undefined, outerName: __String, meaning: SymbolFlags): string | undefined { + function getSuggestionForNonexistentSymbol( + location: Node | undefined, + outerName: __String, + meaning: SymbolFlags, + ): string | undefined { const symbolResult = getSuggestedSymbolForNonexistentSymbol(location, outerName, meaning); return symbolResult && symbolName(symbolResult); } function getSuggestedSymbolForNonexistentModule(name: Identifier, targetModule: Symbol): Symbol | undefined { - return targetModule.exports && getSpellingSuggestionForName(idText(name), getExportsOfModuleAsArray(targetModule), SymbolFlags.ModuleMember); + return targetModule.exports + && getSpellingSuggestionForName( + idText(name), + getExportsOfModuleAsArray(targetModule), + SymbolFlags.ModuleMember, + ); } function getSuggestionForNonexistentExport(name: Identifier, targetModule: Symbol): string | undefined { @@ -32033,7 +41506,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return suggestion && symbolName(suggestion); } - function getSuggestionForNonexistentIndexSignature(objectType: Type, expr: ElementAccessExpression, keyedType: Type): string | undefined { + function getSuggestionForNonexistentIndexSignature( + objectType: Type, + expr: ElementAccessExpression, + keyedType: Type, + ): string | undefined { // check if object type has setter or getter function hasProp(name: "set" | "get") { const prop = getPropertyOfObjectType(objectType, name as __String); @@ -32060,8 +41537,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return suggestion; } - function getSuggestedTypeForNonexistentStringLiteralType(source: StringLiteralType, target: UnionType): StringLiteralType | undefined { - const candidates = target.types.filter((type): type is StringLiteralType => !!(type.flags & TypeFlags.StringLiteral)); + function getSuggestedTypeForNonexistentStringLiteralType( + source: StringLiteralType, + target: UnionType, + ): StringLiteralType | undefined { + const candidates = target.types.filter((type): type is StringLiteralType => + !!(type.flags & TypeFlags.StringLiteral) + ); return getSpellingSuggestion(source.value, candidates, type => type.value); } @@ -32085,7 +41567,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getCandidateName(candidate: Symbol) { const candidateName = symbolName(candidate); - if (startsWith(candidateName, "\"")) { + if (startsWith(candidateName, '"')) { return undefined; } @@ -32104,17 +41586,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isSelfTypeAccess: boolean) { + function markPropertyAsReferenced( + prop: Symbol, + nodeForCheckWriteOnly: Node | undefined, + isSelfTypeAccess: boolean, + ) { const valueDeclaration = prop && (prop.flags & SymbolFlags.ClassMember) && prop.valueDeclaration; if (!valueDeclaration) { return; } const hasPrivateModifier = hasEffectiveModifier(valueDeclaration, ModifierFlags.Private); - const hasPrivateIdentifier = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) && isPrivateIdentifier(prop.valueDeclaration.name); + const hasPrivateIdentifier = prop.valueDeclaration && isNamedDeclaration(prop.valueDeclaration) + && isPrivateIdentifier(prop.valueDeclaration.name); if (!hasPrivateModifier && !hasPrivateIdentifier) { return; } - if (nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) && !(prop.flags & SymbolFlags.SetAccessor)) { + if ( + nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) && !(prop.flags & SymbolFlags.SetAccessor) + ) { return; } if (isSelfTypeAccess) { @@ -32125,7 +41614,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - (getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop)!.isReferenced = SymbolFlags.All; + (getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop)!.isReferenced = + SymbolFlags.All; } function isSelfTypeAccess(name: Expression | QualifiedName, parent: Symbol | undefined) { @@ -32133,12 +41623,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || !!parent && isEntityNameExpression(name) && parent === getResolvedSymbol(getFirstIdentifier(name)); } - function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: __String): boolean { + function isValidPropertyAccess( + node: PropertyAccessExpression | QualifiedName | ImportTypeNode, + propertyName: __String, + ): boolean { switch (node.kind) { case SyntaxKind.PropertyAccessExpression: - return isValidPropertyAccessWithType(node, node.expression.kind === SyntaxKind.SuperKeyword, propertyName, getWidenedType(checkExpression(node.expression))); + return isValidPropertyAccessWithType( + node, + node.expression.kind === SyntaxKind.SuperKeyword, + propertyName, + getWidenedType(checkExpression(node.expression)), + ); case SyntaxKind.QualifiedName: - return isValidPropertyAccessWithType(node, /*isSuper*/ false, propertyName, getWidenedType(checkExpression(node.left))); + return isValidPropertyAccessWithType( + node, + /*isSuper*/ false, + propertyName, + getWidenedType(checkExpression(node.left)), + ); case SyntaxKind.ImportType: return isValidPropertyAccessWithType(node, /*isSuper*/ false, propertyName, getTypeFromTypeNode(node)); } @@ -32154,12 +41657,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param type the type whose property we are checking. * @param property the accessed property's symbol. */ - function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode | QualifiedName, type: Type, property: Symbol): boolean { - return isPropertyAccessible(node, + function isValidPropertyAccessForCompletions( + node: PropertyAccessExpression | ImportTypeNode | QualifiedName, + type: Type, + property: Symbol, + ): boolean { + return isPropertyAccessible( + node, node.kind === SyntaxKind.PropertyAccessExpression && node.expression.kind === SyntaxKind.SuperKeyword, /*isWrite*/ false, type, - property); + property, + ); // Previously we validated the 'this' type of methods but this adversely affected performance. See #31377 for more context. } @@ -32167,8 +41676,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node: PropertyAccessExpression | QualifiedName | ImportTypeNode, isSuper: boolean, propertyName: __String, - type: Type): boolean { - + type: Type, + ): boolean { // Short-circuiting for improved performance. if (isTypeAny(type)) { return true; @@ -32193,16 +41702,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isSuper: boolean, isWrite: boolean, containingType: Type, - property: Symbol): boolean { - + property: Symbol, + ): boolean { // Short-circuiting for improved performance. if (isTypeAny(containingType)) { return true; } // A #private property access in an optional chain is an error dealt with by the parser. - // The checker does not check for it, so we need to do our own check here. - if (property.valueDeclaration && isPrivateIdentifierClassElementDeclaration(property.valueDeclaration)) { + // The checker does not check for it, so we need to do our own check here. + if (property.valueDeclaration && isPrivateIdentifierClassElementDeclaration(property.valueDeclaration)) { const declClass = getContainingClass(property.valueDeclaration); return !isOptionalChain(node) && !!findAncestor(node, parent => parent === declClass); } @@ -32246,10 +41755,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let child: Node = expr; let node = expr.parent; while (node) { - if (node.kind === SyntaxKind.ForInStatement && - child === (node as ForInStatement).statement && - getForInVariableSymbol(node as ForInStatement) === symbol && - hasNumericPropertyNames(getTypeOfExpression((node as ForInStatement).expression))) { + if ( + node.kind === SyntaxKind.ForInStatement + && child === (node as ForInStatement).statement + && getForInVariableSymbol(node as ForInStatement) === symbol + && hasNumericPropertyNames(getTypeOfExpression((node as ForInStatement).expression)) + ) { return true; } child = node; @@ -32261,18 +41772,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkIndexedAccess(node: ElementAccessExpression, checkMode: CheckMode | undefined): Type { - return node.flags & NodeFlags.OptionalChain ? checkElementAccessChain(node as ElementAccessChain, checkMode) : - checkElementAccessExpression(node, checkNonNullExpression(node.expression), checkMode); + return node.flags & NodeFlags.OptionalChain ? checkElementAccessChain(node as ElementAccessChain, checkMode) + : checkElementAccessExpression(node, checkNonNullExpression(node.expression), checkMode); } function checkElementAccessChain(node: ElementAccessChain, checkMode: CheckMode | undefined) { const exprType = checkExpression(node.expression); const nonOptionalType = getOptionalExpressionType(exprType, node.expression); - return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression), checkMode), node, nonOptionalType !== exprType); + return propagateOptionalTypeMarker( + checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression), checkMode), + node, + nonOptionalType !== exprType, + ); } - function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type, checkMode: CheckMode | undefined): Type { - const objectType = getAssignmentTargetKind(node) !== AssignmentKind.None || isMethodAccessForCall(node) ? getWidenedType(exprType) : exprType; + function checkElementAccessExpression( + node: ElementAccessExpression, + exprType: Type, + checkMode: CheckMode | undefined, + ): Type { + const objectType = getAssignmentTargetKind(node) !== AssignmentKind.None || isMethodAccessForCall(node) + ? getWidenedType(exprType) : exprType; const indexExpression = node.argumentExpression; const indexType = checkExpression(indexExpression); @@ -32286,14 +41806,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const effectiveIndexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType; - const accessFlags = isAssignmentTarget(node) ? - AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) : - AccessFlags.ExpressionPosition; - const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node) || errorType; - return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, getNodeLinks(node).resolvedSymbol, indexedAccessType, indexExpression, checkMode), node); + const accessFlags = isAssignmentTarget(node) + ? AccessFlags.Writing + | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures + : 0) + : AccessFlags.ExpressionPosition; + const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node) + || errorType; + return checkIndexedAccessIndexType( + getFlowTypeOfAccessExpression( + node, + getNodeLinks(node).resolvedSymbol, + indexedAccessType, + indexExpression, + checkMode, + ), + node, + ); } - function callLikeExpressionMayHaveTypeArguments(node: CallLikeExpression): node is CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement { + function callLikeExpressionMayHaveTypeArguments( + node: CallLikeExpression, + ): node is CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement { return isCallOrNewExpression(node) || isTaggedTemplateExpression(node) || isJsxOpeningLikeElement(node); } @@ -32331,7 +41865,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // interface B extends A { (x: 'foo'): string } // const b: B; // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void] - function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags): void { + function reorderCandidates( + signatures: readonly Signature[], + result: Signature[], + callChainFlags: SignatureFlags, + ): void { let lastParent: Node | undefined; let lastSymbol: Symbol | undefined; let cutoffIndex = 0; @@ -32373,12 +41911,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { spliceIndex = index; } - result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags) : signature); + result.splice( + spliceIndex, + 0, + callChainFlags ? getOptionalCallSignature(signature, callChainFlags) : signature, + ); } } function isSpreadArgument(arg: Expression | undefined): arg is Expression { - return !!arg && (arg.kind === SyntaxKind.SpreadElement || arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).isSpread); + return !!arg + && (arg.kind === SyntaxKind.SpreadElement + || arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).isSpread); } function getSpreadArgumentIndex(args: readonly Expression[]): number { @@ -32393,7 +41937,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(t.flags & (TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Unknown | TypeFlags.Any)); } - function hasCorrectArity(node: CallLikeExpression, args: readonly Expression[], signature: Signature, signatureHelpTrailingComma = false) { + function hasCorrectArity( + node: CallLikeExpression, + args: readonly Expression[], + signature: Signature, + signatureHelpTrailingComma = false, + ) { let argCount: number; let callIsIncomplete = false; // In incomplete call we want to be lenient when we have too few arguments let effectiveParameterCount = getParameterCount(signature); @@ -32442,7 +41991,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If a spread argument is present, check that it corresponds to a rest parameter or at least that it's in the valid range. const spreadArgIndex = getSpreadArgumentIndex(args); if (spreadArgIndex >= 0) { - return spreadArgIndex >= getMinArgumentCount(signature) && (hasEffectiveRestParameter(signature) || spreadArgIndex < getParameterCount(signature)); + return spreadArgIndex >= getMinArgumentCount(signature) + && (hasEffectiveRestParameter(signature) || spreadArgIndex < getParameterCount(signature)); } } @@ -32458,7 +42008,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } for (let i = argCount; i < effectiveMinimumArguments; i++) { const type = getTypeAtPosition(signature, i); - if (filterType(type, isInJSFile(node) && !strictNullChecks ? acceptsVoidUndefinedUnknownOrAny : acceptsVoid).flags & TypeFlags.Never) { + if ( + filterType(type, isInJSFile(node) && !strictNullChecks ? acceptsVoidUndefinedUnknownOrAny : acceptsVoid) + .flags & TypeFlags.Never + ) { return false; } } @@ -32470,8 +42023,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the declared number of type parameters, the call has an incorrect arity. const numTypeParameters = length(signature.typeParameters); const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters); - return !some(typeArguments) || - (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters); + return !some(typeArguments) + || (typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters); } // If type has a single call signature and no other members, return that signature. Otherwise, return undefined. @@ -32480,18 +42033,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getSingleCallOrConstructSignature(type: Type): Signature | undefined { - return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false) || - getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ false); + return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false) + || getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ false); } function getSingleSignature(type: Type, kind: SignatureKind, allowMembers: boolean): Signature | undefined { if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); if (allowMembers || resolved.properties.length === 0 && resolved.indexInfos.length === 0) { - if (kind === SignatureKind.Call && resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0) { + if ( + kind === SignatureKind.Call && resolved.callSignatures.length === 1 + && resolved.constructSignatures.length === 0 + ) { return resolved.callSignatures[0]; } - if (kind === SignatureKind.Construct && resolved.constructSignatures.length === 1 && resolved.callSignatures.length === 0) { + if ( + kind === SignatureKind.Construct && resolved.constructSignatures.length === 1 + && resolved.callSignatures.length === 0 + ) { return resolved.constructSignatures[0]; } } @@ -32500,13 +42059,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec) - function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, inferenceContext?: InferenceContext, compareTypes?: TypeComparer): Signature { + function instantiateSignatureInContextOf( + signature: Signature, + contextualSignature: Signature, + inferenceContext?: InferenceContext, + compareTypes?: TypeComparer, + ): Signature { const context = createInferenceContext(signature.typeParameters!, signature, InferenceFlags.None, compareTypes); // We clone the inferenceContext to avoid fixing. For example, when the source signature is (x: T) => T[] and // the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any') // for T but leave it possible to later infer '[any]' back to A. const restType = getEffectiveRestType(contextualSignature); - const mapper = inferenceContext && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper : inferenceContext.mapper); + const mapper = inferenceContext + && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper + : inferenceContext.mapper); const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature; applyToParameterTypes(sourceSignature, signature, (source, target) => { // Type parameters from outer context referenced by source type are fixed by instantiation of the source type @@ -32517,10 +42083,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferTypes(context.inferences, source, target, InferencePriority.ReturnType); }); } - return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration)); + return getSignatureInstantiation( + signature, + getInferredTypes(context), + isInJSFile(contextualSignature.declaration), + ); } - function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, checkMode: CheckMode, context: InferenceContext): Type[] { + function inferJsxTypeArguments( + node: JsxOpeningLikeElement, + signature: Signature, + checkMode: CheckMode, + context: InferenceContext, + ): Type[] { const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, context, checkMode); inferTypes(context.inferences, checkAttrType, paramType); @@ -32532,12 +42107,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return voidType; } const thisArgumentType = checkExpression(thisArgumentNode); - return isOptionalChainRoot(thisArgumentNode.parent) ? getNonNullableType(thisArgumentType) : - isOptionalChain(thisArgumentNode.parent) ? removeOptionalTypeMarker(thisArgumentType) : - thisArgumentType; + return isOptionalChainRoot(thisArgumentNode.parent) ? getNonNullableType(thisArgumentType) + : isOptionalChain(thisArgumentNode.parent) ? removeOptionalTypeMarker(thisArgumentType) + : thisArgumentType; } - function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: readonly Expression[], checkMode: CheckMode, context: InferenceContext): Type[] { + function inferTypeArguments( + node: CallLikeExpression, + signature: Signature, + args: readonly Expression[], + checkMode: CheckMode, + context: InferenceContext, + ): Type[] { if (isJsxOpeningLikeElement(node)) { return inferJsxTypeArguments(node, signature, checkMode, context); } @@ -32548,12 +42129,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // return type of 'wrap'. if (node.kind !== SyntaxKind.Decorator) { const skipBindingPatterns = every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p)); - const contextualType = getContextualType(node, skipBindingPatterns ? ContextFlags.SkipBindingPatterns : ContextFlags.None); + const contextualType = getContextualType( + node, + skipBindingPatterns ? ContextFlags.SkipBindingPatterns : ContextFlags.None, + ); if (contextualType) { const inferenceTargetType = getReturnTypeOfSignature(signature); if (couldContainTypeVariables(inferenceTargetType)) { const outerContext = getInferenceContext(node); - const isFromBindingPattern = !skipBindingPatterns && getContextualType(node, ContextFlags.SkipBindingPatterns) !== contextualType; + const isFromBindingPattern = !skipBindingPatterns + && getContextualType(node, ContextFlags.SkipBindingPatterns) !== contextualType; // A return type inference from a binding pattern can be used in instantiating the contextual // type of an argument later in inference, but cannot stand on its own as the final return type. // It is incorporated into `context.returnMapper` which is used in `instantiateContextualType`, @@ -32568,7 +42153,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We clone the inference context to avoid disturbing a resolution in progress for an // outer call expression. Effectively we just want a snapshot of whatever has been // inferred for any outer call expression so far. - const outerMapper = getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlags.NoDefault)); + const outerMapper = getMapperFromContext( + cloneInferenceContext(outerContext, InferenceFlags.NoDefault), + ); const instantiatedType = instantiateType(contextualType, outerMapper); // If the contextual type is a generic function type with a single call signature, we // instantiate the type with its own type parameters and type arguments. This ensures that @@ -32578,11 +42165,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // const boxElements: (a: A[]) => { value: A }[] = arrayMap(value => ({ value })); // Above, the type of the 'value' parameter is inferred to be 'A'. const contextualSignature = getSingleCallSignature(instantiatedType); - const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? - getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) : - instantiatedType; + const inferenceSourceType = contextualSignature && contextualSignature.typeParameters + ? getOrCreateTypeFromSignature( + getSignatureInstantiationWithoutFillingInTypeArguments( + contextualSignature, + contextualSignature.typeParameters, + ), + ) + : instantiatedType; // Inferences made from return types have lower priority than all other inferences. - inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); + inferTypes( + context.inferences, + inferenceSourceType, + inferenceTargetType, + InferencePriority.ReturnType, + ); } // Create a type mapper for instantiating generic contextual types using the inferences made // from the return type. We need a separate inference pass here because (a) instantiation of @@ -32591,7 +42188,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); - context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; + context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) + ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; } } } @@ -32601,7 +42199,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (restType && restType.flags & TypeFlags.TypeParameter) { const info = find(context.inferences, info => info.typeParameter === restType); if (info) { - info.impliedArity = findIndex(args, isSpreadArgument, argCount) < 0 ? args.length - argCount : undefined; + info.impliedArity = findIndex(args, isSpreadArgument, argCount) < 0 ? args.length - argCount + : undefined; } } @@ -32631,13 +42230,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getMutableArrayOrTupleType(type: Type) { - return type.flags & TypeFlags.Union ? mapType(type, getMutableArrayOrTupleType) : - type.flags & TypeFlags.Any || isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) ? type : - isTupleType(type) ? createTupleType(getElementTypes(type), type.target.elementFlags, /*readonly*/ false, type.target.labeledElementDeclarations) : - createTupleType([type], [ElementFlags.Variadic]); - } - - function getSpreadArgumentType(args: readonly Expression[], index: number, argCount: number, restType: Type, context: InferenceContext | undefined, checkMode: CheckMode) { + return type.flags & TypeFlags.Union ? mapType(type, getMutableArrayOrTupleType) + : type.flags & TypeFlags.Any || isMutableArrayOrTuple(getBaseConstraintOfType(type) || type) ? type + : isTupleType(type) + ? createTupleType( + getElementTypes(type), + type.target.elementFlags, + /*readonly*/ false, + type.target.labeledElementDeclarations, + ) + : createTupleType([type], [ElementFlags.Variadic]); + } + + function getSpreadArgumentType( + args: readonly Expression[], + index: number, + argCount: number, + restType: Type, + context: InferenceContext | undefined, + checkMode: CheckMode, + ) { const inConstContext = isConstTypeVariable(restType); if (index >= argCount - 1) { @@ -32645,14 +42257,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isSpreadArgument(arg)) { // We are inferring from a spread expression in the last argument position, i.e. both the parameter // and the argument are ...x forms. - const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type : - checkExpressionWithContextualType((arg as SpreadElement).expression, restType, context, checkMode); + const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type + : checkExpressionWithContextualType( + (arg as SpreadElement).expression, + restType, + context, + checkMode, + ); if (isArrayLikeType(spreadType)) { return getMutableArrayOrTupleType(spreadType); } - return createArrayType(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg), inConstContext); + return createArrayType( + checkIteratedTypeOrElementType( + IterationUse.Spread, + spreadType, + undefinedType, + arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg, + ), + inConstContext, + ); } } const types = []; @@ -32661,23 +42286,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = index; i < argCount; i++) { const arg = args[i]; if (isSpreadArgument(arg)) { - const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type : checkExpression((arg as SpreadElement).expression); + const spreadType = arg.kind === SyntaxKind.SyntheticExpression ? (arg as SyntheticExpression).type + : checkExpression((arg as SpreadElement).expression); if (isArrayLikeType(spreadType)) { types.push(spreadType); flags.push(ElementFlags.Variadic); } else { - types.push(checkIteratedTypeOrElementType(IterationUse.Spread, spreadType, undefinedType, arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg)); + types.push( + checkIteratedTypeOrElementType( + IterationUse.Spread, + spreadType, + undefinedType, + arg.kind === SyntaxKind.SpreadElement ? (arg as SpreadElement).expression : arg, + ), + ); flags.push(ElementFlags.Rest); } } else { - const contextualType = isTupleType(restType) ? - getContextualTypeForElementExpression(restType, i - index, argCount - index) || unknownType : - getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual); + const contextualType = isTupleType(restType) + ? getContextualTypeForElementExpression(restType, i - index, argCount - index) || unknownType + : getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual); const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode); - const hasPrimitiveContextualType = inConstContext || maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); - types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType)); + const hasPrimitiveContextualType = inConstContext + || maybeTypeOfKind( + contextualType, + TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping, + ); + types.push( + hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType), + ); flags.push(ElementFlags.Required); } if (arg.kind === SyntaxKind.SyntheticExpression && (arg as SyntheticExpression).tupleNameSource) { @@ -32687,27 +42326,47 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createTupleType(types, flags, inConstContext, length(names) === length(types) ? names : undefined); } - function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined { + function checkTypeArguments( + signature: Signature, + typeArgumentNodes: readonly TypeNode[], + reportErrors: boolean, + headMessage?: DiagnosticMessage, + ): Type[] | undefined { const isJavascript = isInJSFile(signature.declaration); const typeParameters = signature.typeParameters!; - const typeArgumentTypes = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, getMinTypeArgumentCount(typeParameters), isJavascript); + const typeArgumentTypes = fillMissingTypeArguments( + map(typeArgumentNodes, getTypeFromTypeNode), + typeParameters, + getMinTypeArgumentCount(typeParameters), + isJavascript, + ); let mapper: TypeMapper | undefined; for (let i = 0; i < typeArgumentNodes.length; i++) { - Debug.assert(typeParameters[i] !== undefined, "Should not call checkTypeArguments with too many type arguments"); + Debug.assert( + typeParameters[i] !== undefined, + "Should not call checkTypeArguments with too many type arguments", + ); const constraint = getConstraintOfTypeParameter(typeParameters[i]); if (constraint) { - const errorInfo = reportErrors && headMessage ? (() => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Type_0_does_not_satisfy_the_constraint_1)) : undefined; + const errorInfo = reportErrors && headMessage ? (() => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Type_0_does_not_satisfy_the_constraint_1, + )) : undefined; const typeArgumentHeadMessage = headMessage || Diagnostics.Type_0_does_not_satisfy_the_constraint_1; if (!mapper) { mapper = createTypeMapper(typeParameters, typeArgumentTypes); } const typeArgument = typeArgumentTypes[i]; - if (!checkTypeAssignableTo( - typeArgument, - getTypeWithThisArgument(instantiateType(constraint, mapper), typeArgument), - reportErrors ? typeArgumentNodes[i] : undefined, - typeArgumentHeadMessage, - errorInfo)) { + if ( + !checkTypeAssignableTo( + typeArgument, + getTypeWithThisArgument(instantiateType(constraint, mapper), typeArgument), + reportErrors ? typeArgumentNodes[i] : undefined, + typeArgumentHeadMessage, + errorInfo, + ) + ) { return undefined; } } @@ -32742,14 +42401,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkMode: CheckMode, reportErrors: boolean, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, - errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } + errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; }, ) { // Stateless function components can have maximum of three arguments: "props", "context", and "updater". // However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props, // can be specified by users through attributes property. const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node); - const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*inferenceContext*/ undefined, checkMode); - const checkAttributesType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(attributesType) : attributesType; + const attributesType = checkExpressionWithContextualType( + node.attributes, + paramType, + /*inferenceContext*/ undefined, + checkMode, + ); + const checkAttributesType = checkMode & CheckMode.SkipContextSensitive + ? getRegularTypeOfObjectLiteral(attributesType) : attributesType; return checkTagNameDoesNotExpectTooManyArguments() && checkTypeRelatedToAndOptionallyElaborate( checkAttributesType, paramType, @@ -32758,13 +42423,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { node.attributes, /*headMessage*/ undefined, containingMessageChain, - errorOutputContainer); + errorOutputContainer, + ); function checkTagNameDoesNotExpectTooManyArguments(): boolean { if (getJsxNamespaceContainerForImplicitImport(node)) { return true; // factory is implicitly jsx/jsxdev - assume it fits the bill, since we don't strongly look for the jsx/jsxs/jsxDEV factory APIs anywhere else (at least not yet) } - const tagType = (isJsxOpeningElement(node) || isJsxSelfClosingElement(node)) && !(isJsxIntrinsicTagName(node.tagName) || isJsxNamespacedName(node.tagName)) ? checkExpression(node.tagName) : undefined; + const tagType = (isJsxOpeningElement(node) || isJsxSelfClosingElement(node)) + && !(isJsxIntrinsicTagName(node.tagName) || isJsxNamespacedName(node.tagName)) + ? checkExpression(node.tagName) : undefined; if (!tagType) { return true; } @@ -32776,7 +42444,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!factory) { return true; } - const factorySymbol = resolveEntityName(factory, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, node); + const factorySymbol = resolveEntityName( + factory, + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ false, + node, + ); if (!factorySymbol) { return true; } @@ -32822,10 +42496,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (reportErrors) { - const diag = createDiagnosticForNode(node.tagName, Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, entityNameToString(node.tagName), absoluteMinArgCount, entityNameToString(factory), maxParamCount); + const diag = createDiagnosticForNode( + node.tagName, + Diagnostics.Tag_0_expects_at_least_1_arguments_but_the_JSX_factory_2_provides_at_most_3, + entityNameToString(node.tagName), + absoluteMinArgCount, + entityNameToString(factory), + maxParamCount, + ); const tagNameDeclaration = getSymbolAtLocation(node.tagName)?.valueDeclaration; if (tagNameDeclaration) { - addRelatedInfo(diag, createDiagnosticForNode(tagNameDeclaration, Diagnostics._0_is_declared_here, entityNameToString(node.tagName))); + addRelatedInfo( + diag, + createDiagnosticForNode( + tagNameDeclaration, + Diagnostics._0_is_declared_here, + entityNameToString(node.tagName), + ), + ); } if (errorOutputContainer && errorOutputContainer.skipLogging) { (errorOutputContainer.errors || (errorOutputContainer.errors = [])).push(diag); @@ -32847,16 +42535,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reportErrors: boolean, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, ): readonly Diagnostic[] | undefined { - const errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } = { errors: undefined, skipLogging: true }; + const errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } = { + errors: undefined, + skipLogging: true, + }; if (isJsxOpeningLikeElement(node)) { - if (!checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "jsx should have errors when reporting errors"); + if ( + !checkApplicableSignatureForJsxOpeningLikeElement( + node, + signature, + relation, + checkMode, + reportErrors, + containingMessageChain, + errorOutputContainer, + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "jsx should have errors when reporting errors", + ); return errorOutputContainer.errors || emptyArray; } return undefined; } const thisType = getThisTypeOfSignature(signature); - if (thisType && thisType !== voidType && !(isNewExpression(node) || isCallExpression(node) && isSuperProperty(node.expression))) { + if ( + thisType && thisType !== voidType + && !(isNewExpression(node) || isCallExpression(node) && isSuperProperty(node.expression)) + ) { // If the called expression is not of the form `x.f` or `x["f"]`, then sourceType = voidType // If the signature's 'this' type is voidType, then the check is skipped -- anything is compatible. // If the expression is a new expression or super call expression, then the check is skipped. @@ -32864,8 +42571,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const thisArgumentType = getThisArgumentType(thisArgumentNode); const errorNode = reportErrors ? (thisArgumentNode || node) : undefined; const headMessage = Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1; - if (!checkTypeRelatedTo(thisArgumentType, thisType, relation, errorNode, headMessage, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "this parameter should have errors when reporting errors"); + if ( + !checkTypeRelatedTo( + thisArgumentType, + thisType, + relation, + errorNode, + headMessage, + containingMessageChain, + errorOutputContainer, + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "this parameter should have errors when reporting errors", + ); return errorOutputContainer.errors || emptyArray; } } @@ -32876,27 +42596,71 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression) { const paramType = getTypeAtPosition(signature, i); - const argType = checkExpressionWithContextualType(arg, paramType, /*inferenceContext*/ undefined, checkMode); + const argType = checkExpressionWithContextualType( + arg, + paramType, + /*inferenceContext*/ undefined, + checkMode, + ); // If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive), // we obtain the regular type of any object literal arguments because we may not have inferred complete // parameter types yet and therefore excess property checks may yield false positives (see #17041). - const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; - if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage, containingMessageChain, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors"); + const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) + : argType; + if ( + !checkTypeRelatedToAndOptionallyElaborate( + checkArgType, + paramType, + relation, + reportErrors ? arg : undefined, + arg, + headMessage, + containingMessageChain, + errorOutputContainer, + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "parameter should have errors when reporting errors", + ); maybeAddMissingAwaitInfo(arg, checkArgType, paramType); return errorOutputContainer.errors || emptyArray; } } } if (restType) { - const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, /*context*/ undefined, checkMode); + const spreadType = getSpreadArgumentType( + args, + argCount, + args.length, + restType, + /*context*/ undefined, + checkMode, + ); const restArgCount = args.length - argCount; - const errorNode = !reportErrors ? undefined : - restArgCount === 0 ? node : - restArgCount === 1 ? args[argCount] : - setTextRangePosEnd(createSyntheticExpression(node, spreadType), args[argCount].pos, args[args.length - 1].end); - if (!checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage, /*containingMessageChain*/ undefined, errorOutputContainer)) { - Debug.assert(!reportErrors || !!errorOutputContainer.errors, "rest parameter should have errors when reporting errors"); + const errorNode = !reportErrors ? undefined + : restArgCount === 0 ? node + : restArgCount === 1 ? args[argCount] + : setTextRangePosEnd( + createSyntheticExpression(node, spreadType), + args[argCount].pos, + args[args.length - 1].end, + ); + if ( + !checkTypeRelatedTo( + spreadType, + restType, + relation, + errorNode, + headMessage, + /*containingMessageChain*/ undefined, + errorOutputContainer, + ) + ) { + Debug.assert( + !reportErrors || !!errorOutputContainer.errors, + "rest parameter should have errors when reporting errors", + ); maybeAddMissingAwaitInfo(errorNode, spreadType, restType); return errorOutputContainer.errors || emptyArray; } @@ -32911,7 +42675,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const awaitedTypeOfSource = getAwaitedTypeOfPromise(source); if (awaitedTypeOfSource && isTypeRelatedTo(awaitedTypeOfSource, target, relation)) { - addRelatedInfo(errorOutputContainer.errors[0], createDiagnosticForNode(errorNode, Diagnostics.Did_you_forget_to_use_await)); + addRelatedInfo( + errorOutputContainer.errors[0], + createDiagnosticForNode(errorNode, Diagnostics.Did_you_forget_to_use_await), + ); } } } @@ -32921,10 +42688,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Returns the this argument in calls like x.f(...) and x[f](...). Undefined otherwise. */ function getThisArgumentOfCall(node: CallLikeExpression): LeftHandSideExpression | undefined { - const expression = node.kind === SyntaxKind.CallExpression ? node.expression : - node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag : - node.kind === SyntaxKind.Decorator && !legacyDecorators ? node.expression : - undefined; + const expression = node.kind === SyntaxKind.CallExpression ? node.expression + : node.kind === SyntaxKind.TaggedTemplateExpression ? node.tag + : node.kind === SyntaxKind.Decorator && !legacyDecorators ? node.expression + : undefined; if (expression) { const callee = skipOuterExpressions(expression); if (isAccessExpression(callee)) { @@ -32933,7 +42700,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function createSyntheticExpression(parent: Node, type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember) { + function createSyntheticExpression( + parent: Node, + type: Type, + isSpread?: boolean, + tupleNameSource?: ParameterDeclaration | NamedTupleMember, + ) { const result = parseNodeFactory.createSyntheticExpression(type, isSpread, tupleNameSource); setTextRange(result, parent); setParent(result, parent); @@ -32958,7 +42730,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getEffectiveDecoratorArguments(node); } if (isJsxOpeningLikeElement(node)) { - return node.attributes.properties.length > 0 || (isJsxOpeningElement(node) && node.parent.children.length > 0) ? [node.attributes] : emptyArray; + return node.attributes.properties.length > 0 + || (isJsxOpeningElement(node) && node.parent.children.length > 0) ? [node.attributes] : emptyArray; } const args = node.arguments || emptyArray; const spreadIndex = getSpreadArgumentIndex(args); @@ -32968,12 +42741,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = spreadIndex; i < args.length; i++) { const arg = args[i]; // We can call checkExpressionCached because spread expressions never have a contextual type. - const spreadType = arg.kind === SyntaxKind.SpreadElement && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) : checkExpressionCached((arg as SpreadElement).expression)); + const spreadType = arg.kind === SyntaxKind.SpreadElement + && (flowLoopCount ? checkExpression((arg as SpreadElement).expression) + : checkExpressionCached((arg as SpreadElement).expression)); if (spreadType && isTupleType(spreadType)) { forEach(getElementTypes(spreadType), (t, i) => { const flags = spreadType.target.elementFlags[i]; - const syntheticArg = createSyntheticExpression(arg, flags & ElementFlags.Rest ? createArrayType(t) : t, - !!(flags & ElementFlags.Variable), spreadType.target.labeledElementDeclarations?.[i]); + const syntheticArg = createSyntheticExpression( + arg, + flags & ElementFlags.Rest ? createArrayType(t) : t, + !!(flags & ElementFlags.Variable), + spreadType.target.labeledElementDeclarations?.[i], + ); effectiveArgs.push(syntheticArg); }); } @@ -33007,9 +42786,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Returns the argument count for a decorator node that works like a function invocation. */ function getDecoratorArgumentCount(node: Decorator, signature: Signature) { - return compilerOptions.experimentalDecorators ? - getLegacyDecoratorArgumentCount(node, signature) : - 2; + return compilerOptions.experimentalDecorators + ? getLegacyDecoratorArgumentCount(node, signature) + : 2; } /** @@ -33052,7 +42831,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return { start, length, sourceFile }; } - function getDiagnosticForCallNode(node: CallLikeExpression, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): DiagnosticWithLocation { + function getDiagnosticForCallNode( + node: CallLikeExpression, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: DiagnosticArguments + ): DiagnosticWithLocation { if (isCallExpression(node)) { const { sourceFile, start, length } = getDiagnosticSpanForCallNode(node); if ("message" in message) { // eslint-disable-line local/no-in-operator @@ -33071,9 +42854,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isPromiseResolveArityError(node: CallLikeExpression) { if (!isCallExpression(node) || !isIdentifier(node.expression)) return false; - const symbol = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + const symbol = resolveName( + node.expression, + node.expression.escapedText, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); const decl = symbol?.valueDeclaration; - if (!decl || !isParameter(decl) || !isFunctionExpressionOrArrowFunction(decl.parent) || !isNewExpression(decl.parent.parent) || !isIdentifier(decl.parent.parent.expression)) { + if ( + !decl || !isParameter(decl) || !isFunctionExpressionOrArrowFunction(decl.parent) + || !isNewExpression(decl.parent.parent) || !isIdentifier(decl.parent.parent.expression) + ) { return false; } @@ -33084,10 +42877,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return constructorSymbol === globalPromiseSymbol; } - function getArgumentArityError(node: CallLikeExpression, signatures: readonly Signature[], args: readonly Expression[], headMessage?: DiagnosticMessage) { + function getArgumentArityError( + node: CallLikeExpression, + signatures: readonly Signature[], + args: readonly Expression[], + headMessage?: DiagnosticMessage, + ) { const spreadIndex = getSpreadArgumentIndex(args); if (spreadIndex > -1) { - return createDiagnosticForNode(args[spreadIndex], Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter); + return createDiagnosticForNode( + args[spreadIndex], + Diagnostics.A_spread_argument_must_either_have_a_tuple_type_or_be_passed_to_a_rest_parameter, + ); } let min = Number.POSITIVE_INFINITY; // smallest parameter count let max = Number.NEGATIVE_INFINITY; // largest parameter count @@ -33112,26 +42913,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parameterRange = hasRestParameter ? min : min < max ? min + "-" + max : min; - const isVoidPromiseError = !hasRestParameter && parameterRange === 1 && args.length === 0 && isPromiseResolveArityError(node); + const isVoidPromiseError = !hasRestParameter && parameterRange === 1 && args.length === 0 + && isPromiseResolveArityError(node); if (isVoidPromiseError && isInJSFile(node)) { - return getDiagnosticForCallNode(node, Diagnostics.Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments); + return getDiagnosticForCallNode( + node, + Diagnostics + .Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments, + ); } - const error = - isDecorator(node) ? - hasRestParameter ? Diagnostics.The_runtime_will_invoke_the_decorator_with_1_arguments_but_the_decorator_expects_at_least_0 : - Diagnostics.The_runtime_will_invoke_the_decorator_with_1_arguments_but_the_decorator_expects_0 : - hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 : - isVoidPromiseError ? Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise : - Diagnostics.Expected_0_arguments_but_got_1; + const error = isDecorator(node) + ? hasRestParameter + ? Diagnostics + .The_runtime_will_invoke_the_decorator_with_1_arguments_but_the_decorator_expects_at_least_0 + : Diagnostics.The_runtime_will_invoke_the_decorator_with_1_arguments_but_the_decorator_expects_0 + : hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 + : isVoidPromiseError + ? Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise + : Diagnostics.Expected_0_arguments_but_got_1; if (min < args.length && args.length < max) { // between min and max, but with no matching overload if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics + .No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, + args.length, + maxBelow, + minAbove, + ); chain = chainDiagnosticMessages(chain, headMessage); return getDiagnosticForCallNode(node, chain); } - return getDiagnosticForCallNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, args.length, maxBelow, minAbove); + return getDiagnosticForCallNode( + node, + Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, + args.length, + maxBelow, + minAbove, + ); } else if (args.length < min) { // too short: put the error span on the call expression, not any of the args @@ -33144,12 +42965,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { diagnostic = getDiagnosticForCallNode(node, error, parameterRange, args.length); } - const parameter = closestSignature?.declaration?.parameters[closestSignature.thisParameter ? args.length + 1 : args.length]; + const parameter = closestSignature?.declaration + ?.parameters[closestSignature.thisParameter ? args.length + 1 : args.length]; if (parameter) { - const messageAndArgs: DiagnosticAndArguments = - isBindingPattern(parameter.name) ? [Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided] - : isRestParameter(parameter) ? [Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided, idText(getFirstIdentifier(parameter.name))] - : [Diagnostics.An_argument_for_0_was_not_provided, !parameter.name ? args.length : idText(getFirstIdentifier(parameter.name))]; + const messageAndArgs: DiagnosticAndArguments = isBindingPattern(parameter.name) + ? [Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided] + : isRestParameter(parameter) + ? [ + Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided, + idText(getFirstIdentifier(parameter.name)), + ] + : [ + Diagnostics.An_argument_for_0_was_not_provided, + !parameter.name ? args.length : idText(getFirstIdentifier(parameter.name)), + ]; const parameterError = createDiagnosticForNode(parameter, ...messageAndArgs); return addRelatedInfo(diagnostic, parameterError); } @@ -33169,11 +42998,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { chain = chainDiagnosticMessages(chain, headMessage); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), errorSpan, chain); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), errorSpan, error, parameterRange, args.length); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + errorSpan, + error, + parameterRange, + args.length, + ); } } - function getTypeArgumentArityError(node: Node, signatures: readonly Signature[], typeArguments: NodeArray, headMessage?: DiagnosticMessage) { + function getTypeArgumentArityError( + node: Node, + signatures: readonly Signature[], + typeArguments: NodeArray, + headMessage?: DiagnosticMessage, + ) { const argCount = typeArguments.length; // No overloads exist if (signatures.length === 1) { @@ -33181,11 +43021,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const min = getMinTypeArgumentCount(sig.typeParameters); const max = length(sig.typeParameters); if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min , argCount); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Expected_0_type_arguments_but_got_1, + min < max ? min + "-" + max : min, + argCount, + ); chain = chainDiagnosticMessages(chain, headMessage); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, min < max ? min + "-" + max : min , argCount); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Expected_0_type_arguments_but_got_1, + min < max ? min + "-" + max : min, + argCount, + ); } // Overloads exist let belowArgCount = -Infinity; @@ -33202,21 +43053,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (belowArgCount !== -Infinity && aboveArgCount !== Infinity) { if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, argCount, belowArgCount, aboveArgCount); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics + .No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, + argCount, + belowArgCount, + aboveArgCount, + ); chain = chainDiagnosticMessages(chain, headMessage); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, argCount, belowArgCount, aboveArgCount); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics + .No_overload_expects_0_type_arguments_but_overloads_do_exist_that_expect_either_1_or_2_type_arguments, + argCount, + belowArgCount, + aboveArgCount, + ); } if (headMessage) { - let chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); + let chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Expected_0_type_arguments_but_got_1, + belowArgCount === -Infinity ? aboveArgCount : belowArgCount, + argCount, + ); chain = chainDiagnosticMessages(chain, headMessage); return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain); } - return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount); + return createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Expected_0_type_arguments_but_got_1, + belowArgCount === -Infinity ? aboveArgCount : belowArgCount, + argCount, + ); } - function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags, headMessage?: DiagnosticMessage): Signature { + function resolveCall( + node: CallLikeExpression, + signatures: readonly Signature[], + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + callChainFlags: SignatureFlags, + headMessage?: DiagnosticMessage, + ): Signature { const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression; const isDecorator = node.kind === SyntaxKind.Decorator; const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node); @@ -33228,7 +43112,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typeArguments = (node as CallExpression).typeArguments; // We already perform checking on the type arguments on the class declaration itself. - if (isTaggedTemplate || isJsxOpeningOrSelfClosingElement || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword) { + if ( + isTaggedTemplate || isJsxOpeningOrSelfClosingElement + || (node as CallExpression).expression.kind !== SyntaxKind.SuperKeyword + ) { forEach(typeArguments, checkSourceElement); } } @@ -33253,7 +43140,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For a decorator, no arguments are susceptible to contextual typing due to the fact // decorators are applied to a declaration by the emitter, and not to an expression. const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters; - let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) ? CheckMode.SkipContextSensitive : CheckMode.Normal; + let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) + ? CheckMode.SkipContextSensitive : CheckMode.Normal; // The following variables are captured and modified by calls to chooseOverload. // If overload resolution or type argument inference fails, we want to report the @@ -33283,8 +43171,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If we are in signature help, a trailing comma indicates that we intend to provide another argument, // so we will only accept overloads with arity at least 1 higher than the current number of provided arguments. - const signatureHelpTrailingComma = - !!(checkMode & CheckMode.IsForSignatureHelp) && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma; + const signatureHelpTrailingComma = !!(checkMode & CheckMode.IsForSignatureHelp) + && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma; // Section 4.12.1: // if the candidate list contains one or more signatures for which the type of each argument @@ -33297,10 +43185,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // is just important for choosing the best signature. So in the case where there is only one // signature, the subtype pass is useless. So skipping it is an optimization. if (candidates.length > 1) { - result = chooseOverload(candidates, subtypeRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma); + result = chooseOverload( + candidates, + subtypeRelation, + isSingleNonGenericCandidate, + signatureHelpTrailingComma, + ); } if (!result) { - result = chooseOverload(candidates, assignableRelation, isSingleNonGenericCandidate, signatureHelpTrailingComma); + result = chooseOverload( + candidates, + assignableRelation, + isSingleNonGenericCandidate, + signatureHelpTrailingComma, + ); } if (result) { return result; @@ -33332,11 +43230,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (headMessage) { chain = chainDiagnosticMessages(chain, headMessage); } - const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain); + const diags = getSignatureApplicabilityError( + node, + args, + last, + assignableRelation, + CheckMode.Normal, + /*reportErrors*/ true, + () => chain, + ); if (diags) { for (const d of diags) { if (last.declaration && candidatesForArgumentError.length > 3) { - addRelatedInfo(d, createDiagnosticForNode(last.declaration, Diagnostics.The_last_overload_is_declared_here)); + addRelatedInfo( + d, + createDiagnosticForNode( + last.declaration, + Diagnostics.The_last_overload_is_declared_here, + ), + ); } addImplementationSuccessElaboration(last, d); diagnostics.add(d); @@ -33353,8 +43265,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let minIndex = 0; let i = 0; for (const c of candidatesForArgumentError) { - const chain = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Overload_0_of_1_2_gave_the_following_error, i + 1, candidates.length, signatureToString(c)); - const diags = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, chain); + const chain = () => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Overload_0_of_1_2_gave_the_following_error, + i + 1, + candidates.length, + signatureToString(c), + ); + const diags = getSignatureApplicabilityError( + node, + args, + c, + assignableRelation, + CheckMode.Normal, + /*reportErrors*/ true, + chain, + ); if (diags) { if (diags.length <= min) { min = diags.length; @@ -33373,17 +43300,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert(diags.length > 0, "No errors reported for 3 or fewer overload signatures"); let chain = chainDiagnosticMessages( map(diags, createDiagnosticMessageChainFromDiagnostic), - Diagnostics.No_overload_matches_this_call); + Diagnostics.No_overload_matches_this_call, + ); if (headMessage) { chain = chainDiagnosticMessages(chain, headMessage); } // The below is a spread to guarantee we get a new (mutable) array - our `flatMap` helper tries to do "smart" optimizations where it reuses input // arrays and the emptyArray singleton where possible, which is decidedly not what we want while we're still constructing this diagnostic - const related = [...flatMap(diags, d => (d as Diagnostic).relatedInformation) as DiagnosticRelatedInformation[]]; + const related = [ + ...flatMap(diags, d => (d as Diagnostic).relatedInformation) as DiagnosticRelatedInformation[], + ]; let diag: Diagnostic; - if (every(diags, d => d.start === diags[0].start && d.length === diags[0].length && d.file === diags[0].file)) { + if ( + every( + diags, + d => d.start === diags[0].start && d.length === diags[0].length && d.file === diags[0].file, + ) + ) { const { file, start, length } = diags[0]; - diag = { file, start, length, code: chain.code, category: chain.category, messageText: chain, relatedInformation: related }; + diag = { + file, + start, + length, + code: chain.code, + category: chain.category, + messageText: chain, + relatedInformation: related, + }; } else { diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node), node, chain, related); @@ -33396,15 +43339,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args, headMessage)); } else if (candidateForTypeArgumentError) { - checkTypeArguments(candidateForTypeArgumentError, (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, /*reportErrors*/ true, headMessage); + checkTypeArguments( + candidateForTypeArgumentError, + (node as CallExpression | TaggedTemplateExpression | JsxOpeningLikeElement).typeArguments!, + /*reportErrors*/ true, + headMessage, + ); } else { - const signaturesWithCorrectTypeArgumentArity = filter(signatures, s => hasCorrectTypeArgumentArity(s, typeArguments)); + const signaturesWithCorrectTypeArgumentArity = filter( + signatures, + s => hasCorrectTypeArgumentArity(s, typeArguments), + ); if (signaturesWithCorrectTypeArgumentArity.length === 0) { diagnostics.add(getTypeArgumentArityError(node, signatures, typeArguments!, headMessage)); } else { - diagnostics.add(getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args, headMessage)); + diagnostics.add( + getArgumentArityError(node, signaturesWithCorrectTypeArgumentArity, args, headMessage), + ); } } } @@ -33418,12 +43371,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const failedSignatureDeclarations = failed.declaration?.symbol?.declarations || emptyArray; const isOverload = failedSignatureDeclarations.length > 1; - const implDecl = isOverload ? find(failedSignatureDeclarations, d => isFunctionLikeDeclaration(d) && nodeIsPresent(d.body)) : undefined; + const implDecl = isOverload + ? find(failedSignatureDeclarations, d => isFunctionLikeDeclaration(d) && nodeIsPresent(d.body)) + : undefined; if (implDecl) { const candidate = getSignatureFromDeclaration(implDecl as FunctionLikeDeclaration); const isSingleNonGenericCandidate = !candidate.typeParameters; if (chooseOverload([candidate], assignableRelation, isSingleNonGenericCandidate)) { - addRelatedInfo(diagnostic, createDiagnosticForNode(implDecl, Diagnostics.The_call_would_have_succeeded_against_this_implementation_but_implementation_signatures_of_overloads_are_not_externally_visible)); + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + implDecl, + Diagnostics + .The_call_would_have_succeeded_against_this_implementation_but_implementation_signatures_of_overloads_are_not_externally_visible, + ), + ); } } @@ -33432,7 +43394,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { candidateForTypeArgumentError = oldCandidateForTypeArgumentError; } - function chooseOverload(candidates: Signature[], relation: Map, isSingleNonGenericCandidate: boolean, signatureHelpTrailingComma = false) { + function chooseOverload( + candidates: Signature[], + relation: Map, + isSingleNonGenericCandidate: boolean, + signatureHelpTrailingComma = false, + ) { candidatesForArgumentError = undefined; candidateForArgumentArityError = undefined; candidateForTypeArgumentError = undefined; @@ -33442,7 +43409,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { return undefined; } - if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + candidate, + relation, + CheckMode.Normal, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined, + ) + ) { candidatesForArgumentError = [candidate]; return undefined; } @@ -33451,7 +43428,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) { const candidate = candidates[candidateIndex]; - if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) { + if ( + !hasCorrectTypeArgumentArity(candidate, typeArguments) + || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma) + ) { continue; } @@ -33468,14 +43448,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else { - inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext); - argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal; - } - checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters); + inferenceContext = createInferenceContext( + candidate.typeParameters, + candidate, + /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None, + ); + typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + argCheckMode | CheckMode.SkipGenericFunctions, + inferenceContext, + ); + argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction + ? CheckMode.SkipGenericFunctions : CheckMode.Normal; + } + checkCandidate = getSignatureInstantiation( + candidate, + typeArgumentTypes, + isInJSFile(candidate.declaration), + inferenceContext && inferenceContext.inferredTypeParameters, + ); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. - if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if ( + getNonArrayRestType(candidate) + && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma) + ) { candidateForArgumentArityError = checkCandidate; continue; } @@ -33483,7 +43482,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { checkCandidate = candidate; } - if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + checkCandidate, + relation, + argCheckMode, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined, + ) + ) { // Give preference to error candidates that have no rest parameters (as they are more specific) (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); continue; @@ -33494,16 +43503,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // round of type inference and applicability checking for this particular candidate. argCheckMode = CheckMode.Normal; if (inferenceContext) { - const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext); - checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext.inferredTypeParameters); + const typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + argCheckMode, + inferenceContext, + ); + checkCandidate = getSignatureInstantiation( + candidate, + typeArgumentTypes, + isInJSFile(candidate.declaration), + inferenceContext.inferredTypeParameters, + ); // If the original signature has a generic rest type, instantiation may produce a // signature with different arity and we need to perform another arity check. - if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) { + if ( + getNonArrayRestType(candidate) + && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma) + ) { candidateForArgumentArityError = checkCandidate; continue; } } - if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) { + if ( + getSignatureApplicabilityError( + node, + args, + checkCandidate, + relation, + argCheckMode, + /*reportErrors*/ false, + /*containingMessageChain*/ undefined, + ) + ) { // Give preference to error candidates that have no rest parameters (as they are more specific) (candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate); continue; @@ -33544,16 +43577,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const { min: minArgumentCount, max: maxNonRestParam } = minAndMax(candidates, getNumNonRestParameters); const parameters: Symbol[] = []; for (let i = 0; i < maxNonRestParam; i++) { - const symbols = mapDefined(candidates, s => signatureHasRestParameter(s) ? - i < s.parameters.length - 1 ? s.parameters[i] : last(s.parameters) : - i < s.parameters.length ? s.parameters[i] : undefined); + const symbols = mapDefined(candidates, s => + signatureHasRestParameter(s) + ? i < s.parameters.length - 1 ? s.parameters[i] : last(s.parameters) + : i < s.parameters.length ? s.parameters[i] : undefined); Debug.assert(symbols.length !== 0); - parameters.push(createCombinedSymbolFromTypes(symbols, mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i)))); + parameters.push( + createCombinedSymbolFromTypes( + symbols, + mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i)), + ), + ); } - const restParameterSymbols = mapDefined(candidates, c => signatureHasRestParameter(c) ? last(c.parameters) : undefined); + const restParameterSymbols = mapDefined( + candidates, + c => signatureHasRestParameter(c) ? last(c.parameters) : undefined, + ); let flags = SignatureFlags.IsSignatureCandidateForOverloadFailure; if (restParameterSymbols.length !== 0) { - const type = createArrayType(getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), UnionReduction.Subtype)); + const type = createArrayType( + getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), UnionReduction.Subtype), + ); parameters.push(createCombinedSymbolForOverloadFailure(restParameterSymbols, type)); flags |= SignatureFlags.HasRestParameter; } @@ -33568,7 +43612,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*resolvedReturnType*/ getIntersectionType(candidates.map(getReturnTypeOfSignature)), /*resolvedTypePredicate*/ undefined, minArgumentCount, - flags); + flags, + ); } function getNumNonRestParameters(signature: Signature): number { @@ -33585,42 +43630,78 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createSymbolWithType(first(sources), type); } - function pickLongestCandidateSignature(node: CallLikeExpression, candidates: Signature[], args: readonly Expression[], checkMode: CheckMode): Signature { + function pickLongestCandidateSignature( + node: CallLikeExpression, + candidates: Signature[], + args: readonly Expression[], + checkMode: CheckMode, + ): Signature { // Pick the longest signature. This way we can get a contextual type for cases like: // declare function f(a: { xa: number; xb: number; }, b: number); // f({ | // Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like: // declare function f(k: keyof T); // f(" - const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount); + const bestIndex = getLongestCandidateIndex( + candidates, + apparentArgumentCount === undefined ? args.length : apparentArgumentCount, + ); const candidate = candidates[bestIndex]; const { typeParameters } = candidate; if (!typeParameters) { return candidate; } - const typeArgumentNodes: readonly TypeNode[] | undefined = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments : undefined; + const typeArgumentNodes: readonly TypeNode[] | undefined = callLikeExpressionMayHaveTypeArguments(node) + ? node.typeArguments : undefined; const instantiated = typeArgumentNodes - ? createSignatureInstantiation(candidate, getTypeArgumentsFromNodes(typeArgumentNodes, typeParameters, isInJSFile(node))) + ? createSignatureInstantiation( + candidate, + getTypeArgumentsFromNodes(typeArgumentNodes, typeParameters, isInJSFile(node)), + ) : inferSignatureInstantiationForOverloadFailure(node, typeParameters, candidate, args, checkMode); candidates[bestIndex] = instantiated; return instantiated; } - function getTypeArgumentsFromNodes(typeArgumentNodes: readonly TypeNode[], typeParameters: readonly TypeParameter[], isJs: boolean): readonly Type[] { + function getTypeArgumentsFromNodes( + typeArgumentNodes: readonly TypeNode[], + typeParameters: readonly TypeParameter[], + isJs: boolean, + ): readonly Type[] { const typeArguments = typeArgumentNodes.map(getTypeOfNode); while (typeArguments.length > typeParameters.length) { typeArguments.pop(); } while (typeArguments.length < typeParameters.length) { - typeArguments.push(getDefaultFromTypeParameter(typeParameters[typeArguments.length]) || getConstraintOfTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isJs)); + typeArguments.push( + getDefaultFromTypeParameter(typeParameters[typeArguments.length]) + || getConstraintOfTypeParameter(typeParameters[typeArguments.length]) + || getDefaultTypeArgumentType(isJs), + ); } return typeArguments; } - function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: readonly TypeParameter[], candidate: Signature, args: readonly Expression[], checkMode: CheckMode): Signature { - const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None); - const typeArgumentTypes = inferTypeArguments(node, candidate, args, checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext); + function inferSignatureInstantiationForOverloadFailure( + node: CallLikeExpression, + typeParameters: readonly TypeParameter[], + candidate: Signature, + args: readonly Expression[], + checkMode: CheckMode, + ): Signature { + const inferenceContext = createInferenceContext( + typeParameters, + candidate, + /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None, + ); + const typeArgumentTypes = inferTypeArguments( + node, + candidate, + args, + checkMode | CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, + inferenceContext, + ); return createSignatureInstantiation(candidate, typeArgumentTypes); } @@ -33643,7 +43724,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return maxParamsIndex; } - function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveCallExpression( + node: CallExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { if (node.expression.kind === SyntaxKind.SuperKeyword) { const superType = checkSuperExpression(node.expression); if (isTypeAny(superType)) { @@ -33657,7 +43742,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // with the type arguments specified in the extends clause. const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!); if (baseTypeNode) { - const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode); + const baseConstructors = getInstantiatedConstructorsForTypeArguments( + superType, + baseTypeNode.typeArguments, + baseTypeNode, + ); return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None); } } @@ -33668,9 +43757,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let funcType = checkExpression(node.expression); if (isCallChain(node)) { const nonOptionalType = getOptionalExpressionType(funcType, node.expression); - callChainFlags = nonOptionalType === funcType ? SignatureFlags.None : - isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain : - SignatureFlags.IsInnerCallChain; + callChainFlags = nonOptionalType === funcType ? SignatureFlags.None + : isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain + : SignatureFlags.IsInnerCallChain; funcType = nonOptionalType; } else { @@ -33680,7 +43769,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { funcType = checkNonNullTypeWithReporter( funcType, node.expression, - reportCannotInvokePossiblyNullOrUndefinedError + reportCannotInvokePossiblyNullOrUndefinedError, ); if (funcType === silentNeverType) { @@ -33716,14 +43805,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // with multiple call signatures. if (!callSignatures.length) { if (numConstructSignatures) { - error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); + error( + node, + Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, + typeToString(funcType), + ); } else { let relatedInformation: DiagnosticRelatedInformation | undefined; if (node.arguments.length === 1) { const text = getSourceFileOfNode(node).text; - if (isLineBreak(text.charCodeAt(skipTrivia(text, node.expression.end, /*stopAfterLineBreak*/ true) - 1))) { - relatedInformation = createDiagnosticForNode(node.expression, Diagnostics.Are_you_missing_a_semicolon); + if ( + isLineBreak( + text.charCodeAt(skipTrivia(text, node.expression.end, /*stopAfterLineBreak*/ true) - 1), + ) + ) { + relatedInformation = createDiagnosticForNode( + node.expression, + Diagnostics.Are_you_missing_a_semicolon, + ); } } invocationError(node.expression, apparentType, SignatureKind.Call, relatedInformation); @@ -33742,13 +43842,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // use the resolvingSignature singleton to indicate that we deferred processing. This result will be // propagated out and eventually turned into silentNeverType (a type that is assignable to anything and // from which we never make inferences). - if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) { + if ( + checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments + && callSignatures.some(isGenericFunctionReturningFunction) + ) { skippedGenericFunction(node, checkMode); return resolvingSignature; } // If the function is explicitly marked with `@class`, then it must be constructed. if (callSignatures.some(sig => isInJSFile(sig.declaration) && !!getJSDocClassTag(sig.declaration!))) { - error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType)); + error( + node, + Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, + typeToString(funcType), + ); return resolveErrorCall(node); } @@ -33764,17 +43871,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * If FuncExpr is of type Any, or of an object type that has no call or construct signatures * but is a subtype of the Function interface, the call is an untyped function call. */ - function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number): boolean { + function isUntypedFunctionCall( + funcType: Type, + apparentFuncType: Type, + numCallSignatures: number, + numConstructSignatures: number, + ): boolean { // We exclude union types because we may have a union of function types that happen to have no common signatures. - return isTypeAny(funcType) || isTypeAny(apparentFuncType) && !!(funcType.flags & TypeFlags.TypeParameter) || - !numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & TypeFlags.Union) && !(getReducedType(apparentFuncType).flags & TypeFlags.Never) && isTypeAssignableTo(funcType, globalFunctionType); + return isTypeAny(funcType) || isTypeAny(apparentFuncType) && !!(funcType.flags & TypeFlags.TypeParameter) + || !numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & TypeFlags.Union) + && !(getReducedType(apparentFuncType).flags & TypeFlags.Never) + && isTypeAssignableTo(funcType, globalFunctionType); } - function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveNewExpression( + node: NewExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { if (node.arguments && languageVersion < ScriptTarget.ES5) { const spreadIndex = getSpreadArgumentIndex(node.arguments); if (spreadIndex >= 0) { - error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_5_and_higher); + error( + node.arguments[spreadIndex], + Diagnostics + .Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_5_and_higher, + ); } } @@ -33838,11 +43960,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (callSignatures.length) { const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None); if (!noImplicitAny) { - if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) { + if ( + signature.declaration && !isJSConstructor(signature.declaration) + && getReturnTypeOfSignature(signature) !== voidType + ) { error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); } if (getThisTypeOfSignature(signature) === voidType) { - error(node, Diagnostics.A_function_that_is_called_with_the_new_keyword_cannot_have_a_this_type_that_is_void); + error( + node, + Diagnostics.A_function_that_is_called_with_the_new_keyword_cannot_have_a_this_type_that_is_void, + ); } } return signature; @@ -33917,10 +44045,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (modifiers & ModifierFlags.Private) { - error(node, Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); + error( + node, + Diagnostics.Constructor_of_class_0_is_private_and_only_accessible_within_the_class_declaration, + typeToString(declaringClass), + ); } if (modifiers & ModifierFlags.Protected) { - error(node, Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, typeToString(declaringClass)); + error( + node, + Diagnostics.Constructor_of_class_0_is_protected_and_only_accessible_within_the_class_declaration, + typeToString(declaringClass), + ); } return false; } @@ -33928,7 +44064,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function invocationErrorDetails(errorTarget: Node, apparentType: Type, kind: SignatureKind): { messageChain: DiagnosticMessageChain, relatedMessage: DiagnosticMessage | undefined } { + function invocationErrorDetails( + errorTarget: Node, + apparentType: Type, + kind: SignatureKind, + ): { messageChain: DiagnosticMessageChain; relatedMessage: DiagnosticMessage | undefined; } { let errorInfo: DiagnosticMessageChain | undefined; const isCall = kind === SignatureKind.Call; const awaitedType = getAwaitedType(apparentType); @@ -33950,17 +44090,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!errorInfo) { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Type_0_has_no_call_signatures : - Diagnostics.Type_0_has_no_construct_signatures, - typeToString(constituent) + isCall + ? Diagnostics.Type_0_has_no_call_signatures + : Diagnostics.Type_0_has_no_construct_signatures, + typeToString(constituent), ); errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Not_all_constituents_of_type_0_are_callable : - Diagnostics.Not_all_constituents_of_type_0_are_constructable, - typeToString(apparentType) + isCall + ? Diagnostics.Not_all_constituents_of_type_0_are_callable + : Diagnostics.Not_all_constituents_of_type_0_are_constructable, + typeToString(apparentType), ); } if (hasSignatures) { @@ -33972,39 +44112,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!hasSignatures) { errorInfo = chainDiagnosticMessages( /*details*/ undefined, - isCall ? - Diagnostics.No_constituent_of_type_0_is_callable : - Diagnostics.No_constituent_of_type_0_is_constructable, - typeToString(apparentType) + isCall + ? Diagnostics.No_constituent_of_type_0_is_callable + : Diagnostics.No_constituent_of_type_0_is_constructable, + typeToString(apparentType), ); } if (!errorInfo) { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other : - Diagnostics.Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other, - typeToString(apparentType) + isCall + ? Diagnostics + .Each_member_of_the_union_type_0_has_signatures_but_none_of_those_signatures_are_compatible_with_each_other + : Diagnostics + .Each_member_of_the_union_type_0_has_construct_signatures_but_none_of_those_signatures_are_compatible_with_each_other, + typeToString(apparentType), ); } } else { errorInfo = chainDiagnosticMessages( errorInfo, - isCall ? - Diagnostics.Type_0_has_no_call_signatures : - Diagnostics.Type_0_has_no_construct_signatures, - typeToString(apparentType) + isCall + ? Diagnostics.Type_0_has_no_call_signatures + : Diagnostics.Type_0_has_no_construct_signatures, + typeToString(apparentType), ); } - let headMessage = isCall ? Diagnostics.This_expression_is_not_callable : Diagnostics.This_expression_is_not_constructable; + let headMessage = isCall ? Diagnostics.This_expression_is_not_callable + : Diagnostics.This_expression_is_not_constructable; // Diagnose get accessors incorrectly called as functions if (isCallExpression(errorTarget.parent) && errorTarget.parent.arguments.length === 0) { const { resolvedSymbol } = getNodeLinks(errorTarget); if (resolvedSymbol && resolvedSymbol.flags & SymbolFlags.GetAccessor) { - headMessage = Diagnostics.This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without; + headMessage = Diagnostics + .This_expression_is_not_callable_because_it_is_a_get_accessor_Did_you_mean_to_use_it_without; } } @@ -34013,9 +44157,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { relatedMessage: maybeMissingAwait ? Diagnostics.Did_you_forget_to_use_await : undefined, }; } - function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) { + function invocationError( + errorTarget: Node, + apparentType: Type, + kind: SignatureKind, + relatedInformation?: DiagnosticRelatedInformation, + ) { const { messageChain, relatedMessage: relatedInfo } = invocationErrorDetails(errorTarget, apparentType, kind); - const diagnostic = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorTarget), errorTarget, messageChain); + const diagnostic = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(errorTarget), + errorTarget, + messageChain, + ); if (relatedInfo) { addRelatedInfo(diagnostic, createDiagnosticForNode(errorTarget, relatedInfo)); } @@ -34025,7 +44178,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { diagnostic.length = length; } diagnostics.add(diagnostic); - invocationErrorRecovery(apparentType, kind, relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic); + invocationErrorRecovery( + apparentType, + kind, + relatedInformation ? addRelatedInfo(diagnostic, relatedInformation) : diagnostic, + ); } function invocationErrorRecovery(apparentType: Type, kind: SignatureKind, diagnostic: Diagnostic) { @@ -34039,13 +44196,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sigs = getSignaturesOfType(getTypeOfSymbol(getSymbolLinks(apparentType.symbol).target!), kind); if (!sigs || !sigs.length) return; - addRelatedInfo(diagnostic, - createDiagnosticForNode(importNode, Diagnostics.Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead) + addRelatedInfo( + diagnostic, + createDiagnosticForNode( + importNode, + Diagnostics + .Type_originates_at_this_import_A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_Consider_using_a_default_import_or_import_require_here_instead, + ), ); } } - function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveTaggedTemplateExpression( + node: TaggedTemplateExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { const tagType = checkExpression(node.tag); const apparentType = getApparentType(tagType); @@ -34063,7 +44229,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!callSignatures.length) { if (isArrayLiteralExpression(node.parent)) { - const diagnostic = createDiagnosticForNode(node.tag, Diagnostics.It_is_likely_that_you_are_missing_a_comma_to_separate_these_two_template_expressions_They_form_a_tagged_template_expression_which_cannot_be_invoked); + const diagnostic = createDiagnosticForNode( + node.tag, + Diagnostics + .It_is_likely_that_you_are_missing_a_comma_to_separate_these_two_template_expressions_They_form_a_tagged_template_expression_which_cannot_be_invoked, + ); diagnostics.add(diagnostic); return resolveErrorCall(node); } @@ -34103,7 +44273,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Resolves a decorator as if it were a call expression. */ - function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveDecorator( + node: Decorator, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { const funcType = checkExpression(node.expression); const apparentType = getApparentType(funcType); if (isErrorType(apparentType)) { @@ -34118,7 +44292,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isPotentiallyUncalledDecorator(node, callSignatures) && !isParenthesizedExpression(node.expression)) { const nodeStr = getTextOfNode(node.expression, /*includeTrivia*/ false); - error(node, Diagnostics._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0, nodeStr); + error( + node, + Diagnostics + ._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0, + nodeStr, + ); return resolveErrorCall(node); } @@ -34126,7 +44305,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!callSignatures.length) { const errorDetails = invocationErrorDetails(node.expression, apparentType, SignatureKind.Call); const messageChain = chainDiagnosticMessages(errorDetails.messageChain, headMessage); - const diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node.expression), node.expression, messageChain); + const diag = createDiagnosticForNodeFromMessageChain( + getSourceFileOfNode(node.expression), + node.expression, + messageChain, + ); if (errorDetails.relatedMessage) { addRelatedInfo(diag, createDiagnosticForNode(node.expression, errorDetails.relatedMessage)); } @@ -34145,9 +44328,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // file would probably be preferable. const typeSymbol = exports && getSymbol(exports, JsxNames.Element, SymbolFlags.Type); const returnNode = typeSymbol && nodeBuilder.symbolToEntityName(typeSymbol, SymbolFlags.Type, node); - const declaration = factory.createFunctionTypeNode(/*typeParameters*/ undefined, - [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "props", /*questionToken*/ undefined, nodeBuilder.typeToTypeNode(result, node))], - returnNode ? factory.createTypeReferenceNode(returnNode, /*typeArguments*/ undefined) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + const declaration = factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "props", + /*questionToken*/ undefined, + nodeBuilder.typeToTypeNode(result, node), + )], + returnNode ? factory.createTypeReferenceNode(returnNode, /*typeArguments*/ undefined) + : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), ); const parameterSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "props" as __String); parameterSymbol.links.type = result; @@ -34159,18 +44350,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : errorType, /*resolvedTypePredicate*/ undefined, 1, - SignatureFlags.None + SignatureFlags.None, ); } - function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveJsxOpeningLikeElement( + node: JsxOpeningLikeElement, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { if (isJsxIntrinsicTagName(node.tagName)) { const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); const fakeSignature = createSignatureForJSXIntrinsic(node, result); - checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*inferenceContext*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes); + checkTypeAssignableToAndOptionallyElaborate( + checkExpressionWithContextualType( + node.attributes, + getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), + /*inferenceContext*/ undefined, + CheckMode.Normal, + ), + result, + node.tagName, + node.attributes, + ); if (length(node.typeArguments)) { forEach(node.typeArguments, checkSourceElement); - diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), node.typeArguments!, Diagnostics.Expected_0_type_arguments_but_got_1, 0, length(node.typeArguments))); + diagnostics.add( + createDiagnosticForNodeArray( + getSourceFileOfNode(node), + node.typeArguments!, + Diagnostics.Expected_0_type_arguments_but_got_1, + 0, + length(node.typeArguments), + ), + ); } return fakeSignature; } @@ -34187,7 +44400,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (signatures.length === 0) { // We found no signatures at all, which is an error - error(node.tagName, Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, getTextOfNode(node.tagName)); + error( + node.tagName, + Diagnostics.JSX_element_type_0_does_not_have_any_construct_or_call_signatures, + getTextOfNode(node.tagName), + ); return resolveErrorCall(node); } @@ -34201,12 +44418,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { */ function isPotentiallyUncalledDecorator(decorator: Decorator, signatures: readonly Signature[]) { return signatures.length && every(signatures, signature => - signature.minArgumentCount === 0 && - !signatureHasRestParameter(signature) && - signature.parameters.length < getDecoratorArgumentCount(decorator, signature)); + signature.minArgumentCount === 0 + && !signatureHasRestParameter(signature) + && signature.parameters.length < getDecoratorArgumentCount(decorator, signature)); } - function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { + function resolveSignature( + node: CallLikeExpression, + candidatesOutArray: Signature[] | undefined, + checkMode: CheckMode, + ): Signature { switch (node.kind) { case SyntaxKind.CallExpression: return resolveCallExpression(node, candidatesOutArray, checkMode); @@ -34230,7 +44451,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * the function will fill it up with appropriate candidate signatures * @return a signature of the call-like expression or undefined if one can't be found */ - function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, checkMode?: CheckMode): Signature { + function getResolvedSignature( + node: CallLikeExpression, + candidatesOutArray?: Signature[] | undefined, + checkMode?: CheckMode, + ): Signature { const links = getNodeLinks(node); // If getResolvedSignature has already been called, we will have cached the resolvedSignature. // However, it is possible that either candidatesOutArray was not passed in the first time, @@ -34269,9 +44494,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!node || !isInJSFile(node)) { return false; } - const func = isFunctionDeclaration(node) || isFunctionExpression(node) ? node : - (isVariableDeclaration(node) || isPropertyAssignment(node)) && node.initializer && isFunctionExpression(node.initializer) ? node.initializer : - undefined; + const func = isFunctionDeclaration(node) || isFunctionExpression(node) ? node + : (isVariableDeclaration(node) || isPropertyAssignment(node)) && node.initializer + && isFunctionExpression(node.initializer) ? node.initializer + : undefined; if (func) { // If the node has a @class or @constructor tag, treat it like a constructor. if (getJSDocClassTag(node)) return true; @@ -34300,7 +44526,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.members?.size) { mergeSymbolTable(inferred.members, source.members); } - (links.inferredClassSymbol || (links.inferredClassSymbol = new Map())).set(getSymbolId(inferred), inferred); + (links.inferredClassSymbol || (links.inferredClassSymbol = new Map())).set( + getSymbolId(inferred), + inferred, + ); return inferred; } return links.inferredClassSymbol.get(getSymbolId(target)); @@ -34334,12 +44563,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { name = parentNode.left; decl = name; } - else if (parentNodeOperator === SyntaxKind.BarBarToken || parentNodeOperator === SyntaxKind.QuestionQuestionToken) { + else if ( + parentNodeOperator === SyntaxKind.BarBarToken || parentNodeOperator === SyntaxKind.QuestionQuestionToken + ) { if (isVariableDeclaration(parentNode.parent) && parentNode.parent.initializer === parentNode) { name = parentNode.parent.name; decl = parentNode.parent; } - else if (isBinaryExpression(parentNode.parent) && parentNode.parent.operatorToken.kind === SyntaxKind.EqualsToken && (allowDeclaration || parentNode.parent.right === parentNode)) { + else if ( + isBinaryExpression(parentNode.parent) + && parentNode.parent.operatorToken.kind === SyntaxKind.EqualsToken + && (allowDeclaration || parentNode.parent.right === parentNode) + ) { name = parentNode.parent.left; decl = name; } @@ -34368,7 +44603,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { while (parent && parent.kind === SyntaxKind.PropertyAccessExpression) { parent = parent.parent; } - if (parent && isBinaryExpression(parent) && isPrototypeAccess(parent.left) && parent.operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + parent && isBinaryExpression(parent) && isPrototypeAccess(parent.left) + && parent.operatorToken.kind === SyntaxKind.EqualsToken + ) { const right = getInitializerOfBinaryExpression(parent); return isObjectLiteralExpression(right) && right; } @@ -34398,17 +44636,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind === SyntaxKind.NewExpression) { const declaration = signature.declaration; - if (declaration && - declaration.kind !== SyntaxKind.Constructor && - declaration.kind !== SyntaxKind.ConstructSignature && - declaration.kind !== SyntaxKind.ConstructorType && - !(isJSDocSignature(declaration) && getJSDocRoot(declaration)?.parent?.kind === SyntaxKind.Constructor) && - !isJSDocConstructSignature(declaration) && - !isJSConstructor(declaration)) { - + if ( + declaration + && declaration.kind !== SyntaxKind.Constructor + && declaration.kind !== SyntaxKind.ConstructSignature + && declaration.kind !== SyntaxKind.ConstructorType + && !(isJSDocSignature(declaration) + && getJSDocRoot(declaration)?.parent?.kind === SyntaxKind.Constructor) + && !isJSDocConstructSignature(declaration) + && !isJSConstructor(declaration) + ) { // When resolved signature is a call signature (and not a construct signature) the result type is any if (noImplicitAny) { - error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); + error( + node, + Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type, + ); } return anyType; } @@ -34425,13 +44668,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) { return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent)); } - if (node.kind === SyntaxKind.CallExpression && !node.questionDotToken && node.parent.kind === SyntaxKind.ExpressionStatement && - returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(signature)) { + if ( + node.kind === SyntaxKind.CallExpression && !node.questionDotToken + && node.parent.kind === SyntaxKind.ExpressionStatement + && returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(signature) + ) { if (!isDottedName(node.expression)) { - error(node.expression, Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name); + error( + node.expression, + Diagnostics.Assertions_require_the_call_target_to_be_an_identifier_or_qualified_name, + ); } else if (!getEffectsSignature(node)) { - const diagnostic = error(node.expression, Diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation); + const diagnostic = error( + node.expression, + Diagnostics + .Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation, + ); getTypeOfDottedName(node.expression, diagnostic); } } @@ -34439,7 +44692,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInJSFile(node)) { const jsSymbol = getSymbolOfExpando(node, /*allowDeclaration*/ false); if (jsSymbol?.exports?.size) { - const jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, emptyArray); + const jsAssignmentType = createAnonymousType( + jsSymbol, + jsSymbol.exports, + emptyArray, + emptyArray, + emptyArray, + ); jsAssignmentType.objectFlags |= ObjectFlags.JSLiteral; return getIntersectionType([returnType, jsAssignmentType]); } @@ -34453,7 +44712,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (signature.declaration && signature.declaration.flags & NodeFlags.Deprecated) { const suggestionNode = getDeprecatedSuggestionNode(node); const name = tryGetPropertyAccessOrIdentifierToString(getInvokedExpression(node)); - addDeprecatedSuggestionWithSignature(suggestionNode, signature.declaration, name, signatureToString(signature)); + addDeprecatedSuggestionWithSignature( + suggestionNode, + signature.declaration, + name, + signatureToString(signature), + ); } } @@ -34497,7 +44761,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - return globalESSymbol === resolveName(left, "Symbol" as __String, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); + return globalESSymbol + === resolveName( + left, + "Symbol" as __String, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); } function checkImportCallExpression(node: ImportCall): Type { @@ -34516,32 +44788,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkExpressionCached(node.arguments[i]); } - if (specifierType.flags & TypeFlags.Undefined || specifierType.flags & TypeFlags.Null || !isTypeAssignableTo(specifierType, stringType)) { - error(specifier, Diagnostics.Dynamic_import_s_specifier_must_be_of_type_string_but_here_has_type_0, typeToString(specifierType)); + if ( + specifierType.flags & TypeFlags.Undefined || specifierType.flags & TypeFlags.Null + || !isTypeAssignableTo(specifierType, stringType) + ) { + error( + specifier, + Diagnostics.Dynamic_import_s_specifier_must_be_of_type_string_but_here_has_type_0, + typeToString(specifierType), + ); } if (optionsType) { const importCallOptionsType = getGlobalImportCallOptionsType(/*reportErrors*/ true); if (importCallOptionsType !== emptyObjectType) { - checkTypeAssignableTo(optionsType, getNullableType(importCallOptionsType, TypeFlags.Undefined), node.arguments[1]); + checkTypeAssignableTo( + optionsType, + getNullableType(importCallOptionsType, TypeFlags.Undefined), + node.arguments[1], + ); } } // resolveExternalModuleName will return undefined if the moduleReferenceExpression is not a string literal const moduleSymbol = resolveExternalModuleName(node, specifier); if (moduleSymbol) { - const esModuleSymbol = resolveESModuleSymbol(moduleSymbol, specifier, /*dontResolveAlias*/ true, /*suppressInteropError*/ false); + const esModuleSymbol = resolveESModuleSymbol( + moduleSymbol, + specifier, + /*dontResolveAlias*/ true, + /*suppressInteropError*/ false, + ); if (esModuleSymbol) { - return createPromiseReturnType(node, - getTypeWithSyntheticDefaultOnly(getTypeOfSymbol(esModuleSymbol), esModuleSymbol, moduleSymbol, specifier) || - getTypeWithSyntheticDefaultImportType(getTypeOfSymbol(esModuleSymbol), esModuleSymbol, moduleSymbol, specifier) + return createPromiseReturnType( + node, + getTypeWithSyntheticDefaultOnly( + getTypeOfSymbol(esModuleSymbol), + esModuleSymbol, + moduleSymbol, + specifier, + ) + || getTypeWithSyntheticDefaultImportType( + getTypeOfSymbol(esModuleSymbol), + esModuleSymbol, + moduleSymbol, + specifier, + ), ); } } return createPromiseReturnType(node, anyType); } - function createDefaultPropertyWrapperForModule(symbol: Symbol, originalSymbol: Symbol | undefined, anonymousSymbol?: Symbol | undefined) { + function createDefaultPropertyWrapperForModule( + symbol: Symbol, + originalSymbol: Symbol | undefined, + anonymousSymbol?: Symbol | undefined, + ) { const memberTable = createSymbolTable(); const newSymbol = createSymbol(SymbolFlags.Alias, InternalSymbolName.Default); newSymbol.parent = originalSymbol; @@ -34551,7 +44854,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createAnonymousType(anonymousSymbol, memberTable, emptyArray, emptyArray, emptyArray); } - function getTypeWithSyntheticDefaultOnly(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression) { + function getTypeWithSyntheticDefaultOnly( + type: Type, + symbol: Symbol, + originalSymbol: Symbol, + moduleSpecifier: Expression, + ) { const hasDefaultOnly = isOnlyImportedAsDefault(moduleSpecifier); if (hasDefaultOnly && type && !isErrorType(type)) { const synthType = type as SyntheticDefaultModuleType; @@ -34564,17 +44872,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function getTypeWithSyntheticDefaultImportType(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression): Type { + function getTypeWithSyntheticDefaultImportType( + type: Type, + symbol: Symbol, + originalSymbol: Symbol, + moduleSpecifier: Expression, + ): Type { if (allowSyntheticDefaultImports && type && !isErrorType(type)) { const synthType = type as SyntheticDefaultModuleType; if (!synthType.syntheticType) { const file = originalSymbol.declarations?.find(isSourceFile); - const hasSyntheticDefault = canHaveSyntheticDefault(file, originalSymbol, /*dontResolveAlias*/ false, moduleSpecifier); + const hasSyntheticDefault = canHaveSyntheticDefault( + file, + originalSymbol, + /*dontResolveAlias*/ false, + moduleSpecifier, + ); if (hasSyntheticDefault) { const anonymousSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); - const defaultContainingObject = createDefaultPropertyWrapperForModule(symbol, originalSymbol, anonymousSymbol); + const defaultContainingObject = createDefaultPropertyWrapperForModule( + symbol, + originalSymbol, + anonymousSymbol, + ); anonymousSymbol.links.type = defaultContainingObject; - synthType.syntheticType = isValidSpreadType(type) ? getSpreadType(type, defaultContainingObject, anonymousSymbol, /*objectFlags*/ 0, /*readonly*/ false) : defaultContainingObject; + synthType.syntheticType = isValidSpreadType(type) + ? getSpreadType( + type, + defaultContainingObject, + anonymousSymbol, + /*objectFlags*/ 0, + /*readonly*/ false, + ) : defaultContainingObject; } else { synthType.syntheticType = type; @@ -34592,7 +44921,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Make sure require is not a local function if (!isIdentifier(node.expression)) return Debug.fail(); - const resolvedRequire = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true)!; // TODO: GH#18217 + const resolvedRequire = resolveName( + node.expression, + node.expression.escapedText, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + )!; // TODO: GH#18217 if (resolvedRequire === requireSymbol) { return true; } @@ -34604,8 +44940,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetDeclarationKind = resolvedRequire.flags & SymbolFlags.Function ? SyntaxKind.FunctionDeclaration : resolvedRequire.flags & SymbolFlags.Variable - ? SyntaxKind.VariableDeclaration - : SyntaxKind.Unknown; + ? SyntaxKind.VariableDeclaration + : SyntaxKind.Unknown; if (targetDeclarationKind !== SyntaxKind.Unknown) { const decl = getDeclarationOfKind(resolvedRequire, targetDeclarationKind)!; // function/variable declaration should be ambient @@ -34628,7 +44964,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind === SyntaxKind.TypeAssertionExpression) { const file = getSourceFileOfNode(node); if (file && fileExtensionIsOneOf(file.fileName, [Extension.Cts, Extension.Mts])) { - grammarErrorOnNode(node, Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Use_an_as_expression_instead); + grammarErrorOnNode( + node, + Diagnostics + .This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Use_an_as_expression_instead, + ); } } return checkAssertionWorker(node, checkMode); @@ -34651,12 +44991,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.PrefixUnaryExpression: const op = (node as PrefixUnaryExpression).operator; const arg = (node as PrefixUnaryExpression).operand; - return op === SyntaxKind.MinusToken && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) || - op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral; + return op === SyntaxKind.MinusToken + && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) + || op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: const expr = skipParentheses((node as PropertyAccessExpression | ElementAccessExpression).expression); - const symbol = isEntityNameExpression(expr) ? resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true) : undefined; + const symbol = isEntityNameExpression(expr) + ? resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true) : undefined; return !!(symbol && symbol.flags & SymbolFlags.Enum); } return false; @@ -34667,7 +45009,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const exprType = checkExpression(expression, checkMode); if (isConstTypeReference(type)) { if (!isValidConstAssertionArgument(expression)) { - error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); + error( + expression, + Diagnostics + .A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals, + ); } return getRegularTypeOfLiteralType(exprType); } @@ -34707,8 +45053,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addLazyDiagnostic(() => { const widenedType = getWidenedType(exprType); if (!isTypeComparableTo(targetType, widenedType)) { - checkTypeComparableTo(exprType, targetType, errNode, - Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first); + checkTypeComparableTo( + exprType, + targetType, + errNode, + Diagnostics + .Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first, + ); } }); } @@ -34721,8 +45072,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkNonNullAssertion(node: NonNullExpression) { - return node.flags & NodeFlags.OptionalChain ? checkNonNullChain(node as NonNullChain) : - getNonNullableType(checkExpression(node.expression)); + return node.flags & NodeFlags.OptionalChain ? checkNonNullChain(node as NonNullChain) + : getNonNullableType(checkExpression(node.expression)); } function checkExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { @@ -34730,13 +45081,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { forEach(node.typeArguments, checkSourceElement); if (node.kind === SyntaxKind.ExpressionWithTypeArguments) { const parent = walkUpParenthesizedExpressions(node.parent); - if (parent.kind === SyntaxKind.BinaryExpression && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.InstanceOfKeyword && isNodeDescendantOf(node, (parent as BinaryExpression).right)) { - error(node, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_not_be_an_instantiation_expression); + if ( + parent.kind === SyntaxKind.BinaryExpression + && (parent as BinaryExpression).operatorToken.kind === SyntaxKind.InstanceOfKeyword + && isNodeDescendantOf(node, (parent as BinaryExpression).right) + ) { + error( + node, + Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_not_be_an_instantiation_expression, + ); } } - const exprType = node.kind === SyntaxKind.ExpressionWithTypeArguments ? checkExpression(node.expression) : - isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName) : - checkExpression(node.exprName); + const exprType = node.kind === SyntaxKind.ExpressionWithTypeArguments ? checkExpression(node.expression) + : isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName) + : checkExpression(node.exprName); return getInstantiationExpressionType(exprType, node); } @@ -34750,7 +45108,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const result = getInstantiatedType(exprType); const errorType = hasSomeApplicableSignature ? nonApplicableType : exprType; if (errorType) { - diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, typeToString(errorType))); + diagnostics.add( + createDiagnosticForNodeArray( + getSourceFileOfNode(node), + typeArguments, + Diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, + typeToString(errorType), + ), + ); } return result; @@ -34771,8 +45136,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constructSignatures = getInstantiatedSignatures(resolved.constructSignatures); hasSignatures ||= resolved.callSignatures.length !== 0 || resolved.constructSignatures.length !== 0; hasApplicableSignature ||= callSignatures.length !== 0 || constructSignatures.length !== 0; - if (callSignatures !== resolved.callSignatures || constructSignatures !== resolved.constructSignatures) { - const result = createAnonymousType(/*symbol*/ undefined, resolved.members, callSignatures, constructSignatures, resolved.indexInfos) as ResolvedType & InstantiationExpressionType; + if ( + callSignatures !== resolved.callSignatures + || constructSignatures !== resolved.constructSignatures + ) { + const result = createAnonymousType( + /*symbol*/ undefined, + resolved.members, + callSignatures, + constructSignatures, + resolved.indexInfos, + ) as ResolvedType & InstantiationExpressionType; result.objectFlags |= ObjectFlags.InstantiationExpressionType; result.node = node; return result; @@ -34798,10 +45172,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getInstantiatedSignatures(signatures: readonly Signature[]) { - const applicableSignatures = filter(signatures, sig => !!sig.typeParameters && hasCorrectTypeArgumentArity(sig, typeArguments)); + const applicableSignatures = filter( + signatures, + sig => !!sig.typeParameters && hasCorrectTypeArgumentArity(sig, typeArguments), + ); return sameMap(applicableSignatures, sig => { const typeArgumentTypes = checkTypeArguments(sig, typeArguments!, /*reportErrors*/ true); - return typeArgumentTypes ? getSignatureInstantiation(sig, typeArgumentTypes, isInJSFile(sig.declaration)) : sig; + return typeArgumentTypes + ? getSignatureInstantiation(sig, typeArgumentTypes, isInJSFile(sig.declaration)) : sig; }); } } @@ -34817,8 +45195,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isErrorType(targetType)) { return targetType; } - const errorNode = findAncestor(target.parent, n => n.kind === SyntaxKind.SatisfiesExpression || n.kind === SyntaxKind.JSDocSatisfiesTag); - checkTypeAssignableToAndOptionallyElaborate(exprType, targetType, errorNode, expression, Diagnostics.Type_0_does_not_satisfy_the_expected_type_1); + const errorNode = findAncestor( + target.parent, + n => n.kind === SyntaxKind.SatisfiesExpression || n.kind === SyntaxKind.JSDocSatisfiesTag, + ); + checkTypeAssignableToAndOptionallyElaborate( + exprType, + targetType, + errorNode, + expression, + Diagnostics.Type_0_does_not_satisfy_the_expected_type_1, + ); return exprType; } @@ -34851,7 +45238,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkNewTargetMetaProperty(node: MetaProperty) { const container = getNewTargetContainer(node); if (!container) { - error(node, Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, "new.target"); + error( + node, + Diagnostics + .Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, + "new.target", + ); return errorType; } else if (container.kind === SyntaxKind.Constructor) { @@ -34867,14 +45259,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkImportMetaProperty(node: MetaProperty) { if (moduleKind === ModuleKind.Node16 || moduleKind === ModuleKind.NodeNext) { if (getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.ESNext) { - error(node, Diagnostics.The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output); + error( + node, + Diagnostics + .The_import_meta_meta_property_is_not_allowed_in_files_which_will_build_into_CommonJS_output, + ); } } else if (moduleKind < ModuleKind.ES2020 && moduleKind !== ModuleKind.System) { - error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_es2020_es2022_esnext_system_node16_or_nodenext); + error( + node, + Diagnostics + .The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_es2020_es2022_esnext_system_node16_or_nodenext, + ); } const file = getSourceFileOfNode(node); - Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag."); + Debug.assert( + !!(file.flags & NodeFlags.PossiblyContainsImportMeta), + "Containing file is missing import meta node flag.", + ); return node.name.escapedText === "meta" ? getGlobalImportMetaType() : errorType; } @@ -34890,8 +45293,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember): __String; - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember | undefined, index: number, restParameterName?: __String): __String; - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember | undefined, index?: number, restParameterName = "arg" as __String) { + function getTupleElementLabel( + d: ParameterDeclaration | NamedTupleMember | undefined, + index: number, + restParameterName?: __String, + ): __String; + function getTupleElementLabel( + d: ParameterDeclaration | NamedTupleMember | undefined, + index?: number, + restParameterName = "arg" as __String, + ) { if (!d) { return `${restParameterName}_${index}` as __String; } @@ -34914,7 +45325,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return restParameter.escapedName; } - function getParameterIdentifierInfoAtPosition(signature: Signature, pos: number): { parameter: Identifier, parameterName: __String, isRestParameter: boolean } | undefined { + function getParameterIdentifierInfoAtPosition( + signature: Signature, + pos: number, + ): { parameter: Identifier; parameterName: __String; isRestParameter: boolean; } | undefined { if (signature.declaration?.kind === SyntaxKind.JSDocFunctionType) { return undefined; } @@ -34925,7 +45339,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return paramIdent ? { parameter: paramIdent, parameterName: param.escapedName, - isRestParameter: false + isRestParameter: false, } : undefined; } @@ -34944,7 +45358,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (associatedName) { Debug.assert(isIdentifier(associatedName.name)); - return { parameter: associatedName.name, parameterName: associatedName.name.escapedText, isRestParameter: isRestTupleElement }; + return { + parameter: associatedName.name, + parameterName: associatedName.name.escapedText, + isRestParameter: isRestTupleElement, + }; } return undefined; @@ -34957,9 +45375,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getParameterDeclarationIdentifier(symbol: Symbol) { - return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) && isIdentifier(symbol.valueDeclaration.name) && symbol.valueDeclaration.name; + return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) + && isIdentifier(symbol.valueDeclaration.name) && symbol.valueDeclaration.name; } - function isValidDeclarationForTupleLabel(d: Declaration): d is NamedTupleMember | (ParameterDeclaration & { name: Identifier }) { + function isValidDeclarationForTupleLabel( + d: Declaration, + ): d is NamedTupleMember | (ParameterDeclaration & { name: Identifier; }) { return d.kind === SyntaxKind.NamedTupleMember || (isParameter(d) && d.name && isIdentifier(d.name)); } @@ -34976,7 +45397,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const index = pos - paramCount; return associatedNames && associatedNames[index]; } - return restParameter.valueDeclaration && isValidDeclarationForTupleLabel(restParameter.valueDeclaration) ? restParameter.valueDeclaration : undefined; + return restParameter.valueDeclaration && isValidDeclarationForTupleLabel(restParameter.valueDeclaration) + ? restParameter.valueDeclaration : undefined; } function getTypeAtPosition(signature: Signature, pos: number): Type { @@ -35051,7 +45473,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (signatureHasRestParameter(signature)) { const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]); if (isTupleType(restType)) { - const firstOptionalIndex = findIndex(restType.target.elementFlags, f => !(f & ElementFlags.Required)); + const firstOptionalIndex = findIndex( + restType.target.elementFlags, + f => !(f & ElementFlags.Required), + ); const requiredCount = firstOptionalIndex < 0 ? restType.target.fixedLength : firstOptionalIndex; if (requiredCount > 0) { minArgumentCount = signature.parameters.length - 1 + requiredCount; @@ -35113,14 +45538,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : fallbackType; } - function inferFromAnnotatedParameters(signature: Signature, context: Signature, inferenceContext: InferenceContext) { + function inferFromAnnotatedParameters( + signature: Signature, + context: Signature, + inferenceContext: InferenceContext, + ) { const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); for (let i = 0; i < len; i++) { const declaration = signature.parameters[i].valueDeclaration as ParameterDeclaration; if (declaration.type) { const typeNode = getEffectiveTypeAnnotationNode(declaration); if (typeNode) { - inferTypes(inferenceContext.inferences, getTypeFromTypeNode(typeNode), getTypeAtPosition(context, i)); + const source = addOptionality( + getTypeFromTypeNode(typeNode), + /*isProperty*/ false, + isOptionalDeclaration(declaration), + ); + const target = getTypeAtPosition(context, i); + inferTypes(inferenceContext.inferences, source, target); } } } @@ -35137,7 +45572,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (context.thisParameter) { const parameter = signature.thisParameter; - if (!parameter || parameter.valueDeclaration && !(parameter.valueDeclaration as ParameterDeclaration).type) { + if ( + !parameter || parameter.valueDeclaration && !(parameter.valueDeclaration as ParameterDeclaration).type + ) { if (!parameter) { signature.thisParameter = createSymbolWithType(context.thisParameter, /*type*/ undefined); } @@ -35155,11 +45592,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (signatureHasRestParameter(signature)) { // parameter might be a transient symbol generated by use of `arguments` in the function body. const parameter = last(signature.parameters); - if (parameter.valueDeclaration - ? !getEffectiveTypeAnnotationNode(parameter.valueDeclaration as ParameterDeclaration) - // a declarationless parameter may still have a `.type` already set by its construction logic - // (which may pull a type from a jsdoc) - only allow fixing on `DeferredType` parameters with a fallback type - : !!(getCheckFlags(parameter) & CheckFlags.DeferredType) + if ( + parameter.valueDeclaration + ? !getEffectiveTypeAnnotationNode(parameter.valueDeclaration as ParameterDeclaration) + // a declarationless parameter may still have a `.type` already set by its construction logic + // (which may pull a type from a jsdoc) - only allow fixing on `DeferredType` parameters with a fallback type + : !!(getCheckFlags(parameter) & CheckFlags.DeferredType) ) { const contextualParameterType = getRestTypeAtPosition(context, len); assignParameterType(parameter, contextualParameterType); @@ -35180,7 +45618,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const links = getSymbolLinks(parameter); if (!links.type) { const declaration = parameter.valueDeclaration as ParameterDeclaration | undefined; - links.type = type || (declaration ? getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true) : getTypeOfSymbol(parameter)); + links.type = type + || (declaration ? getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true) + : getTypeOfSymbol(parameter)); if (declaration && declaration.name.kind !== SyntaxKind.Identifier) { // if inference didn't come up with anything but unknown, fall back to the binding pattern if present. if (links.type === unknownType) { @@ -35190,7 +45630,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (type) { - Debug.assertEqual(links.type, type, "Parameter symbol already has a cached type which differs from newly assigned type"); + Debug.assertEqual( + links.type, + type, + "Parameter symbol already has a cached type which differs from newly assigned type", + ); } } @@ -35215,23 +45659,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function createClassMethodDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassMethodDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + return tryCreateTypeReference(getGlobalClassMethodDecoratorContextType(/*reportErrors*/ true), [ + thisType, + valueType, + ]); } function createClassGetterDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassGetterDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + return tryCreateTypeReference(getGlobalClassGetterDecoratorContextType(/*reportErrors*/ true), [ + thisType, + valueType, + ]); } function createClassSetterDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassSetterDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + return tryCreateTypeReference(getGlobalClassSetterDecoratorContextType(/*reportErrors*/ true), [ + thisType, + valueType, + ]); } function createClassAccessorDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassAccessorDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + return tryCreateTypeReference(getGlobalClassAccessorDecoratorContextType(/*reportErrors*/ true), [ + thisType, + valueType, + ]); } function createClassFieldDecoratorContextType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassFieldDecoratorContextType(/*reportErrors*/ true), [thisType, valueType]); + return tryCreateTypeReference(getGlobalClassFieldDecoratorContextType(/*reportErrors*/ true), [ + thisType, + valueType, + ]); } /** @@ -35252,34 +45711,50 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return overrideType; } - function createClassMemberDecoratorContextTypeForNode(node: MethodDeclaration | AccessorDeclaration | PropertyDeclaration, thisType: Type, valueType: Type) { + function createClassMemberDecoratorContextTypeForNode( + node: MethodDeclaration | AccessorDeclaration | PropertyDeclaration, + thisType: Type, + valueType: Type, + ) { const isStatic = hasStaticModifier(node); const isPrivate = isPrivateIdentifier(node.name); - const nameType = isPrivate ? getStringLiteralType(idText(node.name)) : getLiteralTypeFromPropertyName(node.name); - const contextType = - isMethodDeclaration(node) ? createClassMethodDecoratorContextType(thisType, valueType) : - isGetAccessorDeclaration(node) ? createClassGetterDecoratorContextType(thisType, valueType) : - isSetAccessorDeclaration(node) ? createClassSetterDecoratorContextType(thisType, valueType) : - isAutoAccessorPropertyDeclaration(node) ? createClassAccessorDecoratorContextType(thisType, valueType) : - isPropertyDeclaration(node) ? createClassFieldDecoratorContextType(thisType, valueType) : - Debug.failBadSyntaxKind(node); + const nameType = isPrivate ? getStringLiteralType(idText(node.name)) + : getLiteralTypeFromPropertyName(node.name); + const contextType = isMethodDeclaration(node) ? createClassMethodDecoratorContextType(thisType, valueType) + : isGetAccessorDeclaration(node) ? createClassGetterDecoratorContextType(thisType, valueType) + : isSetAccessorDeclaration(node) ? createClassSetterDecoratorContextType(thisType, valueType) + : isAutoAccessorPropertyDeclaration(node) ? createClassAccessorDecoratorContextType(thisType, valueType) + : isPropertyDeclaration(node) ? createClassFieldDecoratorContextType(thisType, valueType) + : Debug.failBadSyntaxKind(node); const overrideType = getClassMemberDecoratorContextOverrideType(nameType, isPrivate, isStatic); return getIntersectionType([contextType, overrideType]); - } function createClassAccessorDecoratorTargetType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassAccessorDecoratorTargetType(/*reportErrors*/ true), [thisType, valueType]); + return tryCreateTypeReference(getGlobalClassAccessorDecoratorTargetType(/*reportErrors*/ true), [ + thisType, + valueType, + ]); } function createClassAccessorDecoratorResultType(thisType: Type, valueType: Type) { - return tryCreateTypeReference(getGlobalClassAccessorDecoratorResultType(/*reportErrors*/ true), [thisType, valueType]); + return tryCreateTypeReference(getGlobalClassAccessorDecoratorResultType(/*reportErrors*/ true), [ + thisType, + valueType, + ]); } function createClassFieldDecoratorInitializerMutatorType(thisType: Type, valueType: Type) { const thisParam = createParameter("this" as __String, thisType); const valueParam = createParameter("value" as __String, valueType); - return createFunctionType(/*typeParameters*/ undefined, thisParam, [valueParam], valueType, /*typePredicate*/ undefined, 1); + return createFunctionType( + /*typeParameters*/ undefined, + thisParam, + [valueParam], + valueType, + /*typePredicate*/ undefined, + 1, + ); } /** @@ -35290,7 +45765,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetParam = createParameter("target" as __String, targetType); const contextParam = createParameter("context" as __String, contextType); const returnType = getUnionType([nonOptionalReturnType, voidType]); - return createCallSignature(/*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam, contextParam], returnType); + return createCallSignature(/*typeParameters*/ undefined, /*thisParameter*/ undefined, [ + targetParam, + contextParam, + ], returnType); } /** @@ -35416,29 +45894,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In all three cases, the `This` type argument is the "final type" of either the class or // instance, depending on whether the member was `static`. - const valueType = - isMethodDeclaration(node) ? getOrCreateTypeFromSignature(getSignatureFromDeclaration(node)) : - getTypeOfNode(node); + const valueType = isMethodDeclaration(node) + ? getOrCreateTypeFromSignature(getSignatureFromDeclaration(node)) + : getTypeOfNode(node); - const thisType = hasStaticModifier(node) ? - getTypeOfSymbol(getSymbolOfDeclaration(node.parent)) : - getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node.parent)); + const thisType = hasStaticModifier(node) + ? getTypeOfSymbol(getSymbolOfDeclaration(node.parent)) + : getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node.parent)); // We wrap the "input type", if necessary, to match the decoration target. For getters this is // something like `() => inputType`, for setters it's `(value: inputType) => void` and for // methods it is just the input type. - const targetType = - isGetAccessorDeclaration(node) ? createGetterFunctionType(valueType) : - isSetAccessorDeclaration(node) ? createSetterFunctionType(valueType) : - valueType; + const targetType = isGetAccessorDeclaration(node) ? createGetterFunctionType(valueType) + : isSetAccessorDeclaration(node) ? createSetterFunctionType(valueType) + : valueType; const contextType = createClassMemberDecoratorContextTypeForNode(node, thisType, valueType); // We also wrap the "output type", as needed. - const returnType = - isGetAccessorDeclaration(node) ? createGetterFunctionType(valueType) : - isSetAccessorDeclaration(node) ? createSetterFunctionType(valueType) : - valueType; + const returnType = isGetAccessorDeclaration(node) ? createGetterFunctionType(valueType) + : isSetAccessorDeclaration(node) ? createSetterFunctionType(valueType) + : valueType; links.decoratorSignature = createESDecoratorCallSignature(targetType, contextType, returnType); break; @@ -35455,16 +45931,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // the "final type" of the value stored in the field. const valueType = getTypeOfNode(node); - const thisType = hasStaticModifier(node) ? - getTypeOfSymbol(getSymbolOfDeclaration(node.parent)) : - getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node.parent)); + const thisType = hasStaticModifier(node) + ? getTypeOfSymbol(getSymbolOfDeclaration(node.parent)) + : getDeclaredTypeOfClassOrInterface(getSymbolOfDeclaration(node.parent)); // The `target` of an auto-accessor decorator is a `{ get, set }` object, representing the // runtime-generated getter and setter that are added to the class/prototype. The `target` of a // regular field decorator is always `undefined` as it isn't installed until it is initialized. - const targetType = - hasAccessorModifier(node) ? createClassAccessorDecoratorTargetType(thisType, valueType) : - undefinedType; + const targetType = hasAccessorModifier(node) + ? createClassAccessorDecoratorTargetType(thisType, valueType) + : undefinedType; const contextType = createClassMemberDecoratorContextTypeForNode(node, thisType, valueType); @@ -35472,9 +45948,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // "output type" in a `ClassAccessorDecoratorResult` type, which allows for // mutation of the runtime-generated getter and setter, as well as the injection of an // initializer mutator. For regular fields, we wrap the "output type" in an initializer mutator. - const returnType = - hasAccessorModifier(node) ? createClassAccessorDecoratorResultType(thisType, valueType) : - createClassFieldDecoratorInitializerMutatorType(thisType, valueType); + const returnType = hasAccessorModifier(node) + ? createClassAccessorDecoratorResultType(thisType, valueType) + : createClassFieldDecoratorInitializerMutatorType(thisType, valueType); links.decoratorSignature = createESDecoratorCallSignature(targetType, contextType, returnType); break; @@ -35501,14 +45977,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam], - getUnionType([targetType, voidType]) + getUnionType([targetType, voidType]), ); break; } case SyntaxKind.Parameter: { const node = parent as ParameterDeclaration; - if (!isConstructorDeclaration(node.parent) && - !((isMethodDeclaration(node.parent) || isSetAccessorDeclaration(node.parent) && isClassLike(node.parent.parent)))) { + if ( + !isConstructorDeclaration(node.parent) + && !(isMethodDeclaration(node.parent) + || isSetAccessorDeclaration(node.parent) && isClassLike(node.parent.parent)) + ) { break; } @@ -35516,21 +45995,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; } - const index = getThisParameter(node.parent) ? - node.parent.parameters.indexOf(node) - 1 : - node.parent.parameters.indexOf(node); + const index = getThisParameter(node.parent) + ? node.parent.parameters.indexOf(node) - 1 + : node.parent.parameters.indexOf(node); Debug.assert(index >= 0); // A parameter declaration decorator will have three arguments (see `ParameterDecorator` in // core.d.ts). - const targetType = - isConstructorDeclaration(node.parent) ? getTypeOfSymbol(getSymbolOfDeclaration(node.parent.parent)) : - getParentTypeOfClassElement(node.parent); + const targetType = isConstructorDeclaration(node.parent) + ? getTypeOfSymbol(getSymbolOfDeclaration(node.parent.parent)) + : getParentTypeOfClassElement(node.parent); - const keyType = - isConstructorDeclaration(node.parent) ? undefinedType : - getClassElementPropertyKeyType(node.parent); + const keyType = isConstructorDeclaration(node.parent) ? undefinedType + : getClassElementPropertyKeyType(node.parent); const indexType = getNumberLiteralType(index); @@ -35541,7 +46019,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam, keyParam, indexParam], - voidType + voidType, ); break; } @@ -35562,11 +46040,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const keyType = getClassElementPropertyKeyType(node); const keyParam = createParameter("propertyKey" as __String, keyType); - const returnType = - isPropertyDeclaration(node) ? voidType : - createTypedPropertyDescriptorType(getTypeOfNode(node)); + const returnType = isPropertyDeclaration(node) ? voidType + : createTypedPropertyDescriptorType(getTypeOfNode(node)); - const hasPropDesc = languageVersion !== ScriptTarget.ES3 && (!isPropertyDeclaration(parent) || hasAccessorModifier(parent)); + const hasPropDesc = languageVersion !== ScriptTarget.ES3 + && (!isPropertyDeclaration(parent) || hasAccessorModifier(parent)); if (hasPropDesc) { const descriptorType = createTypedPropertyDescriptorType(getTypeOfNode(node)); const descriptorParam = createParameter("descriptor" as __String, descriptorType); @@ -35574,7 +46052,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam, keyParam, descriptorParam], - getUnionType([returnType, voidType]) + getUnionType([returnType, voidType]), ); } else { @@ -35582,7 +46060,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*typeParameters*/ undefined, /*thisParameter*/ undefined, [targetParam, keyParam], - getUnionType([returnType, voidType]) + getUnionType([returnType, voidType]), ); } break; @@ -35593,8 +46071,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getDecoratorCallSignature(decorator: Decorator) { - return legacyDecorators ? getLegacyDecoratorCallSignature(decorator) : - getESDecoratorCallSignature(decorator); + return legacyDecorators ? getLegacyDecoratorCallSignature(decorator) + : getESDecoratorCallSignature(decorator); } function createPromiseType(promisedType: Type): Type { @@ -35626,15 +46104,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createPromiseReturnType(func: FunctionLikeDeclaration | ImportCall, promisedType: Type) { const promiseType = createPromiseType(promisedType); if (promiseType === unknownType) { - error(func, isImportCall(func) ? - Diagnostics.A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option : - Diagnostics.An_async_function_or_method_must_return_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option); + error( + func, + isImportCall(func) + ? Diagnostics + .A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option + : Diagnostics + .An_async_function_or_method_must_return_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option, + ); return errorType; } else if (!getGlobalPromiseConstructorSymbol(/*reportErrors*/ true)) { - error(func, isImportCall(func) ? - Diagnostics.A_dynamic_import_call_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option : - Diagnostics.An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option); + error( + func, + isImportCall(func) + ? Diagnostics + .A_dynamic_import_call_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option + : Diagnostics + .An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option, + ); } return promiseType; @@ -35673,7 +46161,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which we will wrap in // the native Promise type later in this function. - returnType = unwrapAwaitedType(checkAwaitedType(returnType, /*withAlias*/ false, /*errorNode*/ func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)); + returnType = unwrapAwaitedType( + checkAwaitedType( + returnType, + /*withAlias*/ false, + /*errorNode*/ func, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ), + ); } } else if (isGenerator) { // Generator or AsyncGenerator function @@ -35699,9 +46195,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (types.length === 0) { // For an async function, the return type will not be void/undefined, but rather a Promise for void/undefined. const contextualReturnType = getContextualReturnType(func, /*contextFlags*/ undefined); - const returnType = contextualReturnType && (unwrapReturnType(contextualReturnType, functionFlags) || voidType).flags & TypeFlags.Undefined ? undefinedType : voidType; - return functionFlags & FunctionFlags.Async ? createPromiseReturnType(func, returnType) : // Async function - returnType; // Normal function + const returnType = contextualReturnType + && (unwrapReturnType(contextualReturnType, functionFlags) || voidType).flags + & TypeFlags.Undefined ? undefinedType : voidType; + return functionFlags & FunctionFlags.Async ? createPromiseReturnType(func, returnType) // Async function + : returnType; // Normal function } // Return a union of the return expression types. @@ -35712,20 +46210,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (yieldType) reportErrorsFromWidening(func, yieldType, WideningKind.GeneratorYield); if (returnType) reportErrorsFromWidening(func, returnType, WideningKind.FunctionReturn); if (nextType) reportErrorsFromWidening(func, nextType, WideningKind.GeneratorNext); - if (returnType && isUnitType(returnType) || - yieldType && isUnitType(yieldType) || - nextType && isUnitType(nextType)) { + if ( + returnType && isUnitType(returnType) + || yieldType && isUnitType(yieldType) + || nextType && isUnitType(nextType) + ) { const contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func); - const contextualType = !contextualSignature ? undefined : - contextualSignature === getSignatureFromDeclaration(func) ? isGenerator ? undefined : returnType : - instantiateContextualType(getReturnTypeOfSignature(contextualSignature), func, /*contextFlags*/ undefined); + const contextualType = !contextualSignature ? undefined + : contextualSignature === getSignatureFromDeclaration(func) ? isGenerator ? undefined : returnType + : instantiateContextualType( + getReturnTypeOfSignature(contextualSignature), + func, + /*contextFlags*/ undefined, + ); if (isGenerator) { - yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(yieldType, contextualType, IterationTypeKind.Yield, isAsync); - returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(returnType, contextualType, IterationTypeKind.Return, isAsync); - nextType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(nextType, contextualType, IterationTypeKind.Next, isAsync); + yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + yieldType, + contextualType, + IterationTypeKind.Yield, + isAsync, + ); + returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + returnType, + contextualType, + IterationTypeKind.Return, + isAsync, + ); + nextType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded( + nextType, + contextualType, + IterationTypeKind.Next, + isAsync, + ); } else { - returnType = getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded(returnType, contextualType, isAsync); + returnType = getWidenedLiteralLikeTypeForContextualReturnTypeIfNeeded( + returnType, + contextualType, + isAsync, + ); } } @@ -35739,7 +46262,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { yieldType || neverType, returnType || fallbackReturnType, nextType || getContextualIterationType(IterationTypeKind.Next, func) || unknownType, - isAsync); + isAsync, + ); } else { // From within an async function you can return either a non-promise value or a promise. Any @@ -35762,11 +46286,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // type of IterableIterator, and the expected next iteration type of IterableIterator is assignable to // nextType. const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); - const iterationTypes = globalType !== emptyGenericType ? getIterationTypesOfGlobalIterableType(globalType, resolver) : undefined; + const iterationTypes = globalType !== emptyGenericType + ? getIterationTypesOfGlobalIterableType(globalType, resolver) : undefined; const iterableIteratorReturnType = iterationTypes ? iterationTypes.returnType : anyType; const iterableIteratorNextType = iterationTypes ? iterationTypes.nextType : undefinedType; - if (isTypeAssignableTo(returnType, iterableIteratorReturnType) && - isTypeAssignableTo(iterableIteratorNextType, nextType)) { + if ( + isTypeAssignableTo(returnType, iterableIteratorReturnType) + && isTypeAssignableTo(iterableIteratorNextType, nextType) + ) { if (globalType !== emptyGenericType) { return createTypeFromGenericGlobalType(globalType, [yieldType]); } @@ -35789,14 +46316,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const nextTypes: Type[] = []; const isAsync = (getFunctionFlags(func) & FunctionFlags.Async) !== 0; forEachYieldExpression(func.body as Block, yieldExpression => { - const yieldExpressionType = yieldExpression.expression ? checkExpression(yieldExpression.expression, checkMode) : undefinedWideningType; - pushIfUnique(yieldTypes, getYieldedTypeOfYieldExpression(yieldExpression, yieldExpressionType, anyType, isAsync)); + const yieldExpressionType = yieldExpression.expression + ? checkExpression(yieldExpression.expression, checkMode) : undefinedWideningType; + pushIfUnique( + yieldTypes, + getYieldedTypeOfYieldExpression(yieldExpression, yieldExpressionType, anyType, isAsync), + ); let nextType: Type | undefined; if (yieldExpression.asteriskToken) { const iterationTypes = getIterationTypesOfIterable( yieldExpressionType, isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, - yieldExpression.expression); + yieldExpression.expression, + ); nextType = iterationTypes && iterationTypes.nextType; } else { @@ -35807,17 +46339,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return { yieldTypes, nextTypes }; } - function getYieldedTypeOfYieldExpression(node: YieldExpression, expressionType: Type, sentType: Type, isAsync: boolean): Type | undefined { + function getYieldedTypeOfYieldExpression( + node: YieldExpression, + expressionType: Type, + sentType: Type, + isAsync: boolean, + ): Type | undefined { const errorNode = node.expression || node; // A `yield*` expression effectively yields everything that its operand yields - const yieldedType = node.asteriskToken ? checkIteratedTypeOrElementType(isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, expressionType, sentType, errorNode) : expressionType; - return !isAsync ? yieldedType : getAwaitedType(yieldedType, errorNode, node.asteriskToken - ? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member - : Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); + const yieldedType = node.asteriskToken + ? checkIteratedTypeOrElementType( + isAsync ? IterationUse.AsyncYieldStar : IterationUse.YieldStar, + expressionType, + sentType, + errorNode, + ) : expressionType; + return !isAsync ? yieldedType : getAwaitedType( + yieldedType, + errorNode, + node.asteriskToken + ? Diagnostics + .Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member + : Diagnostics + .Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ); } // Return the combined not-equal type facts for all cases except those between the start and end indices. - function getNotEqualFactsFromTypeofSwitch(start: number, end: number, witnesses: (string | undefined)[]): TypeFacts { + function getNotEqualFactsFromTypeofSwitch( + start: number, + end: number, + witnesses: (string | undefined)[], + ): TypeFacts { let facts: TypeFacts = TypeFacts.None; for (let i = 0; i < witnesses.length; i++) { const witness = i < start || i >= end ? witnesses[i] : undefined; @@ -35829,14 +46382,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isExhaustiveSwitchStatement(node: SwitchStatement): boolean { const links = getNodeLinks(node); if (links.isExhaustive === undefined) { - links.isExhaustive = 0; // Indicate resolution is in process + links.isExhaustive = 0; // Indicate resolution is in process const exhaustive = computeExhaustiveSwitchStatement(node); if (links.isExhaustive === 0) { links.isExhaustive = exhaustive; } } else if (links.isExhaustive === 0) { - links.isExhaustive = false; // Resolve circularity to false + links.isExhaustive = false; // Resolve circularity to false } return links.isExhaustive; } @@ -35847,7 +46400,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!witnesses) { return false; } - const operandConstraint = getBaseConstraintOrType(checkExpressionCached((node.expression as TypeOfExpression).expression)); + const operandConstraint = getBaseConstraintOrType( + checkExpressionCached((node.expression as TypeOfExpression).expression), + ); // Get the not-equal flags for all handled cases. const notEqualFacts = getNotEqualFactsFromTypeofSwitch(0, 0, witnesses); if (operandConstraint.flags & TypeFlags.AnyOrUnknown) { @@ -35873,7 +46428,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** NOTE: Return value of `[]` means a different thing than `undefined`. `[]` means func returns `void`, `undefined` means it returns `never`. */ - function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, checkMode: CheckMode | undefined): Type[] | undefined { + function checkAndAggregateReturnExpressionTypes( + func: FunctionLikeDeclaration, + checkMode: CheckMode | undefined, + ): Type[] | undefined { const functionFlags = getFunctionFlags(func); const aggregatedTypes: Type[] = []; let hasReturnWithNoExpression = functionHasImplicitReturn(func); @@ -35882,9 +46440,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const expr = returnStatement.expression; if (expr) { // Bare calls to this same function don't contribute to inference - if (expr.kind === SyntaxKind.CallExpression && - (expr as CallExpression).expression.kind === SyntaxKind.Identifier && - checkExpressionCached((expr as CallExpression).expression).symbol === func.symbol) { + if ( + expr.kind === SyntaxKind.CallExpression + && (expr as CallExpression).expression.kind === SyntaxKind.Identifier + && checkExpressionCached((expr as CallExpression).expression).symbol === func.symbol + ) { hasReturnOfTypeNever = true; return; } @@ -35895,7 +46455,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Promise/A+ compatible implementation will always assimilate any foreign promise, so the // return type of the body should be unwrapped to its awaited type, which should be wrapped in // the native Promise type by the caller. - type = unwrapAwaitedType(checkAwaitedType(type, /*withAlias*/ false, func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)); + type = unwrapAwaitedType( + checkAwaitedType( + type, + /*withAlias*/ false, + func, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ), + ); } if (type.flags & TypeFlags.Never) { hasReturnOfTypeNever = true; @@ -35906,11 +46474,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { hasReturnWithNoExpression = true; } }); - if (aggregatedTypes.length === 0 && !hasReturnWithNoExpression && (hasReturnOfTypeNever || mayReturnNever(func))) { + if ( + aggregatedTypes.length === 0 && !hasReturnWithNoExpression && (hasReturnOfTypeNever || mayReturnNever(func)) + ) { return undefined; } - if (strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression && - !(isJSConstructor(func) && aggregatedTypes.some(t => t.symbol === func.symbol))) { + if ( + strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression + && !(isJSConstructor(func) && aggregatedTypes.some(t => t.symbol === func.symbol)) + ) { // Javascript "callable constructors", containing eg `if (!(this instanceof A)) return new A()` should not add undefined pushIfUnique(aggregatedTypes, undefinedType); } @@ -35937,7 +46509,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * @param returnType - return type of the function, can be undefined if return type is not explicitly specified */ - function checkAllCodePathsInNonVoidFunctionReturnOrThrow(func: FunctionLikeDeclaration | MethodSignature, returnType: Type | undefined) { + function checkAllCodePathsInNonVoidFunctionReturnOrThrow( + func: FunctionLikeDeclaration | MethodSignature, + returnType: Type | undefined, + ) { addLazyDiagnostic(checkAllCodePathsInNonVoidFunctionReturnOrThrowDiagnostics); return; @@ -35953,7 +46528,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check. // also if HasImplicitReturn flag is not set this means that all codepaths in function body end with return or throw - if (func.kind === SyntaxKind.MethodSignature || nodeIsMissing(func.body) || func.body!.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func)) { + if ( + func.kind === SyntaxKind.MethodSignature || nodeIsMissing(func.body) + || func.body!.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func) + ) { return; } @@ -35966,10 +46544,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (type && !hasExplicitReturn) { // minimal check: function has syntactic return type annotation and no explicit return statements in the body // this function does not conform to the specification. - error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value); + error( + errorNode, + Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value, + ); } else if (type && strictNullChecks && !isTypeAssignableTo(undefinedType, type)) { - error(errorNode, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined); + error( + errorNode, + Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined, + ); } else if (compilerOptions.noImplicitReturns) { if (!type) { @@ -35989,7 +46573,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode): Type { + function checkFunctionExpressionOrObjectLiteralMethod( + node: FunctionExpression | ArrowFunction | MethodDeclaration, + checkMode?: CheckMode, + ): Type { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); checkNodeDeferred(node); @@ -36009,8 +46596,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return links.contextFreeType; } const returnType = getReturnTypeFromBody(node, checkMode); - const returnOnlySignature = createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, emptyArray, returnType, /*resolvedTypePredicate*/ undefined, 0, SignatureFlags.IsNonInferrable); - const returnOnlyType = createAnonymousType(node.symbol, emptySymbols, [returnOnlySignature], emptyArray, emptyArray); + const returnOnlySignature = createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + emptyArray, + returnType, + /*resolvedTypePredicate*/ undefined, + 0, + SignatureFlags.IsNonInferrable, + ); + const returnOnlyType = createAnonymousType( + node.symbol, + emptySymbols, + [returnOnlySignature], + emptyArray, + emptyArray, + ); returnOnlyType.objectFlags |= ObjectFlags.NonInferrableType; return links.contextFreeType = returnOnlyType; } @@ -36029,7 +46631,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getTypeOfSymbol(getSymbolOfDeclaration(node)); } - function contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode) { + function contextuallyCheckFunctionExpressionOrObjectLiteralMethod( + node: FunctionExpression | ArrowFunction | MethodDeclaration, + checkMode?: CheckMode, + ) { const links = getNodeLinks(node); // Check if function expression is contextually typed and assign parameter types if so. if (!(links.flags & NodeCheckFlags.ContextChecked)) { @@ -36039,7 +46644,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // already assigned contextual types. if (!(links.flags & NodeCheckFlags.ContextChecked)) { links.flags |= NodeCheckFlags.ContextChecked; - const signature = firstOrUndefined(getSignaturesOfType(getTypeOfSymbol(getSymbolOfDeclaration(node)), SignatureKind.Call)); + const signature = firstOrUndefined( + getSignaturesOfType(getTypeOfSymbol(getSymbolOfDeclaration(node)), SignatureKind.Call), + ); if (!signature) { return; } @@ -36051,11 +46658,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferFromAnnotatedParameters(signature, contextualSignature, inferenceContext!); const restType = getEffectiveRestType(contextualSignature); if (restType && restType.flags & TypeFlags.TypeParameter) { - instantiatedContextualSignature = instantiateSignature(contextualSignature, inferenceContext!.nonFixingMapper); + instantiatedContextualSignature = instantiateSignature( + contextualSignature, + inferenceContext!.nonFixingMapper, + ); } } - instantiatedContextualSignature ||= inferenceContext ? - instantiateSignature(contextualSignature, inferenceContext.mapper) : contextualSignature; + instantiatedContextualSignature ||= inferenceContext + ? instantiateSignature(contextualSignature, inferenceContext.mapper) : contextualSignature; assignContextualParameterTypes(signature, instantiatedContextualSignature); } else { @@ -36063,7 +46673,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { assignNonContextualParameterTypes(signature); } } - else if (contextualSignature && !node.typeParameters && contextualSignature.parameters.length > node.parameters.length) { + else if ( + contextualSignature && !node.typeParameters + && contextualSignature.parameters.length > node.parameters.length + ) { const inferenceContext = getInferenceContext(node); if (checkMode && checkMode & CheckMode.Inferential) { inferFromAnnotatedParameters(signature, contextualSignature, inferenceContext!); @@ -36080,7 +46693,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) { + function checkFunctionExpressionOrObjectLiteralMethodDeferred( + node: ArrowFunction | FunctionExpression | MethodDeclaration, + ) { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); const functionFlags = getFunctionFlags(node); @@ -36110,24 +46725,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const returnOrPromisedType = returnType && unwrapReturnType(returnType, functionFlags); if (returnOrPromisedType) { if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { // Async function - const awaitedType = checkAwaitedType(exprType, /*withAlias*/ false, node.body, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); - checkTypeAssignableToAndOptionallyElaborate(awaitedType, returnOrPromisedType, node.body, node.body); + const awaitedType = checkAwaitedType( + exprType, + /*withAlias*/ false, + node.body, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ); + checkTypeAssignableToAndOptionallyElaborate( + awaitedType, + returnOrPromisedType, + node.body, + node.body, + ); } else { // Normal function - checkTypeAssignableToAndOptionallyElaborate(exprType, returnOrPromisedType, node.body, node.body); + checkTypeAssignableToAndOptionallyElaborate( + exprType, + returnOrPromisedType, + node.body, + node.body, + ); } } } } } - function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage, isAwaitValid = false): boolean { + function checkArithmeticOperandType( + operand: Node, + type: Type, + diagnostic: DiagnosticMessage, + isAwaitValid = false, + ): boolean { if (!isTypeAssignableTo(type, numberOrBigIntType)) { const awaitedType = isAwaitValid && getAwaitedTypeOfPromise(type); errorAndMaybeSuggestAwait( operand, !!awaitedType && isTypeAssignableTo(awaitedType, numberOrBigIntType), - diagnostic); + diagnostic, + ); return false; } return true; @@ -36172,13 +46809,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Enum members // Object.defineProperty assignments with writable false or no setter // Unions and intersections of the above (unions and intersections eagerly set isReadonly on creation) - return !!(getCheckFlags(symbol) & CheckFlags.Readonly || - symbol.flags & SymbolFlags.Property && getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.Readonly || - symbol.flags & SymbolFlags.Variable && getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant || - symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor) || - symbol.flags & SymbolFlags.EnumMember || - some(symbol.declarations, isReadonlyAssignmentDeclaration) - ); + return !!(getCheckFlags(symbol) & CheckFlags.Readonly + || symbol.flags & SymbolFlags.Property + && getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.Readonly + || symbol.flags & SymbolFlags.Variable && getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant + || symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor) + || symbol.flags & SymbolFlags.EnumMember + || some(symbol.declarations, isReadonlyAssignmentDeclaration)); } function isAssignmentToReadonlyEntity(expr: Expression, symbol: Symbol, assignmentKind: AssignmentKind) { @@ -36188,9 +46825,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isReadonlySymbol(symbol)) { // Allow assignments to readonly properties within constructors of the same class declaration. - if (symbol.flags & SymbolFlags.Property && - isAccessExpression(expr) && - expr.expression.kind === SyntaxKind.ThisKeyword) { + if ( + symbol.flags & SymbolFlags.Property + && isAccessExpression(expr) + && expr.expression.kind === SyntaxKind.ThisKeyword + ) { // Look for if this is the constructor for the class that `symbol` is a property of. const ctor = getContainingFunction(expr); if (!(ctor && (ctor.kind === SyntaxKind.Constructor || isJSConstructor(ctor)))) { @@ -36200,10 +46839,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isAssignmentDeclaration = isBinaryExpression(symbol.valueDeclaration); const isLocalPropertyDeclaration = ctor.parent === symbol.valueDeclaration.parent; const isLocalParameterProperty = ctor === symbol.valueDeclaration.parent; - const isLocalThisPropertyAssignment = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor.parent; - const isLocalThisPropertyAssignmentConstructorFunction = isAssignmentDeclaration && symbol.parent?.valueDeclaration === ctor; - const isWriteableSymbol = - isLocalPropertyDeclaration + const isLocalThisPropertyAssignment = isAssignmentDeclaration + && symbol.parent?.valueDeclaration === ctor.parent; + const isLocalThisPropertyAssignmentConstructorFunction = isAssignmentDeclaration + && symbol.parent?.valueDeclaration === ctor; + const isWriteableSymbol = isLocalPropertyDeclaration || isLocalParameterProperty || isLocalThisPropertyAssignment || isLocalThisPropertyAssignmentConstructorFunction; @@ -36226,7 +46866,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function checkReferenceExpression(expr: Expression, invalidReferenceMessage: DiagnosticMessage, invalidOptionalChainMessage: DiagnosticMessage): boolean { + function checkReferenceExpression( + expr: Expression, + invalidReferenceMessage: DiagnosticMessage, + invalidOptionalChainMessage: DiagnosticMessage, + ): boolean { // References are combinations of identifiers, parentheses, and property accesses. const node = skipOuterExpressions(expr, OuterExpressionKinds.Assertions | OuterExpressionKinds.Parentheses); if (node.kind !== SyntaxKind.Identifier && !isAccessExpression(node)) { @@ -36263,9 +46907,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkDeleteExpressionMustBeOptional(expr: AccessExpression, symbol: Symbol) { const type = getTypeOfSymbol(symbol); - if (strictNullChecks && - !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) && - !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional : getTypeFacts(type) & TypeFacts.IsUndefined)) { + if ( + strictNullChecks + && !(type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Never)) + && !(exactOptionalPropertyTypes ? symbol.flags & SymbolFlags.Optional + : getTypeFacts(type) & TypeFacts.IsUndefined) + ) { error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional); } } @@ -36286,8 +46933,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const container = getContainingFunctionOrClassStaticBlock(node); if (container && isClassStaticBlockDeclaration(container)) { // NOTE: We report this regardless as to whether there are parse diagnostics. - const message = isAwaitExpression(node) ? Diagnostics.await_expression_cannot_be_used_inside_a_class_static_block : - Diagnostics.await_using_statements_cannot_be_used_inside_a_class_static_block; + const message = isAwaitExpression(node) + ? Diagnostics.await_expression_cannot_be_used_inside_a_class_static_block + : Diagnostics.await_using_statements_cannot_be_used_inside_a_class_static_block; error(node, message); hasError = true; } @@ -36298,8 +46946,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let span: TextSpan | undefined; if (!isEffectiveExternalModule(sourceFile, compilerOptions)) { span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); - const message = isAwaitExpression(node) ? Diagnostics.await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module : - Diagnostics.await_using_statements_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module; + const message = isAwaitExpression(node) + ? Diagnostics + .await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module + : Diagnostics + .await_using_statements_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module; const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, message); diagnostics.add(diagnostic); hasError = true; @@ -36310,7 +46961,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) { span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); diagnostics.add( - createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level) + createFileDiagnostic( + sourceFile, + span.start, + span.length, + Diagnostics + .The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level, + ), ); hasError = true; break; @@ -36325,8 +46982,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // fallthrough default: span ??= getSpanOfTokenAtPosition(sourceFile, node.pos); - const message = isAwaitExpression(node) ? Diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher : - Diagnostics.Top_level_await_using_statements_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher; + const message = isAwaitExpression(node) + ? Diagnostics + .Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher + : Diagnostics + .Top_level_await_using_statements_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher; diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, message)); hasError = true; break; @@ -36338,11 +46998,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); - const message = isAwaitExpression(node) ? Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules : - Diagnostics.await_using_statements_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules; + const message = isAwaitExpression(node) + ? Diagnostics + .await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules + : Diagnostics + .await_using_statements_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules; const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, message); - if (container && container.kind !== SyntaxKind.Constructor && (getFunctionFlags(container) & FunctionFlags.Async) === 0) { - const relatedInfo = createDiagnosticForNode(container, Diagnostics.Did_you_mean_to_mark_this_function_as_async); + if ( + container && container.kind !== SyntaxKind.Constructor + && (getFunctionFlags(container) & FunctionFlags.Async) === 0 + ) { + const relatedInfo = createDiagnosticForNode( + container, + Diagnostics.Did_you_mean_to_mark_this_function_as_async, + ); addRelatedInfo(diagnostic, relatedInfo); } diagnostics.add(diagnostic); @@ -36364,9 +47033,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addLazyDiagnostic(() => checkAwaitGrammar(node)); const operandType = checkExpression(node.expression); - const awaitedType = checkAwaitedType(operandType, /*withAlias*/ true, node, Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); + const awaitedType = checkAwaitedType( + operandType, + /*withAlias*/ true, + node, + Diagnostics.Type_of_await_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ); if (awaitedType === operandType && !isErrorType(awaitedType) && !(operandType.flags & TypeFlags.AnyOrUnknown)) { - addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.await_has_no_effect_on_the_type_of_this_expression)); + addErrorOrSuggestion( + /*isError*/ false, + createDiagnosticForNode(node, Diagnostics.await_has_no_effect_on_the_type_of_this_expression), + ); } return awaitedType; } @@ -36389,7 +47066,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.operator === SyntaxKind.MinusToken) { return getFreshTypeOfLiteralType(getBigIntLiteralType({ negative: true, - base10Value: parsePseudoBigInt((node.operand as BigIntLiteral).text) + base10Value: parsePseudoBigInt((node.operand as BigIntLiteral).text), })); } } @@ -36399,11 +47076,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.TildeToken: checkNonNullType(operandType, node.operand); if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.ESSymbolLike)) { - error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator)); + error( + node.operand, + Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, + tokenToString(node.operator), + ); } if (node.operator === SyntaxKind.PlusToken) { if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.BigIntLike)) { - error(node.operand, Diagnostics.Operator_0_cannot_be_applied_to_type_1, tokenToString(node.operator), typeToString(getBaseTypeOfLiteralType(operandType))); + error( + node.operand, + Diagnostics.Operator_0_cannot_be_applied_to_type_1, + tokenToString(node.operator), + typeToString(getBaseTypeOfLiteralType(operandType)), + ); } return numberType; } @@ -36411,19 +47097,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ExclamationToken: checkTruthinessOfType(operandType, node.operand); const facts = getTypeFacts(operandType) & (TypeFacts.Truthy | TypeFacts.Falsy); - return facts === TypeFacts.Truthy ? falseType : - facts === TypeFacts.Falsy ? trueType : - booleanType; + return facts === TypeFacts.Truthy ? falseType + : facts === TypeFacts.Falsy ? trueType + : booleanType; case SyntaxKind.PlusPlusToken: case SyntaxKind.MinusMinusToken: - const ok = checkArithmeticOperandType(node.operand, checkNonNullType(operandType, node.operand), - Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type); + const ok = checkArithmeticOperandType( + node.operand, + checkNonNullType(operandType, node.operand), + Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type, + ); if (ok) { // run check only if former checks succeeded to avoid reporting cascading errors checkReferenceExpression( node.operand, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access); + Diagnostics + .The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, + Diagnostics + .The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, + ); } return getUnaryResultType(operandType); } @@ -36438,20 +47130,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const ok = checkArithmeticOperandType( node.operand, checkNonNullType(operandType, node.operand), - Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type); + Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_bigint_or_an_enum_type, + ); if (ok) { // run check only if former checks succeeded to avoid reporting cascading errors checkReferenceExpression( node.operand, Diagnostics.The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access, - Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access); + Diagnostics.The_operand_of_an_increment_or_decrement_operator_may_not_be_an_optional_property_access, + ); } return getUnaryResultType(operandType); } function getUnaryResultType(operandType: Type): Type { if (maybeTypeOfKind(operandType, TypeFlags.BigIntLike)) { - return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) || maybeTypeOfKind(operandType, TypeFlags.NumberLike) + return isTypeAssignableToKind(operandType, TypeFlags.AnyOrUnknown) + || maybeTypeOfKind(operandType, TypeFlags.NumberLike) ? numberOrBigIntType : bigintType; } @@ -36492,22 +47187,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (strict && source.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void | TypeFlags.Undefined | TypeFlags.Null)) { return false; } - return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) || - !!(kind & TypeFlags.BigIntLike) && isTypeAssignableTo(source, bigintType) || - !!(kind & TypeFlags.StringLike) && isTypeAssignableTo(source, stringType) || - !!(kind & TypeFlags.BooleanLike) && isTypeAssignableTo(source, booleanType) || - !!(kind & TypeFlags.Void) && isTypeAssignableTo(source, voidType) || - !!(kind & TypeFlags.Never) && isTypeAssignableTo(source, neverType) || - !!(kind & TypeFlags.Null) && isTypeAssignableTo(source, nullType) || - !!(kind & TypeFlags.Undefined) && isTypeAssignableTo(source, undefinedType) || - !!(kind & TypeFlags.ESSymbol) && isTypeAssignableTo(source, esSymbolType) || - !!(kind & TypeFlags.NonPrimitive) && isTypeAssignableTo(source, nonPrimitiveType); + return !!(kind & TypeFlags.NumberLike) && isTypeAssignableTo(source, numberType) + || !!(kind & TypeFlags.BigIntLike) && isTypeAssignableTo(source, bigintType) + || !!(kind & TypeFlags.StringLike) && isTypeAssignableTo(source, stringType) + || !!(kind & TypeFlags.BooleanLike) && isTypeAssignableTo(source, booleanType) + || !!(kind & TypeFlags.Void) && isTypeAssignableTo(source, voidType) + || !!(kind & TypeFlags.Never) && isTypeAssignableTo(source, neverType) + || !!(kind & TypeFlags.Null) && isTypeAssignableTo(source, nullType) + || !!(kind & TypeFlags.Undefined) && isTypeAssignableTo(source, undefinedType) + || !!(kind & TypeFlags.ESSymbol) && isTypeAssignableTo(source, esSymbolType) + || !!(kind & TypeFlags.NonPrimitive) && isTypeAssignableTo(source, nonPrimitiveType); } function allTypesAssignableToKind(source: Type, kind: TypeFlags, strict?: boolean): boolean { - return source.flags & TypeFlags.Union ? - every((source as UnionType).types, subType => allTypesAssignableToKind(subType, kind, strict)) : - isTypeAssignableToKind(source, kind, strict); + return source.flags & TypeFlags.Union + ? every((source as UnionType).types, subType => allTypesAssignableToKind(subType, kind, strict)) + : isTypeAssignableToKind(source, kind, strict); } function isConstEnumObjectType(type: Type): boolean { @@ -36527,19 +47222,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and the right operand to be of type Any, a subtype of the 'Function' interface type, or have a call or construct signature. // The result is always of the Boolean primitive type. // NOTE: do not raise error if leftType is unknown as related error was already reported - if (!isTypeAny(leftType) && - allTypesAssignableToKind(leftType, TypeFlags.Primitive)) { - error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + if ( + !isTypeAny(leftType) + && allTypesAssignableToKind(leftType, TypeFlags.Primitive) + ) { + error( + left, + Diagnostics + .The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter, + ); } // NOTE: do not raise error if right is unknown as related error was already reported - if (!(isTypeAny(rightType) || typeHasCallOrConstructSignatures(rightType) || isTypeSubtypeOf(rightType, globalFunctionType))) { - error(right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); + if ( + !(isTypeAny(rightType) || typeHasCallOrConstructSignatures(rightType) + || isTypeSubtypeOf(rightType, globalFunctionType)) + ) { + error( + right, + Diagnostics + .The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type, + ); } return booleanType; } function hasEmptyObjectIntersection(type: Type): boolean { - return someType(type, t => t === unknownEmptyObjectType || !!(t.flags & TypeFlags.Intersection) && isEmptyAnonymousObjectType(getBaseConstraintOrType(t))); + return someType( + type, + t => t === unknownEmptyObjectType + || !!(t.flags & TypeFlags.Intersection) && isEmptyAnonymousObjectType(getBaseConstraintOrType(t)), + ); } function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type { @@ -36568,14 +47280,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // that include {} (we know that the other types in such intersections are assignable to object // since we already checked for that). if (hasEmptyObjectIntersection(rightType)) { - error(right, Diagnostics.Type_0_may_represent_a_primitive_value_which_is_not_permitted_as_the_right_operand_of_the_in_operator, typeToString(rightType)); + error( + right, + Diagnostics + .Type_0_may_represent_a_primitive_value_which_is_not_permitted_as_the_right_operand_of_the_in_operator, + typeToString(rightType), + ); } } // The result is always of the Boolean primitive type. return booleanType; } - function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, rightIsThis?: boolean): Type { + function checkObjectLiteralAssignment( + node: ObjectLiteralExpression, + sourceType: Type, + rightIsThis?: boolean, + ): Type { const properties = node.properties; if (strictNullChecks && properties.length === 0) { return checkNonNullType(sourceType, node); @@ -36587,10 +47308,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** Note: If property cannot be a SpreadAssignment, then allProperties does not need to be provided */ - function checkObjectLiteralDestructuringPropertyAssignment(node: ObjectLiteralExpression, objectLiteralType: Type, propertyIndex: number, allProperties?: NodeArray, rightIsThis = false) { + function checkObjectLiteralDestructuringPropertyAssignment( + node: ObjectLiteralExpression, + objectLiteralType: Type, + propertyIndex: number, + allProperties?: NodeArray, + rightIsThis = false, + ) { const properties = node.properties; const property = properties[propertyIndex]; - if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) { + if ( + property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment + ) { const name = property.name; const exprType = getLiteralTypeFromPropertyName(name); if (isTypeUsableAsPropertyName(exprType)) { @@ -36603,7 +47332,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const elementType = getIndexedAccessType(objectLiteralType, exprType, AccessFlags.ExpressionPosition, name); const type = getFlowTypeOfDestructuring(property, elementType); - return checkDestructuringAssignment(property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, type); + return checkDestructuringAssignment( + property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, + type, + ); } else if (property.kind === SyntaxKind.SpreadAssignment) { if (propertyIndex < properties.length - 1) { @@ -36622,7 +47354,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } const type = getRestType(objectLiteralType, nonRestNames, objectLiteralType.symbol); - checkGrammarForDisallowedTrailingComma(allProperties, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + allProperties, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, + ); return checkDestructuringAssignment(property.expression, type); } } @@ -36639,20 +47374,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This elementType will be used if the specific property corresponding to this index is not // present (aka the tuple element property). This call also checks that the parentType is in // fact an iterable or array (depending on target language). - const possiblyOutOfBoundsType = checkIteratedTypeOrElementType(IterationUse.Destructuring | IterationUse.PossiblyOutOfBounds, sourceType, undefinedType, node) || errorType; - let inBoundsType: Type | undefined = compilerOptions.noUncheckedIndexedAccess ? undefined: possiblyOutOfBoundsType; + const possiblyOutOfBoundsType = checkIteratedTypeOrElementType( + IterationUse.Destructuring | IterationUse.PossiblyOutOfBounds, + sourceType, + undefinedType, + node, + ) || errorType; + let inBoundsType: Type | undefined = compilerOptions.noUncheckedIndexedAccess ? undefined + : possiblyOutOfBoundsType; for (let i = 0; i < elements.length; i++) { let type = possiblyOutOfBoundsType; if (node.elements[i].kind === SyntaxKind.SpreadElement) { - type = inBoundsType = inBoundsType ?? (checkIteratedTypeOrElementType(IterationUse.Destructuring, sourceType, undefinedType, node) || errorType); + type = inBoundsType = inBoundsType + ?? (checkIteratedTypeOrElementType(IterationUse.Destructuring, sourceType, undefinedType, node) + || errorType); } checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, type, checkMode); } return sourceType; } - function checkArrayLiteralDestructuringElementAssignment(node: ArrayLiteralExpression, sourceType: Type, - elementIndex: number, elementType: Type, checkMode?: CheckMode) { + function checkArrayLiteralDestructuringElementAssignment( + node: ArrayLiteralExpression, + sourceType: Type, + elementIndex: number, + elementType: Type, + checkMode?: CheckMode, + ) { const elements = node.elements; const element = elements[elementIndex]; if (element.kind !== SyntaxKind.OmittedExpression) { @@ -36661,9 +47409,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isArrayLikeType(sourceType)) { // We create a synthetic expression so that getIndexedAccessType doesn't get confused // when the element is a SyntaxKind.ElementAccessExpression. - const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(element) ? AccessFlags.NoTupleBoundsCheck : 0); - const elementType = getIndexedAccessTypeOrUndefined(sourceType, indexType, accessFlags, createSyntheticExpression(element, indexType)) || errorType; - const assignedType = hasDefaultValue(element) ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) : elementType; + const accessFlags = AccessFlags.ExpressionPosition + | (hasDefaultValue(element) ? AccessFlags.NoTupleBoundsCheck : 0); + const elementType = getIndexedAccessTypeOrUndefined( + sourceType, + indexType, + accessFlags, + createSyntheticExpression(element, indexType), + ) || errorType; + const assignedType = hasDefaultValue(element) ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) + : elementType; const type = getFlowTypeOfDestructuring(element, assignedType); return checkDestructuringAssignment(element, type, checkMode); } @@ -36674,14 +47429,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { const restExpression = (element as SpreadElement).expression; - if (restExpression.kind === SyntaxKind.BinaryExpression && (restExpression as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { - error((restExpression as BinaryExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); + if ( + restExpression.kind === SyntaxKind.BinaryExpression + && (restExpression as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { + error( + (restExpression as BinaryExpression).operatorToken, + Diagnostics.A_rest_element_cannot_have_an_initializer, + ); } else { - checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); - const type = everyType(sourceType, isTupleType) ? - mapType(sourceType, t => sliceTupleType(t as TupleTypeReference, elementIndex)) : - createArrayType(elementType); + checkGrammarForDisallowedTrailingComma( + node.elements, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, + ); + const type = everyType(sourceType, isTupleType) + ? mapType(sourceType, t => sliceTupleType(t as TupleTypeReference, elementIndex)) + : createArrayType(elementType); return checkDestructuringAssignment(restExpression, type, checkMode); } } @@ -36689,15 +47453,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, checkMode?: CheckMode, rightIsThis?: boolean): Type { + function checkDestructuringAssignment( + exprOrAssignment: Expression | ShorthandPropertyAssignment, + sourceType: Type, + checkMode?: CheckMode, + rightIsThis?: boolean, + ): Type { let target: Expression; if (exprOrAssignment.kind === SyntaxKind.ShorthandPropertyAssignment) { const prop = exprOrAssignment as ShorthandPropertyAssignment; if (prop.objectAssignmentInitializer) { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. - if (strictNullChecks && - !(getTypeFacts(checkExpression(prop.objectAssignmentInitializer)) & TypeFacts.IsUndefined)) { + if ( + strictNullChecks + && !(getTypeFacts(checkExpression(prop.objectAssignmentInitializer)) & TypeFacts.IsUndefined) + ) { sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); } checkBinaryLikeExpression(prop.name, prop.equalsToken!, prop.objectAssignmentInitializer, checkMode); @@ -36708,7 +47479,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { target = exprOrAssignment; } - if (target.kind === SyntaxKind.BinaryExpression && (target as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + target.kind === SyntaxKind.BinaryExpression + && (target as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { checkBinaryExpression(target as BinaryExpression, checkMode); target = (target as BinaryExpression).left; // A default value is specified, so remove undefined from the final type. @@ -36727,12 +47501,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkReferenceAssignment(target: Expression, sourceType: Type, checkMode?: CheckMode): Type { const targetType = checkExpression(target, checkMode); - const error = target.parent.kind === SyntaxKind.SpreadAssignment ? - Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access : - Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access; - const optionalError = target.parent.kind === SyntaxKind.SpreadAssignment ? - Diagnostics.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access : - Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access; + const error = target.parent.kind === SyntaxKind.SpreadAssignment + ? Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access + : Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access; + const optionalError = target.parent.kind === SyntaxKind.SpreadAssignment + ? Diagnostics.The_target_of_an_object_rest_assignment_may_not_be_an_optional_property_access + : Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access; if (checkReferenceExpression(target, error, optionalError)) { checkTypeAssignableToAndOptionallyElaborate(sourceType, targetType, target, target); } @@ -36777,15 +47551,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; case SyntaxKind.ConditionalExpression: - return isSideEffectFree((node as ConditionalExpression).whenTrue) && - isSideEffectFree((node as ConditionalExpression).whenFalse); + return isSideEffectFree((node as ConditionalExpression).whenTrue) + && isSideEffectFree((node as ConditionalExpression).whenFalse); case SyntaxKind.BinaryExpression: if (isAssignmentOperator((node as BinaryExpression).operatorToken.kind)) { return false; } - return isSideEffectFree((node as BinaryExpression).left) && - isSideEffectFree((node as BinaryExpression).right); + return isSideEffectFree((node as BinaryExpression).left) + && isSideEffectFree((node as BinaryExpression).right); case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: @@ -36859,9 +47633,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkGrammarNullishCoalesceWithLogicalExpression(node); const operator = node.operatorToken.kind; - if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { + if ( + operator === SyntaxKind.EqualsToken + && (node.left.kind === SyntaxKind.ObjectLiteralExpression + || node.left.kind === SyntaxKind.ArrayLiteralExpression) + ) { state.skip = true; - setLastResult(state, checkDestructuringAssignment(node.left, checkExpression(node.right, checkMode), checkMode, node.right.kind === SyntaxKind.ThisKeyword)); + setLastResult( + state, + checkDestructuringAssignment( + node.left, + checkExpression(node.right, checkMode), + checkMode, + node.right.kind === SyntaxKind.ThisKeyword, + ), + ); return state; } @@ -36883,11 +47669,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const operator = operatorToken.kind; if (isLogicalOrCoalescingBinaryOperator(operator)) { let parent = node.parent; - while (parent.kind === SyntaxKind.ParenthesizedExpression || isLogicalOrCoalescingBinaryExpression(parent)) { + while ( + parent.kind === SyntaxKind.ParenthesizedExpression + || isLogicalOrCoalescingBinaryExpression(parent) + ) { parent = parent.parent; } if (operator === SyntaxKind.AmpersandAmpersandToken || isIfStatement(parent)) { - checkTestingKnownTruthyCallableOrAwaitableType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined); + checkTestingKnownTruthyCallableOrAwaitableType( + node.left, + leftType, + isIfStatement(parent) ? parent.thenStatement : undefined, + ); } checkTruthinessOfType(leftType, node.left); } @@ -36912,7 +47705,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const rightType = getLastResult(state); Debug.assertIsDefined(rightType); - result = checkBinaryLikeExpressionWorker(node.left, node.operatorToken, node.right, leftType, rightType, state.checkMode, node); + result = checkBinaryLikeExpressionWorker( + node.left, + node.operatorToken, + node.right, + leftType, + rightType, + state.checkMode, + node, + ); } state.skip = false; @@ -36958,21 +47759,53 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarNullishCoalesceWithLogicalExpression(node: BinaryExpression) { const { left, operatorToken, right } = node; if (operatorToken.kind === SyntaxKind.QuestionQuestionToken) { - if (isBinaryExpression(left) && (left.operatorToken.kind === SyntaxKind.BarBarToken || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) { - grammarErrorOnNode(left, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(left.operatorToken.kind), tokenToString(operatorToken.kind)); + if ( + isBinaryExpression(left) + && (left.operatorToken.kind === SyntaxKind.BarBarToken + || left.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) + ) { + grammarErrorOnNode( + left, + Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, + tokenToString(left.operatorToken.kind), + tokenToString(operatorToken.kind), + ); } - if (isBinaryExpression(right) && (right.operatorToken.kind === SyntaxKind.BarBarToken || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken)) { - grammarErrorOnNode(right, Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, tokenToString(right.operatorToken.kind), tokenToString(operatorToken.kind)); + if ( + isBinaryExpression(right) + && (right.operatorToken.kind === SyntaxKind.BarBarToken + || right.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) + ) { + grammarErrorOnNode( + right, + Diagnostics._0_and_1_operations_cannot_be_mixed_without_parentheses, + tokenToString(right.operatorToken.kind), + tokenToString(operatorToken.kind), + ); } } } // Note that this and `checkBinaryExpression` above should behave mostly the same, except this elides some // expression-wide checks and does not use a work stack to fold nested binary expressions into the same callstack frame - function checkBinaryLikeExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, checkMode?: CheckMode, errorNode?: Node): Type { + function checkBinaryLikeExpression( + left: Expression, + operatorToken: BinaryOperatorToken, + right: Expression, + checkMode?: CheckMode, + errorNode?: Node, + ): Type { const operator = operatorToken.kind; - if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) { - return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode, right.kind === SyntaxKind.ThisKeyword); + if ( + operator === SyntaxKind.EqualsToken + && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression) + ) { + return checkDestructuringAssignment( + left, + checkExpression(right, checkMode), + checkMode, + right.kind === SyntaxKind.ThisKeyword, + ); } let leftType: Type; if (isLogicalOrCoalescingBinaryOperator(operator)) { @@ -36993,7 +47826,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { leftType: Type, rightType: Type, checkMode?: CheckMode, - errorNode?: Node + errorNode?: Node, ): Type { const operator = operatorToken.kind; switch (operator) { @@ -37029,21 +47862,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let suggestedOperator: PunctuationSyntaxKind | undefined; // if a user tries to apply a bitwise operator to 2 boolean operands // try and return them a helpful suggestion - if ((leftType.flags & TypeFlags.BooleanLike) && - (rightType.flags & TypeFlags.BooleanLike) && - (suggestedOperator = getSuggestedBooleanOperator(operatorToken.kind)) !== undefined) { - error(errorNode || operatorToken, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(operatorToken.kind), tokenToString(suggestedOperator)); + if ( + (leftType.flags & TypeFlags.BooleanLike) + && (rightType.flags & TypeFlags.BooleanLike) + && (suggestedOperator = getSuggestedBooleanOperator(operatorToken.kind)) !== undefined + ) { + error( + errorNode || operatorToken, + Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, + tokenToString(operatorToken.kind), + tokenToString(suggestedOperator), + ); return numberType; } else { // otherwise just check each operand separately and report errors as normal - const leftOk = checkArithmeticOperandType(left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true); - const rightOk = checkArithmeticOperandType(right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, /*isAwaitValid*/ true); + const leftOk = checkArithmeticOperandType( + left, + leftType, + Diagnostics + .The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, + /*isAwaitValid*/ true, + ); + const rightOk = checkArithmeticOperandType( + right, + rightType, + Diagnostics + .The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_bigint_or_an_enum_type, + /*isAwaitValid*/ true, + ); let resultType: Type; // If both are any or unknown, allow operation; assume it will resolve to number - if ((isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) || + if ( + (isTypeAssignableToKind(leftType, TypeFlags.AnyOrUnknown) + && isTypeAssignableToKind(rightType, TypeFlags.AnyOrUnknown)) // Or, if neither could be bigint, implicit coercion results in a number result - !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) || maybeTypeOfKind(rightType, TypeFlags.BigIntLike)) + || !(maybeTypeOfKind(leftType, TypeFlags.BigIntLike) + || maybeTypeOfKind(rightType, TypeFlags.BigIntLike)) ) { resultType = numberType; } @@ -37057,7 +47912,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.AsteriskAsteriskToken: case SyntaxKind.AsteriskAsteriskEqualsToken: if (languageVersion < ScriptTarget.ES2016) { - error(errorNode, Diagnostics.Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later); + error( + errorNode, + Diagnostics + .Exponentiation_cannot_be_performed_on_bigint_values_unless_the_target_option_is_set_to_es2016_or_later, + ); } } resultType = bigintType; @@ -37078,22 +47937,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return silentNeverType; } - if (!isTypeAssignableToKind(leftType, TypeFlags.StringLike) && !isTypeAssignableToKind(rightType, TypeFlags.StringLike)) { + if ( + !isTypeAssignableToKind(leftType, TypeFlags.StringLike) + && !isTypeAssignableToKind(rightType, TypeFlags.StringLike) + ) { leftType = checkNonNullType(leftType, left); rightType = checkNonNullType(rightType, right); } let resultType: Type | undefined; - if (isTypeAssignableToKind(leftType, TypeFlags.NumberLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.NumberLike, /*strict*/ true)) { + if ( + isTypeAssignableToKind(leftType, TypeFlags.NumberLike, /*strict*/ true) + && isTypeAssignableToKind(rightType, TypeFlags.NumberLike, /*strict*/ true) + ) { // Operands of an enum type are treated as having the primitive type Number. // If both operands are of the Number primitive type, the result is of the Number primitive type. resultType = numberType; } - else if (isTypeAssignableToKind(leftType, TypeFlags.BigIntLike, /*strict*/ true) && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike, /*strict*/ true)) { + else if ( + isTypeAssignableToKind(leftType, TypeFlags.BigIntLike, /*strict*/ true) + && isTypeAssignableToKind(rightType, TypeFlags.BigIntLike, /*strict*/ true) + ) { // If both operands are of the BigInt primitive type, the result is of the BigInt primitive type. resultType = bigintType; } - else if (isTypeAssignableToKind(leftType, TypeFlags.StringLike, /*strict*/ true) || isTypeAssignableToKind(rightType, TypeFlags.StringLike, /*strict*/ true)) { + else if ( + isTypeAssignableToKind(leftType, TypeFlags.StringLike, /*strict*/ true) + || isTypeAssignableToKind(rightType, TypeFlags.StringLike, /*strict*/ true) + ) { // If one or both operands are of the String primitive type, the result is of the String primitive type. resultType = stringType; } @@ -37113,10 +47984,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If both types have an awaited type of one of these, we'll assume the user // might be missing an await without doing an exhaustive check that inserting // await(s) will actually be a completely valid binary expression. - const closeEnoughKind = TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.AnyOrUnknown; + const closeEnoughKind = TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike + | TypeFlags.AnyOrUnknown; reportOperatorError((left, right) => - isTypeAssignableToKind(left, closeEnoughKind) && - isTypeAssignableToKind(right, closeEnoughKind)); + isTypeAssignableToKind(left, closeEnoughKind) + && isTypeAssignableToKind(right, closeEnoughKind) + ); return anyType; } @@ -37137,8 +48010,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const leftAssignableToNumber = isTypeAssignableTo(left, numberOrBigIntType); const rightAssignableToNumber = isTypeAssignableTo(right, numberOrBigIntType); - return leftAssignableToNumber && rightAssignableToNumber || - !leftAssignableToNumber && !rightAssignableToNumber && areTypesComparable(left, right); + return leftAssignableToNumber && rightAssignableToNumber + || !leftAssignableToNumber && !rightAssignableToNumber && areTypesComparable(left, right); }); } return booleanType; @@ -37151,15 +48024,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // types may cause the operands to not be comparable. We don't want such errors reported (see #46475). if (!(checkMode && checkMode & CheckMode.TypeOnly)) { if ( - (isLiteralExpressionOfObject(left) || isLiteralExpressionOfObject(right)) && + (isLiteralExpressionOfObject(left) || isLiteralExpressionOfObject(right)) // only report for === and !== in JS, not == or != - (!isInJSFile(left) || (operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken)) + && (!isInJSFile(left) + || (operator === SyntaxKind.EqualsEqualsEqualsToken + || operator === SyntaxKind.ExclamationEqualsEqualsToken)) ) { - const eqType = operator === SyntaxKind.EqualsEqualsToken || operator === SyntaxKind.EqualsEqualsEqualsToken; - error(errorNode, Diagnostics.This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, eqType ? "false" : "true"); + const eqType = operator === SyntaxKind.EqualsEqualsToken + || operator === SyntaxKind.EqualsEqualsEqualsToken; + error( + errorNode, + Diagnostics + .This_condition_will_always_return_0_since_JavaScript_compares_objects_by_reference_not_value, + eqType ? "false" : "true", + ); } checkNaNEquality(errorNode, operator, left, right); - reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left)); + reportOperatorErrorUnless((left, right) => + isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left) + ); } return booleanType; case SyntaxKind.InstanceOfKeyword: @@ -37168,9 +48051,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkInExpression(left, right, leftType, rightType); case SyntaxKind.AmpersandAmpersandToken: case SyntaxKind.AmpersandAmpersandEqualsToken: { - const resultType = getTypeFacts(leftType) & TypeFacts.Truthy ? - getUnionType([extractDefinitelyFalsyTypes(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType)), rightType]) : - leftType; + const resultType = getTypeFacts(leftType) & TypeFacts.Truthy + ? getUnionType([ + extractDefinitelyFalsyTypes(strictNullChecks ? leftType : getBaseTypeOfLiteralType(rightType)), + rightType, + ]) + : leftType; if (operator === SyntaxKind.AmpersandAmpersandEqualsToken) { checkAssignmentOperator(rightType); } @@ -37178,9 +48064,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } case SyntaxKind.BarBarToken: case SyntaxKind.BarBarEqualsToken: { - const resultType = getTypeFacts(leftType) & TypeFacts.Falsy ? - getUnionType([getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], UnionReduction.Subtype) : - leftType; + const resultType = getTypeFacts(leftType) & TypeFacts.Falsy + ? getUnionType( + [getNonNullableType(removeDefinitelyFalsyTypes(leftType)), rightType], + UnionReduction.Subtype, + ) + : leftType; if (operator === SyntaxKind.BarBarEqualsToken) { checkAssignmentOperator(rightType); } @@ -37188,24 +48077,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } case SyntaxKind.QuestionQuestionToken: case SyntaxKind.QuestionQuestionEqualsToken: { - const resultType = getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ? - getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) : - leftType; + const resultType = getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull + ? getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) + : leftType; if (operator === SyntaxKind.QuestionQuestionEqualsToken) { checkAssignmentOperator(rightType); } return resultType; } case SyntaxKind.EqualsToken: - const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None; + const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) + : AssignmentDeclarationKind.None; checkAssignmentDeclaration(declKind, rightType); if (isAssignmentDeclaration(declKind)) { - if (!(rightType.flags & TypeFlags.Object) || - declKind !== AssignmentDeclarationKind.ModuleExports && - declKind !== AssignmentDeclarationKind.Prototype && - !isEmptyObjectType(rightType) && - !isFunctionObjectType(rightType as ObjectType) && - !(getObjectFlags(rightType) & ObjectFlags.Class)) { + if ( + !(rightType.flags & TypeFlags.Object) + || declKind !== AssignmentDeclarationKind.ModuleExports + && declKind !== AssignmentDeclarationKind.Prototype + && !isEmptyObjectType(rightType) + && !isFunctionObjectType(rightType as ObjectType) + && !(getObjectFlags(rightType) & ObjectFlags.Class) + ) { // don't check assignability of module.exports=, C.prototype=, or expando types because they will necessarily be incomplete checkAssignmentOperator(rightType); } @@ -37216,7 +48108,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return rightType; } case SyntaxKind.CommaToken: - if (!compilerOptions.allowUnreachableCode && isSideEffectFree(left) && !isIndirectCall(left.parent as BinaryExpression)) { + if ( + !compilerOptions.allowUnreachableCode && isSideEffectFree(left) + && !isIndirectCall(left.parent as BinaryExpression) + ) { const sf = getSourceFileOfNode(left); const sourceText = sf.text; const start = skipTrivia(sourceText, left.pos); @@ -37224,7 +48119,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (diag.code !== Diagnostics.JSX_expressions_must_have_one_parent_element.code) return false; return textSpanContainsPosition(diag, start); }); - if (!isInDiag2657) error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects); + if (!isInDiag2657) { + error(left, Diagnostics.Left_side_of_comma_operator_is_unused_and_has_no_side_effects); + } } return rightType; @@ -37233,7 +48130,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function bothAreBigIntLike(left: Type, right: Type): boolean { - return isTypeAssignableToKind(left, TypeFlags.BigIntLike) && isTypeAssignableToKind(right, TypeFlags.BigIntLike); + return isTypeAssignableToKind(left, TypeFlags.BigIntLike) + && isTypeAssignableToKind(right, TypeFlags.BigIntLike); } function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, rightType: Type) { @@ -37242,10 +48140,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const propType = getTypeOfSymbol(prop); if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) { const name = prop.escapedName; - const symbol = resolveName(prop.valueDeclaration, name, SymbolFlags.Type, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ false); + const symbol = resolveName( + prop.valueDeclaration, + name, + SymbolFlags.Type, + /*nameNotFoundMessage*/ undefined, + name, + /*isUse*/ false, + ); if (symbol?.declarations && symbol.declarations.some(isJSDocTypedefTag)) { - addDuplicateDeclarationErrorsForSymbols(symbol, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name), prop); - addDuplicateDeclarationErrorsForSymbols(prop, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name), symbol); + addDuplicateDeclarationErrorsForSymbols( + symbol, + Diagnostics.Duplicate_identifier_0, + unescapeLeadingUnderscores(name), + prop, + ); + addDuplicateDeclarationErrorsForSymbols( + prop, + Diagnostics.Duplicate_identifier_0, + unescapeLeadingUnderscores(name), + symbol, + ); } } } @@ -37254,23 +48169,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Return true for "indirect calls", (i.e. `(0, x.f)(...)` or `(0, eval)(...)`), which prevents passing `this`. function isIndirectCall(node: BinaryExpression): boolean { - return node.parent.kind === SyntaxKind.ParenthesizedExpression && - isNumericLiteral(node.left) && - node.left.text === "0" && - (isCallExpression(node.parent.parent) && node.parent.parent.expression === node.parent || node.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) && + return node.parent.kind === SyntaxKind.ParenthesizedExpression + && isNumericLiteral(node.left) + && node.left.text === "0" + && (isCallExpression(node.parent.parent) && node.parent.parent.expression === node.parent + || node.parent.parent.kind === SyntaxKind.TaggedTemplateExpression) // special-case for "eval" because it's the only non-access case where an indirect call actually affects behavior. - (isAccessExpression(node.right) || isIdentifier(node.right) && node.right.escapedText === "eval"); + && (isAccessExpression(node.right) || isIdentifier(node.right) && node.right.escapedText === "eval"); } // Return true if there was no error, false if there was an error. function checkForDisallowedESSymbolOperand(operator: PunctuationSyntaxKind): boolean { - const offendingSymbolOperand = - maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) ? left : - maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right : - undefined; + const offendingSymbolOperand = maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) + ? left + : maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right + : undefined; if (offendingSymbolOperand) { - error(offendingSymbolOperand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(operator)); + error( + offendingSymbolOperand, + Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, + tokenToString(operator), + ); return false; } @@ -37303,7 +48223,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // getters can be a subtype of setters, so to check for assignability we use the setter's type instead if (isCompoundAssignment(operatorToken.kind) && left.kind === SyntaxKind.PropertyAccessExpression) { - assigneeType = checkPropertyAccessExpression(left as PropertyAccessExpression, /*checkMode*/ undefined, /*writeOnly*/ true); + assigneeType = checkPropertyAccessExpression( + left as PropertyAccessExpression, + /*checkMode*/ undefined, + /*writeOnly*/ true, + ); } // TypeScript 1.0 spec (April 2014): 4.17 @@ -37313,16 +48237,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A compound assignment furthermore requires VarExpr to be classified as a reference (section 4.1) // and the type of the non-compound operation to be assignable to the type of VarExpr. - if (checkReferenceExpression(left, - Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access, - Diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access) - ) { - + if ( + checkReferenceExpression( + left, + Diagnostics + .The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access, + Diagnostics + .The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access, + ) + ) { let headMessage: DiagnosticMessage | undefined; - if (exactOptionalPropertyTypes && isPropertyAccessExpression(left) && maybeTypeOfKind(valueType, TypeFlags.Undefined)) { - const target = getTypeOfPropertyOfType(getTypeOfExpression(left.expression), left.name.escapedText); + if ( + exactOptionalPropertyTypes && isPropertyAccessExpression(left) + && maybeTypeOfKind(valueType, TypeFlags.Undefined) + ) { + const target = getTypeOfPropertyOfType( + getTypeOfExpression(left.expression), + left.name.escapedText, + ); if (isExactOptionalPropertyMismatch(valueType, target)) { - headMessage = Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target; + headMessage = Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target; } } // to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported @@ -37342,8 +48277,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case AssignmentDeclarationKind.ThisProperty: const symbol = getSymbolOfNode(left); const init = getAssignedExpandoInitializer(right); - return !!init && isObjectLiteralExpression(init) && - !!symbol?.exports?.size; + return !!init && isObjectLiteralExpression(init) + && !!symbol?.exports?.size; default: return false; } @@ -37389,7 +48324,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function tryGiveBetterPrimaryError(errNode: Node, maybeMissingAwait: boolean, leftStr: string, rightStr: string) { + function tryGiveBetterPrimaryError( + errNode: Node, + maybeMissingAwait: boolean, + leftStr: string, + rightStr: string, + ) { switch (operatorToken.kind) { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.EqualsEqualsToken: @@ -37398,25 +48338,49 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return errorAndMaybeSuggestAwait( errNode, maybeMissingAwait, - Diagnostics.This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap, - leftStr, rightStr); + Diagnostics + .This_comparison_appears_to_be_unintentional_because_the_types_0_and_1_have_no_overlap, + leftStr, + rightStr, + ); default: return undefined; } } - function checkNaNEquality(errorNode: Node | undefined, operator: SyntaxKind, left: Expression, right: Expression) { + function checkNaNEquality( + errorNode: Node | undefined, + operator: SyntaxKind, + left: Expression, + right: Expression, + ) { const isLeftNaN = isGlobalNaN(skipParentheses(left)); const isRightNaN = isGlobalNaN(skipParentheses(right)); if (isLeftNaN || isRightNaN) { - const err = error(errorNode, Diagnostics.This_condition_will_always_return_0, - tokenToString(operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.EqualsEqualsToken ? SyntaxKind.FalseKeyword : SyntaxKind.TrueKeyword)); + const err = error( + errorNode, + Diagnostics.This_condition_will_always_return_0, + tokenToString( + operator === SyntaxKind.EqualsEqualsEqualsToken || operator === SyntaxKind.EqualsEqualsToken + ? SyntaxKind.FalseKeyword : SyntaxKind.TrueKeyword, + ), + ); if (isLeftNaN && isRightNaN) return; - const operatorString = operator === SyntaxKind.ExclamationEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken ? tokenToString(SyntaxKind.ExclamationToken) : ""; + const operatorString = operator === SyntaxKind.ExclamationEqualsEqualsToken + || operator === SyntaxKind.ExclamationEqualsToken ? tokenToString(SyntaxKind.ExclamationToken) + : ""; const location = isLeftNaN ? right : left; const expression = skipParentheses(location); - addRelatedInfo(err, createDiagnosticForNode(location, Diagnostics.Did_you_mean_0, - `${operatorString}Number.isNaN(${isEntityNameExpression(expression) ? entityNameToString(expression) : "..."})`)); + addRelatedInfo( + err, + createDiagnosticForNode( + location, + Diagnostics.Did_you_mean_0, + `${operatorString}Number.isNaN(${ + isEntityNameExpression(expression) ? entityNameToString(expression) : "..." + })`, + ), + ); } } @@ -37429,7 +48393,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getBaseTypesIfUnrelated(leftType: Type, rightType: Type, isRelated: (left: Type, right: Type) => boolean): [Type, Type] { + function getBaseTypesIfUnrelated( + leftType: Type, + rightType: Type, + isRelated: (left: Type, right: Type) => boolean, + ): [Type, Type] { let effectiveLeft = leftType; let effectiveRight = rightType; const leftBase = getBaseTypeOfLiteralType(leftType); @@ -37438,7 +48406,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { effectiveLeft = leftBase; effectiveRight = rightBase; } - return [ effectiveLeft, effectiveRight ]; + return [effectiveLeft, effectiveRight]; } function checkYieldExpression(node: YieldExpression): Type { @@ -37476,9 +48444,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const signatureNextType = iterationTypes && iterationTypes.nextType || anyType; const resolvedSignatureNextType = isAsync ? getAwaitedType(signatureNextType) || anyType : signatureNextType; const yieldExpressionType = node.expression ? checkExpression(node.expression) : undefinedWideningType; - const yieldedType = getYieldedTypeOfYieldExpression(node, yieldExpressionType, resolvedSignatureNextType, isAsync); + const yieldedType = getYieldedTypeOfYieldExpression( + node, + yieldExpressionType, + resolvedSignatureNextType, + isAsync, + ); if (returnType && yieldedType) { - checkTypeAssignableToAndOptionallyElaborate(yieldedType, signatureYieldType, node.expression || node, node.expression); + checkTypeAssignableToAndOptionallyElaborate( + yieldedType, + signatureYieldType, + node.expression || node, + node.expression, + ); } if (node.asteriskToken) { @@ -37497,7 +48475,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (noImplicitAny && !expressionResultIsUnused(node)) { const contextualType = getContextualType(node, /*contextFlags*/ undefined); if (!contextualType || isTypeAny(contextualType)) { - error(node, Diagnostics.yield_expression_implicitly_results_in_an_any_type_because_its_containing_generator_lacks_a_return_type_annotation); + error( + node, + Diagnostics + .yield_expression_implicitly_results_in_an_any_type_because_its_containing_generator_lacks_a_return_type_annotation, + ); } } }); @@ -37525,8 +48507,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isTemplateLiteralContext(node: Node): boolean { const parent = node.parent; - return isParenthesizedExpression(parent) && isTemplateLiteralContext(parent) || - isElementAccessExpression(parent) && parent.argumentExpression === node; + return isParenthesizedExpression(parent) && isTemplateLiteralContext(parent) + || isElementAccessExpression(parent) && parent.argumentExpression === node; } function checkTemplateExpression(node: TemplateExpression): Type { @@ -37535,12 +48517,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const span of node.templateSpans) { const type = checkExpression(span.expression); if (maybeTypeOfKindConsideringBaseConstraint(type, TypeFlags.ESSymbolLike)) { - error(span.expression, Diagnostics.Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String); + error( + span.expression, + Diagnostics + .Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String, + ); } texts.push(span.literal.text); types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType); } - if (isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType)) { + if ( + isConstContext(node) || isTemplateLiteralContext(node) + || someType( + getContextualType(node, /*contextFlags*/ undefined) || unknownType, + isTemplateLiteralContextualType, + ) + ) { return getTemplateLiteralType(texts, types); } const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluateTemplateExpression(node); @@ -37548,8 +48540,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTemplateLiteralContextualType(type: Type): boolean { - return !!(type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral) || - type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike)); + return !!(type.flags & (TypeFlags.StringLiteral | TypeFlags.TemplateLiteral) + || type.flags & TypeFlags.InstantiableNonPrimitive + && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.StringLike)); } function getContextNode(node: Expression): Expression { @@ -37559,11 +48552,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return node; } - function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type { + function checkExpressionWithContextualType( + node: Expression, + contextualType: Type, + inferenceContext: InferenceContext | undefined, + checkMode: CheckMode, + ): Type { const contextNode = getContextNode(node); pushContextualType(contextNode, contextualType, /*isCache*/ false); pushInferenceContext(contextNode, inferenceContext); - const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0)); + const type = checkExpression( + node, + checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0), + ); // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type // parameters. This information is no longer needed after the call to checkExpression. if (inferenceContext && inferenceContext.intraExpressionInferenceSites) { @@ -37572,8 +48573,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We strip literal freshness when an appropriate contextual type is present such that contextually typed // literals always preserve their literal types (otherwise they might widen during type inference). An alternative // here would be to not mark contextually typed literals as fresh in the first place. - const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ? - getRegularTypeOfLiteralType(type) : type; + const result = maybeTypeOfKind(type, TypeFlags.Literal) + && isLiteralOfContextualType( + type, + instantiateContextualType(contextualType, node, /*contextFlags*/ undefined), + ) + ? getRegularTypeOfLiteralType(type) : type; popInferenceContext(); popContextualType(); return result; @@ -37601,15 +48606,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isTypeAssertion(node: Expression) { node = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); - return node.kind === SyntaxKind.TypeAssertionExpression || - node.kind === SyntaxKind.AsExpression || - isJSDocTypeAssertion(node); + return node.kind === SyntaxKind.TypeAssertionExpression + || node.kind === SyntaxKind.AsExpression + || isJSDocTypeAssertion(node); } function checkDeclarationInitializer( declaration: HasExpressionInitializer, checkMode: CheckMode, - contextualType?: Type | undefined + contextualType?: Type | undefined, ) { const initializer = getEffectiveInitializer(declaration)!; if (isInJSFile(declaration)) { @@ -37618,13 +48623,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkSatisfiesExpressionWorker(initializer, typeNode, checkMode); } } - const type = getQuickTypeOfExpression(initializer) || - (contextualType ? - checkExpressionWithContextualType(initializer, contextualType, /*inferenceContext*/ undefined, checkMode || CheckMode.Normal) + const type = getQuickTypeOfExpression(initializer) + || (contextualType + ? checkExpressionWithContextualType( + initializer, + contextualType, + /*inferenceContext*/ undefined, + checkMode || CheckMode.Normal, + ) : checkExpressionCached(initializer, checkMode)); - return isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern && - isTupleType(type) && !type.target.hasRestElement && getTypeReferenceArity(type) < declaration.name.elements.length ? - padTupleType(type, declaration.name) : type; + return isParameter(declaration) && declaration.name.kind === SyntaxKind.ArrayBindingPattern + && isTupleType(type) && !type.target.hasRestElement + && getTypeReferenceArity(type) < declaration.name.elements.length + ? padTupleType(type, declaration.name) : type; } function padTupleType(type: TupleTypeReference, pattern: ArrayBindingPattern) { @@ -37634,7 +48645,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = getTypeReferenceArity(type); i < patternElements.length; i++) { const e = patternElements[i]; if (i < patternElements.length - 1 || !(e.kind === SyntaxKind.BindingElement && e.dotDotDotToken)) { - elementTypes.push(!isOmittedExpression(e) && hasDefaultValue(e) ? getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ false) : anyType); + elementTypes.push( + !isOmittedExpression(e) && hasDefaultValue(e) + ? getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ false) + : anyType, + ); elementFlags.push(ElementFlags.Optional); if (!isOmittedExpression(e) && !hasDefaultValue(e)) { reportImplicitAny(e, anyType); @@ -37645,7 +48660,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function widenTypeInferredFromInitializer(declaration: HasExpressionInitializer, type: Type) { - const widened = getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || isDeclarationReadonly(declaration) ? type : getWidenedLiteralType(type); + const widened = + getCombinedNodeFlagsCached(declaration) & NodeFlags.Constant || isDeclarationReadonly(declaration) ? type + : getWidenedLiteralType(type); if (isInJSFile(declaration)) { if (isEmptyLiteralType(widened)) { reportImplicitAny(declaration, anyType); @@ -37670,37 +48687,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // this a literal context for literals of that primitive type. For example, given a // type parameter 'T extends string', infer string literal types for T. const constraint = getBaseConstraintOfType(contextualType) || unknownType; - return maybeTypeOfKind(constraint, TypeFlags.String) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || - maybeTypeOfKind(constraint, TypeFlags.Number) && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || - maybeTypeOfKind(constraint, TypeFlags.BigInt) && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || - maybeTypeOfKind(constraint, TypeFlags.ESSymbol) && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) || - isLiteralOfContextualType(candidateType, constraint); + return maybeTypeOfKind(constraint, TypeFlags.String) + && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) + || maybeTypeOfKind(constraint, TypeFlags.Number) + && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) + || maybeTypeOfKind(constraint, TypeFlags.BigInt) + && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) + || maybeTypeOfKind(constraint, TypeFlags.ESSymbol) + && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol) + || isLiteralOfContextualType(candidateType, constraint); } // If the contextual type is a literal of a particular primitive type, we consider this a // literal context for all literals of that primitive type. - return !!(contextualType.flags & (TypeFlags.StringLiteral | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) || - contextualType.flags & TypeFlags.NumberLiteral && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) || - contextualType.flags & TypeFlags.BigIntLiteral && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) || - contextualType.flags & TypeFlags.BooleanLiteral && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) || - contextualType.flags & TypeFlags.UniqueESSymbol && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol)); + return !!(contextualType.flags + & (TypeFlags.StringLiteral | TypeFlags.Index | TypeFlags.TemplateLiteral + | TypeFlags.StringMapping) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) + || contextualType.flags & TypeFlags.NumberLiteral + && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) + || contextualType.flags & TypeFlags.BigIntLiteral + && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) + || contextualType.flags & TypeFlags.BooleanLiteral + && maybeTypeOfKind(candidateType, TypeFlags.BooleanLiteral) + || contextualType.flags & TypeFlags.UniqueESSymbol + && maybeTypeOfKind(candidateType, TypeFlags.UniqueESSymbol)); } return false; } function isConstContext(node: Expression): boolean { const parent = node.parent; - return isAssertionExpression(parent) && isConstTypeReference(parent.type) || - isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) || - isValidConstAssertionArgument(node) && isConstTypeVariable(getContextualType(node, ContextFlags.None)) || - (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) || - (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) && isConstContext(parent.parent); + return isAssertionExpression(parent) && isConstTypeReference(parent.type) + || isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) + || isValidConstAssertionArgument(node) && isConstTypeVariable(getContextualType(node, ContextFlags.None)) + || (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) + && isConstContext(parent) + || (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) + && isConstContext(parent.parent); } - function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, forceTuple?: boolean): Type { + function checkExpressionForMutableLocation( + node: Expression, + checkMode: CheckMode | undefined, + forceTuple?: boolean, + ): Type { const type = checkExpression(node, checkMode, forceTuple); - return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) : - isTypeAssertion(node) ? type : - getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(getContextualType(node, /*contextFlags*/ undefined), node, /*contextFlags*/ undefined)); + return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) + : isTypeAssertion(node) ? type + : getWidenedLiteralLikeTypeForContextualType( + type, + instantiateContextualType( + getContextualType(node, /*contextFlags*/ undefined), + node, + /*contextFlags*/ undefined, + ), + ); } function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type { @@ -37729,7 +48769,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode); } - function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName, type: Type, checkMode?: CheckMode) { + function instantiateTypeWithSingleGenericCallSignature( + node: Expression | MethodDeclaration | QualifiedName, + type: Type, + checkMode?: CheckMode, + ) { if (checkMode && checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions)) { const callSignature = getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ true); const constructSignature = getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ true); @@ -37737,7 +48781,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (signature && signature.typeParameters) { const contextualType = getApparentTypeOfContextualType(node as Expression, ContextFlags.NoConstraints); if (contextualType) { - const contextualSignature = getSingleSignature(getNonNullableType(contextualType), callSignature ? SignatureKind.Call : SignatureKind.Construct, /*allowMembers*/ false); + const contextualSignature = getSingleSignature( + getNonNullableType(contextualType), + callSignature ? SignatureKind.Call : SignatureKind.Construct, + /*allowMembers*/ false, + ); if (contextualSignature && !contextualSignature.typeParameters) { if (checkMode & CheckMode.SkipGenericFunctions) { skippedGenericFunction(node, checkMode); @@ -37752,11 +48800,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // potentially add inferred type parameters to the outer function return type. const returnType = context.signature && getReturnTypeOfSignature(context.signature); const returnSignature = returnType && getSingleCallOrConstructSignature(returnType); - if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) { + if ( + returnSignature && !returnSignature.typeParameters + && !every(context.inferences, hasInferenceCandidates) + ) { // Instantiate the signature with its own type parameters as type arguments, possibly // renaming the type parameters to ensure they have unique names. const uniqueTypeParameters = getUniqueTypeParameters(context, signature.typeParameters); - const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters); + const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments( + signature, + uniqueTypeParameters, + ); // Infer from the parameters of the instantiated signature to the parameters of the // contextual signature starting with an empty set of inference candidates. const inferences = map(context.inferences, info => createInferenceInfo(info.typeParameter)); @@ -37774,12 +48828,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // to the set of inferred type parameters for the outer function return type. if (!hasOverlappingInferences(context.inferences, inferences)) { mergeInferences(context.inferences, inferences); - context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters); + context.inferredTypeParameters = concatenate( + context.inferredTypeParameters, + uniqueTypeParameters, + ); return getOrCreateTypeFromSignature(instantiatedSignature); } } } - return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context)); + return getOrCreateTypeFromSignature( + instantiateSignatureInContextOf(signature, contextualSignature, context), + ); } } } @@ -37821,7 +48880,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getUniqueTypeParameters(context: InferenceContext, typeParameters: readonly TypeParameter[]): readonly TypeParameter[] { + function getUniqueTypeParameters( + context: InferenceContext, + typeParameters: readonly TypeParameter[], + ): readonly TypeParameter[] { const result: TypeParameter[] = []; let oldTypeParameters: TypeParameter[] | undefined; let newTypeParameters: TypeParameter[] | undefined; @@ -37855,10 +48917,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getUniqueTypeParameterName(typeParameters: readonly TypeParameter[], baseName: __String) { let len = (baseName as string).length; - while (len > 1 && (baseName as string).charCodeAt(len - 1) >= CharacterCodes._0 && (baseName as string).charCodeAt(len - 1) <= CharacterCodes._9) len--; + while ( + len > 1 && (baseName as string).charCodeAt(len - 1) >= CharacterCodes._0 + && (baseName as string).charCodeAt(len - 1) <= CharacterCodes._9 + ) len--; const s = (baseName as string).slice(0, len); for (let index = 1; true; index++) { - const augmentedName = (s + index as __String); + const augmentedName = s + index as __String; if (!hasTypeParameterByName(typeParameters, augmentedName)) { return augmentedName; } @@ -37922,9 +48987,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Optimize for the common case of a call to a function with a single non-generic call // signature where we can just fetch the return type without checking the arguments. - if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !isSymbolOrSymbolForCall(expr)) { - return isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) : - getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression)); + if ( + isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword + && !isRequireCall(expr, /*requireStringLiteralLikeArgument*/ true) && !isSymbolOrSymbolForCall(expr) + ) { + return isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) + : getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression)); } else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) { return getTypeFromTypeNode((expr as TypeAssertion).type); @@ -37954,7 +49022,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type { - tracing?.push(tracing.Phase.Check, "checkExpression", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + tracing?.push(tracing.Phase.Check, "checkExpression", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); const saveCurrentNode = currentNode; currentNode = node; instantiationCount = 0; @@ -37973,22 +49046,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - 'left' in property access // - 'object' in indexed access // - target in rhs of import statement - const ok = - (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent as PropertyAccessExpression).expression === node) || - (node.parent.kind === SyntaxKind.ElementAccessExpression && (node.parent as ElementAccessExpression).expression === node) || - ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(node as Identifier) || - (node.parent.kind === SyntaxKind.TypeQuery && (node.parent as TypeQueryNode).exprName === node)) || - (node.parent.kind === SyntaxKind.ExportSpecifier); // We allow reexporting const enums + const ok = (node.parent.kind === SyntaxKind.PropertyAccessExpression + && (node.parent as PropertyAccessExpression).expression === node) + || (node.parent.kind === SyntaxKind.ElementAccessExpression + && (node.parent as ElementAccessExpression).expression === node) + || ((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) + && isInRightSideOfImportOrExportAssignment(node as Identifier) + || (node.parent.kind === SyntaxKind.TypeQuery && (node.parent as TypeQueryNode).exprName === node)) + || (node.parent.kind === SyntaxKind.ExportSpecifier); // We allow reexporting const enums if (!ok) { - error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query); + error( + node, + Diagnostics + .const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query, + ); } if (getIsolatedModules(compilerOptions)) { Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum)); const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration; if (constEnumDeclaration.flags & NodeFlags.Ambient && !isValidTypeOnlyAliasUseSite(node)) { - error(node, Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, isolatedModulesLikeFlagName); + error( + node, + Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, + isolatedModulesLikeFlagName, + ); } } } @@ -37996,7 +49079,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type { if (hasJSDocNodes(node)) { if (isJSDocSatisfiesExpression(node)) { - return checkSatisfiesExpressionWorker(node.expression, getJSDocSatisfiesExpressionType(node), checkMode); + return checkSatisfiesExpressionWorker( + node.expression, + getJSDocSatisfiesExpressionType(node), + checkMode, + ); } if (isJSDocTypeAssertion(node)) { return checkAssertionWorker(node, checkMode); @@ -38005,7 +49092,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkExpression(node.expression, checkMode); } - function checkExpressionWorker(node: Expression | QualifiedName, checkMode: CheckMode | undefined, forceTuple?: boolean): Type { + function checkExpressionWorker( + node: Expression | QualifiedName, + checkMode: CheckMode | undefined, + forceTuple?: boolean, + ): Type { const kind = node.kind; if (cancellationToken) { // Only bother checking on a few construct kinds. We don't want to be excessively @@ -38030,9 +49121,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return nullWideningType; case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.StringLiteral: - return hasSkipDirectInferenceFlag(node) ? - wildcardType : - getFreshTypeOfLiteralType(getStringLiteralType((node as StringLiteralLike).text)); + return hasSkipDirectInferenceFlag(node) + ? wildcardType + : getFreshTypeOfLiteralType(getStringLiteralType((node as StringLiteralLike).text)); case SyntaxKind.NumericLiteral: { checkGrammarNumericLiteral(node as NumericLiteral); const value = +(node as NumericLiteral).text; @@ -38045,7 +49136,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkGrammarBigIntLiteral(node as BigIntLiteral); return getFreshTypeOfLiteralType(getBigIntLiteralType({ negative: false, - base10Value: parsePseudoBigInt((node as BigIntLiteral).text) + base10Value: parsePseudoBigInt((node as BigIntLiteral).text), })); case SyntaxKind.TrueKeyword: return trueType; @@ -38080,7 +49171,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkClassExpression(node as ClassExpression); case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - return checkFunctionExpressionOrObjectLiteralMethod(node as FunctionExpression | ArrowFunction, checkMode); + return checkFunctionExpressionOrObjectLiteralMethod( + node as FunctionExpression | ArrowFunction, + checkMode, + ); case SyntaxKind.TypeOfExpression: return checkTypeOfExpression(node as TypeOfExpression); case SyntaxKind.TypeAssertionExpression: @@ -38152,7 +49246,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constraintType = getConstraintOfTypeParameter(typeParameter); const defaultType = getDefaultFromTypeParameter(typeParameter); if (constraintType && defaultType) { - checkTypeAssignableTo(defaultType, getTypeWithThisArgument(instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), defaultType), node.default, Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + checkTypeAssignableTo( + defaultType, + getTypeWithThisArgument( + instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), + defaultType, + ), + node.default, + Diagnostics.Type_0_does_not_satisfy_the_constraint_1, + ); } checkNodeDeferred(node); addLazyDiagnostic(() => checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0)); @@ -38164,16 +49266,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const modifiers = getTypeParameterModifiers(typeParameter) & (ModifierFlags.In | ModifierFlags.Out); if (modifiers) { const symbol = getSymbolOfDeclaration(node.parent); - if (isTypeAliasDeclaration(node.parent) && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped))) { - error(node, Diagnostics.Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types); + if ( + isTypeAliasDeclaration(node.parent) + && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) + ) { + error( + node, + Diagnostics + .Variance_annotations_are_only_supported_in_type_aliases_for_object_function_constructor_and_mapped_types, + ); } else if (modifiers === ModifierFlags.In || modifiers === ModifierFlags.Out) { - tracing?.push(tracing.Phase.CheckTypes, "checkTypeParameterDeferred", { parent: getTypeId(getDeclaredTypeOfSymbol(symbol)), id: getTypeId(typeParameter) }); - const source = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSubTypeForCheck : markerSuperTypeForCheck); - const target = createMarkerType(symbol, typeParameter, modifiers === ModifierFlags.Out ? markerSuperTypeForCheck : markerSubTypeForCheck); + tracing?.push(tracing.Phase.CheckTypes, "checkTypeParameterDeferred", { + parent: getTypeId(getDeclaredTypeOfSymbol(symbol)), + id: getTypeId(typeParameter), + }); + const source = createMarkerType( + symbol, + typeParameter, + modifiers === ModifierFlags.Out ? markerSubTypeForCheck : markerSuperTypeForCheck, + ); + const target = createMarkerType( + symbol, + typeParameter, + modifiers === ModifierFlags.Out ? markerSuperTypeForCheck : markerSubTypeForCheck, + ); const saveVarianceTypeParameter = typeParameter; varianceTypeParameter = typeParameter; - checkTypeAssignableTo(source, target, node, Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation); + checkTypeAssignableTo( + source, + target, + node, + Diagnostics.Type_0_is_not_assignable_to_type_1_as_implied_by_variance_annotation, + ); varianceTypeParameter = saveVarianceTypeParameter; tracing?.pop(); } @@ -38194,18 +49319,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); } - if (func.kind === SyntaxKind.Constructor && isIdentifier(node.name) && node.name.escapedText === "constructor") { + if ( + func.kind === SyntaxKind.Constructor && isIdentifier(node.name) + && node.name.escapedText === "constructor" + ) { error(node.name, Diagnostics.constructor_cannot_be_used_as_a_parameter_property_name); } } - if (!node.initializer && isOptionalDeclaration(node) && isBindingPattern(node.name) && (func as FunctionLikeDeclaration).body) { + if ( + !node.initializer && isOptionalDeclaration(node) && isBindingPattern(node.name) + && (func as FunctionLikeDeclaration).body + ) { error(node, Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature); } - if (node.name && isIdentifier(node.name) && (node.name.escapedText === "this" || node.name.escapedText === "new")) { + if ( + node.name && isIdentifier(node.name) + && (node.name.escapedText === "this" || node.name.escapedText === "new") + ) { if (func.parameters.indexOf(node) !== 0) { error(node, Diagnostics.A_0_parameter_must_be_the_first_parameter, node.name.escapedText as string); } - if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) { + if ( + func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature + || func.kind === SyntaxKind.ConstructorType + ) { error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter); } if (func.kind === SyntaxKind.ArrowFunction) { @@ -38218,7 +49355,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Only check rest parameter type if it's not a binding pattern. Since binding patterns are // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. - if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType)) { + if ( + node.dotDotDotToken && !isBindingPattern(node.name) + && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType) + ) { error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); } } @@ -38245,25 +49385,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { if (typePredicate.parameterIndex >= 0) { - if (signatureHasRestParameter(signature) && typePredicate.parameterIndex === signature.parameters.length - 1) { + if ( + signatureHasRestParameter(signature) + && typePredicate.parameterIndex === signature.parameters.length - 1 + ) { error(parameterName, Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); } else { if (typePredicate.type) { - const leadingError = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type); - checkTypeAssignableTo(typePredicate.type, + const leadingError = () => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.A_type_predicate_s_type_must_be_assignable_to_its_parameter_s_type, + ); + checkTypeAssignableTo( + typePredicate.type, getTypeOfSymbol(signature.parameters[typePredicate.parameterIndex]), node.type, /*headMessage*/ undefined, - leadingError); + leadingError, + ); } } } else if (parameterName) { let hasReportedError = false; for (const { name } of parent.parameters) { - if (isBindingPattern(name) && - checkIfTypePredicateVariableIsDeclaredInBindingPattern(name, parameterName, typePredicate.parameterName)) { + if ( + isBindingPattern(name) + && checkIfTypePredicateVariableIsDeclaredInBindingPattern( + name, + parameterName, + typePredicate.parameterName, + ) + ) { hasReportedError = true; break; } @@ -38294,7 +49449,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkIfTypePredicateVariableIsDeclaredInBindingPattern( pattern: BindingPattern, predicateVariableNode: Node, - predicateVariableName: string) { + predicateVariableName: string, + ) { for (const element of pattern.elements) { if (isOmittedExpression(element)) { continue; @@ -38302,16 +49458,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const name = element.name; if (name.kind === SyntaxKind.Identifier && name.escapedText === predicateVariableName) { - error(predicateVariableNode, + error( + predicateVariableNode, Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, - predicateVariableName); + predicateVariableName, + ); return true; } else if (name.kind === SyntaxKind.ArrayBindingPattern || name.kind === SyntaxKind.ObjectBindingPattern) { - if (checkIfTypePredicateVariableIsDeclaredInBindingPattern( - name, - predicateVariableNode, - predicateVariableName)) { + if ( + checkIfTypePredicateVariableIsDeclaredInBindingPattern( + name, + predicateVariableNode, + predicateVariableName, + ) + ) { return true; } } @@ -38324,27 +49485,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkGrammarIndexSignature(node); } // TODO (yuisu): Remove this check in else-if when SyntaxKind.Construct is moved and ambient context is handled - else if (node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.ConstructorType || - node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor || - node.kind === SyntaxKind.ConstructSignature) { + else if ( + node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.FunctionDeclaration + || node.kind === SyntaxKind.ConstructorType + || node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.Constructor + || node.kind === SyntaxKind.ConstructSignature + ) { checkGrammarFunctionLikeDeclaration(node as FunctionLikeDeclaration); } const functionFlags = getFunctionFlags(node as FunctionLikeDeclaration); if (!(functionFlags & FunctionFlags.Invalid)) { // Async generators prior to ESNext require the __await and __asyncGenerator helpers - if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator && languageVersion < ScriptTarget.ESNext) { + if ( + (functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator + && languageVersion < ScriptTarget.ESNext + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncGeneratorIncludes); } // Async functions prior to ES2017 require the __awaiter helper - if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async && languageVersion < ScriptTarget.ES2017) { + if ( + (functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async + && languageVersion < ScriptTarget.ES2017 + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Awaiter); } // Generator functions, Async functions, and Async Generator functions prior to // ES2015 require the __generator helper - if ((functionFlags & FunctionFlags.AsyncGenerator) !== FunctionFlags.Normal && languageVersion < ScriptTarget.ES2015) { + if ( + (functionFlags & FunctionFlags.AsyncGenerator) !== FunctionFlags.Normal + && languageVersion < ScriptTarget.ES2015 + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Generator); } } @@ -38381,10 +49554,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (noImplicitAny && !returnTypeNode) { switch (node.kind) { case SyntaxKind.ConstructSignature: - error(node, Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + error( + node, + Diagnostics + .Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type, + ); break; case SyntaxKind.CallSignature: - error(node, Diagnostics.Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); + error( + node, + Diagnostics + .Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type, + ); break; } } @@ -38403,15 +49584,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // interface BadGenerator extends Iterable, Iterator { } // function* g(): BadGenerator { } // Iterable and Iterator have different types! // - const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, returnType, (functionFlags & FunctionFlags.Async) !== 0) || anyType; - const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, (functionFlags & FunctionFlags.Async) !== 0) || generatorYieldType; - const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, returnType, (functionFlags & FunctionFlags.Async) !== 0) || unknownType; - const generatorInstantiation = createGeneratorReturnType(generatorYieldType, generatorReturnType, generatorNextType, !!(functionFlags & FunctionFlags.Async)); + const generatorYieldType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Yield, + returnType, + (functionFlags & FunctionFlags.Async) !== 0, + ) || anyType; + const generatorReturnType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + returnType, + (functionFlags & FunctionFlags.Async) !== 0, + ) || generatorYieldType; + const generatorNextType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Next, + returnType, + (functionFlags & FunctionFlags.Async) !== 0, + ) || unknownType; + const generatorInstantiation = createGeneratorReturnType( + generatorYieldType, + generatorReturnType, + generatorNextType, + !!(functionFlags & FunctionFlags.Async), + ); checkTypeAssignableTo(generatorInstantiation, returnType, returnTypeErrorLocation); } } else if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { - checkAsyncFunctionReturnType(node as FunctionLikeDeclaration, returnTypeNode, returnTypeErrorLocation); + checkAsyncFunctionReturnType( + node as FunctionLikeDeclaration, + returnTypeNode, + returnTypeErrorLocation, + ); } } if (node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.JSDocFunctionType) { @@ -38441,10 +49643,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const isPrivate = isPrivateIdentifier(name); const privateStaticFlags = isPrivate && isStaticMember ? DeclarationMeaning.PrivateStatic : 0; - const names = - isPrivate ? privateIdentifiers : - isStaticMember ? staticNames : - instanceNames; + const names = isPrivate ? privateIdentifiers + : isStaticMember ? staticNames + : instanceNames; const memberName = name && getPropertyNameForPropertyNameNode(name); if (memberName) { @@ -38469,12 +49670,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function addName(names: Map<__String, DeclarationMeaning>, location: Node, name: __String, meaning: DeclarationMeaning) { + function addName( + names: Map<__String, DeclarationMeaning>, + location: Node, + name: __String, + meaning: DeclarationMeaning, + ) { const prev = names.get(name); if (prev) { // For private identifiers, do not allow mixing of static and instance members with the same name if ((prev & DeclarationMeaning.PrivateStatic) !== (meaning & DeclarationMeaning.PrivateStatic)) { - error(location, Diagnostics.Duplicate_identifier_0_Static_and_instance_elements_cannot_share_the_same_private_name, getTextOfNode(location)); + error( + location, + Diagnostics + .Duplicate_identifier_0_Static_and_instance_elements_cannot_share_the_same_private_name, + getTextOfNode(location), + ); } else { const prevIsMethod = !!(prev & DeclarationMeaning.Method); @@ -38526,7 +49737,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // fall through case "prototype": - const message = Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1; + const message = Diagnostics + .Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1; const className = getNameOfSymbolAsWritten(getSymbolOfDeclaration(node)); error(memberNameNode, message, memberName, className); break; @@ -38554,7 +49766,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (names.get(memberName)) { - error(getNameOfDeclaration(member.symbol.valueDeclaration), Diagnostics.Duplicate_identifier_0, memberName); + error( + getNameOfDeclaration(member.symbol.valueDeclaration), + Diagnostics.Duplicate_identifier_0, + memberName, + ); error(member.name, Diagnostics.Duplicate_identifier_0, memberName); } else { @@ -38579,7 +49795,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 8.5: A class declaration can have at most one string index member declaration and one numeric index member declaration const indexSymbol = getIndexSymbol(getSymbolOfDeclaration(node)!); if (indexSymbol?.declarations) { - const indexSignatureMap = new Map(); + const indexSignatureMap = new Map(); for (const declaration of (indexSymbol.declarations as IndexSignatureDeclaration[])) { if (declaration.parameters.length === 1 && declaration.parameters[0].type) { forEachType(getTypeFromTypeNode(declaration.parameters[0].type), type => { @@ -38611,8 +49827,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { setNodeLinksForPrivateIdentifierScope(node); // property signatures already report "initializer not allowed in ambient context" elsewhere - if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.PropertyDeclaration && node.initializer) { - error(node, Diagnostics.Property_0_cannot_have_an_initializer_because_it_is_marked_abstract, declarationNameToString(node.name)); + if ( + hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.PropertyDeclaration + && node.initializer + ) { + error( + node, + Diagnostics.Property_0_cannot_have_an_initializer_because_it_is_marked_abstract, + declarationNameToString(node.name), + ); } } @@ -38627,7 +49850,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Grammar checking if (!checkGrammarMethod(node)) checkGrammarComputedPropertyName(node.name); - if (isMethodDeclaration(node) && node.asteriskToken && isIdentifier(node.name) && idText(node.name) === "constructor") { + if ( + isMethodDeclaration(node) && node.asteriskToken && isIdentifier(node.name) + && idText(node.name) === "constructor" + ) { error(node.name, Diagnostics.Class_constructor_may_not_be_a_generator); } @@ -38635,8 +49861,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkFunctionOrMethodDeclaration(node); // method signatures already report "implementation not allowed in ambient context" elsewhere - if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body) { - error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); + if ( + hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration + && node.body + ) { + error( + node, + Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, + declarationNameToString(node.name), + ); } // Private named methods are only allowed in class declarations @@ -38647,9 +49880,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { setNodeLinksForPrivateIdentifierScope(node); } - function setNodeLinksForPrivateIdentifierScope(node: PropertyDeclaration | PropertySignature | MethodDeclaration | MethodSignature | AccessorDeclaration) { + function setNodeLinksForPrivateIdentifierScope( + node: PropertyDeclaration | PropertySignature | MethodDeclaration | MethodSignature | AccessorDeclaration, + ) { if (isPrivateIdentifier(node.name) && languageVersion < ScriptTarget.ESNext) { - for (let lexicalScope = getEnclosingBlockScopeContainer(node); !!lexicalScope; lexicalScope = getEnclosingBlockScopeContainer(lexicalScope)) { + for ( + let lexicalScope = getEnclosingBlockScopeContainer(node); + !!lexicalScope; + lexicalScope = getEnclosingBlockScopeContainer(lexicalScope) + ) { getNodeLinks(lexicalScope).flags |= NodeCheckFlags.ContainsClassWithPrivateIdentifiers; } @@ -38660,7 +49899,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const enclosingIterationStatement = getEnclosingIterationStatement(node.parent); if (enclosingIterationStatement) { getNodeLinks(node.name).flags |= NodeCheckFlags.BlockScopedBindingInLoop; - getNodeLinks(enclosingIterationStatement).flags |= NodeCheckFlags.LoopWithCapturedBlockScopedBinding; + getNodeLinks(enclosingIterationStatement).flags |= + NodeCheckFlags.LoopWithCapturedBlockScopedBinding; } } } @@ -38701,9 +49941,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isPrivateIdentifierClassElementDeclaration(n)) { return true; } - return n.kind === SyntaxKind.PropertyDeclaration && - !isStatic(n) && - !!(n as PropertyDeclaration).initializer; + return n.kind === SyntaxKind.PropertyDeclaration + && !isStatic(n) + && !!(n as PropertyDeclaration).initializer; } function checkConstructorDeclarationDiagnostics() { @@ -38717,7 +49957,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const superCall = findFirstSuperCall(node.body!); if (superCall) { if (classExtendsNull) { - error(superCall, Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null); + error( + superCall, + Diagnostics.A_constructor_cannot_contain_a_super_call_when_its_class_extends_null, + ); } // A super call must be root-level in a constructor if both of the following are true: @@ -38725,23 +49968,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - The constructor declares parameter properties // or the containing class declares instance member variables with initializers. - const superCallShouldBeRootLevel = - !emitStandardClassFields && - (some((node.parent as ClassDeclaration).members, isInstancePropertyWithInitializerOrPrivateIdentifierProperty) || - some(node.parameters, p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier))); + const superCallShouldBeRootLevel = !emitStandardClassFields + && (some( + (node.parent as ClassDeclaration).members, + isInstancePropertyWithInitializerOrPrivateIdentifierProperty, + ) + || some( + node.parameters, + p => hasSyntacticModifier(p, ModifierFlags.ParameterPropertyModifier), + )); if (superCallShouldBeRootLevel) { // Until we have better flow analysis, it is an error to place the super call within any kind of block or conditional // See GH #8277 if (!superCallIsRootLevelInConstructor(superCall, node.body!)) { - error(superCall, Diagnostics.A_super_call_must_be_a_root_level_statement_within_a_constructor_of_a_derived_class_that_contains_initialized_properties_parameter_properties_or_private_identifiers); + error( + superCall, + Diagnostics + .A_super_call_must_be_a_root_level_statement_within_a_constructor_of_a_derived_class_that_contains_initialized_properties_parameter_properties_or_private_identifiers, + ); } // Skip past any prologue directives to check statements for referring to 'super' or 'this' before a super call else { let superCallStatement: ExpressionStatement | undefined; for (const statement of node.body!.statements) { - if (isExpressionStatement(statement) && isSuperCall(skipOuterExpressions(statement.expression))) { + if ( + isExpressionStatement(statement) + && isSuperCall(skipOuterExpressions(statement.expression)) + ) { superCallStatement = statement; break; } @@ -38753,7 +50008,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Until we have better flow analysis, it is an error to place the super call within any kind of block or conditional // See GH #8277 if (superCallStatement === undefined) { - error(node, Diagnostics.A_super_call_must_be_the_first_statement_in_the_constructor_to_refer_to_super_or_this_when_a_derived_class_contains_initialized_properties_parameter_properties_or_private_identifiers); + error( + node, + Diagnostics + .A_super_call_must_be_the_first_statement_in_the_constructor_to_refer_to_super_or_this_when_a_derived_class_contains_initialized_properties_parameter_properties_or_private_identifiers, + ); } } } @@ -38792,12 +50051,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkAccessorDeclarationDiagnostics() { // Grammar checking accessors - if (!checkGrammarFunctionLikeDeclaration(node) && !checkGrammarAccessor(node)) checkGrammarComputedPropertyName(node.name); + if (!checkGrammarFunctionLikeDeclaration(node) && !checkGrammarAccessor(node)) { + checkGrammarComputedPropertyName(node.name); + } checkDecorators(node); checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { - if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { + if ( + !(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) + && (node.flags & NodeFlags.HasImplicitReturn) + ) { if (!(node.flags & NodeFlags.HasExplicitReturn)) { error(node.name, Diagnostics.A_get_accessor_must_return_a_value); } @@ -38824,8 +50088,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(getter.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract); error(setter.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract); } - if (((getterFlags & ModifierFlags.Protected) && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) || - ((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private))) { + if ( + ((getterFlags & ModifierFlags.Protected) + && !(setterFlags & (ModifierFlags.Protected | ModifierFlags.Private))) + || ((getterFlags & ModifierFlags.Private) && !(setterFlags & ModifierFlags.Private)) + ) { error(getter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter); error(setter.name, Diagnostics.A_get_accessor_must_be_at_least_as_accessible_as_the_setter); } @@ -38842,19 +50109,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkDecorators(node); } - function getEffectiveTypeArgumentAtIndex(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[], index: number): Type { + function getEffectiveTypeArgumentAtIndex( + node: TypeReferenceNode | ExpressionWithTypeArguments, + typeParameters: readonly TypeParameter[], + index: number, + ): Type { if (node.typeArguments && index < node.typeArguments.length) { return getTypeFromTypeNode(node.typeArguments[index]); } return getEffectiveTypeArguments(node, typeParameters)[index]; } - function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, typeParameters: readonly TypeParameter[]): Type[] { - return fillMissingTypeArguments(map(node.typeArguments!, getTypeFromTypeNode), typeParameters, - getMinTypeArgumentCount(typeParameters), isInJSFile(node)); + function getEffectiveTypeArguments( + node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, + typeParameters: readonly TypeParameter[], + ): Type[] { + return fillMissingTypeArguments( + map(node.typeArguments!, getTypeFromTypeNode), + typeParameters, + getMinTypeArgumentCount(typeParameters), + isInJSFile(node), + ); } - function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, typeParameters: readonly TypeParameter[]): boolean { + function checkTypeArgumentConstraints( + node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, + typeParameters: readonly TypeParameter[], + ): boolean { let typeArguments: Type[] | undefined; let mapper: TypeMapper | undefined; let result = true; @@ -38869,7 +50150,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typeArguments[i], instantiateType(constraint, mapper), node.typeArguments![i], - Diagnostics.Type_0_does_not_satisfy_the_constraint_1); + Diagnostics.Type_0_does_not_satisfy_the_constraint_1, + ); } } return result; @@ -38877,13 +50159,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeParametersForTypeAndSymbol(type: Type, symbol: Symbol) { if (!isErrorType(type)) { - return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters || - (getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters : undefined); + return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters + || (getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters + : undefined); } return undefined; } - function getTypeParametersForTypeReferenceOrImport(node: TypeReferenceNode | ExpressionWithTypeArguments | ImportTypeNode) { + function getTypeParametersForTypeReferenceOrImport( + node: TypeReferenceNode | ExpressionWithTypeArguments | ImportTypeNode, + ) { const type = getTypeFromTypeNode(node); if (!isErrorType(type)) { const symbol = getNodeLinks(node).resolvedSymbol; @@ -38896,11 +50181,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) { checkGrammarTypeArguments(node, node.typeArguments); - if (node.kind === SyntaxKind.TypeReference && !isInJSFile(node) && !isInJSDoc(node) && node.typeArguments && node.typeName.end !== node.typeArguments.pos) { + if ( + node.kind === SyntaxKind.TypeReference && !isInJSFile(node) && !isInJSDoc(node) && node.typeArguments + && node.typeName.end !== node.typeArguments.pos + ) { // If there was a token between the type name and the type arguments, check if it was a DotToken const sourceFile = getSourceFileOfNode(node); if (scanTokenAtPosition(sourceFile, node.typeName.end) === SyntaxKind.DotToken) { - grammarErrorAtPos(node, skipTrivia(sourceFile.text, node.typeName.end), 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); + grammarErrorAtPos( + node, + skipTrivia(sourceFile.text, node.typeName.end), + 1, + Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments, + ); } } forEach(node.typeArguments, checkSourceElement); @@ -38924,7 +50217,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addDeprecatedSuggestion( getDeprecatedSuggestionNode(node), symbol.declarations!, - symbol.escapedName as string + symbol.escapedName as string, ); } } @@ -38937,7 +50230,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeParameters = getTypeParametersForTypeReferenceOrImport(typeReferenceNode); if (!typeParameters) return undefined; const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments!.indexOf(node)]); - return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters))); + return constraint + && instantiateType( + constraint, + createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)), + ); } function checkTypeQuery(node: TypeQueryNode) { @@ -39012,8 +50309,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const objectType = (type as IndexedAccessType).objectType; const indexType = (type as IndexedAccessType).indexType; if (isTypeAssignableTo(indexType, getIndexType(objectType, IndexFlags.None))) { - if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && - getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly) { + if ( + accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) + && getObjectFlags(objectType) & ObjectFlags.Mapped + && getMappedTypeModifiers(objectType as MappedType) & MappedTypeModifiers.IncludeReadonly + ) { error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType)); } return type; @@ -39021,20 +50321,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Check if we're indexing with a numeric type and if either object or index types // is a generic type with a constraint that has a numeric index signature. const apparentObjectType = getApparentType(objectType); - if (getIndexInfoOfType(apparentObjectType, numberType) && isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) { + if ( + getIndexInfoOfType(apparentObjectType, numberType) + && isTypeAssignableToKind(indexType, TypeFlags.NumberLike) + ) { return type; } if (isGenericObjectType(objectType)) { const propertyName = getPropertyNameFromIndex(indexType, accessNode); if (propertyName) { const propertySymbol = forEachType(apparentObjectType, t => getPropertyOfType(t, propertyName)); - if (propertySymbol && getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.NonPublicAccessibilityModifier) { - error(accessNode, Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, unescapeLeadingUnderscores(propertyName)); + if ( + propertySymbol + && getDeclarationModifierFlagsFromSymbol(propertySymbol) + & ModifierFlags.NonPublicAccessibilityModifier + ) { + error( + accessNode, + Diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, + unescapeLeadingUnderscores(propertyName), + ); return errorType; } } } - error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType)); + error( + accessNode, + Diagnostics.Type_0_cannot_be_used_to_index_type_1, + typeToString(indexType), + typeToString(objectType), + ); return errorType; } @@ -39061,7 +50377,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { const constraintType = getConstraintTypeFromMappedType(type); - checkTypeAssignableTo(constraintType, keyofConstraintType, getEffectiveConstraintOfTypeParameter(node.typeParameter)); + checkTypeAssignableTo( + constraintType, + keyofConstraintType, + getEffectiveConstraintOfTypeParameter(node.typeParameter), + ); } } @@ -39085,8 +50405,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkInferType(node: InferTypeNode) { - if (!findAncestor(node, n => n.parent && n.parent.kind === SyntaxKind.ConditionalType && (n.parent as ConditionalTypeNode).extendsType === n)) { - grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type); + if ( + !findAncestor(node, n => + n.parent && n.parent.kind === SyntaxKind.ConditionalType + && (n.parent as ConditionalTypeNode).extendsType === n) + ) { + grammarErrorOnNode( + node, + Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type, + ); } checkSourceElement(node.typeParameter); const symbol = getSymbolOfDeclaration(node.typeParameter); @@ -39095,12 +50422,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.typeParametersChecked) { links.typeParametersChecked = true; const typeParameter = getDeclaredTypeOfTypeParameter(symbol); - const declarations: TypeParameterDeclaration[] = getDeclarationsOfKind(symbol, SyntaxKind.TypeParameter); + const declarations: TypeParameterDeclaration[] = getDeclarationsOfKind( + symbol, + SyntaxKind.TypeParameter, + ); if (!areTypeParametersIdentical(declarations, [typeParameter], decl => [decl])) { // Report an error on every conflicting declaration. const name = symbolToString(symbol); for (const declaration of declarations) { - error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_constraints, name); + error( + declaration.name, + Diagnostics.All_declarations_of_0_must_have_identical_constraints, + name, + ); } } } @@ -39124,10 +50458,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const override = getResolutionModeOverrideForClause(node.assertions.assertClause, grammarErrorOnNode); if (override) { if (!isNightly()) { - grammarErrorOnNode(node.assertions.assertClause, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next); + grammarErrorOnNode( + node.assertions.assertClause, + Diagnostics + .resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next, + ); } - if (getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) { - grammarErrorOnNode(node.assertions.assertClause, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext); + if ( + getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext + ) { + grammarErrorOnNode( + node.assertions.assertClause, + Diagnostics + .resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext, + ); } } } @@ -39140,17 +50485,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { grammarErrorOnNode(node, Diagnostics.A_tuple_member_cannot_be_both_optional_and_rest); } if (node.type.kind === SyntaxKind.OptionalType) { - grammarErrorOnNode(node.type, Diagnostics.A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type); + grammarErrorOnNode( + node.type, + Diagnostics + .A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type, + ); } if (node.type.kind === SyntaxKind.RestType) { - grammarErrorOnNode(node.type, Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type); + grammarErrorOnNode( + node.type, + Diagnostics + .A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type, + ); } checkSourceElement(node.type); getTypeFromTypeNode(node); } function isPrivateWithinAmbient(node: Node): boolean { - return (hasEffectiveModifier(node, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(node)) && !!(node.flags & NodeFlags.Ambient); + return (hasEffectiveModifier(node, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(node)) + && !!(node.flags & NodeFlags.Ambient); } function getEffectiveDeclarationFlags(n: Declaration, flagsToCheck: ModifierFlags): ModifierFlags { @@ -39158,12 +50512,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // children of classes (even ambient classes) should not be marked as ambient or export // because those flags have no useful semantics there. - if (n.parent.kind !== SyntaxKind.InterfaceDeclaration && - n.parent.kind !== SyntaxKind.ClassDeclaration && - n.parent.kind !== SyntaxKind.ClassExpression && - n.flags & NodeFlags.Ambient) { + if ( + n.parent.kind !== SyntaxKind.InterfaceDeclaration + && n.parent.kind !== SyntaxKind.ClassDeclaration + && n.parent.kind !== SyntaxKind.ClassExpression + && n.flags & NodeFlags.Ambient + ) { const container = getEnclosingContainer(n); - if ((container && container.flags & NodeFlags.ExportContext) && !(flags & ModifierFlags.Ambient) && !(isModuleBlock(n.parent) && isModuleDeclaration(n.parent.parent) && isGlobalScopeAugmentation(n.parent.parent))) { + if ( + (container && container.flags & NodeFlags.ExportContext) && !(flags & ModifierFlags.Ambient) + && !(isModuleBlock(n.parent) && isModuleDeclaration(n.parent.parent) + && isGlobalScopeAugmentation(n.parent.parent)) + ) { // It is nested in an ambient export context, which means it is automatically exported flags |= ModifierFlags.Export; } @@ -39178,53 +50538,87 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkFunctionOrConstructorSymbolWorker(symbol: Symbol): void { - function getCanonicalOverload(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined): Declaration { + function getCanonicalOverload( + overloads: Declaration[], + implementation: FunctionLikeDeclaration | undefined, + ): Declaration { // Consider the canonical set of flags to be the flags of the bodyDeclaration or the first declaration // Error on all deviations from this canonical set of flags // The caveat is that if some overloads are defined in lib.d.ts, we don't want to // report the errors on those. To achieve this, we will say that the implementation is // the canonical signature only if it is in the same container as the first overload - const implementationSharesContainerWithFirstOverload = implementation !== undefined && implementation.parent === overloads[0].parent; + const implementationSharesContainerWithFirstOverload = implementation !== undefined + && implementation.parent === overloads[0].parent; return implementationSharesContainerWithFirstOverload ? implementation : overloads[0]; } - function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, flagsToCheck: ModifierFlags, someOverloadFlags: ModifierFlags, allOverloadFlags: ModifierFlags): void { + function checkFlagAgreementBetweenOverloads( + overloads: Declaration[], + implementation: FunctionLikeDeclaration | undefined, + flagsToCheck: ModifierFlags, + someOverloadFlags: ModifierFlags, + allOverloadFlags: ModifierFlags, + ): void { // Error if some overloads have a flag that is not shared by all overloads. To find the // deviations, we XOR someOverloadFlags with allOverloadFlags const someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags; if (someButNotAllOverloadFlags !== 0) { - const canonicalFlags = getEffectiveDeclarationFlags(getCanonicalOverload(overloads, implementation), flagsToCheck); + const canonicalFlags = getEffectiveDeclarationFlags( + getCanonicalOverload(overloads, implementation), + flagsToCheck, + ); forEach(overloads, o => { const deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags; if (deviation & ModifierFlags.Export) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_exported_or_non_exported); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_exported_or_non_exported, + ); } else if (deviation & ModifierFlags.Ambient) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient, + ); } else if (deviation & (ModifierFlags.Private | ModifierFlags.Protected)) { - error(getNameOfDeclaration(o) || o, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); + error( + getNameOfDeclaration(o) || o, + Diagnostics.Overload_signatures_must_all_be_public_private_or_protected, + ); } else if (deviation & ModifierFlags.Abstract) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract, + ); } }); } } - function checkQuestionTokenAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration | undefined, someHaveQuestionToken: boolean, allHaveQuestionToken: boolean): void { + function checkQuestionTokenAgreementBetweenOverloads( + overloads: Declaration[], + implementation: FunctionLikeDeclaration | undefined, + someHaveQuestionToken: boolean, + allHaveQuestionToken: boolean, + ): void { if (someHaveQuestionToken !== allHaveQuestionToken) { const canonicalHasQuestionToken = hasQuestionToken(getCanonicalOverload(overloads, implementation)); forEach(overloads, o => { const deviation = hasQuestionToken(o) !== canonicalHasQuestionToken; if (deviation) { - error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_optional_or_required); + error( + getNameOfDeclaration(o), + Diagnostics.Overload_signatures_must_all_be_optional_or_required, + ); } }); } } - const flagsToCheck: ModifierFlags = ModifierFlags.Export | ModifierFlags.Ambient | ModifierFlags.Private | ModifierFlags.Protected | ModifierFlags.Abstract; + const flagsToCheck: ModifierFlags = ModifierFlags.Export | ModifierFlags.Ambient | ModifierFlags.Private + | ModifierFlags.Protected | ModifierFlags.Abstract; let someNodeFlags: ModifierFlags = ModifierFlags.None; let allNodeFlags = flagsToCheck; let someHaveQuestionToken = false; @@ -39257,30 +50651,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (subsequentNode.kind === node.kind) { const errorNode: Node = (subsequentNode as FunctionLikeDeclaration).name || subsequentNode; const subsequentName = (subsequentNode as FunctionLikeDeclaration).name; - if (node.name && subsequentName && ( - // both are private identifiers - isPrivateIdentifier(node.name) && isPrivateIdentifier(subsequentName) && node.name.escapedText === subsequentName.escapedText || - // Both are computed property names - isComputedPropertyName(node.name) && isComputedPropertyName(subsequentName) && isTypeIdenticalTo(checkComputedPropertyName(node.name), checkComputedPropertyName(subsequentName)) || - // Both are literal property names that are the same. - isPropertyNameLiteral(node.name) && isPropertyNameLiteral(subsequentName) && - getEscapedTextOfIdentifierOrLiteral(node.name) === getEscapedTextOfIdentifierOrLiteral(subsequentName) - )) { + if ( + node.name && subsequentName && ( + // both are private identifiers + isPrivateIdentifier(node.name) && isPrivateIdentifier(subsequentName) + && node.name.escapedText === subsequentName.escapedText + // Both are computed property names + || isComputedPropertyName(node.name) && isComputedPropertyName(subsequentName) + && isTypeIdenticalTo( + checkComputedPropertyName(node.name), + checkComputedPropertyName(subsequentName), + ) + // Both are literal property names that are the same. + || isPropertyNameLiteral(node.name) && isPropertyNameLiteral(subsequentName) + && getEscapedTextOfIdentifierOrLiteral(node.name) + === getEscapedTextOfIdentifierOrLiteral(subsequentName) + ) + ) { const reportError = - (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && - isStatic(node) !== isStatic(subsequentNode); + (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) + && isStatic(node) !== isStatic(subsequentNode); // we can get here in two cases // 1. mixed static and instance class members // 2. something with the same name was defined before the set of overloads that prevents them from merging // here we'll report error only for the first case since for second we should already report error in binder if (reportError) { - const diagnostic = isStatic(node) ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; + const diagnostic = isStatic(node) ? Diagnostics.Function_overload_must_be_static + : Diagnostics.Function_overload_must_not_be_static; error(errorNode, diagnostic); } return; } if (nodeIsPresent((subsequentNode as FunctionLikeDeclaration).body)) { - error(errorNode, Diagnostics.Function_implementation_name_must_be_0, declarationNameToString(node.name)); + error( + errorNode, + Diagnostics.Function_implementation_name_must_be_0, + declarationNameToString(node.name), + ); return; } } @@ -39296,7 +50703,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(errorNode, Diagnostics.All_declarations_of_an_abstract_method_must_be_consecutive); } else { - error(errorNode, Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration); + error( + errorNode, + Diagnostics.Function_implementation_is_missing_or_not_immediately_following_the_declaration, + ); } } } @@ -39309,7 +50719,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const current of declarations) { const node = current as SignatureDeclaration | ClassDeclaration | ClassExpression; const inAmbientContext = node.flags & NodeFlags.Ambient; - const inAmbientContextOrInterface = node.parent && (node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.TypeLiteral) || inAmbientContext; + const inAmbientContextOrInterface = node.parent + && (node.parent.kind === SyntaxKind.InterfaceDeclaration + || node.parent.kind === SyntaxKind.TypeLiteral) || inAmbientContext; if (inAmbientContextOrInterface) { // check if declarations are consecutive only if they are non-ambient // 1. ambient declarations can be interleaved @@ -39321,11 +50733,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { previousDeclaration = undefined; } - if ((node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) && !inAmbientContext) { + if ( + (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression) + && !inAmbientContext + ) { hasNonAmbientClass = true; } - if (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature || node.kind === SyntaxKind.Constructor) { + if ( + node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration + || node.kind === SyntaxKind.MethodSignature || node.kind === SyntaxKind.Constructor + ) { functionDeclarations.push(node); const currentNodeFlags = getEffectiveDeclarationFlags(node, flagsToCheck); someNodeFlags |= currentNodeFlags; @@ -39393,29 +50811,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { forEach(declarations, declaration => { const diagnostic = declaration.kind === SyntaxKind.ClassDeclaration - ? Diagnostics.Class_declaration_cannot_implement_overload_list_for_0 - : declaration.kind === SyntaxKind.FunctionDeclaration - ? Diagnostics.Function_with_bodies_can_only_merge_with_classes_that_are_ambient - : undefined; + ? Diagnostics.Class_declaration_cannot_implement_overload_list_for_0 + : declaration.kind === SyntaxKind.FunctionDeclaration + ? Diagnostics.Function_with_bodies_can_only_merge_with_classes_that_are_ambient + : undefined; if (diagnostic) { addRelatedInfo( error(getNameOfDeclaration(declaration) || declaration, diagnostic, symbolName(symbol)), - ...relatedDiagnostics + ...relatedDiagnostics, ); } }); } // Abstract methods can't have an implementation -- in particular, they don't need one. - if (lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && - !hasSyntacticModifier(lastSeenNonAmbientDeclaration, ModifierFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken) { + if ( + lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body + && !hasSyntacticModifier(lastSeenNonAmbientDeclaration, ModifierFlags.Abstract) + && !lastSeenNonAmbientDeclaration.questionToken + ) { reportImplementationExpectedError(lastSeenNonAmbientDeclaration); } if (hasOverloads) { if (declarations) { - checkFlagAgreementBetweenOverloads(declarations, bodyDeclaration, flagsToCheck, someNodeFlags, allNodeFlags); - checkQuestionTokenAgreementBetweenOverloads(declarations, bodyDeclaration, someHaveQuestionToken, allHaveQuestionToken); + checkFlagAgreementBetweenOverloads( + declarations, + bodyDeclaration, + flagsToCheck, + someNodeFlags, + allNodeFlags, + ); + checkQuestionTokenAgreementBetweenOverloads( + declarations, + bodyDeclaration, + someHaveQuestionToken, + allHaveQuestionToken, + ); } if (bodyDeclaration) { @@ -39427,8 +50859,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? (signature.declaration.parent as JSDocOverloadTag | JSDocCallbackTag).tagName : signature.declaration; addRelatedInfo( - error(errorNode, Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature), - createDiagnosticForNode(bodyDeclaration, Diagnostics.The_implementation_signature_is_declared_here) + error( + errorNode, + Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature, + ), + createDiagnosticForNode( + bodyDeclaration, + Diagnostics.The_implementation_signature_is_declared_here, + ), ); break; } @@ -39464,7 +50902,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let defaultExportedDeclarationSpaces = DeclarationSpaces.None; for (const d of symbol.declarations!) { const declarationSpaces = getDeclarationSpaces(d); - const effectiveDeclarationFlags = getEffectiveDeclarationFlags(d, ModifierFlags.Export | ModifierFlags.Default); + const effectiveDeclarationFlags = getEffectiveDeclarationFlags( + d, + ModifierFlags.Export | ModifierFlags.Default, + ); if (effectiveDeclarationFlags & ModifierFlags.Export) { if (effectiveDeclarationFlags & ModifierFlags.Default) { @@ -39483,7 +50924,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const nonDefaultExportedDeclarationSpaces = exportedDeclarationSpaces | nonExportedDeclarationSpaces; const commonDeclarationSpacesForExportsAndLocals = exportedDeclarationSpaces & nonExportedDeclarationSpaces; - const commonDeclarationSpacesForDefaultAndNonDefault = defaultExportedDeclarationSpaces & nonDefaultExportedDeclarationSpaces; + const commonDeclarationSpacesForDefaultAndNonDefault = defaultExportedDeclarationSpaces + & nonDefaultExportedDeclarationSpaces; if (commonDeclarationSpacesForExportsAndLocals || commonDeclarationSpacesForDefaultAndNonDefault) { // declaration spaces for exported and non-exported declarations intersect @@ -39493,10 +50935,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const name = getNameOfDeclaration(d); // Only error on the declarations that contributed to the intersecting spaces. if (declarationSpaces & commonDeclarationSpacesForDefaultAndNonDefault) { - error(name, Diagnostics.Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead, declarationNameToString(name)); + error( + name, + Diagnostics + .Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead, + declarationNameToString(name), + ); } else if (declarationSpaces & commonDeclarationSpacesForExportsAndLocals) { - error(name, Diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, declarationNameToString(name)); + error( + name, + Diagnostics.Individual_declarations_in_merged_declaration_0_must_be_all_exported_or_all_local, + declarationNameToString(name), + ); } } } @@ -39514,7 +50965,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.JSDocEnumTag: return DeclarationSpaces.ExportType; case SyntaxKind.ModuleDeclaration: - return isAmbientModule(d as ModuleDeclaration) || getModuleInstanceState(d as ModuleDeclaration) !== ModuleInstanceState.NonInstantiated + return isAmbientModule(d as ModuleDeclaration) + || getModuleInstanceState(d as ModuleDeclaration) !== ModuleInstanceState.NonInstantiated ? DeclarationSpaces.ExportNamespace | DeclarationSpaces.ExportValue : DeclarationSpaces.ExportNamespace; case SyntaxKind.ClassDeclaration: @@ -39522,7 +50974,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.EnumMember: return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue; case SyntaxKind.SourceFile: - return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue | DeclarationSpaces.ExportNamespace; + return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue + | DeclarationSpaces.ExportNamespace; case SyntaxKind.ExportAssignment: case SyntaxKind.BinaryExpression: const node = d as ExportAssignment | BinaryExpression; @@ -39539,7 +50992,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NamespaceImport: case SyntaxKind.ImportClause: let result = DeclarationSpaces.None; - const target = resolveAlias(getSymbolOfDeclaration(d as ImportEqualsDeclaration | NamespaceImport | ImportClause | ExportAssignment | BinaryExpression)!); + const target = resolveAlias( + getSymbolOfDeclaration( + d as + | ImportEqualsDeclaration + | NamespaceImport + | ImportClause + | ExportAssignment + | BinaryExpression, + )!, + ); forEach(target.declarations, d => { result |= getDeclarationSpaces(d); }); @@ -39549,12 +51011,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.FunctionDeclaration: case SyntaxKind.ImportSpecifier: // https://github.com/Microsoft/TypeScript/pull/7591 case SyntaxKind.Identifier: // https://github.com/microsoft/TypeScript/issues/36098 - // Identifiers are used as declarations of assignment declarations whose parents may be - // SyntaxKind.CallExpression - `Object.defineProperty(thing, "aField", {value: 42});` - // SyntaxKind.ElementAccessExpression - `thing["aField"] = 42;` or `thing["aField"];` (with a doc comment on it) - // or SyntaxKind.PropertyAccessExpression - `thing.aField = 42;` - // all of which are pretty much always values, or at least imply a value meaning. - // It may be apprpriate to treat these as aliases in the future. + // Identifiers are used as declarations of assignment declarations whose parents may be + // SyntaxKind.CallExpression - `Object.defineProperty(thing, "aField", {value: 42});` + // SyntaxKind.ElementAccessExpression - `thing["aField"] = 42;` or `thing["aField"];` (with a doc comment on it) + // or SyntaxKind.PropertyAccessExpression - `thing.aField = 42;` + // all of which are pretty much always values, or at least imply a value meaning. + // It may be apprpriate to treat these as aliases in the future. return DeclarationSpaces.ExportValue; case SyntaxKind.MethodSignature: case SyntaxKind.PropertySignature: @@ -39565,7 +51027,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getAwaitedTypeOfPromise(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { + function getAwaitedTypeOfPromise( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + ...args: DiagnosticArguments + ): Type | undefined { const promisedType = getPromisedTypeOfPromise(type, errorNode); return promisedType && getAwaitedType(promisedType, errorNode, diagnosticMessage, ...args); } @@ -39575,7 +51042,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param type The type of the promise. * @remarks The "promised type" of a type is the type of the "value" parameter of the "onfulfilled" callback. */ - function getPromisedTypeOfPromise(type: Type, errorNode?: Node, thisTypeForErrorOut?: { value?: Type }): Type | undefined { + function getPromisedTypeOfPromise( + type: Type, + errorNode?: Node, + thisTypeForErrorOut?: { value?: Type; }, + ): Type | undefined { // // { // type // then( // thenFunction @@ -39635,12 +51106,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { thisTypeForErrorOut.value = thisTypeForError; } if (errorNode) { - error(errorNode, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForError)); + error( + errorNode, + Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, + typeToString(type), + typeToString(thisTypeForError), + ); } return undefined; } - const onfulfilledParameterType = getTypeWithFacts(getUnionType(map(candidates, getTypeOfFirstParameterOfSignature)), TypeFacts.NEUndefinedOrNull); + const onfulfilledParameterType = getTypeWithFacts( + getUnionType(map(candidates, getTypeOfFirstParameterOfSignature)), + TypeFacts.NEUndefinedOrNull, + ); if (isTypeAny(onfulfilledParameterType)) { return undefined; } @@ -39653,7 +51132,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - return typeAsPromise.promisedTypeOfPromise = getUnionType(map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature), UnionReduction.Subtype); + return typeAsPromise.promisedTypeOfPromise = getUnionType( + map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature), + UnionReduction.Subtype, + ); } /** @@ -39664,10 +51146,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Promise-like type; otherwise, it is the type of the expression. This is used to reflect * The runtime behavior of the `await` keyword. */ - function checkAwaitedType(type: Type, withAlias: boolean, errorNode: Node, diagnosticMessage: DiagnosticMessage, ...args: DiagnosticArguments): Type { - const awaitedType = withAlias ? - getAwaitedType(type, errorNode, diagnosticMessage, ...args) : - getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, ...args); + function checkAwaitedType( + type: Type, + withAlias: boolean, + errorNode: Node, + diagnosticMessage: DiagnosticMessage, + ...args: DiagnosticArguments + ): Type { + const awaitedType = withAlias + ? getAwaitedType(type, errorNode, diagnosticMessage, ...args) + : getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, ...args); return awaitedType || errorType; } @@ -39681,7 +51169,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const thenFunction = getTypeOfPropertyOfType(type, "then" as __String); - return !!thenFunction && getSignaturesOfType(getTypeWithFacts(thenFunction, TypeFacts.NEUndefinedOrNull), SignatureKind.Call).length > 0; + return !!thenFunction + && getSignaturesOfType(getTypeWithFacts(thenFunction, TypeFacts.NEUndefinedOrNull), SignatureKind.Call) + .length > 0; } interface AwaitedTypeInstantiation extends Type { @@ -39702,9 +51192,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * For a generic `Awaited`, gets `T`. */ function unwrapAwaitedType(type: Type) { - return type.flags & TypeFlags.Union ? mapType(type, unwrapAwaitedType) : - isAwaitedTypeInstantiation(type) ? type.aliasTypeArguments[0] : - type; + return type.flags & TypeFlags.Union ? mapType(type, unwrapAwaitedType) + : isAwaitedTypeInstantiation(type) ? type.aliasTypeArguments[0] + : type; } function isAwaitedTypeNeeded(type: Type) { @@ -39718,9 +51208,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseConstraint = getBaseConstraintOfType(type); // We only need `Awaited` if `T` is a type variable that has no base constraint, or the base constraint of `T` is `any`, `unknown`, `{}`, `object`, // or is promise-like. - if (baseConstraint ? - baseConstraint.flags & TypeFlags.AnyOrUnknown || isEmptyObjectType(baseConstraint) || someType(baseConstraint, isThenableType) : - maybeTypeOfKind(type, TypeFlags.TypeVariable)) { + if ( + baseConstraint + ? baseConstraint.flags & TypeFlags.AnyOrUnknown || isEmptyObjectType(baseConstraint) + || someType(baseConstraint, isThenableType) + : maybeTypeOfKind(type, TypeFlags.TypeVariable) + ) { return true; } } @@ -39756,7 +51249,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - Debug.assert(isAwaitedTypeInstantiation(type) || getPromisedTypeOfPromise(type) === undefined, "type provided should not be a non-generic 'promise'-like."); + Debug.assert( + isAwaitedTypeInstantiation(type) || getPromisedTypeOfPromise(type) === undefined, + "type provided should not be a non-generic 'promise'-like.", + ); return type; } @@ -39770,7 +51266,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * This is used to reflect the runtime behavior of the `await` keyword. */ - function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { + function getAwaitedType( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + ...args: DiagnosticArguments + ): Type | undefined { const awaitedType = getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, ...args); return awaitedType && createAwaitedTypeIfNeeded(awaitedType); } @@ -39780,7 +51281,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * @see {@link getAwaitedType} */ - function getAwaitedTypeNoAlias(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { + function getAwaitedTypeNoAlias( + type: Type, + errorNode?: Node, + diagnosticMessage?: DiagnosticMessage, + ...args: DiagnosticArguments + ): Type | undefined { if (isTypeAny(type)) { return type; } @@ -39800,12 +51306,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.Union) { if (awaitedTypeStack.lastIndexOf(type.id) >= 0) { if (errorNode) { - error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method); + error( + errorNode, + Diagnostics + .Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method, + ); } return undefined; } - const mapper = errorNode ? (constituentType: Type) => getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, ...args) : getAwaitedTypeNoAlias; + const mapper = errorNode ? (constituentType: Type) => + getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, ...args) : getAwaitedTypeNoAlias; awaitedTypeStack.push(type.id); const mapped = mapType(type, mapper); @@ -39819,7 +51330,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeAsAwaitable.awaitedTypeOfType = type; } - const thisTypeForErrorOut: { value: Type | undefined } = { value: undefined }; + const thisTypeForErrorOut: { value: Type | undefined; } = { value: undefined }; const promisedType = getPromisedTypeOfPromise(type, /*errorNode*/ undefined, thisTypeForErrorOut); if (promisedType) { if (type.id === promisedType.id || awaitedTypeStack.lastIndexOf(promisedType.id) >= 0) { @@ -39857,7 +51368,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // } // if (errorNode) { - error(errorNode, Diagnostics.Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method); + error( + errorNode, + Diagnostics + .Type_is_referenced_directly_or_indirectly_in_the_fulfillment_callback_of_its_own_then_method, + ); } return undefined; } @@ -39895,10 +51410,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assertIsDefined(diagnosticMessage); let chain: DiagnosticMessageChain | undefined; if (thisTypeForErrorOut.value) { - chain = chainDiagnosticMessages(chain, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForErrorOut.value)); + chain = chainDiagnosticMessages( + chain, + Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, + typeToString(type), + typeToString(thisTypeForErrorOut.value), + ); } chain = chainDiagnosticMessages(chain, diagnosticMessage, ...args); - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode), errorNode, chain)); + diagnostics.add( + createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode), errorNode, chain), + ); } return undefined; } @@ -39918,7 +51440,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * @param node The signature to check */ - function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature, returnTypeNode: TypeNode, returnTypeErrorLocation: TypeNode) { + function checkAsyncFunctionReturnType( + node: FunctionLikeDeclaration | MethodSignature, + returnTypeNode: TypeNode, + returnTypeErrorLocation: TypeNode, + ) { // As part of our emit for an async function, we will need to emit the entity name of // the return type annotation as an expression. To meet the necessary runtime semantics // for __awaiter, we must also check that the type of the declaration (e.g. the static @@ -39952,7 +51478,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (globalPromiseType !== emptyGenericType && !isReferenceToType(returnType, globalPromiseType)) { // The promise type was not a valid type reference to the global promise type, so we // report an error and return the unknown type. - reportErrorForInvalidReturnType(Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, returnTypeNode, returnTypeErrorLocation, typeToString(getAwaitedTypeNoAlias(returnType) || voidType)); + reportErrorForInvalidReturnType( + Diagnostics + .The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0, + returnTypeNode, + returnTypeErrorLocation, + typeToString(getAwaitedTypeNoAlias(returnType) || voidType), + ); return; } } @@ -39966,18 +51498,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const promiseConstructorName = getEntityNameFromTypeNode(returnTypeNode); if (promiseConstructorName === undefined) { - reportErrorForInvalidReturnType(Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, returnTypeNode, returnTypeErrorLocation, typeToString(returnType)); + reportErrorForInvalidReturnType( + Diagnostics + .Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + returnTypeNode, + returnTypeErrorLocation, + typeToString(returnType), + ); return; } - const promiseConstructorSymbol = resolveEntityName(promiseConstructorName, SymbolFlags.Value, /*ignoreErrors*/ true); - const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : errorType; + const promiseConstructorSymbol = resolveEntityName( + promiseConstructorName, + SymbolFlags.Value, + /*ignoreErrors*/ true, + ); + const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) + : errorType; if (isErrorType(promiseConstructorType)) { - if (promiseConstructorName.kind === SyntaxKind.Identifier && promiseConstructorName.escapedText === "Promise" && getTargetType(returnType) === getGlobalPromiseType(/*reportErrors*/ false)) { - error(returnTypeErrorLocation, Diagnostics.An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option); + if ( + promiseConstructorName.kind === SyntaxKind.Identifier + && promiseConstructorName.escapedText === "Promise" + && getTargetType(returnType) === getGlobalPromiseType(/*reportErrors*/ false) + ) { + error( + returnTypeErrorLocation, + Diagnostics + .An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_declaration_for_the_Promise_constructor_or_include_ES2015_in_your_lib_option, + ); } else { - reportErrorForInvalidReturnType(Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, returnTypeNode, returnTypeErrorLocation, entityNameToString(promiseConstructorName)); + reportErrorForInvalidReturnType( + Diagnostics + .Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + returnTypeNode, + returnTypeErrorLocation, + entityNameToString(promiseConstructorName), + ); } return; } @@ -39986,13 +51543,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (globalPromiseConstructorLikeType === emptyObjectType) { // If we couldn't resolve the global PromiseConstructorLike type we cannot verify // compatibility with __awaiter. - reportErrorForInvalidReturnType(Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, returnTypeNode, returnTypeErrorLocation, entityNameToString(promiseConstructorName)); + reportErrorForInvalidReturnType( + Diagnostics + .Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, + returnTypeNode, + returnTypeErrorLocation, + entityNameToString(promiseConstructorName), + ); return; } - const headMessage = Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value; - const errorInfo = () => returnTypeNode === returnTypeErrorLocation ? undefined : chainDiagnosticMessages(/*details*/ undefined, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type); - if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, returnTypeErrorLocation, headMessage, errorInfo)) { + const headMessage = Diagnostics + .Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value; + const errorInfo = () => + returnTypeNode === returnTypeErrorLocation ? undefined + : chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type, + ); + if ( + !checkTypeAssignableTo( + promiseConstructorType, + globalPromiseConstructorLikeType, + returnTypeErrorLocation, + headMessage, + errorInfo, + ) + ) { return; } @@ -40000,21 +51577,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const rootName = promiseConstructorName && getFirstIdentifier(promiseConstructorName); const collidingSymbol = getSymbol(node.locals!, rootName.escapedText, SymbolFlags.Value); if (collidingSymbol) { - error(collidingSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions, + error( + collidingSymbol.valueDeclaration, + Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions, idText(rootName), - entityNameToString(promiseConstructorName)); + entityNameToString(promiseConstructorName), + ); return; } } - checkAwaitedType(returnType, /*withAlias*/ false, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member); + checkAwaitedType( + returnType, + /*withAlias*/ false, + node, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ); - function reportErrorForInvalidReturnType(message: DiagnosticMessage, returnTypeNode: TypeNode, returnTypeErrorLocation: TypeNode, typeName: string) { + function reportErrorForInvalidReturnType( + message: DiagnosticMessage, + returnTypeNode: TypeNode, + returnTypeErrorLocation: TypeNode, + typeName: string, + ) { if (returnTypeNode === returnTypeErrorLocation) { error(returnTypeErrorLocation, message, typeName); } else { - const diag = error(returnTypeErrorLocation, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type); + const diag = error( + returnTypeErrorLocation, + Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type, + ); addRelatedInfo(diag, createDiagnosticForNode(returnTypeNode, message, typeName)); } } @@ -40075,10 +51669,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { returnType: Type, typePredicate?: TypePredicate, minArgumentCount: number = parameters.length, - flags: SignatureFlags = SignatureFlags.None + flags: SignatureFlags = SignatureFlags.None, ) { - const decl = factory.createFunctionTypeNode(/*typeParameters*/ undefined, emptyArray, factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)); - return createSignature(decl, typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, flags); + const decl = factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + emptyArray, + factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + ); + return createSignature( + decl, + typeParameters, + thisParameter, + parameters, + returnType, + typePredicate, + minArgumentCount, + flags, + ); } /** @@ -40091,9 +51698,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { returnType: Type, typePredicate?: TypePredicate, minArgumentCount?: number, - flags?: SignatureFlags + flags?: SignatureFlags, ) { - const signature = createCallSignature(typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, flags); + const signature = createCallSignature( + typeParameters, + thisParameter, + parameters, + returnType, + typePredicate, + minArgumentCount, + flags, + ); return getOrCreateTypeFromSignature(signature); } @@ -40111,31 +51726,56 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * marked as referenced to prevent import elision. */ function markTypeNodeAsReferenced(node: TypeNode) { - markEntityNameOrEntityExpressionAsReference(node && getEntityNameFromTypeNode(node), /*forDecoratorMetadata*/ false); + markEntityNameOrEntityExpressionAsReference( + node && getEntityNameFromTypeNode(node), + /*forDecoratorMetadata*/ false, + ); } - function markEntityNameOrEntityExpressionAsReference(typeName: EntityNameOrEntityNameExpression | undefined, forDecoratorMetadata: boolean) { + function markEntityNameOrEntityExpressionAsReference( + typeName: EntityNameOrEntityNameExpression | undefined, + forDecoratorMetadata: boolean, + ) { if (!typeName) return; const rootName = getFirstIdentifier(typeName); - const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias; - const rootSymbol = resolveName(rootName, rootName.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); + const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) + | SymbolFlags.Alias; + const rootSymbol = resolveName( + rootName, + rootName.escapedText, + meaning, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + ); if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) { - if (canCollectSymbolAliasAccessabilityData + if ( + canCollectSymbolAliasAccessabilityData && symbolIsValue(rootSymbol) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol)) - && !getTypeOnlyAliasDeclaration(rootSymbol)) { + && !getTypeOnlyAliasDeclaration(rootSymbol) + ) { markAliasSymbolAsReferenced(rootSymbol); } - else if (forDecoratorMetadata + else if ( + forDecoratorMetadata && getIsolatedModules(compilerOptions) && getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015 && !symbolIsValue(rootSymbol) - && !some(rootSymbol.declarations, isTypeOnlyImportOrExportDeclaration)) { - const diag = error(typeName, Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled); + && !some(rootSymbol.declarations, isTypeOnlyImportOrExportDeclaration) + ) { + const diag = error( + typeName, + Diagnostics + .A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled, + ); const aliasDeclaration = find(rootSymbol.declarations || emptyArray, isAliasSymbolDeclaration); if (aliasDeclaration) { - addRelatedInfo(diag, createDiagnosticForNode(aliasDeclaration, Diagnostics._0_was_imported_here, idText(rootName))); + addRelatedInfo( + diag, + createDiagnosticForNode(aliasDeclaration, Diagnostics._0_was_imported_here, idText(rootName)), + ); } } } @@ -40163,7 +51803,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getEntityNameForDecoratorMetadataFromTypeList((node as UnionOrIntersectionTypeNode).types); case SyntaxKind.ConditionalType: - return getEntityNameForDecoratorMetadataFromTypeList([(node as ConditionalTypeNode).trueType, (node as ConditionalTypeNode).falseType]); + return getEntityNameForDecoratorMetadataFromTypeList([ + (node as ConditionalTypeNode).trueType, + (node as ConditionalTypeNode).falseType, + ]); case SyntaxKind.ParenthesizedType: case SyntaxKind.NamedTupleMember: @@ -40184,7 +51827,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeNode.kind === SyntaxKind.NeverKeyword) { continue; // Always elide `never` from the union/intersection if possible } - if (!strictNullChecks && (typeNode.kind === SyntaxKind.LiteralType && (typeNode as LiteralTypeNode).literal.kind === SyntaxKind.NullKeyword || typeNode.kind === SyntaxKind.UndefinedKeyword)) { + if ( + !strictNullChecks + && (typeNode.kind === SyntaxKind.LiteralType + && (typeNode as LiteralTypeNode).literal.kind === SyntaxKind.NullKeyword + || typeNode.kind === SyntaxKind.UndefinedKeyword) + ) { continue; // Elide null and undefined from unions for metadata, just like what we did prior to the implementation of strict null checks } const individualEntityName = getEntityNameForDecoratorMetadata(typeNode); @@ -40200,9 +51848,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Keep this in sync with serializeUnionOrIntersectionType // Verify if they refer to same entity and is identifier // return undefined if they dont match because we would emit object - if (!isIdentifier(commonEntityName) || - !isIdentifier(individualEntityName) || - commonEntityName.escapedText !== individualEntityName.escapedText) { + if ( + !isIdentifier(commonEntityName) + || !isIdentifier(individualEntityName) + || commonEntityName.escapedText !== individualEntityName.escapedText + ) { return undefined; } } @@ -40222,7 +51872,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkDecorators(node: Node): void { // skip this check for nodes that cannot have decorators. These should have already had an error reported by // checkGrammarModifiers. - if (!canHaveDecorators(node) || !hasDecorators(node) || !node.modifiers || !nodeCanBeDecorated(legacyDecorators, node, node.parent, node.parent.parent)) { + if ( + !canHaveDecorators(node) || !hasDecorators(node) || !node.modifiers + || !nodeCanBeDecorated(legacyDecorators, node, node.parent, node.parent.parent) + ) { return; } @@ -40251,7 +51904,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (!isClassExpression(node)) { - if (isPrivateIdentifier(node.name) && (isMethodDeclaration(node) || isAccessor(node) || isAutoAccessorPropertyDeclaration(node))) { + if ( + isPrivateIdentifier(node.name) + && (isMethodDeclaration(node) || isAccessor(node) || isAutoAccessorPropertyDeclaration(node)) + ) { checkExternalEmitHelpers(firstDecorator, ExternalEmitHelpers.SetFunctionName); } if (isComputedPropertyName(node.name)) { @@ -40269,16 +51925,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constructor = getFirstConstructorWithBody(node); if (constructor) { for (const parameter of constructor.parameters) { - markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter)); + markDecoratorMedataDataTypeNodeAsReferenced( + getParameterTypeNodeForDecoratorCheck(parameter), + ); } } break; case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; - const otherAccessor = getDeclarationOfKind(getSymbolOfDeclaration(node), otherKind); - markDecoratorMedataDataTypeNodeAsReferenced(getAnnotatedAccessorTypeNode(node) || otherAccessor && getAnnotatedAccessorTypeNode(otherAccessor)); + const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor + : SyntaxKind.GetAccessor; + const otherAccessor = getDeclarationOfKind( + getSymbolOfDeclaration(node), + otherKind, + ); + markDecoratorMedataDataTypeNodeAsReferenced( + getAnnotatedAccessorTypeNode(node) + || otherAccessor && getAnnotatedAccessorTypeNode(otherAccessor), + ); break; case SyntaxKind.MethodDeclaration: for (const parameter of node.parameters) { @@ -40323,7 +51988,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJSDocTypeAliasTag(node: JSDocTypedefTag | JSDocCallbackTag) { if (!node.typeExpression) { // If the node had `@property` tags, `typeExpression` would have been set to the first property tag. - error(node.name, Diagnostics.JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags); + error( + node.name, + Diagnostics + .JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags, + ); } if (node.name) { @@ -40407,7 +52076,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (extend) { const className = getIdentifierFromEntityNameExpression(extend.expression); if (className && name.escapedText !== className.escapedText) { - error(name, Diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, idText(node.tagName), idText(name), idText(className)); + error( + name, + Diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, + idText(node.tagName), + idText(name), + idText(className), + ); } } } @@ -40419,7 +52094,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier | PrivateIdentifier; + function getIdentifierFromEntityNameExpression( + node: Identifier | PropertyAccessExpression, + ): Identifier | PrivateIdentifier; function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined; function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateIdentifier | undefined { switch (node.kind) { @@ -40458,7 +52135,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // checkFunctionOrConstructorSymbol wouldn't be called if we didnt ignore javascript function. const firstDeclaration = localSymbol.declarations?.find( // Get first non javascript function declaration - declaration => declaration.kind === node.kind && !(declaration.flags & NodeFlags.JavaScriptFile)); + declaration => declaration.kind === node.kind && !(declaration.flags & NodeFlags.JavaScriptFile), + ); // Only type check the symbol once if (node === firstDeclaration) { @@ -40480,8 +52158,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A js function declaration can have a @type tag instead of a return type node, but that type must have a call signature if (isInJSFile(node)) { const typeTag = getJSDocTypeTag(node); - if (typeTag && typeTag.typeExpression && !getContextualCallSignature(getTypeFromTypeNode(typeTag.typeExpression), node)) { - error(typeTag.typeExpression.type, Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature); + if ( + typeTag && typeTag.typeExpression + && !getContextualCallSignature(getTypeFromTypeNode(typeTag.typeExpression), node) + ) { + error( + typeTag.typeExpression.type, + Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature, + ); } } @@ -40521,12 +52205,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } type PotentiallyUnusedIdentifier = - | SourceFile | ModuleDeclaration | ClassLikeDeclaration | InterfaceDeclaration - | Block | CaseBlock | ForStatement | ForInStatement | ForOfStatement - | Exclude | TypeAliasDeclaration + | SourceFile + | ModuleDeclaration + | ClassLikeDeclaration + | InterfaceDeclaration + | Block + | CaseBlock + | ForStatement + | ForInStatement + | ForOfStatement + | Exclude + | TypeAliasDeclaration | InferTypeNode; - function checkUnusedIdentifiers(potentiallyUnusedIdentifiers: readonly PotentiallyUnusedIdentifier[], addDiagnostic: AddUnusedDiagnostic) { + function checkUnusedIdentifiers( + potentiallyUnusedIdentifiers: readonly PotentiallyUnusedIdentifier[], + addDiagnostic: AddUnusedDiagnostic, + ) { for (const node of potentiallyUnusedIdentifiers) { switch (node.kind) { case SyntaxKind.ClassDeclaration: @@ -40575,7 +52270,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function errorUnusedLocal(declaration: Declaration, name: string, addDiagnostic: AddUnusedDiagnostic) { const node = getNameOfDeclaration(declaration) || declaration; - const message = isTypeDeclaration(declaration) ? Diagnostics._0_is_declared_but_never_used : Diagnostics._0_is_declared_but_its_value_is_never_read; + const message = isTypeDeclaration(declaration) ? Diagnostics._0_is_declared_but_never_used + : Diagnostics._0_is_declared_but_its_value_is_never_read; addDiagnostic(declaration, UnusedKind.Local, createDiagnosticForNode(node, message, name)); } @@ -40583,7 +52279,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isIdentifier(node) && idText(node).charCodeAt(0) === CharacterCodes._; } - function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression, addDiagnostic: AddUnusedDiagnostic): void { + function checkUnusedClassMembers( + node: ClassDeclaration | ClassExpression, + addDiagnostic: AddUnusedDiagnostic, + ): void { for (const member of node.members) { switch (member.kind) { case SyntaxKind.MethodDeclaration: @@ -40595,16 +52294,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; } const symbol = getSymbolOfDeclaration(member); - if (!symbol.isReferenced - && (hasEffectiveModifier(member, ModifierFlags.Private) || isNamedDeclaration(member) && isPrivateIdentifier(member.name)) - && !(member.flags & NodeFlags.Ambient)) { - addDiagnostic(member, UnusedKind.Local, createDiagnosticForNode(member.name!, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolToString(symbol))); + if ( + !symbol.isReferenced + && (hasEffectiveModifier(member, ModifierFlags.Private) + || isNamedDeclaration(member) && isPrivateIdentifier(member.name)) + && !(member.flags & NodeFlags.Ambient) + ) { + addDiagnostic( + member, + UnusedKind.Local, + createDiagnosticForNode( + member.name!, + Diagnostics._0_is_declared_but_its_value_is_never_read, + symbolToString(symbol), + ), + ); } break; case SyntaxKind.Constructor: for (const parameter of (member as ConstructorDeclaration).parameters) { if (!parameter.symbol.isReferenced && hasSyntacticModifier(parameter, ModifierFlags.Private)) { - addDiagnostic(parameter, UnusedKind.Local, createDiagnosticForNode(parameter.name, Diagnostics.Property_0_is_declared_but_its_value_is_never_read, symbolName(parameter.symbol))); + addDiagnostic( + parameter, + UnusedKind.Local, + createDiagnosticForNode( + parameter.name, + Diagnostics.Property_0_is_declared_but_its_value_is_never_read, + symbolName(parameter.symbol), + ), + ); } } break; @@ -40622,11 +52340,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkUnusedInferTypeParameter(node: InferTypeNode, addDiagnostic: AddUnusedDiagnostic): void { const { typeParameter } = node; if (isTypeParameterUnused(typeParameter)) { - addDiagnostic(node, UnusedKind.Parameter, createDiagnosticForNode(node, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(typeParameter.name))); + addDiagnostic( + node, + UnusedKind.Parameter, + createDiagnosticForNode( + node, + Diagnostics._0_is_declared_but_its_value_is_never_read, + idText(typeParameter.name), + ), + ); } } - function checkUnusedTypeParameters(node: ClassLikeDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration, addDiagnostic: AddUnusedDiagnostic): void { + function checkUnusedTypeParameters( + node: ClassLikeDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration, + addDiagnostic: AddUnusedDiagnostic, + ): void { // Only report errors on the last declaration for the type parameter container; // this ensures that all uses have been accounted for. const declarations = getSymbolOfDeclaration(node).declarations; @@ -40649,21 +52378,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Include the `<>` in the error message : rangeOfTypeParameters(sourceFile, parent.typeParameters!); const only = parent.typeParameters!.length === 1; - //TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag + // TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag const messageAndArg: DiagnosticAndArguments = only ? [Diagnostics._0_is_declared_but_its_value_is_never_read, name] : [Diagnostics.All_type_parameters_are_unused]; - addDiagnostic(typeParameter, UnusedKind.Parameter, createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, ...messageAndArg)); + addDiagnostic( + typeParameter, + UnusedKind.Parameter, + createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, ...messageAndArg), + ); } } else { - //TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag - addDiagnostic(typeParameter, UnusedKind.Parameter, createDiagnosticForNode(typeParameter, Diagnostics._0_is_declared_but_its_value_is_never_read, name)); + // TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag + addDiagnostic( + typeParameter, + UnusedKind.Parameter, + createDiagnosticForNode( + typeParameter, + Diagnostics._0_is_declared_but_its_value_is_never_read, + name, + ), + ); } } } function isTypeParameterUnused(typeParameter: TypeParameterDeclaration): boolean { - return !(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderscore(typeParameter.name); + return !(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) + && !isIdentifierThatStartsWithUnderscore(typeParameter.name); } function addToGroup(map: Map, key: K, value: V, getKey: (key: K) => number | string): void { @@ -40692,8 +52434,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return isIdentifierThatStartsWithUnderscore(declaration.name); } - return isAmbientModule(declaration) || - (isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) || isImportedDeclaration(declaration)) && isIdentifierThatStartsWithUnderscore(declaration.name!); + return isAmbientModule(declaration) + || (isVariableDeclaration(declaration) && isForInOrOfStatement(declaration.parent.parent) + || isImportedDeclaration(declaration)) && isIdentifierThatStartsWithUnderscore(declaration.name!); } function checkUnusedLocalsAndParameters(nodeWithLocals: HasLocals, addDiagnostic: AddUnusedDiagnostic): void { @@ -40704,7 +52447,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { nodeWithLocals.locals!.forEach(local => { // If it's purely a type parameter, ignore, will be checked in `checkUnusedTypeParameters`. // If it's a type parameter merged with a parameter, check if the parameter-side is used. - if (local.flags & SymbolFlags.TypeParameter ? !(local.flags & SymbolFlags.Variable && !(local.isReferenced! & SymbolFlags.Variable)) : local.isReferenced || local.exportSymbol) { + if ( + local.flags & SymbolFlags.TypeParameter + ? !(local.flags & SymbolFlags.Variable && !(local.isReferenced! & SymbolFlags.Variable)) + : local.isReferenced || local.exportSymbol + ) { return; } @@ -40727,20 +52474,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (isVariableDeclaration(declaration)) { const blockScopeKind = getCombinedNodeFlagsCached(declaration) & NodeFlags.BlockScoped; const name = getNameOfDeclaration(declaration); - if (blockScopeKind !== NodeFlags.Using && blockScopeKind !== NodeFlags.AwaitUsing || !name || !isIdentifierThatStartsWithUnderscore(name)) { + if ( + blockScopeKind !== NodeFlags.Using && blockScopeKind !== NodeFlags.AwaitUsing || !name + || !isIdentifierThatStartsWithUnderscore(name) + ) { addToGroup(unusedVariables, declaration.parent, declaration, getNodeId); } } else { - const parameter = local.valueDeclaration && tryGetRootParameterDeclaration(local.valueDeclaration); + const parameter = local.valueDeclaration + && tryGetRootParameterDeclaration(local.valueDeclaration); const name = local.valueDeclaration && getNameOfDeclaration(local.valueDeclaration); if (parameter && name) { - if (!isParameterPropertyDeclaration(parameter, parameter.parent) && !parameterIsThisKeyword(parameter) && !isIdentifierThatStartsWithUnderscore(name)) { + if ( + !isParameterPropertyDeclaration(parameter, parameter.parent) + && !parameterIsThisKeyword(parameter) && !isIdentifierThatStartsWithUnderscore(name) + ) { if (isBindingElement(declaration) && isArrayBindingPattern(declaration.parent)) { addToGroup(unusedDestructures, declaration.parent, declaration, getNodeId); } else { - addDiagnostic(parameter, UnusedKind.Parameter, createDiagnosticForNode(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local))); + addDiagnostic( + parameter, + UnusedKind.Parameter, + createDiagnosticForNode( + name, + Diagnostics._0_is_declared_but_its_value_is_never_read, + symbolName(local), + ), + ); } } } @@ -40753,46 +52515,95 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); unusedImports.forEach(([importClause, unuseds]) => { const importDecl = importClause.parent; - const nDeclarations = (importClause.name ? 1 : 0) + - (importClause.namedBindings ? - (importClause.namedBindings.kind === SyntaxKind.NamespaceImport ? 1 : importClause.namedBindings.elements.length) + const nDeclarations = (importClause.name ? 1 : 0) + + (importClause.namedBindings + ? (importClause.namedBindings.kind === SyntaxKind.NamespaceImport ? 1 + : importClause.namedBindings.elements.length) : 0); if (nDeclarations === unuseds.length) { - addDiagnostic(importDecl, UnusedKind.Local, unuseds.length === 1 - ? createDiagnosticForNode(importDecl, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(first(unuseds).name!)) - : createDiagnosticForNode(importDecl, Diagnostics.All_imports_in_import_declaration_are_unused)); + addDiagnostic( + importDecl, + UnusedKind.Local, + unuseds.length === 1 + ? createDiagnosticForNode( + importDecl, + Diagnostics._0_is_declared_but_its_value_is_never_read, + idText(first(unuseds).name!), + ) + : createDiagnosticForNode(importDecl, Diagnostics.All_imports_in_import_declaration_are_unused), + ); } else { for (const unused of unuseds) errorUnusedLocal(unused, idText(unused.name!), addDiagnostic); } }); unusedDestructures.forEach(([bindingPattern, bindingElements]) => { - const kind = tryGetRootParameterDeclaration(bindingPattern.parent) ? UnusedKind.Parameter : UnusedKind.Local; + const kind = tryGetRootParameterDeclaration(bindingPattern.parent) ? UnusedKind.Parameter + : UnusedKind.Local; if (bindingPattern.elements.length === bindingElements.length) { - if (bindingElements.length === 1 && bindingPattern.parent.kind === SyntaxKind.VariableDeclaration && bindingPattern.parent.parent.kind === SyntaxKind.VariableDeclarationList) { + if ( + bindingElements.length === 1 && bindingPattern.parent.kind === SyntaxKind.VariableDeclaration + && bindingPattern.parent.parent.kind === SyntaxKind.VariableDeclarationList + ) { addToGroup(unusedVariables, bindingPattern.parent.parent, bindingPattern.parent, getNodeId); } else { - addDiagnostic(bindingPattern, kind, bindingElements.length === 1 - ? createDiagnosticForNode(bindingPattern, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(first(bindingElements).name)) - : createDiagnosticForNode(bindingPattern, Diagnostics.All_destructured_elements_are_unused)); + addDiagnostic( + bindingPattern, + kind, + bindingElements.length === 1 + ? createDiagnosticForNode( + bindingPattern, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(first(bindingElements).name), + ) + : createDiagnosticForNode(bindingPattern, Diagnostics.All_destructured_elements_are_unused), + ); } } else { for (const e of bindingElements) { - addDiagnostic(e, kind, createDiagnosticForNode(e, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(e.name))); + addDiagnostic( + e, + kind, + createDiagnosticForNode( + e, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(e.name), + ), + ); } } }); unusedVariables.forEach(([declarationList, declarations]) => { if (declarationList.declarations.length === declarations.length) { - addDiagnostic(declarationList, UnusedKind.Local, declarations.length === 1 - ? createDiagnosticForNode(first(declarations).name, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(first(declarations).name)) - : createDiagnosticForNode(declarationList.parent.kind === SyntaxKind.VariableStatement ? declarationList.parent : declarationList, Diagnostics.All_variables_are_unused)); + addDiagnostic( + declarationList, + UnusedKind.Local, + declarations.length === 1 + ? createDiagnosticForNode( + first(declarations).name, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(first(declarations).name), + ) + : createDiagnosticForNode( + declarationList.parent.kind === SyntaxKind.VariableStatement ? declarationList.parent + : declarationList, + Diagnostics.All_variables_are_unused, + ), + ); } else { for (const decl of declarations) { - addDiagnostic(decl, UnusedKind.Local, createDiagnosticForNode(decl, Diagnostics._0_is_declared_but_its_value_is_never_read, bindingNameText(decl.name))); + addDiagnostic( + decl, + UnusedKind.Local, + createDiagnosticForNode( + decl, + Diagnostics._0_is_declared_but_its_value_is_never_read, + bindingNameText(decl.name), + ), + ); } } }); @@ -40802,13 +52613,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const node of potentialUnusedRenamedBindingElementsInTypes) { if (!getSymbolOfDeclaration(node)?.isReferenced) { const wrappingDeclaration = walkUpBindingElementsAndPatterns(node); - Debug.assert(isParameterDeclaration(wrappingDeclaration), "Only parameter declaration should be checked here"); - const diagnostic = createDiagnosticForNode(node.name, Diagnostics._0_is_an_unused_renaming_of_1_Did_you_intend_to_use_it_as_a_type_annotation, declarationNameToString(node.name), declarationNameToString(node.propertyName)); + Debug.assert( + isParameterDeclaration(wrappingDeclaration), + "Only parameter declaration should be checked here", + ); + const diagnostic = createDiagnosticForNode( + node.name, + Diagnostics._0_is_an_unused_renaming_of_1_Did_you_intend_to_use_it_as_a_type_annotation, + declarationNameToString(node.name), + declarationNameToString(node.propertyName), + ); if (!wrappingDeclaration.type) { // entire parameter does not have type annotation, suggest adding an annotation addRelatedInfo( diagnostic, - createFileDiagnostic(getSourceFileOfNode(wrappingDeclaration), wrappingDeclaration.end, 1, Diagnostics.We_can_only_write_a_type_for_0_by_adding_a_type_for_the_entire_parameter_here, declarationNameToString(node.propertyName)) + createFileDiagnostic( + getSourceFileOfNode(wrappingDeclaration), + wrappingDeclaration.end, + 1, + Diagnostics.We_can_only_write_a_type_for_0_by_adding_a_type_for_the_entire_parameter_here, + declarationNameToString(node.propertyName), + ), ); } diagnostics.add(diagnostic); @@ -40830,10 +52655,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type ImportedDeclaration = ImportClause | ImportSpecifier | NamespaceImport; function isImportedDeclaration(node: Node): node is ImportedDeclaration { - return node.kind === SyntaxKind.ImportClause || node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.NamespaceImport; + return node.kind === SyntaxKind.ImportClause || node.kind === SyntaxKind.ImportSpecifier + || node.kind === SyntaxKind.NamespaceImport; } function importClauseFromImported(decl: ImportedDeclaration): ImportClause { - return decl.kind === SyntaxKind.ImportClause ? decl : decl.kind === SyntaxKind.NamespaceImport ? decl.parent : decl.parent.parent; + return decl.kind === SyntaxKind.ImportClause ? decl + : decl.kind === SyntaxKind.NamespaceImport ? decl.parent : decl.parent.parent; } function checkBlock(node: Block) { @@ -40856,13 +52683,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { // no rest parameters \ declaration context \ overload - no codegen impact - if (languageVersion >= ScriptTarget.ES2015 || !hasRestParameter(node) || node.flags & NodeFlags.Ambient || nodeIsMissing((node as FunctionLikeDeclaration).body)) { + if ( + languageVersion >= ScriptTarget.ES2015 || !hasRestParameter(node) || node.flags & NodeFlags.Ambient + || nodeIsMissing((node as FunctionLikeDeclaration).body) + ) { return; } forEach(node.parameters, p => { if (p.name && !isBindingPattern(p.name) && p.name.escapedText === argumentsSymbol.escapedName) { - errorSkippedOn("noEmit", p, Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters); + errorSkippedOn( + "noEmit", + p, + Diagnostics.Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters, + ); } }); } @@ -40877,13 +52711,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - if (node.kind === SyntaxKind.PropertyDeclaration || - node.kind === SyntaxKind.PropertySignature || - node.kind === SyntaxKind.MethodDeclaration || - node.kind === SyntaxKind.MethodSignature || - node.kind === SyntaxKind.GetAccessor || - node.kind === SyntaxKind.SetAccessor || - node.kind === SyntaxKind.PropertyAssignment) { + if ( + node.kind === SyntaxKind.PropertyDeclaration + || node.kind === SyntaxKind.PropertySignature + || node.kind === SyntaxKind.MethodDeclaration + || node.kind === SyntaxKind.MethodSignature + || node.kind === SyntaxKind.GetAccessor + || node.kind === SyntaxKind.SetAccessor + || node.kind === SyntaxKind.PropertyAssignment + ) { // it is ok to have member named '_super', '_this', `Promise`, etc. - member access is always qualified return false; } @@ -40915,10 +52751,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureThis) { const isDeclaration = node.kind !== SyntaxKind.Identifier; if (isDeclaration) { - error(getNameOfDeclaration(node as Declaration), Diagnostics.Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference); + error( + getNameOfDeclaration(node as Declaration), + Diagnostics + .Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference, + ); } else { - error(node, Diagnostics.Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference); + error( + node, + Diagnostics + .Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference, + ); } return true; } @@ -40931,10 +52775,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureNewTarget) { const isDeclaration = node.kind !== SyntaxKind.Identifier; if (isDeclaration) { - error(getNameOfDeclaration(node as Declaration), Diagnostics.Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference); + error( + getNameOfDeclaration(node as Declaration), + Diagnostics + .Duplicate_identifier_newTarget_Compiler_uses_variable_declaration_newTarget_to_capture_new_target_meta_property_reference, + ); } else { - error(node, Diagnostics.Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference); + error( + node, + Diagnostics + .Expression_resolves_to_variable_declaration_newTarget_that_compiler_uses_to_capture_new_target_meta_property_reference, + ); } return true; } @@ -40944,11 +52796,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier | undefined) { // No need to check for require or exports for ES6 modules and later - if (moduleKind >= ModuleKind.ES2015 && !(moduleKind >= ModuleKind.Node16 && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) { + if ( + moduleKind >= ModuleKind.ES2015 + && !(moduleKind >= ModuleKind.Node16 && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + ) { return; } - if (!name || !needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) { + if ( + !name + || !needCollisionCheckForIdentifier(node, name, "require") + && !needCollisionCheckForIdentifier(node, name, "exports") + ) { return; } @@ -40961,13 +52820,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = getDeclarationContainer(node); if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile)) { // If the declaration happens to be in external module, report error that require and exports are reserved keywords - errorSkippedOn("noEmit", name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, - declarationNameToString(name), declarationNameToString(name)); + errorSkippedOn( + "noEmit", + name, + Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, + declarationNameToString(name), + declarationNameToString(name), + ); } } function checkCollisionWithGlobalPromiseInGeneratedCode(node: Node, name: Identifier | undefined): void { - if (!name || languageVersion >= ScriptTarget.ES2017 || !needCollisionCheckForIdentifier(node, name, "Promise")) { + if ( + !name || languageVersion >= ScriptTarget.ES2017 || !needCollisionCheckForIdentifier(node, name, "Promise") + ) { return; } @@ -40978,16 +52844,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent const parent = getDeclarationContainer(node); - if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile) && parent.flags & NodeFlags.HasAsyncFunctions) { + if ( + parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent as SourceFile) + && parent.flags & NodeFlags.HasAsyncFunctions + ) { // If the declaration happens to be in external module, report error that Promise is a reserved identifier. - errorSkippedOn("noEmit", name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions, - declarationNameToString(name), declarationNameToString(name)); + errorSkippedOn( + "noEmit", + name, + Diagnostics + .Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module_containing_async_functions, + declarationNameToString(name), + declarationNameToString(name), + ); } } function recordPotentialCollisionWithWeakMapSetInGeneratedCode(node: Node, name: Identifier): void { - if (languageVersion <= ScriptTarget.ES2021 - && (needCollisionCheckForIdentifier(node, name, "WeakMap") || needCollisionCheckForIdentifier(node, name, "WeakSet"))) { + if ( + languageVersion <= ScriptTarget.ES2021 + && (needCollisionCheckForIdentifier(node, name, "WeakMap") + || needCollisionCheckForIdentifier(node, name, "WeakSet")) + ) { potentialWeakMapSetCollisions.push(node); } } @@ -40995,14 +52873,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkWeakMapSetCollision(node: Node) { const enclosingBlockScope = getEnclosingBlockScopeContainer(node); if (getNodeCheckFlags(enclosingBlockScope) & NodeCheckFlags.ContainsClassWithPrivateIdentifiers) { - Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name) && typeof node.name.escapedText === "string", "The target of a WeakMap/WeakSet collision check should be an identifier"); - errorSkippedOn("noEmit", node, Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, node.name.escapedText); + Debug.assert( + isNamedDeclaration(node) && isIdentifier(node.name) && typeof node.name.escapedText === "string", + "The target of a WeakMap/WeakSet collision check should be an identifier", + ); + errorSkippedOn( + "noEmit", + node, + Diagnostics.Compiler_reserves_name_0_when_emitting_private_identifier_downlevel, + node.name.escapedText, + ); } } function recordPotentialCollisionWithReflectInGeneratedCode(node: Node, name: Identifier | undefined): void { - if (name && languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 - && needCollisionCheckForIdentifier(node, name, "Reflect")) { + if ( + name && languageVersion >= ScriptTarget.ES2015 && languageVersion <= ScriptTarget.ES2021 + && needCollisionCheckForIdentifier(node, name, "Reflect") + ) { potentialReflectCollisions.push(node); } } @@ -41031,10 +52919,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (hasCollision) { - Debug.assert(isNamedDeclaration(node) && isIdentifier(node.name), "The target of a Reflect collision check should be an identifier"); - errorSkippedOn("noEmit", node, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers, + Debug.assert( + isNamedDeclaration(node) && isIdentifier(node.name), + "The target of a Reflect collision check should be an identifier", + ); + errorSkippedOn( + "noEmit", + node, + Diagnostics + .Duplicate_identifier_0_Compiler_reserves_name_1_when_emitting_super_references_in_static_initializers, declarationNameToString(node.name), - "Reflect"); + "Reflect", + ); } } @@ -41092,12 +52988,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getSymbolOfDeclaration(node); if (symbol.flags & SymbolFlags.FunctionScopedVariable) { if (!isIdentifier(node.name)) return Debug.fail(); - const localDeclarationSymbol = resolveName(node, node.name.escapedText, SymbolFlags.Variable, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); - if (localDeclarationSymbol && - localDeclarationSymbol !== symbol && - localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { + const localDeclarationSymbol = resolveName( + node, + node.name.escapedText, + SymbolFlags.Variable, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ); + if ( + localDeclarationSymbol + && localDeclarationSymbol !== symbol + && localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable + ) { if (getDeclarationNodeFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { - const varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList)!; + const varDeclList = getAncestor( + localDeclarationSymbol.valueDeclaration, + SyntaxKind.VariableDeclarationList, + )!; const container = varDeclList.parent.kind === SyntaxKind.VariableStatement && varDeclList.parent.parent ? varDeclList.parent.parent @@ -41105,18 +53013,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // names of block-scoped and function scoped variables can collide only // if block scoped variable is defined in the function\module\source file scope (because of variable hoisting) - const namesShareScope = - container && - (container.kind === SyntaxKind.Block && isFunctionLike(container.parent) || - container.kind === SyntaxKind.ModuleBlock || - container.kind === SyntaxKind.ModuleDeclaration || - container.kind === SyntaxKind.SourceFile); + const namesShareScope = container + && (container.kind === SyntaxKind.Block && isFunctionLike(container.parent) + || container.kind === SyntaxKind.ModuleBlock + || container.kind === SyntaxKind.ModuleDeclaration + || container.kind === SyntaxKind.SourceFile); // here we know that function scoped variable is "shadowed" by block scoped one // a var declatation can't hoist past a lexical declaration and it results in a SyntaxError at runtime if (!namesShareScope) { const name = symbolToString(localDeclarationSymbol); - error(node, Diagnostics.Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, name, name); + error( + node, + Diagnostics + .Cannot_initialize_outer_scoped_variable_0_in_the_same_scope_as_block_scoped_declaration_1, + name, + name, + ); } } } @@ -41128,7 +53041,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Check variable, parameter, or property declaration - function checkVariableLikeDeclaration(node: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement) { + function checkVariableLikeDeclaration( + node: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement, + ) { checkDecorators(node); if (!isBindingElement(node)) { checkSourceElement(node.type); @@ -41152,10 +53067,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isBindingElement(node)) { if ( - node.propertyName && - isIdentifier(node.name) && - isParameterDeclaration(node) && - nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body)) { + node.propertyName + && isIdentifier(node.name) + && isParameterDeclaration(node) + && nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body) + ) { // type F = ({a: string}) => void; // ^^^^^^ // variable renaming in function type notation is confusing, @@ -41183,8 +53099,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const nameText = getPropertyNameFromType(exprType); const property = getPropertyOfType(parentType, nameText); if (property) { - markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isSelfTypeAccess*/ false); // A destructuring is never a write-only reference. - checkPropertyAccessibility(node, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, /*writing*/ false, parentType, property); + markPropertyAsReferenced( + property, + /*nodeForCheckWriteOnly*/ undefined, + /*isSelfTypeAccess*/ false, + ); // A destructuring is never a write-only reference. + checkPropertyAccessibility( + node, + !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, + /*writing*/ false, + parentType, + property, + ); } } } @@ -41192,15 +53118,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // For a binding pattern, check contained binding elements if (isBindingPattern(node.name)) { - if (node.name.kind === SyntaxKind.ArrayBindingPattern && languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) { + if ( + node.name.kind === SyntaxKind.ArrayBindingPattern && languageVersion < ScriptTarget.ES2015 + && compilerOptions.downlevelIteration + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Read); } forEach(node.name.elements, checkSourceElement); } // For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body - if (isParameter(node) && node.initializer && nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body)) { - error(node, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); + if ( + isParameter(node) && node.initializer + && nodeIsMissing((getContainingFunction(node) as FunctionLikeDeclaration).body) + ) { + error( + node, + Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation, + ); return; } // For a binding pattern, validate the initializer and exit @@ -41208,7 +53143,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInAmbientOrTypeNode(node)) { return; } - const needCheckInitializer = hasOnlyExpressionInitializer(node) && node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement; + const needCheckInitializer = hasOnlyExpressionInitializer(node) && node.initializer + && node.parent.parent.kind !== SyntaxKind.ForInStatement; const needCheckWidenedType = !some(node.name.elements, not(isOmittedExpression)); if (needCheckInitializer || needCheckWidenedType) { // Don't validate for-in initializer as it is already an error @@ -41219,7 +53155,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkNonNullNonVoidType(initializerType, node); } else { - checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer); + checkTypeAssignableToAndOptionallyElaborate( + initializerType, + getWidenedTypeForVariableLikeDeclaration(node), + node, + node.initializer, + ); } } // check the binding pattern with empty elements @@ -41236,7 +53177,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // For a commonjs `const x = require`, validate the alias and exit const symbol = getSymbolOfDeclaration(node); - if (symbol.flags & SymbolFlags.Alias && (isVariableDeclarationInitializedToBareOrAccessedRequire(node) || isBindingElementOfBareOrAccessedRequire(node))) { + if ( + symbol.flags & SymbolFlags.Alias + && (isVariableDeclarationInitializedToBareOrAccessedRequire(node) + || isBindingElementOfBareOrAccessedRequire(node)) + ) { checkAliasSymbol(node); return; } @@ -41247,34 +53192,70 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't validate for-in initializer as it is already an error const initializer = hasOnlyExpressionInitializer(node) && getEffectiveInitializer(node); if (initializer) { - const isJSObjectLiteralInitializer = isInJSFile(node) && - isObjectLiteralExpression(initializer) && - (initializer.properties.length === 0 || isPrototypeAccess(node.name)) && - !!symbol.exports?.size; + const isJSObjectLiteralInitializer = isInJSFile(node) + && isObjectLiteralExpression(initializer) + && (initializer.properties.length === 0 || isPrototypeAccess(node.name)) + && !!symbol.exports?.size; if (!isJSObjectLiteralInitializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) { const initializerType = checkExpressionCached(initializer); - checkTypeAssignableToAndOptionallyElaborate(initializerType, type, node, initializer, /*headMessage*/ undefined); + checkTypeAssignableToAndOptionallyElaborate( + initializerType, + type, + node, + initializer, + /*headMessage*/ undefined, + ); const blockScopeKind = getCombinedNodeFlagsCached(node) & NodeFlags.BlockScoped; if (blockScopeKind === NodeFlags.AwaitUsing) { const globalAsyncDisposableType = getGlobalAsyncDisposableType(/*reportErrors*/ true); const globalDisposableType = getGlobalDisposableType(/*reportErrors*/ true); if (globalAsyncDisposableType !== emptyObjectType && globalDisposableType !== emptyObjectType) { - const optionalDisposableType = getUnionType([globalAsyncDisposableType, globalDisposableType, nullType, undefinedType]); - checkTypeAssignableTo(initializerType, optionalDisposableType, initializer, Diagnostics.The_initializer_of_an_await_using_declaration_must_be_either_an_object_with_a_Symbol_asyncDispose_or_Symbol_dispose_method_or_be_null_or_undefined); + const optionalDisposableType = getUnionType([ + globalAsyncDisposableType, + globalDisposableType, + nullType, + undefinedType, + ]); + checkTypeAssignableTo( + initializerType, + optionalDisposableType, + initializer, + Diagnostics + .The_initializer_of_an_await_using_declaration_must_be_either_an_object_with_a_Symbol_asyncDispose_or_Symbol_dispose_method_or_be_null_or_undefined, + ); } } else if (blockScopeKind === NodeFlags.Using) { const globalDisposableType = getGlobalDisposableType(/*reportErrors*/ true); if (globalDisposableType !== emptyObjectType) { - const optionalDisposableType = getUnionType([globalDisposableType, nullType, undefinedType]); - checkTypeAssignableTo(initializerType, optionalDisposableType, initializer, Diagnostics.The_initializer_of_a_using_declaration_must_be_either_an_object_with_a_Symbol_dispose_method_or_be_null_or_undefined); + const optionalDisposableType = getUnionType([ + globalDisposableType, + nullType, + undefinedType, + ]); + checkTypeAssignableTo( + initializerType, + optionalDisposableType, + initializer, + Diagnostics + .The_initializer_of_a_using_declaration_must_be_either_an_object_with_a_Symbol_dispose_method_or_be_null_or_undefined, + ); } } } } if (symbol.declarations && symbol.declarations.length > 1) { - if (some(symbol.declarations, d => d !== node && isVariableLike(d) && !areDeclarationFlagsIdentical(d, node))) { - error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); + if ( + some( + symbol.declarations, + d => d !== node && isVariableLike(d) && !areDeclarationFlagsIdentical(d, node), + ) + ) { + error( + node.name, + Diagnostics.All_declarations_of_0_must_have_identical_modifiers, + declarationNameToString(node.name), + ); } } } @@ -41283,16 +53264,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // initializer is consistent with type associated with the node const declarationType = convertAutoToAny(getWidenedTypeForVariableLikeDeclaration(node)); - if (!isErrorType(type) && !isErrorType(declarationType) && - !isTypeIdenticalTo(type, declarationType) && - !(symbol.flags & SymbolFlags.Assignment)) { - errorNextVariableOrPropertyDeclarationMustHaveSameType(symbol.valueDeclaration, type, node, declarationType); + if ( + !isErrorType(type) && !isErrorType(declarationType) + && !isTypeIdenticalTo(type, declarationType) + && !(symbol.flags & SymbolFlags.Assignment) + ) { + errorNextVariableOrPropertyDeclarationMustHaveSameType( + symbol.valueDeclaration, + type, + node, + declarationType, + ); } if (hasOnlyExpressionInitializer(node) && node.initializer) { - checkTypeAssignableToAndOptionallyElaborate(checkExpressionCached(node.initializer), declarationType, node, node.initializer, /*headMessage*/ undefined); + checkTypeAssignableToAndOptionallyElaborate( + checkExpressionCached(node.initializer), + declarationType, + node, + node.initializer, + /*headMessage*/ undefined, + ); } if (symbol.valueDeclaration && !areDeclarationFlagsIdentical(node, symbol.valueDeclaration)) { - error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_modifiers, declarationNameToString(node.name)); + error( + node.name, + Diagnostics.All_declarations_of_0_must_have_identical_modifiers, + declarationNameToString(node.name), + ); } } if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) { @@ -41305,29 +53303,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function errorNextVariableOrPropertyDeclarationMustHaveSameType(firstDeclaration: Declaration | undefined, firstType: Type, nextDeclaration: Declaration, nextType: Type): void { + function errorNextVariableOrPropertyDeclarationMustHaveSameType( + firstDeclaration: Declaration | undefined, + firstType: Type, + nextDeclaration: Declaration, + nextType: Type, + ): void { const nextDeclarationName = getNameOfDeclaration(nextDeclaration); - const message = nextDeclaration.kind === SyntaxKind.PropertyDeclaration || nextDeclaration.kind === SyntaxKind.PropertySignature - ? Diagnostics.Subsequent_property_declarations_must_have_the_same_type_Property_0_must_be_of_type_1_but_here_has_type_2 - : Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2; + const message = nextDeclaration.kind === SyntaxKind.PropertyDeclaration + || nextDeclaration.kind === SyntaxKind.PropertySignature + ? Diagnostics + .Subsequent_property_declarations_must_have_the_same_type_Property_0_must_be_of_type_1_but_here_has_type_2 + : Diagnostics + .Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2; const declName = declarationNameToString(nextDeclarationName); const err = error( nextDeclarationName, message, declName, typeToString(firstType), - typeToString(nextType) + typeToString(nextType), ); if (firstDeclaration) { - addRelatedInfo(err, - createDiagnosticForNode(firstDeclaration, Diagnostics._0_was_also_declared_here, declName) + addRelatedInfo( + err, + createDiagnosticForNode(firstDeclaration, Diagnostics._0_was_also_declared_here, declName), ); } } function areDeclarationFlagsIdentical(left: Declaration, right: Declaration) { - if ((left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) || - (left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter)) { + if ( + (left.kind === SyntaxKind.Parameter && right.kind === SyntaxKind.VariableDeclaration) + || (left.kind === SyntaxKind.VariableDeclaration && right.kind === SyntaxKind.Parameter) + ) { // Differences in optionality between parameters and variables are allowed. return true; } @@ -41336,18 +53345,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - const interestingFlags = ModifierFlags.Private | - ModifierFlags.Protected | - ModifierFlags.Async | - ModifierFlags.Abstract | - ModifierFlags.Readonly | - ModifierFlags.Static; + const interestingFlags = ModifierFlags.Private + | ModifierFlags.Protected + | ModifierFlags.Async + | ModifierFlags.Abstract + | ModifierFlags.Readonly + | ModifierFlags.Static; - return getSelectedEffectiveModifierFlags(left, interestingFlags) === getSelectedEffectiveModifierFlags(right, interestingFlags); + return getSelectedEffectiveModifierFlags(left, interestingFlags) + === getSelectedEffectiveModifierFlags(right, interestingFlags); } function checkVariableDeclaration(node: VariableDeclaration) { - tracing?.push(tracing.Phase.Check, "checkVariableDeclaration", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + tracing?.push(tracing.Phase.Check, "checkVariableDeclaration", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); checkGrammarVariableDeclaration(node); checkVariableLikeDeclaration(node); tracing?.pop(); @@ -41369,7 +53384,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkVariableStatement(node: VariableStatement) { // Grammar checking - if (!checkGrammarModifiers(node) && !checkGrammarVariableDeclarationList(node.declarationList)) checkGrammarForDisallowedBlockScopedVariableStatement(node); + if (!checkGrammarModifiers(node) && !checkGrammarVariableDeclarationList(node.declarationList)) { + checkGrammarForDisallowedBlockScopedVariableStatement(node); + } checkVariableDeclarationList(node.declarationList); } @@ -41394,7 +53411,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkSourceElement(node.elseStatement); } - function checkTestingKnownTruthyCallableOrAwaitableType(condExpr: Expression, condType: Type, body?: Statement | Expression) { + function checkTestingKnownTruthyCallableOrAwaitableType( + condExpr: Expression, + condType: Type, + body?: Statement | Expression, + ) { if (!strictNullChecks) return; bothHelper(condExpr, body); @@ -41403,14 +53424,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { helper(condExpr, body); - while (isBinaryExpression(condExpr) && (condExpr.operatorToken.kind === SyntaxKind.BarBarToken || condExpr.operatorToken.kind === SyntaxKind.QuestionQuestionToken)) { + while ( + isBinaryExpression(condExpr) + && (condExpr.operatorToken.kind === SyntaxKind.BarBarToken + || condExpr.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + ) { condExpr = skipParentheses(condExpr.left); helper(condExpr, body); } } function helper(condExpr: Expression, body: Expression | Statement | undefined) { - const location = isLogicalOrCoalescingBinaryExpression(condExpr) ? skipParentheses(condExpr.right) : condExpr; + const location = isLogicalOrCoalescingBinaryExpression(condExpr) ? skipParentheses(condExpr.right) + : condExpr; if (isModuleExportsAccessExpression(location)) { return; } @@ -41419,7 +53445,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } const type = location === condExpr ? condType : checkTruthinessExpression(location); - const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression); + const isPropertyExpressionCast = isPropertyAccessExpression(location) + && isTypeAssertion(location.expression); if (!(getTypeFacts(type) & TypeFacts.Truthy) || isPropertyExpressionCast) return; // While it technically should be invalid for any known-truthy value @@ -41441,7 +53468,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } - const isUsed = testedSymbol && isBinaryExpression(condExpr.parent) && isSymbolUsedInBinaryExpressionChain(condExpr.parent, testedSymbol) + const isUsed = testedSymbol && isBinaryExpression(condExpr.parent) + && isSymbolUsedInBinaryExpressionChain(condExpr.parent, testedSymbol) || testedSymbol && body && isSymbolUsedInConditionBody(condExpr, body, testedNode, testedSymbol); if (!isUsed) { if (isPromise) { @@ -41449,16 +53477,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { location, /*maybeMissingAwait*/ true, Diagnostics.This_condition_will_always_return_true_since_this_0_is_always_defined, - getTypeNameForErrorDisplay(type)); + getTypeNameForErrorDisplay(type), + ); } else { - error(location, Diagnostics.This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead); + error( + location, + Diagnostics + .This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead, + ); } } } } - function isSymbolUsedInConditionBody(expr: Expression, body: Statement | Expression, testedNode: Node, testedSymbol: Symbol): boolean { + function isSymbolUsedInConditionBody( + expr: Expression, + body: Statement | Expression, + testedNode: Node, + testedSymbol: Symbol, + ): boolean { return !!forEachChild(body, function check(childNode): boolean | undefined { if (isIdentifier(childNode)) { const childSymbol = getSymbolAtLocation(childNode); @@ -41471,12 +53509,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let testedExpression = testedNode.parent; let childExpression = childNode.parent; while (testedExpression && childExpression) { - if (isIdentifier(testedExpression) && isIdentifier(childExpression) || - testedExpression.kind === SyntaxKind.ThisKeyword && childExpression.kind === SyntaxKind.ThisKeyword) { + if ( + isIdentifier(testedExpression) && isIdentifier(childExpression) + || testedExpression.kind === SyntaxKind.ThisKeyword + && childExpression.kind === SyntaxKind.ThisKeyword + ) { return getSymbolAtLocation(testedExpression) === getSymbolAtLocation(childExpression); } - else if (isPropertyAccessExpression(testedExpression) && isPropertyAccessExpression(childExpression)) { - if (getSymbolAtLocation(testedExpression.name) !== getSymbolAtLocation(childExpression.name)) { + else if ( + isPropertyAccessExpression(testedExpression) && isPropertyAccessExpression(childExpression) + ) { + if ( + getSymbolAtLocation(testedExpression.name) !== getSymbolAtLocation(childExpression.name) + ) { return false; } childExpression = childExpression.expression; @@ -41573,11 +53618,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const container = getContainingFunctionOrClassStaticBlock(node); if (node.awaitModifier) { if (container && isClassStaticBlockDeclaration(container)) { - grammarErrorOnNode(node.awaitModifier, Diagnostics.for_await_loops_cannot_be_used_inside_a_class_static_block); + grammarErrorOnNode( + node.awaitModifier, + Diagnostics.for_await_loops_cannot_be_used_inside_a_class_static_block, + ); } else { const functionFlags = getFunctionFlags(container); - if ((functionFlags & (FunctionFlags.Invalid | FunctionFlags.Async)) === FunctionFlags.Async && languageVersion < ScriptTarget.ESNext) { + if ( + (functionFlags & (FunctionFlags.Invalid | FunctionFlags.Async)) === FunctionFlags.Async + && languageVersion < ScriptTarget.ESNext + ) { // for..await..of in an async function or async generator function prior to ESNext requires the __asyncValues helper checkExternalEmitHelpers(node, ExternalEmitHelpers.ForAwaitOfIncludes); } @@ -41601,7 +53652,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const iteratedType = checkRightHandSideOfForOf(node); // There may be a destructuring assignment on the left side - if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { + if ( + varExpr.kind === SyntaxKind.ArrayLiteralExpression + || varExpr.kind === SyntaxKind.ObjectLiteralExpression + ) { // iteratedType may be undefined. In this case, we still want to check the structure of // varExpr, in particular making sure it's a valid LeftHandSideExpression. But we'd like // to short circuit the type relation checking as much as possible, so we pass the unknownType. @@ -41612,7 +53666,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkReferenceExpression( varExpr, Diagnostics.The_left_hand_side_of_a_for_of_statement_must_be_a_variable_or_a_property_access, - Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_an_optional_property_access); + Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_an_optional_property_access, + ); // iteratedType will be undefined if the rightType was missing properties/signatures // required to get its iteratedType (like [Symbol.iterator] or next). This may be @@ -41643,7 +53698,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { const variable = (node.initializer as VariableDeclarationList).declarations[0]; if (variable && isBindingPattern(variable.name)) { - error(variable.name, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); + error( + variable.name, + Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern, + ); } checkVariableDeclarationList(node.initializer as VariableDeclarationList); } @@ -41654,7 +53712,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and Expr must be an expression of type Any, an object type, or a type parameter type. const varExpr = node.initializer; const leftType = checkExpression(varExpr); - if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) { + if ( + varExpr.kind === SyntaxKind.ArrayLiteralExpression + || varExpr.kind === SyntaxKind.ObjectLiteralExpression + ) { error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_destructuring_pattern); } else if (!isTypeAssignableTo(getIndexTypeOrString(rightType), leftType)) { @@ -41665,14 +53726,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkReferenceExpression( varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_a_variable_or_a_property_access, - Diagnostics.The_left_hand_side_of_a_for_in_statement_may_not_be_an_optional_property_access); + Diagnostics.The_left_hand_side_of_a_for_in_statement_may_not_be_an_optional_property_access, + ); } } // unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved // in this case error about missing name is already reported - do not report extra one - if (rightType === neverType || !isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive)) { - error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter_but_here_has_type_0, typeToString(rightType)); + if ( + rightType === neverType + || !isTypeAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) + ) { + error( + node.expression, + Diagnostics + .The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter_but_here_has_type_0, + typeToString(rightType), + ); } checkSourceElement(node.statement); @@ -41683,14 +53753,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkRightHandSideOfForOf(statement: ForOfStatement): Type { const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf; - return checkIteratedTypeOrElementType(use, checkNonNullExpression(statement.expression), undefinedType, statement.expression); + return checkIteratedTypeOrElementType( + use, + checkNonNullExpression(statement.expression), + undefinedType, + statement.expression, + ); } - function checkIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined): Type { + function checkIteratedTypeOrElementType( + use: IterationUse, + inputType: Type, + sentType: Type, + errorNode: Node | undefined, + ): Type { if (isTypeAny(inputType)) { return inputType; } - return getIteratedTypeOrElementType(use, inputType, sentType, errorNode, /*checkAssignability*/ true) || anyType; + return getIteratedTypeOrElementType(use, inputType, sentType, errorNode, /*checkAssignability*/ true) + || anyType; } /** @@ -41698,7 +53779,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * we want to get the iterated type of an iterable for ES2015 or later, or the iterated type * of a iterable (if defined globally) or element type of an array like for ES2015 or earlier. */ - function getIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined, checkAssignability: boolean): Type | undefined { + function getIteratedTypeOrElementType( + use: IterationUse, + inputType: Type, + sentType: Type, + errorNode: Node | undefined, + checkAssignability: boolean, + ): Type | undefined { const allowAsyncIterables = (use & IterationUse.AllowsAsyncIterablesFlag) !== 0; if (inputType === neverType) { reportTypeNotIterableError(errorNode!, inputType, allowAsyncIterables); // TODO: GH#18217 @@ -41707,29 +53794,43 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const uplevelIteration = languageVersion >= ScriptTarget.ES2015; const downlevelIteration = !uplevelIteration && compilerOptions.downlevelIteration; - const possibleOutOfBounds = compilerOptions.noUncheckedIndexedAccess && !!(use & IterationUse.PossiblyOutOfBounds); + const possibleOutOfBounds = compilerOptions.noUncheckedIndexedAccess + && !!(use & IterationUse.PossiblyOutOfBounds); // Get the iterated type of an `Iterable` or `IterableIterator` only in ES2015 // or higher, when inside of an async generator or for-await-if, or when // downlevelIteration is requested. if (uplevelIteration || downlevelIteration || allowAsyncIterables) { // We only report errors for an invalid iterable type in ES2015 or higher. - const iterationTypes = getIterationTypesOfIterable(inputType, use, uplevelIteration ? errorNode : undefined); + const iterationTypes = getIterationTypesOfIterable( + inputType, + use, + uplevelIteration ? errorNode : undefined, + ); if (checkAssignability) { if (iterationTypes) { - const diagnostic = - use & IterationUse.ForOfFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_for_of_will_always_send_0 : - use & IterationUse.SpreadFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_spread_will_always_send_0 : - use & IterationUse.DestructuringFlag ? Diagnostics.Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_destructuring_will_always_send_0 : - use & IterationUse.YieldStarFlag ? Diagnostics.Cannot_delegate_iteration_to_value_because_the_next_method_of_its_iterator_expects_type_1_but_the_containing_generator_will_always_send_0 : - undefined; + const diagnostic = use & IterationUse.ForOfFlag + ? Diagnostics + .Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_for_of_will_always_send_0 + : use & IterationUse.SpreadFlag + ? Diagnostics + .Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_spread_will_always_send_0 + : use & IterationUse.DestructuringFlag + ? Diagnostics + .Cannot_iterate_value_because_the_next_method_of_its_iterator_expects_type_1_but_array_destructuring_will_always_send_0 + : use & IterationUse.YieldStarFlag + ? Diagnostics + .Cannot_delegate_iteration_to_value_because_the_next_method_of_its_iterator_expects_type_1_but_the_containing_generator_will_always_send_0 + : undefined; if (diagnostic) { checkTypeAssignableTo(sentType, iterationTypes.nextType, errorNode, diagnostic); } } } if (iterationTypes || uplevelIteration) { - return possibleOutOfBounds ? includeUndefinedInIndexSignature(iterationTypes && iterationTypes.yieldType) : (iterationTypes && iterationTypes.yieldType); + return possibleOutOfBounds + ? includeUndefinedInIndexSignature(iterationTypes && iterationTypes.yieldType) + : (iterationTypes && iterationTypes.yieldType); } } @@ -41758,7 +53859,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (hasStringConstituent) { if (languageVersion < ScriptTarget.ES5) { if (errorNode) { - error(errorNode, Diagnostics.Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher); + error( + errorNode, + Diagnostics + .Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher, + ); reportedError = true; } } @@ -41779,14 +53884,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // number and string input is allowed, we want to say that number is not an // array type or a string type. const allowsStrings = !!(use & IterationUse.AllowsStringInputFlag) && !hasStringConstituent; - const [defaultDiagnostic, maybeMissingAwait] = getIterationDiagnosticDetails(allowsStrings, downlevelIteration); + const [defaultDiagnostic, maybeMissingAwait] = getIterationDiagnosticDetails( + allowsStrings, + downlevelIteration, + ); errorAndMaybeSuggestAwait( errorNode, maybeMissingAwait && !!getAwaitedTypeOfPromise(arrayType), defaultDiagnostic, - typeToString(arrayType)); + typeToString(arrayType), + ); } - return hasStringConstituent ? possibleOutOfBounds ? includeUndefinedInIndexSignature(stringType) : stringType : undefined; + return hasStringConstituent + ? possibleOutOfBounds ? includeUndefinedInIndexSignature(stringType) : stringType : undefined; } const arrayElementType = getIndexTypeOfType(arrayType, numberType); @@ -41796,26 +53906,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return stringType; } - return getUnionType(possibleOutOfBounds ? [arrayElementType, stringType, undefinedType] : [arrayElementType, stringType], UnionReduction.Subtype); + return getUnionType( + possibleOutOfBounds ? [arrayElementType, stringType, undefinedType] : [arrayElementType, stringType], + UnionReduction.Subtype, + ); } - return (use & IterationUse.PossiblyOutOfBounds) ? includeUndefinedInIndexSignature(arrayElementType) : arrayElementType; + return (use & IterationUse.PossiblyOutOfBounds) ? includeUndefinedInIndexSignature(arrayElementType) + : arrayElementType; - function getIterationDiagnosticDetails(allowsStrings: boolean, downlevelIteration: boolean | undefined): [error: DiagnosticMessage, maybeMissingAwait: boolean] { + function getIterationDiagnosticDetails( + allowsStrings: boolean, + downlevelIteration: boolean | undefined, + ): [error: DiagnosticMessage, maybeMissingAwait: boolean] { if (downlevelIteration) { return allowsStrings - ? [Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true] - : [Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, true]; - } - - const yieldType = getIterationTypeOfIterable(use, IterationTypeKind.Yield, inputType, /*errorNode*/ undefined); + ? [ + Diagnostics + .Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, + true, + ] + : [ + Diagnostics + .Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator, + true, + ]; + } + + const yieldType = getIterationTypeOfIterable( + use, + IterationTypeKind.Yield, + inputType, + /*errorNode*/ undefined, + ); if (yieldType) { - return [Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, false]; + return [ + Diagnostics + .Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, + false, + ]; } if (isES2015OrLaterIterable(inputType.symbol?.escapedName)) { - return [Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, true]; + return [ + Diagnostics + .Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, + true, + ]; } return allowsStrings @@ -41844,7 +53982,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * Gets the requested "iteration type" from an `Iterable`-like or `AsyncIterable`-like type. */ - function getIterationTypeOfIterable(use: IterationUse, typeKind: IterationTypeKind, inputType: Type, errorNode: Node | undefined): Type | undefined { + function getIterationTypeOfIterable( + use: IterationUse, + typeKind: IterationTypeKind, + inputType: Type, + errorNode: Node | undefined, + ): Type | undefined { if (isTypeAny(inputType)) { return undefined; } @@ -41853,7 +53996,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return iterationTypes && iterationTypes[getIterationTypesKeyFromIterationTypeKind(typeKind)]; } - function createIterationTypes(yieldType: Type = neverType, returnType: Type = neverType, nextType: Type = unknownType): IterationTypes { + function createIterationTypes( + yieldType: Type = neverType, + returnType: Type = neverType, + nextType: Type = unknownType, + ): IterationTypes { // `yieldType` and `returnType` are defaulted to `neverType` they each will be combined // via `getUnionType` when merging iteration types. `nextType` is defined as `unknownType` // as it is combined via `getIntersectionType` when merging iteration types. @@ -41862,9 +54009,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // more frequently created (i.e. `Iterator`). Iteration types // are also cached on the type they are requested for, so we shouldn't need to maintain // the cache for less-frequently used types. - if (yieldType.flags & TypeFlags.Intrinsic && - returnType.flags & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) && - nextType.flags & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined)) { + if ( + yieldType.flags & TypeFlags.Intrinsic + && returnType.flags + & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) + && nextType.flags + & (TypeFlags.Any | TypeFlags.Never | TypeFlags.Unknown | TypeFlags.Void | TypeFlags.Undefined) + ) { const id = getTypeListId([yieldType, returnType, nextType]); let iterationTypes = iterationTypesCache.get(id); if (!iterationTypes) { @@ -41902,16 +54053,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createIterationTypes( yieldTypes && getUnionType(yieldTypes), returnTypes && getUnionType(returnTypes), - nextTypes && getIntersectionType(nextTypes)); + nextTypes && getIntersectionType(nextTypes), + ); } return noIterationTypes; } - function getCachedIterationTypes(type: Type, cacheKey: MatchingKeys) { + function getCachedIterationTypes( + type: Type, + cacheKey: MatchingKeys, + ) { return (type as IterableOrIteratorType)[cacheKey]; } - function setCachedIterationTypes(type: Type, cacheKey: MatchingKeys, cachedTypes: IterationTypes) { + function setCachedIterationTypes( + type: Type, + cacheKey: MatchingKeys, + cachedTypes: IterationTypes, + ) { return (type as IterableOrIteratorType)[cacheKey] = cachedTypes; } @@ -41942,11 +54101,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (!(type.flags & TypeFlags.Union)) { - const errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined = errorNode ? { errors: undefined } : undefined; + const errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined = errorNode + ? { errors: undefined } : undefined; const iterationTypes = getIterationTypesOfIterableWorker(type, use, errorNode, errorOutputContainer); if (iterationTypes === noIterationTypes) { if (errorNode) { - const rootDiag = reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag)); + const rootDiag = reportTypeNotIterableError( + errorNode, + type, + !!(use & IterationUse.AllowsAsyncIterablesFlag), + ); if (errorOutputContainer?.errors) { addRelatedInfo(rootDiag, ...errorOutputContainer.errors); } @@ -41961,17 +54125,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return iterationTypes; } - const cacheKey = use & IterationUse.AllowsAsyncIterablesFlag ? "iterationTypesOfAsyncIterable" : "iterationTypesOfIterable"; + const cacheKey = use & IterationUse.AllowsAsyncIterablesFlag ? "iterationTypesOfAsyncIterable" + : "iterationTypesOfIterable"; const cachedTypes = getCachedIterationTypes(type, cacheKey); if (cachedTypes) return cachedTypes === noIterationTypes ? undefined : cachedTypes; let allIterationTypes: IterationTypes[] | undefined; for (const constituent of (type as UnionType).types) { - const errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined = errorNode ? { errors: undefined } : undefined; + const errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined = errorNode + ? { errors: undefined } : undefined; const iterationTypes = getIterationTypesOfIterableWorker(constituent, use, errorNode, errorOutputContainer); if (iterationTypes === noIterationTypes) { if (errorNode) { - const rootDiag = reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag)); + const rootDiag = reportTypeNotIterableError( + errorNode, + type, + !!(use & IterationUse.AllowsAsyncIterablesFlag), + ); if (errorOutputContainer?.errors) { addRelatedInfo(rootDiag, ...errorOutputContainer.errors); } @@ -42004,7 +54174,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return createIterationTypes( getAwaitedType(yieldType, errorNode) || anyType, getAwaitedType(returnType, errorNode) || anyType, - nextType); + nextType, + ); } /** @@ -42017,7 +54188,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterable` instead. */ - function getIterationTypesOfIterableWorker(type: Type, use: IterationUse, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined) { + function getIterationTypesOfIterableWorker( + type: Type, + use: IterationUse, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + ) { if (isTypeAny(type)) { return anyIterationTypes; } @@ -42027,26 +54203,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let noCache = false; if (use & IterationUse.AllowsAsyncIterablesFlag) { - const iterationTypes = - getIterationTypesOfIterableCached(type, asyncIterationTypesResolver) || - getIterationTypesOfIterableFast(type, asyncIterationTypesResolver); + const iterationTypes = getIterationTypesOfIterableCached(type, asyncIterationTypesResolver) + || getIterationTypesOfIterableFast(type, asyncIterationTypesResolver); if (iterationTypes) { if (iterationTypes === noIterationTypes && errorNode) { // ignore the cached value noCache = true; } else { - return use & IterationUse.ForOfFlag ? - getAsyncFromSyncIterationTypes(iterationTypes, errorNode) : - iterationTypes; + return use & IterationUse.ForOfFlag + ? getAsyncFromSyncIterationTypes(iterationTypes, errorNode) + : iterationTypes; } } } if (use & IterationUse.AllowsSyncIterablesFlag) { - let iterationTypes = - getIterationTypesOfIterableCached(type, syncIterationTypesResolver) || - getIterationTypesOfIterableFast(type, syncIterationTypesResolver); + let iterationTypes = getIterationTypesOfIterableCached(type, syncIterationTypesResolver) + || getIterationTypesOfIterableFast(type, syncIterationTypesResolver); if (iterationTypes) { if (iterationTypes === noIterationTypes && errorNode) { // ignore the cached value @@ -42057,7 +54231,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // for a sync iterable in an async context, only use the cached types if they are valid. if (iterationTypes !== noIterationTypes) { iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode); - return noCache ? iterationTypes : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); + return noCache ? iterationTypes + : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); } } else { @@ -42068,18 +54243,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (use & IterationUse.AllowsAsyncIterablesFlag) { - const iterationTypes = getIterationTypesOfIterableSlow(type, asyncIterationTypesResolver, errorNode, errorOutputContainer, noCache); + const iterationTypes = getIterationTypesOfIterableSlow( + type, + asyncIterationTypesResolver, + errorNode, + errorOutputContainer, + noCache, + ); if (iterationTypes !== noIterationTypes) { return iterationTypes; } } if (use & IterationUse.AllowsSyncIterablesFlag) { - let iterationTypes = getIterationTypesOfIterableSlow(type, syncIterationTypesResolver, errorNode, errorOutputContainer, noCache); + let iterationTypes = getIterationTypesOfIterableSlow( + type, + syncIterationTypesResolver, + errorNode, + errorOutputContainer, + noCache, + ); if (iterationTypes !== noIterationTypes) { if (use & IterationUse.AllowsAsyncIterablesFlag) { iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode); - return noCache ? iterationTypes : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); + return noCache ? iterationTypes + : setCachedIterationTypes(type, "iterationTypesOfAsyncIterable", iterationTypes); } else { return iterationTypes; @@ -42102,9 +54290,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getIterationTypesOfGlobalIterableType(globalType: Type, resolver: IterationTypesResolver) { - const globalIterationTypes = - getIterationTypesOfIterableCached(globalType, resolver) || - getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined, /*noCache*/ false); + const globalIterationTypes = getIterationTypesOfIterableCached(globalType, resolver) + || getIterationTypesOfIterableSlow( + globalType, + resolver, + /*errorNode*/ undefined, + /*errorOutputContainer*/ undefined, + /*noCache*/ false, + ); return globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes; } @@ -42126,15 +54319,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - `Iterable` or `AsyncIterable` // - `IterableIterator` or `AsyncIterableIterator` let globalType: Type; - if (isReferenceToType(type, globalType = resolver.getGlobalIterableType(/*reportErrors*/ false)) || - isReferenceToType(type, globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false))) { + if ( + isReferenceToType(type, globalType = resolver.getGlobalIterableType(/*reportErrors*/ false)) + || isReferenceToType(type, globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false)) + ) { const [yieldType] = getTypeArguments(type as GenericType); // The "return" and "next" types of `Iterable` and `IterableIterator` are defined by the // iteration types of their `[Symbol.iterator]()` method. The same is true for their async cousins. // While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use // different definitions. const { returnType, nextType } = getIterationTypesOfGlobalIterableType(globalType, resolver); - return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, nextType)); + return setCachedIterationTypes( + type, + resolver.iterableCacheKey, + createIterationTypes( + resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, + resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, + nextType, + ), + ); } // As an optimization, if the type is an instantiation of the following global type, then @@ -42142,14 +54345,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // - `Generator` or `AsyncGenerator` if (isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); - return setCachedIterationTypes(type, resolver.iterableCacheKey, createIterationTypes(resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, nextType)); + return setCachedIterationTypes( + type, + resolver.iterableCacheKey, + createIterationTypes( + resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || yieldType, + resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || returnType, + nextType, + ), + ); } } function getPropertyNameForKnownSymbolName(symbolName: string): __String { const ctorType = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false); - const uniqueType = ctorType && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName)); - return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) : `__@${symbolName}` as __String; + const uniqueType = ctorType + && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName)); + return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) + : `__@${symbolName}` as __String; } /** @@ -42162,20 +54375,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterable` instead. */ - function getIterationTypesOfIterableSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined, noCache: boolean) { + function getIterationTypesOfIterableSlow( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + noCache: boolean, + ) { const method = getPropertyOfType(type, getPropertyNameForKnownSymbolName(resolver.iteratorSymbolName)); const methodType = method && !(method.flags & SymbolFlags.Optional) ? getTypeOfSymbol(method) : undefined; if (isTypeAny(methodType)) { - return noCache ? anyIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, anyIterationTypes); + return noCache ? anyIterationTypes + : setCachedIterationTypes(type, resolver.iterableCacheKey, anyIterationTypes); } const signatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : undefined; if (!some(signatures)) { - return noCache ? noIterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes); + return noCache ? noIterationTypes + : setCachedIterationTypes(type, resolver.iterableCacheKey, noIterationTypes); } const iteratorType = getIntersectionType(map(signatures, getReturnTypeOfSignature)); - const iterationTypes = getIterationTypesOfIteratorWorker(iteratorType, resolver, errorNode, errorOutputContainer, noCache) ?? noIterationTypes; + const iterationTypes = + getIterationTypesOfIteratorWorker(iteratorType, resolver, errorNode, errorOutputContainer, noCache) + ?? noIterationTypes; return noCache ? iterationTypes : setCachedIterationTypes(type, resolver.iterableCacheKey, iterationTypes); } @@ -42188,12 +54411,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !!getAwaitedTypeOfPromise(type) // for (const x of AsyncIterable<...>) || ( - !allowAsyncIterables && - isForOfStatement(errorNode.parent) && - errorNode.parent.expression === errorNode && - getGlobalAsyncIterableType(/*reportErrors*/ false) !== emptyGenericType && - isTypeAssignableTo(type, getGlobalAsyncIterableType(/*reportErrors*/ false) - )); + !allowAsyncIterables + && isForOfStatement(errorNode.parent) + && errorNode.parent.expression === errorNode + && getGlobalAsyncIterableType(/*reportErrors*/ false) !== emptyGenericType + && isTypeAssignableTo(type, getGlobalAsyncIterableType(/*reportErrors*/ false)) + ); return errorAndMaybeSuggestAwait(errorNode, suggestAwait, message, typeToString(type)); } @@ -42203,7 +54426,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` * record is returned. Otherwise, `undefined` is returned. */ - function getIterationTypesOfIterator(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined) { + function getIterationTypesOfIterator( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + ) { return getIterationTypesOfIteratorWorker(type, resolver, errorNode, errorOutputContainer, /*noCache*/ false); } @@ -42216,14 +54444,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterator` instead. */ - function getIterationTypesOfIteratorWorker(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined, noCache: boolean) { + function getIterationTypesOfIteratorWorker( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + noCache: boolean, + ) { if (isTypeAny(type)) { return anyIterationTypes; } - let iterationTypes = - getIterationTypesOfIteratorCached(type, resolver) || - getIterationTypesOfIteratorFast(type, resolver); + let iterationTypes = getIterationTypesOfIteratorCached(type, resolver) + || getIterationTypesOfIteratorFast(type, resolver); if (iterationTypes === noIterationTypes && errorNode) { iterationTypes = undefined; @@ -42269,16 +54502,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The "return" and "next" types of `IterableIterator` and `AsyncIterableIterator` are defined by the // iteration types of their `next`, `return`, and `throw` methods. While we define these as `any` // and `undefined` in our libs by default, a custom lib *could* use different definitions. - const globalIterationTypes = - getIterationTypesOfIteratorCached(globalType, resolver) || - getIterationTypesOfIteratorSlow(globalType, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined, /*noCache*/ false); - const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes; - return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType)); - } - if (isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) || - isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false))) { + const globalIterationTypes = getIterationTypesOfIteratorCached(globalType, resolver) + || getIterationTypesOfIteratorSlow( + globalType, + resolver, + /*errorNode*/ undefined, + /*errorOutputContainer*/ undefined, + /*noCache*/ false, + ); + const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes + : globalIterationTypes; + return setCachedIterationTypes( + type, + resolver.iteratorCacheKey, + createIterationTypes(yieldType, returnType, nextType), + ); + } + if ( + isReferenceToType(type, resolver.getGlobalIteratorType(/*reportErrors*/ false)) + || isReferenceToType(type, resolver.getGlobalGeneratorType(/*reportErrors*/ false)) + ) { const [yieldType, returnType, nextType] = getTypeArguments(type as GenericType); - return setCachedIterationTypes(type, resolver.iteratorCacheKey, createIterationTypes(yieldType, returnType, nextType)); + return setCachedIterationTypes( + type, + resolver.iteratorCacheKey, + createIterationTypes(yieldType, returnType, nextType), + ); } } @@ -42320,19 +54569,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // or `IteratorReturnResult` types, then just grab its type argument. if (isReferenceToType(type, getGlobalIteratorYieldResultType(/*reportErrors*/ false))) { const yieldType = getTypeArguments(type as GenericType)[0]; - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes(yieldType, /*returnType*/ undefined, /*nextType*/ undefined), + ); } if (isReferenceToType(type, getGlobalIteratorReturnResultType(/*reportErrors*/ false))) { const returnType = getTypeArguments(type as GenericType)[0]; - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined), + ); } // Choose any constituents that can produce the requested iteration type. const yieldIteratorResult = filterType(type, isYieldIteratorResult); - const yieldType = yieldIteratorResult !== neverType ? getTypeOfPropertyOfType(yieldIteratorResult, "value" as __String) : undefined; + const yieldType = yieldIteratorResult !== neverType + ? getTypeOfPropertyOfType(yieldIteratorResult, "value" as __String) : undefined; const returnIteratorResult = filterType(type, isReturnIteratorResult); - const returnType = returnIteratorResult !== neverType ? getTypeOfPropertyOfType(returnIteratorResult, "value" as __String) : undefined; + const returnType = returnIteratorResult !== neverType + ? getTypeOfPropertyOfType(returnIteratorResult, "value" as __String) : undefined; if (!yieldType && !returnType) { return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", noIterationTypes); @@ -42342,7 +54601,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // > ... If the iterator does not have a return value, `value` is `undefined`. In that case, the // > `value` property may be absent from the conforming object if it does not inherit an explicit // > `value` property. - return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(yieldType, returnType || voidType, /*nextType*/ undefined)); + return setCachedIterationTypes( + type, + "iterationTypesOfIteratorResult", + createIterationTypes(yieldType, returnType || voidType, /*nextType*/ undefined), + ); } /** @@ -42352,7 +54615,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * If we successfully found the *yield*, *return*, and *next* types, an `IterationTypes` * record is returned. Otherwise, we return `undefined`. */ - function getIterationTypesOfMethod(type: Type, resolver: IterationTypesResolver, methodName: "next" | "return" | "throw", errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined): IterationTypes | undefined { + function getIterationTypesOfMethod( + type: Type, + resolver: IterationTypesResolver, + methodName: "next" | "return" | "throw", + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + ): IterationTypes | undefined { const method = getPropertyOfType(type, methodName as __String); // Ignore 'return' or 'throw' if they are missing. @@ -42361,7 +54630,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const methodType = method && !(methodName === "next" && (method.flags & SymbolFlags.Optional)) - ? methodName === "next" ? getTypeOfSymbol(method) : getTypeWithFacts(getTypeOfSymbol(method), TypeFacts.NEUndefinedOrNull) + ? methodName === "next" ? getTypeOfSymbol(method) + : getTypeWithFacts(getTypeOfSymbol(method), TypeFacts.NEUndefinedOrNull) : undefined; if (isTypeAny(methodType)) { @@ -42397,15 +54667,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (methodType?.symbol && methodSignatures.length === 1) { const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false); const globalIteratorType = resolver.getGlobalIteratorType(/*reportErrors*/ false); - const isGeneratorMethod = globalGeneratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; - const isIteratorMethod = !isGeneratorMethod && globalIteratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; + const isGeneratorMethod = + globalGeneratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; + const isIteratorMethod = !isGeneratorMethod + && globalIteratorType.symbol?.members?.get(methodName as __String) === methodType.symbol; if (isGeneratorMethod || isIteratorMethod) { const globalType = isGeneratorMethod ? globalGeneratorType : globalIteratorType; const { mapper } = methodType as AnonymousType; return createIterationTypes( getMappedType(globalType.typeParameters![0], mapper!), getMappedType(globalType.typeParameters![1], mapper!), - methodName === "next" ? getMappedType(globalType.typeParameters![2], mapper!) : undefined); + methodName === "next" ? getMappedType(globalType.typeParameters![2], mapper!) : undefined, + ); } } @@ -42431,7 +54704,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (methodName === "return") { // The value of `return(value)` *is* awaited by async generators - const resolvedMethodParameterType = resolver.resolveIterationType(methodParameterType, errorNode) || anyType; + const resolvedMethodParameterType = resolver.resolveIterationType(methodParameterType, errorNode) + || anyType; returnTypes = append(returnTypes, resolvedMethodParameterType); } } @@ -42445,7 +54719,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (errorNode) { if (errorOutputContainer) { errorOutputContainer.errors ??= []; - errorOutputContainer.errors.push(createDiagnosticForNode(errorNode, resolver.mustHaveAValueDiagnostic, methodName)); + errorOutputContainer.errors.push( + createDiagnosticForNode(errorNode, resolver.mustHaveAValueDiagnostic, methodName), + ); } else { error(errorNode, resolver.mustHaveAValueDiagnostic, methodName); @@ -42472,7 +54748,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * NOTE: You probably don't want to call this directly and should be calling * `getIterationTypesOfIterator` instead. */ - function getIterationTypesOfIteratorSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined, errorOutputContainer: { errors: Diagnostic[] | undefined } | undefined, noCache: boolean) { + function getIterationTypesOfIteratorSlow( + type: Type, + resolver: IterationTypesResolver, + errorNode: Node | undefined, + errorOutputContainer: { errors: Diagnostic[] | undefined; } | undefined, + noCache: boolean, + ) { const iterationTypes = combineIterationTypes([ getIterationTypesOfMethod(type, resolver, "next", errorNode, errorOutputContainer), getIterationTypesOfMethod(type, resolver, "return", errorNode, errorOutputContainer), @@ -42486,7 +54768,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * `IterableIterator`-like, or `Generator`-like (for a non-async generator); or `AsyncIterable`-like, * `AsyncIterator`-like, `AsyncIterableIterator`-like, or `AsyncGenerator`-like (for an async generator). */ - function getIterationTypeOfGeneratorFunctionReturnType(kind: IterationTypeKind, returnType: Type, isAsyncGenerator: boolean): Type | undefined { + function getIterationTypeOfGeneratorFunctionReturnType( + kind: IterationTypeKind, + returnType: Type, + isAsyncGenerator: boolean, + ): Type | undefined { if (isTypeAny(returnType)) { return undefined; } @@ -42502,8 +54788,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const use = isAsyncGenerator ? IterationUse.AsyncGeneratorReturnType : IterationUse.GeneratorReturnType; const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver; - return getIterationTypesOfIterable(type, use, /*errorNode*/ undefined) || - getIterationTypesOfIterator(type, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined); + return getIterationTypesOfIterable(type, use, /*errorNode*/ undefined) + || getIterationTypesOfIterator(type, resolver, /*errorNode*/ undefined, /*errorOutputContainer*/ undefined); } function checkBreakOrContinueStatement(node: BreakOrContinueStatement) { @@ -42517,7 +54803,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isGenerator = !!(functionFlags & FunctionFlags.Generator); const isAsync = !!(functionFlags & FunctionFlags.Async); if (isGenerator) { - const returnIterationType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync); + const returnIterationType = getIterationTypeOfGeneratorFunctionReturnType( + IterationTypeKind.Return, + returnType, + isAsync, + ); if (!returnIterationType) { return errorType; } @@ -42528,7 +54818,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isUnwrappedReturnTypeUndefinedVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean { const type = unwrapReturnType(returnType, getFunctionFlags(func)); - return !!(type && (maybeTypeOfKind(type, TypeFlags.Void) || type.flags & (TypeFlags.Any | TypeFlags.Undefined))); + return !!(type + && (maybeTypeOfKind(type, TypeFlags.Void) || type.flags & (TypeFlags.Any | TypeFlags.Undefined))); } function checkReturnStatement(node: ReturnStatement) { @@ -42538,7 +54829,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const container = getContainingFunctionOrClassStaticBlock(node); - if(container && isClassStaticBlockDeclaration(container)) { + if (container && isClassStaticBlockDeclaration(container)) { grammarErrorOnFirstToken(node, Diagnostics.A_return_statement_cannot_be_used_inside_a_class_static_block); return; } @@ -42559,24 +54850,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else if (container.kind === SyntaxKind.Constructor) { - if (node.expression && !checkTypeAssignableToAndOptionallyElaborate(exprType, returnType, node, node.expression)) { - error(node, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); + if ( + node.expression + && !checkTypeAssignableToAndOptionallyElaborate(exprType, returnType, node, node.expression) + ) { + error( + node, + Diagnostics + .Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class, + ); } } else if (getReturnTypeFromAnnotation(container)) { const unwrappedReturnType = unwrapReturnType(returnType, functionFlags) ?? returnType; const unwrappedExprType = functionFlags & FunctionFlags.Async - ? checkAwaitedType(exprType, /*withAlias*/ false, node, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member) + ? checkAwaitedType( + exprType, + /*withAlias*/ false, + node, + Diagnostics + .The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, + ) : exprType; if (unwrappedReturnType) { // If the function has a return type, but promisedType is // undefined, an error will be reported in checkAsyncFunctionReturnType // so we don't need to report one here. - checkTypeAssignableToAndOptionallyElaborate(unwrappedExprType, unwrappedReturnType, node, node.expression); + checkTypeAssignableToAndOptionallyElaborate( + unwrappedExprType, + unwrappedReturnType, + node, + node.expression, + ); } } } - else if (container.kind !== SyntaxKind.Constructor && compilerOptions.noImplicitReturns && !isUnwrappedReturnTypeUndefinedVoidOrAny(container, returnType)) { + else if ( + container.kind !== SyntaxKind.Constructor && compilerOptions.noImplicitReturns + && !isUnwrappedReturnTypeUndefinedVoidOrAny(container, returnType) + ) { // The function has a return type, but the return statement doesn't have an expression. error(node, Diagnostics.Not_all_code_paths_return_a_value); } @@ -42596,7 +54908,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!hasParseDiagnostics(sourceFile)) { const start = getSpanOfTokenAtPosition(sourceFile, node.pos).start; const end = node.statement.pos; - grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.The_with_statement_is_not_supported_All_symbols_in_a_with_block_will_have_type_any); + grammarErrorAtPos( + sourceFile, + start, + end - start, + Diagnostics.The_with_statement_is_not_supported_All_symbols_in_a_with_block_will_have_type_any, + ); } } @@ -42616,7 +54933,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { firstDefaultClause = clause; } else { - grammarErrorOnNode(clause, Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement); + grammarErrorOnNode( + clause, + Diagnostics.A_default_clause_cannot_appear_more_than_once_in_a_switch_statement, + ); hasDuplicateDefaultClause = true; } } @@ -42625,7 +54945,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addLazyDiagnostic(createLazyCaseClauseDiagnostics(clause)); } forEach(clause.statements, checkSourceElement); - if (compilerOptions.noFallthroughCasesInSwitch && clause.fallthroughFlowNode && isReachableFlowNode(clause.fallthroughFlowNode)) { + if ( + compilerOptions.noFallthroughCasesInSwitch && clause.fallthroughFlowNode + && isReachableFlowNode(clause.fallthroughFlowNode) + ) { error(clause, Diagnostics.Fallthrough_case_in_switch); } @@ -42655,7 +54978,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isFunctionLike(current)) { return "quit"; } - if (current.kind === SyntaxKind.LabeledStatement && (current as LabeledStatement).label.escapedText === node.label.escapedText) { + if ( + current.kind === SyntaxKind.LabeledStatement + && (current as LabeledStatement).label.escapedText === node.label.escapedText + ) { grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNode(node.label)); return true; } @@ -42695,19 +55021,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (typeNode) { const type = getTypeFromTypeNode(typeNode); if (type && !(type.flags & TypeFlags.AnyOrUnknown)) { - grammarErrorOnFirstToken(typeNode, Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified); + grammarErrorOnFirstToken( + typeNode, + Diagnostics.Catch_clause_variable_type_annotation_must_be_any_or_unknown_if_specified, + ); } } else if (declaration.initializer) { - grammarErrorOnFirstToken(declaration.initializer, Diagnostics.Catch_clause_variable_cannot_have_an_initializer); + grammarErrorOnFirstToken( + declaration.initializer, + Diagnostics.Catch_clause_variable_cannot_have_an_initializer, + ); } else { const blockLocals = catchClause.block.locals; if (blockLocals) { forEachKey(catchClause.locals!, caughtName => { const blockLocal = blockLocals.get(caughtName); - if (blockLocal?.valueDeclaration && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0) { - grammarErrorOnNode(blockLocal.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, unescapeLeadingUnderscores(caughtName)); + if ( + blockLocal?.valueDeclaration + && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0 + ) { + grammarErrorOnNode( + blockLocal.valueDeclaration, + Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, + unescapeLeadingUnderscores(caughtName), + ); } }); } @@ -42729,7 +55068,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } for (const prop of getPropertiesOfObjectType(type)) { if (!(isStaticIndex && prop.flags & SymbolFlags.Prototype)) { - checkIndexConstraintForProperty(type, prop, getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique, /*includeNonPublic*/ true), getNonMissingTypeOfSymbol(prop)); + checkIndexConstraintForProperty( + type, + prop, + getLiteralTypeFromProperty( + prop, + TypeFlags.StringOrNumberLiteralOrUnique, + /*includeNonPublic*/ true, + ), + getNonMissingTypeOfSymbol(prop), + ); } } const typeDeclaration = symbol.valueDeclaration; @@ -42739,7 +55087,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and properties with literal names were already checked. if (!isStatic(member) && !hasBindableName(member)) { const symbol = getSymbolOfDeclaration(member); - checkIndexConstraintForProperty(type, symbol, getTypeOfExpression((member as DynamicNamedDeclaration).name.expression), getNonMissingTypeOfSymbol(symbol)); + checkIndexConstraintForProperty( + type, + symbol, + getTypeOfExpression((member as DynamicNamedDeclaration).name.expression), + getNonMissingTypeOfSymbol(symbol), + ); } } } @@ -42757,22 +55110,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } const indexInfos = getApplicableIndexInfos(type, propNameType); - const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; - const propDeclaration = declaration && declaration.kind === SyntaxKind.BinaryExpression || - name && name.kind === SyntaxKind.ComputedPropertyName ? declaration : undefined; + const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface + ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; + const propDeclaration = declaration && declaration.kind === SyntaxKind.BinaryExpression + || name && name.kind === SyntaxKind.ComputedPropertyName ? declaration : undefined; const localPropDeclaration = getParentOfSymbol(prop) === type.symbol ? declaration : undefined; for (const info of indexInfos) { - const localIndexDeclaration = info.declaration && getParentOfSymbol(getSymbolOfDeclaration(info.declaration)) === type.symbol ? info.declaration : undefined; + const localIndexDeclaration = + info.declaration && getParentOfSymbol(getSymbolOfDeclaration(info.declaration)) === type.symbol + ? info.declaration : undefined; // We check only when (a) the property is declared in the containing type, or (b) the applicable index signature is declared // in the containing type, or (c) the containing type is an interface and no base interface contains both the property and // the index signature (i.e. property and index signature are declared in separate inherited interfaces). - const errorNode = localPropDeclaration || localIndexDeclaration || - (interfaceDeclaration && !some(getBaseTypes(type as InterfaceType), base => !!getPropertyOfObjectType(base, prop.escapedName) && !!getIndexTypeOfType(base, info.keyType)) ? interfaceDeclaration : undefined); + const errorNode = localPropDeclaration || localIndexDeclaration + || (interfaceDeclaration + && !some( + getBaseTypes(type as InterfaceType), + base => + !!getPropertyOfObjectType(base, prop.escapedName) + && !!getIndexTypeOfType(base, info.keyType), + ) ? interfaceDeclaration : undefined); if (errorNode && !isTypeAssignableTo(propType, info.type)) { - const diagnostic = createError(errorNode, Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3, - symbolToString(prop), typeToString(propType), typeToString(info.keyType), typeToString(info.type)); + const diagnostic = createError( + errorNode, + Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3, + symbolToString(prop), + typeToString(propType), + typeToString(info.keyType), + typeToString(info.type), + ); if (propDeclaration && errorNode !== propDeclaration) { - addRelatedInfo(diagnostic, createDiagnosticForNode(propDeclaration, Diagnostics._0_is_declared_here, symbolToString(prop))); + addRelatedInfo( + diagnostic, + createDiagnosticForNode(propDeclaration, Diagnostics._0_is_declared_here, symbolToString(prop)), + ); } diagnostics.add(diagnostic); } @@ -42782,19 +55153,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkIndexConstraintForIndexSignature(type: Type, checkInfo: IndexInfo) { const declaration = checkInfo.declaration; const indexInfos = getApplicableIndexInfos(type, checkInfo.keyType); - const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; - const localCheckDeclaration = declaration && getParentOfSymbol(getSymbolOfDeclaration(declaration)) === type.symbol ? declaration : undefined; + const interfaceDeclaration = getObjectFlags(type) & ObjectFlags.Interface + ? getDeclarationOfKind(type.symbol, SyntaxKind.InterfaceDeclaration) : undefined; + const localCheckDeclaration = + declaration && getParentOfSymbol(getSymbolOfDeclaration(declaration)) === type.symbol ? declaration + : undefined; for (const info of indexInfos) { if (info === checkInfo) continue; - const localIndexDeclaration = info.declaration && getParentOfSymbol(getSymbolOfDeclaration(info.declaration)) === type.symbol ? info.declaration : undefined; + const localIndexDeclaration = + info.declaration && getParentOfSymbol(getSymbolOfDeclaration(info.declaration)) === type.symbol + ? info.declaration : undefined; // We check only when (a) the check index signature is declared in the containing type, or (b) the applicable index // signature is declared in the containing type, or (c) the containing type is an interface and no base interface contains // both index signatures (i.e. the index signatures are declared in separate inherited interfaces). - const errorNode = localCheckDeclaration || localIndexDeclaration || - (interfaceDeclaration && !some(getBaseTypes(type as InterfaceType), base => !!getIndexInfoOfType(base, checkInfo.keyType) && !!getIndexTypeOfType(base, info.keyType)) ? interfaceDeclaration : undefined); + const errorNode = localCheckDeclaration || localIndexDeclaration + || (interfaceDeclaration + && !some( + getBaseTypes(type as InterfaceType), + base => + !!getIndexInfoOfType(base, checkInfo.keyType) + && !!getIndexTypeOfType(base, info.keyType), + ) ? interfaceDeclaration : undefined); if (errorNode && !isTypeAssignableTo(checkInfo.type, info.type)) { - error(errorNode, Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3, - typeToString(checkInfo.keyType), typeToString(checkInfo.type), typeToString(info.keyType), typeToString(info.type)); + error( + errorNode, + Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3, + typeToString(checkInfo.keyType), + typeToString(checkInfo.type), + typeToString(info.keyType), + typeToString(info.type), + ); } } } @@ -42821,9 +55209,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * The name cannot be used as 'Object' of user defined types with special target. */ function checkClassNameCollisionWithObject(name: Identifier): void { - if (languageVersion >= ScriptTarget.ES5 && name.escapedText === "Object" - && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(name).impliedNodeFormat === ModuleKind.CommonJS)) { - error(name, Diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_with_module_0, ModuleKind[moduleKind]); // https://github.com/Microsoft/TypeScript/issues/17494 + if ( + languageVersion >= ScriptTarget.ES5 && name.escapedText === "Object" + && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(name).impliedNodeFormat === ModuleKind.CommonJS) + ) { + error( + name, + Diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_with_module_0, + ModuleKind[moduleKind], + ); // https://github.com/Microsoft/TypeScript/issues/17494 } } @@ -42847,9 +55241,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (containsArguments) { const lastJSDocParamIndex = jsdocParameters.length - 1; const lastJSDocParam = jsdocParameters[lastJSDocParamIndex]; - if (isJs && lastJSDocParam && isIdentifier(lastJSDocParam.name) && lastJSDocParam.typeExpression && - lastJSDocParam.typeExpression.type && !parameters.has(lastJSDocParam.name.escapedText) && !excludedParameters.has(lastJSDocParamIndex) && !isArrayType(getTypeFromTypeNode(lastJSDocParam.typeExpression.type))) { - error(lastJSDocParam.name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type, idText(lastJSDocParam.name)); + if ( + isJs && lastJSDocParam && isIdentifier(lastJSDocParam.name) && lastJSDocParam.typeExpression + && lastJSDocParam.typeExpression.type && !parameters.has(lastJSDocParam.name.escapedText) + && !excludedParameters.has(lastJSDocParamIndex) + && !isArrayType(getTypeFromTypeNode(lastJSDocParam.typeExpression.type)) + ) { + error( + lastJSDocParam.name, + Diagnostics + .JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name_It_would_match_arguments_if_it_had_an_array_type, + idText(lastJSDocParam.name), + ); } } else { @@ -42859,12 +55262,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isQualifiedName(name)) { if (isJs) { - error(name, Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1, entityNameToString(name), entityNameToString(name.left)); + error( + name, + Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1, + entityNameToString(name), + entityNameToString(name.left), + ); } } else { if (!isNameFirst) { - errorOrSuggestion(isJs, name, Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name, idText(name)); + errorOrSuggestion( + isJs, + name, + Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name, + idText(name), + ); } } }); @@ -42904,7 +55317,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } /** Check that type parameter defaults only reference previously declared type parameters */ - function checkTypeParametersNotReferenced(root: TypeNode, typeParameters: readonly TypeParameterDeclaration[], index: number) { + function checkTypeParametersNotReferenced( + root: TypeNode, + typeParameters: readonly TypeParameterDeclaration[], + index: number, + ) { visit(root); function visit(node: Node) { if (node.kind === SyntaxKind.TypeReference) { @@ -42912,7 +55329,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (type.flags & TypeFlags.TypeParameter) { for (let i = index; i < typeParameters.length; i++) { if (type.symbol === getSymbolOfDeclaration(typeParameters[i])) { - error(node, Diagnostics.Type_parameter_defaults_can_only_reference_previously_declared_type_parameters); + error( + node, + Diagnostics + .Type_parameter_defaults_can_only_reference_previously_declared_type_parameters, + ); } } } @@ -42936,17 +55357,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; - if (!areTypeParametersIdentical(declarations, type.localTypeParameters!, getEffectiveTypeParameterDeclarations)) { + if ( + !areTypeParametersIdentical( + declarations, + type.localTypeParameters!, + getEffectiveTypeParameterDeclarations, + ) + ) { // Report an error on every conflicting declaration. const name = symbolToString(symbol); for (const declaration of declarations) { - error(declaration.name, Diagnostics.All_declarations_of_0_must_have_identical_type_parameters, name); + error( + declaration.name, + Diagnostics.All_declarations_of_0_must_have_identical_type_parameters, + name, + ); } } } } - function areTypeParametersIdentical(declarations: readonly T[], targetParameters: TypeParameter[], getTypeParameterDeclarations: (node: T) => readonly TypeParameterDeclaration[]) { + function areTypeParametersIdentical( + declarations: readonly T[], + targetParameters: TypeParameter[], + getTypeParameterDeclarations: (node: T) => readonly TypeParameterDeclaration[], + ) { const maxTypeArgumentCount = length(targetParameters); const minTypeArgumentCount = getMinTypeArgumentCount(targetParameters); @@ -42993,14 +55428,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getFirstTransformableStaticClassElement(node: ClassLikeDeclaration) { - const willTransformStaticElementsOfDecoratedClass = - !legacyDecorators && languageVersion < ScriptTarget.ESNext && - classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node); + const willTransformStaticElementsOfDecoratedClass = !legacyDecorators && languageVersion < ScriptTarget.ESNext + && classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node); const willTransformPrivateElementsOrClassStaticBlocks = languageVersion <= ScriptTarget.ES2022; const willTransformInitializers = !emitStandardClassFields; if (willTransformStaticElementsOfDecoratedClass || willTransformPrivateElementsOrClassStaticBlocks) { for (const member of node.members) { - if (willTransformStaticElementsOfDecoratedClass && classElementOrClassElementParameterIsDecorated(/*useLegacyDecorators*/ false, member, node)) { + if ( + willTransformStaticElementsOfDecoratedClass + && classElementOrClassElementParameterIsDecorated(/*useLegacyDecorators*/ false, member, node) + ) { return firstOrUndefined(getDecorators(node)) ?? node; } else if (willTransformPrivateElementsOrClassStaticBlocks) { @@ -43008,8 +55445,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return member; } else if (isStatic(member)) { - if (isPrivateIdentifierClassElementDeclaration(member) || - willTransformInitializers && isInitializedProperty(member)) { + if ( + isPrivateIdentifierClassElementDeclaration(member) + || willTransformInitializers && isInitializedProperty(member) + ) { return member; } } @@ -43035,7 +55474,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (location) { checkExternalEmitHelpers(location, ExternalEmitHelpers.SetFunctionName); - if ((isPropertyAssignment(parent) || isPropertyDeclaration(parent) || isBindingElement(parent)) && isComputedPropertyName(parent.name)) { + if ( + (isPropertyAssignment(parent) || isPropertyDeclaration(parent) || isBindingElement(parent)) + && isComputedPropertyName(parent.name) + ) { checkExternalEmitHelpers(location, ExternalEmitHelpers.PropKey); } } @@ -43055,11 +55497,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkClassDeclaration(node: ClassDeclaration) { const firstDecorator = find(node.modifiers, isDecorator); - if (legacyDecorators && firstDecorator && some(node.members, p => hasStaticModifier(p) && isPrivateIdentifierClassElementDeclaration(p))) { - grammarErrorOnNode(firstDecorator, Diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator); + if ( + legacyDecorators && firstDecorator + && some(node.members, p => hasStaticModifier(p) && isPrivateIdentifierClassElementDeclaration(p)) + ) { + grammarErrorOnNode( + firstDecorator, + Diagnostics + .Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator, + ); } if (!node.name && !hasSyntacticModifier(node, ModifierFlags.Default)) { - grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); + grammarErrorOnFirstToken( + node, + Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name, + ); } checkClassLikeDeclaration(node); forEach(node.members, checkSourceElement); @@ -43109,7 +55561,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkSourceElement(baseTypeNode.expression); if (some(baseTypeNode.typeArguments)) { forEach(baseTypeNode.typeArguments, checkSourceElement); - for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) { + for ( + const constructor of getConstructorsForTypeArguments( + staticBaseType, + baseTypeNode.typeArguments, + baseTypeNode, + ) + ) { if (!checkTypeArgumentConstraints(baseTypeNode, constructor.typeParameters!)) { break; } @@ -43117,31 +55575,68 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const baseWithThis = getTypeWithThisArgument(baseType, type.thisType); if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { - issueMemberSpecificError(node, typeWithThis, baseWithThis, Diagnostics.Class_0_incorrectly_extends_base_class_1); + issueMemberSpecificError( + node, + typeWithThis, + baseWithThis, + Diagnostics.Class_0_incorrectly_extends_base_class_1, + ); } else { // Report static side error only when instance type is assignable - checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node, - Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1); + checkTypeAssignableTo( + staticType, + getTypeWithoutSignatures(staticBaseType), + node.name || node, + Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1, + ); } if (baseConstructorType.flags & TypeFlags.TypeVariable) { if (!isMixinConstructorType(staticType)) { - error(node.name || node, Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any); + error( + node.name || node, + Diagnostics + .A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any, + ); } else { - const constructSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); - if (constructSignatures.some(signature => signature.flags & SignatureFlags.Abstract) && !hasSyntacticModifier(node, ModifierFlags.Abstract)) { - error(node.name || node, Diagnostics.A_mixin_class_that_extends_from_a_type_variable_containing_an_abstract_construct_signature_must_also_be_declared_abstract); + const constructSignatures = getSignaturesOfType( + baseConstructorType, + SignatureKind.Construct, + ); + if ( + constructSignatures.some(signature => signature.flags & SignatureFlags.Abstract) + && !hasSyntacticModifier(node, ModifierFlags.Abstract) + ) { + error( + node.name || node, + Diagnostics + .A_mixin_class_that_extends_from_a_type_variable_containing_an_abstract_construct_signature_must_also_be_declared_abstract, + ); } } } - if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) && !(baseConstructorType.flags & TypeFlags.TypeVariable)) { + if ( + !(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) + && !(baseConstructorType.flags & TypeFlags.TypeVariable) + ) { // When the static base type is a "class-like" constructor function (but not actually a class), we verify // that all instantiated base constructor signatures return the same type. - const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode); - if (forEach(constructors, sig => !isJSConstructor(sig.declaration) && !isTypeIdenticalTo(getReturnTypeOfSignature(sig), baseType))) { - error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type); + const constructors = getInstantiatedConstructorsForTypeArguments( + staticBaseType, + baseTypeNode.typeArguments, + baseTypeNode, + ); + if ( + forEach(constructors, sig => + !isJSConstructor(sig.declaration) + && !isTypeIdenticalTo(getReturnTypeOfSignature(sig), baseType)) + ) { + error( + baseTypeNode.expression, + Diagnostics.Base_constructors_must_all_have_the_same_return_type, + ); } } checkKindsOfPropertyMemberOverrides(type, baseType); @@ -43155,7 +55650,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (implementedTypeNodes) { for (const typeRefNode of implementedTypeNodes) { if (!isEntityNameExpression(typeRefNode.expression) || isOptionalChain(typeRefNode.expression)) { - error(typeRefNode.expression, Diagnostics.A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments); + error( + typeRefNode.expression, + Diagnostics + .A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments, + ); } checkTypeReferenceNode(typeRefNode); addLazyDiagnostic(createImplementsDiagnostics(typeRefNode)); @@ -43174,23 +55673,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const t = getReducedType(getTypeFromTypeNode(typeRefNode)); if (!isErrorType(t)) { if (isValidBaseType(t)) { - const genericDiag = t.symbol && t.symbol.flags & SymbolFlags.Class ? - Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass : - Diagnostics.Class_0_incorrectly_implements_interface_1; + const genericDiag = t.symbol && t.symbol.flags & SymbolFlags.Class + ? Diagnostics + .Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass + : Diagnostics.Class_0_incorrectly_implements_interface_1; const baseWithThis = getTypeWithThisArgument(t, type.thisType); if (!checkTypeAssignableTo(typeWithThis, baseWithThis, /*errorNode*/ undefined)) { issueMemberSpecificError(node, typeWithThis, baseWithThis, genericDiag); } } else { - error(typeRefNode, Diagnostics.A_class_can_only_implement_an_object_type_or_intersection_of_object_types_with_statically_known_members); + error( + typeRefNode, + Diagnostics + .A_class_can_only_implement_an_object_type_or_intersection_of_object_types_with_statically_known_members, + ); } } }; } } - function checkMembersForOverrideModifier(node: ClassLikeDeclaration, type: InterfaceType, typeWithThis: Type, staticType: ObjectType) { + function checkMembersForOverrideModifier( + node: ClassLikeDeclaration, + type: InterfaceType, + typeWithThis: Type, + staticType: ObjectType, + ) { const baseTypeNode = getEffectiveBaseTypeNode(node); const baseTypes = baseTypeNode && getBaseTypes(type); const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) : undefined; @@ -43212,7 +55721,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { type, typeWithThis, param, - /*memberIsParameterProperty*/ true + /*memberIsParameterProperty*/ true, ); } }); @@ -43246,7 +55755,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { reportErrors = true, ): MemberOverrideStatus { const declaredProp = member.name - && getSymbolAtLocation(member.name) + && getSymbolAtLocation(member.name) || getSymbolAtLocation(member); if (!declaredProp) { return MemberOverrideStatus.Ok; @@ -43303,20 +55812,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (prop && !baseProp && memberHasOverrideModifier) { if (errorNode) { const suggestion = getSuggestedSymbolForNonexistentClassMember(memberName, baseType); // Again, using symbol name: note that's different from `symbol.escapedName` - suggestion ? - error( + suggestion + ? error( errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 : - Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, + isJs + ? Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 + : Diagnostics + .This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, baseClassName, - symbolToString(suggestion)) : - error( + symbolToString(suggestion), + ) + : error( errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 : - Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, - baseClassName); + isJs + ? Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + : Diagnostics + .This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, + baseClassName, + ); } return MemberOverrideStatus.HasInvalidOverride; } @@ -43328,20 +55843,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!baseHasAbstract) { if (errorNode) { - const diag = memberIsParameterProperty ? - isJs ? - Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 : - Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 : - isJs ? - Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 : - Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0; + const diag = memberIsParameterProperty + ? isJs + ? Diagnostics + .This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + : Diagnostics + .This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 + : isJs + ? Diagnostics + .This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + : Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0; error(errorNode, diag, baseClassName); } return MemberOverrideStatus.NeedsOverride; } else if (memberHasAbstractModifier && baseHasAbstract) { if (errorNode) { - error(errorNode, Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0, baseClassName); + error( + errorNode, + Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0, + baseClassName, + ); } return MemberOverrideStatus.NeedsOverride; } @@ -43352,10 +55876,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const className = typeToString(type); error( errorNode, - isJs ? - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class : - Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class, - className); + isJs + ? Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + : Diagnostics + .This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class, + className, + ); } return MemberOverrideStatus.HasInvalidOverride; } @@ -43363,7 +55890,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return MemberOverrideStatus.Ok; } - function issueMemberSpecificError(node: ClassLikeDeclaration, typeWithThis: Type, baseWithThis: Type, broadDiag: DiagnosticMessage) { + function issueMemberSpecificError( + node: ClassLikeDeclaration, + typeWithThis: Type, + baseWithThis: Type, + broadDiag: DiagnosticMessage, + ) { // iterate over all implemented properties and issue errors on each one which isn't compatible, rather than the class as a whole, if possible let issuedMemberError = false; for (const member of node.members) { @@ -43375,14 +55907,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const prop = getPropertyOfType(typeWithThis, declaredProp.escapedName); const baseProp = getPropertyOfType(baseWithThis, declaredProp.escapedName); if (prop && baseProp) { - const rootChain = () => chainDiagnosticMessages( - /*details*/ undefined, - Diagnostics.Property_0_in_type_1_is_not_assignable_to_the_same_property_in_base_type_2, - symbolToString(declaredProp), - typeToString(typeWithThis), - typeToString(baseWithThis) - ); - if (!checkTypeAssignableTo(getTypeOfSymbol(prop), getTypeOfSymbol(baseProp), member.name || member, /*headMessage*/ undefined, rootChain)) { + const rootChain = () => + chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Property_0_in_type_1_is_not_assignable_to_the_same_property_in_base_type_2, + symbolToString(declaredProp), + typeToString(typeWithThis), + typeToString(baseWithThis), + ); + if ( + !checkTypeAssignableTo( + getTypeOfSymbol(prop), + getTypeOfSymbol(baseProp), + member.name || member, + /*headMessage*/ undefined, + rootChain, + ) + ) { issuedMemberError = true; } } @@ -43401,7 +55942,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (declaration && hasEffectiveModifier(declaration, ModifierFlags.Private)) { const typeClassDeclaration = getClassLikeDeclarationOfSymbol(type.symbol)!; if (!isNodeWithinClass(node, typeClassDeclaration)) { - error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, getFullyQualifiedName(type.symbol)); + error( + node, + Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, + getFullyQualifiedName(type.symbol), + ); } } } @@ -43414,7 +55959,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * @param memberSymbol Member symbol. * Note: `member` can be a synthetic node without a parent. */ - function getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement, memberSymbol: Symbol): MemberOverrideStatus { + function getMemberOverrideModifierStatus( + node: ClassLikeDeclaration, + member: ClassElement, + memberSymbol: Symbol, + ): MemberOverrideStatus { if (!member.name) { return MemberOverrideStatus.Ok; } @@ -43456,8 +56005,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getClassOrInterfaceDeclarationsOfSymbol(symbol: Symbol) { - return filter(symbol.declarations, (d: Declaration): d is ClassDeclaration | InterfaceDeclaration => - d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration); + return filter( + symbol.declarations, + (d: Declaration): d is ClassDeclaration | InterfaceDeclaration => + d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration, + ); } function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: BaseType): void { @@ -43478,7 +56030,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // NOTE: assignability is checked in checkClassDeclaration const baseProperties = getPropertiesOfType(baseType); let inheritedAbstractMemberNotImplementedError: Diagnostic | undefined; - basePropertyCheck: for (const baseProperty of baseProperties) { + basePropertyCheck: + for (const baseProperty of baseProperties) { const base = getTargetSymbol(baseProperty); if (base.flags & SymbolFlags.Prototype) { @@ -43503,7 +56056,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // It is an error to inherit an abstract member without implementing it or being declared abstract. // If there is no declaration for the derived class (as in the case of class expressions), // then the class cannot be declared abstract. - if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasSyntacticModifier(derivedClassDecl, ModifierFlags.Abstract))) { + if ( + baseDeclarationFlags & ModifierFlags.Abstract + && (!derivedClassDecl || !hasSyntacticModifier(derivedClassDecl, ModifierFlags.Abstract)) + ) { // Searches other base types for a declaration that would satisfy the inherited abstract member. // (The class may have more than one base type via declaration merging with an interface with the // same name.) @@ -43518,26 +56074,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!inheritedAbstractMemberNotImplementedError) { inheritedAbstractMemberNotImplementedError = error( - derivedClassDecl, - Diagnostics.Non_abstract_class_0_does_not_implement_all_abstract_members_of_1, - typeToString(type), typeToString(baseType)); - + derivedClassDecl, + Diagnostics.Non_abstract_class_0_does_not_implement_all_abstract_members_of_1, + typeToString(type), + typeToString(baseType), + ); } if (derivedClassDecl.kind === SyntaxKind.ClassExpression) { addRelatedInfo( inheritedAbstractMemberNotImplementedError, createDiagnosticForNode( - baseProperty.valueDeclaration ?? (baseProperty.declarations && first(baseProperty.declarations)) ?? derivedClassDecl, - Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, - symbolToString(baseProperty), typeToString(baseType))); + baseProperty.valueDeclaration + ?? (baseProperty.declarations && first(baseProperty.declarations)) + ?? derivedClassDecl, + Diagnostics + .Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, + symbolToString(baseProperty), + typeToString(baseType), + ), + ); } else { addRelatedInfo( inheritedAbstractMemberNotImplementedError, createDiagnosticForNode( - baseProperty.valueDeclaration ?? (baseProperty.declarations && first(baseProperty.declarations)) ?? derivedClassDecl, - Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, - typeToString(type), symbolToString(baseProperty), typeToString(baseType))); + baseProperty.valueDeclaration + ?? (baseProperty.declarations && first(baseProperty.declarations)) + ?? derivedClassDecl, + Diagnostics + .Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, + typeToString(type), + symbolToString(baseProperty), + typeToString(baseType), + ), + ); } } } @@ -43554,41 +56124,67 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const derivedPropertyFlags = derived.flags & SymbolFlags.PropertyOrAccessor; if (basePropertyFlags && derivedPropertyFlags) { // property/accessor is overridden with property/accessor - if ((getCheckFlags(base) & CheckFlags.Synthetic - ? base.declarations?.some(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags)) - : base.declarations?.every(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags))) + if ( + (getCheckFlags(base) & CheckFlags.Synthetic + ? base.declarations?.some(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags)) + : base.declarations?.every(d => isPropertyAbstractOrInterface(d, baseDeclarationFlags))) || getCheckFlags(base) & CheckFlags.Mapped - || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration)) { + || derived.valueDeclaration && isBinaryExpression(derived.valueDeclaration) + ) { // when the base property is abstract or from an interface, base/derived flags don't need to match // for intersection properties, this must be true of *any* of the declarations, for others it must be true of *all* // same when the derived property is from an assignment continue; } - const overriddenInstanceProperty = basePropertyFlags !== SymbolFlags.Property && derivedPropertyFlags === SymbolFlags.Property; - const overriddenInstanceAccessor = basePropertyFlags === SymbolFlags.Property && derivedPropertyFlags !== SymbolFlags.Property; + const overriddenInstanceProperty = basePropertyFlags !== SymbolFlags.Property + && derivedPropertyFlags === SymbolFlags.Property; + const overriddenInstanceAccessor = basePropertyFlags === SymbolFlags.Property + && derivedPropertyFlags !== SymbolFlags.Property; if (overriddenInstanceProperty || overriddenInstanceAccessor) { - const errorMessage = overriddenInstanceProperty ? - Diagnostics._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property : - Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor; - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, symbolToString(base), typeToString(baseType), typeToString(type)); + const errorMessage = overriddenInstanceProperty + ? Diagnostics + ._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property + : Diagnostics + ._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor; + error( + getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, + errorMessage, + symbolToString(base), + typeToString(baseType), + typeToString(type), + ); } else if (useDefineForClassFields) { - const uninitialized = derived.declarations?.find(d => d.kind === SyntaxKind.PropertyDeclaration && !(d as PropertyDeclaration).initializer); - if (uninitialized + const uninitialized = derived.declarations?.find(d => + d.kind === SyntaxKind.PropertyDeclaration && !(d as PropertyDeclaration).initializer + ); + if ( + uninitialized && !(derived.flags & SymbolFlags.Transient) && !(baseDeclarationFlags & ModifierFlags.Abstract) && !(derivedDeclarationFlags & ModifierFlags.Abstract) - && !derived.declarations?.some(d => !!(d.flags & NodeFlags.Ambient))) { - const constructor = findConstructorDeclaration(getClassLikeDeclarationOfSymbol(type.symbol)!); + && !derived.declarations?.some(d => !!(d.flags & NodeFlags.Ambient)) + ) { + const constructor = findConstructorDeclaration( + getClassLikeDeclarationOfSymbol(type.symbol)!, + ); const propName = (uninitialized as PropertyDeclaration).name; - if ((uninitialized as PropertyDeclaration).exclamationToken + if ( + (uninitialized as PropertyDeclaration).exclamationToken || !constructor || !isIdentifier(propName) || !strictNullChecks - || !isPropertyInitializedInConstructor(propName, type, constructor)) { - const errorMessage = Diagnostics.Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration; - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, symbolToString(base), typeToString(baseType)); + || !isPropertyInitializedInConstructor(propName, type, constructor) + ) { + const errorMessage = Diagnostics + .Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration; + error( + getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, + errorMessage, + symbolToString(base), + typeToString(baseType), + ); } } } @@ -43603,23 +56199,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { Debug.assert(!!(derived.flags & SymbolFlags.Accessor)); - errorMessage = Diagnostics.Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; + errorMessage = Diagnostics + .Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor; } } else if (base.flags & SymbolFlags.Accessor) { - errorMessage = Diagnostics.Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; + errorMessage = Diagnostics + .Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function; } else { - errorMessage = Diagnostics.Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; + errorMessage = Diagnostics + .Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function; } - error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type)); + error( + getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, + errorMessage, + typeToString(baseType), + symbolToString(base), + typeToString(type), + ); } } } function isPropertyAbstractOrInterface(declaration: Declaration, baseDeclarationFlags: ModifierFlags) { - return baseDeclarationFlags & ModifierFlags.Abstract && (!isPropertyDeclaration(declaration) || !declaration.initializer) + return baseDeclarationFlags & ModifierFlags.Abstract + && (!isPropertyDeclaration(declaration) || !declaration.initializer) || isInterfaceDeclaration(declaration.parent); } @@ -43651,7 +56257,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - interface InheritanceInfoMap { prop: Symbol; containingType: Type; } + interface InheritanceInfoMap { + prop: Symbol; + containingType: Type; + } const seen = new Map<__String, InheritanceInfoMap>(); forEach(resolveDeclaredMembers(type).declaredProperties, p => { seen.set(p.escapedName, { prop: p, containingType: type }); @@ -43673,9 +56282,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeName1 = typeToString(existing.containingType); const typeName2 = typeToString(base); - let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, symbolToString(prop), typeName1, typeName2); - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2); - diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(typeNode), typeNode, errorInfo)); + let errorInfo = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, + symbolToString(prop), + typeName1, + typeName2, + ); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, + typeToString(type), + typeName1, + typeName2, + ); + diagnostics.add( + createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(typeNode), typeNode, errorInfo), + ); } } } @@ -43699,7 +56322,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const type = getTypeOfSymbol(getSymbolOfDeclaration(member)); if (!(type.flags & TypeFlags.AnyOrUnknown || containsUndefinedType(type))) { if (!constructor || !isPropertyInitializedInConstructor(propName, type, constructor)) { - error(member.name, Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, declarationNameToString(propName)); + error( + member.name, + Diagnostics + .Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor, + declarationNameToString(propName), + ); } } } @@ -43708,13 +56336,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isPropertyWithoutInitializer(node: Node) { - return node.kind === SyntaxKind.PropertyDeclaration && - !hasAbstractModifier(node) && - !(node as PropertyDeclaration).exclamationToken && - !(node as PropertyDeclaration).initializer; - } - - function isPropertyInitializedInStaticBlocks(propName: Identifier | PrivateIdentifier, propType: Type, staticBlocks: readonly ClassStaticBlockDeclaration[], startPos: number, endPos: number) { + return node.kind === SyntaxKind.PropertyDeclaration + && !hasAbstractModifier(node) + && !(node as PropertyDeclaration).exclamationToken + && !(node as PropertyDeclaration).initializer; + } + + function isPropertyInitializedInStaticBlocks( + propName: Identifier | PrivateIdentifier, + propType: Type, + staticBlocks: readonly ClassStaticBlockDeclaration[], + startPos: number, + endPos: number, + ) { for (const staticBlock of staticBlocks) { // static block must be within the provided range as they are evaluated in document order (unlike constructors) if (staticBlock.pos >= startPos && staticBlock.pos <= endPos) { @@ -43731,7 +56365,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function isPropertyInitializedInConstructor(propName: Identifier | PrivateIdentifier | ComputedPropertyName, propType: Type, constructor: ConstructorDeclaration) { + function isPropertyInitializedInConstructor( + propName: Identifier | PrivateIdentifier | ComputedPropertyName, + propType: Type, + constructor: ConstructorDeclaration, + ) { const reference = isComputedPropertyName(propName) ? factory.createElementAccessExpression(factory.createThis(), propName.expression) : factory.createPropertyAccessExpression(factory.createThis(), propName); @@ -43742,7 +56380,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !containsUndefinedType(flowType); } - function checkInterfaceDeclaration(node: InterfaceDeclaration) { // Grammar checking if (!checkGrammarModifiers(node)) checkGrammarInterfaceDeclaration(node); @@ -43756,14 +56393,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkTypeParameterListsIdentical(symbol); // Only check this symbol once - const firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); + const firstInterfaceDecl = getDeclarationOfKind( + symbol, + SyntaxKind.InterfaceDeclaration, + ); if (node === firstInterfaceDecl) { const type = getDeclaredTypeOfSymbol(symbol) as InterfaceType; const typeWithThis = getTypeWithThisArgument(type); // run subsequent checks only if first set succeeded if (checkInheritedPropertiesAreIdentical(type, node.name)) { for (const baseType of getBaseTypes(type)) { - checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(baseType, type.thisType), node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1); + checkTypeAssignableTo( + typeWithThis, + getTypeWithThisArgument(baseType, type.thisType), + node.name, + Diagnostics.Interface_0_incorrectly_extends_interface_1, + ); } checkIndexConstraints(type, symbol); } @@ -43772,7 +56417,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }); forEach(getInterfaceBaseTypeNodes(node), heritageElement => { if (!isEntityNameExpression(heritageElement.expression) || isOptionalChain(heritageElement.expression)) { - error(heritageElement.expression, Diagnostics.An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments); + error( + heritageElement.expression, + Diagnostics + .An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments, + ); } checkTypeReferenceNode(heritageElement); }); @@ -43793,7 +56442,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkTypeParameters(node.typeParameters); if (node.type.kind === SyntaxKind.IntrinsicKeyword) { if (!intrinsicTypeKinds.has(node.name.escapedText as string) || length(node.typeParameters) !== 1) { - error(node.type, Diagnostics.The_intrinsic_keyword_can_only_be_used_to_declare_compiler_provided_intrinsic_types); + error( + node.type, + Diagnostics.The_intrinsic_keyword_can_only_be_used_to_declare_compiler_provided_intrinsic_types, + ); } } else { @@ -43850,9 +56502,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const value = evaluate(initializer, member); if (value !== undefined) { if (isConstEnum && typeof value === "number" && !isFinite(value)) { - error(initializer, isNaN(value) ? - Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN : - Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value); + error( + initializer, + isNaN(value) + ? Diagnostics.const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN + : Diagnostics.const_enum_member_initializer_was_evaluated_to_a_non_finite_value, + ); } } else if (isConstEnum) { @@ -43862,7 +56517,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(initializer, Diagnostics.In_ambient_enum_declarations_member_initializer_must_be_constant_expression); } else { - checkTypeAssignableTo(checkExpression(initializer), numberType, initializer, Diagnostics.Type_0_is_not_assignable_to_type_1_as_required_for_computed_enum_member_values); + checkTypeAssignableTo( + checkExpression(initializer), + numberType, + initializer, + Diagnostics.Type_0_is_not_assignable_to_type_1_as_required_for_computed_enum_member_values, + ); } return value; } @@ -43873,9 +56533,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const value = evaluate((expr as PrefixUnaryExpression).operand, location); if (typeof value === "number") { switch ((expr as PrefixUnaryExpression).operator) { - case SyntaxKind.PlusToken: return value; - case SyntaxKind.MinusToken: return -value; - case SyntaxKind.TildeToken: return ~value; + case SyntaxKind.PlusToken: + return value; + case SyntaxKind.MinusToken: + return -value; + case SyntaxKind.TildeToken: + return ~value; } } break; @@ -43884,23 +56547,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const right = evaluate((expr as BinaryExpression).right, location); if (typeof left === "number" && typeof right === "number") { switch ((expr as BinaryExpression).operatorToken.kind) { - case SyntaxKind.BarToken: return left | right; - case SyntaxKind.AmpersandToken: return left & right; - case SyntaxKind.GreaterThanGreaterThanToken: return left >> right; - case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return left >>> right; - case SyntaxKind.LessThanLessThanToken: return left << right; - case SyntaxKind.CaretToken: return left ^ right; - case SyntaxKind.AsteriskToken: return left * right; - case SyntaxKind.SlashToken: return left / right; - case SyntaxKind.PlusToken: return left + right; - case SyntaxKind.MinusToken: return left - right; - case SyntaxKind.PercentToken: return left % right; - case SyntaxKind.AsteriskAsteriskToken: return left ** right; - } - } - else if ((typeof left === "string" || typeof left === "number") && - (typeof right === "string" || typeof right === "number") && - (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken) { + case SyntaxKind.BarToken: + return left | right; + case SyntaxKind.AmpersandToken: + return left & right; + case SyntaxKind.GreaterThanGreaterThanToken: + return left >> right; + case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + return left >>> right; + case SyntaxKind.LessThanLessThanToken: + return left << right; + case SyntaxKind.CaretToken: + return left ^ right; + case SyntaxKind.AsteriskToken: + return left * right; + case SyntaxKind.SlashToken: + return left / right; + case SyntaxKind.PlusToken: + return left + right; + case SyntaxKind.MinusToken: + return left - right; + case SyntaxKind.PercentToken: + return left % right; + case SyntaxKind.AsteriskAsteriskToken: + return left ** right; + } + } + else if ( + (typeof left === "string" || typeof left === "number") + && (typeof right === "string" || typeof right === "number") + && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken + ) { return "" + left + right; } break; @@ -43916,7 +56593,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return evaluate((expr as ParenthesizedExpression).expression, location); case SyntaxKind.Identifier: { const identifier = expr as Identifier; - if (isInfinityOrNaNString(identifier.escapedText) && (resolveEntityName(identifier, SymbolFlags.Value, /*ignoreErrors*/ true) === getGlobalSymbol(identifier.escapedText, SymbolFlags.Value, /*diagnostic*/ undefined))) { + if ( + isInfinityOrNaNString(identifier.escapedText) + && (resolveEntityName(identifier, SymbolFlags.Value, /*ignoreErrors*/ true) + === getGlobalSymbol(identifier.escapedText, SymbolFlags.Value, /*diagnostic*/ undefined)) + ) { return +(identifier.escapedText); } // falls through @@ -43926,11 +56607,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true); if (symbol) { if (symbol.flags & SymbolFlags.EnumMember) { - return location ? evaluateEnumMember(expr, symbol, location) : getEnumMemberValue(symbol.valueDeclaration as EnumMember); + return location ? evaluateEnumMember(expr, symbol, location) + : getEnumMemberValue(symbol.valueDeclaration as EnumMember); } if (isConstantVariable(symbol)) { const declaration = symbol.valueDeclaration as VariableDeclaration | undefined; - if (declaration && !declaration.type && declaration.initializer && (!location || declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location))) { + if ( + declaration && !declaration.type && declaration.initializer + && (!location + || declaration !== location + && isBlockScopedNameDeclaredBeforeUse(declaration, location)) + ) { return evaluate(declaration.initializer, declaration); } } @@ -43939,13 +56626,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; case SyntaxKind.ElementAccessExpression: const root = (expr as ElementAccessExpression).expression; - if (isEntityNameExpression(root) && isStringLiteralLike((expr as ElementAccessExpression).argumentExpression)) { + if ( + isEntityNameExpression(root) + && isStringLiteralLike((expr as ElementAccessExpression).argumentExpression) + ) { const rootSymbol = resolveEntityName(root, SymbolFlags.Value, /*ignoreErrors*/ true); if (rootSymbol && rootSymbol.flags & SymbolFlags.Enum) { - const name = escapeLeadingUnderscores(((expr as ElementAccessExpression).argumentExpression as StringLiteralLike).text); + const name = escapeLeadingUnderscores( + ((expr as ElementAccessExpression).argumentExpression as StringLiteralLike).text, + ); const member = rootSymbol.exports!.get(name); if (member) { - return location ? evaluateEnumMember(expr, member, location) : getEnumMemberValue(member.valueDeclaration as EnumMember); + return location ? evaluateEnumMember(expr, member, location) + : getEnumMemberValue(member.valueDeclaration as EnumMember); } } } @@ -43961,7 +56654,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } if (!isBlockScopedNameDeclaredBeforeUse(declaration, location)) { - error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums); + error( + expr, + Diagnostics + .A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums, + ); return 0; } return getEnumMemberValue(declaration as EnumMember); @@ -44028,7 +56725,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const firstEnumMember = enumDeclaration.members[0]; if (!firstEnumMember.initializer) { if (seenEnumMissingInitialInitializer) { - error(firstEnumMember.name, Diagnostics.In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element); + error( + firstEnumMember.name, + Diagnostics + .In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element, + ); } else { seenEnumMissingInitialInitializer = true; @@ -44051,9 +56752,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const declarations = symbol.declarations; if (declarations) { for (const declaration of declarations) { - if ((declaration.kind === SyntaxKind.ClassDeclaration || - (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((declaration as FunctionLikeDeclaration).body))) && - !(declaration.flags & NodeFlags.Ambient)) { + if ( + (declaration.kind === SyntaxKind.ClassDeclaration + || (declaration.kind === SyntaxKind.FunctionDeclaration + && nodeIsPresent((declaration as FunctionLikeDeclaration).body))) + && !(declaration.flags & NodeFlags.Ambient) + ) { return declaration; } } @@ -44090,7 +56794,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const isGlobalAugmentation = isGlobalScopeAugmentation(node); const inAmbientContext = node.flags & NodeFlags.Ambient; if (isGlobalAugmentation && !inAmbientContext) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_should_have_declare_modifier_unless_they_appear_in_already_ambient_context); + error( + node.name, + Diagnostics + .Augmentations_for_the_global_scope_should_have_declare_modifier_unless_they_appear_in_already_ambient_context, + ); } const isAmbientExternalModule: boolean = isAmbientModule(node); @@ -44116,7 +56824,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getSymbolOfDeclaration(node); // The following checks only apply on a non-ambient instantiated module declaration. - if (symbol.flags & SymbolFlags.ValueModule + if ( + symbol.flags & SymbolFlags.ValueModule && !inAmbientContext && isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions)) ) { @@ -44124,34 +56833,54 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This could be loosened a little if needed. The only problem we are trying to avoid is unqualified // references to namespace members declared in other files. But use of namespaces is discouraged anyway, // so for now we will just not allow them in scripts, which is the only place they can merge cross-file. - error(node.name, Diagnostics.Namespaces_are_not_allowed_in_global_script_files_when_0_is_enabled_If_this_file_is_not_intended_to_be_a_global_script_set_moduleDetection_to_force_or_add_an_empty_export_statement, isolatedModulesLikeFlagName); + error( + node.name, + Diagnostics + .Namespaces_are_not_allowed_in_global_script_files_when_0_is_enabled_If_this_file_is_not_intended_to_be_a_global_script_set_moduleDetection_to_force_or_add_an_empty_export_statement, + isolatedModulesLikeFlagName, + ); } if (symbol.declarations?.length! > 1) { const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); if (firstNonAmbientClassOrFunc) { if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { - error(node.name, Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged); + error( + node.name, + Diagnostics + .A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged, + ); } else if (node.pos < firstNonAmbientClassOrFunc.pos) { - error(node.name, Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged); + error( + node.name, + Diagnostics + .A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged, + ); } } // if the module merges with a class declaration in the same lexical scope, // we need to track this to ensure the correct emit. const mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration); - if (mergedClass && - inSameLexicalScope(node, mergedClass)) { + if ( + mergedClass + && inSameLexicalScope(node, mergedClass) + ) { getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; } } - if (compilerOptions.verbatimModuleSyntax && - node.parent.kind === SyntaxKind.SourceFile && - (moduleKind === ModuleKind.CommonJS || node.parent.impliedNodeFormat === ModuleKind.CommonJS) + if ( + compilerOptions.verbatimModuleSyntax + && node.parent.kind === SyntaxKind.SourceFile + && (moduleKind === ModuleKind.CommonJS || node.parent.impliedNodeFormat === ModuleKind.CommonJS) ) { const exportModifier = node.modifiers?.find(m => m.kind === SyntaxKind.ExportKeyword); if (exportModifier) { - error(exportModifier, Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + error( + exportModifier, + Diagnostics + .A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled, + ); } } } @@ -44163,7 +56892,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We can detect if augmentation was applied using following rules: // - augmentation for a global scope is always applied // - augmentation for some external module is applied if symbol for augmentation is merged (it was combined with target module). - const checkBody = isGlobalAugmentation || (getSymbolOfDeclaration(node).flags & SymbolFlags.Transient); + const checkBody = isGlobalAugmentation + || (getSymbolOfDeclaration(node).flags & SymbolFlags.Transient); if (checkBody && node.body) { for (const statement of node.body.statements) { checkModuleAugmentationElement(statement, isGlobalAugmentation); @@ -44172,7 +56902,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (isGlobalSourceFile(node.parent)) { if (isGlobalAugmentation) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations); + error( + node.name, + Diagnostics + .Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations, + ); } else if (isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(node.name))) { error(node.name, Diagnostics.Ambient_module_declaration_cannot_specify_relative_module_name); @@ -44180,7 +56914,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { if (isGlobalAugmentation) { - error(node.name, Diagnostics.Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations); + error( + node.name, + Diagnostics + .Augmentations_for_the_global_scope_can_only_be_directly_nested_in_external_modules_or_ambient_module_declarations, + ); } else { // Node is not an augmentation and is not located on the script level. @@ -44202,11 +56940,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; case SyntaxKind.ExportAssignment: case SyntaxKind.ExportDeclaration: - grammarErrorOnFirstToken(node, Diagnostics.Exports_and_export_assignments_are_not_permitted_in_module_augmentations); + grammarErrorOnFirstToken( + node, + Diagnostics.Exports_and_export_assignments_are_not_permitted_in_module_augmentations, + ); break; case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ImportDeclaration: - grammarErrorOnFirstToken(node, Diagnostics.Imports_are_not_permitted_in_module_augmentations_Consider_moving_them_to_the_enclosing_external_module); + grammarErrorOnFirstToken( + node, + Diagnostics + .Imports_are_not_permitted_in_module_augmentations_Consider_moving_them_to_the_enclosing_external_module, + ); break; case SyntaxKind.BindingElement: case SyntaxKind.VariableDeclaration: @@ -44239,7 +56984,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.QualifiedName: do { node = node.left; - } while (node.kind !== SyntaxKind.Identifier); + } + while (node.kind !== SyntaxKind.Identifier); return node; case SyntaxKind.PropertyAccessExpression: do { @@ -44247,12 +56993,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return node.name; } node = node.expression; - } while (node.kind !== SyntaxKind.Identifier); + } + while (node.kind !== SyntaxKind.Identifier); return node; } } - function checkExternalImportOrExportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): boolean { + function checkExternalImportOrExportDeclaration( + node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration, + ): boolean { const moduleName = getExternalModuleName(node); if (!moduleName || nodeIsMissing(moduleName)) { // Should be a parse error. @@ -44262,11 +57011,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(moduleName, Diagnostics.String_literal_expected); return false; } - const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); + const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock + && isAmbientModule(node.parent.parent); if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule) { - error(moduleName, node.kind === SyntaxKind.ExportDeclaration ? - Diagnostics.Export_declarations_are_not_permitted_in_a_namespace : - Diagnostics.Import_declarations_in_a_namespace_cannot_reference_a_module); + error( + moduleName, + node.kind === SyntaxKind.ExportDeclaration + ? Diagnostics.Export_declarations_are_not_permitted_in_a_namespace + : Diagnostics.Import_declarations_in_a_namespace_cannot_reference_a_module, + ); return false; } if (inAmbientExternalModule && isExternalModuleNameRelative(moduleName.text)) { @@ -44277,7 +57030,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference // other external modules only through top - level external module names. // Relative external module names are not permitted. - error(node, Diagnostics.Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relative_module_name); + error( + node, + Diagnostics + .Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relative_module_name, + ); return false; } } @@ -44309,54 +57066,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // A type-only import/export will already have a grammar error in a JS file, so no need to issue more errors within if (isInJSFile(node) && !(target.flags & SymbolFlags.Value) && !isTypeOnlyImportOrExportDeclaration(node)) { - const errorNode = - isImportOrExportSpecifier(node) ? node.propertyName || node.name : - isNamedDeclaration(node) ? node.name : - node; + const errorNode = isImportOrExportSpecifier(node) ? node.propertyName || node.name + : isNamedDeclaration(node) ? node.name + : node; Debug.assert(node.kind !== SyntaxKind.NamespaceExport); if (node.kind === SyntaxKind.ExportSpecifier) { - const diag = error(errorNode, Diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files); - const alreadyExportedSymbol = getSourceFileOfNode(node).symbol?.exports?.get((node.propertyName || node.name).escapedText); + const diag = error( + errorNode, + Diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files, + ); + const alreadyExportedSymbol = getSourceFileOfNode(node).symbol?.exports?.get( + (node.propertyName || node.name).escapedText, + ); if (alreadyExportedSymbol === target) { const exportingDeclaration = alreadyExportedSymbol.declarations?.find(isJSDocNode); if (exportingDeclaration) { - addRelatedInfo(diag, createDiagnosticForNode( - exportingDeclaration, - Diagnostics._0_is_automatically_exported_here, - unescapeLeadingUnderscores(alreadyExportedSymbol.escapedName))); + addRelatedInfo( + diag, + createDiagnosticForNode( + exportingDeclaration, + Diagnostics._0_is_automatically_exported_here, + unescapeLeadingUnderscores(alreadyExportedSymbol.escapedName), + ), + ); } } } else { Debug.assert(node.kind !== SyntaxKind.VariableDeclaration); const importDeclaration = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration)); - const moduleSpecifier = (importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration)?.text) ?? "..."; - const importedIdentifier = unescapeLeadingUnderscores(isIdentifier(errorNode) ? errorNode.escapedText : symbol.escapedName); + const moduleSpecifier = + (importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration)?.text) ?? "..."; + const importedIdentifier = unescapeLeadingUnderscores( + isIdentifier(errorNode) ? errorNode.escapedText : symbol.escapedName, + ); error( errorNode, - Diagnostics._0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation, + Diagnostics + ._0_is_a_type_and_cannot_be_imported_in_JavaScript_files_Use_1_in_a_JSDoc_type_annotation, importedIdentifier, - `import("${moduleSpecifier}").${importedIdentifier}`); + `import("${moduleSpecifier}").${importedIdentifier}`, + ); } return; } const targetFlags = getSymbolFlags(target); const excludedMeanings = - (symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) ? SymbolFlags.Value : 0) | - (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) | - (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); + (symbol.flags & (SymbolFlags.Value | SymbolFlags.ExportValue) ? SymbolFlags.Value : 0) + | (symbol.flags & SymbolFlags.Type ? SymbolFlags.Type : 0) + | (symbol.flags & SymbolFlags.Namespace ? SymbolFlags.Namespace : 0); if (targetFlags & excludedMeanings) { - const message = node.kind === SyntaxKind.ExportSpecifier ? - Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 : - Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; + const message = node.kind === SyntaxKind.ExportSpecifier + ? Diagnostics.Export_declaration_conflicts_with_exported_declaration_of_0 + : Diagnostics.Import_declaration_conflicts_with_local_declaration_of_0; error(node, message, symbolToString(symbol)); } - if (getIsolatedModules(compilerOptions) + if ( + getIsolatedModules(compilerOptions) && !isTypeOnlyImportOrExportDeclaration(node) - && !(node.flags & NodeFlags.Ambient)) { + && !(node.flags & NodeFlags.Ambient) + ) { const typeOnlyAlias = getTypeOnlyAliasDeclaration(symbol); const isType = !(targetFlags & SymbolFlags.Value); if (isType || typeOnlyAlias) { @@ -44366,24 +57138,41 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportEqualsDeclaration: { if (compilerOptions.preserveValueImports || compilerOptions.verbatimModuleSyntax) { Debug.assertIsDefined(node.name, "An ImportClause with a symbol should have a name"); - const message = compilerOptions.verbatimModuleSyntax && isInternalModuleImportEqualsDeclaration(node) - ? Diagnostics.An_import_alias_cannot_resolve_to_a_type_or_type_only_declaration_when_verbatimModuleSyntax_is_enabled + const message = compilerOptions.verbatimModuleSyntax + && isInternalModuleImportEqualsDeclaration(node) + ? Diagnostics + .An_import_alias_cannot_resolve_to_a_type_or_type_only_declaration_when_verbatimModuleSyntax_is_enabled : isType - ? compilerOptions.verbatimModuleSyntax - ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled - : Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled - : compilerOptions.verbatimModuleSyntax - ? Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled - : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; - const name = idText(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name); + ? compilerOptions.verbatimModuleSyntax + ? Diagnostics + ._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled + : Diagnostics + ._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled + : compilerOptions.verbatimModuleSyntax + ? Diagnostics + ._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled + : Diagnostics + ._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; + const name = idText( + node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name + : node.name, + ); addTypeOnlyDeclarationRelatedInfo( error(node, message, name), isType ? undefined : typeOnlyAlias, - name + name, ); } - if (isType && node.kind === SyntaxKind.ImportEqualsDeclaration && hasEffectiveModifier(node, ModifierFlags.Export)) { - error(node, Diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_0_is_enabled, isolatedModulesLikeFlagName); + if ( + isType && node.kind === SyntaxKind.ImportEqualsDeclaration + && hasEffectiveModifier(node, ModifierFlags.Export) + ) { + error( + node, + Diagnostics + .Cannot_use_export_import_on_a_type_or_type_only_namespace_when_0_is_enabled, + isolatedModulesLikeFlagName, + ); } break; } @@ -44391,11 +57180,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't allow re-exporting an export that will be elided when `--isolatedModules` is set. // The exception is that `import type { A } from './a'; export { A }` is allowed // because single-file analysis can determine that the export should be dropped. - if (compilerOptions.verbatimModuleSyntax || getSourceFileOfNode(typeOnlyAlias) !== getSourceFileOfNode(node)) { + if ( + compilerOptions.verbatimModuleSyntax + || getSourceFileOfNode(typeOnlyAlias) !== getSourceFileOfNode(node) + ) { const name = idText(node.propertyName || node.name); const diagnostic = isType - ? error(node, Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type, isolatedModulesLikeFlagName) - : error(node, Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_1_is_enabled, name, isolatedModulesLikeFlagName); + ? error( + node, + Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type, + isolatedModulesLikeFlagName, + ) + : error( + node, + Diagnostics + ._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_1_is_enabled, + name, + isolatedModulesLikeFlagName, + ); addTypeOnlyDeclarationRelatedInfo(diagnostic, isType ? undefined : typeOnlyAlias, name); break; } @@ -44403,12 +57205,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - if (compilerOptions.verbatimModuleSyntax && - node.kind !== SyntaxKind.ImportEqualsDeclaration && - !isInJSFile(node) && - (moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + if ( + compilerOptions.verbatimModuleSyntax + && node.kind !== SyntaxKind.ImportEqualsDeclaration + && !isInJSFile(node) + && (moduleKind === ModuleKind.CommonJS + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) ) { - error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + error( + node, + Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled, + ); } } @@ -44454,10 +57261,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkImportBinding(node: ImportEqualsDeclaration | ImportClause | NamespaceImport | ImportSpecifier) { checkCollisionsForDeclarationName(node, node.name); checkAliasSymbol(node); - if (node.kind === SyntaxKind.ImportSpecifier && - idText(node.propertyName || node.name) === "default" && - getESModuleInterop(compilerOptions) && - moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) { + if ( + node.kind === SyntaxKind.ImportSpecifier + && idText(node.propertyName || node.name) === "default" + && getESModuleInterop(compilerOptions) + && moduleKind !== ModuleKind.System + && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault); } } @@ -44465,38 +57275,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkAssertClause(declaration: ImportDeclaration | ExportDeclaration) { if (declaration.assertClause) { const validForTypeAssertions = isExclusivelyTypeOnlyImportOrExport(declaration); - const override = getResolutionModeOverrideForClause(declaration.assertClause, validForTypeAssertions ? grammarErrorOnNode : undefined); + const override = getResolutionModeOverrideForClause( + declaration.assertClause, + validForTypeAssertions ? grammarErrorOnNode : undefined, + ); if (validForTypeAssertions && override) { if (!isNightly()) { - grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next); + grammarErrorOnNode( + declaration.assertClause, + Diagnostics + .resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next, + ); } - if (getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) { - return grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext); + if ( + getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext + ) { + return grammarErrorOnNode( + declaration.assertClause, + Diagnostics + .resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext, + ); } return; // Other grammar checks do not apply to type-only imports with resolution mode assertions } - const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier && getUsageModeForExpression(declaration.moduleSpecifier); + const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier + && getUsageModeForExpression(declaration.moduleSpecifier); if (mode !== ModuleKind.ESNext && moduleKind !== ModuleKind.ESNext) { - return grammarErrorOnNode(declaration.assertClause, + return grammarErrorOnNode( + declaration.assertClause, moduleKind === ModuleKind.NodeNext - ? Diagnostics.Import_assertions_are_not_allowed_on_statements_that_transpile_to_commonjs_require_calls - : Diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext); + ? Diagnostics + .Import_assertions_are_not_allowed_on_statements_that_transpile_to_commonjs_require_calls + : Diagnostics + .Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext_or_nodenext, + ); } if (isImportDeclaration(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly) { - return grammarErrorOnNode(declaration.assertClause, Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports); + return grammarErrorOnNode( + declaration.assertClause, + Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports, + ); } if (override) { - return grammarErrorOnNode(declaration.assertClause, Diagnostics.resolution_mode_can_only_be_set_for_type_only_imports); + return grammarErrorOnNode( + declaration.assertClause, + Diagnostics.resolution_mode_can_only_be_set_for_type_only_imports, + ); } } } function checkImportDeclaration(node: ImportDeclaration) { - if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { + if ( + checkGrammarModuleElementContext( + node, + isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module + : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module, + ) + ) { // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. return; } @@ -44512,7 +57353,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (importClause.namedBindings) { if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { checkImportBinding(importClause.namedBindings); - if (moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && getESModuleInterop(compilerOptions)) { + if ( + moduleKind !== ModuleKind.System + && (moduleKind < ModuleKind.ES2015 + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + && getESModuleInterop(compilerOptions) + ) { // import * as ns from "foo"; checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportStar); } @@ -44530,7 +57376,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) { - if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { + if ( + checkGrammarModuleElementContext( + node, + isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module + : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module, + ) + ) { // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. return; } @@ -44548,8 +57400,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (targetFlags & SymbolFlags.Value) { // Target is a value symbol, check that it is not hidden by a local declaration with the same name const moduleName = getFirstIdentifier(node.moduleReference); - if (!(resolveEntityName(moduleName, SymbolFlags.Value | SymbolFlags.Namespace)!.flags & SymbolFlags.Namespace)) { - error(moduleName, Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, declarationNameToString(moduleName)); + if ( + !(resolveEntityName(moduleName, SymbolFlags.Value | SymbolFlags.Namespace)!.flags + & SymbolFlags.Namespace) + ) { + error( + moduleName, + Diagnostics.Module_0_is_hidden_by_a_local_declaration_with_the_same_name, + declarationNameToString(moduleName), + ); } } if (targetFlags & SymbolFlags.Type) { @@ -44561,16 +57420,29 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else { - if (moduleKind >= ModuleKind.ES2015 && getSourceFileOfNode(node).impliedNodeFormat === undefined && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient)) { + if ( + moduleKind >= ModuleKind.ES2015 && getSourceFileOfNode(node).impliedNodeFormat === undefined + && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient) + ) { // Import equals declaration is deprecated in es6 or above - grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead); + grammarErrorOnNode( + node, + Diagnostics + .Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead, + ); } } } } function checkExportDeclaration(node: ExportDeclaration) { - if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) { + if ( + checkGrammarModuleElementContext( + node, + isInJSFile(node) ? Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_module + : Diagnostics.An_export_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module, + ) + ) { // If we hit an export in an illegal context, just bail out to avoid cascading errors. return; } @@ -44579,7 +57451,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers); } - if (node.moduleSpecifier && node.exportClause && isNamedExports(node.exportClause) && length(node.exportClause.elements) && languageVersion === ScriptTarget.ES3) { + if ( + node.moduleSpecifier && node.exportClause && isNamedExports(node.exportClause) + && length(node.exportClause.elements) && languageVersion === ScriptTarget.ES3 + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.CreateBinding); } @@ -44589,10 +57464,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // export { x, y } // export { x, y } from "foo" forEach(node.exportClause.elements, checkExportSpecifier); - const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock && isAmbientModule(node.parent.parent); - const inAmbientNamespaceDeclaration = !inAmbientExternalModule && node.parent.kind === SyntaxKind.ModuleBlock && - !node.moduleSpecifier && node.flags & NodeFlags.Ambient; - if (node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule && !inAmbientNamespaceDeclaration) { + const inAmbientExternalModule = node.parent.kind === SyntaxKind.ModuleBlock + && isAmbientModule(node.parent.parent); + const inAmbientNamespaceDeclaration = !inAmbientExternalModule + && node.parent.kind === SyntaxKind.ModuleBlock + && !node.moduleSpecifier && node.flags & NodeFlags.Ambient; + if ( + node.parent.kind !== SyntaxKind.SourceFile && !inAmbientExternalModule + && !inAmbientNamespaceDeclaration + ) { error(node, Diagnostics.Export_declarations_are_not_permitted_in_a_namespace); } } @@ -44601,12 +57481,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // export * as ns from "foo"; const moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier!); if (moduleSymbol && hasExportAssignmentSymbol(moduleSymbol)) { - error(node.moduleSpecifier, Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol)); + error( + node.moduleSpecifier, + Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, + symbolToString(moduleSymbol), + ); } else if (node.exportClause) { checkAliasSymbol(node.exportClause); } - if (moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) { + if ( + moduleKind !== ModuleKind.System + && (moduleKind < ModuleKind.ES2015 + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + ) { if (node.exportClause) { // export * as ns from "foo"; // For ES2015 modules, we emit it as a pair of `import * as a_1 ...; export { a_1 as ns }` and don't need the helper. @@ -44633,7 +57521,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkGrammarModuleElementContext(node: Statement, errorMessage: DiagnosticMessage): boolean { - const isInAppropriateContext = node.parent.kind === SyntaxKind.SourceFile || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.ModuleDeclaration; + const isInAppropriateContext = node.parent.kind === SyntaxKind.SourceFile + || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.ModuleDeclaration; if (!isInAppropriateContext) { grammarErrorOnFirstToken(node, errorMessage); } @@ -44653,21 +57542,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function canConvertImportDeclarationToTypeOnly(statement: Statement) { - return isImportDeclaration(statement) && - statement.importClause && - !statement.importClause.isTypeOnly && - importClauseContainsReferencedImport(statement.importClause) && - !isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) && - !importClauseContainsConstEnumUsedAsValue(statement.importClause); + return isImportDeclaration(statement) + && statement.importClause + && !statement.importClause.isTypeOnly + && importClauseContainsReferencedImport(statement.importClause) + && !isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) + && !importClauseContainsConstEnumUsedAsValue(statement.importClause); } function canConvertImportEqualsDeclarationToTypeOnly(statement: Statement) { - return isImportEqualsDeclaration(statement) && - isExternalModuleReference(statement.moduleReference) && - !statement.isTypeOnly && - getSymbolOfDeclaration(statement).isReferenced && - !isReferencedAliasDeclaration(statement, /*checkChildren*/ false) && - !getSymbolLinks(getSymbolOfDeclaration(statement)).constEnumReferenced; + return isImportEqualsDeclaration(statement) + && isExternalModuleReference(statement.moduleReference) + && !statement.isTypeOnly + && getSymbolOfDeclaration(statement).isReferenced + && !isReferencedAliasDeclaration(statement, /*checkChildren*/ false) + && !getSymbolLinks(getSymbolOfDeclaration(statement)).constEnumReferenced; } function checkImportsForTypeOnlyConversion(sourceFile: SourceFile) { @@ -44675,10 +57564,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } for (const statement of sourceFile.statements) { - if (canConvertImportDeclarationToTypeOnly(statement) || canConvertImportEqualsDeclarationToTypeOnly(statement)) { + if ( + canConvertImportDeclarationToTypeOnly(statement) + || canConvertImportEqualsDeclarationToTypeOnly(statement) + ) { error( statement, - Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error); + Diagnostics + .This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error, + ); } } } @@ -44691,10 +57585,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!node.parent.parent.moduleSpecifier) { const exportedName = node.propertyName || node.name; // find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases) - const symbol = resolveName(exportedName, exportedName.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, - /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); - if (symbol && (symbol === undefinedSymbol || symbol === globalThisSymbol || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0])))) { - error(exportedName, Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, idText(exportedName)); + const symbol = resolveName( + exportedName, + exportedName.escapedText, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + ); + if ( + symbol + && (symbol === undefinedSymbol || symbol === globalThisSymbol + || symbol.declarations && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0]))) + ) { + error( + exportedName, + Diagnostics.Cannot_export_0_Only_local_declarations_can_be_exported_from_a_module, + idText(exportedName), + ); } else { if (!node.isTypeOnly && !node.parent.parent.isTypeOnly) { @@ -44707,10 +57615,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else { - if (getESModuleInterop(compilerOptions) && - moduleKind !== ModuleKind.System && - (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && - idText(node.propertyName || node.name) === "default") { + if ( + getESModuleInterop(compilerOptions) + && moduleKind !== ModuleKind.System + && (moduleKind < ModuleKind.ES2015 + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + && idText(node.propertyName || node.name) === "default" + ) { checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault); } } @@ -44725,7 +57636,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } - const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent as ModuleDeclaration; + const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent + : node.parent.parent as ModuleDeclaration; if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) { if (node.isExportEquals) { error(node, Diagnostics.An_export_assignment_cannot_be_used_in_a_namespace); @@ -44743,37 +57655,58 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const typeAnnotationNode = getEffectiveTypeAnnotationNode(node); if (typeAnnotationNode) { - checkTypeAssignableTo(checkExpressionCached(node.expression), getTypeFromTypeNode(typeAnnotationNode), node.expression); + checkTypeAssignableTo( + checkExpressionCached(node.expression), + getTypeFromTypeNode(typeAnnotationNode), + node.expression, + ); } - const isIllegalExportDefaultInCJS = !node.isExportEquals && - !(node.flags & NodeFlags.Ambient) && - compilerOptions.verbatimModuleSyntax && - (moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS); + const isIllegalExportDefaultInCJS = !node.isExportEquals + && !(node.flags & NodeFlags.Ambient) + && compilerOptions.verbatimModuleSyntax + && (moduleKind === ModuleKind.CommonJS + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS); if (node.expression.kind === SyntaxKind.Identifier) { const id = node.expression as Identifier; - const sym = getExportSymbolOfValueSymbolIfExported(resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node)); + const sym = getExportSymbolOfValueSymbolIfExported( + resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node), + ); if (sym) { markAliasReferenced(sym, id); // If not a value, we're interpreting the identifier as a type export, along the lines of (`export { Id as default }`) if (getSymbolFlags(sym) & SymbolFlags.Value) { // However if it is a value, we need to check it's being used correctly checkExpressionCached(id); - if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax && getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value)) { - error(id, + if ( + !isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) + && compilerOptions.verbatimModuleSyntax && getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value) + ) { + error( + id, node.isExportEquals - ? Diagnostics.An_export_declaration_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration - : Diagnostics.An_export_default_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration, - idText(id)); + ? Diagnostics + .An_export_declaration_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration + : Diagnostics + .An_export_default_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration, + idText(id), + ); } } - else if (!isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) && compilerOptions.verbatimModuleSyntax) { - error(id, + else if ( + !isIllegalExportDefaultInCJS && !(node.flags & NodeFlags.Ambient) + && compilerOptions.verbatimModuleSyntax + ) { + error( + id, node.isExportEquals - ? Diagnostics.An_export_declaration_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type - : Diagnostics.An_export_default_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type, - idText(id)); + ? Diagnostics + .An_export_declaration_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type + : Diagnostics + .An_export_default_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type, + idText(id), + ); } } else { @@ -44789,22 +57722,37 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isIllegalExportDefaultInCJS) { - error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + error( + node, + Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled, + ); } checkExternalModuleExports(container); if ((node.flags & NodeFlags.Ambient) && !isEntityNameExpression(node.expression)) { - grammarErrorOnNode(node.expression, Diagnostics.The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context); + grammarErrorOnNode( + node.expression, + Diagnostics + .The_expression_of_an_export_assignment_must_be_an_identifier_or_qualified_name_in_an_ambient_context, + ); } if (node.isExportEquals) { // Forbid export= in esm implementation files, and esm mode declaration files - if (moduleKind >= ModuleKind.ES2015 && - ((node.flags & NodeFlags.Ambient && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.ESNext) || - (!(node.flags & NodeFlags.Ambient) && getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.CommonJS))) { + if ( + moduleKind >= ModuleKind.ES2015 + && ((node.flags & NodeFlags.Ambient + && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.ESNext) + || (!(node.flags & NodeFlags.Ambient) + && getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.CommonJS)) + ) { // export assignment is not supported in es6 modules - grammarErrorOnNode(node, Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead); + grammarErrorOnNode( + node, + Diagnostics + .Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead, + ); } else if (moduleKind === ModuleKind.System && !(node.flags & NodeFlags.Ambient)) { // system modules does not support export assignment @@ -44823,9 +57771,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!links.exportsChecked) { const exportEqualsSymbol = moduleSymbol.exports!.get("export=" as __String); if (exportEqualsSymbol && hasExportedMembers(moduleSymbol)) { - const declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) || exportEqualsSymbol.valueDeclaration; + const declaration = getDeclarationOfAliasSymbol(exportEqualsSymbol) + || exportEqualsSymbol.valueDeclaration; if (declaration && !isTopLevelInExternalModuleAugmentation(declaration) && !isInJSFile(declaration)) { - error(declaration, Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements); + error( + declaration, + Diagnostics.An_export_assignment_cannot_be_used_in_a_module_with_other_exported_elements, + ); } } // Checks for export * conflicts @@ -44840,7 +57792,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & (SymbolFlags.Namespace | SymbolFlags.Enum)) { return; } - const exportedDeclarationsCount = countWhere(declarations, and(isNotOverloadAndNotAccessor, not(isInterfaceDeclaration))); + const exportedDeclarationsCount = countWhere( + declarations, + and(isNotOverloadAndNotAccessor, not(isInterfaceDeclaration)), + ); if (flags & SymbolFlags.TypeAlias && exportedDeclarationsCount <= 2) { // it is legal to merge type alias with other values // so count should be either 1 (just type alias) or 2 (type alias + merged value) @@ -44850,7 +57805,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isDuplicatedCommonJSExport(declarations)) { for (const declaration of declarations!) { if (isNotOverload(declaration)) { - diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Cannot_redeclare_exported_variable_0, unescapeLeadingUnderscores(id))); + diagnostics.add( + createDiagnosticForNode( + declaration, + Diagnostics.Cannot_redeclare_exported_variable_0, + unescapeLeadingUnderscores(id), + ), + ); } } } @@ -44864,7 +57825,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isDuplicatedCommonJSExport(declarations: Declaration[] | undefined) { return declarations && declarations.length > 1 - && declarations.every(d => isInJSFile(d) && isAccessExpression(d) && (isExportsIdentifier(d.expression) || isModuleExportsAccessExpression(d.expression))); + && declarations.every(d => + isInJSFile(d) && isAccessExpression(d) + && (isExportsIdentifier(d.expression) || isModuleExportsAccessExpression(d.expression)) + ); } function checkSourceElement(node: Node | undefined): void { @@ -44902,8 +57866,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { cancellationToken.throwIfCancellationRequested(); } } - if (kind >= SyntaxKind.FirstStatement && kind <= SyntaxKind.LastStatement && canHaveFlowNode(node) && node.flowNode && !isReachableFlowNode(node.flowNode)) { - errorOrSuggestion(compilerOptions.allowUnreachableCode === false, node, Diagnostics.Unreachable_code_detected); + if ( + kind >= SyntaxKind.FirstStatement && kind <= SyntaxKind.LastStatement && canHaveFlowNode(node) + && node.flowNode && !isReachableFlowNode(node.flowNode) + ) { + errorOrSuggestion( + compilerOptions.allowUnreachableCode === false, + node, + Diagnostics.Unreachable_code_detected, + ); } switch (kind) { @@ -45090,15 +58061,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJSDocTypeIsInJsFile(node: Node): void { if (!isInJSFile(node)) { if (isJSDocNonNullableType(node) || isJSDocNullableType(node)) { - const token = tokenToString(isJSDocNonNullableType(node) ? SyntaxKind.ExclamationToken : SyntaxKind.QuestionToken); + const token = tokenToString( + isJSDocNonNullableType(node) ? SyntaxKind.ExclamationToken : SyntaxKind.QuestionToken, + ); const diagnostic = node.postfix ? Diagnostics._0_at_the_end_of_a_type_is_not_valid_TypeScript_syntax_Did_you_mean_to_write_1 : Diagnostics._0_at_the_start_of_a_type_is_not_valid_TypeScript_syntax_Did_you_mean_to_write_1; const typeNode = node.type; const type = getTypeFromTypeNode(typeNode); - grammarErrorOnNode(node, diagnostic, token, typeToString( - isJSDocNullableType(node) && !(type === neverType || type === voidType) - ? getUnionType(append([type, undefinedType], node.postfix ? undefined : nullType)) : type)); + grammarErrorOnNode( + node, + diagnostic, + token, + typeToString( + isJSDocNullableType(node) && !(type === neverType || type === voidType) + ? getUnionType(append([type, undefinedType], node.postfix ? undefined : nullType)) : type, + ), + ); } else { grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); @@ -45161,8 +58140,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? lastOrUndefined((paramTag.parent.parent as unknown as JSDocCallbackTag).typeExpression.parameters) : lastOrUndefined(host!.parameters); const symbol = getParameterSymbolFromJSDoc(paramTag); - if (!lastParamDeclaration || - symbol && lastParamDeclaration.symbol === symbol && isRestParameter(lastParamDeclaration)) { + if ( + !lastParamDeclaration + || symbol && lastParamDeclaration.symbol === symbol && isRestParameter(lastParamDeclaration) + ) { return createArrayType(type); } } @@ -45203,7 +58184,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkDeferredNode(node: Node) { - tracing?.push(tracing.Phase.Check, "checkDeferredNode", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath }); + tracing?.push(tracing.Phase.Check, "checkDeferredNode", { + kind: node.kind, + pos: node.pos, + end: node.end, + path: (node as TracingNode).tracingPath, + }); const saveCurrentNode = currentNode; currentNode = node; instantiationCount = 0; @@ -45306,7 +58292,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // This relies on the results of other lazy diagnostics, so must be computed after them if (!node.isDeclarationFile && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters)) { checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(node), (containingNode, kind, diag) => { - if (!containsParseError(containingNode) && unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient))) { + if ( + !containsParseError(containingNode) + && unusedIsError(kind, !!(containingNode.flags & NodeFlags.Ambient)) + ) { diagnostics.add(diag); } }); @@ -45316,9 +58305,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } }); - if (compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error && - !node.isDeclarationFile && - isExternalModule(node) + if ( + compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error + && !node.isDeclarationFile + && isExternalModule(node) ) { checkImportsForTypeOnlyConversion(node); } @@ -45400,7 +58390,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const currentGlobalDiagnostics = diagnostics.getGlobalDiagnostics(); if (currentGlobalDiagnostics !== previousGlobalDiagnostics) { // If the arrays are not the same reference, new diagnostics were added. - const deferredGlobalDiagnostics = relativeComplement(previousGlobalDiagnostics, currentGlobalDiagnostics, compareDiagnostics); + const deferredGlobalDiagnostics = relativeComplement( + previousGlobalDiagnostics, + currentGlobalDiagnostics, + compareDiagnostics, + ); return concatenate(deferredGlobalDiagnostics, semanticDiagnostics); } else if (previousGlobalDiagnosticsSize === 0 && currentGlobalDiagnostics.length > 0) { @@ -45451,10 +58445,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isExternalModule(location as SourceFile)) break; // falls through case SyntaxKind.ModuleDeclaration: - copyLocallyVisibleExportSymbols(getSymbolOfDeclaration(location as ModuleDeclaration | SourceFile).exports!, meaning & SymbolFlags.ModuleMember); + copyLocallyVisibleExportSymbols( + getSymbolOfDeclaration(location as ModuleDeclaration | SourceFile).exports!, + meaning & SymbolFlags.ModuleMember, + ); break; case SyntaxKind.EnumDeclaration: - copySymbols(getSymbolOfDeclaration(location as EnumDeclaration).exports!, meaning & SymbolFlags.EnumMember); + copySymbols( + getSymbolOfDeclaration(location as EnumDeclaration).exports!, + meaning & SymbolFlags.EnumMember, + ); break; case SyntaxKind.ClassExpression: const className = (location as ClassExpression).name; @@ -45472,7 +58472,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // (type parameters of classDeclaration/classExpression and interface are in member property of the symbol. // Note: that the memberFlags come from previous iteration. if (!isStaticSymbol) { - copySymbols(getMembersOfSymbol(getSymbolOfDeclaration(location as ClassDeclaration | InterfaceDeclaration)), meaning & SymbolFlags.Type); + copySymbols( + getMembersOfSymbol( + getSymbolOfDeclaration(location as ClassDeclaration | InterfaceDeclaration), + ), + meaning & SymbolFlags.Type, + ); } break; case SyntaxKind.FunctionExpression: @@ -45525,7 +58530,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (meaning) { source.forEach(symbol => { // Similar condition as in `resolveNameHelper` - if (!getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier) && !getDeclarationOfKind(symbol, SyntaxKind.NamespaceExport) && symbol.escapedName !== InternalSymbolName.Default) { + if ( + !getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier) + && !getDeclarationOfKind(symbol, SyntaxKind.NamespaceExport) + && symbol.escapedName !== InternalSymbolName.Default + ) { copySymbol(symbol, meaning); } }); @@ -45534,9 +58543,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isTypeDeclarationName(name: Node): boolean { - return name.kind === SyntaxKind.Identifier && - isTypeDeclaration(name.parent) && - getNameOfDeclaration(name.parent) === name; + return name.kind === SyntaxKind.Identifier + && isTypeDeclaration(name.parent) + && getNameOfDeclaration(name.parent) === name; } // True if the given identifier is part of a type reference @@ -45556,7 +58565,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return node.parent.kind === SyntaxKind.ExpressionWithTypeArguments; } - function forEachEnclosingClass(node: Node, callback: (node: ClassLikeDeclaration) => T | undefined): T | undefined { + function forEachEnclosingClass( + node: Node, + callback: (node: ClassLikeDeclaration) => T | undefined, + ): T | undefined { let result: T | undefined; let containingClass = getContainingClass(node); while (containingClass) { @@ -45584,17 +58596,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!forEachEnclosingClass(node, n => n === classDeclaration); } - function getLeftSideOfImportEqualsOrExportAssignment(nodeOnRightSide: EntityName): ImportEqualsDeclaration | ExportAssignment | undefined { + function getLeftSideOfImportEqualsOrExportAssignment( + nodeOnRightSide: EntityName, + ): ImportEqualsDeclaration | ExportAssignment | undefined { while (nodeOnRightSide.parent.kind === SyntaxKind.QualifiedName) { nodeOnRightSide = nodeOnRightSide.parent as QualifiedName; } if (nodeOnRightSide.parent.kind === SyntaxKind.ImportEqualsDeclaration) { - return (nodeOnRightSide.parent as ImportEqualsDeclaration).moduleReference === nodeOnRightSide ? nodeOnRightSide.parent as ImportEqualsDeclaration : undefined; + return (nodeOnRightSide.parent as ImportEqualsDeclaration).moduleReference === nodeOnRightSide + ? nodeOnRightSide.parent as ImportEqualsDeclaration : undefined; } if (nodeOnRightSide.parent.kind === SyntaxKind.ExportAssignment) { - return (nodeOnRightSide.parent as ExportAssignment).expression === nodeOnRightSide as Node ? nodeOnRightSide.parent as ExportAssignment : undefined; + return (nodeOnRightSide.parent as ExportAssignment).expression === nodeOnRightSide as Node + ? nodeOnRightSide.parent as ExportAssignment : undefined; } return undefined; @@ -45605,7 +58621,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getSpecialPropertyAssignmentSymbolFromEntityName(entityName: EntityName | PropertyAccessExpression) { - const specialPropertyAssignmentKind = getAssignmentDeclarationKind(entityName.parent.parent as BinaryExpression); + const specialPropertyAssignmentKind = getAssignmentDeclarationKind( + entityName.parent.parent as BinaryExpression, + ); switch (specialPropertyAssignmentKind) { case AssignmentDeclarationKind.ExportsProperty: case AssignmentDeclarationKind.PrototypeProperty: @@ -45631,11 +58649,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isThisPropertyAndThisTyped(node: PropertyAccessExpression) { if (node.expression.kind === SyntaxKind.ThisKeyword) { - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); if (isFunctionLike(container)) { const containingLiteral = getContainingObjectLiteral(container); if (containingLiteral) { - const contextualType = getApparentTypeOfContextualType(containingLiteral, /*contextFlags*/ undefined); + const contextualType = getApparentTypeOfContextualType( + containingLiteral, + /*contextFlags*/ undefined, + ); const type = getThisTypeOfObjectLiteralFromContextualType(containingLiteral, contextualType); return type && !isTypeAny(type); } @@ -45643,16 +58668,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getSymbolOfNameOrPropertyAccessExpression(name: EntityName | PrivateIdentifier | PropertyAccessExpression | JSDocMemberName): Symbol | undefined { + function getSymbolOfNameOrPropertyAccessExpression( + name: EntityName | PrivateIdentifier | PropertyAccessExpression | JSDocMemberName, + ): Symbol | undefined { if (isDeclarationName(name)) { return getSymbolOfNode(name.parent); } - if (isInJSFile(name) && - name.parent.kind === SyntaxKind.PropertyAccessExpression && - name.parent === (name.parent.parent as BinaryExpression).left) { + if ( + isInJSFile(name) + && name.parent.kind === SyntaxKind.PropertyAccessExpression + && name.parent === (name.parent.parent as BinaryExpression).left + ) { // Check if this is a special property assignment - if (!isPrivateIdentifier(name) && !isJSDocMemberName(name) && !isThisPropertyAndThisTyped(name.parent as PropertyAccessExpression)) { + if ( + !isPrivateIdentifier(name) && !isJSDocMemberName(name) + && !isThisPropertyAndThisTyped(name.parent as PropertyAccessExpression) + ) { const specialPropertyAssignmentSymbol = getSpecialPropertyAssignmentSymbolFromEntityName(name); if (specialPropertyAssignmentSymbol) { return specialPropertyAssignmentSymbol; @@ -45662,8 +58694,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (name.parent.kind === SyntaxKind.ExportAssignment && isEntityNameExpression(name)) { // Even an entity name expression that doesn't resolve as an entityname may still typecheck as a property access expression - const success = resolveEntityName(name, - /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*ignoreErrors*/ true); + const success = resolveEntityName( + name, + /*all meanings*/ SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + /*ignoreErrors*/ true, + ); if (success && success !== unknownSymbol) { return success; } @@ -45705,7 +58740,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } meaning |= SymbolFlags.Alias; - const entityNameSymbol = isEntityNameExpression(name) ? resolveEntityName(name, meaning, /*ignoreErrors*/ true) : undefined; + const entityNameSymbol = isEntityNameExpression(name) + ? resolveEntityName(name, meaning, /*ignoreErrors*/ true) : undefined; if (entityNameSymbol) { return entityNameSymbol; } @@ -45717,7 +58753,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (name.parent.kind === SyntaxKind.TypeParameter && name.parent.parent.kind === SyntaxKind.JSDocTemplateTag) { Debug.assert(!isInJSFile(name)); // Otherwise `isDeclarationName` would have been true. - const typeParameter = getTypeParameterFromJsDoc(name.parent as TypeParameterDeclaration & { parent: JSDocTemplateTag }); + const typeParameter = getTypeParameterFromJsDoc( + name.parent as TypeParameterDeclaration & { parent: JSDocTemplateTag; }, + ); return typeParameter && typeParameter.symbol; } @@ -45734,7 +58772,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const symbol = getIntrinsicTagSymbol(name.parent as JsxOpeningLikeElement); return symbol === unknownSymbol ? undefined : symbol; } - const result = resolveEntityName(name, meaning, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name)); + const result = resolveEntityName( + name, + meaning, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + getHostSignatureFromJSDoc(name), + ); if (!result && isJSDoc) { const container = findAncestor(name, or(isClassLike, isInterfaceDeclaration)); if (container) { @@ -45744,7 +58788,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (result && isJSDoc) { const container = getJSDocHost(name); if (container && isEnumMember(container) && container === result.valueDeclaration) { - return resolveEntityName(name, meaning, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, getSourceFileOfNode(container)) || result; + return resolveEntityName( + name, + meaning, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + getSourceFileOfNode(container), + ) || result; } } return result; @@ -45761,7 +58811,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (name.kind === SyntaxKind.PropertyAccessExpression) { checkPropertyAccessExpression(name, CheckMode.Normal); if (!links.resolvedSymbol) { - links.resolvedSymbol = getApplicableIndexSymbol(checkExpressionCached(name.expression), getLiteralTypeFromPropertyName(name.name)); + links.resolvedSymbol = getApplicableIndexSymbol( + checkExpressionCached(name.expression), + getLiteralTypeFromPropertyName(name.name), + ); } } else { @@ -45778,7 +58831,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (isTypeReferenceIdentifier(name as EntityName)) { const meaning = name.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; - const symbol = resolveEntityName(name as EntityName, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ true); + const symbol = resolveEntityName( + name as EntityName, + meaning, + /*ignoreErrors*/ false, + /*dontResolveAlias*/ true, + ); return symbol && symbol !== unknownSymbol ? symbol : getUnresolvedSymbolForEntityName(name as EntityName); } if (name.parent.kind === SyntaxKind.TypePredicate) { @@ -45808,7 +58866,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { const copy = createSymbol(SymbolFlags.Signature, InternalSymbolName.Index); copy.declarations = mapDefined(infos, i => i.declaration); - copy.parent = type.aliasSymbol ? type.aliasSymbol : type.symbol ? type.symbol : getSymbolAtLocation(copy.declarations[0].parent); + copy.parent = type.aliasSymbol ? type.aliasSymbol + : type.symbol ? type.symbol : getSymbolAtLocation(copy.declarations[0].parent); symbolLinks.filteredIndexSymbolCache.set(nodeListId, copy); return copy; } @@ -45824,11 +58883,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * For unqualified names, a container K may be provided as a second argument. */ - function resolveJSDocMemberName(name: EntityName | JSDocMemberName, ignoreErrors?: boolean, container?: Symbol): Symbol | undefined { + function resolveJSDocMemberName( + name: EntityName | JSDocMemberName, + ignoreErrors?: boolean, + container?: Symbol, + ): Symbol | undefined { if (isEntityName(name)) { // resolve static values first const meaning = SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value; - let symbol = resolveEntityName(name, meaning, ignoreErrors, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name)); + let symbol = resolveEntityName( + name, + meaning, + ignoreErrors, + /*dontResolveAlias*/ true, + getHostSignatureFromJSDoc(name), + ); if (!symbol && isIdentifier(name) && container) { symbol = getMergedSymbol(getSymbol(getExportsOfSymbol(container), name.escapedText, meaning)); } @@ -45839,7 +58908,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const left = isIdentifier(name) ? container : resolveJSDocMemberName(name.left, ignoreErrors, container); const right = isIdentifier(name) ? name.escapedText : name.right.escapedText; if (left) { - const proto = left.flags & SymbolFlags.Value && getPropertyOfType(getTypeOfSymbol(left), "prototype" as __String); + const proto = left.flags & SymbolFlags.Value + && getPropertyOfType(getTypeOfSymbol(left), "prototype" as __String); const t = proto ? getTypeOfSymbol(proto) : getDeclaredTypeOfSymbol(left); return getPropertyOfType(t, right); } @@ -45872,9 +58942,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInRightSideOfImportOrExportAssignment(node as Identifier)) { return getSymbolOfNameOrPropertyAccessExpression(node as Identifier); } - else if (parent.kind === SyntaxKind.BindingElement && - grandParent.kind === SyntaxKind.ObjectBindingPattern && - node === (parent as BindingElement).propertyName) { + else if ( + parent.kind === SyntaxKind.BindingElement + && grandParent.kind === SyntaxKind.ObjectBindingPattern + && node === (parent as BindingElement).propertyName + ) { const typeOfPattern = getTypeOfNode(grandParent); const propertyDeclaration = getPropertyOfType(typeOfPattern, (node as Identifier).escapedText); @@ -45905,12 +58977,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.PropertyAccessExpression: case SyntaxKind.QualifiedName: if (!isThisInTypeQuery(node)) { - return getSymbolOfNameOrPropertyAccessExpression(node as EntityName | PrivateIdentifier | PropertyAccessExpression); + return getSymbolOfNameOrPropertyAccessExpression( + node as EntityName | PrivateIdentifier | PropertyAccessExpression, + ); } // falls through case SyntaxKind.ThisKeyword: - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); if (isFunctionLike(container)) { const sig = getSignatureFromDeclaration(container); if (sig.thisParameter) { @@ -45942,14 +59020,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 2). External module name in an import declaration // 3). Dynamic import call or require in javascript // 4). type A = import("./f/*gotToDefinitionHere*/oo") - if ((isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) || - ((node.parent.kind === SyntaxKind.ImportDeclaration || node.parent.kind === SyntaxKind.ExportDeclaration) && (node.parent as ImportDeclaration).moduleSpecifier === node) || - ((isInJSFile(node) && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler && isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false)) || isImportCall(node.parent)) || - (isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) && node.parent.parent.argument === node.parent) + if ( + (isExternalModuleImportEqualsDeclaration(node.parent.parent) + && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node) + || ((node.parent.kind === SyntaxKind.ImportDeclaration + || node.parent.kind === SyntaxKind.ExportDeclaration) + && (node.parent as ImportDeclaration).moduleSpecifier === node) + || ((isInJSFile(node) + && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler + && isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false)) + || isImportCall(node.parent)) + || (isLiteralTypeNode(node.parent) && isLiteralImportTypeNode(node.parent.parent) + && node.parent.parent.argument === node.parent) ) { return resolveExternalModuleName(node, node as LiteralExpression, ignoreErrors); } - if (isCallExpression(parent) && isBindableObjectDefinePropertyCall(parent) && parent.arguments[1] === node) { + if ( + isCallExpression(parent) && isBindableObjectDefinePropertyCall(parent) + && parent.arguments[1] === node + ) { return getSymbolOfDeclaration(parent); } // falls through @@ -45959,9 +59048,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const objectType = isElementAccessExpression(parent) ? parent.argumentExpression === node ? getTypeOfExpression(parent.expression) : undefined : isLiteralTypeNode(parent) && isIndexedAccessTypeNode(grandParent) - ? getTypeFromTypeNode(grandParent.objectType) - : undefined; - return objectType && getPropertyOfType(objectType, escapeLeadingUnderscores((node as StringLiteral | NumericLiteral).text)); + ? getTypeFromTypeNode(grandParent.objectType) + : undefined; + return objectType + && getPropertyOfType( + objectType, + escapeLeadingUnderscores((node as StringLiteral | NumericLiteral).text), + ); case SyntaxKind.DefaultKeyword: case SyntaxKind.FunctionKeyword: @@ -45969,7 +59062,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ClassKeyword: return getSymbolOfNode(node.parent); case SyntaxKind.ImportType: - return isLiteralImportTypeNode(node) ? getSymbolAtLocation(node.argument.literal, ignoreErrors) : undefined; + return isLiteralImportTypeNode(node) ? getSymbolAtLocation(node.argument.literal, ignoreErrors) + : undefined; case SyntaxKind.ExportKeyword: return isExportAssignment(node.parent) ? Debug.checkDefined(node.parent.symbol) : undefined; @@ -45996,14 +59090,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const keyType = getLiteralTypeFromPropertyName(node); const objectType = getTypeOfExpression(node.parent.expression); const objectTypes = objectType.flags & TypeFlags.Union ? (objectType as UnionType).types : [objectType]; - return flatMap(objectTypes, t => filter(getIndexInfosOfType(t), info => isApplicableIndexType(keyType, info.keyType))); + return flatMap( + objectTypes, + t => filter(getIndexInfosOfType(t), info => isApplicableIndexType(keyType, info.keyType)), + ); } return undefined; } function getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined { if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) { - return resolveEntityName((location as ShorthandPropertyAssignment).name, SymbolFlags.Value | SymbolFlags.Alias); + return resolveEntityName( + (location as ShorthandPropertyAssignment).name, + SymbolFlags.Value | SymbolFlags.Alias, + ); } return undefined; } @@ -46011,12 +59111,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** Returns the target of an export specifier without following aliases */ function getExportSpecifierLocalTargetSymbol(node: ExportSpecifier | Identifier): Symbol | undefined { if (isExportSpecifier(node)) { - return node.parent.parent.moduleSpecifier ? - getExternalModuleMember(node.parent.parent, node) : - resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + return node.parent.parent.moduleSpecifier + ? getExternalModuleMember(node.parent.parent, node) + : resolveEntityName( + node.propertyName || node.name, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + ); } else { - return resolveEntityName(node, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); + return resolveEntityName( + node, + SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, + ); } } @@ -46078,7 +59184,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isBindingPattern(node)) { - return getTypeForVariableLikeDeclaration(node.parent, /*includeOptionality*/ true, CheckMode.Normal) || errorType; + return getTypeForVariableLikeDeclaration(node.parent, /*includeOptionality*/ true, CheckMode.Normal) + || errorType; } if (isInRightSideOfImportOrExportAssignment(node as Identifier)) { @@ -46103,7 +59210,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // [ a ] from // [a] = [ some array ...] function getTypeOfAssignmentPattern(expr: AssignmentPattern): Type | undefined { - Debug.assert(expr.kind === SyntaxKind.ObjectLiteralExpression || expr.kind === SyntaxKind.ArrayLiteralExpression); + Debug.assert( + expr.kind === SyntaxKind.ObjectLiteralExpression || expr.kind === SyntaxKind.ArrayLiteralExpression, + ); // If this is from "for of" // for ( { a } of elems) { // } @@ -46129,8 +59238,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const node = cast(expr.parent, isArrayLiteralExpression); // [{ property1: p1, property2 }] = elems; const typeOfArrayLiteral = getTypeOfAssignmentPattern(node) || errorType; - const elementType = checkIteratedTypeOrElementType(IterationUse.Destructuring, typeOfArrayLiteral, undefinedType, expr.parent) || errorType; - return checkArrayLiteralDestructuringElementAssignment(node, typeOfArrayLiteral, node.elements.indexOf(expr), elementType); + const elementType = + checkIteratedTypeOrElementType(IterationUse.Destructuring, typeOfArrayLiteral, undefinedType, expr.parent) + || errorType; + return checkArrayLiteralDestructuringElementAssignment( + node, + typeOfArrayLiteral, + node.elements.indexOf(expr), + elementType, + ); } // Gets the property symbol corresponding to the property in destructuring assignment @@ -46184,9 +59300,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getAugmentedPropertiesOfType(type: Type): Symbol[] { type = getApparentType(type); const propsByName = createSymbolTable(getPropertiesOfType(type)); - const functionType = getSignaturesOfType(type, SignatureKind.Call).length ? globalCallableFunctionType : - getSignaturesOfType(type, SignatureKind.Construct).length ? globalNewableFunctionType : - undefined; + const functionType = getSignaturesOfType(type, SignatureKind.Call).length ? globalCallableFunctionType + : getSignaturesOfType(type, SignatureKind.Construct).length ? globalNewableFunctionType + : undefined; if (functionType) { forEach(getPropertiesOfType(functionType), p => { if (!propsByName.has(p.escapedName)) { @@ -46198,7 +59314,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function typeHasCallOrConstructSignatures(type: Type): boolean { - return getSignaturesOfType(type, SignatureKind.Call).length !== 0 || getSignaturesOfType(type, SignatureKind.Construct).length !== 0; + return getSignaturesOfType(type, SignatureKind.Call).length !== 0 + || getSignaturesOfType(type, SignatureKind.Construct).length !== 0; } function getRootSymbols(symbol: Symbol): readonly Symbol[] { @@ -46207,7 +59324,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getImmediateRootSymbols(symbol: Symbol): readonly Symbol[] | undefined { if (getCheckFlags(symbol) & CheckFlags.Synthetic) { - return mapDefined(getSymbolLinks(symbol).containingType!.types, type => getPropertyOfType(type, symbol.escapedName)); + return mapDefined( + getSymbolLinks(symbol).containingType!.types, + type => getPropertyOfType(type, symbol.escapedName), + ); } else if (symbol.flags & SymbolFlags.Transient) { const { links: { leftSpread, rightSpread, syntheticOrigin } } = symbol as TransientSymbol; @@ -46235,9 +59355,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!node) return false; const parent = node.parent; if (!parent) return false; - const isPropertyName = ((isPropertyAccessExpression(parent) - || isPropertyAssignment(parent)) - && parent.name === node); + const isPropertyName = (isPropertyAccessExpression(parent) + || isPropertyAssignment(parent)) + && parent.name === node; return !isPropertyName && getReferencedValueSymbol(node) === argumentsSymbol; } @@ -46276,35 +59396,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When resolved as an expression identifier, if the given node references an exported entity, return the declaration // node of the exported entity's container. Otherwise, return undefined. - function getReferencedExportContainer(nodeIn: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration | undefined { + function getReferencedExportContainer( + nodeIn: Identifier, + prefixLocals?: boolean, + ): SourceFile | ModuleDeclaration | EnumDeclaration | undefined { const node = getParseTreeNode(nodeIn, isIdentifier); if (node) { // When resolving the export container for the name of a module or enum // declaration, we need to start resolution at the declaration's container. // Otherwise, we could incorrectly resolve the export container as the // declaration if it contains an exported member with the same name. - let symbol = getReferencedValueSymbol(node, /*startInDeclarationContainer*/ isNameOfModuleOrEnumDeclaration(node)); + let symbol = getReferencedValueSymbol( + node, + /*startInDeclarationContainer*/ isNameOfModuleOrEnumDeclaration(node), + ); if (symbol) { if (symbol.flags & SymbolFlags.ExportValue) { // If we reference an exported entity within the same module declaration, then whether // we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the // kinds that we do NOT prefix. const exportSymbol = getMergedSymbol(symbol.exportSymbol!); - if (!prefixLocals && exportSymbol.flags & SymbolFlags.ExportHasLocal && !(exportSymbol.flags & SymbolFlags.Variable)) { + if ( + !prefixLocals && exportSymbol.flags & SymbolFlags.ExportHasLocal + && !(exportSymbol.flags & SymbolFlags.Variable) + ) { return undefined; } symbol = exportSymbol; } const parentSymbol = getParentOfSymbol(symbol); if (parentSymbol) { - if (parentSymbol.flags & SymbolFlags.ValueModule && parentSymbol.valueDeclaration?.kind === SyntaxKind.SourceFile) { + if ( + parentSymbol.flags & SymbolFlags.ValueModule + && parentSymbol.valueDeclaration?.kind === SyntaxKind.SourceFile + ) { const symbolFile = parentSymbol.valueDeclaration as SourceFile; const referenceFile = getSourceFileOfNode(node); // If `node` accesses an export and that export isn't in the same file, then symbol is a namespace export, so return undefined. const symbolIsUmdExport = symbolFile !== referenceFile; return symbolIsUmdExport ? undefined : symbolFile; } - return findAncestor(node.parent, (n): n is ModuleDeclaration | EnumDeclaration => isModuleOrEnumDeclaration(n) && getSymbolOfDeclaration(n) === parentSymbol); + return findAncestor( + node.parent, + (n): n is ModuleDeclaration | EnumDeclaration => + isModuleOrEnumDeclaration(n) && getSymbolOfDeclaration(n) === parentSymbol, + ); } } } @@ -46323,7 +59459,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We should only get the declaration of an alias if there isn't a local value // declaration for the symbol - if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) { + if ( + isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) + && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value) + ) { return getDeclarationOfAliasSymbol(symbol); } } @@ -46338,13 +59477,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isSymbolOfDeclarationWithCollidingName(symbol: Symbol): boolean { - if (symbol.flags & SymbolFlags.BlockScoped && symbol.valueDeclaration && !isSourceFile(symbol.valueDeclaration)) { + if ( + symbol.flags & SymbolFlags.BlockScoped && symbol.valueDeclaration && !isSourceFile(symbol.valueDeclaration) + ) { const links = getSymbolLinks(symbol); if (links.isDeclarationWithCollidingName === undefined) { const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration); if (isStatementWithLocals(container) || isSymbolOfDestructuredElementOfCatchBinding(symbol)) { const nodeLinks = getNodeLinks(symbol.valueDeclaration); - if (resolveName(container.parent, symbol.escapedName, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false)) { + if ( + resolveName( + container.parent, + symbol.escapedName, + SymbolFlags.Value, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ false, + ) + ) { // redeclaration - always should be renamed links.isDeclarationWithCollidingName = true; } @@ -46366,9 +59516,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // they will not collide with anything const isDeclaredInLoop = nodeLinks.flags & NodeCheckFlags.BlockScopedBindingInLoop; const inLoopInitializer = isIterationStatement(container, /*lookInLabeledStatements*/ false); - const inLoopBodyBlock = container.kind === SyntaxKind.Block && isIterationStatement(container.parent, /*lookInLabeledStatements*/ false); + const inLoopBodyBlock = container.kind === SyntaxKind.Block + && isIterationStatement(container.parent, /*lookInLabeledStatements*/ false); - links.isDeclarationWithCollidingName = !isBlockScopedContainerTopLevel(container) && (!isDeclaredInLoop || (!inLoopInitializer && !inLoopBodyBlock)); + links.isDeclarationWithCollidingName = !isBlockScopedContainerTopLevel(container) + && (!isDeclaredInLoop || (!inLoopInitializer && !inLoopBodyBlock)); } else { links.isDeclarationWithCollidingName = false; @@ -46420,25 +59572,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.NamespaceImport: case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: - const symbol = getSymbolOfDeclaration(node as ImportClause | NamespaceImport | ImportSpecifier | ExportSpecifier); + const symbol = getSymbolOfDeclaration( + node as ImportClause | NamespaceImport | ImportSpecifier | ExportSpecifier, + ); return !!symbol && isAliasResolvedToValue(symbol, /*excludeTypeOnlyValues*/ true); case SyntaxKind.ExportDeclaration: const exportClause = (node as ExportDeclaration).exportClause; return !!exportClause && ( - isNamespaceExport(exportClause) || - some(exportClause.elements, isValueAliasDeclaration) + isNamespaceExport(exportClause) + || some(exportClause.elements, isValueAliasDeclaration) ); case SyntaxKind.ExportAssignment: - return (node as ExportAssignment).expression && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier ? - isAliasResolvedToValue(getSymbolOfDeclaration(node as ExportAssignment)) : - true; + return (node as ExportAssignment).expression + && (node as ExportAssignment).expression.kind === SyntaxKind.Identifier + ? isAliasResolvedToValue(getSymbolOfDeclaration(node as ExportAssignment)) + : true; } return false; } function isTopLevelValueImportEqualsWithEntityName(nodeIn: ImportEqualsDeclaration): boolean { const node = getParseTreeNode(nodeIn, isImportEqualsDeclaration); - if (node === undefined || node.parent.kind !== SyntaxKind.SourceFile || !isInternalModuleImportEqualsDeclaration(node)) { + if ( + node === undefined || node.parent.kind !== SyntaxKind.SourceFile + || !isInternalModuleImportEqualsDeclaration(node) + ) { // parent is not source file or it is not reference to internal module return false; } @@ -46457,8 +59615,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // const enums and modules that contain only const enums are not considered values from the emit perspective // unless 'preserveConstEnums' option is set to true - return !!(getSymbolFlags(symbol, excludeTypeOnlyValues, /*excludeLocalMeanings*/ true) & SymbolFlags.Value) && - (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)); + return !!(getSymbolFlags(symbol, excludeTypeOnlyValues, /*excludeLocalMeanings*/ true) & SymbolFlags.Value) + && (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)); } function isConstEnumOrConstEnumOnlyModule(s: Symbol): boolean { @@ -46474,9 +59632,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } const target = getSymbolLinks(symbol).aliasTarget; - if (target && getEffectiveModifierFlags(node) & ModifierFlags.Export && - getSymbolFlags(target) & SymbolFlags.Value && - (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target))) { + if ( + target && getEffectiveModifierFlags(node) & ModifierFlags.Export + && getSymbolFlags(target) & SymbolFlags.Value + && (shouldPreserveConstEnums(compilerOptions) || !isConstEnumOrConstEnumOnlyModule(target)) + ) { // An `export import ... =` of a value symbol is always considered referenced return true; } @@ -46499,30 +59659,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // function foo(a: any) { // This is implementation of the overloads // return a; // } - return signaturesOfSymbol.length > 1 || + return signaturesOfSymbol.length > 1 // If there is single signature for the symbol, it is overload if that signature isn't coming from the node // e.g.: function foo(a: string): string; // function foo(a: any) { // This is implementation of the overloads // return a; // } - (signaturesOfSymbol.length === 1 && signaturesOfSymbol[0].declaration !== node); + || (signaturesOfSymbol.length === 1 && signaturesOfSymbol[0].declaration !== node); } return false; } function isRequiredInitializedParameter(parameter: ParameterDeclaration | JSDocParameterTag): boolean { - return !!strictNullChecks && - !isOptionalParameter(parameter) && - !isJSDocParameterTag(parameter) && - !!parameter.initializer && - !hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); + return !!strictNullChecks + && !isOptionalParameter(parameter) + && !isJSDocParameterTag(parameter) + && !!parameter.initializer + && !hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); } function isOptionalUninitializedParameterProperty(parameter: ParameterDeclaration) { - return strictNullChecks && - isOptionalParameter(parameter) && - !parameter.initializer && - hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); + return strictNullChecks + && isOptionalParameter(parameter) + && !parameter.initializer + && hasSyntacticModifier(parameter, ModifierFlags.ParameterPropertyModifier); } function isExpandoFunctionDeclaration(node: Declaration): boolean { @@ -46534,7 +59694,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!symbol || !(symbol.flags & SymbolFlags.Function)) { return false; } - return !!forEachEntry(getExportsOfSymbol(symbol), p => p.flags & SymbolFlags.Value && p.valueDeclaration && isPropertyAccessExpression(p.valueDeclaration)); + return !!forEachEntry( + getExportsOfSymbol(symbol), + p => p.flags & SymbolFlags.Value && p.valueDeclaration && isPropertyAccessExpression(p.valueDeclaration), + ); } function getPropertiesOfContainerFunction(node: Declaration): Symbol[] { @@ -46588,7 +59751,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(type.flags & TypeFlags.Object) && getSignaturesOfType(type, SignatureKind.Call).length > 0; } - function getTypeReferenceSerializationKind(typeNameIn: EntityName, location?: Node): TypeReferenceSerializationKind { + function getTypeReferenceSerializationKind( + typeNameIn: EntityName, + location?: Node, + ): TypeReferenceSerializationKind { // ensure both `typeName` and `location` are parse tree nodes. const typeName = getParseTreeNode(typeNameIn, isEntityName); if (!typeName) return TypeReferenceSerializationKind.Unknown; @@ -46601,15 +59767,34 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Resolve the symbol as a value to ensure the type can be reached at runtime during emit. let isTypeOnly = false; if (isQualifiedName(typeName)) { - const rootValueSymbol = resolveEntityName(getFirstIdentifier(typeName), SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); + const rootValueSymbol = resolveEntityName( + getFirstIdentifier(typeName), + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + location, + ); isTypeOnly = !!rootValueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); } - const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); - const resolvedSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) : valueSymbol; + const valueSymbol = resolveEntityName( + typeName, + SymbolFlags.Value, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ true, + location, + ); + const resolvedSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) + : valueSymbol; isTypeOnly ||= !!(valueSymbol && getTypeOnlyAliasDeclaration(valueSymbol, SymbolFlags.Value)); // Resolve the symbol as a type so that we can provide a more useful hint for the type serializer. - const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location); + const typeSymbol = resolveEntityName( + typeName, + SymbolFlags.Type, + /*ignoreErrors*/ true, + /*dontResolveAlias*/ false, + location, + ); if (resolvedSymbol && resolvedSymbol === typeSymbol) { const globalPromiseSymbol = getGlobalPromiseConstructorSymbol(/*reportErrors*/ false); if (globalPromiseSymbol && resolvedSymbol === globalPromiseSymbol) { @@ -46618,7 +59803,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const constructorType = getTypeOfSymbol(resolvedSymbol); if (constructorType && isConstructorType(constructorType)) { - return isTypeOnly ? TypeReferenceSerializationKind.TypeWithCallSignature : TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue; + return isTypeOnly ? TypeReferenceSerializationKind.TypeWithCallSignature + : TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue; } } @@ -46665,7 +59851,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function createTypeOfDeclaration(declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean) { + function createTypeOfDeclaration( + declarationIn: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + addUndefined?: boolean, + ) { const declaration = getParseTreeNode(declarationIn, isVariableLikeOrAccessor); if (!declaration) { return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; @@ -46675,39 +59867,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature)) ? getWidenedLiteralType(getTypeOfSymbol(symbol)) : errorType; - if (type.flags & TypeFlags.UniqueESSymbol && - type.symbol === symbol) { + if ( + type.flags & TypeFlags.UniqueESSymbol + && type.symbol === symbol + ) { flags |= NodeBuilderFlags.AllowUniqueESSymbolType; } if (addUndefined) { type = getOptionalType(type); } - return nodeBuilder.typeToTypeNode(type, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); + return nodeBuilder.typeToTypeNode( + type, + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + tracker, + ); } - function createReturnTypeOfSignatureDeclaration(signatureDeclarationIn: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker) { + function createReturnTypeOfSignatureDeclaration( + signatureDeclarationIn: SignatureDeclaration, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + ) { const signatureDeclaration = getParseTreeNode(signatureDeclarationIn, isFunctionLike); if (!signatureDeclaration) { return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; } const signature = getSignatureFromDeclaration(signatureDeclaration); - return nodeBuilder.typeToTypeNode(getReturnTypeOfSignature(signature), enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); + return nodeBuilder.typeToTypeNode( + getReturnTypeOfSignature(signature), + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + tracker, + ); } - function createTypeOfExpression(exprIn: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker) { + function createTypeOfExpression( + exprIn: Expression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + ) { const expr = getParseTreeNode(exprIn, isExpression); if (!expr) { return factory.createToken(SyntaxKind.AnyKeyword) as KeywordTypeNode; } const type = getWidenedType(getRegularTypeOfExpression(expr)); - return nodeBuilder.typeToTypeNode(type, enclosingDeclaration, flags | NodeBuilderFlags.MultilineObjectLiterals, tracker); + return nodeBuilder.typeToTypeNode( + type, + enclosingDeclaration, + flags | NodeBuilderFlags.MultilineObjectLiterals, + tracker, + ); } function hasGlobalName(name: string): boolean { return globals.has(escapeLeadingUnderscores(name)); } - function getReferencedValueSymbol(reference: Identifier, startInDeclarationContainer?: boolean): Symbol | undefined { + function getReferencedValueSymbol( + reference: Identifier, + startInDeclarationContainer?: boolean, + ): Symbol | undefined { const resolvedSymbol = getNodeLinks(reference).resolvedSymbol; if (resolvedSymbol) { return resolvedSymbol; @@ -46723,7 +59945,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - return resolveName(location, reference.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true); + return resolveName( + location, + reference.escapedText, + SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias, + /*nameNotFoundMessage*/ undefined, + /*nameArg*/ undefined, + /*isUse*/ true, + ); } /** @@ -46747,7 +59976,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*nameArg*/ undefined, /*isUse*/ true, /*excludeGlobals*/ undefined, - /*getSpellingSuggestions*/ undefined); + /*getSpellingSuggestions*/ undefined, + ); } function getReferencedValueDeclaration(referenceIn: Identifier): Declaration | undefined { @@ -46801,7 +60031,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean { + function isLiteralConstDeclaration( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, + ): boolean { if (isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConstLike(node)) { return isFreshLiteralType(getTypeOfSymbol(getSymbolOfDeclaration(node))); } @@ -46809,23 +60041,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function literalTypeToNode(type: FreshableType, enclosing: Node, tracker: SymbolTracker): Expression { - const enumResult = type.flags & TypeFlags.EnumLike ? nodeBuilder.symbolToExpression(type.symbol, SymbolFlags.Value, enclosing, /*flags*/ undefined, tracker) + const enumResult = type.flags & TypeFlags.EnumLike + ? nodeBuilder.symbolToExpression(type.symbol, SymbolFlags.Value, enclosing, /*flags*/ undefined, tracker) : type === trueType ? factory.createTrue() : type === falseType && factory.createFalse(); if (enumResult) return enumResult; const literalValue = (type as LiteralType).value; - return typeof literalValue === "object" ? factory.createBigIntLiteral(literalValue) : - typeof literalValue === "string" ? factory.createStringLiteral(literalValue) : - literalValue < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(literalValue))) : - factory.createNumericLiteral(literalValue); - } - - function createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker) { + return typeof literalValue === "object" ? factory.createBigIntLiteral(literalValue) + : typeof literalValue === "string" ? factory.createStringLiteral(literalValue) + : literalValue < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(Math.abs(literalValue)), + ) + : factory.createNumericLiteral(literalValue); + } + + function createLiteralConstValue( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, + tracker: SymbolTracker, + ) { const type = getTypeOfSymbol(getSymbolOfDeclaration(node)); return literalTypeToNode(type as FreshableType, node, tracker); } function getJsxFactoryEntity(location: Node): EntityName | undefined { - return location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity; + return location + ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) + : _jsxFactoryEntity; } function getJsxFragmentFactoryEntity(location: Node): EntityName | undefined { @@ -46838,7 +60080,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const jsxFragPragmas = file.pragmas.get("jsxfrag"); const jsxFragPragma = isArray(jsxFragPragmas) ? jsxFragPragmas[0] : jsxFragPragmas; if (jsxFragPragma) { - file.localJsxFragmentFactory = parseIsolatedEntityName(jsxFragPragma.arguments.factory, languageVersion); + file.localJsxFragmentFactory = parseIsolatedEntityName( + jsxFragPragma.arguments.factory, + languageVersion, + ); return file.localJsxFragmentFactory; } } @@ -46884,7 +60129,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { isReferencedAliasDeclaration: (nodeIn, checkChildren?) => { const node = getParseTreeNode(nodeIn); // Synthesized nodes are always treated as referenced. - return node && canCollectSymbolAliasAccessabilityData ? isReferencedAliasDeclaration(node, checkChildren) : true; + return node && canCollectSymbolAliasAccessabilityData + ? isReferencedAliasDeclaration(node, checkChildren) : true; }, getNodeCheckFlags: nodeIn => { const node = getParseTreeNode(nodeIn); @@ -46930,33 +60176,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getJsxFragmentFactoryEntity, getAllAccessorDeclarations(accessor: AccessorDeclaration): AllAccessorDeclarations { accessor = getParseTreeNode(accessor, isGetOrSetAccessorDeclaration)!; // TODO: GH#18217 - const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor; - const otherAccessor = getDeclarationOfKind(getSymbolOfDeclaration(accessor), otherKind); + const otherKind = accessor.kind === SyntaxKind.SetAccessor ? SyntaxKind.GetAccessor + : SyntaxKind.SetAccessor; + const otherAccessor = getDeclarationOfKind( + getSymbolOfDeclaration(accessor), + otherKind, + ); const firstAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? otherAccessor : accessor; const secondAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? accessor : otherAccessor; - const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor : otherAccessor as SetAccessorDeclaration; - const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor : otherAccessor as GetAccessorDeclaration; + const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor + : otherAccessor as SetAccessorDeclaration; + const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor + : otherAccessor as GetAccessorDeclaration; return { firstAccessor, secondAccessor, setAccessor, - getAccessor + getAccessor, }; }, - getSymbolOfExternalModuleSpecifier: moduleName => resolveExternalModuleNameWorker(moduleName, moduleName, /*moduleNotFoundError*/ undefined), + getSymbolOfExternalModuleSpecifier: moduleName => + resolveExternalModuleNameWorker(moduleName, moduleName, /*moduleNotFoundError*/ undefined), isBindingCapturedByNode: (node, decl) => { const parseNode = getParseTreeNode(node); const parseDecl = getParseTreeNode(decl); - return !!parseNode && !!parseDecl && (isVariableDeclaration(parseDecl) || isBindingElement(parseDecl)) && isBindingCapturedByNode(parseNode, parseDecl); + return !!parseNode && !!parseDecl && (isVariableDeclaration(parseDecl) || isBindingElement(parseDecl)) + && isBindingCapturedByNode(parseNode, parseDecl); }, getDeclarationStatementsForSourceFile: (node, flags, tracker, bundled) => { const n = getParseTreeNode(node) as SourceFile; - Debug.assert(n && n.kind === SyntaxKind.SourceFile, "Non-sourcefile node passed into getDeclarationsForSourceFile"); + Debug.assert( + n && n.kind === SyntaxKind.SourceFile, + "Non-sourcefile node passed into getDeclarationsForSourceFile", + ); const sym = getSymbolOfDeclaration(node); if (!sym) { - return !node.locals ? [] : nodeBuilder.symbolTableToDeclarationStatements(node.locals, node, flags, tracker, bundled); + return !node.locals ? [] + : nodeBuilder.symbolTableToDeclarationStatements(node.locals, node, flags, tracker, bundled); } - return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled); + return !sym.exports ? [] + : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker, bundled); }, isImportRequiredByAugmentation, }; @@ -46985,11 +60244,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isInHeritageClause(node: PropertyAccessEntityNameExpression) { - return node.parent && node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && node.parent.parent && node.parent.parent.kind === SyntaxKind.HeritageClause; + return node.parent && node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && node.parent.parent + && node.parent.parent.kind === SyntaxKind.HeritageClause; } // defined here to avoid outer scope pollution - function getTypeReferenceDirectivesForEntityName(node: EntityNameOrEntityNameExpression): [specifier: string, mode: ResolutionMode][] | undefined { + function getTypeReferenceDirectivesForEntityName( + node: EntityNameOrEntityNameExpression, + ): [specifier: string, mode: ResolutionMode][] | undefined { // program does not have any files with type reference directives - bail out if (!fileToDirective) { return undefined; @@ -47004,17 +60266,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { meaning = SymbolFlags.Type | SymbolFlags.Namespace; - if ((node.kind === SyntaxKind.Identifier && isInTypeQuery(node)) || (node.kind === SyntaxKind.PropertyAccessExpression && !isInHeritageClause(node))) { + if ( + (node.kind === SyntaxKind.Identifier && isInTypeQuery(node)) + || (node.kind === SyntaxKind.PropertyAccessExpression && !isInHeritageClause(node)) + ) { meaning = SymbolFlags.Value | SymbolFlags.ExportValue; } } const symbol = resolveEntityName(node, meaning, /*ignoreErrors*/ true); - return symbol && symbol !== unknownSymbol ? getTypeReferenceDirectivesForSymbol(symbol, meaning) : undefined; + return symbol && symbol !== unknownSymbol ? getTypeReferenceDirectivesForSymbol(symbol, meaning) + : undefined; } // defined here to avoid outer scope pollution - function getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): [specifier: string, mode: ResolutionMode][] | undefined { + function getTypeReferenceDirectivesForSymbol( + symbol: Symbol, + meaning?: SymbolFlags, + ): [specifier: string, mode: ResolutionMode][] | undefined { // program does not have any files with type reference directives - bail out if (!fileToDirective || !isSymbolFromTypeDeclarationFile(symbol)) { return undefined; @@ -47057,7 +60326,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - if (current.valueDeclaration && current.valueDeclaration.kind === SyntaxKind.SourceFile && current.flags & SymbolFlags.ValueModule) { + if ( + current.valueDeclaration && current.valueDeclaration.kind === SyntaxKind.SourceFile + && current.flags & SymbolFlags.ValueModule + ) { return false; } @@ -47084,8 +60356,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getExternalModuleFileFromDeclaration(declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined { - const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) : getExternalModuleName(declaration); + function getExternalModuleFileFromDeclaration( + declaration: AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall, + ): SourceFile | undefined { + const specifier = declaration.kind === SyntaxKind.ModuleDeclaration ? tryCast(declaration.name, isStringLiteral) + : getExternalModuleName(declaration); const moduleSymbol = resolveExternalModuleNameWorker(specifier!, specifier!, /*moduleNotFoundError*/ undefined); // TODO: GH#18217 if (!moduleSymbol) { return undefined; @@ -47113,7 +60388,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const fileGlobalThisSymbol = file.locals!.get("globalThis" as __String); if (fileGlobalThisSymbol?.declarations) { for (const declaration of fileGlobalThisSymbol.declarations) { - diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, "globalThis")); + diagnostics.add( + createDiagnosticForNode( + declaration, + Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, + "globalThis", + ), + ); } } mergeSymbolTable(globals, file.locals!); @@ -47156,10 +60437,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Setup global builtins - addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0); + addToSymbolTable( + globals, + builtinGlobals, + Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, + ); getSymbolLinks(undefinedSymbol).type = undefinedWideningType; - getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments" as __String, /*arity*/ 0, /*reportErrors*/ true); + getSymbolLinks(argumentsSymbol).type = getGlobalType( + "IArguments" as __String, + /*arity*/ 0, + /*reportErrors*/ true, + ); getSymbolLinks(unknownSymbol).type = errorType; getSymbolLinks(globalThisSymbol).type = createObjectType(ObjectFlags.Anonymous, globalThisSymbol); @@ -47167,8 +60456,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { globalArrayType = getGlobalType("Array" as __String, /*arity*/ 1, /*reportErrors*/ true); globalObjectType = getGlobalType("Object" as __String, /*arity*/ 0, /*reportErrors*/ true); globalFunctionType = getGlobalType("Function" as __String, /*arity*/ 0, /*reportErrors*/ true); - globalCallableFunctionType = strictBindCallApply && getGlobalType("CallableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) || globalFunctionType; - globalNewableFunctionType = strictBindCallApply && getGlobalType("NewableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) || globalFunctionType; + globalCallableFunctionType = + strictBindCallApply && getGlobalType("CallableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) + || globalFunctionType; + globalNewableFunctionType = + strictBindCallApply && getGlobalType("NewableFunction" as __String, /*arity*/ 0, /*reportErrors*/ true) + || globalFunctionType; globalStringType = getGlobalType("String" as __String, /*arity*/ 0, /*reportErrors*/ true); globalNumberType = getGlobalType("Number" as __String, /*arity*/ 0, /*reportErrors*/ true); globalBooleanType = getGlobalType("Boolean" as __String, /*arity*/ 0, /*reportErrors*/ true); @@ -47181,8 +60474,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { autoArrayType = createAnonymousType(/*symbol*/ undefined, emptySymbols, emptyArray, emptyArray, emptyArray); } - globalReadonlyArrayType = getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) as GenericType || globalArrayType; - anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType; + globalReadonlyArrayType = getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) as GenericType + || globalArrayType; + anyReadonlyArrayType = globalReadonlyArrayType + ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType; globalThisType = getGlobalTypeOrUndefined("ThisType" as __String, /*arity*/ 1) as GenericType; if (augmentations) { @@ -47200,7 +60495,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If not many things conflict, issue individual errors if (conflictingSymbols.size < 8) { conflictingSymbols.forEach(({ isBlockScoped, firstFileLocations, secondFileLocations }, symbolName) => { - const message = isBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; + const message = isBlockScoped ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 + : Diagnostics.Duplicate_identifier_0; for (const node of firstFileLocations) { addDuplicateDeclarationError(node, message, symbolName, secondFileLocations); } @@ -47213,12 +60509,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Otherwise issue top-level error since the files appear very identical in terms of what they contain const list = arrayFrom(conflictingSymbols.keys()).join(", "); diagnostics.add(addRelatedInfo( - createDiagnosticForNode(firstFile, Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, list), - createDiagnosticForNode(secondFile, Diagnostics.Conflicts_are_in_this_file) + createDiagnosticForNode( + firstFile, + Diagnostics + .Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, + list, + ), + createDiagnosticForNode(secondFile, Diagnostics.Conflicts_are_in_this_file), )); diagnostics.add(addRelatedInfo( - createDiagnosticForNode(secondFile, Diagnostics.Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, list), - createDiagnosticForNode(firstFile, Diagnostics.Conflicts_are_in_this_file) + createDiagnosticForNode( + secondFile, + Diagnostics + .Definitions_of_the_following_identifiers_conflict_with_those_in_another_file_Colon_0, + list, + ), + createDiagnosticForNode(firstFile, Diagnostics.Conflicts_are_in_this_file), )); } }); @@ -47232,29 +60538,81 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const helpersModule = resolveHelpersModule(sourceFile, location); if (helpersModule !== unknownSymbol) { const uncheckedHelpers = helpers & ~requestedExternalEmitHelpers; - for (let helper = ExternalEmitHelpers.FirstEmitHelper; helper <= ExternalEmitHelpers.LastEmitHelper; helper <<= 1) { + for ( + let helper = ExternalEmitHelpers.FirstEmitHelper; + helper <= ExternalEmitHelpers.LastEmitHelper; + helper <<= 1 + ) { if (uncheckedHelpers & helper) { for (const name of getHelperNames(helper)) { if (requestedExternalEmitHelperNames.has(name)) continue; requestedExternalEmitHelperNames.add(name); - const symbol = resolveSymbol(getSymbol(getExportsOfModule(helpersModule), escapeLeadingUnderscores(name), SymbolFlags.Value)); + const symbol = resolveSymbol( + getSymbol( + getExportsOfModule(helpersModule), + escapeLeadingUnderscores(name), + SymbolFlags.Value, + ), + ); if (!symbol) { - error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_which_does_not_exist_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name); + error( + location, + Diagnostics + .This_syntax_requires_an_imported_helper_named_1_which_does_not_exist_in_0_Consider_upgrading_your_version_of_0, + externalHelpersModuleNameText, + name, + ); } else if (helper & ExternalEmitHelpers.ClassPrivateFieldGet) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 3)) { - error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 4); + if ( + !some( + getSignaturesOfSymbol(symbol), + signature => getParameterCount(signature) > 3, + ) + ) { + error( + location, + Diagnostics + .This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, + externalHelpersModuleNameText, + name, + 4, + ); } } else if (helper & ExternalEmitHelpers.ClassPrivateFieldSet) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 4)) { - error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 5); + if ( + !some( + getSignaturesOfSymbol(symbol), + signature => getParameterCount(signature) > 4, + ) + ) { + error( + location, + Diagnostics + .This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, + externalHelpersModuleNameText, + name, + 5, + ); } } else if (helper & ExternalEmitHelpers.SpreadArray) { - if (!some(getSignaturesOfSymbol(symbol), signature => getParameterCount(signature) > 2)) { - error(location, Diagnostics.This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, externalHelpersModuleNameText, name, 3); + if ( + !some( + getSignaturesOfSymbol(symbol), + signature => getParameterCount(signature) > 2, + ) + ) { + error( + location, + Diagnostics + .This_syntax_requires_an_imported_helper_named_1_with_2_parameters_which_is_not_compatible_with_the_one_in_0_Consider_upgrading_your_version_of_0, + externalHelpersModuleNameText, + name, + 3, + ); } } } @@ -47268,57 +60626,99 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getHelperNames(helper: ExternalEmitHelpers) { switch (helper) { - case ExternalEmitHelpers.Extends: return ["__extends"]; - case ExternalEmitHelpers.Assign: return ["__assign"]; - case ExternalEmitHelpers.Rest: return ["__rest"]; - case ExternalEmitHelpers.Decorate: return legacyDecorators ? ["__decorate"] : ["__esDecorate", "__runInitializers"]; - case ExternalEmitHelpers.Metadata: return ["__metadata"]; - case ExternalEmitHelpers.Param: return ["__param"]; - case ExternalEmitHelpers.Awaiter: return ["__awaiter"]; - case ExternalEmitHelpers.Generator: return ["__generator"]; - case ExternalEmitHelpers.Values: return ["__values"]; - case ExternalEmitHelpers.Read: return ["__read"]; - case ExternalEmitHelpers.SpreadArray: return ["__spreadArray"]; - case ExternalEmitHelpers.Await: return ["__await"]; - case ExternalEmitHelpers.AsyncGenerator: return ["__asyncGenerator"]; - case ExternalEmitHelpers.AsyncDelegator: return ["__asyncDelegator"]; - case ExternalEmitHelpers.AsyncValues: return ["__asyncValues"]; - case ExternalEmitHelpers.ExportStar: return ["__exportStar"]; - case ExternalEmitHelpers.ImportStar: return ["__importStar"]; - case ExternalEmitHelpers.ImportDefault: return ["__importDefault"]; - case ExternalEmitHelpers.MakeTemplateObject: return ["__makeTemplateObject"]; - case ExternalEmitHelpers.ClassPrivateFieldGet: return ["__classPrivateFieldGet"]; - case ExternalEmitHelpers.ClassPrivateFieldSet: return ["__classPrivateFieldSet"]; - case ExternalEmitHelpers.ClassPrivateFieldIn: return ["__classPrivateFieldIn"]; - case ExternalEmitHelpers.CreateBinding: return ["__createBinding"]; - case ExternalEmitHelpers.SetFunctionName: return ["__setFunctionName"]; - case ExternalEmitHelpers.PropKey: return ["__propKey"]; - case ExternalEmitHelpers.AddDisposableResourceAndDisposeResources: return ["__addDisposableResource", "__disposeResources"]; - default: return Debug.fail("Unrecognized helper"); + case ExternalEmitHelpers.Extends: + return ["__extends"]; + case ExternalEmitHelpers.Assign: + return ["__assign"]; + case ExternalEmitHelpers.Rest: + return ["__rest"]; + case ExternalEmitHelpers.Decorate: + return legacyDecorators ? ["__decorate"] : ["__esDecorate", "__runInitializers"]; + case ExternalEmitHelpers.Metadata: + return ["__metadata"]; + case ExternalEmitHelpers.Param: + return ["__param"]; + case ExternalEmitHelpers.Awaiter: + return ["__awaiter"]; + case ExternalEmitHelpers.Generator: + return ["__generator"]; + case ExternalEmitHelpers.Values: + return ["__values"]; + case ExternalEmitHelpers.Read: + return ["__read"]; + case ExternalEmitHelpers.SpreadArray: + return ["__spreadArray"]; + case ExternalEmitHelpers.Await: + return ["__await"]; + case ExternalEmitHelpers.AsyncGenerator: + return ["__asyncGenerator"]; + case ExternalEmitHelpers.AsyncDelegator: + return ["__asyncDelegator"]; + case ExternalEmitHelpers.AsyncValues: + return ["__asyncValues"]; + case ExternalEmitHelpers.ExportStar: + return ["__exportStar"]; + case ExternalEmitHelpers.ImportStar: + return ["__importStar"]; + case ExternalEmitHelpers.ImportDefault: + return ["__importDefault"]; + case ExternalEmitHelpers.MakeTemplateObject: + return ["__makeTemplateObject"]; + case ExternalEmitHelpers.ClassPrivateFieldGet: + return ["__classPrivateFieldGet"]; + case ExternalEmitHelpers.ClassPrivateFieldSet: + return ["__classPrivateFieldSet"]; + case ExternalEmitHelpers.ClassPrivateFieldIn: + return ["__classPrivateFieldIn"]; + case ExternalEmitHelpers.CreateBinding: + return ["__createBinding"]; + case ExternalEmitHelpers.SetFunctionName: + return ["__setFunctionName"]; + case ExternalEmitHelpers.PropKey: + return ["__propKey"]; + case ExternalEmitHelpers.AddDisposableResourceAndDisposeResources: + return ["__addDisposableResource", "__disposeResources"]; + default: + return Debug.fail("Unrecognized helper"); } } function resolveHelpersModule(node: SourceFile, errorNode: Node) { if (!externalHelpersModule) { - externalHelpersModule = resolveExternalModule(node, externalHelpersModuleNameText, Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, errorNode) || unknownSymbol; + externalHelpersModule = resolveExternalModule( + node, + externalHelpersModuleNameText, + Diagnostics.This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found, + errorNode, + ) || unknownSymbol; } return externalHelpersModule; } // GRAMMAR CHECKING - function checkGrammarModifiers(node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators): boolean { + function checkGrammarModifiers( + node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators, + ): boolean { const quickResult = reportObviousDecoratorErrors(node) || reportObviousModifierErrors(node); if (quickResult !== undefined) { return quickResult; } if (isParameter(node) && parameterIsThisKeyword(node)) { - return grammarErrorOnFirstToken(node, Diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters); + return grammarErrorOnFirstToken( + node, + Diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters, + ); } - const blockScopeKind = isVariableStatement(node) ? node.declarationList.flags & NodeFlags.BlockScoped : NodeFlags.None; - let lastStatic: Node | undefined, lastDeclare: Node | undefined, lastAsync: Node | undefined, lastOverride: Node | undefined, firstDecorator: Decorator | undefined; + const blockScopeKind = isVariableStatement(node) ? node.declarationList.flags & NodeFlags.BlockScoped + : NodeFlags.None; + let lastStatic: Node | undefined, + lastDeclare: Node | undefined, + lastAsync: Node | undefined, + lastOverride: Node | undefined, + firstDecorator: Decorator | undefined; let flags = ModifierFlags.None; let sawExportBeforeDecorators = false; // We parse decorators and modifiers in four contiguous chunks: @@ -47329,16 +60729,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isDecorator(modifier)) { if (!nodeCanBeDecorated(legacyDecorators, node, node.parent, node.parent.parent)) { if (node.kind === SyntaxKind.MethodDeclaration && !nodeIsPresent(node.body)) { - return grammarErrorOnFirstToken(node, Diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload); + return grammarErrorOnFirstToken( + node, + Diagnostics.A_decorator_can_only_decorate_a_method_implementation_not_an_overload, + ); } else { return grammarErrorOnFirstToken(node, Diagnostics.Decorators_are_not_valid_here); } } - else if (legacyDecorators && (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor)) { - const accessors = getAllAccessorDeclarations((node.parent as ClassDeclaration).members, node as AccessorDeclaration); + else if ( + legacyDecorators && (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) + ) { + const accessors = getAllAccessorDeclarations( + (node.parent as ClassDeclaration).members, + node as AccessorDeclaration, + ); if (hasDecorators(accessors.firstAccessor) && node === accessors.secondAccessor) { - return grammarErrorOnFirstToken(node, Diagnostics.Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name); + return grammarErrorOnFirstToken( + node, + Diagnostics + .Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name, + ); } } @@ -47353,8 +60765,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceFile = getSourceFileOfNode(modifier); if (!hasParseDiagnostics(sourceFile)) { addRelatedInfo( - error(modifier, Diagnostics.Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear_before_export), - createDiagnosticForNode(firstDecorator, Diagnostics.Decorator_used_before_export_here)); + error( + modifier, + Diagnostics + .Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear_before_export, + ), + createDiagnosticForNode(firstDecorator, Diagnostics.Decorator_used_before_export_here), + ); return true; } return false; @@ -47375,26 +60792,57 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { if (modifier.kind !== SyntaxKind.ReadonlyKeyword) { if (node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.MethodSignature) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_member, tokenToString(modifier.kind)); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_type_member, + tokenToString(modifier.kind), + ); } - if (node.kind === SyntaxKind.IndexSignature && (modifier.kind !== SyntaxKind.StaticKeyword || !isClassLike(node.parent))) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_index_signature, tokenToString(modifier.kind)); + if ( + node.kind === SyntaxKind.IndexSignature + && (modifier.kind !== SyntaxKind.StaticKeyword || !isClassLike(node.parent)) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_index_signature, + tokenToString(modifier.kind), + ); } } - if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword && modifier.kind !== SyntaxKind.ConstKeyword) { + if ( + modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword + && modifier.kind !== SyntaxKind.ConstKeyword + ) { if (node.kind === SyntaxKind.TypeParameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, tokenToString(modifier.kind)); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, + tokenToString(modifier.kind), + ); } } switch (modifier.kind) { case SyntaxKind.ConstKeyword: if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) { - return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); + return grammarErrorOnNode( + node, + Diagnostics.A_class_member_cannot_have_the_0_keyword, + tokenToString(SyntaxKind.ConstKeyword), + ); } const parent = node.parent; - if (node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(parent) || isClassLike(parent) || isFunctionTypeNode(parent) || - isConstructorTypeNode(parent) || isCallSignatureDeclaration(parent) || isConstructSignatureDeclaration(parent) || isMethodSignature(parent))) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, tokenToString(modifier.kind)); + if ( + node.kind === SyntaxKind.TypeParameter + && !(isFunctionLikeDeclaration(parent) || isClassLike(parent) || isFunctionTypeNode(parent) + || isConstructorTypeNode(parent) || isCallSignatureDeclaration(parent) + || isConstructSignatureDeclaration(parent) || isMethodSignature(parent)) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics + ._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, + tokenToString(modifier.kind), + ); } break; case SyntaxKind.OverrideKeyword: @@ -47403,16 +60851,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); } else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "override", "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "override", + "declare", + ); } else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "readonly"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "readonly", + ); } else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "accessor", + ); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "override", + "async", + ); } flags |= ModifierFlags.Override; lastOverride = modifier; @@ -47427,33 +60895,77 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(modifier, Diagnostics.Accessibility_modifier_already_seen); } else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "override", + ); } else if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "static"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "static", + ); } else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "accessor", + ); } else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "readonly"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "readonly", + ); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "async", + ); } - else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, text); + else if ( + node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, + text, + ); } else if (flags & ModifierFlags.Abstract) { if (modifier.kind === SyntaxKind.PrivateKeyword) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, text, "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + text, + "abstract", + ); } else { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + text, + "abstract", + ); } } else if (isPrivateIdentifierClassElementDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier); + return grammarErrorOnNode( + modifier, + Diagnostics.An_accessibility_modifier_cannot_be_used_with_a_private_identifier, + ); } flags |= modifierToFlag(modifier.kind); break; @@ -47463,25 +60975,60 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "static"); } else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "readonly"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "readonly", + ); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "async", + ); } else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "accessor", + ); } - else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "static"); + else if ( + node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile + ) { + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, + "static", + ); } else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "static"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "static", + ); } else if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "static", + "abstract", + ); } else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "static", + "override", + ); } flags |= ModifierFlags.Static; lastStatic = modifier; @@ -47492,13 +61039,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "accessor"); } else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "accessor", "readonly"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "accessor", + "readonly", + ); } else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "accessor", "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "accessor", + "declare", + ); } else if (node.kind !== SyntaxKind.PropertyDeclaration) { - return grammarErrorOnNode(modifier, Diagnostics.accessor_modifier_can_only_appear_on_a_property_declaration); + return grammarErrorOnNode( + modifier, + Diagnostics.accessor_modifier_can_only_appear_on_a_property_declaration, + ); } flags |= ModifierFlags.Accessor; @@ -47508,67 +61068,132 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & ModifierFlags.Readonly) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "readonly"); } - else if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature && node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.Parameter) { + else if ( + node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature + && node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.Parameter + ) { // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. - return grammarErrorOnNode(modifier, Diagnostics.readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature); + return grammarErrorOnNode( + modifier, + Diagnostics + .readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature, + ); } else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "readonly", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "readonly", + "accessor", + ); } flags |= ModifierFlags.Readonly; break; case SyntaxKind.ExportKeyword: - if (compilerOptions.verbatimModuleSyntax && - !(node.flags & NodeFlags.Ambient) && - node.kind !== SyntaxKind.TypeAliasDeclaration && - node.kind !== SyntaxKind.InterfaceDeclaration && + if ( + compilerOptions.verbatimModuleSyntax + && !(node.flags & NodeFlags.Ambient) + && node.kind !== SyntaxKind.TypeAliasDeclaration + && node.kind !== SyntaxKind.InterfaceDeclaration // ModuleDeclaration needs to be checked that it is uninstantiated later - node.kind !== SyntaxKind.ModuleDeclaration && - node.parent.kind === SyntaxKind.SourceFile && - (moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + && node.kind !== SyntaxKind.ModuleDeclaration + && node.parent.kind === SyntaxKind.SourceFile + && (moduleKind === ModuleKind.CommonJS + || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) ) { - return grammarErrorOnNode(modifier, Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + return grammarErrorOnNode( + modifier, + Diagnostics + .A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled, + ); } if (flags & ModifierFlags.Export) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "export"); } else if (flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "declare", + ); } else if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "abstract", + ); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "async", + ); } else if (isClassLike(node.parent)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, "export"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, + "export", + ); } else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "export"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "export", + ); } else if (blockScopeKind === NodeFlags.Using) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, "export"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, + "export", + ); } else if (blockScopeKind === NodeFlags.AwaitUsing) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, "export"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, + "export", + ); } flags |= ModifierFlags.Export; break; case SyntaxKind.DefaultKeyword: const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent; if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) { - return grammarErrorOnNode(modifier, Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module); + return grammarErrorOnNode( + modifier, + Diagnostics.A_default_export_can_only_be_used_in_an_ECMAScript_style_module, + ); } else if (blockScopeKind === NodeFlags.Using) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, "default"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, + "default", + ); } else if (blockScopeKind === NodeFlags.AwaitUsing) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, "default"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, + "default", + ); } else if (!(flags & ModifierFlags.Export)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "default"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "export", + "default", + ); } else if (sawExportBeforeDecorators) { return grammarErrorOnNode(firstDecorator!, Diagnostics.Decorators_are_not_valid_here); @@ -47581,31 +61206,69 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "declare"); } else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "async", + ); } else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "override", + ); } else if (isClassLike(node.parent) && !isPropertyDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_class_elements_of_this_kind, + "declare", + ); } else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "declare", + ); } else if (blockScopeKind === NodeFlags.Using) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_using_declaration, + "declare", + ); } else if (blockScopeKind === NodeFlags.AwaitUsing) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_an_await_using_declaration, + "declare", + ); } - else if ((node.parent.flags & NodeFlags.Ambient) && node.parent.kind === SyntaxKind.ModuleBlock) { - return grammarErrorOnNode(modifier, Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); + else if ( + (node.parent.flags & NodeFlags.Ambient) && node.parent.kind === SyntaxKind.ModuleBlock + ) { + return grammarErrorOnNode( + modifier, + Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context, + ); } else if (isPrivateIdentifierClassElementDeclaration(node)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, "declare"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, + "declare", + ); } else if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "declare", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "declare", + "accessor", + ); } flags |= ModifierFlags.Ambient; lastDeclare = modifier; @@ -47615,38 +61278,78 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract"); } - if (node.kind !== SyntaxKind.ClassDeclaration && - node.kind !== SyntaxKind.ConstructorType) { - if (node.kind !== SyntaxKind.MethodDeclaration && - node.kind !== SyntaxKind.PropertyDeclaration && - node.kind !== SyntaxKind.GetAccessor && - node.kind !== SyntaxKind.SetAccessor) { - return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration); + if ( + node.kind !== SyntaxKind.ClassDeclaration + && node.kind !== SyntaxKind.ConstructorType + ) { + if ( + node.kind !== SyntaxKind.MethodDeclaration + && node.kind !== SyntaxKind.PropertyDeclaration + && node.kind !== SyntaxKind.GetAccessor + && node.kind !== SyntaxKind.SetAccessor + ) { + return grammarErrorOnNode( + modifier, + Diagnostics + .abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration, + ); } - if (!(node.parent.kind === SyntaxKind.ClassDeclaration && hasSyntacticModifier(node.parent, ModifierFlags.Abstract))) { + if ( + !(node.parent.kind === SyntaxKind.ClassDeclaration + && hasSyntacticModifier(node.parent, ModifierFlags.Abstract)) + ) { const message = node.kind === SyntaxKind.PropertyDeclaration ? Diagnostics.Abstract_properties_can_only_appear_within_an_abstract_class : Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class; return grammarErrorOnNode(modifier, message); } if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "static", + "abstract", + ); } if (flags & ModifierFlags.Private) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "private", + "abstract", + ); } if (flags & ModifierFlags.Async && lastAsync) { - return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "async", "abstract"); + return grammarErrorOnNode( + lastAsync, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "async", + "abstract", + ); } if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "abstract", "override"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "abstract", + "override", + ); } if (flags & ModifierFlags.Accessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "abstract", "accessor"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "abstract", + "accessor", + ); } } if (isNamedDeclaration(node) && node.name.kind === SyntaxKind.PrivateIdentifier) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_a_private_identifier, + "abstract", + ); } flags |= ModifierFlags.Abstract; @@ -47657,13 +61360,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); } else if (flags & ModifierFlags.Ambient || node.parent.flags & NodeFlags.Ambient) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, + "async", + ); } else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "async"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_appear_on_a_parameter, + "async", + ); } if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "async", "abstract"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_cannot_be_used_with_1_modifier, + "async", + "abstract", + ); } flags |= ModifierFlags.Async; lastAsync = modifier; @@ -47673,14 +61389,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.OutKeyword: const inOutFlag = modifier.kind === SyntaxKind.InKeyword ? ModifierFlags.In : ModifierFlags.Out; const inOutText = modifier.kind === SyntaxKind.InKeyword ? "in" : "out"; - if (node.kind !== SyntaxKind.TypeParameter || !(isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent))) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, inOutText); + if ( + node.kind !== SyntaxKind.TypeParameter + || !(isInterfaceDeclaration(node.parent) || isClassLike(node.parent) + || isTypeAliasDeclaration(node.parent)) + ) { + return grammarErrorOnNode( + modifier, + Diagnostics + ._0_modifier_can_only_appear_on_a_type_parameter_of_a_class_interface_or_type_alias, + inOutText, + ); } if (flags & inOutFlag) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, inOutText); } if (inOutFlag & ModifierFlags.In && flags & ModifierFlags.Out) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "in", "out"); + return grammarErrorOnNode( + modifier, + Diagnostics._0_modifier_must_precede_1_modifier, + "in", + "out", + ); } flags |= inOutFlag; break; @@ -47690,23 +61420,51 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind === SyntaxKind.Constructor) { if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(lastStatic!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static"); + return grammarErrorOnNode( + lastStatic!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "static", + ); } if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(lastOverride!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "override"); // TODO: GH#18217 + return grammarErrorOnNode( + lastOverride!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "override", + ); // TODO: GH#18217 } if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(lastAsync!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async"); + return grammarErrorOnNode( + lastAsync!, + Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, + "async", + ); } return false; } - else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && flags & ModifierFlags.Ambient) { - return grammarErrorOnNode(lastDeclare!, Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, "declare"); + else if ( + (node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) + && flags & ModifierFlags.Ambient + ) { + return grammarErrorOnNode( + lastDeclare!, + Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, + "declare", + ); } - else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && isBindingPattern(node.name)) { - return grammarErrorOnNode(node, Diagnostics.A_parameter_property_may_not_be_declared_using_a_binding_pattern); + else if ( + node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) + && isBindingPattern(node.name) + ) { + return grammarErrorOnNode( + node, + Diagnostics.A_parameter_property_may_not_be_declared_using_a_binding_pattern, + ); } - else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) && node.dotDotDotToken) { + else if ( + node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.ParameterPropertyModifier) + && node.dotDotDotToken + ) { return grammarErrorOnNode(node, Diagnostics.A_parameter_property_cannot_be_declared_using_a_rest_parameter); } if (flags & ModifierFlags.Async) { @@ -47727,9 +61485,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function findFirstModifierExcept(node: HasModifiers, allowedModifier: SyntaxKind): Modifier | undefined { - const modifier = find(node.modifiers, isModifier); - return modifier && modifier.kind !== allowedModifier ? modifier : undefined; - } + const modifier = find(node.modifiers, isModifier); + return modifier && modifier.kind !== allowedModifier ? modifier : undefined; + } function findFirstIllegalModifier(node: HasModifiers | HasIllegalModifiers): Modifier | undefined { switch (node.kind) { @@ -47772,9 +61530,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.TypeAliasDeclaration: return find(node.modifiers, isModifier); case SyntaxKind.VariableStatement: - return node.declarationList.flags & NodeFlags.Using ? - findFirstModifierExcept(node, SyntaxKind.AwaitKeyword) : - find(node.modifiers, isModifier); + return node.declarationList.flags & NodeFlags.Using + ? findFirstModifierExcept(node, SyntaxKind.AwaitKeyword) + : find(node.modifiers, isModifier); case SyntaxKind.EnumDeclaration: return findFirstModifierExcept(node, SyntaxKind.ConstKeyword); default: @@ -47783,12 +61541,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function reportObviousDecoratorErrors(node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators) { + function reportObviousDecoratorErrors( + node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators, + ) { const decorator = findFirstIllegalDecorator(node); return decorator && grammarErrorOnFirstToken(decorator, Diagnostics.Decorators_are_not_valid_here); } - function findFirstIllegalDecorator(node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators): Decorator | undefined { + function findFirstIllegalDecorator( + node: HasModifiers | HasDecorators | HasIllegalModifiers | HasIllegalDecorators, + ): Decorator | undefined { return canHaveIllegalDecorators(node) ? find(node.modifiers, isDecorator) : undefined; } @@ -47804,14 +61566,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(asyncModifier, Diagnostics._0_modifier_cannot_be_used_here, "async"); } - function checkGrammarForDisallowedTrailingComma(list: NodeArray | undefined, diag = Diagnostics.Trailing_comma_not_allowed): boolean { + function checkGrammarForDisallowedTrailingComma( + list: NodeArray | undefined, + diag = Diagnostics.Trailing_comma_not_allowed, + ): boolean { if (list && list.hasTrailingComma) { return grammarErrorAtPos(list[0], list.end - ",".length, ",".length, diag); } return false; } - function checkGrammarTypeParameterList(typeParameters: NodeArray | undefined, file: SourceFile): boolean { + function checkGrammarTypeParameterList( + typeParameters: NodeArray | undefined, + file: SourceFile, + ): boolean { if (typeParameters && typeParameters.length === 0) { const start = typeParameters.pos - "<".length; const end = skipTrivia(file.text, typeParameters.end) + ">".length; @@ -47828,10 +61596,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parameter = parameters[i]; if (parameter.dotDotDotToken) { if (i !== (parameterCount - 1)) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list, + ); } if (!(parameter.flags & NodeFlags.Ambient)) { // Allow `...foo,` in ambient declarations; see GH#23070 - checkGrammarForDisallowedTrailingComma(parameters, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + parameters, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, + ); } if (parameter.questionToken) { @@ -47845,17 +61619,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else if (isOptionalParameter(parameter)) { seenOptionalParameter = true; if (parameter.questionToken && parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.Parameter_cannot_have_question_mark_and_initializer); + return grammarErrorOnNode( + parameter.name, + Diagnostics.Parameter_cannot_have_question_mark_and_initializer, + ); } } else if (seenOptionalParameter && !parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter); + return grammarErrorOnNode( + parameter.name, + Diagnostics.A_required_parameter_cannot_follow_an_optional_parameter, + ); } } } function getNonSimpleParameters(parameters: readonly ParameterDeclaration[]): readonly ParameterDeclaration[] { - return filter(parameters, parameter => !!parameter.initializer || isBindingPattern(parameter.name) || isRestParameter(parameter)); + return filter( + parameters, + parameter => !!parameter.initializer || isBindingPattern(parameter.name) || isRestParameter(parameter), + ); } function checkGrammarForUseStrictSimpleParameterList(node: FunctionLikeDeclaration): boolean { @@ -47867,14 +61650,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { forEach(nonSimpleParameters, parameter => { addRelatedInfo( error(parameter, Diagnostics.This_parameter_is_not_allowed_with_use_strict_directive), - createDiagnosticForNode(useStrictDirective, Diagnostics.use_strict_directive_used_here) + createDiagnosticForNode(useStrictDirective, Diagnostics.use_strict_directive_used_here), ); }); const diagnostics = nonSimpleParameters.map((parameter, index) => ( - index === 0 ? createDiagnosticForNode(parameter, Diagnostics.Non_simple_parameter_declared_here) : createDiagnosticForNode(parameter, Diagnostics.and_here) + index === 0 ? createDiagnosticForNode(parameter, Diagnostics.Non_simple_parameter_declared_here) + : createDiagnosticForNode(parameter, Diagnostics.and_here) )) as [DiagnosticWithLocation, ...DiagnosticWithLocation[]]; - addRelatedInfo(error(useStrictDirective, Diagnostics.use_strict_directive_cannot_be_used_with_non_simple_parameter_list), ...diagnostics); + addRelatedInfo( + error( + useStrictDirective, + Diagnostics.use_strict_directive_cannot_be_used_with_non_simple_parameter_list, + ), + ...diagnostics, + ); return true; } } @@ -47885,17 +61675,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration | MethodSignature): boolean { // Prevent cascading error by short-circuit const file = getSourceFileOfNode(node); - return checkGrammarModifiers(node) || - checkGrammarTypeParameterList(node.typeParameters, file) || - checkGrammarParameterList(node.parameters) || - checkGrammarArrowFunction(node, file) || - (isFunctionLikeDeclaration(node) && checkGrammarForUseStrictSimpleParameterList(node)); + return checkGrammarModifiers(node) + || checkGrammarTypeParameterList(node.typeParameters, file) + || checkGrammarParameterList(node.parameters) + || checkGrammarArrowFunction(node, file) + || (isFunctionLikeDeclaration(node) && checkGrammarForUseStrictSimpleParameterList(node)); } function checkGrammarClassLikeDeclaration(node: ClassLikeDeclaration): boolean { const file = getSourceFileOfNode(node); - return checkGrammarClassDeclarationHeritageClauses(node) || - checkGrammarTypeParameterList(node.typeParameters, file); + return checkGrammarClassDeclarationHeritageClauses(node) + || checkGrammarTypeParameterList(node.typeParameters, file); } function checkGrammarArrowFunction(node: Node, file: SourceFile): boolean { @@ -47903,50 +61693,87 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - if (node.typeParameters && !(length(node.typeParameters) > 1 || node.typeParameters.hasTrailingComma || node.typeParameters[0].constraint)) { + if ( + node.typeParameters + && !(length(node.typeParameters) > 1 || node.typeParameters.hasTrailingComma + || node.typeParameters[0].constraint) + ) { if (file && fileExtensionIsOneOf(file.fileName, [Extension.Mts, Extension.Cts])) { - grammarErrorOnNode(node.typeParameters[0], Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Add_a_trailing_comma_or_explicit_constraint); + grammarErrorOnNode( + node.typeParameters[0], + Diagnostics + .This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Add_a_trailing_comma_or_explicit_constraint, + ); } } const { equalsGreaterThanToken } = node; const startLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.pos).line; const endLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.end).line; - return startLine !== endLine && grammarErrorOnNode(equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); + return startLine !== endLine + && grammarErrorOnNode(equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow); } function checkGrammarIndexSignatureParameters(node: SignatureDeclaration): boolean { const parameter = node.parameters[0]; if (node.parameters.length !== 1) { if (parameter) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_must_have_exactly_one_parameter); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_must_have_exactly_one_parameter, + ); } else { return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_exactly_one_parameter); } } - checkGrammarForDisallowedTrailingComma(node.parameters, Diagnostics.An_index_signature_cannot_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + node.parameters, + Diagnostics.An_index_signature_cannot_have_a_trailing_comma, + ); if (parameter.dotDotDotToken) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter); + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.An_index_signature_cannot_have_a_rest_parameter, + ); } if (hasEffectiveModifiers(parameter)) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier, + ); } if (parameter.questionToken) { - return grammarErrorOnNode(parameter.questionToken, Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark); + return grammarErrorOnNode( + parameter.questionToken, + Diagnostics.An_index_signature_parameter_cannot_have_a_question_mark, + ); } if (parameter.initializer) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_initializer); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_cannot_have_an_initializer, + ); } if (!parameter.type) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_must_have_a_type_annotation); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_must_have_a_type_annotation, + ); } const type = getTypeFromTypeNode(parameter.type); if (someType(type, t => !!(t.flags & TypeFlags.StringOrNumberLiteralOrUnique)) || isGenericType(type)) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead); + return grammarErrorOnNode( + parameter.name, + Diagnostics + .An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead, + ); } if (!everyType(type, isValidIndexKeyType)) { - return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type); + return grammarErrorOnNode( + parameter.name, + Diagnostics.An_index_signature_parameter_type_must_be_string_number_symbol_or_a_template_literal_type, + ); } if (!node.type) { return grammarErrorOnNode(node, Diagnostics.An_index_signature_must_have_a_type_annotation); @@ -47959,7 +61786,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkGrammarModifiers(node) || checkGrammarIndexSignatureParameters(node); } - function checkGrammarForAtLeastOneTypeArgument(node: Node, typeArguments: NodeArray | undefined): boolean { + function checkGrammarForAtLeastOneTypeArgument( + node: Node, + typeArguments: NodeArray | undefined, + ): boolean { if (typeArguments && typeArguments.length === 0) { const sourceFile = getSourceFileOfNode(node); const start = typeArguments.pos - "<".length; @@ -47970,13 +61800,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkGrammarTypeArguments(node: Node, typeArguments: NodeArray | undefined): boolean { - return checkGrammarForDisallowedTrailingComma(typeArguments) || - checkGrammarForAtLeastOneTypeArgument(node, typeArguments); + return checkGrammarForDisallowedTrailingComma(typeArguments) + || checkGrammarForAtLeastOneTypeArgument(node, typeArguments); } function checkGrammarTaggedTemplateChain(node: TaggedTemplateExpression): boolean { if (node.questionDotToken || node.flags & NodeFlags.OptionalChain) { - return grammarErrorOnNode(node.template, Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain); + return grammarErrorOnNode( + node.template, + Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain, + ); } return false; } @@ -47995,7 +61828,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { if (isExpressionWithTypeArguments(node) && isImportKeyword(node.expression) && node.typeArguments) { - return grammarErrorOnNode(node, Diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments); + return grammarErrorOnNode( + node, + Diagnostics + .This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments, + ); } return checkGrammarTypeArguments(node, node.typeArguments); } @@ -48012,11 +61849,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (seenImplementsClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_must_precede_implements_clause); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.extends_clause_must_precede_implements_clause, + ); } if (heritageClause.types.length > 1) { - return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_can_only_extend_a_single_class); + return grammarErrorOnFirstToken( + heritageClause.types[1], + Diagnostics.Classes_can_only_extend_a_single_class, + ); } seenExtendsClause = true; @@ -48050,7 +61893,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword); - return grammarErrorOnFirstToken(heritageClause, Diagnostics.Interface_declaration_cannot_have_implements_clause); + return grammarErrorOnFirstToken( + heritageClause, + Diagnostics.Interface_declaration_cannot_have_implements_clause, + ); } // Grammar checking heritageClause inside class declaration @@ -48067,8 +61913,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const computedPropertyName = node as ComputedPropertyName; - if (computedPropertyName.expression.kind === SyntaxKind.BinaryExpression && (computedPropertyName.expression as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken) { - return grammarErrorOnNode(computedPropertyName.expression, Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name); + if ( + computedPropertyName.expression.kind === SyntaxKind.BinaryExpression + && (computedPropertyName.expression as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken + ) { + return grammarErrorOnNode( + computedPropertyName.expression, + Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name, + ); } return false; } @@ -48076,23 +61928,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarForGenerator(node: FunctionLikeDeclaration) { if (node.asteriskToken) { Debug.assert( - node.kind === SyntaxKind.FunctionDeclaration || - node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.MethodDeclaration); + node.kind === SyntaxKind.FunctionDeclaration + || node.kind === SyntaxKind.FunctionExpression + || node.kind === SyntaxKind.MethodDeclaration, + ); if (node.flags & NodeFlags.Ambient) { - return grammarErrorOnNode(node.asteriskToken, Diagnostics.Generators_are_not_allowed_in_an_ambient_context); + return grammarErrorOnNode( + node.asteriskToken, + Diagnostics.Generators_are_not_allowed_in_an_ambient_context, + ); } if (!node.body) { - return grammarErrorOnNode(node.asteriskToken, Diagnostics.An_overload_signature_cannot_be_declared_as_a_generator); + return grammarErrorOnNode( + node.asteriskToken, + Diagnostics.An_overload_signature_cannot_be_declared_as_a_generator, + ); } } } - function checkGrammarForInvalidQuestionMark(questionToken: QuestionToken | undefined, message: DiagnosticMessage): boolean { + function checkGrammarForInvalidQuestionMark( + questionToken: QuestionToken | undefined, + message: DiagnosticMessage, + ): boolean { return !!questionToken && grammarErrorOnNode(questionToken, message); } - function checkGrammarForInvalidExclamationToken(exclamationToken: ExclamationToken | undefined, message: DiagnosticMessage): boolean { + function checkGrammarForInvalidExclamationToken( + exclamationToken: ExclamationToken | undefined, + message: DiagnosticMessage, + ): boolean { return !!exclamationToken && grammarErrorOnNode(exclamationToken, message); } @@ -48105,7 +61970,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // a rest property cannot be destructured any further const expression = skipParentheses(prop.expression); if (isArrayLiteralExpression(expression) || isObjectLiteralExpression(expression)) { - return grammarErrorOnNode(prop.expression, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern); + return grammarErrorOnNode( + prop.expression, + Diagnostics.A_rest_element_cannot_contain_a_binding_pattern, + ); } } continue; @@ -48116,10 +61984,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkGrammarComputedPropertyName(name); } - if (prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring && prop.objectAssignmentInitializer) { + if ( + prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring + && prop.objectAssignmentInitializer + ) { // having objectAssignmentInitializer is only valid in ObjectAssignmentPattern // outside of destructuring it is a syntax error - grammarErrorOnNode(prop.equalsToken!, Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern); + grammarErrorOnNode( + prop.equalsToken!, + Diagnostics + .Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern, + ); } if (name.kind === SyntaxKind.PrivateIdentifier) { @@ -48129,14 +62004,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Modifiers are never allowed on properties except for 'async' on a method declaration if (canHaveModifiers(prop) && prop.modifiers) { for (const mod of prop.modifiers) { - if (isModifier(mod) && (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration)) { + if ( + isModifier(mod) + && (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) + ) { grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); } } } else if (canHaveIllegalModifiers(prop) && prop.modifiers) { for (const mod of prop.modifiers) { - if (isModifier(mod)) { + if (isModifier(mod)) { grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); } } @@ -48155,8 +62033,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.PropertyAssignment: // Grammar checking for computedPropertyName and shorthandPropertyAssignment - checkGrammarForInvalidExclamationToken(prop.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context); - checkGrammarForInvalidQuestionMark(prop.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); + checkGrammarForInvalidExclamationToken( + prop.exclamationToken, + Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context, + ); + checkGrammarForInvalidQuestionMark( + prop.questionToken, + Diagnostics.An_object_member_cannot_be_declared_optional, + ); if (name.kind === SyntaxKind.NumericLiteral) { checkGrammarNumericLiteral(name); } @@ -48189,19 +62073,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if ((currentKind & DeclarationMeaning.Method) && (existingKind & DeclarationMeaning.Method)) { grammarErrorOnNode(name, Diagnostics.Duplicate_identifier_0, getTextOfNode(name)); } - else if ((currentKind & DeclarationMeaning.PropertyAssignment) && (existingKind & DeclarationMeaning.PropertyAssignment)) { - grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name, getTextOfNode(name)); + else if ( + (currentKind & DeclarationMeaning.PropertyAssignment) + && (existingKind & DeclarationMeaning.PropertyAssignment) + ) { + grammarErrorOnNode( + name, + Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name, + getTextOfNode(name), + ); } - else if ((currentKind & DeclarationMeaning.GetOrSetAccessor) && (existingKind & DeclarationMeaning.GetOrSetAccessor)) { + else if ( + (currentKind & DeclarationMeaning.GetOrSetAccessor) + && (existingKind & DeclarationMeaning.GetOrSetAccessor) + ) { if (existingKind !== DeclarationMeaning.GetOrSetAccessor && currentKind !== existingKind) { seen.set(effectiveName, currentKind | existingKind); } else { - return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name); + return grammarErrorOnNode( + name, + Diagnostics + .An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name, + ); } } else { - return grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name); + return grammarErrorOnNode( + name, + Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name, + ); } } } @@ -48224,27 +62125,42 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { seen.set(escapedText, true); } else { - return grammarErrorOnNode(name, Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name); + return grammarErrorOnNode( + name, + Diagnostics.JSX_elements_cannot_have_multiple_attributes_with_the_same_name, + ); } if (initializer && initializer.kind === SyntaxKind.JsxExpression && !initializer.expression) { - return grammarErrorOnNode(initializer, Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression); + return grammarErrorOnNode( + initializer, + Diagnostics.JSX_attributes_must_only_be_assigned_a_non_empty_expression, + ); } } } function checkGrammarJsxName(node: JsxTagNameExpression) { if (isPropertyAccessExpression(node) && isJsxNamespacedName(node.expression)) { - return grammarErrorOnNode(node.expression, Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names); + return grammarErrorOnNode( + node.expression, + Diagnostics.JSX_property_access_expressions_cannot_include_JSX_namespace_names, + ); } - if (isJsxNamespacedName(node) && getJSXTransformEnabled(compilerOptions) && !isIntrinsicJsxName(node.namespace.escapedText)) { + if ( + isJsxNamespacedName(node) && getJSXTransformEnabled(compilerOptions) + && !isIntrinsicJsxName(node.namespace.escapedText) + ) { return grammarErrorOnNode(node, Diagnostics.React_components_cannot_include_JSX_namespace_names); } } function checkGrammarJsxExpression(node: JsxExpression) { if (node.expression && isCommaSequence(node.expression)) { - return grammarErrorOnNode(node.expression, Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array); + return grammarErrorOnNode( + node.expression, + Diagnostics.JSX_expressions_may_not_use_the_comma_operator_Did_you_mean_to_write_an_array, + ); } } @@ -48259,15 +62175,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isInTopLevelContext(forInOrOfStatement)) { if (!hasParseDiagnostics(sourceFile)) { if (!isEffectiveExternalModule(sourceFile, compilerOptions)) { - diagnostics.add(createDiagnosticForNode(forInOrOfStatement.awaitModifier, - Diagnostics.for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module)); + diagnostics.add( + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics + .for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module, + ), + ); } switch (moduleKind) { case ModuleKind.Node16: case ModuleKind.NodeNext: if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) { diagnostics.add( - createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level) + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics + .The_current_file_is_a_CommonJS_module_and_cannot_use_await_at_the_top_level, + ), ); break; } @@ -48281,9 +62206,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // fallthrough default: diagnostics.add( - createDiagnosticForNode(forInOrOfStatement.awaitModifier, - Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher - ) + createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics + .Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher, + ), ); break; } @@ -48292,11 +62219,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { // use of 'for-await-of' in non-async function if (!hasParseDiagnostics(sourceFile)) { - const diagnostic = createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules); + const diagnostic = createDiagnosticForNode( + forInOrOfStatement.awaitModifier, + Diagnostics + .for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules, + ); const func = getContainingFunction(forInOrOfStatement); if (func && func.kind !== SyntaxKind.Constructor) { - Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function."); - const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async); + Debug.assert( + (getFunctionFlags(func) & FunctionFlags.Async) === 0, + "Enclosing function should never be an async function.", + ); + const relatedInfo = createDiagnosticForNode( + func, + Diagnostics.Did_you_mean_to_mark_this_function_as_async, + ); addRelatedInfo(diagnostic, relatedInfo); } diagnostics.add(diagnostic); @@ -48307,9 +62244,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - if (isForOfStatement(forInOrOfStatement) && !(forInOrOfStatement.flags & NodeFlags.AwaitContext) && - isIdentifier(forInOrOfStatement.initializer) && forInOrOfStatement.initializer.escapedText === "async") { - grammarErrorOnNode(forInOrOfStatement.initializer, Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async); + if ( + isForOfStatement(forInOrOfStatement) && !(forInOrOfStatement.flags & NodeFlags.AwaitContext) + && isIdentifier(forInOrOfStatement.initializer) && forInOrOfStatement.initializer.escapedText === "async" + ) { + grammarErrorOnNode( + forInOrOfStatement.initializer, + Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async, + ); return false; } @@ -48356,12 +62298,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkGrammarAccessor(accessor: AccessorDeclaration): boolean { - if (!(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration)) { + if ( + !(accessor.flags & NodeFlags.Ambient) && (accessor.parent.kind !== SyntaxKind.TypeLiteral) + && (accessor.parent.kind !== SyntaxKind.InterfaceDeclaration) + ) { if (languageVersion < ScriptTarget.ES5) { - return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher); + return grammarErrorOnNode( + accessor.name, + Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher, + ); } if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(accessor.name)) { - return grammarErrorOnNode(accessor.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + return grammarErrorOnNode( + accessor.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher, + ); } if (accessor.body === undefined && !hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { return grammarErrorAtPos(accessor, accessor.end - 1, ";".length, Diagnostics._0_expected, "{"); @@ -48371,32 +62322,55 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation); } - if (accessor.parent.kind === SyntaxKind.TypeLiteral || accessor.parent.kind === SyntaxKind.InterfaceDeclaration) { - return grammarErrorOnNode(accessor.body, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); + if ( + accessor.parent.kind === SyntaxKind.TypeLiteral + || accessor.parent.kind === SyntaxKind.InterfaceDeclaration + ) { + return grammarErrorOnNode( + accessor.body, + Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts, + ); } } if (accessor.typeParameters) { return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_have_type_parameters); } if (!doesAccessorHaveCorrectParameterCount(accessor)) { - return grammarErrorOnNode(accessor.name, - accessor.kind === SyntaxKind.GetAccessor ? - Diagnostics.A_get_accessor_cannot_have_parameters : - Diagnostics.A_set_accessor_must_have_exactly_one_parameter); + return grammarErrorOnNode( + accessor.name, + accessor.kind === SyntaxKind.GetAccessor + ? Diagnostics.A_get_accessor_cannot_have_parameters + : Diagnostics.A_set_accessor_must_have_exactly_one_parameter, + ); } if (accessor.kind === SyntaxKind.SetAccessor) { if (accessor.type) { - return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation); + return grammarErrorOnNode( + accessor.name, + Diagnostics.A_set_accessor_cannot_have_a_return_type_annotation, + ); } - const parameter = Debug.checkDefined(getSetAccessorValueParameter(accessor), "Return value does not match parameter count assertion."); + const parameter = Debug.checkDefined( + getSetAccessorValueParameter(accessor), + "Return value does not match parameter count assertion.", + ); if (parameter.dotDotDotToken) { - return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_set_accessor_cannot_have_rest_parameter); + return grammarErrorOnNode( + parameter.dotDotDotToken, + Diagnostics.A_set_accessor_cannot_have_rest_parameter, + ); } if (parameter.questionToken) { - return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_set_accessor_cannot_have_an_optional_parameter); + return grammarErrorOnNode( + parameter.questionToken, + Diagnostics.A_set_accessor_cannot_have_an_optional_parameter, + ); } if (parameter.initializer) { - return grammarErrorOnNode(accessor.name, Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer); + return grammarErrorOnNode( + accessor.name, + Diagnostics.A_set_accessor_parameter_cannot_have_an_initializer, + ); } } return false; @@ -48407,7 +62381,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * A set accessor has one parameter or a `this` parameter and one more parameter. */ function doesAccessorHaveCorrectParameterCount(accessor: AccessorDeclaration) { - return getAccessorThisParameter(accessor) || accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 0 : 1); + return getAccessorThisParameter(accessor) + || accessor.parameters.length === (accessor.kind === SyntaxKind.GetAccessor ? 0 : 1); } function getAccessorThisParameter(accessor: AccessorDeclaration): ParameterDeclaration | undefined { @@ -48432,26 +62407,46 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.VariableDeclaration: const decl = parent as VariableDeclaration; if (decl.name.kind !== SyntaxKind.Identifier) { - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name); + return grammarErrorOnNode( + node, + Diagnostics + .unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name, + ); } if (!isVariableDeclarationInVariableStatement(decl)) { - return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement); + return grammarErrorOnNode( + node, + Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement, + ); } if (!(decl.parent.flags & NodeFlags.Const)) { - return grammarErrorOnNode((parent as VariableDeclaration).name, Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const); + return grammarErrorOnNode( + (parent as VariableDeclaration).name, + Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const, + ); } break; case SyntaxKind.PropertyDeclaration: - if (!isStatic(parent) || - !hasEffectiveReadonlyModifier(parent)) { - return grammarErrorOnNode((parent as PropertyDeclaration).name, Diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly); + if ( + !isStatic(parent) + || !hasEffectiveReadonlyModifier(parent) + ) { + return grammarErrorOnNode( + (parent as PropertyDeclaration).name, + Diagnostics + .A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly, + ); } break; case SyntaxKind.PropertySignature: if (!hasSyntacticModifier(parent, ModifierFlags.Readonly)) { - return grammarErrorOnNode((parent as PropertySignature).name, Diagnostics.A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly); + return grammarErrorOnNode( + (parent as PropertySignature).name, + Diagnostics + .A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly, + ); } break; @@ -48461,7 +62456,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (node.operator === SyntaxKind.ReadonlyKeyword) { if (node.type.kind !== SyntaxKind.ArrayType && node.type.kind !== SyntaxKind.TupleType) { - return grammarErrorOnFirstToken(node, Diagnostics.readonly_type_modifier_is_only_permitted_on_array_and_tuple_literal_types, tokenToString(SyntaxKind.SymbolKeyword)); + return grammarErrorOnFirstToken( + node, + Diagnostics.readonly_type_modifier_is_only_permitted_on_array_and_tuple_literal_types, + tokenToString(SyntaxKind.SymbolKeyword), + ); } } } @@ -48480,13 +62479,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind === SyntaxKind.MethodDeclaration) { if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { // We only disallow modifier on a method declaration if it is a property of object-literal-expression - if (node.modifiers && !(node.modifiers.length === 1 && first(node.modifiers).kind === SyntaxKind.AsyncKeyword)) { + if ( + node.modifiers + && !(node.modifiers.length === 1 && first(node.modifiers).kind === SyntaxKind.AsyncKeyword) + ) { return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); } - else if (checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) { + else if ( + checkGrammarForInvalidQuestionMark( + node.questionToken, + Diagnostics.An_object_member_cannot_be_declared_optional, + ) + ) { return true; } - else if (checkGrammarForInvalidExclamationToken(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context)) { + else if ( + checkGrammarForInvalidExclamationToken( + node.exclamationToken, + Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context, + ) + ) { return true; } else if (node.body === undefined) { @@ -48500,7 +62512,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isClassLike(node.parent)) { if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(node.name)) { - return grammarErrorOnNode(node.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + return grammarErrorOnNode( + node.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher, + ); } // Technically, computed properties in ambient contexts is disallowed // for property declarations and accessors too, not just methods. @@ -48508,17 +62523,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and accessors are not allowed in ambient contexts in general, // so this error only really matters for methods. if (node.flags & NodeFlags.Ambient) { - return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_ambient_context_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); + return checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_an_ambient_context_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ); } else if (node.kind === SyntaxKind.MethodDeclaration && !node.body) { - return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_method_overload_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); + return checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_a_method_overload_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ); } } else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { - return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); + return checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ); } else if (node.parent.kind === SyntaxKind.TypeLiteral) { - return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type); + return checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ); } } @@ -48535,10 +62566,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // found matching label - verify that label usage is correct // continue can only target labels that are on iteration statements const isMisplacedContinueLabel = node.kind === SyntaxKind.ContinueStatement - && !isIterationStatement((current as LabeledStatement).statement, /*lookInLabeledStatements*/ true); + && !isIterationStatement( + (current as LabeledStatement).statement, + /*lookInLabeledStatements*/ true, + ); if (isMisplacedContinueLabel) { - return grammarErrorOnNode(node, Diagnostics.A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement); + return grammarErrorOnNode( + node, + Diagnostics + .A_continue_statement_can_only_jump_to_a_label_of_an_enclosing_iteration_statement, + ); } return false; @@ -48582,7 +62620,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node !== last(elements)) { return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern); } - checkGrammarForDisallowedTrailingComma(elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma); + checkGrammarForDisallowedTrailingComma( + elements, + Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma, + ); if (node.propertyName) { return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_have_a_property_name); @@ -48591,25 +62632,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.dotDotDotToken && node.initializer) { // Error on equals token which immediately precedes the initializer - return grammarErrorAtPos(node, node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer); + return grammarErrorAtPos( + node, + node.initializer.pos - 1, + 1, + Diagnostics.A_rest_element_cannot_have_an_initializer, + ); } } function isStringOrNumberLiteralExpression(expr: Expression) { - return isStringOrNumericLiteralLike(expr) || - expr.kind === SyntaxKind.PrefixUnaryExpression && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && - (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; + return isStringOrNumericLiteralLike(expr) + || expr.kind === SyntaxKind.PrefixUnaryExpression + && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken + && (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.NumericLiteral; } function isBigIntLiteralExpression(expr: Expression) { - return expr.kind === SyntaxKind.BigIntLiteral || - expr.kind === SyntaxKind.PrefixUnaryExpression && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken && - (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.BigIntLiteral; + return expr.kind === SyntaxKind.BigIntLiteral + || expr.kind === SyntaxKind.PrefixUnaryExpression + && (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusToken + && (expr as PrefixUnaryExpression).operand.kind === SyntaxKind.BigIntLiteral; } function isSimpleLiteralEnumReference(expr: Expression) { - if ((isPropertyAccessExpression(expr) || (isElementAccessExpression(expr) && isStringOrNumberLiteralExpression(expr.argumentExpression))) && - isEntityNameExpression(expr.expression)) { + if ( + (isPropertyAccessExpression(expr) + || (isElementAccessExpression(expr) && isStringOrNumberLiteralExpression(expr.argumentExpression))) + && isEntityNameExpression(expr.expression) + ) { return !!(checkExpressionCached(expr).flags & TypeFlags.EnumLike); } } @@ -48618,15 +62669,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const initializer = node.initializer; if (initializer) { const isInvalidInitializer = !( - isStringOrNumberLiteralExpression(initializer) || - isSimpleLiteralEnumReference(initializer) || - initializer.kind === SyntaxKind.TrueKeyword || initializer.kind === SyntaxKind.FalseKeyword || - isBigIntLiteralExpression(initializer) + isStringOrNumberLiteralExpression(initializer) + || isSimpleLiteralEnumReference(initializer) + || initializer.kind === SyntaxKind.TrueKeyword || initializer.kind === SyntaxKind.FalseKeyword + || isBigIntLiteralExpression(initializer) ); - const isConstOrReadonly = isDeclarationReadonly(node) || isVariableDeclaration(node) && (isVarConstLike(node)); + const isConstOrReadonly = isDeclarationReadonly(node) + || isVariableDeclaration(node) && (isVarConstLike(node)); if (isConstOrReadonly && !node.type) { if (isInvalidInitializer) { - return grammarErrorOnNode(initializer, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_reference); + return grammarErrorOnNode( + initializer, + Diagnostics + .A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_reference, + ); } } else { @@ -48641,13 +62697,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isBindingPattern(node.name)) { switch (blockScopeKind) { case NodeFlags.AwaitUsing: - return grammarErrorOnNode(node, Diagnostics._0_declarations_may_not_have_binding_patterns, "await using"); + return grammarErrorOnNode( + node, + Diagnostics._0_declarations_may_not_have_binding_patterns, + "await using", + ); case NodeFlags.Using: return grammarErrorOnNode(node, Diagnostics._0_declarations_may_not_have_binding_patterns, "using"); } } - if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) { + if ( + node.parent.parent.kind !== SyntaxKind.ForInStatement + && node.parent.parent.kind !== SyntaxKind.ForOfStatement + ) { if (nodeFlags & NodeFlags.Ambient) { checkAmbientInitializer(node); } @@ -48666,17 +62729,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || nodeFlags & NodeFlags.Ambient)) { + if ( + node.exclamationToken + && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer + || nodeFlags & NodeFlags.Ambient) + ) { const message = node.initializer ? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions : !node.type - ? Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations - : Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context; + ? Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations + : Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context; return grammarErrorOnNode(node.exclamationToken, message); } - if ((moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && moduleKind !== ModuleKind.System && - !(node.parent.parent.flags & NodeFlags.Ambient) && hasSyntacticModifier(node.parent.parent, ModifierFlags.Export)) { + if ( + (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + && moduleKind !== ModuleKind.System + && !(node.parent.parent.flags & NodeFlags.Ambient) + && hasSyntacticModifier(node.parent.parent, ModifierFlags.Export) + ) { checkESModuleMarker(node.name); } @@ -48693,7 +62764,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkESModuleMarker(name: Identifier | BindingPattern): boolean { if (name.kind === SyntaxKind.Identifier) { if (idText(name) === "__esModule") { - return grammarErrorOnNodeSkippedOn("noEmit", name, Diagnostics.Identifier_expected_esModule_is_reserved_as_an_exported_marker_when_transforming_ECMAScript_modules); + return grammarErrorOnNodeSkippedOn( + "noEmit", + name, + Diagnostics + .Identifier_expected_esModule_is_reserved_as_an_exported_marker_when_transforming_ECMAScript_modules, + ); } } else { @@ -48710,7 +62786,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean { if (name.kind === SyntaxKind.Identifier) { if (name.escapedText === "let") { - return grammarErrorOnNode(name, Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations); + return grammarErrorOnNode( + name, + Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations, + ); } } else { @@ -48731,15 +62810,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (!declarationList.declarations.length) { - return grammarErrorAtPos(declarationList, declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty); + return grammarErrorAtPos( + declarationList, + declarations.pos, + declarations.end - declarations.pos, + Diagnostics.Variable_declaration_list_cannot_be_empty, + ); } const blockScopeFlags = declarationList.flags & NodeFlags.BlockScoped; - if ((blockScopeFlags === NodeFlags.Using || blockScopeFlags === NodeFlags.AwaitUsing) && isForInStatement(declarationList.parent)) { - return grammarErrorOnNode(declarationList, - blockScopeFlags === NodeFlags.Using ? - Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_using_declaration : - Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_an_await_using_declaration); + if ( + (blockScopeFlags === NodeFlags.Using || blockScopeFlags === NodeFlags.AwaitUsing) + && isForInStatement(declarationList.parent) + ) { + return grammarErrorOnNode( + declarationList, + blockScopeFlags === NodeFlags.Using + ? Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_a_using_declaration + : Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_be_an_await_using_declaration, + ); } if (blockScopeFlags === NodeFlags.AwaitUsing) { @@ -48770,12 +62859,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!allowLetAndConstDeclarations(node.parent)) { const blockScopeKind = getCombinedNodeFlagsCached(node.declarationList) & NodeFlags.BlockScoped; if (blockScopeKind) { - const keyword = blockScopeKind === NodeFlags.Let ? "let" : - blockScopeKind === NodeFlags.Const ? "const" : - blockScopeKind === NodeFlags.Using ? "using" : - blockScopeKind === NodeFlags.AwaitUsing ? "await using" : - Debug.fail("Unknown BlockScope flag"); - return grammarErrorOnNode(node, Diagnostics._0_declarations_can_only_be_declared_inside_a_block, keyword); + const keyword = blockScopeKind === NodeFlags.Let ? "let" + : blockScopeKind === NodeFlags.Const ? "const" + : blockScopeKind === NodeFlags.Using ? "using" + : blockScopeKind === NodeFlags.AwaitUsing ? "await using" + : Debug.fail("Unknown BlockScope flag"); + return grammarErrorOnNode( + node, + Diagnostics._0_declarations_can_only_be_declared_inside_a_block, + keyword, + ); } } } @@ -48785,12 +62878,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (node.keywordToken) { case SyntaxKind.NewKeyword: if (escapedText !== "target") { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, unescapeLeadingUnderscores(node.name.escapedText), tokenToString(node.keywordToken), "target"); + return grammarErrorOnNode( + node.name, + Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, + unescapeLeadingUnderscores(node.name.escapedText), + tokenToString(node.keywordToken), + "target", + ); } break; case SyntaxKind.ImportKeyword: if (escapedText !== "meta") { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, unescapeLeadingUnderscores(node.name.escapedText), tokenToString(node.keywordToken), "meta"); + return grammarErrorOnNode( + node.name, + Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, + unescapeLeadingUnderscores(node.name.escapedText), + tokenToString(node.keywordToken), + "meta", + ); } break; } @@ -48810,7 +62915,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function grammarErrorAtPos(nodeForSourceFile: Node, start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { + function grammarErrorAtPos( + nodeForSourceFile: Node, + start: number, + length: number, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean { const sourceFile = getSourceFileOfNode(nodeForSourceFile); if (!hasParseDiagnostics(sourceFile)) { diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, ...args)); @@ -48819,7 +62930,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function grammarErrorOnNodeSkippedOn(key: keyof CompilerOptions, node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { + function grammarErrorOnNodeSkippedOn( + key: keyof CompilerOptions, + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { errorSkippedOn(key, node, message, ...args); @@ -48842,7 +62958,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const range = node.typeParameters || jsdocTypeParameters && firstOrUndefined(jsdocTypeParameters); if (range) { const pos = range.pos === range.end ? range.pos : skipTrivia(getSourceFileOfNode(node).text, range.pos); - return grammarErrorAtPos(node, pos, range.end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); + return grammarErrorAtPos( + node, + pos, + range.end - pos, + Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration, + ); } } @@ -48854,45 +62975,88 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkGrammarProperty(node: PropertyDeclaration | PropertySignature) { - if (isComputedPropertyName(node.name) && isBinaryExpression(node.name.expression) && node.name.expression.operatorToken.kind === SyntaxKind.InKeyword) { - return grammarErrorOnNode(node.parent.members[0], Diagnostics.A_mapped_type_may_not_declare_properties_or_methods); + if ( + isComputedPropertyName(node.name) && isBinaryExpression(node.name.expression) + && node.name.expression.operatorToken.kind === SyntaxKind.InKeyword + ) { + return grammarErrorOnNode( + node.parent.members[0], + Diagnostics.A_mapped_type_may_not_declare_properties_or_methods, + ); } if (isClassLike(node.parent)) { if (isStringLiteral(node.name) && node.name.text === "constructor") { return grammarErrorOnNode(node.name, Diagnostics.Classes_may_not_have_a_field_named_constructor); } - if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_class_property_declaration_must_have_a_simple_literal_type_or_a_unique_symbol_type)) { + if ( + checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_a_class_property_declaration_must_have_a_simple_literal_type_or_a_unique_symbol_type, + ) + ) { return true; } if (languageVersion < ScriptTarget.ES2015 && isPrivateIdentifier(node.name)) { - return grammarErrorOnNode(node.name, Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher); + return grammarErrorOnNode( + node.name, + Diagnostics.Private_identifiers_are_only_available_when_targeting_ECMAScript_2015_and_higher, + ); } if (languageVersion < ScriptTarget.ES2015 && isAutoAccessorPropertyDeclaration(node)) { - return grammarErrorOnNode(node.name, Diagnostics.Properties_with_the_accessor_modifier_are_only_available_when_targeting_ECMAScript_2015_and_higher); + return grammarErrorOnNode( + node.name, + Diagnostics + .Properties_with_the_accessor_modifier_are_only_available_when_targeting_ECMAScript_2015_and_higher, + ); } - if (isAutoAccessorPropertyDeclaration(node) && checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_accessor_property_cannot_be_declared_optional)) { + if ( + isAutoAccessorPropertyDeclaration(node) + && checkGrammarForInvalidQuestionMark( + node.questionToken, + Diagnostics.An_accessor_property_cannot_be_declared_optional, + ) + ) { return true; } } else if (node.parent.kind === SyntaxKind.InterfaceDeclaration) { - if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type)) { + if ( + checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_an_interface_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ) + ) { return true; } // Interfaces cannot contain property declarations Debug.assertNode(node, isPropertySignature); if (node.initializer) { - return grammarErrorOnNode(node.initializer, Diagnostics.An_interface_property_cannot_have_an_initializer); + return grammarErrorOnNode( + node.initializer, + Diagnostics.An_interface_property_cannot_have_an_initializer, + ); } } else if (isTypeLiteralNode(node.parent)) { - if (checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type)) { + if ( + checkGrammarForInvalidDynamicName( + node.name, + Diagnostics + .A_computed_property_name_in_a_type_literal_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type, + ) + ) { return true; } // Type literals cannot contain property declarations Debug.assertNode(node, isPropertySignature); if (node.initializer) { - return grammarErrorOnNode(node.initializer, Diagnostics.A_type_literal_property_cannot_have_an_initializer); + return grammarErrorOnNode( + node.initializer, + Diagnostics.A_type_literal_property_cannot_have_an_initializer, + ); } } @@ -48900,13 +63064,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkAmbientInitializer(node); } - if (isPropertyDeclaration(node) && node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer || - node.flags & NodeFlags.Ambient || isStatic(node) || hasAbstractModifier(node))) { + if ( + isPropertyDeclaration(node) && node.exclamationToken + && (!isClassLike(node.parent) || !node.type || node.initializer + || node.flags & NodeFlags.Ambient || isStatic(node) || hasAbstractModifier(node)) + ) { const message = node.initializer ? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions : !node.type - ? Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations - : Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context; + ? Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations + : Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context; return grammarErrorOnNode(node.exclamationToken, message); } } @@ -48924,18 +63091,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // export_opt AmbientDeclaration // // TODO: The spec needs to be amended to reflect this grammar. - if (node.kind === SyntaxKind.InterfaceDeclaration || - node.kind === SyntaxKind.TypeAliasDeclaration || - node.kind === SyntaxKind.ImportDeclaration || - node.kind === SyntaxKind.ImportEqualsDeclaration || - node.kind === SyntaxKind.ExportDeclaration || - node.kind === SyntaxKind.ExportAssignment || - node.kind === SyntaxKind.NamespaceExportDeclaration || - hasSyntacticModifier(node, ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default)) { + if ( + node.kind === SyntaxKind.InterfaceDeclaration + || node.kind === SyntaxKind.TypeAliasDeclaration + || node.kind === SyntaxKind.ImportDeclaration + || node.kind === SyntaxKind.ImportEqualsDeclaration + || node.kind === SyntaxKind.ExportDeclaration + || node.kind === SyntaxKind.ExportAssignment + || node.kind === SyntaxKind.NamespaceExportDeclaration + || hasSyntacticModifier(node, ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default) + ) { return false; } - return grammarErrorOnFirstToken(node, Diagnostics.Top_level_declarations_in_d_ts_files_must_start_with_either_a_declare_or_export_modifier); + return grammarErrorOnFirstToken( + node, + Diagnostics.Top_level_declarations_in_d_ts_files_must_start_with_either_a_declare_or_export_modifier, + ); } function checkGrammarTopLevelElementsForRequiredDeclareModifier(file: SourceFile): boolean { @@ -48957,8 +63129,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.flags & NodeFlags.Ambient) { // Find containing block which is either Block, ModuleBlock, SourceFile const links = getNodeLinks(node); - if (!links.hasReportedStatementInAmbientContext && (isFunctionLike(node.parent) || isAccessor(node.parent))) { - return getNodeLinks(node).hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); + if ( + !links.hasReportedStatementInAmbientContext && (isFunctionLike(node.parent) || isAccessor(node.parent)) + ) { + return getNodeLinks(node).hasReportedStatementInAmbientContext = grammarErrorOnFirstToken( + node, + Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts, + ); } // We are either parented by another statement, or some sort of block. @@ -48966,11 +63143,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // to prevent noisiness. So use a bit on the block to indicate if // this has already been reported, and don't report if it has. // - if (node.parent.kind === SyntaxKind.Block || node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + if ( + node.parent.kind === SyntaxKind.Block || node.parent.kind === SyntaxKind.ModuleBlock + || node.parent.kind === SyntaxKind.SourceFile + ) { const links = getNodeLinks(node.parent); // Check if the containing block ever report this error if (!links.hasReportedStatementInAmbientContext) { - return links.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken(node, Diagnostics.Statements_are_not_allowed_in_ambient_contexts); + return links.hasReportedStatementInAmbientContext = grammarErrorOnFirstToken( + node, + Diagnostics.Statements_are_not_allowed_in_ambient_contexts, + ); } } else { @@ -49005,15 +63188,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return; } - addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(node, Diagnostics.Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers)); + addErrorOrSuggestion( + /*isError*/ false, + createDiagnosticForNode( + node, + Diagnostics + .Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers, + ), + ); } function checkGrammarBigIntLiteral(node: BigIntLiteral): boolean { - const literalType = isLiteralTypeNode(node.parent) || - isPrefixUnaryExpression(node.parent) && isLiteralTypeNode(node.parent.parent); + const literalType = isLiteralTypeNode(node.parent) + || isPrefixUnaryExpression(node.parent) && isLiteralTypeNode(node.parent.parent); if (!literalType) { if (languageVersion < ScriptTarget.ES2020) { - if (grammarErrorOnNode(node, Diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020)) { + if ( + grammarErrorOnNode( + node, + Diagnostics.BigInt_literals_are_not_available_when_targeting_lower_than_ES2020, + ) + ) { return true; } } @@ -49021,7 +63216,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { + function grammarErrorAfterFirstToken( + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); @@ -49046,7 +63245,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarImportClause(node: ImportClause): boolean { if (node.isTypeOnly && node.name && node.namedBindings) { - return grammarErrorOnNode(node, Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both); + return grammarErrorOnNode( + node, + Diagnostics.A_type_only_import_can_specify_a_default_import_or_named_bindings_but_not_both, + ); } if (node.isTypeOnly && node.namedBindings?.kind === SyntaxKind.NamedImports) { return checkGrammarNamedImportsOrExports(node.namedBindings); @@ -49060,38 +63262,61 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnFirstToken( specifier, specifier.kind === SyntaxKind.ImportSpecifier - ? Diagnostics.The_type_modifier_cannot_be_used_on_a_named_import_when_import_type_is_used_on_its_import_statement - : Diagnostics.The_type_modifier_cannot_be_used_on_a_named_export_when_export_type_is_used_on_its_export_statement); + ? Diagnostics + .The_type_modifier_cannot_be_used_on_a_named_import_when_import_type_is_used_on_its_import_statement + : Diagnostics + .The_type_modifier_cannot_be_used_on_a_named_export_when_export_type_is_used_on_its_export_statement, + ); } }); } function checkGrammarImportCallExpression(node: ImportCall): boolean { if (compilerOptions.verbatimModuleSyntax && moduleKind === ModuleKind.CommonJS) { - return grammarErrorOnNode(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + return grammarErrorOnNode( + node, + Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled, + ); } if (moduleKind === ModuleKind.ES2015) { - return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_or_nodenext); + return grammarErrorOnNode( + node, + Diagnostics + .Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_or_nodenext, + ); } if (node.typeArguments) { - return grammarErrorOnNode(node, Diagnostics.This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments); + return grammarErrorOnNode( + node, + Diagnostics + .This_use_of_import_is_invalid_import_calls_can_be_written_but_they_must_have_parentheses_and_cannot_have_type_arguments, + ); } const nodeArguments = node.arguments; - if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.NodeNext && moduleKind !== ModuleKind.Node16) { + if ( + moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.NodeNext && moduleKind !== ModuleKind.Node16 + ) { // We are allowed trailing comma after proposal-import-assertions. checkGrammarForDisallowedTrailingComma(nodeArguments); if (nodeArguments.length > 1) { const assertionArgument = nodeArguments[1]; - return grammarErrorOnNode(assertionArgument, Diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_or_nodenext); + return grammarErrorOnNode( + assertionArgument, + Diagnostics + .Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext_node16_or_nodenext, + ); } } if (nodeArguments.length === 0 || nodeArguments.length > 2) { - return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments); + return grammarErrorOnNode( + node, + Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments, + ); } // see: parseArgumentOrArrayLiteralElement...we use this function which parse arguments of callExpression to parse specifier for dynamic import. @@ -49105,7 +63330,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function findMatchingTypeReferenceOrTypeAliasReference(source: Type, unionTarget: UnionOrIntersectionType) { const sourceObjectFlags = getObjectFlags(source); - if (sourceObjectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous) && unionTarget.flags & TypeFlags.Union) { + if ( + sourceObjectFlags & (ObjectFlags.Reference | ObjectFlags.Anonymous) && unionTarget.flags & TypeFlags.Union + ) { return find(unionTarget.types, target => { if (target.flags & TypeFlags.Object) { const overlapObjFlags = sourceObjectFlags & getObjectFlags(target); @@ -49113,7 +63340,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return (source as TypeReference).target === (target as TypeReference).target; } if (overlapObjFlags & ObjectFlags.Anonymous) { - return !!(source as AnonymousType).aliasSymbol && (source as AnonymousType).aliasSymbol === (target as AnonymousType).aliasSymbol; + return !!(source as AnonymousType).aliasSymbol + && (source as AnonymousType).aliasSymbol === (target as AnonymousType).aliasSymbol; } } return false; @@ -49129,8 +63357,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function findBestTypeForInvokable(source: Type, unionTarget: UnionOrIntersectionType) { let signatureKind = SignatureKind.Call; - const hasSignatures = getSignaturesOfType(source, signatureKind).length > 0 || - (signatureKind = SignatureKind.Construct, getSignaturesOfType(source, signatureKind).length > 0); + const hasSignatures = getSignaturesOfType(source, signatureKind).length > 0 + || (signatureKind = SignatureKind.Construct, getSignaturesOfType(source, signatureKind).length > 0); if (hasSignatures) { return find(unionTarget.types, t => getSignaturesOfType(t, signatureKind).length > 0); } @@ -49151,7 +63379,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We only want to account for literal types otherwise. // If we have a union of index types, it seems likely that we // needed to elaborate between two generic mapped types anyway. - const len = overlap.flags & TypeFlags.Union ? countWhere((overlap as UnionType).types, isUnitType) : 1; + const len = overlap.flags & TypeFlags.Union + ? countWhere((overlap as UnionType).types, isUnitType) : 1; if (len >= matchingCount) { bestMatch = target; matchingCount = len; @@ -49174,7 +63403,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly - function findMatchingDiscriminantType(source: Type, target: Type, isRelatedTo: (source: Type, target: Type) => Ternary) { + function findMatchingDiscriminantType( + source: Type, + target: Type, + isRelatedTo: (source: Type, target: Type) => Ternary, + ) { if (target.flags & TypeFlags.Union && source.flags & (TypeFlags.Intersection | TypeFlags.Object)) { const match = getMatchingUnionConstituentForType(target as UnionType, source); if (match) { @@ -49184,7 +63417,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sourceProperties) { const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target); if (sourcePropertiesFiltered) { - const discriminated = discriminateTypeByDiscriminableItems(target as UnionType, map(sourcePropertiesFiltered, p => ([() => getTypeOfSymbol(p), p.escapedName] as [() => Type, __String])), isRelatedTo); + const discriminated = discriminateTypeByDiscriminableItems( + target as UnionType, + map( + sourcePropertiesFiltered, + p => ([() => getTypeOfSymbol(p), p.escapedName] as [() => Type, __String]), + ), + isRelatedTo, + ); if (discriminated !== target) { return discriminated; } @@ -49196,8 +63436,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getEffectivePropertyNameForPropertyNameNode(node: PropertyName) { const name = getPropertyNameForPropertyNameNode(node); - return name ? name : - isComputedPropertyName(node) && isEntityNameExpression(node.expression) ? tryGetNameFromEntityNameExpression(node.expression) : undefined; + return name ? name + : isComputedPropertyName(node) && isEntityNameExpression(node.expression) + ? tryGetNameFromEntityNameExpression(node.expression) : undefined; } function getCombinedModifierFlagsCached(node: Declaration) { @@ -49223,9 +63464,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function isVarConstLike(node: VariableDeclaration | VariableDeclarationList) { const blockScopeKind = getCombinedNodeFlagsCached(node) & NodeFlags.BlockScoped; - return blockScopeKind === NodeFlags.Const || - blockScopeKind === NodeFlags.Using || - blockScopeKind === NodeFlags.AwaitUsing; + return blockScopeKind === NodeFlags.Const + || blockScopeKind === NodeFlags.Using + || blockScopeKind === NodeFlags.AwaitUsing; } } @@ -49235,8 +63476,8 @@ function isNotAccessor(declaration: Declaration): boolean { } function isNotOverload(declaration: Declaration): boolean { - return (declaration.kind !== SyntaxKind.FunctionDeclaration && declaration.kind !== SyntaxKind.MethodDeclaration) || - !!(declaration as FunctionDeclaration).body; + return (declaration.kind !== SyntaxKind.FunctionDeclaration && declaration.kind !== SyntaxKind.MethodDeclaration) + || !!(declaration as FunctionDeclaration).body; } /** Like 'isDeclarationName', but returns true for LHS of `import { x as y }` or `export { x as y }`. */ @@ -49265,9 +63506,12 @@ namespace JsxNames { function getIterationTypesKeyFromIterationTypeKind(typeKind: IterationTypeKind) { switch (typeKind) { - case IterationTypeKind.Yield: return "yieldType"; - case IterationTypeKind.Return: return "returnType"; - case IterationTypeKind.Next: return "nextType"; + case IterationTypeKind.Yield: + return "yieldType"; + case IterationTypeKind.Return: + return "returnType"; + case IterationTypeKind.Next: + return "nextType"; } } @@ -49281,9 +63525,12 @@ export function signatureHasLiteralTypes(s: Signature) { return !!(s.flags & SignatureFlags.HasLiteralTypes); } -function createBasicNodeBuilderModuleSpecifierResolutionHost(host: TypeCheckerHost): ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string } { +function createBasicNodeBuilderModuleSpecifierResolutionHost( + host: TypeCheckerHost, +): ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string; } { return { - getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "", + getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory + ? () => (host as Program).getCommonSourceDirectory() : () => "", getCurrentDirectory: () => host.getCurrentDirectory(), getSymlinkCache: maybeBind(host, host.getSymlinkCache), getPackageJsonInfoCache: () => host.getPackageJsonInfoCache?.(), @@ -49320,14 +63567,18 @@ interface NodeBuilderContext { } class SymbolTrackerImpl implements SymbolTracker { - moduleResolverHost: ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string } | undefined = undefined; + moduleResolverHost: ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string; } | undefined = undefined; context: NodeBuilderContext; readonly inner: SymbolTracker | undefined = undefined; readonly canTrackSymbol: boolean; disableTrackSymbol = false; - constructor(context: NodeBuilderContext, tracker: SymbolTracker | undefined, moduleResolverHost: ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string } | undefined) { + constructor( + context: NodeBuilderContext, + tracker: SymbolTracker | undefined, + moduleResolverHost: ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string; } | undefined, + ) { while (tracker instanceof SymbolTrackerImpl) { tracker = tracker.inner; } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 4004f0260ee8f..2965bde2d19fd 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -138,7 +138,9 @@ const jsxOptionMap = new Map(Object.entries({ })); /** @internal */ -export const inverseJsxOptionMap = new Map(mapIterator(jsxOptionMap.entries(), ([key, value]: [string, JsxEmit]) => ["" + value, key] as const)); +export const inverseJsxOptionMap = new Map( + mapIterator(jsxOptionMap.entries(), ([key, value]: [string, JsxEmit]) => ["" + value, key] as const), +); // NOTE: The order here is important to default lib ordering as entries will have the same // order in the generated program (see `getDefaultLibPriority` in program.ts). This @@ -272,7 +274,8 @@ export const optionsForWatch: CommandLineOption[] = [ fixedchunksizepolling: WatchDirectoryKind.FixedChunkSizePolling, })), category: Diagnostics.Watch_and_Build_Modes, - description: Diagnostics.Specify_how_directories_are_watched_on_systems_that_lack_recursive_file_watching_functionality, + description: + Diagnostics.Specify_how_directories_are_watched_on_systems_that_lack_recursive_file_watching_functionality, defaultValueDescription: WatchDirectoryKind.UseFsEvents, }, { @@ -284,14 +287,16 @@ export const optionsForWatch: CommandLineOption[] = [ fixedchunksize: PollingWatchKind.FixedChunkSize, })), category: Diagnostics.Watch_and_Build_Modes, - description: Diagnostics.Specify_what_approach_the_watcher_should_use_if_the_system_runs_out_of_native_file_watchers, + description: + Diagnostics.Specify_what_approach_the_watcher_should_use_if_the_system_runs_out_of_native_file_watchers, defaultValueDescription: PollingWatchKind.PriorityInterval, }, { name: "synchronousWatchDirectory", type: "boolean", category: Diagnostics.Watch_and_Build_Modes, - description: Diagnostics.Synchronously_call_callbacks_and_update_the_state_of_directory_watchers_on_platforms_that_don_t_support_recursive_watching_natively, + description: Diagnostics + .Synchronously_call_callbacks_and_update_the_state_of_directory_watchers_on_platforms_that_don_t_support_recursive_watching_natively, defaultValueDescription: false, }, { @@ -301,7 +306,7 @@ export const optionsForWatch: CommandLineOption[] = [ name: "excludeDirectory", type: "string", isFilePath: true, - extraValidation: specToDiagnostic + extraValidation: specToDiagnostic, }, category: Diagnostics.Watch_and_Build_Modes, description: Diagnostics.Remove_a_list_of_directories_from_the_watch_process, @@ -313,7 +318,7 @@ export const optionsForWatch: CommandLineOption[] = [ name: "excludeFile", type: "string", isFilePath: true, - extraValidation: specToDiagnostic + extraValidation: specToDiagnostic, }, category: Diagnostics.Watch_and_Build_Modes, description: Diagnostics.Remove_a_list_of_files_from_the_watch_mode_s_processing, @@ -384,7 +389,8 @@ export const commonOptionsWithBuild: CommandLineOption[] = [ type: "boolean", showInSimplifiedHelpView: true, category: Diagnostics.Output_Formatting, - description: Diagnostics.Enable_color_and_formatting_in_TypeScript_s_output_to_make_compiler_errors_easier_to_read, + description: + Diagnostics.Enable_color_and_formatting_in_TypeScript_s_output_to_make_compiler_errors_easier_to_read, defaultValueDescription: true, }, { @@ -415,7 +421,7 @@ export const commonOptionsWithBuild: CommandLineOption[] = [ paramType: Diagnostics.FILE_OR_DIRECTORY, category: Diagnostics.Compiler_Diagnostics, description: Diagnostics.Emit_a_v8_CPU_profile_of_the_compiler_run_for_debugging, - defaultValueDescription: "profile.cpuprofile" + defaultValueDescription: "profile.cpuprofile", }, { name: "generateTrace", @@ -424,7 +430,7 @@ export const commonOptionsWithBuild: CommandLineOption[] = [ isCommandLineOnly: true, paramType: Diagnostics.DIRECTORY, category: Diagnostics.Compiler_Diagnostics, - description: Diagnostics.Generates_an_event_trace_and_a_list_of_types + description: Diagnostics.Generates_an_event_trace_and_a_list_of_types, }, { name: "incremental", @@ -433,7 +439,7 @@ export const commonOptionsWithBuild: CommandLineOption[] = [ category: Diagnostics.Projects, description: Diagnostics.Save_tsbuildinfo_files_to_allow_for_incremental_compilation_of_projects, transpileOptionValue: undefined, - defaultValueDescription: Diagnostics.false_unless_composite_is_set + defaultValueDescription: Diagnostics.false_unless_composite_is_set, }, { name: "declaration", @@ -456,7 +462,7 @@ export const commonOptionsWithBuild: CommandLineOption[] = [ category: Diagnostics.Emit, transpileOptionValue: undefined, defaultValueDescription: false, - description: Diagnostics.Create_sourcemaps_for_d_ts_files + description: Diagnostics.Create_sourcemaps_for_d_ts_files, }, { name: "emitDeclarationOnly", @@ -495,7 +501,8 @@ export const commonOptionsWithBuild: CommandLineOption[] = [ affectsEmit: true, affectsBuildInfo: true, category: Diagnostics.Watch_and_Build_Modes, - description: Diagnostics.Have_recompiles_in_projects_that_use_incremental_and_watch_mode_assume_that_changes_within_a_file_will_only_affect_files_directly_depending_on_it, + description: Diagnostics + .Have_recompiles_in_projects_that_use_incremental_and_watch_mode_assume_that_changes_within_a_file_will_only_affect_files_directly_depending_on_it, defaultValueDescription: false, }, { @@ -504,7 +511,7 @@ export const commonOptionsWithBuild: CommandLineOption[] = [ category: Diagnostics.Command_line_Options, isCommandLineOnly: true, description: Diagnostics.Set_the_language_of_the_messaging_from_TypeScript_This_does_not_affect_emit, - defaultValueDescription: Diagnostics.Platform_specific + defaultValueDescription: Diagnostics.Platform_specific, }, ]; @@ -533,7 +540,8 @@ export const targetOptionDeclaration: CommandLineOptionOfCustomType = { paramType: Diagnostics.VERSION, showInSimplifiedHelpView: true, category: Diagnostics.Language_and_Environment, - description: Diagnostics.Set_the_JavaScript_language_version_for_emitted_JavaScript_and_include_compatible_library_declarations, + description: Diagnostics + .Set_the_JavaScript_language_version_for_emitted_JavaScript_and_include_compatible_library_declarations, defaultValueDescription: ScriptTarget.ES5, }; @@ -600,7 +608,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ showInSimplifiedHelpView: true, category: Diagnostics.Command_line_Options, paramType: Diagnostics.FILE_OR_DIRECTORY, - description: Diagnostics.Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json, + description: Diagnostics + .Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json, }, { name: "build", @@ -643,8 +652,9 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsProgramStructure: true, showInSimplifiedHelpView: true, category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_a_set_of_bundled_library_declaration_files_that_describe_the_target_runtime_environment, - transpileOptionValue: undefined + description: + Diagnostics.Specify_a_set_of_bundled_library_declaration_files_that_describe_the_target_runtime_environment, + transpileOptionValue: undefined, }, { name: "allowJs", @@ -652,7 +662,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsModuleResolution: true, showInSimplifiedHelpView: true, category: Diagnostics.JavaScript_Support, - description: Diagnostics.Allow_JavaScript_files_to_be_a_part_of_your_program_Use_the_checkJS_option_to_get_errors_from_these_files, + description: Diagnostics + .Allow_JavaScript_files_to_be_a_part_of_your_program_Use_the_checkJS_option_to_get_errors_from_these_files, defaultValueDescription: false, }, { @@ -687,7 +698,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ paramType: Diagnostics.FILE, showInSimplifiedHelpView: true, category: Diagnostics.Emit, - description: Diagnostics.Specify_a_file_that_bundles_all_outputs_into_one_JavaScript_file_If_declaration_is_true_also_designates_a_file_that_bundles_all_d_ts_output, + description: Diagnostics + .Specify_a_file_that_bundles_all_outputs_into_one_JavaScript_file_If_declaration_is_true_also_designates_a_file_that_bundles_all_d_ts_output, transpileOptionValue: undefined, }, { @@ -712,7 +724,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ paramType: Diagnostics.LOCATION, category: Diagnostics.Modules, description: Diagnostics.Specify_the_root_folder_within_your_source_files, - defaultValueDescription: Diagnostics.Computed_from_the_list_of_input_files + defaultValueDescription: Diagnostics.Computed_from_the_list_of_input_files, }, { name: "composite", @@ -762,7 +774,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsEmit: true, affectsBuildInfo: true, category: Diagnostics.Emit, - description: Diagnostics.Allow_importing_helper_functions_from_tslib_once_per_project_instead_of_including_them_per_file, + description: + Diagnostics.Allow_importing_helper_functions_from_tslib_once_per_project_instead_of_including_them_per_file, defaultValueDescription: false, }, { @@ -800,7 +813,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ name: "verbatimModuleSyntax", type: "boolean", category: Diagnostics.Interop_Constraints, - description: Diagnostics.Do_not_transform_or_elide_any_imports_or_exports_not_marked_as_type_only_ensuring_they_are_written_in_the_output_file_s_format_based_on_the_module_setting, + description: Diagnostics + .Do_not_transform_or_elide_any_imports_or_exports_not_marked_as_type_only_ensuring_they_are_written_in_the_output_file_s_format_based_on_the_module_setting, defaultValueDescription: false, }, @@ -826,7 +840,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ strictFlag: true, category: Diagnostics.Type_Checking, description: Diagnostics.Enable_error_reporting_for_expressions_and_declarations_with_an_implied_any_type, - defaultValueDescription: Diagnostics.false_unless_strict_is_set + defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, { name: "strictNullChecks", @@ -836,7 +850,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ strictFlag: true, category: Diagnostics.Type_Checking, description: Diagnostics.When_type_checking_take_into_account_null_and_undefined, - defaultValueDescription: Diagnostics.false_unless_strict_is_set + defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, { name: "strictFunctionTypes", @@ -845,8 +859,9 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsBuildInfo: true, strictFlag: true, category: Diagnostics.Type_Checking, - description: Diagnostics.When_assigning_functions_check_to_ensure_parameters_and_the_return_values_are_subtype_compatible, - defaultValueDescription: Diagnostics.false_unless_strict_is_set + description: Diagnostics + .When_assigning_functions_check_to_ensure_parameters_and_the_return_values_are_subtype_compatible, + defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, { name: "strictBindCallApply", @@ -856,7 +871,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ strictFlag: true, category: Diagnostics.Type_Checking, description: Diagnostics.Check_that_the_arguments_for_bind_call_and_apply_methods_match_the_original_function, - defaultValueDescription: Diagnostics.false_unless_strict_is_set + defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, { name: "strictPropertyInitialization", @@ -866,7 +881,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ strictFlag: true, category: Diagnostics.Type_Checking, description: Diagnostics.Check_for_class_properties_that_are_declared_but_not_set_in_the_constructor, - defaultValueDescription: Diagnostics.false_unless_strict_is_set + defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, { name: "noImplicitThis", @@ -876,7 +891,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ strictFlag: true, category: Diagnostics.Type_Checking, description: Diagnostics.Enable_error_reporting_when_this_is_given_the_type_any, - defaultValueDescription: Diagnostics.false_unless_strict_is_set + defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, { name: "useUnknownInCatchVariables", @@ -897,7 +912,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ strictFlag: true, category: Diagnostics.Type_Checking, description: Diagnostics.Ensure_use_strict_is_always_emitted, - defaultValueDescription: Diagnostics.false_unless_strict_is_set + defaultValueDescription: Diagnostics.false_unless_strict_is_set, }, // Additional Checks @@ -993,7 +1008,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ paramType: Diagnostics.STRATEGY, category: Diagnostics.Modules, description: Diagnostics.Specify_how_TypeScript_looks_up_a_file_from_a_given_module_specifier, - defaultValueDescription: Diagnostics.module_AMD_or_UMD_or_System_or_ES6_then_Classic_Otherwise_Node + defaultValueDescription: Diagnostics.module_AMD_or_UMD_or_System_or_ES6_then_Classic_Otherwise_Node, }, { name: "baseUrl", @@ -1001,7 +1016,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsModuleResolution: true, isFilePath: true, category: Diagnostics.Modules, - description: Diagnostics.Specify_the_base_directory_to_resolve_non_relative_module_names + description: Diagnostics.Specify_the_base_directory_to_resolve_non_relative_module_names, }, { // this option can only be specified in tsconfig.json @@ -1012,7 +1027,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ isTSConfigOnly: true, category: Diagnostics.Modules, description: Diagnostics.Specify_a_set_of_entries_that_re_map_imports_to_additional_lookup_locations, - transpileOptionValue: undefined + transpileOptionValue: undefined, }, { // this option can only be specified in tsconfig.json @@ -1023,13 +1038,13 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ element: { name: "rootDirs", type: "string", - isFilePath: true + isFilePath: true, }, affectsModuleResolution: true, category: Diagnostics.Modules, description: Diagnostics.Allow_multiple_folders_to_be_treated_as_one_when_resolving_modules, transpileOptionValue: undefined, - defaultValueDescription: Diagnostics.Computed_from_the_list_of_input_files + defaultValueDescription: Diagnostics.Computed_from_the_list_of_input_files, }, { name: "typeRoots", @@ -1037,24 +1052,24 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ element: { name: "typeRoots", type: "string", - isFilePath: true + isFilePath: true, }, affectsModuleResolution: true, category: Diagnostics.Modules, - description: Diagnostics.Specify_multiple_folders_that_act_like_Slashnode_modules_Slash_types + description: Diagnostics.Specify_multiple_folders_that_act_like_Slashnode_modules_Slash_types, }, { name: "types", type: "list", element: { name: "types", - type: "string" + type: "string", }, affectsProgramStructure: true, showInSimplifiedHelpView: true, category: Diagnostics.Modules, description: Diagnostics.Specify_type_package_names_to_be_included_without_being_referenced_in_a_source_file, - transpileOptionValue: undefined + transpileOptionValue: undefined, }, { name: "allowSyntheticDefaultImports", @@ -1063,7 +1078,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsBuildInfo: true, category: Diagnostics.Interop_Constraints, description: Diagnostics.Allow_import_x_from_y_when_a_module_doesn_t_have_a_default_export, - defaultValueDescription: Diagnostics.module_system_or_esModuleInterop + defaultValueDescription: Diagnostics.module_system_or_esModuleInterop, }, { name: "esModuleInterop", @@ -1073,7 +1088,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsBuildInfo: true, showInSimplifiedHelpView: true, category: Diagnostics.Interop_Constraints, - description: Diagnostics.Emit_additional_JavaScript_to_ease_support_for_importing_CommonJS_modules_This_enables_allowSyntheticDefaultImports_for_type_compatibility, + description: Diagnostics + .Emit_additional_JavaScript_to_ease_support_for_importing_CommonJS_modules_This_enables_allowSyntheticDefaultImports_for_type_compatibility, defaultValueDescription: false, }, { @@ -1110,7 +1126,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsSemanticDiagnostics: true, affectsBuildInfo: true, category: Diagnostics.Modules, - description: Diagnostics.Allow_imports_to_include_TypeScript_file_extensions_Requires_moduleResolution_bundler_and_either_noEmit_or_emitDeclarationOnly_to_be_set, + description: Diagnostics + .Allow_imports_to_include_TypeScript_file_extensions_Requires_moduleResolution_bundler_and_either_noEmit_or_emitDeclarationOnly_to_be_set, defaultValueDescription: false, transpileOptionValue: undefined, }, @@ -1159,7 +1176,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsBuildInfo: true, paramType: Diagnostics.LOCATION, category: Diagnostics.Emit, - description: Diagnostics.Specify_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, + description: + Diagnostics.Specify_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, }, { name: "inlineSources", @@ -1198,14 +1216,16 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ name: "jsxFactory", type: "string", category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_the_JSX_factory_function_used_when_targeting_React_JSX_emit_e_g_React_createElement_or_h, - defaultValueDescription: "`React.createElement`" + description: Diagnostics + .Specify_the_JSX_factory_function_used_when_targeting_React_JSX_emit_e_g_React_createElement_or_h, + defaultValueDescription: "`React.createElement`", }, { name: "jsxFragmentFactory", type: "string", category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_the_JSX_Fragment_reference_used_for_fragments_when_targeting_React_JSX_emit_e_g_React_Fragment_or_Fragment, + description: Diagnostics + .Specify_the_JSX_Fragment_reference_used_for_fragments_when_targeting_React_JSX_emit_e_g_React_Fragment_or_Fragment, defaultValueDescription: "React.Fragment", }, { @@ -1216,8 +1236,9 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsBuildInfo: true, affectsModuleResolution: true, category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_module_specifier_used_to_import_the_JSX_factory_functions_when_using_jsx_Colon_react_jsx_Asterisk, - defaultValueDescription: "react" + description: Diagnostics + .Specify_module_specifier_used_to_import_the_JSX_factory_functions_when_using_jsx_Colon_react_jsx_Asterisk, + defaultValueDescription: "react", }, { name: "resolveJsonModule", @@ -1255,7 +1276,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsEmit: true, affectsBuildInfo: true, category: Diagnostics.Language_and_Environment, - description: Diagnostics.Specify_the_object_invoked_for_createElement_This_only_applies_when_targeting_react_JSX_emit, + description: + Diagnostics.Specify_the_object_invoked_for_createElement_This_only_applies_when_targeting_react_JSX_emit, defaultValueDescription: "`React`", }, { @@ -1272,7 +1294,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ type: "string", category: Diagnostics.Backwards_Compatibility, description: Diagnostics.No_longer_supported_In_early_versions_manually_set_the_text_encoding_for_reading_files, - defaultValueDescription: "utf8" + defaultValueDescription: "utf8", }, { name: "emitBOM", @@ -1287,14 +1309,14 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ name: "newLine", type: new Map(Object.entries({ crlf: NewLineKind.CarriageReturnLineFeed, - lf: NewLineKind.LineFeed + lf: NewLineKind.LineFeed, })), affectsEmit: true, affectsBuildInfo: true, paramType: Diagnostics.NEWLINE, category: Diagnostics.Emit, description: Diagnostics.Set_the_newline_character_for_emitting_files, - defaultValueDescription: "lf" + defaultValueDescription: "lf", }, { name: "noErrorTruncation", @@ -1321,7 +1343,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ type: "boolean", affectsModuleResolution: true, category: Diagnostics.Modules, - description: Diagnostics.Disallow_import_s_require_s_or_reference_s_from_expanding_the_number_of_files_TypeScript_should_add_to_a_project, + description: Diagnostics + .Disallow_import_s_require_s_or_reference_s_from_expanding_the_number_of_files_TypeScript_should_add_to_a_project, // We are not doing a full typecheck, we are not resolving the whole context, // so pass --noResolve to avoid reporting missing file errors. transpileOptionValue: true, @@ -1341,7 +1364,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ type: "boolean", affectsProgramStructure: true, category: Diagnostics.Editor_Support, - description: Diagnostics.Remove_the_20mb_cap_on_total_source_code_size_for_JavaScript_files_in_the_TypeScript_language_server, + description: Diagnostics + .Remove_the_20mb_cap_on_total_source_code_size_for_JavaScript_files_in_the_TypeScript_language_server, defaultValueDescription: false, }, { @@ -1349,7 +1373,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ type: "boolean", isTSConfigOnly: true, category: Diagnostics.Projects, - description: Diagnostics.Disable_preferring_source_files_instead_of_declaration_files_when_referencing_composite_projects, + description: Diagnostics + .Disable_preferring_source_files_instead_of_declaration_files_when_referencing_composite_projects, defaultValueDescription: false, }, { @@ -1477,7 +1502,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ type: "number", affectsModuleResolution: true, category: Diagnostics.JavaScript_Support, - description: Diagnostics.Specify_the_maximum_folder_depth_used_for_checking_JavaScript_files_from_node_modules_Only_applicable_with_allowJs, + description: Diagnostics + .Specify_the_maximum_folder_depth_used_for_checking_JavaScript_files_from_node_modules_Only_applicable_with_allowJs, defaultValueDescription: 0, }, { @@ -1497,7 +1523,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsBuildInfo: true, category: Diagnostics.Language_and_Environment, description: Diagnostics.Emit_ECMAScript_standard_compliant_class_fields, - defaultValueDescription: Diagnostics.true_for_ES2022_and_above_including_ESNext + defaultValueDescription: Diagnostics.true_for_ES2022_and_above_including_ESNext, }, { name: "preserveValueImports", @@ -1505,7 +1531,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsEmit: true, affectsBuildInfo: true, category: Diagnostics.Emit, - description: Diagnostics.Preserve_unused_imported_values_in_the_JavaScript_output_that_would_otherwise_be_removed, + description: + Diagnostics.Preserve_unused_imported_values_in_the_JavaScript_output_that_would_otherwise_be_removed, defaultValueDescription: false, }, @@ -1523,11 +1550,10 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ isTSConfigOnly: true, element: { name: "plugin", - type: "object" + type: "object", }, description: Diagnostics.Specify_a_list_of_language_service_plugins_to_include, category: Diagnostics.Editor_Support, - }, { name: "moduleDetection", @@ -1539,7 +1565,8 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ affectsModuleResolution: true, description: Diagnostics.Control_what_method_is_used_to_detect_module_format_JS_files, category: Diagnostics.Language_and_Environment, - defaultValueDescription: Diagnostics.auto_Colon_Treat_files_with_imports_exports_import_meta_jsx_with_jsx_Colon_react_jsx_or_esm_format_with_module_Colon_node16_as_modules, + defaultValueDescription: Diagnostics + .auto_Colon_Treat_files_with_imports_exports_import_meta_jsx_with_jsx_Colon_react_jsx_or_esm_format_with_module_Colon_node16_as_modules, }, { name: "ignoreDeprecations", @@ -1555,32 +1582,39 @@ export const optionDeclarations: CommandLineOption[] = [ ]; /** @internal */ -export const semanticDiagnosticsOptionDeclarations: readonly CommandLineOption[] = - optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics); +export const semanticDiagnosticsOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => + !!option.affectsSemanticDiagnostics +); /** @internal */ -export const affectsEmitOptionDeclarations: readonly CommandLineOption[] = - optionDeclarations.filter(option => !!option.affectsEmit); +export const affectsEmitOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => + !!option.affectsEmit +); /** @internal */ -export const affectsDeclarationPathOptionDeclarations: readonly CommandLineOption[] = - optionDeclarations.filter(option => !!option.affectsDeclarationPath); +export const affectsDeclarationPathOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter( + option => !!option.affectsDeclarationPath, +); /** @internal */ -export const moduleResolutionOptionDeclarations: readonly CommandLineOption[] = - optionDeclarations.filter(option => !!option.affectsModuleResolution); +export const moduleResolutionOptionDeclarations: readonly CommandLineOption[] = optionDeclarations.filter(option => + !!option.affectsModuleResolution +); /** @internal */ export const sourceFileAffectingCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => - !!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics); + !!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics +); /** @internal */ -export const optionsAffectingProgramStructure: readonly CommandLineOption[] = - optionDeclarations.filter(option => !!option.affectsProgramStructure); +export const optionsAffectingProgramStructure: readonly CommandLineOption[] = optionDeclarations.filter(option => + !!option.affectsProgramStructure +); /** @internal */ export const transpileOptionValueCompilerOptions: readonly CommandLineOption[] = optionDeclarations.filter(option => - hasProperty(option, "transpileOptionValue")); + hasProperty(option, "transpileOptionValue") +); // Build related options /** @internal */ @@ -1615,13 +1649,13 @@ export const optionsForBuild: CommandLineOption[] = [ description: Diagnostics.Delete_the_outputs_of_all_projects, type: "boolean", defaultValueDescription: false, - } + }, ]; /** @internal */ export const buildOpts: CommandLineOption[] = [ ...commonOptionsWithBuild, - ...optionsForBuild + ...optionsForBuild, ]; /** @internal */ @@ -1636,16 +1670,16 @@ export const typeAcquisitionDeclarations: CommandLineOption[] = [ type: "list", element: { name: "include", - type: "string" - } + type: "string", + }, }, { name: "exclude", type: "list", element: { name: "exclude", - type: "string" - } + type: "string", + }, }, { name: "disableFilenameBasedTypeAcquisition", @@ -1683,7 +1717,7 @@ export function getOptionsNameMap(): OptionsNameMap { const compilerOptionsAlternateMode: AlternateModeDiagnostics = { diagnostic: Diagnostics.Compiler_option_0_may_only_be_used_with_build, - getOptionsNameMap: getBuildOptionsNameMap + getOptionsNameMap: getBuildOptionsNameMap, }; /** @internal */ @@ -1693,7 +1727,7 @@ export const defaultInitCompilerOptions: CompilerOptions = { strict: true, esModuleInterop: true, forceConsistentCasingInFileNames: true, - skipLibCheck: true + skipLibCheck: true, }; /** @internal */ @@ -1701,9 +1735,14 @@ export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOpt return createDiagnosticForInvalidCustomType(opt, createCompilerDiagnostic); } -function createDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType, createDiagnostic: (message: DiagnosticMessage, ...args: DiagnosticArguments) => Diagnostic): Diagnostic { +function createDiagnosticForInvalidCustomType( + opt: CommandLineOptionOfCustomType, + createDiagnostic: (message: DiagnosticMessage, ...args: DiagnosticArguments) => Diagnostic, +): Diagnostic { const namesOfType = arrayFrom(opt.type.keys()); - const stringNames = (opt.deprecatedKeys ? namesOfType.filter(k => !opt.deprecatedKeys!.has(k)) : namesOfType).map(key => `'${key}'`).join(", "); + const stringNames = (opt.deprecatedKeys ? namesOfType.filter(k => !opt.deprecatedKeys!.has(k)) : namesOfType).map( + key => `'${key}'`, + ).join(", "); return createDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, stringNames); } @@ -1713,7 +1752,11 @@ export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: } /** @internal */ -export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "", errors: Diagnostic[]): string | (string | number)[] | undefined { +export function parseListTypeOption( + opt: CommandLineOptionOfListType, + value = "", + errors: Diagnostic[], +): string | (string | number)[] | undefined { value = trimString(value); if (startsWith(value, "-")) { return undefined; @@ -1734,7 +1777,10 @@ export function parseListTypeOption(opt: CommandLineOptionOfListType, value = "" case "object": return Debug.fail(`List of ${opt.element.type} is not yet supported.`); default: - return mapDefined(values, v => parseCustomTypeOption(opt.element as CommandLineOptionOfCustomType, v, errors)); + return mapDefined( + values, + v => parseCustomTypeOption(opt.element as CommandLineOptionOfCustomType, v, errors), + ); } } @@ -1761,20 +1807,37 @@ function createUnknownOptionError( sourceFile?: TsConfigSourceFile, ) { if (diagnostics.alternateMode?.getOptionsNameMap().optionsNameMap.has(unknownOption.toLowerCase())) { - return createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics.alternateMode.diagnostic, unknownOption); + return createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + node, + diagnostics.alternateMode.diagnostic, + unknownOption, + ); } const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName); - return possibleOption ? - createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : - createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption); + return possibleOption + ? createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + node, + diagnostics.unknownDidYouMeanDiagnostic, + unknownOptionErrorText || unknownOption, + possibleOption.name, + ) + : createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + node, + diagnostics.unknownOptionDiagnostic, + unknownOptionErrorText || unknownOption, + ); } /** @internal */ export function parseCommandLineWorker( diagnostics: ParseCommandLineWorkerDiagnostics, commandLine: readonly string[], - readFile?: (path: string) => string | undefined) { + readFile?: (path: string) => string | undefined, +) { const options = {} as OptionsBase; let watchOptions: WatchOptions | undefined; const fileNames: string[] = []; @@ -1785,7 +1848,7 @@ export function parseCommandLineWorker( options, watchOptions, fileNames, - errors + errors, }; function parseStrings(args: readonly string[]) { @@ -1798,14 +1861,29 @@ export function parseCommandLineWorker( } else if (s.charCodeAt(0) === CharacterCodes.minus) { const inputOptionName = s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1); - const opt = getOptionDeclarationFromName(diagnostics.getOptionsNameMap, inputOptionName, /*allowShort*/ true); + const opt = getOptionDeclarationFromName( + diagnostics.getOptionsNameMap, + inputOptionName, + /*allowShort*/ true, + ); if (opt) { i = parseOptionValue(args, i, diagnostics, opt, options, errors); } else { - const watchOpt = getOptionDeclarationFromName(watchOptionsDidYouMeanDiagnostics.getOptionsNameMap, inputOptionName, /*allowShort*/ true); + const watchOpt = getOptionDeclarationFromName( + watchOptionsDidYouMeanDiagnostics.getOptionsNameMap, + inputOptionName, + /*allowShort*/ true, + ); if (watchOpt) { - i = parseOptionValue(args, i, watchOptionsDidYouMeanDiagnostics, watchOpt, watchOptions || (watchOptions = {}), errors); + i = parseOptionValue( + args, + i, + watchOptionsDidYouMeanDiagnostics, + watchOpt, + watchOptions || (watchOptions = {}), + errors, + ); } else { errors.push(createUnknownOptionError(inputOptionName, diagnostics, s)); @@ -1839,7 +1917,9 @@ export function parseCommandLineWorker( pos++; } else { - errors.push(createCompilerDiagnostic(Diagnostics.Unterminated_quoted_string_in_response_file_0, fileName)); + errors.push( + createCompilerDiagnostic(Diagnostics.Unterminated_quoted_string_in_response_file_0, fileName), + ); } } else { @@ -1857,7 +1937,7 @@ function parseOptionValue( diagnostics: ParseCommandLineWorkerDiagnostics, opt: CommandLineOption, options: OptionsBase, - errors: Diagnostic[] + errors: Diagnostic[], ) { if (opt.isTSConfigOnly) { const optValue = args[i]; @@ -1872,18 +1952,35 @@ function parseOptionValue( } else { if (optValue === "true") i++; - errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_false_or_null_on_command_line, opt.name)); + errors.push( + createCompilerDiagnostic( + Diagnostics + .Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_false_or_null_on_command_line, + opt.name, + ), + ); } } else { - errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_null_on_command_line, opt.name)); + errors.push( + createCompilerDiagnostic( + Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file_or_set_to_null_on_command_line, + opt.name, + ), + ); if (optValue && !startsWith(optValue, "-")) i++; } } else { // Check to see if no argument was provided (e.g. "--locale" is the last command-line argument). if (!args[i] && opt.type !== "boolean") { - errors.push(createCompilerDiagnostic(diagnostics.optionTypeMismatchDiagnostic, opt.name, getCompilerOptionValueTypeString(opt))); + errors.push( + createCompilerDiagnostic( + diagnostics.optionTypeMismatchDiagnostic, + opt.name, + getCompilerOptionValueTypeString(opt), + ), + ); } if (args[i] !== "null") { @@ -1937,9 +2034,12 @@ export const compilerOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnos optionDeclarations, unknownOptionDiagnostic: Diagnostics.Unknown_compiler_option_0, unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1, - optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument + optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument, }; -export function parseCommandLine(commandLine: readonly string[], readFile?: (path: string) => string | undefined): ParsedCommandLine { +export function parseCommandLine( + commandLine: readonly string[], + readFile?: (path: string) => string | undefined, +): ParsedCommandLine { return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile); } @@ -1948,7 +2048,11 @@ export function getOptionFromName(optionName: string, allowShort?: boolean): Com return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort); } -function getOptionDeclarationFromName(getOptionNameMap: () => OptionsNameMap, optionName: string, allowShort = false): CommandLineOption | undefined { +function getOptionDeclarationFromName( + getOptionNameMap: () => OptionsNameMap, + optionName: string, + allowShort = false, +): CommandLineOption | undefined { optionName = optionName.toLowerCase(); const { optionsNameMap, shortOptionNames } = getOptionNameMap(); // Try to translate short option names to their full equivalents. @@ -1976,7 +2080,7 @@ function getBuildOptionsNameMap(): OptionsNameMap { const buildOptionsAlternateMode: AlternateModeDiagnostics = { diagnostic: Diagnostics.Compiler_option_0_may_not_be_used_with_build, - getOptionsNameMap + getOptionsNameMap, }; const buildOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { @@ -1985,14 +2089,14 @@ const buildOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { optionDeclarations: buildOpts, unknownOptionDiagnostic: Diagnostics.Unknown_build_option_0, unknownDidYouMeanDiagnostic: Diagnostics.Unknown_build_option_0_Did_you_mean_1, - optionTypeMismatchDiagnostic: Diagnostics.Build_option_0_requires_a_value_of_type_1 + optionTypeMismatchDiagnostic: Diagnostics.Build_option_0_requires_a_value_of_type_1, }; /** @internal */ export function parseBuildCommand(args: readonly string[]): ParsedBuildCommand { const { options, watchOptions, fileNames: projects, errors } = parseCommandLineWorker( buildOptionsDidYouMeanDiagnostics, - args + args, ); const buildOptions = options as BuildOptions; @@ -2072,7 +2176,7 @@ export function getParsedCommandLineOfConfigFile( /*resolutionStack*/ undefined, extraFileExtensions, extendedConfigCache, - watchOptionsToExtend + watchOptionsToExtend, ); } @@ -2080,9 +2184,13 @@ export function getParsedCommandLineOfConfigFile( * Read tsconfig.json file * @param fileName The path to the config file */ -export function readConfigFile(fileName: string, readFile: (path: string) => string | undefined): { config?: any; error?: Diagnostic } { +export function readConfigFile( + fileName: string, + readFile: (path: string) => string | undefined, +): { config?: any; error?: Diagnostic; } { const textOrDiagnostic = tryReadFile(fileName, readFile); - return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic }; + return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) + : { config: {}, error: textOrDiagnostic }; } /** @@ -2090,11 +2198,15 @@ export function readConfigFile(fileName: string, readFile: (path: string) => str * @param fileName The path to the config file * @param jsonText The text of the config file */ -export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic } { +export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic; } { const jsonSourceFile = parseJsonText(fileName, jsonText); return { - config: convertConfigFileToObject(jsonSourceFile, jsonSourceFile.parseDiagnostics, /*jsonConversionNotifier*/ undefined), - error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined + config: convertConfigFileToObject( + jsonSourceFile, + jsonSourceFile.parseDiagnostics, + /*jsonConversionNotifier*/ undefined, + ), + error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : undefined, }; } @@ -2102,9 +2214,13 @@ export function parseConfigFileTextToJson(fileName: string, jsonText: string): { * Read tsconfig.json file * @param fileName The path to the config file */ -export function readJsonConfigFile(fileName: string, readFile: (path: string) => string | undefined): TsConfigSourceFile { +export function readJsonConfigFile( + fileName: string, + readFile: (path: string) => string | undefined, +): TsConfigSourceFile { const textOrDiagnostic = tryReadFile(fileName, readFile); - return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] } as TsConfigSourceFile; + return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) + : { fileName, parseDiagnostics: [textOrDiagnostic] } as TsConfigSourceFile; } /** @internal */ @@ -2138,20 +2254,23 @@ const watchOptionsDidYouMeanDiagnostics: ParseCommandLineWorkerDiagnostics = { optionDeclarations: optionsForWatch, unknownOptionDiagnostic: Diagnostics.Unknown_watch_option_0, unknownDidYouMeanDiagnostic: Diagnostics.Unknown_watch_option_0_Did_you_mean_1, - optionTypeMismatchDiagnostic: Diagnostics.Watch_option_0_requires_a_value_of_type_1 + optionTypeMismatchDiagnostic: Diagnostics.Watch_option_0_requires_a_value_of_type_1, }; let commandLineCompilerOptionsMapCache: Map; function getCommandLineCompilerOptionsMap() { - return commandLineCompilerOptionsMapCache || (commandLineCompilerOptionsMapCache = commandLineOptionsToMap(optionDeclarations)); + return commandLineCompilerOptionsMapCache + || (commandLineCompilerOptionsMapCache = commandLineOptionsToMap(optionDeclarations)); } let commandLineWatchOptionsMapCache: Map; function getCommandLineWatchOptionsMap() { - return commandLineWatchOptionsMapCache || (commandLineWatchOptionsMapCache = commandLineOptionsToMap(optionsForWatch)); + return commandLineWatchOptionsMapCache + || (commandLineWatchOptionsMapCache = commandLineOptionsToMap(optionsForWatch)); } let commandLineTypeAcquisitionMapCache: Map; function getCommandLineTypeAcquisitionMap() { - return commandLineTypeAcquisitionMapCache || (commandLineTypeAcquisitionMapCache = commandLineOptionsToMap(typeAcquisitionDeclarations)); + return commandLineTypeAcquisitionMapCache + || (commandLineTypeAcquisitionMapCache = commandLineOptionsToMap(typeAcquisitionDeclarations)); } const extendsOptionDeclaration: CommandLineOptionOfListType = { @@ -2159,7 +2278,7 @@ const extendsOptionDeclaration: CommandLineOptionOfListType = { type: "listOrElement", element: { name: "extends", - type: "string" + type: "string", }, category: Diagnostics.File_Management, disallowNullOrUndefined: true, @@ -2180,7 +2299,7 @@ const typeAcquisitionDeclaration: TsConfigOnlyOption = { name: "typeAcquisition", type: "object", elementOptions: getCommandLineTypeAcquisitionMap(), - extraKeyDiagnostics: typeAcquisitionDidYouMeanDiagnostics + extraKeyDiagnostics: typeAcquisitionDidYouMeanDiagnostics, }; let _tsconfigRootOptions: TsConfigOnlyOption; function getTsconfigRootOptionsMap() { @@ -2198,7 +2317,7 @@ function getTsconfigRootOptionsMap() { type: "list", element: { name: "references", - type: "object" + type: "object", }, category: Diagnostics.Projects, }, @@ -2207,7 +2326,7 @@ function getTsconfigRootOptionsMap() { type: "list", element: { name: "files", - type: "string" + type: "string", }, category: Diagnostics.File_Management, }, @@ -2216,23 +2335,25 @@ function getTsconfigRootOptionsMap() { type: "list", element: { name: "include", - type: "string" + type: "string", }, category: Diagnostics.File_Management, - defaultValueDescription: Diagnostics.if_files_is_specified_otherwise_Asterisk_Asterisk_Slash_Asterisk + defaultValueDescription: + Diagnostics.if_files_is_specified_otherwise_Asterisk_Asterisk_Slash_Asterisk, }, { name: "exclude", type: "list", element: { name: "exclude", - type: "string" + type: "string", }, category: Diagnostics.File_Management, - defaultValueDescription: Diagnostics.node_modules_bower_components_jspm_packages_plus_the_value_of_outDir_if_one_is_specified + defaultValueDescription: Diagnostics + .node_modules_bower_components_jspm_packages_plus_the_value_of_outDir_if_one_is_specified, }, - compileOnSaveCommandLineOption - ]) + compileOnSaveCommandLineOption, + ]), }; } return _tsconfigRootOptions; @@ -2261,7 +2382,7 @@ function convertConfigFileToObject( sourceFile, rootExpression, Diagnostics.The_root_value_of_a_0_file_must_be_an_object, - getBaseFileName(sourceFile.fileName) === "jsconfig.json" ? "jsconfig.json" : "tsconfig.json" + getBaseFileName(sourceFile.fileName) === "jsconfig.json" ? "jsconfig.json" : "tsconfig.json", )); // Last-ditch error recovery. Somewhat useful because the JSON parser will recover from some parse errors by // synthesizing a top-level array literal expression. There's a reasonable chance the first element of that @@ -2281,7 +2402,13 @@ function convertConfigFileToObject( * Convert the json syntax tree into the json value */ export function convertToObject(sourceFile: JsonSourceFile, errors: Diagnostic[]): any { - return convertToJson(sourceFile, sourceFile.statements[0]?.expression, errors, /*returnValue*/ true, /*jsonConversionNotifier*/ undefined); + return convertToJson( + sourceFile, + sourceFile.statements[0]?.expression, + errors, + /*returnValue*/ true, + /*jsonConversionNotifier*/ undefined, + ); } /** @@ -2311,15 +2438,30 @@ export function convertToJson( const result: any = returnValue ? {} : undefined; for (const element of node.properties) { if (element.kind !== SyntaxKind.PropertyAssignment) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element, Diagnostics.Property_assignment_expected)); + errors.push( + createDiagnosticForNodeInSourceFile(sourceFile, element, Diagnostics.Property_assignment_expected), + ); continue; } if (element.questionToken) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.questionToken, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?")); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + element.questionToken, + Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, + "?", + ), + ); } if (!isDoubleQuotedString(element.name)) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, Diagnostics.String_literal_with_double_quotes_expected)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + element.name, + Diagnostics.String_literal_with_double_quotes_expected, + ), + ); } const textOfKey = isComputedNonLiteralName(element.name) ? undefined : getTextOfPropertyName(element.name); @@ -2340,7 +2482,7 @@ export function convertToJson( function convertArrayLiteralExpressionToJson( elements: NodeArray, - elementOption: CommandLineOption | undefined + elementOption: CommandLineOption | undefined, ) { if (!returnValue) { elements.forEach(element => convertPropertyValueToJson(element, elementOption)); @@ -2348,7 +2490,10 @@ export function convertToJson( } // Filter out invalid values - return filter(elements.map(element => convertPropertyValueToJson(element, elementOption)), v => v !== undefined); + return filter( + elements.map(element => convertPropertyValueToJson(element, elementOption)), + v => v !== undefined, + ); } function convertPropertyValueToJson(valueExpression: Expression, option: CommandLineOption | undefined): any { @@ -2364,7 +2509,13 @@ export function convertToJson( case SyntaxKind.StringLiteral: if (!isDoubleQuotedString(valueExpression)) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.String_literal_with_double_quotes_expected)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + valueExpression, + Diagnostics.String_literal_with_double_quotes_expected, + ), + ); } return (valueExpression as StringLiteral).text; @@ -2372,7 +2523,10 @@ export function convertToJson( return Number((valueExpression as NumericLiteral).text); case SyntaxKind.PrefixUnaryExpression: - if ((valueExpression as PrefixUnaryExpression).operator !== SyntaxKind.MinusToken || (valueExpression as PrefixUnaryExpression).operand.kind !== SyntaxKind.NumericLiteral) { + if ( + (valueExpression as PrefixUnaryExpression).operator !== SyntaxKind.MinusToken + || (valueExpression as PrefixUnaryExpression).operand.kind !== SyntaxKind.NumericLiteral + ) { break; // not valid JSON syntax } return -Number(((valueExpression as PrefixUnaryExpression).operand as NumericLiteral).text); @@ -2391,15 +2545,31 @@ export function convertToJson( case SyntaxKind.ArrayLiteralExpression: return convertArrayLiteralExpressionToJson( (valueExpression as ArrayLiteralExpression).elements, - option && (option as CommandLineOptionOfListType).element); + option && (option as CommandLineOptionOfListType).element, + ); } // Not in expected format if (option) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Compiler_option_0_requires_a_value_of_type_1, option.name, getCompilerOptionValueTypeString(option))); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + valueExpression, + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + option.name, + getCompilerOptionValueTypeString(option), + ), + ); } else { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueExpression, Diagnostics.Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + valueExpression, + Diagnostics + .Property_value_can_only_be_string_literal_numeric_literal_true_false_null_object_literal_or_array_literal, + ), + ); } return undefined; @@ -2411,11 +2581,11 @@ export function convertToJson( } function getCompilerOptionValueTypeString(option: CommandLineOption): string { - return (option.type === "listOrElement") ? - `${getCompilerOptionValueTypeString(option.element)} or Array`: - option.type === "list" ? - "Array" : - isString(option.type) ? option.type : "string"; + return (option.type === "listOrElement") + ? `${getCompilerOptionValueTypeString(option.element)} or Array` + : option.type === "list" + ? "Array" + : isString(option.type) ? option.type : "string"; } function isCompilerOptionsValue(option: CommandLineOption | undefined, value: any): value is CompilerOptionsValue { @@ -2457,7 +2627,11 @@ export interface ConvertToTSConfigHost { * * @internal */ -export function convertToTSConfig(configParseResult: ParsedCommandLine, configFileName: string, host: ConvertToTSConfigHost): TSConfig { +export function convertToTSConfig( + configParseResult: ParsedCommandLine, + configFileName: string, + host: ConvertToTSConfigHost, +): TSConfig { const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames); const files = map( filter( @@ -2467,11 +2641,18 @@ export function convertToTSConfig(configParseResult: ParsedCommandLine, configFi configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs, configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs, host, - ) + ), + ), + f => getRelativePathFromFile( + getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), + getNormalizedAbsolutePath(f, host.getCurrentDirectory()), + getCanonicalFileName, ), - f => getRelativePathFromFile(getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), getNormalizedAbsolutePath(f, host.getCurrentDirectory()), getCanonicalFileName) ); - const optionMap = serializeCompilerOptions(configParseResult.options, { configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), useCaseSensitiveFileNames: host.useCaseSensitiveFileNames }); + const optionMap = serializeCompilerOptions(configParseResult.options, { + configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), + useCaseSensitiveFileNames: host.useCaseSensitiveFileNames, + }); const watchOptionMap = configParseResult.watchOptions && serializeWatchOptions(configParseResult.watchOptions); const config = { compilerOptions: { @@ -2488,13 +2669,18 @@ export function convertToTSConfig(configParseResult: ParsedCommandLine, configFi version: undefined, }, watchOptions: watchOptionMap && optionMapToObject(watchOptionMap), - references: map(configParseResult.projectReferences, r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined })), + references: map( + configParseResult.projectReferences, + r => ({ ...r, path: r.originalPath ? r.originalPath : "", originalPath: undefined }), + ), files: length(files) ? files : undefined, ...(configParseResult.options.configFile?.configFileSpecs ? { - include: filterSameAsDefaultInclude(configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs), - exclude: configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs + include: filterSameAsDefaultInclude( + configParseResult.options.configFile.configFileSpecs.validatedIncludeSpecs, + ), + exclude: configParseResult.options.configFile.configFileSpecs.validatedExcludeSpecs, } : {}), - compileOnSave: !!configParseResult.compileOnSave ? true : undefined + compileOnSave: !!configParseResult.compileOnSave ? true : undefined, }; return config; } @@ -2513,11 +2699,24 @@ function filterSameAsDefaultInclude(specs: readonly string[] | undefined) { return specs; } -function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, excludeSpecs: readonly string[] | undefined, host: ConvertToTSConfigHost): (path: string) => boolean { +function matchesSpecs( + path: string, + includeSpecs: readonly string[] | undefined, + excludeSpecs: readonly string[] | undefined, + host: ConvertToTSConfigHost, +): (path: string) => boolean { if (!includeSpecs) return returnTrue; - const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, host.useCaseSensitiveFileNames, host.getCurrentDirectory()); - const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames); - const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames); + const patterns = getFileMatcherPatterns( + path, + excludeSpecs, + includeSpecs, + host.useCaseSensitiveFileNames, + host.getCurrentDirectory(), + ); + const excludeRe = patterns.excludePattern + && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames); + const includeRe = patterns.includeFilePattern + && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames); if (includeRe) { if (excludeRe) { return path => !(includeRe.test(path) && !excludeRe.test(path)); @@ -2530,7 +2729,9 @@ function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, return returnTrue; } -function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map | undefined { +function getCustomTypeMapOfCommandLineOption( + optionDefinition: CommandLineOption, +): Map | undefined { switch (optionDefinition.type) { case "string": case "number": @@ -2547,7 +2748,10 @@ function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption } /** @internal */ -export function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: Map): string | undefined { +export function getNameOfCompilerOptionValue( + value: CompilerOptionsValue, + customTypeMap: Map, +): string | undefined { // There is a typeMap associated with this command-line option so use it to map value back to its name return forEachEntry(customTypeMap, (mapValue, key) => { if (mapValue === value) { @@ -2559,7 +2763,7 @@ export function getNameOfCompilerOptionValue(value: CompilerOptionsValue, custom /** @internal */ export function serializeCompilerOptions( options: CompilerOptions, - pathOptions?: { configFilePath: string, useCaseSensitiveFileNames: boolean } + pathOptions?: { configFilePath: string; useCaseSensitiveFileNames: boolean; }, ): Map { return serializeOptionBaseObject(options, getOptionsNameMap(), pathOptions); } @@ -2571,7 +2775,7 @@ function serializeWatchOptions(options: WatchOptions) { function serializeOptionBaseObject( options: OptionsBase, { optionsNameMap }: OptionsNameMap, - pathOptions?: { configFilePath: string, useCaseSensitiveFileNames: boolean } + pathOptions?: { configFilePath: string; useCaseSensitiveFileNames: boolean; }, ): Map { const result = new Map(); const getCanonicalFileName = pathOptions && createGetCanonicalFileName(pathOptions.useCaseSensitiveFileNames); @@ -2580,7 +2784,11 @@ function serializeOptionBaseObject( if (hasProperty(options, name)) { // tsconfig only options cannot be specified via command line, // so we can assume that only types that can appear here string | number | boolean - if (optionsNameMap.has(name) && (optionsNameMap.get(name)!.category === Diagnostics.Command_line_Options || optionsNameMap.get(name)!.category === Diagnostics.Output_Formatting)) { + if ( + optionsNameMap.has(name) + && (optionsNameMap.get(name)!.category === Diagnostics.Command_line_Options + || optionsNameMap.get(name)!.category === Diagnostics.Output_Formatting) + ) { continue; } const value = options[name] as CompilerOptionsValue; @@ -2592,7 +2800,17 @@ function serializeOptionBaseObject( // There is no map associated with this compiler option then use the value as-is // This is the case if the value is expect to be string, number, boolean or list of string if (pathOptions && optionDefinition.isFilePath) { - result.set(name, getRelativePathFromFile(pathOptions.configFilePath, getNormalizedAbsolutePath(value as string, getDirectoryPath(pathOptions.configFilePath)), getCanonicalFileName!)); + result.set( + name, + getRelativePathFromFile( + pathOptions.configFilePath, + getNormalizedAbsolutePath( + value as string, + getDirectoryPath(pathOptions.configFilePath), + ), + getCanonicalFileName!, + ), + ); } else { result.set(name, value); @@ -2600,7 +2818,12 @@ function serializeOptionBaseObject( } else { if (optionDefinition.type === "list") { - result.set(name, (value as readonly (string | number)[]).map(element => getNameOfCompilerOptionValue(element, customTypeMap)!)); // TODO: GH#18217 + result.set( + name, + (value as readonly (string | number)[]).map(element => + getNameOfCompilerOptionValue(element, customTypeMap)! + ), + ); // TODO: GH#18217 } else { // There is a typeMap associated with this command-line option so use it to map value back to its name @@ -2671,8 +2894,16 @@ export function generateTSConfig(options: CompilerOptions, fileNames: readonly s function isAllowedOptionForOutput({ category, name, isCommandLineOnly }: CommandLineOption): boolean { // Skip options which do not have a category or have categories which are more niche - const categoriesToSkip = [Diagnostics.Command_line_Options, Diagnostics.Editor_Support, Diagnostics.Compiler_Diagnostics, Diagnostics.Backwards_Compatibility, Diagnostics.Watch_and_Build_Modes, Diagnostics.Output_Formatting]; - return !isCommandLineOnly && category !== undefined && (!categoriesToSkip.includes(category) || compilerOptionsMap.has(name)); + const categoriesToSkip = [ + Diagnostics.Command_line_Options, + Diagnostics.Editor_Support, + Diagnostics.Compiler_Diagnostics, + Diagnostics.Backwards_Compatibility, + Diagnostics.Watch_and_Build_Modes, + Diagnostics.Output_Formatting, + ]; + return !isCommandLineOnly && category !== undefined + && (!categoriesToSkip.includes(category) || compilerOptionsMap.has(name)); } function writeConfigurations() { @@ -2698,7 +2929,7 @@ export function generateTSConfig(options: CompilerOptions, fileNames: readonly s // Serialize all options and their descriptions let marginLength = 0; let seenKnownKeys = 0; - const entries: { value: string, description?: string }[] = []; + const entries: { value: string; description?: string; }[] = []; categorizedOptions.forEach((options, category) => { if (entries.length !== 0) { entries.push({ value: "" }); @@ -2707,14 +2938,18 @@ export function generateTSConfig(options: CompilerOptions, fileNames: readonly s for (const option of options) { let optionName; if (compilerOptionsMap.has(option.name)) { - optionName = `"${option.name}": ${JSON.stringify(compilerOptionsMap.get(option.name))}${(seenKnownKeys += 1) === compilerOptionsMap.size ? "" : ","}`; + optionName = `"${option.name}": ${JSON.stringify(compilerOptionsMap.get(option.name))}${ + (seenKnownKeys += 1) === compilerOptionsMap.size ? "" : "," + }`; } else { optionName = `// "${option.name}": ${JSON.stringify(getDefaultValueForOption(option))},`; } entries.push({ value: optionName, - description: `/* ${option.description && getLocaleSpecificMessage(option.description) || option.name} */` + description: `/* ${ + option.description && getLocaleSpecificMessage(option.description) || option.name + } */`, }); marginLength = Math.max(optionName.length, marginLength); } @@ -2725,12 +2960,23 @@ export function generateTSConfig(options: CompilerOptions, fileNames: readonly s const result: string[] = []; result.push(`{`); result.push(`${tab}"compilerOptions": {`); - result.push(`${tab}${tab}/* ${getLocaleSpecificMessage(Diagnostics.Visit_https_Colon_Slash_Slashaka_ms_Slashtsconfig_to_read_more_about_this_file)} */`); + result.push( + `${tab}${tab}/* ${ + getLocaleSpecificMessage( + Diagnostics.Visit_https_Colon_Slash_Slashaka_ms_Slashtsconfig_to_read_more_about_this_file, + ) + } */`, + ); result.push(""); // Print out each row, aligning all the descriptions on the same column. for (const entry of entries) { const { value, description = "" } = entry; - result.push(value && `${tab}${tab}${value}${description && (makePadding(marginLength - value.length + 2) + description)}`); + result.push( + value + && `${tab}${tab}${value}${ + description && (makePadding(marginLength - value.length + 2) + description) + }`, + ); } if (fileNames.length) { result.push(`${tab}},`); @@ -2759,7 +3005,7 @@ export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAb result[name] = convertToOptionValueWithAbsolutePaths( optionsNameMap.get(name.toLowerCase()), options[name] as CompilerOptionsValue, - toAbsolutePath + toAbsolutePath, ); } } @@ -2769,7 +3015,11 @@ export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAb return result; } -function convertToOptionValueWithAbsolutePaths(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) { +function convertToOptionValueWithAbsolutePaths( + option: CommandLineOption | undefined, + value: CompilerOptionsValue, + toAbsolutePath: (path: string) => string, +) { if (option && !isNullOrUndefined(value)) { if (option.type === "list") { const values = value as readonly string[]; @@ -2792,8 +3042,29 @@ function convertToOptionValueWithAbsolutePaths(option: CommandLineOption | undef * @param basePath A root directory to resolve relative path entries in the config * file to. e.g. outDir */ -export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map, existingWatchOptions?: WatchOptions): ParsedCommandLine { - return parseJsonConfigFileContentWorker(json, /*sourceFile*/ undefined, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); +export function parseJsonConfigFileContent( + json: any, + host: ParseConfigHost, + basePath: string, + existingOptions?: CompilerOptions, + configFileName?: string, + resolutionStack?: Path[], + extraFileExtensions?: readonly FileExtensionInfo[], + extendedConfigCache?: Map, + existingWatchOptions?: WatchOptions, +): ParsedCommandLine { + return parseJsonConfigFileContentWorker( + json, + /*sourceFile*/ undefined, + host, + basePath, + existingOptions, + existingWatchOptions, + configFileName, + resolutionStack, + extraFileExtensions, + extendedConfigCache, + ); } /** @@ -2803,9 +3074,30 @@ export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, bas * @param basePath A root directory to resolve relative path entries in the config * file to. e.g. outDir */ -export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: readonly FileExtensionInfo[], extendedConfigCache?: Map, existingWatchOptions?: WatchOptions): ParsedCommandLine { +export function parseJsonSourceFileConfigFileContent( + sourceFile: TsConfigSourceFile, + host: ParseConfigHost, + basePath: string, + existingOptions?: CompilerOptions, + configFileName?: string, + resolutionStack?: Path[], + extraFileExtensions?: readonly FileExtensionInfo[], + extendedConfigCache?: Map, + existingWatchOptions?: WatchOptions, +): ParsedCommandLine { tracing?.push(tracing.Phase.Parse, "parseJsonSourceFileConfigFileContent", { path: sourceFile.fileName }); - const result = parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, existingWatchOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache); + const result = parseJsonConfigFileContentWorker( + /*json*/ undefined, + sourceFile, + host, + basePath, + existingOptions, + existingWatchOptions, + configFileName, + resolutionStack, + extraFileExtensions, + extendedConfigCache, + ); tracing?.pop(); return result; } @@ -2849,24 +3141,35 @@ function parseJsonConfigFileContentWorker( configFileName?: string, resolutionStack: Path[] = [], extraFileExtensions: readonly FileExtensionInfo[] = [], - extendedConfigCache?: Map + extendedConfigCache?: Map, ): ParsedCommandLine { Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined)); const errors: Diagnostic[] = []; - const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors, extendedConfigCache); + const parsedConfig = parseConfig( + json, + sourceFile, + host, + basePath, + configFileName, + resolutionStack, + errors, + extendedConfigCache, + ); const { raw } = parsedConfig; const options = extend(existingOptions, parsedConfig.options || {}); - const watchOptions = existingWatchOptions && parsedConfig.watchOptions ? - extend(existingWatchOptions, parsedConfig.watchOptions) : - parsedConfig.watchOptions || existingWatchOptions; + const watchOptions = existingWatchOptions && parsedConfig.watchOptions + ? extend(existingWatchOptions, parsedConfig.watchOptions) + : parsedConfig.watchOptions || existingWatchOptions; options.configFilePath = configFileName && normalizeSlashes(configFileName); const configFileSpecs = getConfigFileSpecs(); if (sourceFile) sourceFile.configFileSpecs = configFileSpecs; setConfigFileInOptions(options, sourceFile); - const basePathForFileNames = normalizePath(configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath); + const basePathForFileNames = normalizePath( + configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath, + ); return { options, watchOptions, @@ -2879,26 +3182,43 @@ function parseJsonConfigFileContentWorker( // file map that marks whether it was a regular wildcard match (with a `*` or `?` token), // or a recursive directory. This information is used by filesystem watchers to monitor for // new entries in these paths. - wildcardDirectories: getWildcardDirectories(configFileSpecs, basePathForFileNames, host.useCaseSensitiveFileNames), + wildcardDirectories: getWildcardDirectories( + configFileSpecs, + basePathForFileNames, + host.useCaseSensitiveFileNames, + ), compileOnSave: !!raw.compileOnSave, }; function getConfigFileSpecs(): ConfigFileSpecs { - const referencesOfRaw = getPropFromRaw("references", element => typeof element === "object", "object"); + const referencesOfRaw = getPropFromRaw( + "references", + element => typeof element === "object", + "object", + ); const filesSpecs = toPropValue(getSpecsFromRaw("files")); if (filesSpecs) { - const hasZeroOrNoReferences = referencesOfRaw === "no-prop" || isArray(referencesOfRaw) && referencesOfRaw.length === 0; + const hasZeroOrNoReferences = referencesOfRaw === "no-prop" + || isArray(referencesOfRaw) && referencesOfRaw.length === 0; const hasExtends = hasProperty(raw, "extends"); if (filesSpecs.length === 0 && hasZeroOrNoReferences && !hasExtends) { if (sourceFile) { const fileName = configFileName || "tsconfig.json"; const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty; const nodeValue = forEachTsConfigPropArray(sourceFile, "files", property => property.initializer); - const error = createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, nodeValue, diagnosticMessage, fileName); + const error = createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + nodeValue, + diagnosticMessage, + fileName, + ); errors.push(error); } else { - createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json"); + createCompilerDiagnosticOnlyIfJson( + Diagnostics.The_files_list_in_config_file_0_is_empty, + configFileName || "tsconfig.json", + ); } } } @@ -2928,11 +3248,23 @@ function parseJsonConfigFileContentWorker( // file system. if (includeSpecs) { - validatedIncludeSpecs = validateSpecs(includeSpecs, errors, /*disallowTrailingRecursion*/ true, sourceFile, "include"); + validatedIncludeSpecs = validateSpecs( + includeSpecs, + errors, + /*disallowTrailingRecursion*/ true, + sourceFile, + "include", + ); } if (excludeSpecs) { - validatedExcludeSpecs = validateSpecs(excludeSpecs, errors, /*disallowTrailingRecursion*/ false, sourceFile, "exclude"); + validatedExcludeSpecs = validateSpecs( + excludeSpecs, + errors, + /*disallowTrailingRecursion*/ false, + sourceFile, + "exclude", + ); } return { @@ -2957,18 +3289,26 @@ function parseJsonConfigFileContentWorker( function getProjectReferences(basePath: string): readonly ProjectReference[] | undefined { let projectReferences: ProjectReference[] | undefined; - const referencesOfRaw = getPropFromRaw("references", element => typeof element === "object", "object"); + const referencesOfRaw = getPropFromRaw( + "references", + element => typeof element === "object", + "object", + ); if (isArray(referencesOfRaw)) { for (const ref of referencesOfRaw) { if (typeof ref.path !== "string") { - createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string"); + createCompilerDiagnosticOnlyIfJson( + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + "reference.path", + "string", + ); } else { (projectReferences || (projectReferences = [])).push({ path: getNormalizedAbsolutePath(ref.path, basePath), originalPath: ref.path, prepend: ref.prepend, - circular: ref.circular + circular: ref.circular, }); } } @@ -2985,17 +3325,31 @@ function parseJsonConfigFileContentWorker( return getPropFromRaw(prop, isString, "string"); } - function getPropFromRaw(prop: "files" | "include" | "exclude" | "references", validateElement: (value: unknown) => boolean, elementTypeName: string): PropOfRaw { + function getPropFromRaw( + prop: "files" | "include" | "exclude" | "references", + validateElement: (value: unknown) => boolean, + elementTypeName: string, + ): PropOfRaw { if (hasProperty(raw, prop) && !isNullOrUndefined(raw[prop])) { if (isArray(raw[prop])) { const result = raw[prop] as T[]; if (!sourceFile && !every(result, validateElement)) { - errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, elementTypeName)); + errors.push( + createCompilerDiagnostic( + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + prop, + elementTypeName, + ), + ); } return result; } else { - createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, prop, "Array"); + createCompilerDiagnosticOnlyIfJson( + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + prop, + "Array", + ); return "not-array"; } } @@ -3010,7 +3364,9 @@ function parseJsonConfigFileContentWorker( } function isErrorNoInputFiles(error: Diagnostic) { - return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code; + return error.code + === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2 + .code; } function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) { @@ -3018,7 +3374,8 @@ function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, configFileName || "tsconfig.json", JSON.stringify(includeSpecs || []), - JSON.stringify(excludeSpecs || [])); + JSON.stringify(excludeSpecs || []), + ); } function shouldReportNoInputFiles(fileNames: string[], canJsonReportNoInutFiles: boolean, resolutionStack?: Path[]) { @@ -3031,7 +3388,13 @@ export function canJsonReportNoInputFiles(raw: any) { } /** @internal */ -export function updateErrorForNoInputFiles(fileNames: string[], configFileName: string, configFileSpecs: ConfigFileSpecs, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean) { +export function updateErrorForNoInputFiles( + fileNames: string[], + configFileName: string, + configFileSpecs: ConfigFileSpecs, + configParseDiagnostics: Diagnostic[], + canJsonReportNoInutFiles: boolean, +) { const existingErrors = configParseDiagnostics.length; if (shouldReportNoInputFiles(fileNames, canJsonReportNoInutFiles)) { configParseDiagnostics.push(getErrorForNoInputFiles(configFileSpecs, configFileName)); @@ -3064,7 +3427,7 @@ interface ExtendsResult { exclude?: string[]; files?: string[]; compileOnSave?: boolean; - extendedSourceFiles?: Set + extendedSourceFiles?: Set; } /** * This *just* extracts options/include/exclude/files out of a config file. @@ -3078,19 +3441,24 @@ function parseConfig( configFileName: string | undefined, resolutionStack: string[], errors: Diagnostic[], - extendedConfigCache?: Map + extendedConfigCache?: Map, ): ParsedTsconfig { basePath = normalizeSlashes(basePath); const resolvedPath = getNormalizedAbsolutePath(configFileName || "", basePath); if (resolutionStack.indexOf(resolvedPath) >= 0) { - errors.push(createCompilerDiagnostic(Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, [...resolutionStack, resolvedPath].join(" -> "))); + errors.push( + createCompilerDiagnostic( + Diagnostics.Circularity_detected_while_resolving_configuration_Colon_0, + [...resolutionStack, resolvedPath].join(" -> "), + ), + ); return { raw: json || convertToObject(sourceFile!, errors) }; } - const ownConfig = json ? - parseOwnConfigOfJson(json, host, basePath, configFileName, errors) : - parseOwnConfigOfJsonSourceFile(sourceFile!, host, basePath, configFileName, errors); + const ownConfig = json + ? parseOwnConfigOfJson(json, host, basePath, configFileName, errors) + : parseOwnConfigOfJsonSourceFile(sourceFile!, host, basePath, configFileName, errors); if (ownConfig.options?.paths) { // If we end up needing to resolve relative paths from 'paths' relative to @@ -3102,7 +3470,7 @@ function parseConfig( if (ownConfig.extendedConfigPath) { // copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios. resolutionStack = resolutionStack.concat([resolvedPath]); - const result: ExtendsResult = { options:{} }; + const result: ExtendsResult = { options: {} }; if (isString(ownConfig.extendedConfigPath)) { applyExtendedConfig(result, ownConfig.extendedConfigPath); } @@ -3112,27 +3480,47 @@ function parseConfig( if (!ownConfig.raw.include && result.include) ownConfig.raw.include = result.include; if (!ownConfig.raw.exclude && result.exclude) ownConfig.raw.exclude = result.exclude; if (!ownConfig.raw.files && result.files) ownConfig.raw.files = result.files; - if (ownConfig.raw.compileOnSave === undefined && result.compileOnSave) ownConfig.raw.compileOnSave = result.compileOnSave; - if (sourceFile && result.extendedSourceFiles) sourceFile.extendedSourceFiles = arrayFrom(result.extendedSourceFiles.keys()); + if (ownConfig.raw.compileOnSave === undefined && result.compileOnSave) { + ownConfig.raw.compileOnSave = result.compileOnSave; + } + if (sourceFile && result.extendedSourceFiles) { + sourceFile.extendedSourceFiles = arrayFrom(result.extendedSourceFiles.keys()); + } ownConfig.options = assign(result.options, ownConfig.options); - ownConfig.watchOptions = ownConfig.watchOptions && result.watchOptions ? - assign(result.watchOptions, ownConfig.watchOptions) : - ownConfig.watchOptions || result.watchOptions; - } + ownConfig.watchOptions = ownConfig.watchOptions && result.watchOptions + ? assign(result.watchOptions, ownConfig.watchOptions) + : ownConfig.watchOptions || result.watchOptions; + } return ownConfig; - function applyExtendedConfig(result: ExtendsResult, extendedConfigPath: string){ - const extendedConfig = getExtendedConfig(sourceFile, extendedConfigPath, host, resolutionStack, errors, extendedConfigCache, result); + function applyExtendedConfig(result: ExtendsResult, extendedConfigPath: string) { + const extendedConfig = getExtendedConfig( + sourceFile, + extendedConfigPath, + host, + resolutionStack, + errors, + extendedConfigCache, + result, + ); if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) { const extendsRaw = extendedConfig.raw; - let relativeDifference: string | undefined ; + let relativeDifference: string | undefined; const setPropertyInResultIfNotUndefined = (propertyName: "include" | "exclude" | "files") => { if (extendsRaw[propertyName]) { - result[propertyName] = map(extendsRaw[propertyName], (path: string) => isRootedDiskPath(path) ? path : combinePaths( - relativeDifference ||= convertToRelativePath(getDirectoryPath(extendedConfigPath), basePath, createGetCanonicalFileName(host.useCaseSensitiveFileNames)), - path - )); + result[propertyName] = map( + extendsRaw[propertyName], + (path: string) => + isRootedDiskPath(path) ? path : combinePaths( + relativeDifference ||= convertToRelativePath( + getDirectoryPath(extendedConfigPath), + basePath, + createGetCanonicalFileName(host.useCaseSensitiveFileNames), + ), + path, + ), + ); } }; setPropertyInResultIfNotUndefined("include"); @@ -3142,9 +3530,9 @@ function parseConfig( result.compileOnSave = extendsRaw.compileOnSave; } assign(result.options, extendedConfig.options); - result.watchOptions = result.watchOptions && extendedConfig.watchOptions ? - assign({}, result.watchOptions, extendedConfig.watchOptions) : - result.watchOptions || extendedConfig.watchOptions; + result.watchOptions = result.watchOptions && extendedConfig.watchOptions + ? assign({}, result.watchOptions, extendedConfig.watchOptions) + : result.watchOptions || extendedConfig.watchOptions; // TODO extend type typeAcquisition } } @@ -3155,19 +3543,24 @@ function parseOwnConfigOfJson( host: ParseConfigHost, basePath: string, configFileName: string | undefined, - errors: Diagnostic[] + errors: Diagnostic[], ): ParsedTsconfig { if (hasProperty(json, "excludes")) { errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude)); } const options = convertCompilerOptionsFromJsonWorker(json.compilerOptions, basePath, errors, configFileName); - const typeAcquisition = convertTypeAcquisitionFromJsonWorker(json.typeAcquisition, basePath, errors, configFileName); + const typeAcquisition = convertTypeAcquisitionFromJsonWorker( + json.typeAcquisition, + basePath, + errors, + configFileName, + ); const watchOptions = convertWatchOptionsFromJsonWorker(json.watchOptions, basePath, errors); json.compileOnSave = convertCompileOnSaveOptionFromJson(json, basePath, errors); - const extendedConfigPath = json.extends || json.extends === "" ? - getExtendsConfigPathOrArray(json.extends, host, basePath, configFileName, errors) : - undefined; + const extendedConfigPath = json.extends || json.extends === "" + ? getExtendsConfigPathOrArray(json.extends, host, basePath, configFileName, errors) + : undefined; return { raw: json, options, watchOptions, typeAcquisition, extendedConfigPath }; } @@ -3198,22 +3591,41 @@ function getExtendsConfigPathOrArray( for (let index = 0; index < (value as unknown[]).length; index++) { const fileName = (value as unknown[])[index]; if (isString(fileName)) { - extendedConfigPath = append(extendedConfigPath, getExtendsConfigPath( - fileName, - host, - newBase, + extendedConfigPath = append( + extendedConfigPath, + getExtendsConfigPath( + fileName, + host, + newBase, + errors, + (valueExpression as ArrayLiteralExpression | undefined)?.elements[index], + sourceFile, + ), + ); + } + else { + convertJsonOption( + extendsOptionDeclaration.element, + value, + basePath, errors, + propertyAssignment, (valueExpression as ArrayLiteralExpression | undefined)?.elements[index], sourceFile, - )); - } - else { - convertJsonOption(extendsOptionDeclaration.element, value, basePath, errors, propertyAssignment, (valueExpression as ArrayLiteralExpression | undefined)?.elements[index], sourceFile); + ); } } } else { - convertJsonOption(extendsOptionDeclaration, value, basePath, errors, propertyAssignment, valueExpression, sourceFile); + convertJsonOption( + extendsOptionDeclaration, + value, + basePath, + errors, + propertyAssignment, + valueExpression, + sourceFile, + ); } return extendedConfigPath; } @@ -3223,7 +3635,7 @@ function parseOwnConfigOfJsonSourceFile( host: ParseConfigHost, basePath: string, configFileName: string | undefined, - errors: Diagnostic[] + errors: Diagnostic[], ): ParsedTsconfig { const options = getDefaultCompilerOptions(configFileName); let typeAcquisition: TypeAcquisition | undefined; @@ -3243,7 +3655,14 @@ function parseOwnConfigOfJsonSourceFile( } if (rootCompilerOptions && json && json.compilerOptions === undefined) { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, rootCompilerOptions[0], Diagnostics._0_should_be_set_inside_the_compilerOptions_object_of_the_config_json_file, getTextOfPropertyName(rootCompilerOptions[0]) as string)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + rootCompilerOptions[0], + Diagnostics._0_should_be_set_inside_the_compilerOptions_object_of_the_config_json_file, + getTextOfPropertyName(rootCompilerOptions[0]) as string, + ), + ); } return { raw: json, options, watchOptions, typeAcquisition, extendedConfigPath }; @@ -3256,13 +3675,25 @@ function parseOwnConfigOfJsonSourceFile( option: CommandLineOption | undefined, ) { // Ensure value is verified except for extends which is handled in its own way for error reporting - if (option && option !== extendsOptionDeclaration) value = convertJsonOption(option, value, basePath, errors, propertyAssignment, propertyAssignment.initializer, sourceFile); + if (option && option !== extendsOptionDeclaration) { + value = convertJsonOption( + option, + value, + basePath, + errors, + propertyAssignment, + propertyAssignment.initializer, + sourceFile, + ); + } if (parentOption?.name) { if (option) { let currentOption; if (parentOption === compilerOptionsDeclaration) currentOption = options; else if (parentOption === watchOptionsDeclaration) currentOption = watchOptions ??= {}; - else if (parentOption === typeAcquisitionDeclaration) currentOption = typeAcquisition ??= getDefaultTypeAcquisition(configFileName); + else if (parentOption === typeAcquisitionDeclaration) { + currentOption = typeAcquisition ??= getDefaultTypeAcquisition(configFileName); + } else Debug.fail("Unknown option"); currentOption[option.name] = value; } @@ -3277,19 +3708,41 @@ function parseOwnConfigOfJsonSourceFile( )); } else { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, propertyAssignment.name, parentOption.extraKeyDiagnostics.unknownOptionDiagnostic, keyText)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + propertyAssignment.name, + parentOption.extraKeyDiagnostics.unknownOptionDiagnostic, + keyText, + ), + ); } } } else if (parentOption === rootOptions) { if (option === extendsOptionDeclaration) { - extendedConfigPath = getExtendsConfigPathOrArray(value, host, basePath, configFileName, errors, propertyAssignment, propertyAssignment.initializer, sourceFile); + extendedConfigPath = getExtendsConfigPathOrArray( + value, + host, + basePath, + configFileName, + errors, + propertyAssignment, + propertyAssignment.initializer, + sourceFile, + ); } else if (!option) { if (keyText === "excludes") { - errors.push(createDiagnosticForNodeInSourceFile(sourceFile, propertyAssignment.name, Diagnostics.Unknown_option_excludes_Did_you_mean_exclude)); + errors.push( + createDiagnosticForNodeInSourceFile( + sourceFile, + propertyAssignment.name, + Diagnostics.Unknown_option_excludes_Did_you_mean_exclude, + ), + ); } - if (find(commandOptionsWithoutBuild, (opt) => opt.name === keyText)) { + if (find(commandOptionsWithoutBuild, opt => opt.name === keyText)) { rootCompilerOptions = append(rootCompilerOptions, propertyAssignment.name); } } @@ -3311,7 +3764,14 @@ function getExtendsConfigPath( if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, Extension.Json)) { extendedConfigPath = `${extendedConfigPath}.json`; if (!host.fileExists(extendedConfigPath)) { - errors.push(createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, valueExpression, Diagnostics.File_0_not_found, extendedConfig)); + errors.push( + createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + valueExpression, + Diagnostics.File_0_not_found, + extendedConfig, + ), + ); return undefined; } } @@ -3323,10 +3783,24 @@ function getExtendsConfigPath( return resolved.resolvedModule.resolvedFileName; } if (extendedConfig === "") { - errors.push(createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, valueExpression, Diagnostics.Compiler_option_0_cannot_be_given_an_empty_string, "extends")); + errors.push( + createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + valueExpression, + Diagnostics.Compiler_option_0_cannot_be_given_an_empty_string, + "extends", + ), + ); } else { - errors.push(createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, valueExpression, Diagnostics.File_0_not_found, extendedConfig)); + errors.push( + createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + valueExpression, + Diagnostics.File_0_not_found, + extendedConfig, + ), + ); } return undefined; } @@ -3343,7 +3817,7 @@ function getExtendedConfig( resolutionStack: string[], errors: Diagnostic[], extendedConfigCache: Map | undefined, - result: ExtendsResult + result: ExtendsResult, ): ParsedTsconfig | undefined { const path = host.useCaseSensitiveFileNames ? extendedConfigPath : toFileNameLowerCase(extendedConfigPath); let value: ExtendedConfigCacheEntry | undefined; @@ -3355,8 +3829,16 @@ function getExtendedConfig( else { extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path)); if (!extendedResult.parseDiagnostics.length) { - extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, getDirectoryPath(extendedConfigPath), - getBaseFileName(extendedConfigPath), resolutionStack, errors, extendedConfigCache); + extendedConfig = parseConfig( + /*json*/ undefined, + extendedResult, + host, + getDirectoryPath(extendedConfigPath), + getBaseFileName(extendedConfigPath), + resolutionStack, + errors, + extendedConfigCache, + ); } if (extendedConfigCache) { extendedConfigCache.set(path, { extendedResult, extendedConfig }); @@ -3385,13 +3867,21 @@ function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, e return typeof result === "boolean" && result; } -export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } { +export function convertCompilerOptionsFromJson( + jsonOptions: any, + basePath: string, + configFileName?: string, +): { options: CompilerOptions; errors: Diagnostic[]; } { const errors: Diagnostic[] = []; const options = convertCompilerOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName); return { options, errors }; } -export function convertTypeAcquisitionFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: TypeAcquisition, errors: Diagnostic[] } { +export function convertTypeAcquisitionFromJson( + jsonOptions: any, + basePath: string, + configFileName?: string, +): { options: TypeAcquisition; errors: Diagnostic[]; } { const errors: Diagnostic[] = []; const options = convertTypeAcquisitionFromJsonWorker(jsonOptions, basePath, errors, configFileName); return { options, errors }; @@ -3399,16 +3889,32 @@ export function convertTypeAcquisitionFromJson(jsonOptions: any, basePath: strin function getDefaultCompilerOptions(configFileName?: string) { const options: CompilerOptions = configFileName && getBaseFileName(configFileName) === "jsconfig.json" - ? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, skipLibCheck: true, noEmit: true } + ? { + allowJs: true, + maxNodeModuleJsDepth: 2, + allowSyntheticDefaultImports: true, + skipLibCheck: true, + noEmit: true, + } : {}; return options; } -function convertCompilerOptionsFromJsonWorker(jsonOptions: any, - basePath: string, errors: Diagnostic[], configFileName?: string): CompilerOptions { - +function convertCompilerOptionsFromJsonWorker( + jsonOptions: any, + basePath: string, + errors: Diagnostic[], + configFileName?: string, +): CompilerOptions { const options = getDefaultCompilerOptions(configFileName); - convertOptionsFromJson(getCommandLineCompilerOptionsMap(), jsonOptions, basePath, options, compilerOptionsDidYouMeanDiagnostics, errors); + convertOptionsFromJson( + getCommandLineCompilerOptionsMap(), + jsonOptions, + basePath, + options, + compilerOptionsDidYouMeanDiagnostics, + errors, + ); if (configFileName) { options.configFilePath = normalizeSlashes(configFileName); } @@ -3416,28 +3922,70 @@ function convertCompilerOptionsFromJsonWorker(jsonOptions: any, } function getDefaultTypeAcquisition(configFileName?: string): TypeAcquisition { - return { enable: !!configFileName && getBaseFileName(configFileName) === "jsconfig.json", include: [], exclude: [] }; + return { + enable: !!configFileName && getBaseFileName(configFileName) === "jsconfig.json", + include: [], + exclude: [], + }; } -function convertTypeAcquisitionFromJsonWorker(jsonOptions: any, - basePath: string, errors: Diagnostic[], configFileName?: string): TypeAcquisition { - +function convertTypeAcquisitionFromJsonWorker( + jsonOptions: any, + basePath: string, + errors: Diagnostic[], + configFileName?: string, +): TypeAcquisition { const options = getDefaultTypeAcquisition(configFileName); - convertOptionsFromJson(getCommandLineTypeAcquisitionMap(), jsonOptions, basePath, options, typeAcquisitionDidYouMeanDiagnostics, errors); + convertOptionsFromJson( + getCommandLineTypeAcquisitionMap(), + jsonOptions, + basePath, + options, + typeAcquisitionDidYouMeanDiagnostics, + errors, + ); return options; } -function convertWatchOptionsFromJsonWorker(jsonOptions: any, basePath: string, errors: Diagnostic[]): WatchOptions | undefined { - return convertOptionsFromJson(getCommandLineWatchOptionsMap(), jsonOptions, basePath, /*defaultOptions*/ undefined, watchOptionsDidYouMeanDiagnostics, errors); +function convertWatchOptionsFromJsonWorker( + jsonOptions: any, + basePath: string, + errors: Diagnostic[], +): WatchOptions | undefined { + return convertOptionsFromJson( + getCommandLineWatchOptionsMap(), + jsonOptions, + basePath, + /*defaultOptions*/ undefined, + watchOptionsDidYouMeanDiagnostics, + errors, + ); } -function convertOptionsFromJson(optionsNameMap: Map, jsonOptions: any, basePath: string, - defaultOptions: undefined, diagnostics: DidYouMeanOptionsDiagnostics, errors: Diagnostic[]): WatchOptions | undefined; -function convertOptionsFromJson(optionsNameMap: Map, jsonOptions: any, basePath: string, - defaultOptions: CompilerOptions | TypeAcquisition, diagnostics: DidYouMeanOptionsDiagnostics, errors: Diagnostic[]): CompilerOptions | TypeAcquisition; -function convertOptionsFromJson(optionsNameMap: Map, jsonOptions: any, basePath: string, - defaultOptions: CompilerOptions | TypeAcquisition | WatchOptions | undefined, diagnostics: DidYouMeanOptionsDiagnostics, errors: Diagnostic[]) { - +function convertOptionsFromJson( + optionsNameMap: Map, + jsonOptions: any, + basePath: string, + defaultOptions: undefined, + diagnostics: DidYouMeanOptionsDiagnostics, + errors: Diagnostic[], +): WatchOptions | undefined; +function convertOptionsFromJson( + optionsNameMap: Map, + jsonOptions: any, + basePath: string, + defaultOptions: CompilerOptions | TypeAcquisition, + diagnostics: DidYouMeanOptionsDiagnostics, + errors: Diagnostic[], +): CompilerOptions | TypeAcquisition; +function convertOptionsFromJson( + optionsNameMap: Map, + jsonOptions: any, + basePath: string, + defaultOptions: CompilerOptions | TypeAcquisition | WatchOptions | undefined, + diagnostics: DidYouMeanOptionsDiagnostics, + errors: Diagnostic[], +) { if (!jsonOptions) { return; } @@ -3445,7 +3993,12 @@ function convertOptionsFromJson(optionsNameMap: Map, for (const id in jsonOptions) { const opt = optionsNameMap.get(id); if (opt) { - (defaultOptions || (defaultOptions = {}))[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors); + (defaultOptions || (defaultOptions = {}))[opt.name] = convertJsonOption( + opt, + jsonOptions[id], + basePath, + errors, + ); } else { errors.push(createUnknownOptionError(id, diagnostics)); @@ -3454,10 +4007,15 @@ function convertOptionsFromJson(optionsNameMap: Map, return defaultOptions; } -function createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile: TsConfigSourceFile | undefined, node: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) { - return sourceFile && node ? - createDiagnosticForNodeInSourceFile(sourceFile, node, message, ...args) : - createCompilerDiagnostic(message, ...args); +function createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile: TsConfigSourceFile | undefined, + node: Node | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments +) { + return sourceFile && node + ? createDiagnosticForNodeInSourceFile(sourceFile, node, message, ...args) + : createCompilerDiagnostic(message, ...args); } /** @internal */ @@ -3471,27 +4029,73 @@ export function convertJsonOption( sourceFile?: TsConfigSourceFile, ): CompilerOptionsValue { if (opt.isCommandLineOnly) { - errors.push(createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, propertyAssignment?.name, Diagnostics.Option_0_can_only_be_specified_on_command_line, opt.name)); + errors.push( + createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + propertyAssignment?.name, + Diagnostics.Option_0_can_only_be_specified_on_command_line, + opt.name, + ), + ); return undefined; } if (isCompilerOptionsValue(opt, value)) { const optType = opt.type; if ((optType === "list") && isArray(value)) { - return convertJsonOptionOfListType(opt, value, basePath, errors, propertyAssignment, valueExpression as ArrayLiteralExpression | undefined, sourceFile); + return convertJsonOptionOfListType( + opt, + value, + basePath, + errors, + propertyAssignment, + valueExpression as ArrayLiteralExpression | undefined, + sourceFile, + ); } else if (optType === "listOrElement") { - return isArray(value) ? - convertJsonOptionOfListType(opt, value, basePath, errors, propertyAssignment, valueExpression as ArrayLiteralExpression | undefined, sourceFile) : - convertJsonOption(opt.element, value, basePath, errors, propertyAssignment, valueExpression, sourceFile); + return isArray(value) + ? convertJsonOptionOfListType( + opt, + value, + basePath, + errors, + propertyAssignment, + valueExpression as ArrayLiteralExpression | undefined, + sourceFile, + ) + : convertJsonOption( + opt.element, + value, + basePath, + errors, + propertyAssignment, + valueExpression, + sourceFile, + ); } else if (!isString(opt.type)) { - return convertJsonOptionOfCustomType(opt as CommandLineOptionOfCustomType, value as string, errors, valueExpression, sourceFile); + return convertJsonOptionOfCustomType( + opt as CommandLineOptionOfCustomType, + value as string, + errors, + valueExpression, + sourceFile, + ); } const validatedValue = validateJsonOptionValue(opt, value, errors, valueExpression, sourceFile); - return isNullOrUndefined(validatedValue) ? validatedValue : normalizeNonListOptionValue(opt, basePath, validatedValue); + return isNullOrUndefined(validatedValue) ? validatedValue + : normalizeNonListOptionValue(opt, basePath, validatedValue); } else { - errors.push(createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, valueExpression, Diagnostics.Compiler_option_0_requires_a_value_of_type_1, opt.name, getCompilerOptionValueTypeString(opt))); + errors.push( + createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + valueExpression, + Diagnostics.Compiler_option_0_requires_a_value_of_type_1, + opt.name, + getCompilerOptionValueTypeString(opt), + ), + ); } } @@ -3533,8 +4137,18 @@ function convertJsonOptionOfCustomType( return validateJsonOptionValue(opt, val, errors, valueExpression, sourceFile); } else { - errors.push(createDiagnosticForInvalidCustomType(opt, (message, ...args) => - createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, valueExpression, message, ...args))); + errors.push( + createDiagnosticForInvalidCustomType( + opt, + (message, ...args) => + createDiagnosticForNodeInSourceFileOrCompilerDiagnostic( + sourceFile, + valueExpression, + message, + ...args, + ), + ), + ); } } @@ -3547,7 +4161,19 @@ function convertJsonOptionOfListType( valueExpression: ArrayLiteralExpression | undefined, sourceFile: TsConfigSourceFile | undefined, ): any[] { - return filter(map(values, (v, index) => convertJsonOption(option.element, v, basePath, errors, propertyAssignment, valueExpression?.elements[index], sourceFile)), v => option.listPreserveFalsyValues ? true : !!v); + return filter( + map(values, (v, index) => + convertJsonOption( + option.element, + v, + basePath, + errors, + propertyAssignment, + valueExpression?.elements[index], + sourceFile, + )), + v => option.listPreserveFalsyValues ? true : !!v, + ); } /** @@ -3593,7 +4219,7 @@ export function getFileNamesFromConfigSpecs( basePath: string, options: CompilerOptions, host: ParseConfigHost, - extraFileExtensions: readonly FileExtensionInfo[] = emptyArray + extraFileExtensions: readonly FileExtensionInfo[] = emptyArray, ): string[] { basePath = normalizePath(basePath); @@ -3618,7 +4244,10 @@ export function getFileNamesFromConfigSpecs( // Rather than re-query this for each file and filespec, we query the supported extensions // once and store it on the expansion context. const supportedExtensions = getSupportedExtensions(options, extraFileExtensions); - const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions); + const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule( + options, + supportedExtensions, + ); // Literal files are always included verbatim. An "include" or "exclude" specification cannot // remove a literal file. @@ -3631,13 +4260,26 @@ export function getFileNamesFromConfigSpecs( let jsonOnlyIncludeRegexes: readonly RegExp[] | undefined; if (validatedIncludeSpecs && validatedIncludeSpecs.length > 0) { - for (const file of host.readDirectory(basePath, flatten(supportedExtensionsWithJsonIfResolveJsonModule), validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) { + for ( + const file of host.readDirectory( + basePath, + flatten(supportedExtensionsWithJsonIfResolveJsonModule), + validatedExcludeSpecs, + validatedIncludeSpecs, + /*depth*/ undefined, + ) + ) { if (fileExtensionIs(file, Extension.Json)) { // Valid only if *.json specified if (!jsonOnlyIncludeRegexes) { const includes = validatedIncludeSpecs.filter(s => endsWith(s, Extension.Json)); - const includeFilePatterns = map(getRegularExpressionsForWildcards(includes, basePath, "files"), pattern => `^${pattern}$`); - jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames)) : emptyArray; + const includeFilePatterns = map( + getRegularExpressionsForWildcards(includes, basePath, "files"), + pattern => `^${pattern}$`, + ); + jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => + getRegexFromPattern(pattern, host.useCaseSensitiveFileNames) + ) : emptyArray; } const includeIndex = findIndex(jsonOnlyIncludeRegexes, re => re.test(file)); if (includeIndex !== -1) { @@ -3654,7 +4296,15 @@ export function getFileNamesFromConfigSpecs( // This handles cases where we may encounter both .ts and // .d.ts (or .js if "allowJs" is enabled) in the same // directory when they are compilation outputs. - if (hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper)) { + if ( + hasFileWithHigherPriorityExtension( + file, + literalFileMap, + wildcardFileMap, + supportedExtensions, + keyMapper, + ) + ) { continue; } @@ -3683,7 +4333,7 @@ export function isExcludedFile( spec: ConfigFileSpecs, basePath: string, useCaseSensitiveFileNames: boolean, - currentDirectory: string + currentDirectory: string, ): boolean { const { validatedFilesSpec, validatedIncludeSpecs, validatedExcludeSpecs } = spec; if (!length(validatedIncludeSpecs) || !length(validatedExcludeSpecs)) return false; @@ -3697,7 +4347,13 @@ export function isExcludedFile( } } - return matchesExcludeWorker(pathToCheck, validatedExcludeSpecs, useCaseSensitiveFileNames, currentDirectory, basePath); + return matchesExcludeWorker( + pathToCheck, + validatedExcludeSpecs, + useCaseSensitiveFileNames, + currentDirectory, + basePath, + ); } function invalidDotDotAfterRecursiveWildcard(s: string) { @@ -3719,13 +4375,13 @@ export function matchesExclude( pathToCheck: string, excludeSpecs: readonly string[] | undefined, useCaseSensitiveFileNames: boolean, - currentDirectory: string + currentDirectory: string, ) { return matchesExcludeWorker( pathToCheck, filter(excludeSpecs, spec => !invalidDotDotAfterRecursiveWildcard(spec)), useCaseSensitiveFileNames, - currentDirectory + currentDirectory, ); } @@ -3734,16 +4390,26 @@ function matchesExcludeWorker( excludeSpecs: readonly string[] | undefined, useCaseSensitiveFileNames: boolean, currentDirectory: string, - basePath?: string + basePath?: string, ) { - const excludePattern = getRegularExpressionForWildcard(excludeSpecs, combinePaths(normalizePath(currentDirectory), basePath), "exclude"); + const excludePattern = getRegularExpressionForWildcard( + excludeSpecs, + combinePaths(normalizePath(currentDirectory), basePath), + "exclude", + ); const excludeRegex = excludePattern && getRegexFromPattern(excludePattern, useCaseSensitiveFileNames); if (!excludeRegex) return false; if (excludeRegex.test(pathToCheck)) return true; return !hasExtension(pathToCheck) && excludeRegex.test(ensureTrailingDirectorySeparator(pathToCheck)); } -function validateSpecs(specs: readonly string[], errors: Diagnostic[], disallowTrailingRecursion: boolean, jsonSourceFile: TsConfigSourceFile | undefined, specKey: string): readonly string[] { +function validateSpecs( + specs: readonly string[], + errors: Diagnostic[], + disallowTrailingRecursion: boolean, + jsonSourceFile: TsConfigSourceFile | undefined, + specKey: string, +): readonly string[] { return specs.filter(spec => { if (!isString(spec)) return false; const diag = specToDiagnostic(spec, disallowTrailingRecursion); @@ -3759,20 +4425,34 @@ function validateSpecs(specs: readonly string[], errors: Diagnostic[], disallowT } } -function specToDiagnostic(spec: CompilerOptionsValue, disallowTrailingRecursion?: boolean): [DiagnosticMessage, string] | undefined { +function specToDiagnostic( + spec: CompilerOptionsValue, + disallowTrailingRecursion?: boolean, +): [DiagnosticMessage, string] | undefined { Debug.assert(typeof spec === "string"); if (disallowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) { - return [Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; + return [ + Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + spec, + ]; } else if (invalidDotDotAfterRecursiveWildcard(spec)) { - return [Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; + return [ + Diagnostics + .File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, + spec, + ]; } } /** * Gets directories in a set of include patterns that should be watched for changes. */ -function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, path: string, useCaseSensitiveFileNames: boolean): MapLike { +function getWildcardDirectories( + { validatedIncludeSpecs: include, validatedExcludeSpecs: exclude }: ConfigFileSpecs, + path: string, + useCaseSensitiveFileNames: boolean, +): MapLike { // We watch a directory recursively if it contains a wildcard anywhere in a directory segment // of the pattern: // @@ -3824,7 +4504,10 @@ function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExclu return wildcardDirectories; } -function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: boolean): { key: string, flags: WatchDirectoryFlags } | undefined { +function getWildcardDirectoryFromSpec( + spec: string, + useCaseSensitiveFileNames: boolean, +): { key: string; flags: WatchDirectoryFlags; } | undefined { const match = wildcardDirectoryPattern.exec(spec); if (match) { // We check this with a few `indexOf` calls because 3 `indexOf`/`lastIndexOf` calls is @@ -3837,14 +4520,14 @@ function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: b return { key: useCaseSensitiveFileNames ? match[0] : toFileNameLowerCase(match[0]), flags: (questionWildcardIndex !== -1 && questionWildcardIndex < lastDirectorySeperatorIndex) - || (starWildcardIndex !== -1 && starWildcardIndex < lastDirectorySeperatorIndex) - ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None + || (starWildcardIndex !== -1 && starWildcardIndex < lastDirectorySeperatorIndex) + ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None, }; } if (isImplicitGlob(spec.substring(spec.lastIndexOf(directorySeparator) + 1))) { return { key: removeTrailingDirectorySeparator(useCaseSensitiveFileNames ? spec : toFileNameLowerCase(spec)), - flags: WatchDirectoryFlags.Recursive + flags: WatchDirectoryFlags.Recursive, }; } return undefined; @@ -3856,7 +4539,13 @@ function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: b * * @param file The path to the file. */ -function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map, wildcardFiles: Map, extensions: readonly string[][], keyMapper: (value: string) => string) { +function hasFileWithHigherPriorityExtension( + file: string, + literalFiles: Map, + wildcardFiles: Map, + extensions: readonly string[][], + keyMapper: (value: string) => string, +) { const extensionGroup = forEach(extensions, group => fileExtensionIsOneOf(file, group) ? group : undefined); if (!extensionGroup) { return false; @@ -3867,7 +4556,9 @@ function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map, extensions: readonly string[][], keyMapper: (value: string) => string) { +function removeWildcardFilesWithLowerPriorityExtension( + file: string, + wildcardFiles: Map, + extensions: readonly string[][], + keyMapper: (value: string) => string, +) { const extensionGroup = forEach(extensions, group => fileExtensionIsOneOf(file, group) ? group : undefined); if (!extensionGroup) { return; @@ -3946,7 +4642,6 @@ function getOptionValueWithEmptyStrings(value: any, option: CommandLineOption): } } - function getDefaultValueForOption(option: CommandLineOption): {} { switch (option.type) { case "number": diff --git a/src/compiler/core.ts b/src/compiler/core.ts index f5d60b0459141..e029b8427541b 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -13,7 +13,6 @@ import { TextSpan, } from "./_namespaces/ts"; - /** @internal */ export const emptyArray: never[] = [] as never[]; /** @internal */ @@ -33,7 +32,10 @@ export function length(array: readonly any[] | undefined): number { * * @internal */ -export function forEach(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { +export function forEach( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U | undefined, +): U | undefined { if (array) { for (let i = 0; i < array.length; i++) { const result = callback(array[i], i); @@ -50,7 +52,10 @@ export function forEach(array: readonly T[] | undefined, callback: (elemen * * @internal */ -export function forEachRight(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { +export function forEachRight( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U | undefined, +): U | undefined { if (array) { for (let i = array.length - 1; i >= 0; i--) { const result = callback(array[i], i); @@ -67,7 +72,10 @@ export function forEachRight(array: readonly T[] | undefined, callback: (e * * @internal */ -export function firstDefined(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined { +export function firstDefined( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U | undefined, +): U | undefined { if (array === undefined) { return undefined; } @@ -93,7 +101,11 @@ export function firstDefinedIterator(iter: Iterable, callback: (element } /** @internal */ -export function reduceLeftIterator(iterator: Iterable | undefined, f: (memo: U, value: T, i: number) => U, initial: U): U { +export function reduceLeftIterator( + iterator: Iterable | undefined, + f: (memo: U, value: T, i: number) => U, + initial: U, +): U { let result = initial; if (iterator) { let pos = 0; @@ -106,7 +118,11 @@ export function reduceLeftIterator(iterator: Iterable | undefined, f: ( } /** @internal */ -export function zipWith(arrayA: readonly T[], arrayB: readonly U[], callback: (a: T, b: U, index: number) => V): V[] { +export function zipWith( + arrayA: readonly T[], + arrayB: readonly U[], + callback: (a: T, b: U, index: number) => V, +): V[] { const result: V[] = []; Debug.assertEqual(arrayA.length, arrayB.length); for (let i = 0; i < arrayA.length; i++) { @@ -140,9 +156,15 @@ export function intersperse(input: T[], element: T): T[] { * * @internal */ -export function every(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[]; +export function every( + array: readonly T[], + callback: (element: T, index: number) => element is U, +): array is readonly U[]; /** @internal */ -export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined; +export function every( + array: readonly T[] | undefined, + callback: (element: T, index: number) => element is U, +): array is readonly U[] | undefined; /** @internal */ export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean; export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean { @@ -162,11 +184,23 @@ export function every(array: readonly T[] | undefined, callback: (element: T, * * @internal */ -export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => element is U, startIndex?: number): U | undefined; +export function find( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => element is U, + startIndex?: number, +): U | undefined; /** @internal */ -export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined; +export function find( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, +): T | undefined; /** @internal */ -export function find(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined { +export function find( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, +): T | undefined { if (array === undefined) return undefined; for (let i = startIndex ?? 0; i < array.length; i++) { const value = array[i]; @@ -178,11 +212,23 @@ export function find(array: readonly T[] | undefined, predicate: (element: T, } /** @internal */ -export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => element is U, startIndex?: number): U | undefined; +export function findLast( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => element is U, + startIndex?: number, +): U | undefined; /** @internal */ -export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined; +export function findLast( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, +): T | undefined; /** @internal */ -export function findLast(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): T | undefined { +export function findLast( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, +): T | undefined { if (array === undefined) return undefined; for (let i = startIndex ?? array.length - 1; i >= 0; i--) { const value = array[i]; @@ -198,7 +244,11 @@ export function findLast(array: readonly T[] | undefined, predicate: (element * * @internal */ -export function findIndex(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): number { +export function findIndex( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, +): number { if (array === undefined) return -1; for (let i = startIndex ?? 0; i < array.length; i++) { if (predicate(array[i], i)) { @@ -209,7 +259,11 @@ export function findIndex(array: readonly T[] | undefined, predicate: (elemen } /** @internal */ -export function findLastIndex(array: readonly T[] | undefined, predicate: (element: T, index: number) => boolean, startIndex?: number): number { +export function findLastIndex( + array: readonly T[] | undefined, + predicate: (element: T, index: number) => boolean, + startIndex?: number, +): number { if (array === undefined) return -1; for (let i = startIndex ?? array.length - 1; i >= 0; i--) { if (predicate(array[i], i)) { @@ -236,7 +290,11 @@ export function findMap(array: readonly T[], callback: (element: T, index: } /** @internal */ -export function contains(array: readonly T[] | undefined, value: T, equalityComparer: EqualityComparer = equateValues): boolean { +export function contains( + array: readonly T[] | undefined, + value: T, + equalityComparer: EqualityComparer = equateValues, +): boolean { if (array) { for (const v of array) { if (equalityComparer(v, value)) { @@ -248,7 +306,11 @@ export function contains(array: readonly T[] | undefined, value: T, equalityC } /** @internal */ -export function arraysEqual(a: readonly T[], b: readonly T[], equalityComparer: EqualityComparer = equateValues): boolean { +export function arraysEqual( + a: readonly T[], + b: readonly T[], + equalityComparer: EqualityComparer = equateValues, +): boolean { return a.length === b.length && a.every((x, i) => equalityComparer(x, b[i])); } @@ -352,9 +414,8 @@ export function map(array: readonly T[] | undefined, f: (x: T, i: number) return result; } - /** @internal */ -export function *mapIterator(iter: Iterable, mapFn: (x: T) => U) { +export function* mapIterator(iter: Iterable, mapFn: (x: T) => U) { for (const x of iter) { yield mapFn(x); } @@ -372,7 +433,10 @@ export function sameMap(array: T[] | undefined, f: (x: T, i: number) = /** @internal */ export function sameMap(array: readonly T[] | undefined, f: (x: T, i: number) => U): readonly U[] | undefined; /** @internal */ -export function sameMap(array: readonly T[] | undefined, f: (x: T, i: number) => U): readonly U[] | undefined { +export function sameMap( + array: readonly T[] | undefined, + f: (x: T, i: number) => U, +): readonly U[] | undefined { if (array) { for (let i = 0; i < array.length; i++) { const item = array[i]; @@ -412,7 +476,6 @@ export function flatten(array: T[][] | readonly (T | readonly T[] | undefined return result; } - /** * Maps an array. If the mapped value is an array, it is spread into the result. * @@ -421,7 +484,10 @@ export function flatten(array: T[][] | readonly (T | readonly T[] | undefined * * @internal */ -export function flatMap(array: readonly T[] | undefined, mapfn: (x: T, i: number) => U | readonly U[] | undefined): readonly U[] { +export function flatMap( + array: readonly T[] | undefined, + mapfn: (x: T, i: number) => U | readonly U[] | undefined, +): readonly U[] { let result: U[] | undefined; if (array) { for (let i = 0; i < array.length; i++) { @@ -440,7 +506,10 @@ export function flatMap(array: readonly T[] | undefined, mapfn: (x: T, i: } /** @internal */ -export function flatMapToMutable(array: readonly T[] | undefined, mapfn: (x: T, i: number) => U | readonly U[] | undefined): U[] { +export function flatMapToMutable( + array: readonly T[] | undefined, + mapfn: (x: T, i: number) => U | readonly U[] | undefined, +): U[] { const result: U[] = []; if (array) { for (let i = 0; i < array.length; i++) { @@ -459,7 +528,7 @@ export function flatMapToMutable(array: readonly T[] | undefined, mapfn: ( } /** @internal */ -export function *flatMapIterator(iter: Iterable, mapfn: (x: T) => readonly U[] | Iterable | undefined) { +export function* flatMapIterator(iter: Iterable, mapfn: (x: T) => readonly U[] | Iterable | undefined) { for (const x of iter) { const iter2 = mapfn(x); if (!iter2) continue; @@ -467,7 +536,6 @@ export function *flatMapIterator(iter: Iterable, mapfn: (x: T) => reado } } - /** * Maps an array. If the mapped value is an array, it is spread into the result. * Avoids allocation if all elements map to themselves. @@ -531,7 +599,7 @@ export function mapDefined(array: readonly T[] | undefined, mapFn: (x: T, } /** @internal */ -export function *mapDefinedIterator(iter: Iterable, mapFn: (x: T) => U | undefined) { +export function* mapDefinedIterator(iter: Iterable, mapFn: (x: T) => U | undefined) { for (const x of iter) { const value = mapFn(x); if (value !== undefined) { @@ -541,11 +609,20 @@ export function *mapDefinedIterator(iter: Iterable, mapFn: (x: T) => U } /** @internal */ -export function mapDefinedEntries(map: ReadonlyMap, f: (key: K1, value: V1) => readonly [K2, V2] | undefined): Map; +export function mapDefinedEntries( + map: ReadonlyMap, + f: (key: K1, value: V1) => readonly [K2, V2] | undefined, +): Map; /** @internal */ -export function mapDefinedEntries(map: ReadonlyMap | undefined, f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined): Map | undefined; +export function mapDefinedEntries( + map: ReadonlyMap | undefined, + f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined, +): Map | undefined; /** @internal */ -export function mapDefinedEntries(map: ReadonlyMap | undefined, f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined): Map | undefined { +export function mapDefinedEntries( + map: ReadonlyMap | undefined, + f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined, +): Map | undefined { if (!map) { return undefined; } @@ -584,7 +661,7 @@ export function tryAddToSet(set: Set, value: T) { } /** @internal */ -export function *singleIterator(value: T) { +export function* singleIterator(value: T) { yield value; } @@ -597,11 +674,23 @@ export function *singleIterator(value: T) { * * @internal */ -export function spanMap(array: readonly T[], keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[]; -/** @internal */ -export function spanMap(array: readonly T[] | undefined, keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] | undefined; -/** @internal */ -export function spanMap(array: readonly T[] | undefined, keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] | undefined { +export function spanMap( + array: readonly T[], + keyfn: (x: T, i: number) => K, + mapfn: (chunk: T[], key: K, start: number, end: number) => U, +): U[]; +/** @internal */ +export function spanMap( + array: readonly T[] | undefined, + keyfn: (x: T, i: number) => K, + mapfn: (chunk: T[], key: K, start: number, end: number) => U, +): U[] | undefined; +/** @internal */ +export function spanMap( + array: readonly T[] | undefined, + keyfn: (x: T, i: number) => K, + mapfn: (chunk: T[], key: K, start: number, end: number) => U, +): U[] | undefined { let result: U[] | undefined; if (array) { result = []; @@ -642,11 +731,20 @@ export function spanMap(array: readonly T[] | undefined, keyfn: (x: T, } /** @internal */ -export function mapEntries(map: ReadonlyMap, f: (key: K1, value: V1) => readonly [K2, V2]): Map; +export function mapEntries( + map: ReadonlyMap, + f: (key: K1, value: V1) => readonly [K2, V2], +): Map; /** @internal */ -export function mapEntries(map: ReadonlyMap | undefined, f: (key: K1, value: V1) => readonly [K2, V2]): Map | undefined; +export function mapEntries( + map: ReadonlyMap | undefined, + f: (key: K1, value: V1) => readonly [K2, V2], +): Map | undefined; /** @internal */ -export function mapEntries(map: ReadonlyMap | undefined, f: (key: K1, value: V1) => readonly [K2, V2]): Map | undefined { +export function mapEntries( + map: ReadonlyMap | undefined, + f: (key: K1, value: V1) => readonly [K2, V2], +): Map | undefined { if (!map) { return undefined; } @@ -685,7 +783,11 @@ export function some(array: readonly T[] | undefined, predicate?: (value: T) * * @internal */ -export function getRangesWhere(arr: readonly T[], pred: (t: T) => boolean, cb: (start: number, afterEnd: number) => void): void { +export function getRangesWhere( + arr: readonly T[], + pred: (t: T) => boolean, + cb: (start: number, afterEnd: number) => void, +): void { let start: number | undefined; for (let i = 0; i < arr.length; i++) { if (pred(arr[i])) { @@ -716,9 +818,15 @@ export function concatenate(array1: readonly T[] | undefined, array2: readonl /** @internal */ export function concatenate(array1: T[] | undefined, array2: T[] | undefined): T[] | undefined; /** @internal */ -export function concatenate(array1: readonly T[] | undefined, array2: readonly T[] | undefined): readonly T[] | undefined; +export function concatenate( + array1: readonly T[] | undefined, + array2: readonly T[] | undefined, +): readonly T[] | undefined; /** @internal */ -export function concatenate(array1: readonly T[] | undefined, array2: readonly T[] | undefined): readonly T[] | undefined { +export function concatenate( + array1: readonly T[] | undefined, + array2: readonly T[] | undefined, +): readonly T[] | undefined { if (!some(array2)) return array1; if (!some(array1)) return array2; return [...array1, ...array2]; @@ -771,17 +879,24 @@ function deduplicateEquality(array: readonly T[], equalityComparer: EqualityC * * @internal */ -export function deduplicate(array: readonly T[], equalityComparer: EqualityComparer, comparer?: Comparer): T[] { - return array.length === 0 ? [] : - array.length === 1 ? array.slice() : - comparer ? deduplicateRelational(array, equalityComparer, comparer) : - deduplicateEquality(array, equalityComparer); +export function deduplicate( + array: readonly T[], + equalityComparer: EqualityComparer, + comparer?: Comparer, +): T[] { + return array.length === 0 ? [] + : array.length === 1 ? array.slice() + : comparer ? deduplicateRelational(array, equalityComparer, comparer) + : deduplicateEquality(array, equalityComparer); } /** * Deduplicates an array that has already been sorted. */ -function deduplicateSorted(array: SortedReadonlyArray, comparer: EqualityComparer | Comparer): SortedReadonlyArray { +function deduplicateSorted( + array: SortedReadonlyArray, + comparer: EqualityComparer | Comparer, +): SortedReadonlyArray { if (array.length === 0) return emptyArray as any as SortedReadonlyArray; let last = array[0]; @@ -814,7 +929,12 @@ export function createSortedArray(): SortedArray { } /** @internal */ -export function insertSorted(array: SortedArray, insert: T, compare: Comparer, allowDuplicates?: boolean): boolean { +export function insertSorted( + array: SortedArray, + insert: T, + compare: Comparer, + allowDuplicates?: boolean, +): boolean { if (array.length === 0) { array.push(insert); return true; @@ -837,10 +957,21 @@ export function insertSorted(array: SortedArray, insert: T, compare: Compa /** @internal */ export function sortAndDeduplicate(array: readonly string[]): SortedReadonlyArray; /** @internal */ -export function sortAndDeduplicate(array: readonly T[], comparer: Comparer, equalityComparer?: EqualityComparer): SortedReadonlyArray; +export function sortAndDeduplicate( + array: readonly T[], + comparer: Comparer, + equalityComparer?: EqualityComparer, +): SortedReadonlyArray; /** @internal */ -export function sortAndDeduplicate(array: readonly T[], comparer?: Comparer, equalityComparer?: EqualityComparer): SortedReadonlyArray { - return deduplicateSorted(sort(array, comparer), equalityComparer || comparer || compareStringsCaseSensitive as any as Comparer); +export function sortAndDeduplicate( + array: readonly T[], + comparer?: Comparer, + equalityComparer?: EqualityComparer, +): SortedReadonlyArray { + return deduplicateSorted( + sort(array, comparer), + equalityComparer || comparer || compareStringsCaseSensitive as any as Comparer, + ); } /** @internal */ @@ -887,7 +1018,11 @@ export function detectSortCaseSensitivity( } /** @internal */ -export function arrayIsEqualTo(array1: readonly T[] | undefined, array2: readonly T[] | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean { +export function arrayIsEqualTo( + array1: readonly T[] | undefined, + array2: readonly T[] | undefined, + equalityComparer: (a: T, b: T, index: number) => boolean = equateValues, +): boolean { if (!array1 || !array2) { return array1 === array2; } @@ -944,16 +1079,22 @@ export function compact(array: readonly T[]): readonly T[] { * * @internal */ -export function relativeComplement(arrayA: T[] | undefined, arrayB: T[] | undefined, comparer: Comparer): T[] | undefined { +export function relativeComplement( + arrayA: T[] | undefined, + arrayB: T[] | undefined, + comparer: Comparer, +): T[] | undefined { if (!arrayB || !arrayA || arrayB.length === 0 || arrayA.length === 0) return arrayB; const result: T[] = []; - loopB: for (let offsetA = 0, offsetB = 0; offsetB < arrayB.length; offsetB++) { + loopB: + for (let offsetA = 0, offsetB = 0; offsetB < arrayB.length; offsetB++) { if (offsetB > 0) { // Ensure `arrayB` is properly sorted. Debug.assertGreaterThanOrEqual(comparer(arrayB[offsetB], arrayB[offsetB - 1]), Comparison.EqualTo); } - loopA: for (const startA = offsetA; offsetA < arrayA.length; offsetA++) { + loopA: + for (const startA = offsetA; offsetA < arrayA.length; offsetA++) { if (offsetA > startA) { // Ensure `arrayA` is properly sorted. We only need to perform this check if // `offsetA` has changed since we entered the loop. @@ -992,7 +1133,10 @@ export function relativeComplement(arrayA: T[] | undefined, arrayB: T[] | und * * @internal */ -export function append[number] | undefined>(to: TArray, value: TValue): [undefined, undefined] extends [TArray, TValue] ? TArray : NonNullable[number][]; +export function append[number] | undefined>( + to: TArray, + value: TValue, +): [undefined, undefined] extends [TArray, TValue] ? TArray : NonNullable[number][]; /** @internal */ export function append(to: T[], value: T | undefined): T[]; /** @internal */ @@ -1025,7 +1169,10 @@ export function append(to: T[] | undefined, value: T | undefined): T[] | unde */ export function combine(xs: T[] | undefined, ys: T[] | undefined): T[] | undefined; /** @internal */ -export function combine(xs: T | readonly T[] | undefined, ys: T | readonly T[] | undefined): T | readonly T[] | undefined; +export function combine( + xs: T | readonly T[] | undefined, + ys: T | readonly T[] | undefined, +): T | readonly T[] | undefined; /** @internal */ export function combine(xs: T | T[] | undefined, ys: T | T[] | undefined): T | T[] | undefined; /** @internal */ @@ -1059,9 +1206,19 @@ function toOffset(array: readonly any[], offset: number) { */ export function addRange(to: T[], from: readonly T[] | undefined, start?: number, end?: number): T[]; /** @internal */ -export function addRange(to: T[] | undefined, from: readonly T[] | undefined, start?: number, end?: number): T[] | undefined; -/** @internal */ -export function addRange(to: T[] | undefined, from: readonly T[] | undefined, start?: number, end?: number): T[] | undefined { +export function addRange( + to: T[] | undefined, + from: readonly T[] | undefined, + start?: number, + end?: number, +): T[] | undefined; +/** @internal */ +export function addRange( + to: T[] | undefined, + from: readonly T[] | undefined, + start?: number, + end?: number, +): T[] | undefined { if (from === undefined || from.length === 0) return to; if (to === undefined) return from.slice(start, end); start = start === undefined ? 0 : toOffset(from, start); @@ -1119,7 +1276,7 @@ export function sort(array: readonly T[], comparer?: Comparer): SortedRead } /** @internal */ -export function *arrayReverseIterator(array: readonly T[]) { +export function* arrayReverseIterator(array: readonly T[]) { for (let i = array.length - 1; i >= 0; i--) { yield array[i]; } @@ -1273,7 +1430,13 @@ export function replaceElement(array: readonly T[], index: number, value: T): * * @internal */ -export function binarySearch(array: readonly T[], value: T, keySelector: (v: T) => U, keyComparer: Comparer, offset?: number): number { +export function binarySearch( + array: readonly T[], + value: T, + keySelector: (v: T) => U, + keyComparer: Comparer, + offset?: number, +): number { return binarySearchKey(array, keySelector(value), keySelector, keyComparer, offset); } @@ -1289,7 +1452,13 @@ export function binarySearch(array: readonly T[], value: T, keySelector: ( * * @internal */ -export function binarySearchKey(array: readonly T[], key: U, keySelector: (v: T, i: number) => U, keyComparer: Comparer, offset?: number): number { +export function binarySearchKey( + array: readonly T[], + key: U, + keySelector: (v: T, i: number) => U, + keyComparer: Comparer, + offset?: number, +): number { if (!some(array)) { return -1; } @@ -1315,11 +1484,23 @@ export function binarySearchKey(array: readonly T[], key: U, keySelector: } /** @internal */ -export function reduceLeft(array: readonly T[] | undefined, f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U; +export function reduceLeft( + array: readonly T[] | undefined, + f: (memo: U, value: T, i: number) => U, + initial: U, + start?: number, + count?: number, +): U; /** @internal */ export function reduceLeft(array: readonly T[], f: (memo: T, value: T, i: number) => T): T | undefined; /** @internal */ -export function reduceLeft(array: readonly T[] | undefined, f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T | undefined { +export function reduceLeft( + array: readonly T[] | undefined, + f: (memo: T, value: T, i: number) => T, + initial?: T, + start?: number, + count?: number, +): T | undefined { if (array && array.length > 0) { const size = array.length; if (size > 0) { @@ -1393,7 +1574,8 @@ export function getAllKeys(obj: object): string[] { for (const name of names) { pushIfUnique(result, name); } - } while (obj = Object.getPrototypeOf(obj)); + } + while (obj = Object.getPrototypeOf(obj)); return result; } @@ -1456,7 +1638,11 @@ export function assign(t: T, ...args: (T | undefined)[]) { * * @internal */ -export function equalOwnProperties(left: MapLike | undefined, right: MapLike | undefined, equalityComparer: EqualityComparer = equateValues) { +export function equalOwnProperties( + left: MapLike | undefined, + right: MapLike | undefined, + equalityComparer: EqualityComparer = equateValues, +) { if (left === right) return true; if (!left || !right) return false; for (const key in left) { @@ -1489,13 +1675,25 @@ export function equalOwnProperties(left: MapLike | undefined, right: MapLi */ export function arrayToMap(array: readonly V[], makeKey: (value: V) => K | undefined): Map; /** @internal */ -export function arrayToMap(array: readonly V1[], makeKey: (value: V1) => K | undefined, makeValue: (value: V1) => V2): Map; +export function arrayToMap( + array: readonly V1[], + makeKey: (value: V1) => K | undefined, + makeValue: (value: V1) => V2, +): Map; /** @internal */ export function arrayToMap(array: readonly T[], makeKey: (value: T) => string | undefined): Map; /** @internal */ -export function arrayToMap(array: readonly T[], makeKey: (value: T) => string | undefined, makeValue: (value: T) => U): Map; -/** @internal */ -export function arrayToMap(array: readonly V1[], makeKey: (value: V1) => K | undefined, makeValue: (value: V1) => V1 | V2 = identity): Map { +export function arrayToMap( + array: readonly T[], + makeKey: (value: T) => string | undefined, + makeValue: (value: T) => U, +): Map; +/** @internal */ +export function arrayToMap( + array: readonly V1[], + makeKey: (value: V1) => K | undefined, + makeValue: (value: V1) => V1 | V2 = identity, +): Map { const result = new Map(); for (const value of array) { const key = makeKey(value); @@ -1507,9 +1705,17 @@ export function arrayToMap(array: readonly V1[], makeKey: (value: V1) /** @internal */ export function arrayToNumericMap(array: readonly T[], makeKey: (value: T) => number): T[]; /** @internal */ -export function arrayToNumericMap(array: readonly T[], makeKey: (value: T) => number, makeValue: (value: T) => U): U[]; +export function arrayToNumericMap( + array: readonly T[], + makeKey: (value: T) => number, + makeValue: (value: T) => U, +): U[]; /** @internal */ -export function arrayToNumericMap(array: readonly T[], makeKey: (value: T) => number, makeValue: (value: T) => T | U = identity): (T | U)[] { +export function arrayToNumericMap( + array: readonly T[], + makeKey: (value: T) => number, + makeValue: (value: T) => T | U = identity, +): (T | U)[] { const result: (T | U)[] = []; for (const value of array) { result[makeKey(value)] = makeValue(value); @@ -1520,9 +1726,17 @@ export function arrayToNumericMap(array: readonly T[], makeKey: (value: T) /** @internal */ export function arrayToMultiMap(values: readonly V[], makeKey: (value: V) => K): MultiMap; /** @internal */ -export function arrayToMultiMap(values: readonly V[], makeKey: (value: V) => K, makeValue: (value: V) => U): MultiMap; -/** @internal */ -export function arrayToMultiMap(values: readonly V[], makeKey: (value: V) => K, makeValue: (value: V) => V | U = identity): MultiMap { +export function arrayToMultiMap( + values: readonly V[], + makeKey: (value: V) => K, + makeValue: (value: V) => U, +): MultiMap; +/** @internal */ +export function arrayToMultiMap( + values: readonly V[], + makeKey: (value: V) => K, + makeValue: (value: V) => V | U = identity, +): MultiMap { const result = createMultiMap(); for (const value of values) { result.add(makeKey(value), makeValue(value)); @@ -1533,21 +1747,42 @@ export function arrayToMultiMap(values: readonly V[], makeKey: (value: /** @internal */ export function group(values: readonly T[], getGroupId: (value: T) => K): readonly (readonly T[])[]; /** @internal */ -export function group(values: readonly T[], getGroupId: (value: T) => K, resultSelector: (values: readonly T[]) => R): R[]; +export function group( + values: readonly T[], + getGroupId: (value: T) => K, + resultSelector: (values: readonly T[]) => R, +): R[]; /** @internal */ export function group(values: readonly T[], getGroupId: (value: T) => string): readonly (readonly T[])[]; /** @internal */ -export function group(values: readonly T[], getGroupId: (value: T) => string, resultSelector: (values: readonly T[]) => R): R[]; -/** @internal */ -export function group(values: readonly T[], getGroupId: (value: T) => K, resultSelector: (values: readonly T[]) => readonly T[] = identity): readonly (readonly T[])[] { +export function group( + values: readonly T[], + getGroupId: (value: T) => string, + resultSelector: (values: readonly T[]) => R, +): R[]; +/** @internal */ +export function group( + values: readonly T[], + getGroupId: (value: T) => K, + resultSelector: (values: readonly T[]) => readonly T[] = identity, +): readonly (readonly T[])[] { return arrayFrom(arrayToMultiMap(values, getGroupId).values(), resultSelector); } /** @internal */ -export function groupBy(values: readonly T[] | undefined, keySelector: (value: T) => value is U): { true?: U[], false?: Exclude[] }; +export function groupBy( + values: readonly T[] | undefined, + keySelector: (value: T) => value is U, +): { true?: U[]; false?: Exclude[]; }; /** @internal */ -export function groupBy(values: readonly T[] | undefined, keySelector: (value: T) => K): { [P in K as `${P}`]?: T[]; }; -export function groupBy(values: readonly T[] | undefined, keySelector: (value: T) => K): { [P in K as `${P}`]?: T[]; } { +export function groupBy( + values: readonly T[] | undefined, + keySelector: (value: T) => K, +): { [P in K as `${P}`]?: T[]; }; +export function groupBy( + values: readonly T[] | undefined, + keySelector: (value: T) => K, +): { [P in K as `${P}`]?: T[]; } { const result: Record = {}; if (values) { for (const value of values) { @@ -1604,7 +1839,10 @@ export function copyProperties(first: T1, second: T2) { } /** @internal */ -export function maybeBind(obj: T, fn: ((this: T, ...args: A) => R) | undefined): ((...args: A) => R) | undefined { +export function maybeBind( + obj: T, + fn: ((this: T, ...args: A) => R) | undefined, +): ((...args: A) => R) | undefined { return fn ? fn.bind(obj) : undefined; } @@ -1704,11 +1942,14 @@ export function createQueue(items?: readonly T[]): Queue { * * @internal */ -export function createSet(getHashCode: (element: TElement) => THash, equals: EqualityComparer): Set { +export function createSet( + getHashCode: (element: TElement) => THash, + equals: EqualityComparer, +): Set { const multiMap = new Map(); let size = 0; - function *getElementIterator(): IterableIterator { + function* getElementIterator(): IterableIterator { for (const value of multiMap.values()) { if (isArray(value)) { yield* value; @@ -1746,7 +1987,7 @@ export function createSet(getHashCode: (element: TElem else { const value = values; if (!equals(value, element)) { - multiMap.set(hash, [ value, element ]); + multiMap.set(hash, [value, element]); size++; } } @@ -1863,7 +2104,10 @@ export function isNumber(x: unknown): x is number { } /** @internal */ -export function tryCast(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined { +export function tryCast( + value: TIn | undefined, + test: (value: TIn) => value is TOut, +): TOut | undefined { return value !== undefined && test(value) ? value : undefined; } @@ -1871,7 +2115,9 @@ export function tryCast(value: TIn | undefined, tes export function cast(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut { if (value !== undefined && test(value)) return value; - return Debug.fail(`Invalid cast. The supplied value ${value} did not pass the test '${Debug.getFunctionName(test)}'.`); + return Debug.fail( + `Invalid cast. The supplied value ${value} did not pass the test '${Debug.getFunctionName(test)}'.`, + ); } /** @@ -1879,7 +2125,7 @@ export function cast(value: TIn | undefined, test: * * @internal */ -export function noop(_?: unknown): void { } +export function noop(_?: unknown): void {} /** * Do nothing and return false @@ -1963,9 +2209,9 @@ const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_. ]+/g; * @internal */ export function toFileNameLowerCase(x: string) { - return fileNameLowerCaseRegExp.test(x) ? - x.replace(fileNameLowerCaseRegExp, toLowerCase) : - x; + return fileNameLowerCaseRegExp.test(x) + ? x.replace(fileNameLowerCaseRegExp, toLowerCase) + : x; } /** @@ -2036,7 +2282,10 @@ export interface MemoizeCache { * * @internal */ -export function memoizeCached(callback: (...args: A) => T, cache: MemoizeCache): (...args: A) => T { +export function memoizeCached( + callback: (...args: A) => T, + cache: MemoizeCache, +): (...args: A) => T { return (...args: A) => { let value = cache.get(args); if (value === undefined && !cache.has(args)) { @@ -2057,7 +2306,13 @@ export function memoizeCached(callback: (...args: A) => T, c */ export function compose(...args: ((t: T) => T)[]): (t: T) => T; /** @internal */ -export function compose(a: (t: T) => T, b: (t: T) => T, c: (t: T) => T, d: (t: T) => T, e: (t: T) => T): (t: T) => T { +export function compose( + 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++) { @@ -2119,8 +2374,8 @@ export function equateValues(a: T, b: T) { export function equateStringsCaseInsensitive(a: string, b: string) { return a === b || a !== undefined - && b !== undefined - && a.toUpperCase() === b.toUpperCase(); + && b !== undefined + && a.toUpperCase() === b.toUpperCase(); } /** @@ -2138,11 +2393,11 @@ export function equateStringsCaseSensitive(a: string, b: string) { function compareComparableValues(a: string | undefined, b: string | undefined): Comparison; function compareComparableValues(a: number | undefined, b: number | undefined): Comparison; function compareComparableValues(a: string | number | undefined, b: string | number | undefined) { - return a === b ? Comparison.EqualTo : - a === undefined ? Comparison.LessThan : - b === undefined ? Comparison.GreaterThan : - a < b ? Comparison.LessThan : - Comparison.GreaterThan; + return a === b ? Comparison.EqualTo + : a === undefined ? Comparison.LessThan + : b === undefined ? Comparison.GreaterThan + : a < b ? Comparison.LessThan + : Comparison.GreaterThan; } /** @@ -2248,7 +2503,11 @@ const createUIStringComparer = (() => { const stringComparerFactory = getStringComparerFactory(); return createStringComparer; - function compareWithCallback(a: string | undefined, b: string | undefined, comparer: (a: string, b: string) => number) { + function compareWithCallback( + a: string | undefined, + b: string | undefined, + comparer: (a: string, b: string) => number, + ) { if (a === b) return Comparison.EqualTo; if (a === undefined) return Comparison.LessThan; if (b === undefined) return Comparison.GreaterThan; @@ -2301,9 +2560,11 @@ const createUIStringComparer = (() => { // If the host does not support Intl, we fall back to localeCompare. // localeCompare in Node v0.10 is just an ordinal comparison, so don't use it. - if (typeof String.prototype.localeCompare === "function" && - typeof String.prototype.toLocaleUpperCase === "function" && - "a".localeCompare("B") < 0) { + if ( + typeof String.prototype.localeCompare === "function" + && typeof String.prototype.toLocaleUpperCase === "function" + && "a".localeCompare("B") < 0 + ) { return createLocaleCompareStringComparer; } @@ -2360,14 +2621,18 @@ export function compareStringsCaseSensitiveUI(a: string, b: string) { } /** @internal */ -export function compareProperties(a: T | undefined, b: T | undefined, key: K, comparer: Comparer): Comparison { - return a === b ? Comparison.EqualTo : - a === undefined ? Comparison.LessThan : - b === undefined ? Comparison.GreaterThan : - comparer(a[key], b[key]); +export function compareProperties( + a: T | undefined, + b: T | undefined, + key: K, + comparer: Comparer, +): Comparison { + return a === b ? Comparison.EqualTo + : a === undefined ? Comparison.LessThan + : b === undefined ? Comparison.GreaterThan + : comparer(a[key], b[key]); } - /** * True is greater than false. * @@ -2391,7 +2656,11 @@ export function compareBooleans(a: boolean, b: boolean): Comparison { * * @internal */ -export function getSpellingSuggestion(name: string, candidates: T[], getName: (candidate: T) => string | undefined): T | undefined { +export function getSpellingSuggestion( + name: string, + candidates: T[], + getName: (candidate: T) => string | undefined, +): T | undefined { const maximumLengthDifference = Math.max(2, Math.floor(name.length * 0.34)); let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result is worse than this, don't bother. let bestCandidate: T | undefined; @@ -2442,12 +2711,16 @@ function levenshteinWithMax(s1: string, s2: string, max: number): number | undef } for (let j = minJ; j <= maxJ; j++) { // case difference should be significantly cheaper than other differences - const substitutionDistance = s1[i - 1].toLowerCase() === s2[j-1].toLowerCase() + const substitutionDistance = s1[i - 1].toLowerCase() === s2[j - 1].toLowerCase() ? (previous[j - 1] + 0.1) : (previous[j - 1] + 2); const dist = c1 === s2.charCodeAt(j - 1) ? previous[j - 1] - : Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ substitutionDistance); + : Math.min( + /*delete*/ previous[j] + 1, + /*insert*/ current[j - 1] + 1, + /*substitute*/ substitutionDistance, + ); current[j] = dist; colMin = Math.min(colMin, dist); } @@ -2508,7 +2781,8 @@ export function removeMinAndVersionNumbers(fileName: string) { do { --pos; ch = fileName.charCodeAt(pos); - } while (pos > 0 && ch >= CharacterCodes._0 && ch <= CharacterCodes._9); + } + while (pos > 0 && ch >= CharacterCodes._0 && ch <= CharacterCodes._9); } else if (pos > 4 && (ch === CharacterCodes.n || ch === CharacterCodes.N)) { // Looking for "min" or "min" @@ -2635,7 +2909,11 @@ export function matchedText(pattern: Pattern, candidate: string): string { * * @internal */ -export function findBestPatternMatch(values: readonly T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined { +export function findBestPatternMatch( + values: readonly T[], + getPattern: (value: T) => Pattern, + candidate: string, +): T | undefined { let matchedValue: T | undefined; // use length of prefix as betterness criteria let longestMatchPrefixLength = -1; @@ -2662,15 +2940,20 @@ export function removePrefix(str: string, prefix: string): string { } /** @internal */ -export function tryRemovePrefix(str: string, prefix: string, getCanonicalFileName: GetCanonicalFileName = identity): string | undefined { - return startsWith(getCanonicalFileName(str), getCanonicalFileName(prefix)) ? str.substring(prefix.length) : undefined; +export function tryRemovePrefix( + str: string, + prefix: string, + getCanonicalFileName: GetCanonicalFileName = identity, +): string | undefined { + return startsWith(getCanonicalFileName(str), getCanonicalFileName(prefix)) ? str.substring(prefix.length) + : undefined; } /** @internal */ export function isPatternMatch({ prefix, suffix }: Pattern, candidate: string) { - return candidate.length >= prefix.length + suffix.length && - startsWith(candidate, prefix) && - endsWith(candidate, suffix); + return candidate.length >= prefix.length + suffix.length + && startsWith(candidate, prefix) + && endsWith(candidate, suffix); } /** @internal */ @@ -2679,9 +2962,16 @@ export function and(f: (arg: T) => boolean, g: (arg: T) => boolean) { } /** @internal */ -export function or(f1: (p1: P) => p1 is R1, f2: (p2: P) => p2 is R2): (p: P) => p is R1 | R2; +export function or( + f1: (p1: P) => p1 is R1, + f2: (p2: P) => p2 is R2, +): (p: P) => p is R1 | R2; /** @internal */ -export function or(f1: (p1: P) => p1 is R1, f2: (p2: P) => p2 is R2, f3: (p3: P) => p3 is R3): (p: P) => p is R1 | R2 | R3; +export function or( + f1: (p1: P) => p1 is R1, + f2: (p2: P) => p2 is R2, + f3: (p3: P) => p3 is R3, +): (p: P) => p is R1 | R2 | R3; /** @internal */ export function or(...fs: ((...args: T) => U)[]): (...args: T) => U; /** @internal */ @@ -2704,7 +2994,7 @@ export function not(fn: (...args: T) => boolean): (...args: } /** @internal */ -export function assertType(_: T): void { } +export function assertType(_: T): void {} /** @internal */ export function singleElementArray(t: T | undefined): T[] | undefined { @@ -2712,7 +3002,14 @@ export function singleElementArray(t: T | undefined): T[] | undefined { } /** @internal */ -export function enumerateInsertsAndDeletes(newItems: readonly T[], oldItems: readonly U[], comparer: (a: T, b: U) => Comparison, inserted: (newItem: T) => void, deleted: (oldItem: U) => void, unchanged?: (oldItem: U, newItem: T) => void) { +export function enumerateInsertsAndDeletes( + newItems: readonly T[], + oldItems: readonly U[], + comparer: (a: T, b: U) => Comparison, + inserted: (newItem: T) => void, + deleted: (oldItem: U) => void, + unchanged?: (oldItem: U, newItem: T) => void, +) { unchanged = unchanged || noop; let newIndex = 0; let oldIndex = 0; @@ -2757,7 +3054,12 @@ export function cartesianProduct(arrays: readonly T[][]) { return result; } -function cartesianProductWorker(arrays: readonly (readonly T[])[], result: (readonly T[])[], outer: readonly T[] | undefined, index: number) { +function cartesianProductWorker( + arrays: readonly (readonly T[])[], + result: (readonly T[])[], + outer: readonly T[] | undefined, + index: number, +) { for (const element of arrays[index]) { let inner: T[]; if (outer) { @@ -2776,7 +3078,6 @@ function cartesianProductWorker(arrays: readonly (readonly T[])[], result: (r } } - /** * Returns string left-padded with spaces or zeros until it reaches the given length. * @@ -2806,8 +3107,14 @@ export function padRight(s: string, length: number, padString: " " = " ") { /** @internal */ export function takeWhile(array: readonly T[], predicate: (element: T) => element is U): U[]; /** @internal */ -export function takeWhile(array: readonly T[] | undefined, predicate: (element: T) => element is U): U[] | undefined; -export function takeWhile(array: readonly T[] | undefined, predicate: (element: T) => element is U): U[] | undefined { +export function takeWhile( + array: readonly T[] | undefined, + predicate: (element: T) => element is U, +): U[] | undefined; +export function takeWhile( + array: readonly T[] | undefined, + predicate: (element: T) => element is U, +): U[] | undefined { if (array) { const len = array.length; let index = 0; @@ -2819,11 +3126,20 @@ export function takeWhile(array: readonly T[] | undefined, predi } /** @internal */ -export function skipWhile(array: readonly T[], predicate: (element: T) => element is U): Exclude[]; -/** @internal */ -export function skipWhile(array: readonly T[] | undefined, predicate: (element: T) => element is U): Exclude[] | undefined; -/** @internal */ -export function skipWhile(array: readonly T[] | undefined, predicate: (element: T) => element is U): Exclude[] | undefined { +export function skipWhile( + array: readonly T[], + predicate: (element: T) => element is U, +): Exclude[]; +/** @internal */ +export function skipWhile( + array: readonly T[] | undefined, + predicate: (element: T) => element is U, +): Exclude[] | undefined; +/** @internal */ +export function skipWhile( + array: readonly T[] | undefined, + predicate: (element: T) => element is U, +): Exclude[] | undefined { if (array) { const len = array.length; let index = 0; @@ -2839,7 +3155,8 @@ export function skipWhile(array: readonly T[] | undefined, predi * * @internal */ -export const trimString = !!String.prototype.trim ? ((s: string) => s.trim()) : (s: string) => trimStringEnd(trimStringStart(s)); +export const trimString = !!String.prototype.trim ? ((s: string) => s.trim()) + : (s: string) => trimStringEnd(trimStringStart(s)); /** * Returns a copy with trailing whitespace removed. @@ -2853,7 +3170,8 @@ export const trimStringEnd = !!String.prototype.trimEnd ? ((s: string) => s.trim * * @internal */ -export const trimStringStart = !!String.prototype.trimStart ? ((s: string) => s.trimStart()) : (s: string) => s.replace(/^\s+/g, ""); +export const trimStringStart = !!String.prototype.trimStart ? ((s: string) => s.trimStart()) + : (s: string) => s.replace(/^\s+/g, ""); /** * https://jsbench.me/gjkoxld4au/1 diff --git a/src/compiler/corePublic.ts b/src/compiler/corePublic.ts index 9ae5e9b94db4f..c026d2c741f79 100644 --- a/src/compiler/corePublic.ts +++ b/src/compiler/corePublic.ts @@ -52,7 +52,7 @@ export type Comparer = (a: T, b: T) => Comparison; /** @internal */ export const enum Comparison { - LessThan = -1, - EqualTo = 0, - GreaterThan = 1 + LessThan = -1, + EqualTo = 0, + GreaterThan = 1, } diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index 21d7fa6129bb1..a6adda4ecf18d 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -100,7 +100,7 @@ export enum LogLevel { Error, Warning, Info, - Verbose + Verbose, } /** @internal */ @@ -151,7 +151,7 @@ export namespace Debug { } } - const assertionCache: Partial> = {}; + const assertionCache: Partial> = {}; export function getAssertionLevel() { return currentAssertionLevel; @@ -205,14 +205,21 @@ export namespace Debug { export function failBadSyntaxKind(node: Node, message?: string, stackCrawlMark?: AnyFunction): never { return fail( `${message || "Unexpected node."}\r\nNode ${formatSyntaxKind(node.kind)} was unexpected.`, - stackCrawlMark || failBadSyntaxKind); + stackCrawlMark || failBadSyntaxKind, + ); } - export function assert(expression: unknown, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: AnyFunction): asserts expression { + export function assert( + expression: unknown, + message?: string, + verboseDebugInfo?: string | (() => string), + stackCrawlMark?: AnyFunction, + ): asserts expression { if (!expression) { message = message ? `False expression: ${message}` : "False expression."; if (verboseDebugInfo) { - message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo()); + message += "\r\nVerbose Debug Information: " + + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo()); } fail(message, stackCrawlMark || assert); } @@ -243,7 +250,11 @@ export namespace Debug { } } - export function assertIsDefined(value: T, message?: string, stackCrawlMark?: AnyFunction): asserts value is NonNullable { + export function assertIsDefined( + value: T, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts value is NonNullable { // eslint-disable-next-line no-null/no-null if (value === undefined || value === null) { fail(message, stackCrawlMark || assertIsDefined); @@ -255,97 +266,220 @@ export namespace Debug { return value; } - export function assertEachIsDefined(value: NodeArray, message?: string, stackCrawlMark?: AnyFunction): asserts value is NodeArray; - export function assertEachIsDefined(value: readonly T[], message?: string, stackCrawlMark?: AnyFunction): asserts value is readonly NonNullable[]; + export function assertEachIsDefined( + value: NodeArray, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts value is NodeArray; + export function assertEachIsDefined( + value: readonly T[], + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts value is readonly NonNullable[]; export function assertEachIsDefined(value: readonly T[], message?: string, stackCrawlMark?: AnyFunction) { for (const v of value) { assertIsDefined(v, message, stackCrawlMark || assertEachIsDefined); } } - export function checkEachDefined(value: A, message?: string, stackCrawlMark?: AnyFunction): A { + export function checkEachDefined( + value: A, + message?: string, + stackCrawlMark?: AnyFunction, + ): A { assertEachIsDefined(value, message, stackCrawlMark || checkEachDefined); return value; } export function assertNever(member: never, message = "Illegal value:", stackCrawlMark?: AnyFunction): never { - const detail = typeof member === "object" && hasProperty(member, "kind") && hasProperty(member, "pos") ? "SyntaxKind: " + formatSyntaxKind((member as Node).kind) : JSON.stringify(member); + const detail = typeof member === "object" && hasProperty(member, "kind") && hasProperty(member, "pos") + ? "SyntaxKind: " + formatSyntaxKind((member as Node).kind) : JSON.stringify(member); return fail(`${message} ${detail}`, stackCrawlMark || assertNever); } - export function assertEachNode(nodes: NodeArray, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is NodeArray; - export function assertEachNode(nodes: readonly T[], test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is readonly U[]; - export function assertEachNode(nodes: NodeArray | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is NodeArray | undefined; - export function assertEachNode(nodes: readonly T[] | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is readonly U[] | undefined; - export function assertEachNode(nodes: readonly Node[], test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertEachNode(nodes: readonly Node[] | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertEachNode( + nodes: NodeArray, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts nodes is NodeArray; + export function assertEachNode( + nodes: readonly T[], + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts nodes is readonly U[]; + export function assertEachNode( + nodes: NodeArray | undefined, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts nodes is NodeArray | undefined; + export function assertEachNode( + nodes: readonly T[] | undefined, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts nodes is readonly U[] | undefined; + export function assertEachNode( + nodes: readonly Node[], + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertEachNode( + nodes: readonly Node[] | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertEachNode")) { assert( test === undefined || every(nodes, test), message || "Unexpected node.", () => `Node array did not pass test '${getFunctionName(test!)}'.`, - stackCrawlMark || assertEachNode); + stackCrawlMark || assertEachNode, + ); } } - export function assertNode(node: T | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U; - export function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertNode( + node: T | undefined, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is U; + export function assertNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertNode")) { assert( node !== undefined && (test === undefined || test(node)), message || "Unexpected node.", () => `Node ${formatSyntaxKind(node?.kind)} did not pass test '${getFunctionName(test!)}'.`, - stackCrawlMark || assertNode); + stackCrawlMark || assertNode, + ); } } - export function assertNotNode(node: T | undefined, test: (node: Node) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is Exclude; - export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertNotNode( + node: T | undefined, + test: (node: Node) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is Exclude; + export function assertNotNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertNotNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertNotNode")) { assert( node === undefined || test === undefined || !test(node), message || "Unexpected node.", () => `Node ${formatSyntaxKind(node!.kind)} should not have passed test '${getFunctionName(test!)}'.`, - stackCrawlMark || assertNotNode); + stackCrawlMark || assertNotNode, + ); } } - export function assertOptionalNode(node: T, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U; - export function assertOptionalNode(node: T | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts node is U | undefined; - export function assertOptionalNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertOptionalNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertOptionalNode( + node: T, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is U; + export function assertOptionalNode( + node: T | undefined, + test: (node: T) => node is U, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is U | undefined; + export function assertOptionalNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertOptionalNode( + node: Node | undefined, + test: ((node: Node) => boolean) | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertOptionalNode")) { assert( test === undefined || node === undefined || test(node), message || "Unexpected node.", () => `Node ${formatSyntaxKind(node?.kind)} did not pass test '${getFunctionName(test!)}'.`, - stackCrawlMark || assertOptionalNode); + stackCrawlMark || assertOptionalNode, + ); } } - export function assertOptionalToken(node: T, kind: K, message?: string, stackCrawlMark?: AnyFunction): asserts node is Extract; - export function assertOptionalToken(node: T | undefined, kind: K, message?: string, stackCrawlMark?: AnyFunction): asserts node is Extract | undefined; - export function assertOptionalToken(node: Node | undefined, kind: SyntaxKind | undefined, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertOptionalToken(node: Node | undefined, kind: SyntaxKind | undefined, message?: string, stackCrawlMark?: AnyFunction) { + export function assertOptionalToken( + node: T, + kind: K, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is Extract; + export function assertOptionalToken( + node: T | undefined, + kind: K, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is Extract | undefined; + export function assertOptionalToken( + node: Node | undefined, + kind: SyntaxKind | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): void; + export function assertOptionalToken( + node: Node | undefined, + kind: SyntaxKind | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ) { if (shouldAssertFunction(AssertionLevel.Normal, "assertOptionalToken")) { assert( kind === undefined || node === undefined || node.kind === kind, message || "Unexpected node.", () => `Node ${formatSyntaxKind(node?.kind)} was not a '${formatSyntaxKind(kind)}' token.`, - stackCrawlMark || assertOptionalToken); + stackCrawlMark || assertOptionalToken, + ); } } - export function assertMissingNode(node: Node | undefined, message?: string, stackCrawlMark?: AnyFunction): asserts node is undefined; + export function assertMissingNode( + node: Node | undefined, + message?: string, + stackCrawlMark?: AnyFunction, + ): asserts node is undefined; export function assertMissingNode(node: Node | undefined, message?: string, stackCrawlMark?: AnyFunction) { if (shouldAssertFunction(AssertionLevel.Normal, "assertMissingNode")) { assert( node === undefined, message || "Unexpected node.", () => `Node ${formatSyntaxKind(node!.kind)} was unexpected'.`, - stackCrawlMark || assertMissingNode); + stackCrawlMark || assertMissingNode, + ); } } @@ -355,7 +489,7 @@ export namespace Debug { * as a result can reduce the number of unnecessary casts. */ export function type(value: unknown): asserts value is T; - export function type(_value: unknown) { } + export function type(_value: unknown) {} export function getFunctionName(func: AnyFunction) { if (typeof func !== "function") { @@ -372,7 +506,9 @@ export namespace Debug { } export function formatSymbol(symbol: Symbol): string { - return `{ name: ${unescapeLeadingUnderscores(symbol.escapedName)}; flags: ${formatSymbolFlags(symbol.flags)}; declarations: ${map(symbol.declarations, node => formatSyntaxKind(node.kind))} }`; + return `{ name: ${unescapeLeadingUnderscores(symbol.escapedName)}; flags: ${ + formatSymbolFlags(symbol.flags) + }; declarations: ${map(symbol.declarations, node => formatSyntaxKind(node.kind))} }`; } /** @@ -507,25 +643,32 @@ export namespace Debug { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { value(this: FlowNodeBase) { - const flowHeader = - this.flags & FlowFlags.Start ? "FlowStart" : - this.flags & FlowFlags.BranchLabel ? "FlowBranchLabel" : - this.flags & FlowFlags.LoopLabel ? "FlowLoopLabel" : - this.flags & FlowFlags.Assignment ? "FlowAssignment" : - this.flags & FlowFlags.TrueCondition ? "FlowTrueCondition" : - this.flags & FlowFlags.FalseCondition ? "FlowFalseCondition" : - this.flags & FlowFlags.SwitchClause ? "FlowSwitchClause" : - this.flags & FlowFlags.ArrayMutation ? "FlowArrayMutation" : - this.flags & FlowFlags.Call ? "FlowCall" : - this.flags & FlowFlags.ReduceLabel ? "FlowReduceLabel" : - this.flags & FlowFlags.Unreachable ? "FlowUnreachable" : - "UnknownFlow"; + const flowHeader = this.flags & FlowFlags.Start ? "FlowStart" + : this.flags & FlowFlags.BranchLabel ? "FlowBranchLabel" + : this.flags & FlowFlags.LoopLabel ? "FlowLoopLabel" + : this.flags & FlowFlags.Assignment ? "FlowAssignment" + : this.flags & FlowFlags.TrueCondition ? "FlowTrueCondition" + : this.flags & FlowFlags.FalseCondition ? "FlowFalseCondition" + : this.flags & FlowFlags.SwitchClause ? "FlowSwitchClause" + : this.flags & FlowFlags.ArrayMutation ? "FlowArrayMutation" + : this.flags & FlowFlags.Call ? "FlowCall" + : this.flags & FlowFlags.ReduceLabel ? "FlowReduceLabel" + : this.flags & FlowFlags.Unreachable ? "FlowUnreachable" + : "UnknownFlow"; const remainingFlags = this.flags & ~(FlowFlags.Referenced - 1); - return `${flowHeader}${remainingFlags ? ` (${formatFlowFlags(remainingFlags)})`: ""}`; - } + return `${flowHeader}${remainingFlags ? ` (${formatFlowFlags(remainingFlags)})` : ""}`; + }, + }, + __debugFlowFlags: { + get(this: FlowNodeBase) { + return formatEnum(this.flags, (ts as any).FlowFlags, /*isFlags*/ true); + }, + }, + __debugToString: { + value(this: FlowNodeBase) { + return formatControlFlowGraph(this); + }, }, - __debugFlowFlags: { get(this: FlowNodeBase) { return formatEnum(this.flags, (ts as any).FlowFlags, /*isFlags*/ true); } }, - __debugToString: { value(this: FlowNodeBase) { return formatControlFlowGraph(this); } } }); } } @@ -563,8 +706,8 @@ export namespace Debug { // we're just taking note of it for anyone checking regex performance in the future. defaultValue = String(defaultValue).replace(/(?:,[\s\w\d_]+:[^,]+)+\]$/, "]"); return `NodeArray ${defaultValue}`; - } - } + }, + }, }); } } @@ -602,50 +745,69 @@ export namespace Debug { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { value(this: Symbol) { - const symbolHeader = - this.flags & SymbolFlags.Transient ? "TransientSymbol" : - "Symbol"; + const symbolHeader = this.flags & SymbolFlags.Transient ? "TransientSymbol" + : "Symbol"; const remainingSymbolFlags = this.flags & ~SymbolFlags.Transient; - return `${symbolHeader} '${symbolName(this)}'${remainingSymbolFlags ? ` (${formatSymbolFlags(remainingSymbolFlags)})` : ""}`; - } + return `${symbolHeader} '${symbolName(this)}'${ + remainingSymbolFlags ? ` (${formatSymbolFlags(remainingSymbolFlags)})` : "" + }`; + }, + }, + __debugFlags: { + get(this: Symbol) { + return formatSymbolFlags(this.flags); + }, }, - __debugFlags: { get(this: Symbol) { return formatSymbolFlags(this.flags); } } }); Object.defineProperties(objectAllocator.getTypeConstructor().prototype, { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { value(this: Type) { - const typeHeader = - this.flags & TypeFlags.Nullable ? "NullableType" : - this.flags & TypeFlags.StringOrNumberLiteral ? `LiteralType ${JSON.stringify((this as LiteralType).value)}` : - this.flags & TypeFlags.BigIntLiteral ? `LiteralType ${(this as BigIntLiteralType).value.negative ? "-" : ""}${(this as BigIntLiteralType).value.base10Value}n` : - this.flags & TypeFlags.UniqueESSymbol ? "UniqueESSymbolType" : - this.flags & TypeFlags.Enum ? "EnumType" : - this.flags & TypeFlags.Intrinsic ? `IntrinsicType ${(this as IntrinsicType).intrinsicName}` : - this.flags & TypeFlags.Union ? "UnionType" : - this.flags & TypeFlags.Intersection ? "IntersectionType" : - this.flags & TypeFlags.Index ? "IndexType" : - this.flags & TypeFlags.IndexedAccess ? "IndexedAccessType" : - this.flags & TypeFlags.Conditional ? "ConditionalType" : - this.flags & TypeFlags.Substitution ? "SubstitutionType" : - this.flags & TypeFlags.TypeParameter ? "TypeParameter" : - this.flags & TypeFlags.Object ? - (this as ObjectType).objectFlags & ObjectFlags.ClassOrInterface ? "InterfaceType" : - (this as ObjectType).objectFlags & ObjectFlags.Reference ? "TypeReference" : - (this as ObjectType).objectFlags & ObjectFlags.Tuple ? "TupleType" : - (this as ObjectType).objectFlags & ObjectFlags.Anonymous ? "AnonymousType" : - (this as ObjectType).objectFlags & ObjectFlags.Mapped ? "MappedType" : - (this as ObjectType).objectFlags & ObjectFlags.ReverseMapped ? "ReverseMappedType" : - (this as ObjectType).objectFlags & ObjectFlags.EvolvingArray ? "EvolvingArrayType" : - "ObjectType" : - "Type"; - const remainingObjectFlags = this.flags & TypeFlags.Object ? (this as ObjectType).objectFlags & ~ObjectFlags.ObjectTypeKindMask : 0; - return `${typeHeader}${this.symbol ? ` '${symbolName(this.symbol)}'` : ""}${remainingObjectFlags ? ` (${formatObjectFlags(remainingObjectFlags)})` : ""}`; - } + const typeHeader = this.flags & TypeFlags.Nullable ? "NullableType" + : this.flags & TypeFlags.StringOrNumberLiteral + ? `LiteralType ${JSON.stringify((this as LiteralType).value)}` + : this.flags & TypeFlags.BigIntLiteral + ? `LiteralType ${(this as BigIntLiteralType).value.negative ? "-" : ""}${ + (this as BigIntLiteralType).value.base10Value + }n` + : this.flags & TypeFlags.UniqueESSymbol ? "UniqueESSymbolType" + : this.flags & TypeFlags.Enum ? "EnumType" + : this.flags & TypeFlags.Intrinsic ? `IntrinsicType ${(this as IntrinsicType).intrinsicName}` + : this.flags & TypeFlags.Union ? "UnionType" + : this.flags & TypeFlags.Intersection ? "IntersectionType" + : this.flags & TypeFlags.Index ? "IndexType" + : this.flags & TypeFlags.IndexedAccess ? "IndexedAccessType" + : this.flags & TypeFlags.Conditional ? "ConditionalType" + : this.flags & TypeFlags.Substitution ? "SubstitutionType" + : this.flags & TypeFlags.TypeParameter ? "TypeParameter" + : this.flags & TypeFlags.Object + ? (this as ObjectType).objectFlags & ObjectFlags.ClassOrInterface ? "InterfaceType" + : (this as ObjectType).objectFlags & ObjectFlags.Reference ? "TypeReference" + : (this as ObjectType).objectFlags & ObjectFlags.Tuple ? "TupleType" + : (this as ObjectType).objectFlags & ObjectFlags.Anonymous ? "AnonymousType" + : (this as ObjectType).objectFlags & ObjectFlags.Mapped ? "MappedType" + : (this as ObjectType).objectFlags & ObjectFlags.ReverseMapped ? "ReverseMappedType" + : (this as ObjectType).objectFlags & ObjectFlags.EvolvingArray ? "EvolvingArrayType" + : "ObjectType" + : "Type"; + const remainingObjectFlags = this.flags & TypeFlags.Object + ? (this as ObjectType).objectFlags & ~ObjectFlags.ObjectTypeKindMask : 0; + return `${typeHeader}${this.symbol ? ` '${symbolName(this.symbol)}'` : ""}${ + remainingObjectFlags ? ` (${formatObjectFlags(remainingObjectFlags)})` : "" + }`; + }, + }, + __debugFlags: { + get(this: Type) { + return formatTypeFlags(this.flags); + }, + }, + __debugObjectFlags: { + get(this: Type) { + return this.flags & TypeFlags.Object ? formatObjectFlags((this as ObjectType).objectFlags) : ""; + }, }, - __debugFlags: { get(this: Type) { return formatTypeFlags(this.flags); } }, - __debugObjectFlags: { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((this as ObjectType).objectFlags) : ""; } }, __debugTypeToString: { value(this: Type) { // avoid recomputing @@ -655,20 +817,28 @@ export namespace Debug { weakTypeTextMap.set(this, text); } return text; - } + }, }, }); Object.defineProperties(objectAllocator.getSignatureConstructor().prototype, { - __debugFlags: { get(this: Signature) { return formatSignatureFlags(this.flags); } }, - __debugSignatureToString: { value(this: Signature) { return this.checker?.signatureToString(this); } } + __debugFlags: { + get(this: Signature) { + return formatSignatureFlags(this.flags); + }, + }, + __debugSignatureToString: { + value(this: Signature) { + return this.checker?.signatureToString(this); + }, + }, }); const nodeConstructors = [ objectAllocator.getNodeConstructor(), objectAllocator.getIdentifierConstructor(), objectAllocator.getTokenConstructor(), - objectAllocator.getSourceFileConstructor() + objectAllocator.getSourceFileConstructor(), ]; for (const ctor of nodeConstructors) { @@ -677,53 +847,79 @@ export namespace Debug { // for use with vscode-js-debug's new customDescriptionGenerator in launch.json __tsDebuggerDisplay: { value(this: Node) { - const nodeHeader = - isGeneratedIdentifier(this) ? "GeneratedIdentifier" : - isIdentifier(this) ? `Identifier '${idText(this)}'` : - isPrivateIdentifier(this) ? `PrivateIdentifier '${idText(this)}'` : - isStringLiteral(this) ? `StringLiteral ${JSON.stringify(this.text.length < 10 ? this.text : this.text.slice(10) + "...")}` : - isNumericLiteral(this) ? `NumericLiteral ${this.text}` : - isBigIntLiteral(this) ? `BigIntLiteral ${this.text}n` : - isTypeParameterDeclaration(this) ? "TypeParameterDeclaration" : - isParameter(this) ? "ParameterDeclaration" : - isConstructorDeclaration(this) ? "ConstructorDeclaration" : - isGetAccessorDeclaration(this) ? "GetAccessorDeclaration" : - isSetAccessorDeclaration(this) ? "SetAccessorDeclaration" : - isCallSignatureDeclaration(this) ? "CallSignatureDeclaration" : - isConstructSignatureDeclaration(this) ? "ConstructSignatureDeclaration" : - isIndexSignatureDeclaration(this) ? "IndexSignatureDeclaration" : - isTypePredicateNode(this) ? "TypePredicateNode" : - isTypeReferenceNode(this) ? "TypeReferenceNode" : - isFunctionTypeNode(this) ? "FunctionTypeNode" : - isConstructorTypeNode(this) ? "ConstructorTypeNode" : - isTypeQueryNode(this) ? "TypeQueryNode" : - isTypeLiteralNode(this) ? "TypeLiteralNode" : - isArrayTypeNode(this) ? "ArrayTypeNode" : - isTupleTypeNode(this) ? "TupleTypeNode" : - isOptionalTypeNode(this) ? "OptionalTypeNode" : - isRestTypeNode(this) ? "RestTypeNode" : - isUnionTypeNode(this) ? "UnionTypeNode" : - isIntersectionTypeNode(this) ? "IntersectionTypeNode" : - isConditionalTypeNode(this) ? "ConditionalTypeNode" : - isInferTypeNode(this) ? "InferTypeNode" : - isParenthesizedTypeNode(this) ? "ParenthesizedTypeNode" : - isThisTypeNode(this) ? "ThisTypeNode" : - isTypeOperatorNode(this) ? "TypeOperatorNode" : - isIndexedAccessTypeNode(this) ? "IndexedAccessTypeNode" : - isMappedTypeNode(this) ? "MappedTypeNode" : - isLiteralTypeNode(this) ? "LiteralTypeNode" : - isNamedTupleMember(this) ? "NamedTupleMember" : - isImportTypeNode(this) ? "ImportTypeNode" : - formatSyntaxKind(this.kind); + const nodeHeader = isGeneratedIdentifier(this) ? "GeneratedIdentifier" + : isIdentifier(this) ? `Identifier '${idText(this)}'` + : isPrivateIdentifier(this) ? `PrivateIdentifier '${idText(this)}'` + : isStringLiteral(this) + ? `StringLiteral ${ + JSON.stringify(this.text.length < 10 ? this.text : this.text.slice(10) + "...") + }` + : isNumericLiteral(this) ? `NumericLiteral ${this.text}` + : isBigIntLiteral(this) ? `BigIntLiteral ${this.text}n` + : isTypeParameterDeclaration(this) ? "TypeParameterDeclaration" + : isParameter(this) ? "ParameterDeclaration" + : isConstructorDeclaration(this) ? "ConstructorDeclaration" + : isGetAccessorDeclaration(this) ? "GetAccessorDeclaration" + : isSetAccessorDeclaration(this) ? "SetAccessorDeclaration" + : isCallSignatureDeclaration(this) ? "CallSignatureDeclaration" + : isConstructSignatureDeclaration(this) ? "ConstructSignatureDeclaration" + : isIndexSignatureDeclaration(this) ? "IndexSignatureDeclaration" + : isTypePredicateNode(this) ? "TypePredicateNode" + : isTypeReferenceNode(this) ? "TypeReferenceNode" + : isFunctionTypeNode(this) ? "FunctionTypeNode" + : isConstructorTypeNode(this) ? "ConstructorTypeNode" + : isTypeQueryNode(this) ? "TypeQueryNode" + : isTypeLiteralNode(this) ? "TypeLiteralNode" + : isArrayTypeNode(this) ? "ArrayTypeNode" + : isTupleTypeNode(this) ? "TupleTypeNode" + : isOptionalTypeNode(this) ? "OptionalTypeNode" + : isRestTypeNode(this) ? "RestTypeNode" + : isUnionTypeNode(this) ? "UnionTypeNode" + : isIntersectionTypeNode(this) ? "IntersectionTypeNode" + : isConditionalTypeNode(this) ? "ConditionalTypeNode" + : isInferTypeNode(this) ? "InferTypeNode" + : isParenthesizedTypeNode(this) ? "ParenthesizedTypeNode" + : isThisTypeNode(this) ? "ThisTypeNode" + : isTypeOperatorNode(this) ? "TypeOperatorNode" + : isIndexedAccessTypeNode(this) ? "IndexedAccessTypeNode" + : isMappedTypeNode(this) ? "MappedTypeNode" + : isLiteralTypeNode(this) ? "LiteralTypeNode" + : isNamedTupleMember(this) ? "NamedTupleMember" + : isImportTypeNode(this) ? "ImportTypeNode" + : formatSyntaxKind(this.kind); return `${nodeHeader}${this.flags ? ` (${formatNodeFlags(this.flags)})` : ""}`; - } + }, + }, + __debugKind: { + get(this: Node) { + return formatSyntaxKind(this.kind); + }, + }, + __debugNodeFlags: { + get(this: Node) { + return formatNodeFlags(this.flags); + }, + }, + __debugModifierFlags: { + get(this: Node) { + return formatModifierFlags(getEffectiveModifierFlagsNoCache(this)); + }, + }, + __debugTransformFlags: { + get(this: Node) { + return formatTransformFlags(this.transformFlags); + }, + }, + __debugIsParseTreeNode: { + get(this: Node) { + return isParseTreeNode(this); + }, + }, + __debugEmitFlags: { + get(this: Node) { + return formatEmitFlags(getEmitFlags(this)); + }, }, - __debugKind: { get(this: Node) { return formatSyntaxKind(this.kind); } }, - __debugNodeFlags: { get(this: Node) { return formatNodeFlags(this.flags); } }, - __debugModifierFlags: { get(this: Node) { return formatModifierFlags(getEffectiveModifierFlagsNoCache(this)); } }, - __debugTransformFlags: { get(this: Node) { return formatTransformFlags(this.transformFlags); } }, - __debugIsParseTreeNode: { get(this: Node) { return isParseTreeNode(this); } }, - __debugEmitFlags: { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } }, __debugGetText: { value(this: Node, includeTrivia?: boolean) { if (nodeIsSynthesized(this)) return ""; @@ -732,12 +928,13 @@ export namespace Debug { if (text === undefined) { const parseNode = getParseTreeNode(this); const sourceFile = parseNode && getSourceFileOfNode(parseNode); - text = sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : ""; + text = sourceFile + ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : ""; weakNodeTextMap.set(this, text); } return text; - } - } + }, + }, }); } } @@ -747,12 +944,11 @@ export namespace Debug { export function formatVariance(varianceFlags: VarianceFlags) { const variance = varianceFlags & VarianceFlags.VarianceMask; - let result = - variance === VarianceFlags.Invariant ? "in out" : - variance === VarianceFlags.Bivariant ? "[bivariant]" : - variance === VarianceFlags.Contravariant ? "in" : - variance === VarianceFlags.Covariant ? "out" : - variance === VarianceFlags.Independent ? "[independent]" : ""; + let result = variance === VarianceFlags.Invariant ? "in out" + : variance === VarianceFlags.Bivariant ? "[bivariant]" + : variance === VarianceFlags.Contravariant ? "in" + : variance === VarianceFlags.Covariant ? "out" + : variance === VarianceFlags.Independent ? "[independent]" : ""; if (varianceFlags & VarianceFlags.Unmeasurable) { result += " (unmeasurable)"; } @@ -762,26 +958,40 @@ export namespace Debug { return result; } - export type DebugType = Type & { __debugTypeToString(): string }; // eslint-disable-line @typescript-eslint/naming-convention + export type DebugType = Type & { __debugTypeToString(): string; }; // eslint-disable-line @typescript-eslint/naming-convention export class DebugTypeMapper { declare kind: TypeMapKind; __debugToString(): string { // eslint-disable-line @typescript-eslint/naming-convention type(this); switch (this.kind) { - case TypeMapKind.Function: return this.debugInfo?.() || "(function mapper)"; - case TypeMapKind.Simple: return `${(this.source as DebugType).__debugTypeToString()} -> ${(this.target as DebugType).__debugTypeToString()}`; - case TypeMapKind.Array: return zipWith( - this.sources as readonly DebugType[], - this.targets as readonly DebugType[] || map(this.sources, () => "any"), - (s, t) => `${s.__debugTypeToString()} -> ${typeof t === "string" ? t : t.__debugTypeToString()}`).join(", "); - case TypeMapKind.Deferred: return zipWith( - this.sources, - this.targets, - (s, t) => `${(s as DebugType).__debugTypeToString()} -> ${(t() as DebugType).__debugTypeToString()}`).join(", "); + case TypeMapKind.Function: + return this.debugInfo?.() || "(function mapper)"; + case TypeMapKind.Simple: + return `${(this.source as DebugType).__debugTypeToString()} -> ${ + (this.target as DebugType).__debugTypeToString() + }`; + case TypeMapKind.Array: + return zipWith( + this.sources as readonly DebugType[], + this.targets as readonly DebugType[] || map(this.sources, () => "any"), + (s, t) => + `${s.__debugTypeToString()} -> ${typeof t === "string" ? t : t.__debugTypeToString()}`, + ).join(", "); + case TypeMapKind.Deferred: + return zipWith( + this.sources, + this.targets, + (s, t) => + `${(s as DebugType).__debugTypeToString()} -> ${(t() as DebugType).__debugTypeToString()}`, + ).join(", "); case TypeMapKind.Merged: - case TypeMapKind.Composite: return `m1: ${(this.mapper1 as unknown as DebugTypeMapper).__debugToString().split("\n").join("\n ")} + case TypeMapKind.Composite: + return `m1: ${ + (this.mapper1 as unknown as DebugTypeMapper).__debugToString().split("\n").join("\n ") + } m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n").join("\n ")}`; - default: return assertNever(this); + default: + return assertNever(this); } } } @@ -860,20 +1070,18 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n") target: FlowGraphNode; } - const hasAntecedentFlags = - FlowFlags.Assignment | - FlowFlags.Condition | - FlowFlags.SwitchClause | - FlowFlags.ArrayMutation | - FlowFlags.Call | - FlowFlags.ReduceLabel; - - const hasNodeFlags = - FlowFlags.Start | - FlowFlags.Assignment | - FlowFlags.Call | - FlowFlags.Condition | - FlowFlags.ArrayMutation; + const hasAntecedentFlags = FlowFlags.Assignment + | FlowFlags.Condition + | FlowFlags.SwitchClause + | FlowFlags.ArrayMutation + | FlowFlags.Call + | FlowFlags.ReduceLabel; + + const hasNodeFlags = FlowFlags.Start + | FlowFlags.Assignment + | FlowFlags.Call + | FlowFlags.Condition + | FlowFlags.ArrayMutation; const links: Record = Object.create(/*o*/ null); // eslint-disable-line no-null/no-null const nodes: FlowGraphNode[] = []; @@ -893,15 +1101,15 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n") return !!(f.flags & FlowFlags.SwitchClause); } - function hasAntecedents(f: FlowNode): f is FlowLabel & { antecedents: FlowNode[] } { + function hasAntecedents(f: FlowNode): f is FlowLabel & { antecedents: FlowNode[]; } { return !!(f.flags & FlowFlags.Label) && !!(f as FlowLabel).antecedents; } - function hasAntecedent(f: FlowNode): f is Extract { + function hasAntecedent(f: FlowNode): f is Extract { return !!(f.flags & hasAntecedentFlags); } - function hasNode(f: FlowNode): f is Extract { + function hasNode(f: FlowNode): f is Extract { return !!(f.flags & hasNodeFlags); } @@ -938,14 +1146,23 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n") lane: -1, endLane: -1, level: -1, - circular: "circularity" + circular: "circularity", }; nodes.push(graphNode); return graphNode; } seen.add(flowNode); if (!graphNode) { - links[id] = graphNode = { id, flowNode, edges: [], text: "", lane: -1, endLane: -1, level: -1, circular: false }; + links[id] = graphNode = { + id, + flowNode, + edges: [], + text: "", + lane: -1, + endLane: -1, + level: -1, + circular: false, + }; nodes.push(graphNode); if (hasAntecedents(flowNode)) { for (const antecedent of flowNode.antecedents) { @@ -1122,7 +1339,11 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n") } } writeLane(lane, getBoxCharacter(connector)); - writeLane(lane, connector & Connection.Right && column < columnCount - 1 && !grid[column + 1][lane] ? BoxCharacter.lr : " "); + writeLane( + lane, + connector & Connection.Right && column < columnCount - 1 && !grid[column + 1][lane] + ? BoxCharacter.lr : " ", + ); } } @@ -1135,17 +1356,28 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n") function getBoxCharacter(connector: Connection) { switch (connector) { - case Connection.UpDown: return BoxCharacter.ud; - case Connection.LeftRight: return BoxCharacter.lr; - case Connection.UpLeft: return BoxCharacter.ul; - case Connection.UpRight: return BoxCharacter.ur; - case Connection.DownLeft: return BoxCharacter.dl; - case Connection.DownRight: return BoxCharacter.dr; - case Connection.UpDownLeft: return BoxCharacter.udl; - case Connection.UpDownRight: return BoxCharacter.udr; - case Connection.UpLeftRight: return BoxCharacter.ulr; - case Connection.DownLeftRight: return BoxCharacter.dlr; - case Connection.UpDownLeftRight: return BoxCharacter.udlr; + case Connection.UpDown: + return BoxCharacter.ud; + case Connection.LeftRight: + return BoxCharacter.lr; + case Connection.UpLeft: + return BoxCharacter.ul; + case Connection.UpRight: + return BoxCharacter.ur; + case Connection.DownLeft: + return BoxCharacter.dl; + case Connection.DownRight: + return BoxCharacter.dr; + case Connection.UpDownLeft: + return BoxCharacter.udl; + case Connection.UpDownRight: + return BoxCharacter.udr; + case Connection.UpLeftRight: + return BoxCharacter.ulr; + case Connection.DownLeftRight: + return BoxCharacter.dlr; + case Connection.UpDownLeftRight: + return BoxCharacter.udlr; } return " "; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 228c58bb8a856..a122c6503febb 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -483,12 +483,15 @@ export function isBuildInfoFile(file: string) { * @internal */ export function forEachEmittedFile( - host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) => T, + host: EmitHost, + action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) => T, sourceFilesOrTargetSourceFile?: readonly SourceFile[] | SourceFile, forceDtsEmit = false, onlyBuildInfo?: boolean, - includeBuildInfo?: boolean) { - const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile, forceDtsEmit); + includeBuildInfo?: boolean, +) { + const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile + : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile, forceDtsEmit); const options = host.getCompilerOptions(); if (outFile(options)) { const prepends = host.getPrependNodes(); @@ -528,11 +531,14 @@ export function getTsBuildInfoEmitOutputFilePath(options: CompilerOptions) { else { if (!configFile) return undefined; const configFileExtensionLess = removeFileExtension(configFile); - buildInfoExtensionLess = options.outDir ? - options.rootDir ? - resolvePath(options.outDir, getRelativePathFromDirectory(options.rootDir, configFileExtensionLess, /*ignoreCase*/ true)) : - combinePaths(options.outDir, getBaseFileName(configFileExtensionLess)) : - configFileExtensionLess; + buildInfoExtensionLess = options.outDir + ? options.rootDir + ? resolvePath( + options.outDir, + getRelativePathFromDirectory(options.rootDir, configFileExtensionLess, /*ignoreCase*/ true), + ) + : combinePaths(options.outDir, getBaseFileName(configFileExtensionLess)) + : configFileExtensionLess; } return buildInfoExtensionLess + Extension.TsBuildInfo; } @@ -542,28 +548,46 @@ export function getOutputPathsForBundle(options: CompilerOptions, forceDtsPaths: const outPath = outFile(options)!; const jsFilePath = options.emitDeclarationOnly ? undefined : outPath; const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options); - const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(outPath) + Extension.Dts : undefined; - const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; + const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) + ? removeFileExtension(outPath) + Extension.Dts : undefined; + const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) + ? declarationFilePath + ".map" : undefined; const buildInfoPath = getTsBuildInfoEmitOutputFilePath(options); return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }; } /** @internal */ -export function getOutputPathsFor(sourceFile: SourceFile | Bundle, host: EmitHost, forceDtsPaths: boolean): EmitFileNames { +export function getOutputPathsFor( + sourceFile: SourceFile | Bundle, + host: EmitHost, + forceDtsPaths: boolean, +): EmitFileNames { const options = host.getCompilerOptions(); if (sourceFile.kind === SyntaxKind.Bundle) { return getOutputPathsForBundle(options, forceDtsPaths); } else { - const ownOutputFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile.fileName, options)); + const ownOutputFilePath = getOwnEmitOutputFilePath( + sourceFile.fileName, + host, + getOutputExtension(sourceFile.fileName, options), + ); const isJsonFile = isJsonSourceFile(sourceFile); // If json file emits to the same location skip writing it, if emitDeclarationOnly skip writing it - const isJsonEmittedToSameLocation = isJsonFile && - comparePaths(sourceFile.fileName, ownOutputFilePath, host.getCurrentDirectory(), !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; + const isJsonEmittedToSameLocation = isJsonFile + && comparePaths( + sourceFile.fileName, + ownOutputFilePath, + host.getCurrentDirectory(), + !host.useCaseSensitiveFileNames(), + ) === Comparison.EqualTo; const jsFilePath = options.emitDeclarationOnly || isJsonEmittedToSameLocation ? undefined : ownOutputFilePath; - const sourceMapFilePath = !jsFilePath || isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options); - const declarationFilePath = (forceDtsPaths || (getEmitDeclarations(options) && !isJsonFile)) ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined; - const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined; + const sourceMapFilePath = !jsFilePath || isJsonSourceFile(sourceFile) ? undefined + : getSourceMapFilePath(jsFilePath, options); + const declarationFilePath = (forceDtsPaths || (getEmitDeclarations(options) && !isJsonFile)) + ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined; + const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) + ? declarationFilePath + ".map" : undefined; return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath: undefined }; } } @@ -574,40 +598,80 @@ function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) { /** @internal */ export function getOutputExtension(fileName: string, options: CompilerOptions): Extension { - return fileExtensionIs(fileName, Extension.Json) ? Extension.Json : - options.jsx === JsxEmit.Preserve && fileExtensionIsOneOf(fileName, [Extension.Jsx, Extension.Tsx]) ? Extension.Jsx : - fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Mjs]) ? Extension.Mjs : - fileExtensionIsOneOf(fileName, [Extension.Cts, Extension.Cjs]) ? Extension.Cjs : - Extension.Js; + return fileExtensionIs(fileName, Extension.Json) ? Extension.Json + : options.jsx === JsxEmit.Preserve && fileExtensionIsOneOf(fileName, [Extension.Jsx, Extension.Tsx]) + ? Extension.Jsx + : fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Mjs]) ? Extension.Mjs + : fileExtensionIsOneOf(fileName, [Extension.Cts, Extension.Cjs]) ? Extension.Cjs + : Extension.Js; } -function getOutputPathWithoutChangingExt(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, outputDir: string | undefined, getCommonSourceDirectory?: () => string) { - return outputDir ? - resolvePath( +function getOutputPathWithoutChangingExt( + inputFileName: string, + configFile: ParsedCommandLine, + ignoreCase: boolean, + outputDir: string | undefined, + getCommonSourceDirectory?: () => string, +) { + return outputDir + ? resolvePath( outputDir, - getRelativePathFromDirectory(getCommonSourceDirectory ? getCommonSourceDirectory() : getCommonSourceDirectoryOfConfig(configFile, ignoreCase), inputFileName, ignoreCase) - ) : - inputFileName; + getRelativePathFromDirectory( + getCommonSourceDirectory ? getCommonSourceDirectory() + : getCommonSourceDirectoryOfConfig(configFile, ignoreCase), + inputFileName, + ignoreCase, + ), + ) + : inputFileName; } /** @internal */ -export function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory?: () => string) { +export function getOutputDeclarationFileName( + inputFileName: string, + configFile: ParsedCommandLine, + ignoreCase: boolean, + getCommonSourceDirectory?: () => string, +) { return changeExtension( - getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.declarationDir || configFile.options.outDir, getCommonSourceDirectory), - getDeclarationEmitExtensionForPath(inputFileName) + getOutputPathWithoutChangingExt( + inputFileName, + configFile, + ignoreCase, + configFile.options.declarationDir || configFile.options.outDir, + getCommonSourceDirectory, + ), + getDeclarationEmitExtensionForPath(inputFileName), ); } -function getOutputJSFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean, getCommonSourceDirectory?: () => string) { +function getOutputJSFileName( + inputFileName: string, + configFile: ParsedCommandLine, + ignoreCase: boolean, + getCommonSourceDirectory?: () => string, +) { if (configFile.options.emitDeclarationOnly) return undefined; const isJsonFile = fileExtensionIs(inputFileName, Extension.Json); const outputFileName = changeExtension( - getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.outDir, getCommonSourceDirectory), - getOutputExtension(inputFileName, configFile.options) + getOutputPathWithoutChangingExt( + inputFileName, + configFile, + ignoreCase, + configFile.options.outDir, + getCommonSourceDirectory, + ), + getOutputExtension(inputFileName, configFile.options), ); - return !isJsonFile || comparePaths(inputFileName, outputFileName, Debug.checkDefined(configFile.options.configFilePath), ignoreCase) !== Comparison.EqualTo ? - outputFileName : - undefined; + return !isJsonFile + || comparePaths( + inputFileName, + outputFileName, + Debug.checkDefined(configFile.options.configFilePath), + ignoreCase, + ) !== Comparison.EqualTo + ? outputFileName + : undefined; } function createAddOutput() { @@ -623,8 +687,12 @@ function createAddOutput() { } } -function getSingleOutputFileNames(configFile: ParsedCommandLine, addOutput: ReturnType["addOutput"]) { - const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = getOutputPathsForBundle(configFile.options, /*forceDtsPaths*/ false); +function getSingleOutputFileNames( + configFile: ParsedCommandLine, + addOutput: ReturnType["addOutput"], +) { + const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = + getOutputPathsForBundle(configFile.options, /*forceDtsPaths*/ false); addOutput(jsFilePath); addOutput(sourceMapFilePath); addOutput(declarationFilePath); @@ -632,7 +700,13 @@ function getSingleOutputFileNames(configFile: ParsedCommandLine, addOutput: Retu addOutput(buildInfoPath); } -function getOwnOutputFileNames(configFile: ParsedCommandLine, inputFileName: string, ignoreCase: boolean, addOutput: ReturnType["addOutput"], getCommonSourceDirectory?: () => string) { +function getOwnOutputFileNames( + configFile: ParsedCommandLine, + inputFileName: string, + ignoreCase: boolean, + addOutput: ReturnType["addOutput"], + getCommonSourceDirectory?: () => string, +) { if (isDeclarationFileName(inputFileName)) return; const js = getOutputJSFileName(inputFileName, configFile, ignoreCase, getCommonSourceDirectory); addOutput(js); @@ -655,7 +729,7 @@ export function getCommonSourceDirectory( emittedFiles: () => readonly string[], currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, - checkSourceFilesBelongToPath?: (commonSourceDirectory: string) => void + checkSourceFilesBelongToPath?: (commonSourceDirectory: string) => void, ): string { let commonSourceDirectory; if (options.rootDir) { @@ -669,7 +743,11 @@ export function getCommonSourceDirectory( checkSourceFilesBelongToPath?.(commonSourceDirectory); } else { - commonSourceDirectory = computeCommonSourceDirectoryOfFilenames(emittedFiles(), currentDirectory, getCanonicalFileName); + commonSourceDirectory = computeCommonSourceDirectoryOfFilenames( + emittedFiles(), + currentDirectory, + getCanonicalFileName, + ); } if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) { @@ -682,12 +760,21 @@ export function getCommonSourceDirectory( } /** @internal */ -export function getCommonSourceDirectoryOfConfig({ options, fileNames }: ParsedCommandLine, ignoreCase: boolean): string { +export function getCommonSourceDirectoryOfConfig( + { options, fileNames }: ParsedCommandLine, + ignoreCase: boolean, +): string { return getCommonSourceDirectory( options, - () => filter(fileNames, file => !(options.noEmitForJsFiles && fileExtensionIsOneOf(file, supportedJSExtensionsFlat)) && !isDeclarationFileName(file)), + () => + filter( + fileNames, + file => + !(options.noEmitForJsFiles && fileExtensionIsOneOf(file, supportedJSExtensionsFlat)) + && !isDeclarationFileName(file), + ), getDirectoryPath(normalizeSlashes(Debug.checkDefined(options.configFilePath))), - createGetCanonicalFileName(!ignoreCase) + createGetCanonicalFileName(!ignoreCase), ); } @@ -707,7 +794,11 @@ export function getAllProjectOutputs(configFile: ParsedCommandLine, ignoreCase: return getOutputs(); } -export function getOutputFileNames(commandLine: ParsedCommandLine, inputFileName: string, ignoreCase: boolean): readonly string[] { +export function getOutputFileNames( + commandLine: ParsedCommandLine, + inputFileName: string, + ignoreCase: boolean, +): readonly string[] { inputFileName = normalizePath(inputFileName); Debug.assert(contains(commandLine.fileNames, inputFileName), `Expected fileName to be present in command line`); const { addOutput, getOutputs } = createAddOutput(); @@ -723,8 +814,14 @@ export function getOutputFileNames(commandLine: ParsedCommandLine, inputFileName /** @internal */ export function getFirstProjectOutput(configFile: ParsedCommandLine, ignoreCase: boolean): string { if (outFile(configFile.options)) { - const { jsFilePath, declarationFilePath } = getOutputPathsForBundle(configFile.options, /*forceDtsPaths*/ false); - return Debug.checkDefined(jsFilePath || declarationFilePath, `project ${configFile.options.configFilePath} expected to have at least one output`); + const { jsFilePath, declarationFilePath } = getOutputPathsForBundle( + configFile.options, + /*forceDtsPaths*/ false, + ); + return Debug.checkDefined( + jsFilePath || declarationFilePath, + `project ${configFile.options.configFilePath} expected to have at least one output`, + ); } const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(configFile, ignoreCase)); @@ -744,12 +841,22 @@ export function getFirstProjectOutput(configFile: ParsedCommandLine, ignoreCase: /** @internal */ // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature -export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile | undefined, { scriptTransformers, declarationTransformers }: EmitTransformers, emitOnly?: boolean | EmitOnly, onlyBuildInfo?: boolean, forceDtsEmit?: boolean): EmitResult { +export function emitFiles( + resolver: EmitResolver, + host: EmitHost, + targetSourceFile: SourceFile | undefined, + { scriptTransformers, declarationTransformers }: EmitTransformers, + emitOnly?: boolean | EmitOnly, + onlyBuildInfo?: boolean, + forceDtsEmit?: boolean, +): EmitResult { // Why var? It avoids TDZ checks in the runtime which can be costly. // See: https://github.com/microsoft/TypeScript/issues/52924 /* eslint-disable no-var */ var compilerOptions = host.getCompilerOptions(); - var sourceMapDataList: SourceMapEmitResult[] | undefined = (compilerOptions.sourceMap || compilerOptions.inlineSourceMap || getAreDeclarationMapsEnabled(compilerOptions)) ? [] : undefined; + var sourceMapDataList: SourceMapEmitResult[] | undefined = + (compilerOptions.sourceMap || compilerOptions.inlineSourceMap || getAreDeclarationMapsEnabled(compilerOptions)) + ? [] : undefined; var emittedFilesList: string[] | undefined = compilerOptions.listEmittedFiles ? [] : undefined; var emitterDiagnostics = createDiagnosticCollection(); var newLine = getNewLineCharacter(compilerOptions); @@ -767,11 +874,10 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi getSourceFilesToEmit(host, targetSourceFile, forceDtsEmit), forceDtsEmit, onlyBuildInfo, - !targetSourceFile + !targetSourceFile, ); exit(); - return { emitSkipped, diagnostics: emitterDiagnostics.getDiagnostics(), @@ -779,13 +885,18 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi sourceMaps: sourceMapDataList, }; - function emitSourceFileOrBundle({ jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) { + function emitSourceFileOrBundle( + { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }: EmitFileNames, + sourceFileOrBundle: SourceFile | Bundle | undefined, + ) { let buildInfoDirectory: string | undefined; if (buildInfoPath && sourceFileOrBundle && isBundle(sourceFileOrBundle)) { buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory())); bundleBuildInfo = { commonSourceDirectory: relativeToBuildInfo(host.getCommonSourceDirectory()), - sourceFiles: sourceFileOrBundle.sourceFiles.map(file => relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory()))) + sourceFiles: sourceFileOrBundle.sourceFiles.map(file => + relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory())) + ), }; } tracing?.push(tracing.Phase.Emit, "emitJsFileOrBundle", { jsFilePath }); @@ -823,7 +934,9 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi } function relativeToBuildInfo(path: string) { - return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory!, path, host.getCanonicalFileName)); + return ensurePathIsNonModuleName( + getRelativePathFromDirectory(buildInfoDirectory!, path, host.getCanonicalFileName), + ); } } @@ -836,14 +949,23 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi } const buildInfo = host.getBuildInfo(bundle) || createBuildInfo(/*program*/ undefined, bundle); // Pass buildinfo as additional data to avoid having to reparse - writeFile(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo }); + writeFile( + host, + emitterDiagnostics, + buildInfoPath, + getBuildInfoText(buildInfo), + /*writeByteOrderMark*/ false, + /*sourceFiles*/ undefined, + { buildInfo }, + ); } function emitJsFileOrBundle( sourceFileOrBundle: SourceFile | Bundle | undefined, jsFilePath: string | undefined, sourceMapFilePath: string | undefined, - relativeToBuildInfo: (path: string) => string) { + relativeToBuildInfo: (path: string) => string, + ) { if (!sourceFileOrBundle || emitOnly || !jsFilePath) { return; } @@ -854,7 +976,15 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi return; } // Transform the source files - const transform = transformNodes(resolver, host, factory, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false); + const transform = transformNodes( + resolver, + host, + factory, + compilerOptions, + [sourceFileOrBundle], + scriptTransformers, + /*allowDtsFiles*/ false, + ); const printerOptions: PrinterOptions = { removeComments: compilerOptions.removeComments, @@ -867,7 +997,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi inlineSources: compilerOptions.inlineSources, extendedDiagnostics: compilerOptions.extendedDiagnostics, writeBundleFileInfo: !!bundleBuildInfo, - relativeToBuildInfo + relativeToBuildInfo, }; // Create a printer to print the nodes @@ -893,7 +1023,8 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi sourceFileOrBundle: SourceFile | Bundle | undefined, declarationFilePath: string | undefined, declarationMapPath: string | undefined, - relativeToBuildInfo: (path: string) => string) { + relativeToBuildInfo: (path: string) => string, + ) { if (!sourceFileOrBundle || emitOnly === EmitOnly.Js) return; if (!declarationFilePath) { if (emitOnly || compilerOptions.emitDeclarationOnly) emitSkipped = true; @@ -902,13 +1033,25 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : sourceFileOrBundle.sourceFiles; const filesForEmit = forceDtsEmit ? sourceFiles : filter(sourceFiles, isSourceFileNotJson); // Setup and perform the transformation to retrieve declarations from the input files - const inputListOrBundle = outFile(compilerOptions) ? [factory.createBundle(filesForEmit, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : filesForEmit; + const inputListOrBundle = outFile(compilerOptions) + ? [factory.createBundle( + filesForEmit, + !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined, + )] : filesForEmit; if (emitOnly && !getEmitDeclarations(compilerOptions)) { // Checker wont collect the linked aliases since thats only done when declaration is enabled. // Do that here when emitting only dts files filesForEmit.forEach(collectLinkedAliases); } - const declarationTransform = transformNodes(resolver, host, factory, compilerOptions, inputListOrBundle, declarationTransformers, /*allowDtsFiles*/ false); + const declarationTransform = transformNodes( + resolver, + host, + factory, + compilerOptions, + inputListOrBundle, + declarationTransformers, + /*allowDtsFiles*/ false, + ); if (length(declarationTransform.diagnostics)) { for (const diagnostic of declarationTransform.diagnostics!) { emitterDiagnostics.add(diagnostic); @@ -927,7 +1070,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi onlyPrintJsDocStyle: true, writeBundleFileInfo: !!bundleBuildInfo, recordInternalSection: !!bundleBuildInfo, - relativeToBuildInfo + relativeToBuildInfo, }; const declarationPrinter = createPrinter(printerOptions, { @@ -939,10 +1082,14 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi isEmitNotificationEnabled: declarationTransform.isEmitNotificationEnabled, substituteNode: declarationTransform.substituteNode, }); - const declBlocked = (!!declarationTransform.diagnostics && !!declarationTransform.diagnostics.length) || !!host.isEmitBlocked(declarationFilePath) || !!compilerOptions.noEmit; + const declBlocked = (!!declarationTransform.diagnostics && !!declarationTransform.diagnostics.length) + || !!host.isEmitBlocked(declarationFilePath) || !!compilerOptions.noEmit; emitSkipped = emitSkipped || declBlocked; if (!declBlocked || forceDtsEmit) { - Debug.assert(declarationTransform.transformed.length === 1, "Should only see one output from the decl transform"); + Debug.assert( + declarationTransform.transformed.length === 1, + "Should only see one output from the decl transform", + ); printSourceFileOrBundle( declarationFilePath, declarationMapPath, @@ -954,7 +1101,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi mapRoot: compilerOptions.mapRoot, extendedDiagnostics: compilerOptions.extendedDiagnostics, // Explicitly do not passthru either `inline` option - } + }, ); } declarationTransform.dispose(); @@ -975,7 +1122,13 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi forEachChild(node, collectLinkedAliases); } - function printSourceFileOrBundle(jsFilePath: string, sourceMapFilePath: string | undefined, transform: TransformationResult, printer: Printer, mapOptions: SourceMapOptions) { + function printSourceFileOrBundle( + jsFilePath: string, + sourceMapFilePath: string | undefined, + transform: TransformationResult, + printer: Printer, + mapOptions: SourceMapOptions, + ) { const sourceFileOrBundle = transform.transformed[0]; const bundle = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle : undefined; const sourceFile = sourceFileOrBundle.kind === SyntaxKind.SourceFile ? sourceFileOrBundle : undefined; @@ -988,7 +1141,8 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi getBaseFileName(normalizeSlashes(jsFilePath)), getSourceRoot(mapOptions), getSourceMapDirectory(mapOptions, jsFilePath, sourceFile), - mapOptions); + mapOptions, + ); } if (bundle) { @@ -1003,7 +1157,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi if (sourceMapDataList) { sourceMapDataList.push({ inputSourceFileNames: sourceMapGenerator.getSources(), - sourceMap: sourceMapGenerator.toJSON() + sourceMap: sourceMapGenerator.toJSON(), }); } @@ -1012,7 +1166,8 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi sourceMapGenerator, jsFilePath, sourceMapFilePath, - sourceFile); + sourceFile, + ); if (sourceMappingURL) { if (!writer.isAtStartOfLine()) writer.rawWrite(newLine); @@ -1023,7 +1178,14 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi // Write the source map if (sourceMapFilePath) { const sourceMap = sourceMapGenerator.toString(); - writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap, /*writeByteOrderMark*/ false, sourceFiles); + writeFile( + host, + emitterDiagnostics, + sourceMapFilePath, + sourceMap, + /*writeByteOrderMark*/ false, + sourceFiles, + ); if (printer.bundleFileInfo) printer.bundleFileInfo.mapHash = computeSignature(sourceMap, host); } } @@ -1033,7 +1195,10 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi // Write the output file const text = writer.getText(); - writeFile(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, { sourceMapUrlPos, diagnostics: transform.diagnostics }); + writeFile(host, emitterDiagnostics, jsFilePath, text, !!compilerOptions.emitBOM, sourceFiles, { + sourceMapUrlPos, + diagnostics: transform.diagnostics, + }); // We store the hash of the text written in the buildinfo to ensure that text of the referenced d.ts file is same as whats in the buildinfo // This is needed because incremental can be toggled between two runs and we might use stale file text to do text manipulation in prepend mode if (printer.bundleFileInfo) printer.bundleFileInfo.hash = computeSignature(text, host); @@ -1053,7 +1218,8 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi function shouldEmitSourceMaps(mapOptions: SourceMapOptions, sourceFileOrBundle: SourceFile | Bundle) { return (mapOptions.sourceMap || mapOptions.inlineSourceMap) - && (sourceFileOrBundle.kind !== SyntaxKind.SourceFile || !fileExtensionIs(sourceFileOrBundle.fileName, Extension.Json)); + && (sourceFileOrBundle.kind !== SyntaxKind.SourceFile + || !fileExtensionIs(sourceFileOrBundle.fileName, Extension.Json)); } function getSourceRoot(mapOptions: SourceMapOptions) { @@ -1081,7 +1247,13 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi return getDirectoryPath(normalizePath(filePath)); } - function getSourceMappingURL(mapOptions: SourceMapOptions, sourceMapGenerator: SourceMapGenerator, filePath: string, sourceMapFilePath: string | undefined, sourceFile: SourceFile | undefined) { + function getSourceMappingURL( + mapOptions: SourceMapOptions, + sourceMapGenerator: SourceMapGenerator, + filePath: string, + sourceMapFilePath: string | undefined, + sourceFile: SourceFile | undefined, + ) { if (mapOptions.inlineSourceMap) { // Encode the sourceMap into the sourceMap url const sourceMapText = sourceMapGenerator.toString(); @@ -1106,7 +1278,9 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi combinePaths(sourceMapDir, sourceMapFile), // this is where user expects to see sourceMap host.getCurrentDirectory(), host.getCanonicalFileName, - /*isAbsolutePathAnUrl*/ true)); + /*isAbsolutePathAnUrl*/ true, + ), + ); } else { return encodeURI(combinePaths(sourceMapDir, sourceMapFile)); @@ -1185,9 +1359,14 @@ export const notImplementedResolver: EmitResolver = { */ export type EmitUsingBuildInfoResult = string | readonly OutputFile[]; -function createSourceFilesFromBundleBuildInfo(bundle: BundleBuildInfo, buildInfoDirectory: string, host: CompilerHost): readonly SourceFile[] { +function createSourceFilesFromBundleBuildInfo( + bundle: BundleBuildInfo, + buildInfoDirectory: string, + host: CompilerHost, +): readonly SourceFile[] { const jsBundle = Debug.checkDefined(bundle.js); - const prologueMap = jsBundle.sources?.prologues && arrayToMap(jsBundle.sources.prologues, prologueInfo => prologueInfo.file); + const prologueMap = jsBundle.sources?.prologues + && arrayToMap(jsBundle.sources.prologues, prologueInfo => prologueInfo.file); return bundle.sourceFiles.map((fileName, index) => { const prologueInfo = prologueMap?.get(index); const statements = prologueInfo?.directives.map(directive => { @@ -1201,7 +1380,7 @@ function createSourceFilesFromBundleBuildInfo(bundle: BundleBuildInfo, buildInfo sourceFile.fileName = getRelativePathFromDirectory( host.getCurrentDirectory(), getNormalizedAbsolutePath(fileName, buildInfoDirectory), - !host.useCaseSensitiveFileNames() + !host.useCaseSensitiveFileNames(), ); sourceFile.text = prologueInfo?.text ?? ""; setTextRangePosWidth(sourceFile, 0, prologueInfo?.text.length ?? 0); @@ -1217,7 +1396,7 @@ export function emitUsingBuildInfo( config: ParsedCommandLine, host: CompilerHost, getCommandLine: (ref: ProjectReference) => ParsedCommandLine | undefined, - customTransformers?: CustomTransformers + customTransformers?: CustomTransformers, ): EmitUsingBuildInfoResult { tracing?.push(tracing.Phase.Emit, "emitUsingBuildInfo", {}, /*separateBeginAndEnd*/ true); performance.mark("beforeEmit"); @@ -1232,13 +1411,16 @@ function emitUsingBuildInfoWorker( config: ParsedCommandLine, host: CompilerHost, getCommandLine: (ref: ProjectReference) => ParsedCommandLine | undefined, - customTransformers?: CustomTransformers + customTransformers?: CustomTransformers, ): EmitUsingBuildInfoResult { - const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false); + const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = + getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false); // If host directly provides buildinfo we can get it directly. This allows host to cache the buildinfo const buildInfo = host.getBuildInfo!(buildInfoPath!, config.options.configFilePath); if (!buildInfo) return buildInfoPath!; - if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationFilePath && !buildInfo.bundle.dts)) return buildInfoPath!; + if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationFilePath && !buildInfo.bundle.dts)) { + return buildInfoPath!; + } const jsFileText = host.readFile(Debug.checkDefined(jsFilePath)); if (!jsFileText) return jsFilePath!; @@ -1246,17 +1428,27 @@ function emitUsingBuildInfoWorker( if (computeSignature(jsFileText, host) !== buildInfo.bundle.js.hash) return jsFilePath!; const sourceMapText = sourceMapFilePath && host.readFile(sourceMapFilePath); // error if no source map or for now if inline sourcemap - if ((sourceMapFilePath && !sourceMapText) || config.options.inlineSourceMap) return sourceMapFilePath || "inline sourcemap decoding"; - if (sourceMapFilePath && computeSignature(sourceMapText!, host) !== buildInfo.bundle.js.mapHash) return sourceMapFilePath; + if ((sourceMapFilePath && !sourceMapText) || config.options.inlineSourceMap) { + return sourceMapFilePath || "inline sourcemap decoding"; + } + if (sourceMapFilePath && computeSignature(sourceMapText!, host) !== buildInfo.bundle.js.mapHash) { + return sourceMapFilePath; + } // read declaration text const declarationText = declarationFilePath && host.readFile(declarationFilePath); if (declarationFilePath && !declarationText) return declarationFilePath; - if (declarationFilePath && computeSignature(declarationText!, host) !== buildInfo.bundle.dts!.hash) return declarationFilePath; + if (declarationFilePath && computeSignature(declarationText!, host) !== buildInfo.bundle.dts!.hash) { + return declarationFilePath; + } const declarationMapText = declarationMapPath && host.readFile(declarationMapPath); // error if no source map or for now if inline sourcemap - if ((declarationMapPath && !declarationMapText) || config.options.inlineSourceMap) return declarationMapPath || "inline sourcemap decoding"; - if (declarationMapPath && computeSignature(declarationMapText!, host) !== buildInfo.bundle.dts!.mapHash) return declarationMapPath; + if ((declarationMapPath && !declarationMapText) || config.options.inlineSourceMap) { + return declarationMapPath || "inline sourcemap decoding"; + } + if (declarationMapPath && computeSignature(declarationMapText!, host) !== buildInfo.bundle.dts!.mapHash) { + return declarationMapPath; + } const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath!, host.getCurrentDirectory())); const ownPrependInput = createInputFilesWithFileTexts( @@ -1270,7 +1462,7 @@ function emitUsingBuildInfoWorker( declarationMapText, buildInfoPath, buildInfo, - /*oldFileOfCurrentEmit*/ true + /*oldFileOfCurrentEmit*/ true, ); const outputFiles: OutputFile[] = []; const prependNodes = createPrependNodes(config.projectReferences, getCommandLine, f => host.readFile(f), host); @@ -1280,7 +1472,8 @@ function emitUsingBuildInfoWorker( const emitHost: EmitHost = { getPrependNodes: memoize(() => [...prependNodes, ownPrependInput]), getCanonicalFileName: host.getCanonicalFileName, - getCommonSourceDirectory: () => getNormalizedAbsolutePath(buildInfo.bundle!.commonSourceDirectory, buildInfoDirectory), + getCommonSourceDirectory: () => + getNormalizedAbsolutePath(buildInfo.bundle!.commonSourceDirectory, buildInfoDirectory), getCompilerOptions: () => config.options, getCurrentDirectory: () => host.getCurrentDirectory(), getSourceFile: returnUndefined, @@ -1322,7 +1515,11 @@ function emitUsingBuildInfoWorker( const program = buildInfo.program; if (program && changedDtsText !== undefined && config.options.composite) { // Update the output signature - (program as ProgramBundleEmitBuildInfo).outSignature = computeSignature(changedDtsText, host, changedDtsData); + (program as ProgramBundleEmitBuildInfo).outSignature = computeSignature( + changedDtsText, + host, + changedDtsData, + ); } // Update sourceFileInfo const { js, dts, sourceFiles } = buildInfo.bundle!; @@ -1342,7 +1539,7 @@ function emitUsingBuildInfoWorker( notImplementedResolver, emitHost, /*targetSourceFile*/ undefined, - getTransformers(config.options, customTransformers) + getTransformers(config.options, customTransformers), ); return outputFiles; } @@ -1362,10 +1559,14 @@ export const createPrinterWithDefaults = /* @__PURE__ */ memoize(() => createPri export const createPrinterWithRemoveComments = /* @__PURE__ */ memoize(() => createPrinter({ removeComments: true })); /** @internal */ -export const createPrinterWithRemoveCommentsNeverAsciiEscape = /* @__PURE__ */ memoize(() => createPrinter({ removeComments: true, neverAsciiEscape: true })); +export const createPrinterWithRemoveCommentsNeverAsciiEscape = /* @__PURE__ */ memoize(() => + createPrinter({ removeComments: true, neverAsciiEscape: true }) +); /** @internal */ -export const createPrinterWithRemoveCommentsOmitTrailingSemicolon = /* @__PURE__ */ memoize(() => createPrinter({ removeComments: true, omitTrailingSemicolon: true })); +export const createPrinterWithRemoveCommentsOmitTrailingSemicolon = /* @__PURE__ */ memoize(() => + createPrinter({ removeComments: true, omitTrailingSemicolon: true }) +); export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer { // Why var? It avoids TDZ checks in the runtime which can be costly. @@ -1381,7 +1582,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri onBeforeEmitNodeArray, onAfterEmitNodeArray, onBeforeEmitToken, - onAfterEmitToken + onAfterEmitToken, } = handlers; var extendedDiagnostics = !!printerOptions.extendedDiagnostics; @@ -1430,15 +1631,20 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri var containerEnd = -1; var declarationListContainerEnd = -1; var currentLineMap: readonly number[] | undefined; - var detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number }[] | undefined; + var detachedCommentsInfo: { nodePos: number; detachedCommentEndPos: number; }[] | undefined; var hasWrittenComment = false; var commentsDisabled = !!printerOptions.removeComments; var lastSubstitution: Node | undefined; var currentParenthesizerRule: ParenthesizerRule | undefined; - var { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment"); + var { enter: enterComment, exit: exitComment } = performance.createTimerIf( + extendedDiagnostics, + "commentTime", + "beforeComment", + "afterComment", + ); var parenthesizer = factory.parenthesizer; var typeArgumentParenthesizerRuleSelector: OrdinalParentheizerRuleSelector = { - select: index => index === 0 ? parenthesizer.parenthesizeLeadingTypeArgument : undefined + select: index => index === 0 ? parenthesizer.parenthesizeLeadingTypeArgument : undefined, }; var emitBinaryExpression = createEmitBinaryExpression(); /* eslint-enable no-var */ @@ -1456,7 +1662,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeList, writeFile, writeBundle, - bundleFileInfo + bundleFileInfo, }; function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string { @@ -1472,9 +1678,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri break; } switch (node.kind) { - case SyntaxKind.SourceFile: return printFile(node as SourceFile); - case SyntaxKind.Bundle: return printBundle(node as Bundle); - case SyntaxKind.UnparsedSource: return printUnparsedSource(node as UnparsedSource); + case SyntaxKind.SourceFile: + return printFile(node as SourceFile); + case SyntaxKind.Bundle: + return printBundle(node as Bundle); + case SyntaxKind.UnparsedSource: + return printUnparsedSource(node as UnparsedSource); } writeNode(hint, node, sourceFile, beginPrint()); return endPrint(); @@ -1513,7 +1722,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writer = previousWriter; } - function writeList(format: ListFormat, nodes: NodeArray, sourceFile: SourceFile | undefined, output: EmitTextWriter) { + function writeList( + format: ListFormat, + nodes: NodeArray, + sourceFile: SourceFile | undefined, + output: EmitTextWriter, + ) { const previousWriter = writer; setWriter(output, /*_sourceMapGenerator*/ undefined); if (sourceFile) { @@ -1539,12 +1753,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function recordBundleFileInternalSectionStart(node: Node) { - if (recordInternalSection && - bundleFileInfo && - currentSourceFile && - (isDeclaration(node) || isVariableStatement(node)) && - isInternalDeclaration(node, currentSourceFile) && - sourceFileTextKind !== BundleFileSectionKind.Internal) { + if ( + recordInternalSection + && bundleFileInfo + && currentSourceFile + && (isDeclaration(node) || isVariableStatement(node)) + && isInternalDeclaration(node, currentSourceFile) + && sourceFileTextKind !== BundleFileSectionKind.Internal + ) { const prevSourceFileTextKind = sourceFileTextKind; recordBundleFileTextLikeSection(writer.getTextPos()); sourceFileTextPos = getTextPosWithWriteLine(); @@ -1554,7 +1770,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return undefined; } - function recordBundleFileInternalSectionEnd(prevSourceFileTextKind: ReturnType) { + function recordBundleFileInternalSectionEnd( + prevSourceFileTextKind: ReturnType, + ) { if (prevSourceFileTextKind) { recordBundleFileTextLikeSection(writer.getTextPos()); sourceFileTextPos = getTextPosWithWriteLine(); @@ -1596,7 +1814,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri end: writer.getTextPos(), kind: BundleFileSectionKind.Prepend, data: relativeToBuildInfo!((prepend as UnparsedSource).fileName), - texts: newSections as BundleFileTextLike[] + texts: newSections as BundleFileTextLike[], }); } } @@ -1637,7 +1855,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writer = previousWriter; } - function writeFile(sourceFile: SourceFile, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) { + function writeFile( + sourceFile: SourceFile, + output: EmitTextWriter, + sourceMapGenerator: SourceMapGenerator | undefined, + ) { isOwnFileEmit = true; const previousWriter = writer; setWriter(output, sourceMapGenerator); @@ -1759,22 +1981,27 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function shouldEmitSourceMaps(node: Node) { - return !sourceMapsDisabled && - !isSourceFile(node) && - !isInJsonFile(node) && - !isUnparsedSource(node) && - !isUnparsedPrepend(node); + return !sourceMapsDisabled + && !isSourceFile(node) + && !isInJsonFile(node) + && !isUnparsedSource(node) + && !isUnparsedPrepend(node); } function getPipelinePhase(phase: PipelinePhase, emitHint: EmitHint, node: Node) { switch (phase) { case PipelinePhase.Notification: - if (onEmitNode !== noEmitNotification && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node))) { + if ( + onEmitNode !== noEmitNotification && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node)) + ) { return pipelineEmitWithNotification; } // falls through case PipelinePhase.Substitution: - if (substituteNode !== noEmitSubstitution && (lastSubstitution = substituteNode(emitHint, node) || node) !== node) { + if ( + substituteNode !== noEmitSubstitution + && (lastSubstitution = substituteNode(emitHint, node) || node) !== node + ) { if (currentParenthesizerRule) { lastSubstitution = currentParenthesizerRule(lastSubstitution); } @@ -1832,8 +2059,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } if (hint === EmitHint.SourceFile) return emitSourceFile(cast(node, isSourceFile)); if (hint === EmitHint.IdentifierName) return emitIdentifier(cast(node, isIdentifier)); - if (hint === EmitHint.JsxAttributeValue) return emitLiteral(cast(node, isStringLiteral), /*jsxAttributeEscape*/ true); - if (hint === EmitHint.MappedTypeParameter) return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); + if (hint === EmitHint.JsxAttributeValue) { + return emitLiteral(cast(node, isStringLiteral), /*jsxAttributeEscape*/ true); + } + if (hint === EmitHint.MappedTypeParameter) { + return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); + } if (hint === EmitHint.EmbeddedStatement) { Debug.assertNode(node, isEmptyStatement); return emitEmptyStatement(/*isEmbeddedStatement*/ true); @@ -2174,7 +2405,15 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri case SyntaxKind.JSDocTypeTag: case SyntaxKind.JSDocThrowsTag: case SyntaxKind.JSDocSatisfiesTag: - return emitJSDocSimpleTypedTag(node as JSDocTypeTag | JSDocReturnTag | JSDocThisTag | JSDocTypeTag | JSDocThrowsTag | JSDocSatisfiesTag); + return emitJSDocSimpleTypedTag( + node as + | JSDocTypeTag + | JSDocReturnTag + | JSDocThisTag + | JSDocTypeTag + | JSDocThrowsTag + | JSDocSatisfiesTag, + ); case SyntaxKind.JSDocTemplateTag: return emitJSDocTemplateTag(node as JSDocTemplateTag); case SyntaxKind.JSDocTypedefTag: @@ -2356,8 +2595,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri const numPrepends = bundle ? bundle.prepends.length : 0; const numNodes = bundle ? bundle.sourceFiles.length + numPrepends : 1; for (let i = 0; i < numNodes; i++) { - const currentNode = bundle ? i < numPrepends ? bundle.prepends[i] : bundle.sourceFiles[i - numPrepends] : node; - const sourceFile = isSourceFile(currentNode) ? currentNode : isUnparsedSource(currentNode) ? undefined : currentSourceFile; + const currentNode = bundle ? i < numPrepends ? bundle.prepends[i] : bundle.sourceFiles[i - numPrepends] + : node; + const sourceFile = isSourceFile(currentNode) ? currentNode + : isUnparsedSource(currentNode) ? undefined : currentSourceFile; const shouldSkip = printerOptions.noEmitHelpers || (!!sourceFile && hasRecordedExternalHelpers(sourceFile)); const shouldBundle = (isSourceFile(currentNode) || isUnparsedSource(currentNode)) && !isOwnFileEmit; const helpers = isUnparsedSource(currentNode) ? currentNode.helpers : getSortedEmitHelpers(currentNode); @@ -2390,7 +2631,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri else { writeLines(helper.text(makeFileLevelOptimisticUniqueName)); } - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.EmitHelpers, data: helper.name }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.EmitHelpers, + data: helper.name, + }); + } helpersEmitted = true; } } @@ -2422,8 +2670,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri // SyntaxKind.TemplateTail function emitLiteral(node: LiteralLikeNode, jsxAttributeEscape: boolean) { const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape, jsxAttributeEscape); - if ((printerOptions.sourceMap || printerOptions.inlineSourceMap) - && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { + if ( + (printerOptions.sourceMap || printerOptions.inlineSourceMap) + && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind)) + ) { writeLiteral(text); } else { @@ -2458,9 +2708,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri updateOrPushBundleFileTextLike( pos, writer.getTextPos(), - unparsed.kind === SyntaxKind.UnparsedText ? - BundleFileSectionKind.Text : - BundleFileSectionKind.Internal + unparsed.kind === SyntaxKind.UnparsedText + ? BundleFileSectionKind.Text + : BundleFileSectionKind.Internal, ); } } @@ -2501,10 +2751,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitTabStop(hint: EmitHint, node: Node, snippet: TabStop) { // A tab stop should only be attached to an empty node, i.e. a node that doesn't emit any text. - Debug.assert(node.kind === SyntaxKind.EmptyStatement, - `A tab stop cannot be attached to a node of kind ${Debug.formatSyntaxKind(node.kind)}.`); - Debug.assert(hint !== EmitHint.EmbeddedStatement, - `A tab stop cannot be attached to an embedded statement.`); + Debug.assert( + node.kind === SyntaxKind.EmptyStatement, + `A tab stop cannot be attached to a node of kind ${Debug.formatSyntaxKind(node.kind)}.`, + ); + Debug.assert(hint !== EmitHint.EmbeddedStatement, `A tab stop cannot be attached to an embedded statement.`); nonEscapingWrite(`$${snippet.order}`); } @@ -2526,7 +2777,6 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri write(getTextOfNode(node, /*includeTrivia*/ false)); } - function emitQualifiedName(node: QualifiedName) { emitEntityName(node.left); writePunctuation("."); @@ -2585,7 +2835,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitTypeAnnotation(node.type); } // The comment position has to fallback to any present node within the parameterdeclaration because as it turns out, the parser can make parameter declarations with _just_ an initializer. - emitInitializer(node.initializer, node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name ? node.name.end : node.modifiers ? node.modifiers.end : node.pos, node, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitInitializer( + node.initializer, + node.type ? node.type.end + : node.questionToken ? node.questionToken.end + : node.name ? node.name.end : node.modifiers ? node.modifiers.end : node.pos, + node, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitDecorator(decorator: Decorator) { @@ -2611,7 +2868,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emit(node.questionToken); emit(node.exclamationToken); emitTypeAnnotation(node.type); - emitInitializer(node.initializer, node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name.end, node); + emitInitializer( + node.initializer, + node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name.end, + node, + ); writeTrailingSemicolon(); } @@ -2732,7 +2993,6 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emit(node.type); } - function emitJSDocNullableType(node: JSDocNullableType) { writePunctuation("?"); emit(node.type); @@ -2775,7 +3035,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri pushPrivateNameGenerationScope(TempFlags.Auto, /*newReservedMemberNames*/ undefined); writePunctuation("{"); - const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers; + const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers + : ListFormat.MultiLineTypeLiteralMembers; emitList(node, node.members, flags | ListFormat.NoSpaceIfEmpty); writePunctuation("}"); @@ -2795,8 +3056,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitTupleType(node: TupleTypeNode) { emitTokenWithComment(SyntaxKind.OpenBracketToken, node.pos, writePunctuation, node); - const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements : ListFormat.MultiLineTupleTypeElements; - emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty, parenthesizer.parenthesizeElementTypeOfTupleType); + const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements + : ListFormat.MultiLineTupleTypeElements; + emitList( + node, + node.elements, + flags | ListFormat.NoSpaceIfEmpty, + parenthesizer.parenthesizeElementTypeOfTupleType, + ); emitTokenWithComment(SyntaxKind.CloseBracketToken, node.elements.end, writePunctuation, node); } @@ -2815,11 +3082,21 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function emitUnionType(node: UnionTypeNode) { - emitList(node, node.types, ListFormat.UnionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfUnionType); + emitList( + node, + node.types, + ListFormat.UnionTypeConstituents, + parenthesizer.parenthesizeConstituentTypeOfUnionType, + ); } function emitIntersectionType(node: IntersectionTypeNode) { - emitList(node, node.types, ListFormat.IntersectionTypeConstituents, parenthesizer.parenthesizeConstituentTypeOfIntersectionType); + emitList( + node, + node.types, + ListFormat.IntersectionTypeConstituents, + parenthesizer.parenthesizeConstituentTypeOfIntersectionType, + ); } function emitConditionalType(node: ConditionalTypeNode) { @@ -2858,9 +3135,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeTokenText(node.operator, writeKeyword); writeSpace(); - const parenthesizerRule = node.operator === SyntaxKind.ReadonlyKeyword ? - parenthesizer.parenthesizeOperandOfReadonlyTypeOperator : - parenthesizer.parenthesizeOperandOfTypeOperator; + const parenthesizerRule = node.operator === SyntaxKind.ReadonlyKeyword + ? parenthesizer.parenthesizeOperandOfReadonlyTypeOperator + : parenthesizer.parenthesizeOperandOfTypeOperator; emit(node.type, parenthesizerRule); } @@ -2992,7 +3269,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitArrayLiteralExpression(node: ArrayLiteralExpression) { const elements = node.elements; const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; - emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitExpressionList( + node, + elements, + ListFormat.ArrayLiteralExpressionElements | preferNewLine, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitObjectLiteralExpression(node: ObjectLiteralExpression) { @@ -3007,8 +3289,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; - const allowTrailingComma = currentSourceFile && currentSourceFile.languageVersion >= ScriptTarget.ES5 && !isJsonSourceFile(currentSourceFile) ? ListFormat.AllowTrailingComma : ListFormat.None; - emitList(node, node.properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine); + const allowTrailingComma = currentSourceFile && currentSourceFile.languageVersion >= ScriptTarget.ES5 + && !isJsonSourceFile(currentSourceFile) ? ListFormat.AllowTrailingComma : ListFormat.None; + emitList( + node, + node.properties, + ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine, + ); if (indentedFlag) { decreaseIndent(); @@ -3019,17 +3306,21 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitPropertyAccessExpression(node: PropertyAccessExpression) { emitExpression(node.expression, parenthesizer.parenthesizeLeftSideOfAccess); - const token = node.questionDotToken || setTextRangePosEnd(factory.createToken(SyntaxKind.DotToken) as DotToken, node.expression.end, node.name.pos); + const token = node.questionDotToken + || setTextRangePosEnd( + factory.createToken(SyntaxKind.DotToken) as DotToken, + node.expression.end, + node.name.pos, + ); const linesBeforeDot = getLinesBetweenNodes(node, node.expression, token); const linesAfterDot = getLinesBetweenNodes(node, token, node.name); writeLinesAndIndent(linesBeforeDot, /*writeSpaceIfNotIndenting*/ false); - const shouldEmitDotDot = - token.kind !== SyntaxKind.QuestionDotToken && - mayNeedDotDotForPropertyAccess(node.expression) && - !writer.hasTrailingComment() && - !writer.hasTrailingWhitespace(); + const shouldEmitDotDot = token.kind !== SyntaxKind.QuestionDotToken + && mayNeedDotDotForPropertyAccess(node.expression) + && !writer.hasTrailingComment() + && !writer.hasTrailingWhitespace(); if (shouldEmitDotDot) { writePunctuation("."); @@ -3052,7 +3343,11 @@ 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, + /*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) @@ -3091,7 +3386,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } emit(node.questionDotToken); emitTypeArguments(node, node.typeArguments); - emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitExpressionList( + node, + node.arguments, + ListFormat.CallExpressionArguments, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitNewExpression(node: NewExpression) { @@ -3099,7 +3399,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeSpace(); emitExpression(node.expression, parenthesizer.parenthesizeExpressionOfNew); emitTypeArguments(node, node.typeArguments); - emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitExpressionList( + node, + node.arguments, + ListFormat.NewExpressionArguments, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitTaggedTemplateExpression(node: TaggedTemplateExpression) { @@ -3132,7 +3437,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitExpression(node.expression, /*parenthesizerRule*/ undefined); writeLineSeparatorsAfter(node.expression, node); decreaseIndentIf(indented); - emitTokenWithComment(SyntaxKind.CloseParenToken, node.expression ? node.expression.end : openParenPos, writePunctuation, node); + emitTokenWithComment( + SyntaxKind.CloseParenToken, + node.expression ? node.expression.end : openParenPos, + writePunctuation, + node, + ); } function emitFunctionExpression(node: FunctionExpression) { @@ -3200,8 +3510,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri // The same is true of minus of course. const operand = node.operand; return operand.kind === SyntaxKind.PrefixUnaryExpression - && ((node.operator === SyntaxKind.PlusToken && ((operand as PrefixUnaryExpression).operator === SyntaxKind.PlusToken || (operand as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken)) - || (node.operator === SyntaxKind.MinusToken && ((operand as PrefixUnaryExpression).operator === SyntaxKind.MinusToken || (operand as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken))); + && ((node.operator === SyntaxKind.PlusToken + && ((operand as PrefixUnaryExpression).operator === SyntaxKind.PlusToken + || (operand as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken)) + || (node.operator === SyntaxKind.MinusToken + && ((operand as PrefixUnaryExpression).operator === SyntaxKind.MinusToken + || (operand as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken))); } function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { @@ -3282,16 +3596,18 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri const shouldEmitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex]; afterEmitNode(savedPreserveSourceNewlines); if (shouldEmitSourceMaps) emitSourceMapsAfterNode(node); - if (shouldEmitComments) emitCommentsAfterNode(node, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); + if (shouldEmitComments) { + emitCommentsAfterNode(node, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); + } onAfterEmitNode?.(node); state.stackIndex--; } } function maybeEmitExpression(next: Expression, parent: BinaryExpression, side: "left" | "right") { - const parenthesizerRule = side === "left" ? - parenthesizer.getParenthesizeLeftSideOfBinaryForOperator(parent.operatorToken.kind) : - parenthesizer.getParenthesizeRightSideOfBinaryForOperator(parent.operatorToken.kind); + const parenthesizerRule = side === "left" + ? parenthesizer.getParenthesizeLeftSideOfBinaryForOperator(parent.operatorToken.kind) + : parenthesizer.getParenthesizeRightSideOfBinaryForOperator(parent.operatorToken.kind); let pipelinePhase = getPipelinePhase(PipelinePhase.Notification, EmitHint.Expression, next); if (pipelinePhase === pipelineEmitWithSubstitution) { @@ -3301,9 +3617,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri lastSubstitution = undefined; } - if (pipelinePhase === pipelineEmitWithComments || - pipelinePhase === pipelineEmitWithSourceMaps || - pipelinePhase === pipelineEmitWithHint) { + if ( + pipelinePhase === pipelineEmitWithComments + || pipelinePhase === pipelineEmitWithSourceMaps + || pipelinePhase === pipelineEmitWithHint + ) { if (isBinaryExpression(next)) { return next; } @@ -3342,7 +3660,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitYieldExpression(node: YieldExpression) { emitTokenWithComment(SyntaxKind.YieldKeyword, node.pos, writeKeyword, node); emit(node.asteriskToken); - emitExpressionWithLeadingSpace(node.expression && parenthesizeExpressionForNoAsi(node.expression), parenthesizeExpressionForNoAsiAndDisallowedComma); + emitExpressionWithLeadingSpace( + node.expression && parenthesizeExpressionForNoAsi(node.expression), + parenthesizeExpressionForNoAsiAndDisallowedComma, + ); } function emitSpreadElement(node: SpreadElement) { @@ -3410,9 +3731,16 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitBlockStatements(node: BlockLike, forceSingleLine: boolean) { emitTokenWithComment(SyntaxKind.OpenBraceToken, node.pos, writePunctuation, /*contextNode*/ node); - const format = forceSingleLine || getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineBlockStatements : ListFormat.MultiLineBlockStatements; + const format = forceSingleLine || getEmitFlags(node) & EmitFlags.SingleLine + ? ListFormat.SingleLineBlockStatements : ListFormat.MultiLineBlockStatements; emitList(node, node.statements, format); - emitTokenWithComment(SyntaxKind.CloseBraceToken, node.statements.end, writePunctuation, /*contextNode*/ node, /*indentLeading*/ !!(format & ListFormat.MultiLine)); + emitTokenWithComment( + SyntaxKind.CloseBraceToken, + node.statements.end, + writePunctuation, + /*contextNode*/ node, + /*indentLeading*/ !!(format & ListFormat.MultiLine), + ); } function emitVariableStatement(node: VariableStatement) { @@ -3493,11 +3821,26 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeSpace(); let pos = emitTokenWithComment(SyntaxKind.OpenParenToken, openParenPos, writePunctuation, /*contextNode*/ node); emitForBinding(node.initializer); - pos = emitTokenWithComment(SyntaxKind.SemicolonToken, node.initializer ? node.initializer.end : pos, writePunctuation, node); + pos = emitTokenWithComment( + SyntaxKind.SemicolonToken, + node.initializer ? node.initializer.end : pos, + writePunctuation, + node, + ); emitExpressionWithLeadingSpace(node.condition); - pos = emitTokenWithComment(SyntaxKind.SemicolonToken, node.condition ? node.condition.end : pos, writePunctuation, node); + pos = emitTokenWithComment( + SyntaxKind.SemicolonToken, + node.condition ? node.condition.end : pos, + writePunctuation, + node, + ); emitExpressionWithLeadingSpace(node.incrementor); - emitTokenWithComment(SyntaxKind.CloseParenToken, node.incrementor ? node.incrementor.end : pos, writePunctuation, node); + emitTokenWithComment( + SyntaxKind.CloseParenToken, + node.incrementor ? node.incrementor.end : pos, + writePunctuation, + node, + ); emitEmbeddedStatement(node, node.statement); } @@ -3551,7 +3894,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeTrailingSemicolon(); } - function emitTokenWithComment(token: SyntaxKind, pos: number, writer: (s: string) => void, contextNode: Node, indentLeading?: boolean) { + function emitTokenWithComment( + token: SyntaxKind, + pos: number, + writer: (s: string) => void, + contextNode: Node, + indentLeading?: boolean, + ) { const node = getParseTreeNode(contextNode); const isSimilarNode = node && node.kind === contextNode.kind; const startPos = pos; @@ -3559,7 +3908,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri pos = skipTrivia(currentSourceFile.text, pos); } if (isSimilarNode && contextNode.pos !== startPos) { - const needsIndent = indentLeading && currentSourceFile && !positionsAreOnSameLine(startPos, pos, currentSourceFile); + const needsIndent = indentLeading && currentSourceFile + && !positionsAreOnSameLine(startPos, pos, currentSourceFile); if (needsIndent) { increaseIndent(); } @@ -3586,7 +3936,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri if (some(getSyntheticLeadingComments(node), commentWillEmitNewLine)) return true; if (isPartiallyEmittedExpression(node)) { if (node.pos !== node.expression.pos) { - if (some(getTrailingCommentRanges(currentSourceFile.text, node.expression.pos), commentWillEmitNewLine)) return true; + if ( + some(getTrailingCommentRanges(currentSourceFile.text, node.expression.pos), commentWillEmitNewLine) + ) return true; } return willEmitLeadingNewLine(node.expression); } @@ -3618,7 +3970,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitReturnStatement(node: ReturnStatement) { emitTokenWithComment(SyntaxKind.ReturnKeyword, node.pos, writeKeyword, /*contextNode*/ node); - emitExpressionWithLeadingSpace(node.expression && parenthesizeExpressionForNoAsi(node.expression), parenthesizeExpressionForNoAsi); + emitExpressionWithLeadingSpace( + node.expression && parenthesizeExpressionForNoAsi(node.expression), + parenthesizeExpressionForNoAsi, + ); writeTrailingSemicolon(); } @@ -3664,7 +4019,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } if (node.finallyBlock) { writeLineOrSpace(node, node.catchClause || node.tryBlock, node.finallyBlock); - emitTokenWithComment(SyntaxKind.FinallyKeyword, (node.catchClause || node.tryBlock).end, writeKeyword, node); + emitTokenWithComment( + SyntaxKind.FinallyKeyword, + (node.catchClause || node.tryBlock).end, + writeKeyword, + node, + ); writeSpace(); emit(node.finallyBlock); } @@ -3683,7 +4043,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emit(node.name); emit(node.exclamationToken); emitTypeAnnotation(node.type); - emitInitializer(node.initializer, node.type?.end ?? node.name.emitNode?.typeNode?.end ?? node.name.end, node, parenthesizer.parenthesizeExpressionForDisallowedComma); + emitInitializer( + node.initializer, + node.type?.end ?? node.name.emitNode?.typeNode?.end ?? node.name.end, + node, + parenthesizer.parenthesizeExpressionForDisallowedComma, + ); } function emitVariableDeclarationList(node: VariableDeclarationList) { @@ -3693,10 +4058,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeKeyword("using"); } else { - const head = isLet(node) ? "let" : - isVarConst(node) ? "const" : - isVarUsing(node) ? "using" : - "var"; + const head = isLet(node) ? "let" + : isVarConst(node) ? "const" + : isVarUsing(node) ? "using" + : "var"; writeKeyword(head); } writeSpace(); @@ -3747,7 +4112,6 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitSignatureHead(node); writeTrailingSemicolon(); } - } function emitSignatureHead(node: SignatureDeclaration) { @@ -3777,8 +4141,15 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return false; } - if (getLeadingLineTerminatorCount(body, firstOrUndefined(body.statements), ListFormat.PreserveLines) - || getClosingLineTerminatorCount(body, lastOrUndefined(body.statements), ListFormat.PreserveLines, body.statements)) { + if ( + getLeadingLineTerminatorCount(body, firstOrUndefined(body.statements), ListFormat.PreserveLines) + || getClosingLineTerminatorCount( + body, + lastOrUndefined(body.statements), + ListFormat.PreserveLines, + body.statements, + ) + ) { return false; } @@ -3826,7 +4197,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri increaseIndent(); } else { - emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, /*parenthesizerRule*/ undefined, statementOffset); + emitList( + body, + body.statements, + ListFormat.MultiLineFunctionBodyStatements, + /*parenthesizerRule*/ undefined, + statementOffset, + ); } } @@ -3940,12 +4317,23 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitCaseBlock(node: CaseBlock) { emitTokenWithComment(SyntaxKind.OpenBraceToken, node.pos, writePunctuation, node); emitList(node, node.clauses, ListFormat.CaseBlockClauses); - emitTokenWithComment(SyntaxKind.CloseBraceToken, node.clauses.end, writePunctuation, node, /*indentLeading*/ true); + emitTokenWithComment( + SyntaxKind.CloseBraceToken, + node.clauses.end, + writePunctuation, + node, + /*indentLeading*/ true, + ); } function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { emitDecoratorsAndModifiers(node, node.modifiers, /*allowDecorators*/ false); - emitTokenWithComment(SyntaxKind.ImportKeyword, node.modifiers ? node.modifiers.end : node.pos, writeKeyword, node); + emitTokenWithComment( + SyntaxKind.ImportKeyword, + node.modifiers ? node.modifiers.end : node.pos, + writeKeyword, + node, + ); writeSpace(); if (node.isTypeOnly) { emitTokenWithComment(SyntaxKind.TypeKeyword, node.pos, writeKeyword, node); @@ -3970,7 +4358,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitImportDeclaration(node: ImportDeclaration) { emitDecoratorsAndModifiers(node, node.modifiers, /*allowDecorators*/ false); - emitTokenWithComment(SyntaxKind.ImportKeyword, node.modifiers ? node.modifiers.end : node.pos, writeKeyword, node); + emitTokenWithComment( + SyntaxKind.ImportKeyword, + node.modifiers ? node.modifiers.end : node.pos, + writeKeyword, + node, + ); writeSpace(); if (node.importClause) { emit(node.importClause); @@ -4024,9 +4417,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitTokenWithComment(SyntaxKind.DefaultKeyword, nextPos, writeKeyword, node); } writeSpace(); - emitExpression(node.expression, node.isExportEquals ? - parenthesizer.getParenthesizeRightSideOfBinaryForOperator(SyntaxKind.EqualsToken) : - parenthesizer.parenthesizeExpressionOfExportDefault); + emitExpression( + node.expression, + node.isExportEquals + ? parenthesizer.getParenthesizeRightSideOfBinaryForOperator(SyntaxKind.EqualsToken) + : parenthesizer.parenthesizeExpressionOfExportDefault, + ); writeTrailingSemicolon(); } @@ -4225,7 +4621,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitJsxExpression(node: JsxExpression) { if (node.expression || (!commentsDisabled && !nodeIsSynthesized(node) && hasCommentsAtPosition(node.pos))) { // preserve empty expressions if they contain comments! - const isMultiline = currentSourceFile && !nodeIsSynthesized(node) && getLineAndCharacterOfPosition(currentSourceFile, node.pos).line !== getLineAndCharacterOfPosition(currentSourceFile, node.end).line; + const isMultiline = currentSourceFile && !nodeIsSynthesized(node) + && getLineAndCharacterOfPosition(currentSourceFile, node.pos).line + !== getLineAndCharacterOfPosition(currentSourceFile, node.end).line; if (isMultiline) { writer.increaseIndent(); } @@ -4272,14 +4670,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function emitCaseOrDefaultClauseRest(parentNode: Node, statements: NodeArray, colonPos: number) { - const emitAsSingleStatement = - statements.length === 1 && - ( + const emitAsSingleStatement = statements.length === 1 + && ( // treat synthesized nodes as located on the same line for emit purposes - !currentSourceFile || - nodeIsSynthesized(parentNode) || - nodeIsSynthesized(statements[0]) || - rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile) + !currentSourceFile + || nodeIsSynthesized(parentNode) + || nodeIsSynthesized(statements[0]) + || rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile) ); let format = ListFormat.CaseOrDefaultClauseStatements; @@ -4393,7 +4790,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri write("*/"); } - function emitJSDocSimpleTypedTag(tag: JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocReturnTag | JSDocThrowsTag | JSDocSatisfiesTag) { + function emitJSDocSimpleTypedTag( + tag: JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocReturnTag | JSDocThrowsTag | JSDocSatisfiesTag, + ) { emitJSDocTagName(tag.tagName); emitJSDocTypeExpression(tag.typeExpression); emitJSDocComment(tag.comment); @@ -4541,9 +4940,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri const statements = node.statements; // Emit detached comment if there are no prologue directives or if the first node is synthesized. // The synthesized node will have no leading comment so some comments may be missed. - const shouldEmitDetachedComment = statements.length === 0 || - !isPrologueDirective(statements[0]) || - nodeIsSynthesized(statements[0]); + const shouldEmitDetachedComment = statements.length === 0 + || !isPrologueDirective(statements[0]) + || nodeIsSynthesized(statements[0]); if (shouldEmitDetachedComment) { emitBodyWithDetachedComments(node, statements, emitSourceFileWorker); return; @@ -4552,7 +4951,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function emitSyntheticTripleSlashReferencesIfNeeded(node: Bundle) { - emitTripleSlashDirectives(!!node.hasNoDefaultLib, node.syntheticFileReferences || [], node.syntheticTypeReferences || [], node.syntheticLibReferences || []); + emitTripleSlashDirectives( + !!node.hasNoDefaultLib, + node.syntheticFileReferences || [], + node.syntheticTypeReferences || [], + node.syntheticLibReferences || [], + ); for (const prepend of node.prepends) { if (isUnparsedSource(prepend) && prepend.syntheticReferences) { for (const ref of prepend.syntheticReferences) { @@ -4564,14 +4968,32 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function emitTripleSlashDirectivesIfNeeded(node: SourceFile) { - if (node.isDeclarationFile) emitTripleSlashDirectives(node.hasNoDefaultLib, node.referencedFiles, node.typeReferenceDirectives, node.libReferenceDirectives); + if (node.isDeclarationFile) { + emitTripleSlashDirectives( + node.hasNoDefaultLib, + node.referencedFiles, + node.typeReferenceDirectives, + node.libReferenceDirectives, + ); + } } - function emitTripleSlashDirectives(hasNoDefaultLib: boolean, files: readonly FileReference[], types: readonly FileReference[], libs: readonly FileReference[]) { + function emitTripleSlashDirectives( + hasNoDefaultLib: boolean, + files: readonly FileReference[], + types: readonly FileReference[], + libs: readonly FileReference[], + ) { if (hasNoDefaultLib) { const pos = writer.getTextPos(); writeComment(`/// `); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.NoDefaultLib }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.NoDefaultLib, + }); + } writeLine(); } if (currentSourceFile && currentSourceFile.moduleName) { @@ -4592,22 +5014,47 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri for (const directive of files) { const pos = writer.getTextPos(); writeComment(`/// `); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Reference, data: directive.fileName }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.Reference, + data: directive.fileName, + }); + } writeLine(); } for (const directive of types) { const pos = writer.getTextPos(); - const resolutionMode = directive.resolutionMode && directive.resolutionMode !== currentSourceFile?.impliedNodeFormat - ? `resolution-mode="${directive.resolutionMode === ModuleKind.ESNext ? "import" : "require"}"` - : ""; + const resolutionMode = + directive.resolutionMode && directive.resolutionMode !== currentSourceFile?.impliedNodeFormat + ? `resolution-mode="${directive.resolutionMode === ModuleKind.ESNext ? "import" : "require"}"` + : ""; writeComment(`/// `); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: !directive.resolutionMode ? BundleFileSectionKind.Type : directive.resolutionMode === ModuleKind.ESNext ? BundleFileSectionKind.TypeResolutionModeImport : BundleFileSectionKind.TypeResolutionModeRequire, data: directive.fileName }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: !directive.resolutionMode ? BundleFileSectionKind.Type + : directive.resolutionMode === ModuleKind.ESNext + ? BundleFileSectionKind.TypeResolutionModeImport + : BundleFileSectionKind.TypeResolutionModeRequire, + data: directive.fileName, + }); + } writeLine(); } for (const directive of libs) { const pos = writer.getTextPos(); writeComment(`/// `); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Lib, data: directive.fileName }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.Lib, + data: directive.fileName, + }); + } writeLine(); } } @@ -4619,7 +5066,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitHelpers(node); const index = findIndex(statements, statement => !isPrologueDirective(statement)); emitTripleSlashDirectivesIfNeeded(node); - emitList(node, statements, ListFormat.MultiLine, /*parenthesizerRule*/ undefined, index === -1 ? statements.length : index); + emitList( + node, + statements, + ListFormat.MultiLine, + /*parenthesizerRule*/ undefined, + index === -1 ? statements.length : index, + ); popNameGenerationScope(node); } @@ -4644,12 +5097,18 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * Emits any prologue directives at the start of a Statement list, returning the * number of prologue directives written to the output. */ - function emitPrologueDirectives(statements: readonly Node[], sourceFile?: SourceFile, seenPrologueDirectives?: Set, recordBundleFileSection?: true): number { + function emitPrologueDirectives( + statements: readonly Node[], + sourceFile?: SourceFile, + seenPrologueDirectives?: Set, + recordBundleFileSection?: true, + ): number { let needsToSetSourceFile = !!sourceFile; for (let i = 0; i < statements.length; i++) { const statement = statements[i]; if (isPrologueDirective(statement)) { - const shouldEmitPrologueDirective = seenPrologueDirectives ? !seenPrologueDirectives.has(statement.expression.text) : true; + const shouldEmitPrologueDirective = seenPrologueDirectives + ? !seenPrologueDirectives.has(statement.expression.text) : true; if (shouldEmitPrologueDirective) { if (needsToSetSourceFile) { needsToSetSourceFile = false; @@ -4658,7 +5117,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeLine(); const pos = writer.getTextPos(); emit(statement); - if (recordBundleFileSection && bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Prologue, data: statement.expression.text }); + if (recordBundleFileSection && bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.Prologue, + data: statement.expression.text, + }); + } if (seenPrologueDirectives) { seenPrologueDirectives.add(statement.expression.text); } @@ -4679,7 +5145,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writeLine(); const pos = writer.getTextPos(); emit(prologue); - if (bundleFileInfo) bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Prologue, data: prologue.data }); + if (bundleFileInfo) { + bundleFileInfo.sections.push({ + pos, + end: writer.getTextPos(), + kind: BundleFileSectionKind.Prologue, + data: prologue.data, + }); + } if (seenPrologueDirectives) { seenPrologueDirectives.add(prologue.data); } @@ -4697,7 +5170,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitUnparsedPrologues((prepend as UnparsedSource).prologues, seenPrologueDirectives); } for (const sourceFile of sourceFileOrBundle.sourceFiles) { - emitPrologueDirectives(sourceFile.statements, sourceFile, seenPrologueDirectives, /*recordBundleFileSection*/ true); + emitPrologueDirectives( + sourceFile.statements, + sourceFile, + seenPrologueDirectives, + /*recordBundleFileSection*/ true, + ); } setSourceFile(undefined); } @@ -4720,12 +5198,18 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri expression: { pos: statement.expression.pos, end: statement.expression.end, - text: statement.expression.text - } + text: statement.expression.text, + }, }); end = end < statement.end ? statement.end : end; } - if (directives) (prologues || (prologues = [])).push({ file: index, text: sourceFile.text.substring(0, end), directives }); + if (directives) { + (prologues || (prologues = [])).push({ + file: index, + text: sourceFile.text.substring(0, end), + directives, + }); + } } return prologues; } @@ -4767,7 +5251,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri write = savedWrite; } - function emitDecoratorsAndModifiers(node: Node, modifiers: NodeArray | undefined, allowDecorators: boolean) { + function emitDecoratorsAndModifiers( + node: Node, + modifiers: NodeArray | undefined, + allowDecorators: boolean, + ) { if (modifiers?.length) { if (every(modifiers, isModifier)) { // if all modifier-likes are `Modifier`, simply emit the array as modifiers. @@ -4817,7 +5305,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri start, pos - start, /*hasTrailingComma*/ false, - textRange); + textRange, + ); } start = pos; lastMode = mode; @@ -4848,7 +5337,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitInitializer(node: Expression | undefined, equalCommentStartPos: number, container: Node, parenthesizerRule?: (node: Expression) => Expression) { + function emitInitializer( + node: Expression | undefined, + equalCommentStartPos: number, + container: Node, + parenthesizerRule?: (node: Expression) => Expression, + ) { if (node) { writeSpace(); emitTokenWithComment(SyntaxKind.EqualsToken, equalCommentStartPos, writeOperator, container); @@ -4857,7 +5351,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitNodeWithPrefix(prefix: string, prefixWriter: (s: string) => void, node: T | undefined, emit: (node: T) => void) { + function emitNodeWithPrefix( + prefix: string, + prefixWriter: (s: string) => void, + node: T | undefined, + emit: (node: T) => void, + ) { if (node) { prefixWriter(prefix); emit(node); @@ -4871,7 +5370,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitExpressionWithLeadingSpace(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression) { + function emitExpressionWithLeadingSpace( + node: Expression | undefined, + parenthesizerRule?: (node: Expression) => Expression, + ) { if (node) { writeSpace(); emitExpression(node, parenthesizerRule); @@ -4886,9 +5388,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function emitEmbeddedStatement(parent: Node, node: Statement) { - if (isBlock(node) || - getEmitFlags(parent) & EmitFlags.SingleLine || - preserveSourceNewlines && !getLeadingLineTerminatorCount(parent, node, ListFormat.None) + if ( + isBlock(node) + || getEmitFlags(parent) & EmitFlags.SingleLine + || preserveSourceNewlines && !getLeadingLineTerminatorCount(parent, node, ListFormat.None) ) { writeSpace(); emit(node); @@ -4916,7 +5419,15 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitList(parentNode, typeArguments, ListFormat.TypeArguments, typeArgumentParenthesizerRuleSelector); } - function emitTypeParameters(parentNode: SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration | ClassDeclaration | ClassExpression, typeParameters: NodeArray | undefined) { + function emitTypeParameters( + parentNode: + | SignatureDeclaration + | InterfaceDeclaration + | TypeAliasDeclaration + | ClassDeclaration + | ClassExpression, + typeParameters: NodeArray | undefined, + ) { if (isFunctionLike(parentNode) && parentNode.typeArguments) { // Quick info uses type arguments in place of type parameters on instantiated signatures return emitTypeArguments(parentNode, parentNode.typeArguments); } @@ -4927,23 +5438,29 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitList(parentNode, parameters, ListFormat.Parameters); } - function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray) { + function canEmitSimpleArrowHead( + parentNode: FunctionTypeNode | ArrowFunction, + parameters: NodeArray, + ) { const parameter = singleOrUndefined(parameters); return parameter && parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter - && isArrowFunction(parentNode) // only arrow functions may have simple arrow head - && !parentNode.type // arrow function may not have return type annotation - && !some(parentNode.modifiers) // parent may not have decorators or modifiers + && isArrowFunction(parentNode) // only arrow functions may have simple arrow head + && !parentNode.type // arrow function may not have return type annotation + && !some(parentNode.modifiers) // parent may not have decorators or modifiers && !some(parentNode.typeParameters) // parent may not have type parameters - && !some(parameter.modifiers) // parameter may not have decorators or modifiers - && !parameter.dotDotDotToken // parameter may not be rest - && !parameter.questionToken // parameter may not be optional - && !parameter.type // parameter may not have a type annotation - && !parameter.initializer // parameter may not have an initializer - && isIdentifier(parameter.name); // parameter name must be identifier - } - - function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray) { + && !some(parameter.modifiers) // parameter may not have decorators or modifiers + && !parameter.dotDotDotToken // parameter may not be rest + && !parameter.questionToken // parameter may not be optional + && !parameter.type // parameter may not have a type annotation + && !parameter.initializer // parameter may not have an initializer + && isIdentifier(parameter.name); // parameter name must be identifier + } + + function emitParametersForArrow( + parentNode: FunctionTypeNode | ArrowFunction, + parameters: NodeArray, + ) { if (canEmitSimpleArrowHead(parentNode, parameters)) { emitList(parentNode, parameters, ListFormat.Parameters & ~ListFormat.Parenthesis); } @@ -4979,7 +5496,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitList>(parentNode: Node | undefined, children: Children | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { + function emitList>( + parentNode: Node | undefined, + children: Children | undefined, + format: ListFormat, + parenthesizerRule?: ParenthesizerRuleOrSelector, + start?: number, + count?: number, + ) { emitNodeList( emit, parentNode, @@ -4987,14 +5511,30 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri format | (parentNode && getEmitFlags(parentNode) & EmitFlags.MultiLine ? ListFormat.PreferNewLine : 0), parenthesizerRule, start, - count); + count, + ); } - function emitExpressionList>(parentNode: Node | undefined, children: Children | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { + function emitExpressionList>( + parentNode: Node | undefined, + children: Children | undefined, + format: ListFormat, + parenthesizerRule?: ParenthesizerRuleOrSelector, + start?: number, + count?: number, + ) { emitNodeList(emitExpression, parentNode, children, format, parenthesizerRule, start, count); } - function emitNodeList>(emit: EmitFunction, parentNode: Node | undefined, children: Children | undefined, format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start = 0, count = children ? children.length - start : 0) { + function emitNodeList>( + emit: EmitFunction, + parentNode: Node | undefined, + children: Children | undefined, + format: ListFormat, + parenthesizerRule: ParenthesizerRuleOrSelector | undefined, + start = 0, + count = children ? children.length - start : 0, + ) { const isUndefined = children === undefined; if (isUndefined && format & ListFormat.OptionalIfUndefined) { return; @@ -5018,7 +5558,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri if (isEmpty) { // Write a line terminator if the parent node was multi-line - if (format & ListFormat.MultiLine && !(preserveSourceNewlines && (!parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile)))) { + if ( + format & ListFormat.MultiLine + && !(preserveSourceNewlines + && (!parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile))) + ) { writeLine(); } else if (format & ListFormat.SpaceBetweenBraces && !(format & ListFormat.NoSpaceIfEmpty)) { @@ -5026,7 +5570,17 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } else { - emitNodeListItems(emit, parentNode, children, format, parenthesizerRule, start, count, children.hasTrailingComma, children); + emitNodeListItems( + emit, + parentNode, + children, + format, + parenthesizerRule, + start, + count, + children.hasTrailingComma, + children, + ); } onAfterEmitNodeArray?.(children); @@ -5044,7 +5598,17 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * * NOTE: You probably don't want to call this directly and should be using `emitList` or `emitExpressionList` instead. */ - function emitNodeListItems(emit: EmitFunction, parentNode: Node | undefined, children: readonly Child[], format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start: number, count: number, hasTrailingComma: boolean, childrenTextRange: TextRange | undefined) { + function emitNodeListItems( + emit: EmitFunction, + parentNode: Node | undefined, + children: readonly Child[], + format: ListFormat, + parenthesizerRule: ParenthesizerRuleOrSelector | undefined, + start: number, + count: number, + hasTrailingComma: boolean, + childrenTextRange: TextRange | undefined, + ) { // Write the opening line terminator or leading whitespace. const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0; let shouldEmitInterveningComments = mayEmitInterveningComments; @@ -5137,7 +5701,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri // Write a trailing comma, if requested. const emitFlags = previousSibling ? getEmitFlags(previousSibling) : 0; const skipTrailingComments = commentsDisabled || !!(emitFlags & EmitFlags.NoTrailingComments); - const emitTrailingComma = hasTrailingComma && (format & ListFormat.AllowTrailingComma) && (format & ListFormat.CommaDelimited); + const emitTrailingComma = hasTrailingComma && (format & ListFormat.AllowTrailingComma) + && (format & ListFormat.CommaDelimited); if (emitTrailingComma) { if (previousSibling && !skipTrailingComments) { emitTokenWithComment(SyntaxKind.CommaToken, previousSibling.end, writePunctuation, previousSibling); @@ -5153,8 +5718,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri // 2 // /* end of element 2 */ // ]; - if (previousSibling && (parentNode ? parentNode.end : -1) !== previousSibling.end && (format & ListFormat.DelimitersMask) && !skipTrailingComments) { - emitLeadingCommentsOfPosition(emitTrailingComma && childrenTextRange?.end ? childrenTextRange.end : previousSibling.end); + if ( + previousSibling && (parentNode ? parentNode.end : -1) !== previousSibling.end + && (format & ListFormat.DelimitersMask) && !skipTrailingComments + ) { + emitLeadingCommentsOfPosition( + emitTrailingComma && childrenTextRange?.end ? childrenTextRange.end : previousSibling.end, + ); } // Decrease the indent, if requested. @@ -5165,7 +5735,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri recordBundleFileInternalSectionEnd(previousSourceFileTextKind); // Write the closing line terminator or closing whitespace. - const closingLineTerminatorCount = getClosingLineTerminatorCount(parentNode, children[start + count - 1], format, childrenTextRange); + const closingLineTerminatorCount = getClosingLineTerminatorCount( + parentNode, + children[start + count - 1], + format, + childrenTextRange, + ); if (closingLineTerminatorCount) { writeLine(closingLineTerminatorCount); } @@ -5325,7 +5900,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function getLeadingLineTerminatorCount(parentNode: Node | undefined, firstChild: Node | undefined, format: ListFormat): number { + function getLeadingLineTerminatorCount( + parentNode: Node | undefined, + firstChild: Node | undefined, + format: ListFormat, + ): number { if (format & ListFormat.PreserveLines || preserveSourceNewlines) { if (format & ListFormat.PreferNewLine) { return 1; @@ -5356,18 +5935,22 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri // JsxText will be written with its leading whitespace, so don't add more manually. return 0; } - if (currentSourceFile && parentNode && - !positionIsSynthesized(parentNode.pos) && - !nodeIsSynthesized(firstChild) && - (!firstChild.parent || getOriginalNode(firstChild.parent) === getOriginalNode(parentNode)) + if ( + currentSourceFile && parentNode + && !positionIsSynthesized(parentNode.pos) + && !nodeIsSynthesized(firstChild) + && (!firstChild.parent || getOriginalNode(firstChild.parent) === getOriginalNode(parentNode)) ) { if (preserveSourceNewlines) { return getEffectiveLines( - includeComments => getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter( - firstChild.pos, - parentNode.pos, - currentSourceFile!, - includeComments)); + includeComments => + getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter( + firstChild.pos, + parentNode.pos, + currentSourceFile!, + includeComments, + ), + ); } return rangeStartPositionsAreOnSameLine(parentNode, firstChild, currentSourceFile) ? 0 : 1; } @@ -5378,7 +5961,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return format & ListFormat.MultiLine ? 1 : 0; } - function getSeparatingLineTerminatorCount(previousNode: Node | undefined, nextNode: Node, format: ListFormat): number { + function getSeparatingLineTerminatorCount( + previousNode: Node | undefined, + nextNode: Node, + format: ListFormat, + ): number { if (format & ListFormat.PreserveLines || preserveSourceNewlines) { if (previousNode === undefined || nextNode === undefined) { return 0; @@ -5390,11 +5977,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri else if (currentSourceFile && !nodeIsSynthesized(previousNode) && !nodeIsSynthesized(nextNode)) { if (preserveSourceNewlines && siblingNodePositionsAreComparable(previousNode, nextNode)) { return getEffectiveLines( - includeComments => getLinesBetweenRangeEndAndRangeStart( - previousNode, - nextNode, - currentSourceFile!, - includeComments)); + includeComments => + getLinesBetweenRangeEndAndRangeStart( + previousNode, + nextNode, + currentSourceFile!, + includeComments, + ), + ); } // If `preserveSourceNewlines` is `false` we do not intend to preserve the effective lines between the // previous and next node. Instead we naively check whether nodes are on separate lines within the @@ -5408,7 +5998,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri // whether new lines are preferred or not. return format & ListFormat.PreferNewLine ? 1 : 0; } - else if (synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format)) { + else if ( + synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format) + ) { return 1; } } @@ -5418,7 +6010,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return format & ListFormat.MultiLine ? 1 : 0; } - function getClosingLineTerminatorCount(parentNode: Node | undefined, lastChild: Node | undefined, format: ListFormat, childrenTextRange: TextRange | undefined): number { + function getClosingLineTerminatorCount( + parentNode: Node | undefined, + lastChild: Node | undefined, + format: ListFormat, + childrenTextRange: TextRange | undefined, + ): number { if (format & ListFormat.PreserveLines || preserveSourceNewlines) { if (format & ListFormat.PreferNewLine) { return 1; @@ -5427,15 +6024,22 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri if (lastChild === undefined) { return !parentNode || currentSourceFile && rangeIsOnSingleLine(parentNode, currentSourceFile) ? 0 : 1; } - if (currentSourceFile && parentNode && !positionIsSynthesized(parentNode.pos) && !nodeIsSynthesized(lastChild) && (!lastChild.parent || lastChild.parent === parentNode)) { + if ( + currentSourceFile && parentNode && !positionIsSynthesized(parentNode.pos) + && !nodeIsSynthesized(lastChild) && (!lastChild.parent || lastChild.parent === parentNode) + ) { if (preserveSourceNewlines) { - const end = childrenTextRange && !positionIsSynthesized(childrenTextRange.end) ? childrenTextRange.end : lastChild.end; + const end = childrenTextRange && !positionIsSynthesized(childrenTextRange.end) + ? childrenTextRange.end : lastChild.end; return getEffectiveLines( - includeComments => getLinesBetweenPositionAndNextNonWhitespaceCharacter( - end, - parentNode.end, - currentSourceFile!, - includeComments)); + includeComments => + getLinesBetweenPositionAndNextNonWhitespaceCharacter( + end, + parentNode.end, + currentSourceFile!, + includeComments, + ), + ); } return rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile) ? 0 : 1; } @@ -5482,7 +6086,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function writeLineSeparatorsAfter(node: Node, parent: Node) { - const trailingNewlines = preserveSourceNewlines && getClosingLineTerminatorCount(parent, node, ListFormat.None, /*childrenTextRange*/ undefined); + const trailingNewlines = preserveSourceNewlines + && getClosingLineTerminatorCount(parent, node, ListFormat.None, /*childrenTextRange*/ undefined); if (trailingNewlines) { writeLine(trailingNewlines); } @@ -5518,11 +6123,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri if (currentSourceFile && !nodeIsSynthesized(parent) && !nodeIsSynthesized(node1) && !nodeIsSynthesized(node2)) { if (preserveSourceNewlines) { return getEffectiveLines( - includeComments => getLinesBetweenRangeEndAndRangeStart( - node1, - node2, - currentSourceFile!, - includeComments)); + includeComments => + getLinesBetweenRangeEndAndRangeStart( + node1, + node2, + currentSourceFile!, + includeComments, + ), + ); } return rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile) ? 0 : 1; } @@ -5543,7 +6151,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return node; } - function getTextOfNode(node: Identifier | PrivateIdentifier | LiteralExpression | JsxNamespacedName, includeTrivia?: boolean): string { + function getTextOfNode( + node: Identifier | PrivateIdentifier | LiteralExpression | JsxNamespacedName, + includeTrivia?: boolean, + ): string { if (isGeneratedIdentifier(node) || isGeneratedPrivateIdentifier(node)) { return generateName(node); } @@ -5571,14 +6182,21 @@ 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, + 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)) { + if ( + isIdentifier(textSourceNode) || isPrivateIdentifier(textSourceNode) || isNumericLiteral(textSourceNode) + || isJsxNamespacedName(textSourceNode) + ) { const text = isNumericLiteral(textSourceNode) ? textSourceNode.text : getTextOfNode(textSourceNode); - return jsxAttributeEscape ? `"${escapeJsxAttributeString(text)}"` : - neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? `"${escapeString(text)}"` : - `"${escapeNonAsciiString(text)}"`; + return jsxAttributeEscape ? `"${escapeJsxAttributeString(text)}"` + : neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? `"${escapeString(text)}"` + : `"${escapeNonAsciiString(text)}"`; } else { return getLiteralTextOfNode(textSourceNode, neverAsciiEscape, jsxAttributeEscape); @@ -5588,7 +6206,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri const flags = (neverAsciiEscape ? GetLiteralTextFlags.NeverAsciiEscape : 0) | (jsxAttributeEscape ? GetLiteralTextFlags.JsxAttributeEscape : 0) | (printerOptions.terminateUnterminatedLiterals ? GetLiteralTextFlags.TerminateUnterminatedLiterals : 0) - | (printerOptions.target && printerOptions.target === ScriptTarget.ESNext ? GetLiteralTextFlags.AllowNumericSeparator : 0); + | (printerOptions.target && printerOptions.target === ScriptTarget.ESNext + ? GetLiteralTextFlags.AllowNumericSeparator : 0); return getLiteralText(node, currentSourceFile, flags); } @@ -5629,7 +6248,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri /** * Push a new member name generation scope. */ - function pushPrivateNameGenerationScope(newPrivateNameTempFlags: TempFlags, newReservedMemberNames: Set | undefined) { + function pushPrivateNameGenerationScope( + newPrivateNameTempFlags: TempFlags, + newReservedMemberNames: Set | undefined, + ) { privateNameTempFlagsStack.push(privateNameTempFlags); privateNameTempFlags = newPrivateNameTempFlags; reservedPrivateNamesStack.push(reservedNames); @@ -5770,20 +6392,40 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri if ((autoGenerate.flags & GeneratedIdentifierFlags.KindMask) === GeneratedIdentifierFlags.Node) { // Node names generate unique names based on their original node // and are cached based on that node's id. - return generateNameCached(getNodeForGeneratedName(name), isPrivateIdentifier(name), autoGenerate.flags, autoGenerate.prefix, autoGenerate.suffix); + return generateNameCached( + getNodeForGeneratedName(name), + isPrivateIdentifier(name), + autoGenerate.flags, + autoGenerate.prefix, + autoGenerate.suffix, + ); } else { // Auto, Loop, and Unique names are cached based on their unique // autoGenerateId. const autoGenerateId = autoGenerate.id; - return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name)); + return autoGeneratedIdToGeneratedName[autoGenerateId] + || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name)); } } - function generateNameCached(node: Node, privateName: boolean, flags?: GeneratedIdentifierFlags, prefix?: string | GeneratedNamePart, suffix?: string) { + function generateNameCached( + node: Node, + privateName: boolean, + flags?: GeneratedIdentifierFlags, + prefix?: string | GeneratedNamePart, + suffix?: string, + ) { const nodeId = getNodeId(node); const cache = privateName ? nodeIdToGeneratedPrivateName : nodeIdToGeneratedName; - return cache[nodeId] || (cache[nodeId] = generateNameForNode(node, privateName, flags ?? GeneratedIdentifierFlags.None, formatGeneratedNamePart(prefix, generateName), formatGeneratedNamePart(suffix))); + return cache[nodeId] + || (cache[nodeId] = generateNameForNode( + node, + privateName, + flags ?? GeneratedIdentifierFlags.None, + formatGeneratedNamePart(prefix, generateName), + formatGeneratedNamePart(suffix), + )); } /** @@ -5857,7 +6499,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name. * Note that names generated by makeTempVariableName and makeUniqueName will never conflict. */ - function makeTempVariableName(flags: TempFlags, reservedInNestedScopes: boolean, privateName: boolean, prefix: string, suffix: string): string { + function makeTempVariableName( + flags: TempFlags, + reservedInNestedScopes: boolean, + privateName: boolean, + prefix: string, + suffix: string, + ): string { if (prefix.length > 0 && prefix.charCodeAt(0) === CharacterCodes.hash) { prefix = prefix.slice(1); } @@ -5912,7 +6560,15 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * makeUniqueName are guaranteed to never conflict. * If `optimistic` is set, the first instance will use 'baseName' verbatim instead of 'baseName_1' */ - function makeUniqueName(baseName: string, checkFn: (name: string, privateName: boolean) => boolean = isUniqueName, optimistic: boolean, scoped: boolean, privateName: boolean, prefix: string, suffix: string): string { + function makeUniqueName( + baseName: string, + checkFn: (name: string, privateName: boolean) => boolean = isUniqueName, + optimistic: boolean, + scoped: boolean, + privateName: boolean, + prefix: string, + suffix: string, + ): string { if (baseName.length > 0 && baseName.charCodeAt(0) === CharacterCodes.hash) { baseName = baseName.slice(1); } @@ -5958,7 +6614,15 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function makeFileLevelOptimisticUniqueName(name: string) { - return makeUniqueName(name, isFileLevelUniqueNameInCurrentFile, /*optimistic*/ true, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + return makeUniqueName( + name, + isFileLevelUniqueNameInCurrentFile, + /*optimistic*/ true, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } /** @@ -5967,7 +6631,16 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { const name = getTextOfNode(node.name); // Use module/enum name itself if it is unique, otherwise make a unique variation - return isUniqueLocalName(name, tryCast(node, canHaveLocals)) ? name : makeUniqueName(name, isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + return isUniqueLocalName(name, tryCast(node, canHaveLocals)) ? name + : makeUniqueName( + name, + isUniqueName, + /*optimistic*/ false, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } /** @@ -5975,26 +6648,55 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri */ function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { const expr = getExternalModuleName(node)!; // TODO: GH#18217 - const baseName = isStringLiteral(expr) ? - makeIdentifierFromModuleName(expr.text) : "module"; - return makeUniqueName(baseName, isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + const baseName = isStringLiteral(expr) + ? makeIdentifierFromModuleName(expr.text) : "module"; + return makeUniqueName( + baseName, + isUniqueName, + /*optimistic*/ false, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } /** * Generates a unique name for a default export. */ function generateNameForExportDefault() { - return makeUniqueName("default", isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + return makeUniqueName( + "default", + isUniqueName, + /*optimistic*/ false, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } /** * Generates a unique name for a class expression. */ function generateNameForClassExpression() { - return makeUniqueName("class", isUniqueName, /*optimistic*/ false, /*scoped*/ false, /*privateName*/ false, /*prefix*/ "", /*suffix*/ ""); + return makeUniqueName( + "class", + isUniqueName, + /*optimistic*/ false, + /*scoped*/ false, + /*privateName*/ false, + /*prefix*/ "", + /*suffix*/ "", + ); } - function generateNameForMethodOrAccessor(node: MethodDeclaration | AccessorDeclaration, privateName: boolean, prefix: string, suffix: string) { + function generateNameForMethodOrAccessor( + node: MethodDeclaration | AccessorDeclaration, + privateName: boolean, + prefix: string, + suffix: string, + ) { if (isIdentifier(node.name)) { return generateNameCached(node.name, privateName); } @@ -6004,7 +6706,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri /** * Generates a unique name from a node. */ - function generateNameForNode(node: Node, privateName: boolean, flags: GeneratedIdentifierFlags, prefix: string, suffix: string): string { + function generateNameForNode( + node: Node, + privateName: boolean, + flags: GeneratedIdentifierFlags, + prefix: string, + suffix: string, + ): string { switch (node.kind) { case SyntaxKind.Identifier: case SyntaxKind.PrivateIdentifier: @@ -6015,7 +6723,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri !!(flags & GeneratedIdentifierFlags.ReservedInNestedScopes), privateName, prefix, - suffix + suffix, ); case SyntaxKind.ModuleDeclaration: case SyntaxKind.EnumDeclaration: @@ -6043,11 +6751,28 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return generateNameForMethodOrAccessor(node as MethodDeclaration | AccessorDeclaration, privateName, prefix, suffix); + return generateNameForMethodOrAccessor( + node as MethodDeclaration | AccessorDeclaration, + privateName, + prefix, + suffix, + ); case SyntaxKind.ComputedPropertyName: - return makeTempVariableName(TempFlags.Auto, /*reservedInNestedScopes*/ true, privateName, prefix, suffix); + return makeTempVariableName( + TempFlags.Auto, + /*reservedInNestedScopes*/ true, + privateName, + prefix, + suffix, + ); default: - return makeTempVariableName(TempFlags.Auto, /*reservedInNestedScopes*/ false, privateName, prefix, suffix); + return makeTempVariableName( + TempFlags.Auto, + /*reservedInNestedScopes*/ false, + privateName, + prefix, + suffix, + ); } } @@ -6060,23 +6785,44 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri const suffix = formatGeneratedNamePart(autoGenerate.suffix); switch (autoGenerate.flags & GeneratedIdentifierFlags.KindMask) { case GeneratedIdentifierFlags.Auto: - return makeTempVariableName(TempFlags.Auto, !!(autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), isPrivateIdentifier(name), prefix, suffix); + return makeTempVariableName( + TempFlags.Auto, + !!(autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), + isPrivateIdentifier(name), + prefix, + suffix, + ); case GeneratedIdentifierFlags.Loop: Debug.assertNode(name, isIdentifier); - return makeTempVariableName(TempFlags._i, !!(autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), /*privateName*/ false, prefix, suffix); + return makeTempVariableName( + TempFlags._i, + !!(autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), + /*privateName*/ false, + prefix, + suffix, + ); case GeneratedIdentifierFlags.Unique: return makeUniqueName( idText(name), - (autoGenerate.flags & GeneratedIdentifierFlags.FileLevel) ? isFileLevelUniqueNameInCurrentFile : isUniqueName, + (autoGenerate.flags & GeneratedIdentifierFlags.FileLevel) ? isFileLevelUniqueNameInCurrentFile + : isUniqueName, !!(autoGenerate.flags & GeneratedIdentifierFlags.Optimistic), !!(autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), isPrivateIdentifier(name), prefix, - suffix + suffix, ); } - return Debug.fail(`Unsupported GeneratedIdentifierKind: ${Debug.formatEnum(autoGenerate.flags & GeneratedIdentifierFlags.KindMask, (ts as any).GeneratedIdentifierFlags, /*isFlags*/ true)}.`); + return Debug.fail( + `Unsupported GeneratedIdentifierKind: ${ + Debug.formatEnum( + autoGenerate.flags & GeneratedIdentifierFlags.KindMask, + (ts as any).GeneratedIdentifierFlags, + /*isFlags*/ true, + ) + }.`, + ); } // Comments @@ -6102,7 +6848,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitCommentsAfterNode(node: Node, savedContainerPos: number, savedContainerEnd: number, savedDeclarationListContainerEnd: number) { + function emitCommentsAfterNode( + node: Node, + savedContainerPos: number, + savedContainerEnd: number, + savedDeclarationListContainerEnd: number, + ) { const emitFlags = getEmitFlags(node); const commentRange = getCommentRange(node); @@ -6110,10 +6861,26 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri if (emitFlags & EmitFlags.NoNestedComments) { commentsDisabled = false; } - emitTrailingCommentsOfNode(node, emitFlags, commentRange.pos, commentRange.end, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); + emitTrailingCommentsOfNode( + node, + emitFlags, + commentRange.pos, + commentRange.end, + savedContainerPos, + savedContainerEnd, + savedDeclarationListContainerEnd, + ); const typeNode = getTypeNode(node); if (typeNode) { - emitTrailingCommentsOfNode(node, emitFlags, typeNode.pos, typeNode.end, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); + emitTrailingCommentsOfNode( + node, + emitFlags, + typeNode.pos, + typeNode.end, + savedContainerPos, + savedContainerEnd, + savedDeclarationListContainerEnd, + ); } } @@ -6123,8 +6890,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri // We have to explicitly check that the node is JsxText because if the compilerOptions.jsx is "preserve" we will not do any transformation. // It is expensive to walk entire tree just to set one kind of node to have no comments. - const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0 || node.kind === SyntaxKind.JsxText; - const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText; + const skipLeadingComments = pos < 0 || (emitFlags & EmitFlags.NoLeadingComments) !== 0 + || node.kind === SyntaxKind.JsxText; + const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 + || node.kind === SyntaxKind.JsxText; // Save current container state on the stack. if ((pos > 0 || end > 0) && pos !== end) { @@ -6154,9 +6923,18 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri exitComment(); } - function emitTrailingCommentsOfNode(node: Node, emitFlags: EmitFlags, pos: number, end: number, savedContainerPos: number, savedContainerEnd: number, savedDeclarationListContainerEnd: number) { + function emitTrailingCommentsOfNode( + node: Node, + emitFlags: EmitFlags, + pos: number, + end: number, + savedContainerPos: number, + savedContainerEnd: number, + savedDeclarationListContainerEnd: number, + ) { enterComment(); - const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 || node.kind === SyntaxKind.JsxText; + const skipTrailingComments = end < 0 || (emitFlags & EmitFlags.NoTrailingComments) !== 0 + || node.kind === SyntaxKind.JsxText; forEach(getSyntheticTrailingComments(node), emitTrailingSynthesizedComment); if ((pos > 0 || end > 0) && pos !== end) { // Restore previous container state. @@ -6208,7 +6986,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri : `//${comment.text}`; } - function emitBodyWithDetachedComments(node: T, detachedRange: TextRange, emitCallback: (node: T) => void) { + function emitBodyWithDetachedComments( + node: T, + detachedRange: TextRange, + emitCallback: (node: T) => void, + ) { enterComment(); const { pos, end } = detachedRange; const emitFlags = getEmitFlags(node); @@ -6236,7 +7018,6 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } exitComment(); - } function originalNodesHaveSameParent(nodeA: Node, nodeB: Node) { @@ -6260,7 +7041,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri const parentNodeArray = getContainingNodeArray(previousNode); const prevNodeIndex = parentNodeArray?.indexOf(previousNode); - return prevNodeIndex !== undefined && prevNodeIndex > -1 && parentNodeArray!.indexOf(nextNode) === prevNodeIndex + 1; + return prevNodeIndex !== undefined && prevNodeIndex > -1 + && parentNodeArray!.indexOf(nextNode) === prevNodeIndex + 1; } function emitLeadingComments(pos: number, isEmittedNode: boolean) { @@ -6287,13 +7069,25 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) { + function emitTripleSlashLeadingComment( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) { if (isTripleSlashComment(commentPos, commentEnd)) { emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos); } } - function emitNonTripleSlashLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) { + function emitNonTripleSlashLeadingComment( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) { if (!isTripleSlashComment(commentPos, commentEnd)) { emitLeadingComment(commentPos, commentEnd, kind, hasTrailingNewLine, rangePos); } @@ -6306,7 +7100,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return true; } - function emitLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) { + function emitLeadingComment( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) { if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return; if (!hasWrittenComment) { emitNewLineBeforeLeadingCommentOfPosition(getCurrentLineMap(), writer, rangePos, commentPos); @@ -6338,7 +7138,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri forEachTrailingCommentToEmit(pos, emitTrailingComment); } - function emitTrailingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) { + function emitTrailingComment( + commentPos: number, + commentEnd: number, + _kind: SyntaxKind, + hasTrailingNewLine: boolean, + ) { if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return; // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment2*/ if (!writer.isAtStartOfLine()) { @@ -6359,7 +7164,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return; } enterComment(); - forEachTrailingCommentToEmit(pos, prefixSpace ? emitTrailingComment : forceNoNewline ? emitTrailingCommentOfPositionNoNewline : emitTrailingCommentOfPosition); + forEachTrailingCommentToEmit( + pos, + prefixSpace ? emitTrailingComment + : forceNoNewline ? emitTrailingCommentOfPositionNoNewline : emitTrailingCommentOfPosition, + ); exitComment(); } @@ -6376,8 +7185,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitTrailingCommentOfPosition(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean) { - if(!currentSourceFile) return; + function emitTrailingCommentOfPosition( + commentPos: number, + commentEnd: number, + _kind: SyntaxKind, + hasTrailingNewLine: boolean, + ) { + if (!currentSourceFile) return; // trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space emitPos(commentPos); @@ -6392,7 +7206,16 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function forEachLeadingCommentToEmit(pos: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) { + function forEachLeadingCommentToEmit( + pos: number, + cb: ( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) => void, + ) { // Emit the leading comments only if the container's pos doesn't match because the container should take care of emitting these comments if (currentSourceFile && (containerPos === -1 || pos !== containerPos)) { if (hasDetachedComments(pos)) { @@ -6404,9 +7227,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function forEachTrailingCommentToEmit(end: number, cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void) { + function forEachTrailingCommentToEmit( + end: number, + cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean) => void, + ) { // Emit the trailing comments only if the container's end doesn't match because the container should take care of emitting these comments - if (currentSourceFile && (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd))) { + if ( + currentSourceFile && (containerEnd === -1 || (end !== containerEnd && end !== declarationListContainerEnd)) + ) { forEachTrailingCommentRange(currentSourceFile.text, end, cb); } } @@ -6415,7 +7243,15 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return detachedCommentsInfo !== undefined && last(detachedCommentsInfo).nodePos === pos; } - function forEachLeadingCommentWithoutDetachedComments(cb: (commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) => void) { + function forEachLeadingCommentWithoutDetachedComments( + cb: ( + commentPos: number, + commentEnd: number, + kind: SyntaxKind, + hasTrailingNewLine: boolean, + rangePos: number, + ) => void, + ) { if (!currentSourceFile) return; // get the leading comments from detachedPos const pos = last(detachedCommentsInfo!).detachedCommentEndPos; @@ -6430,7 +7266,16 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function emitDetachedCommentsAndUpdateCommentsInfo(range: TextRange) { - const currentDetachedCommentInfo = currentSourceFile && emitDetachedComments(currentSourceFile.text, getCurrentLineMap(), writer, emitComment, range, newLine, commentsDisabled); + const currentDetachedCommentInfo = currentSourceFile + && emitDetachedComments( + currentSourceFile.text, + getCurrentLineMap(), + writer, + emitComment, + range, + newLine, + commentsDisabled, + ); if (currentDetachedCommentInfo) { if (detachedCommentsInfo) { detachedCommentsInfo.push(currentDetachedCommentInfo); @@ -6441,7 +7286,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitComment(text: string, lineMap: readonly number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) { + function emitComment( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + commentPos: number, + commentEnd: number, + newLine: string, + ) { if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return; emitPos(commentPos); writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine); @@ -6488,15 +7340,17 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri parsed, node.parent.sourceMapPath!, node.parent.getLineAndCharacterOfPosition(node.pos), - node.parent.getLineAndCharacterOfPosition(node.end) + node.parent.getLineAndCharacterOfPosition(node.end), ); } } else { const source = sourceMapRange.source || sourceMapSource; - if (node.kind !== SyntaxKind.NotEmittedStatement + if ( + node.kind !== SyntaxKind.NotEmittedStatement && (emitFlags & EmitFlags.NoLeadingSourceMap) === 0 - && sourceMapRange.pos >= 0) { + && sourceMapRange.pos >= 0 + ) { emitSourcePos(sourceMapRange.source || sourceMapSource, skipSourceTrivia(source, sourceMapRange.pos)); } if (emitFlags & EmitFlags.NoNestedSourceMaps) { @@ -6514,9 +7368,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri if (emitFlags & EmitFlags.NoNestedSourceMaps) { sourceMapsDisabled = false; } - if (node.kind !== SyntaxKind.NotEmittedStatement + if ( + node.kind !== SyntaxKind.NotEmittedStatement && (emitFlags & EmitFlags.NoTrailingSourceMap) === 0 - && sourceMapRange.end >= 0) { + && sourceMapRange.end >= 0 + ) { emitSourcePos(sourceMapRange.source || sourceMapSource, sourceMapRange.end); } } @@ -6549,7 +7405,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri sourceMapSourceIndex, sourceLine, sourceCharacter, - /*nameIndex*/ undefined); + /*nameIndex*/ undefined, + ); } function emitSourcePos(source: SourceMapSource, pos: number) { @@ -6573,7 +7430,13 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * @param tokenStartPos The start pos of the token. * @param emitCallback The callback used to emit the token. */ - function emitTokenWithSourceMap(node: Node | undefined, token: SyntaxKind, writer: (s: string) => void, tokenPos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, tokenStartPos: number) => number) { + function emitTokenWithSourceMap( + node: Node | undefined, + token: SyntaxKind, + writer: (s: string) => void, + tokenPos: number, + emitCallback: (token: SyntaxKind, writer: (s: string) => void, tokenStartPos: number) => number, + ) { if (sourceMapsDisabled || node && isInJsonFile(node)) { return emitCallback(token, writer, tokenPos); } @@ -6654,9 +7517,9 @@ function getClosingBracket(format: ListFormat) { // Flags enum to track count of temp variables and a few dedicated names const enum TempFlags { - Auto = 0x00000000, // No preferred name - CountMask = 0x0FFFFFFF, // Temp variable counter - _i = 0x10000000, // Use/preference flag for '_i' + Auto = 0x00000000, // No preferred name + CountMask = 0x0FFFFFFF, // Temp variable counter + _i = 0x10000000, // Use/preference flag for '_i' } interface OrdinalParentheizerRuleSelector { @@ -6668,22 +7531,45 @@ type ParenthesizerRule = (node: T) => T; type ParenthesizerRuleOrSelector = OrdinalParentheizerRuleSelector | ParenthesizerRule; type EmitFunction = (node: T, parenthesizerRule?: ParenthesizerRule) => void; -type EmitListItemFunction = (node: Node, emit: EmitFunction, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, index: number) => void; - -function emitListItemNoParenthesizer(node: Node, emit: EmitFunction, _parenthesizerRule: ParenthesizerRuleOrSelector | undefined, _index: number) { +type EmitListItemFunction = ( + node: Node, + emit: EmitFunction, + parenthesizerRule: ParenthesizerRuleOrSelector | undefined, + index: number, +) => void; + +function emitListItemNoParenthesizer( + node: Node, + emit: EmitFunction, + _parenthesizerRule: ParenthesizerRuleOrSelector | undefined, + _index: number, +) { emit(node); } -function emitListItemWithParenthesizerRuleSelector(node: Node, emit: EmitFunction, parenthesizerRuleSelector: OrdinalParentheizerRuleSelector | undefined, index: number) { +function emitListItemWithParenthesizerRuleSelector( + node: Node, + emit: EmitFunction, + parenthesizerRuleSelector: OrdinalParentheizerRuleSelector | undefined, + index: number, +) { emit(node, parenthesizerRuleSelector!.select(index)); } -function emitListItemWithParenthesizerRule(node: Node, emit: EmitFunction, parenthesizerRule: ParenthesizerRule | undefined, _index: number) { +function emitListItemWithParenthesizerRule( + node: Node, + emit: EmitFunction, + parenthesizerRule: ParenthesizerRule | undefined, + _index: number, +) { emit(node, parenthesizerRule); } -function getEmitListItem(emit: EmitFunction, parenthesizerRule: ParenthesizerRuleOrSelector | undefined): EmitListItemFunction { - return emit.length === 1 ? emitListItemNoParenthesizer as EmitListItemFunction : - typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector as EmitListItemFunction : - emitListItemWithParenthesizerRule as EmitListItemFunction; +function getEmitListItem( + emit: EmitFunction, + parenthesizerRule: ParenthesizerRuleOrSelector | undefined, +): EmitListItemFunction { + return emit.length === 1 ? emitListItemNoParenthesizer as EmitListItemFunction + : typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector as EmitListItemFunction + : emitListItemWithParenthesizerRule as EmitListItemFunction; } diff --git a/src/compiler/factory/baseNodeFactory.ts b/src/compiler/factory/baseNodeFactory.ts index 5641e25703ebe..5fe2d2488ab3b 100644 --- a/src/compiler/factory/baseNodeFactory.ts +++ b/src/compiler/factory/baseNodeFactory.ts @@ -35,26 +35,47 @@ export function createBaseNodeFactory(): BaseNodeFactory { createBaseIdentifierNode, createBasePrivateIdentifierNode, createBaseTokenNode, - createBaseNode + createBaseNode, }; function createBaseSourceFileNode(kind: SyntaxKind.SourceFile): Node { - return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } function createBaseIdentifierNode(kind: SyntaxKind.Identifier): Node { - return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } function createBasePrivateIdentifierNode(kind: SyntaxKind.PrivateIdentifier): Node { - return new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (PrivateIdentifierConstructor + || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } function createBaseTokenNode(kind: SyntaxKind): Node { - return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } function createBaseNode(kind: SyntaxKind): Node { - return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, /*pos*/ -1, /*end*/ -1); + return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))( + kind, + /*pos*/ -1, + /*end*/ -1, + ); } } diff --git a/src/compiler/factory/emitHelpers.ts b/src/compiler/factory/emitHelpers.ts index e198c123f302b..64e59d7b33510 100644 --- a/src/compiler/factory/emitHelpers.ts +++ b/src/compiler/factory/emitHelpers.ts @@ -41,7 +41,7 @@ import { export const enum PrivateIdentifierKind { Field = "f", Method = "m", - Accessor = "a" + Accessor = "a", } /** @@ -88,25 +88,35 @@ export interface ESDecorateClassElementAccess { /** @internal */ export type ESDecorateName = - | { computed: true, name: Expression } - | { computed: false, name: Identifier | PrivateIdentifier } - ; + | { computed: true; name: Expression; } + | { computed: false; name: Identifier | PrivateIdentifier; }; /** @internal */ export type ESDecorateContext = | ESDecorateClassContext - | ESDecorateClassElementContext - ; + | ESDecorateClassElementContext; /** @internal */ export interface EmitHelperFactory { getUnscopedHelperName(name: string): Identifier; // TypeScript Helpers - createDecorateHelper(decoratorExpressions: readonly Expression[], target: Expression, memberName?: Expression, descriptor?: Expression): Expression; + createDecorateHelper( + decoratorExpressions: readonly Expression[], + target: Expression, + memberName?: Expression, + descriptor?: Expression, + ): Expression; createMetadataHelper(metadataKey: string, metadataValue: Expression): Expression; createParamHelper(expression: Expression, parameterOffset: number): Expression; // ES Decorators Helpers - createESDecorateHelper(ctor: Expression, descriptorIn: Expression, decorators: Expression, contextIn: ESDecorateContext, initializers: Expression, extraInitializers: Expression): Expression; + createESDecorateHelper( + ctor: Expression, + descriptorIn: Expression, + decorators: Expression, + contextIn: ESDecorateContext, + initializers: Expression, + extraInitializers: Expression, + ): Expression; createRunInitializersHelper(thisArg: Expression, initializers: Expression, value?: Expression): Expression; // ES2018 Helpers createAssignHelper(attributesSegments: readonly Expression[]): Expression; @@ -115,9 +125,19 @@ export interface EmitHelperFactory { createAsyncDelegatorHelper(expression: Expression): Expression; createAsyncValuesHelper(expression: Expression): Expression; // ES2018 Destructuring Helpers - createRestHelper(value: Expression, elements: readonly BindingOrAssignmentElement[], computedTempVariables: readonly Expression[] | undefined, location: TextRange): Expression; + createRestHelper( + value: Expression, + elements: readonly BindingOrAssignmentElement[], + computedTempVariables: readonly Expression[] | undefined, + location: TextRange, + ): Expression; // ES2017 Helpers - createAwaiterHelper(hasLexicalThis: boolean, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression | undefined, body: Block): Expression; + createAwaiterHelper( + hasLexicalThis: boolean, + hasLexicalArguments: boolean, + promiseConstructor: EntityName | Expression | undefined, + body: Block, + ): Expression; // ES2015 Helpers createExtendsHelper(name: Identifier): Expression; createTemplateObjectHelper(cooked: ArrayLiteralExpression, raw: ArrayLiteralExpression): Expression; @@ -130,14 +150,29 @@ export interface EmitHelperFactory { // ES2015 Generator Helpers createGeneratorHelper(body: FunctionExpression): Expression; // ES Module Helpers - createCreateBindingHelper(module: Expression, inputName: Expression, outputName: Expression | undefined): Expression; + createCreateBindingHelper( + module: Expression, + inputName: Expression, + outputName: Expression | undefined, + ): Expression; createImportStarHelper(expression: Expression): Expression; createImportStarCallbackHelper(): Expression; createImportDefaultHelper(expression: Expression): Expression; createExportStarHelper(moduleExpression: Expression, exportsExpression?: Expression): Expression; // Class Fields Helpers - createClassPrivateFieldGetHelper(receiver: Expression, state: Identifier, kind: PrivateIdentifierKind, f: Identifier | undefined): Expression; - createClassPrivateFieldSetHelper(receiver: Expression, state: Identifier, value: Expression, kind: PrivateIdentifierKind, f: Identifier | undefined): Expression; + createClassPrivateFieldGetHelper( + receiver: Expression, + state: Identifier, + kind: PrivateIdentifierKind, + f: Identifier | undefined, + ): Expression; + createClassPrivateFieldSetHelper( + receiver: Expression, + state: Identifier, + value: Expression, + kind: PrivateIdentifierKind, + f: Identifier | undefined, + ): Expression; createClassPrivateFieldInHelper(state: Identifier, receiver: Expression): Expression; // 'using' helpers createAddDisposableResourceHelper(envBinding: Expression, value: Expression, async: boolean): Expression; @@ -204,7 +239,12 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel // TypeScript Helpers - function createDecorateHelper(decoratorExpressions: Expression[], target: Expression, memberName?: Expression, descriptor?: Expression) { + function createDecorateHelper( + decoratorExpressions: Expression[], + target: Expression, + memberName?: Expression, + descriptor?: Expression, + ) { context.requestEmitHelper(decorateHelper); const argumentsArray: Expression[] = []; @@ -220,7 +260,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__decorate"), /*typeArguments*/ undefined, - argumentsArray + argumentsArray, ); } @@ -231,8 +271,8 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel /*typeArguments*/ undefined, [ factory.createStringLiteral(metadataKey), - metadataValue - ] + metadataValue, + ], ); } @@ -244,10 +284,10 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel /*typeArguments*/ undefined, [ factory.createNumericLiteral(parameterOffset + ""), - expression - ] + expression, + ], ), - location + location, ); } @@ -264,9 +304,9 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel } function createESDecorateClassElementAccessGetMethod(elementName: ESDecorateName) { - const accessor = elementName.computed ? - factory.createElementAccessExpression(factory.createIdentifier("obj"), elementName.name) : - factory.createPropertyAccessExpression(factory.createIdentifier("obj"), elementName.name); + const accessor = elementName.computed + ? factory.createElementAccessExpression(factory.createIdentifier("obj"), elementName.name) + : factory.createPropertyAccessExpression(factory.createIdentifier("obj"), elementName.name); return factory.createPropertyAssignment( "get", @@ -276,54 +316,55 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel [factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, - factory.createIdentifier("obj") + factory.createIdentifier("obj"), )], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, - accessor - ) + accessor, + ), ); } function createESDecorateClassElementAccessSetMethod(elementName: ESDecorateName) { - const accessor = elementName.computed ? - factory.createElementAccessExpression(factory.createIdentifier("obj"), elementName.name) : - factory.createPropertyAccessExpression(factory.createIdentifier("obj"), elementName.name); + const accessor = elementName.computed + ? factory.createElementAccessExpression(factory.createIdentifier("obj"), elementName.name) + : factory.createPropertyAccessExpression(factory.createIdentifier("obj"), elementName.name); return factory.createPropertyAssignment( "set", factory.createArrowFunction( /*modifiers*/ undefined, /*typeParameters*/ undefined, - [factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - factory.createIdentifier("obj") - ), - factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - factory.createIdentifier("value") - )], + [ + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + factory.createIdentifier("obj"), + ), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + factory.createIdentifier("value"), + ), + ], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, factory.createBlock([ factory.createExpressionStatement( factory.createAssignment( accessor, - factory.createIdentifier("value") - ) - ) - ]) - ) + factory.createIdentifier("value"), + ), + ), + ]), + ), ); } function createESDecorateClassElementAccessHasMethod(elementName: ESDecorateName) { - const propertyName = - elementName.computed ? elementName.name : - isIdentifier(elementName.name) ? factory.createStringLiteralFromNode(elementName.name) : - elementName.name; + const propertyName = elementName.computed ? elementName.name + : isIdentifier(elementName.name) ? factory.createStringLiteralFromNode(elementName.name) + : elementName.name; return factory.createPropertyAssignment( "has", @@ -333,16 +374,16 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel [factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, - factory.createIdentifier("obj") + factory.createIdentifier("obj"), )], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, factory.createBinaryExpression( propertyName, SyntaxKind.InKeyword, - factory.createIdentifier("obj") - ) - ) + factory.createIdentifier("obj"), + ), + ), ); } @@ -356,22 +397,45 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel function createESDecorateClassElementContextObject(contextIn: ESDecorateClassElementContext) { const properties = [ - factory.createPropertyAssignment(factory.createIdentifier("kind"), factory.createStringLiteral(contextIn.kind)), - factory.createPropertyAssignment(factory.createIdentifier("name"), contextIn.name.computed ? contextIn.name.name : factory.createStringLiteralFromNode(contextIn.name.name)), - factory.createPropertyAssignment(factory.createIdentifier("static"), contextIn.static ? factory.createTrue() : factory.createFalse()), - factory.createPropertyAssignment(factory.createIdentifier("private"), contextIn.private ? factory.createTrue() : factory.createFalse()), - factory.createPropertyAssignment(factory.createIdentifier("access"), createESDecorateClassElementAccessObject(contextIn.name, contextIn.access)), + factory.createPropertyAssignment( + factory.createIdentifier("kind"), + factory.createStringLiteral(contextIn.kind), + ), + factory.createPropertyAssignment( + factory.createIdentifier("name"), + contextIn.name.computed ? contextIn.name.name + : factory.createStringLiteralFromNode(contextIn.name.name), + ), + factory.createPropertyAssignment( + factory.createIdentifier("static"), + contextIn.static ? factory.createTrue() : factory.createFalse(), + ), + factory.createPropertyAssignment( + factory.createIdentifier("private"), + contextIn.private ? factory.createTrue() : factory.createFalse(), + ), + factory.createPropertyAssignment( + factory.createIdentifier("access"), + createESDecorateClassElementAccessObject(contextIn.name, contextIn.access), + ), factory.createPropertyAssignment(factory.createIdentifier("metadata"), contextIn.metadata), ]; return factory.createObjectLiteralExpression(properties); } function createESDecorateContextObject(contextIn: ESDecorateContext) { - return contextIn.kind === "class" ? createESDecorateClassContextObject(contextIn) : - createESDecorateClassElementContextObject(contextIn); + return contextIn.kind === "class" ? createESDecorateClassContextObject(contextIn) + : createESDecorateClassElementContextObject(contextIn); } - function createESDecorateHelper(ctor: Expression, descriptorIn: Expression, decorators: Expression, contextIn: ESDecorateContext, initializers: Expression, extraInitializers: Expression) { + function createESDecorateHelper( + ctor: Expression, + descriptorIn: Expression, + decorators: Expression, + contextIn: ESDecorateContext, + initializers: Expression, + extraInitializers: Expression, + ) { context.requestEmitHelper(esDecorateHelper); return factory.createCallExpression( getUnscopedHelperName("__esDecorate"), @@ -382,8 +446,9 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel decorators, createESDecorateContextObject(contextIn), initializers, - extraInitializers - ]); + extraInitializers, + ], + ); } function createRunInitializersHelper(thisArg: Expression, initializers: Expression, value?: Expression) { @@ -391,28 +456,32 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__runInitializers"), /*typeArguments*/ undefined, - value ? [thisArg, initializers, value] : [thisArg, initializers] + value ? [thisArg, initializers, value] : [thisArg, initializers], ); } // ES2018 Helpers function createAssignHelper(attributesSegments: Expression[]) { if (getEmitScriptTarget(context.getCompilerOptions()) >= ScriptTarget.ES2015) { - return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("Object"), "assign"), - /*typeArguments*/ undefined, - attributesSegments); + return factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier("Object"), "assign"), + /*typeArguments*/ undefined, + attributesSegments, + ); } context.requestEmitHelper(assignHelper); return factory.createCallExpression( getUnscopedHelperName("__assign"), /*typeArguments*/ undefined, - attributesSegments + attributesSegments, ); } function createAwaitHelper(expression: Expression) { context.requestEmitHelper(awaitHelper); - return factory.createCallExpression(getUnscopedHelperName("__await"), /*typeArguments*/ undefined, [expression]); + return factory.createCallExpression(getUnscopedHelperName("__await"), /*typeArguments*/ undefined, [ + expression, + ]); } function createAsyncGeneratorHelper(generatorFunc: FunctionExpression, hasLexicalThis: boolean) { @@ -420,7 +489,8 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel context.requestEmitHelper(asyncGeneratorHelper); // Mark this node as originally an async function - (generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody | EmitFlags.ReuseTempVariableScope; + (generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody + | EmitFlags.ReuseTempVariableScope; return factory.createCallExpression( getUnscopedHelperName("__asyncGenerator"), @@ -428,8 +498,8 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel [ hasLexicalThis ? factory.createThis() : factory.createVoidZero(), factory.createIdentifier("arguments"), - generatorFunc - ] + generatorFunc, + ], ); } @@ -439,7 +509,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__asyncDelegator"), /*typeArguments*/ undefined, - [expression] + [expression], ); } @@ -448,7 +518,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__asyncValues"), /*typeArguments*/ undefined, - [expression] + [expression], ); } @@ -457,7 +527,12 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel /** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement * `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);` */ - function createRestHelper(value: Expression, elements: readonly BindingOrAssignmentElement[], computedTempVariables: readonly Expression[] | undefined, location: TextRange): Expression { + function createRestHelper( + value: Expression, + elements: readonly BindingOrAssignmentElement[], + computedTempVariables: readonly Expression[] | undefined, + location: TextRange, + ): Expression { context.requestEmitHelper(restHelper); const propertyNames: Expression[] = []; let computedTempVariableOffset = 0; @@ -465,7 +540,10 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel const propertyName = getPropertyNameOfBindingOrAssignmentElement(elements[i]); if (propertyName) { if (isComputedPropertyName(propertyName)) { - Debug.assertIsDefined(computedTempVariables, "Encountered computed property name but 'computedTempVariables' argument was not provided."); + Debug.assertIsDefined( + computedTempVariables, + "Encountered computed property name but 'computedTempVariables' argument was not provided.", + ); const temp = computedTempVariables[computedTempVariableOffset]; computedTempVariableOffset++; // typeof _tmp === "symbol" ? _tmp : _tmp + "" @@ -475,8 +553,8 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel /*questionToken*/ undefined, temp, /*colonToken*/ undefined, - factory.createAdd(temp, factory.createStringLiteral("")) - ) + factory.createAdd(temp, factory.createStringLiteral("")), + ), ); } else { @@ -491,14 +569,20 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel value, setTextRange( factory.createArrayLiteralExpression(propertyNames), - location - )] + location, + ), + ], ); } // ES2017 Helpers - function createAwaiterHelper(hasLexicalThis: boolean, hasLexicalArguments: boolean, promiseConstructor: EntityName | Expression | undefined, body: Block) { + function createAwaiterHelper( + hasLexicalThis: boolean, + hasLexicalArguments: boolean, + promiseConstructor: EntityName | Expression | undefined, + body: Block, + ) { context.requestEmitHelper(awaiterHelper); const generatorFunc = factory.createFunctionExpression( @@ -508,11 +592,12 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel /*typeParameters*/ undefined, /*parameters*/ [], /*type*/ undefined, - body + body, ); // Mark this node as originally an async function - (generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody | EmitFlags.ReuseTempVariableScope; + (generatorFunc.emitNode || (generatorFunc.emitNode = {} as EmitNode)).flags |= EmitFlags.AsyncFunctionBody + | EmitFlags.ReuseTempVariableScope; return factory.createCallExpression( getUnscopedHelperName("__awaiter"), @@ -520,9 +605,10 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel [ hasLexicalThis ? factory.createThis() : factory.createVoidZero(), hasLexicalArguments ? factory.createIdentifier("arguments") : factory.createVoidZero(), - promiseConstructor ? createExpressionFromEntityName(factory, promiseConstructor) : factory.createVoidZero(), - generatorFunc - ] + promiseConstructor ? createExpressionFromEntityName(factory, promiseConstructor) + : factory.createVoidZero(), + generatorFunc, + ], ); } @@ -533,7 +619,13 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__extends"), /*typeArguments*/ undefined, - [name, factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)] + [ + name, + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + ], ); } @@ -542,7 +634,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__makeTemplateObject"), /*typeArguments*/ undefined, - [cooked, raw] + [cooked, raw], ); } @@ -551,7 +643,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__spreadArray"), /*typeArguments*/ undefined, - [to, from, packFrom ? immutableTrue() : immutableFalse()] + [to, from, packFrom ? immutableTrue() : immutableFalse()], ); } @@ -560,7 +652,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__propKey"), /*typeArguments*/ undefined, - [expr] + [expr], ); } @@ -569,7 +661,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return context.factory.createCallExpression( getUnscopedHelperName("__setFunctionName"), /*typeArguments*/ undefined, - prefix ? [f, name, context.factory.createStringLiteral(prefix)] : [f, name] + prefix ? [f, name, context.factory.createStringLiteral(prefix)] : [f, name], ); } @@ -580,7 +672,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__values"), /*typeArguments*/ undefined, - [expression] + [expression], ); } @@ -591,7 +683,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel /*typeArguments*/ undefined, count !== undefined ? [iteratorRecord, factory.createNumericLiteral(count + "")] - : [iteratorRecord] + : [iteratorRecord], ); } @@ -602,7 +694,8 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__generator"), /*typeArguments*/ undefined, - [factory.createThis(), body]); + [factory.createThis(), body], + ); } // ES Module Helpers @@ -612,7 +705,8 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__createBinding"), /*typeArguments*/ undefined, - [factory.createIdentifier("exports"), module, inputName, ...(outputName ? [outputName] : [])]); + [factory.createIdentifier("exports"), module, inputName, ...(outputName ? [outputName] : [])], + ); } function createImportStarHelper(expression: Expression) { @@ -620,7 +714,7 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__importStar"), /*typeArguments*/ undefined, - [expression] + [expression], ); } @@ -634,23 +728,31 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__importDefault"), /*typeArguments*/ undefined, - [expression] + [expression], ); } - function createExportStarHelper(moduleExpression: Expression, exportsExpression: Expression = factory.createIdentifier("exports")) { + function createExportStarHelper( + moduleExpression: Expression, + exportsExpression: Expression = factory.createIdentifier("exports"), + ) { context.requestEmitHelper(exportStarHelper); context.requestEmitHelper(createBindingHelper); return factory.createCallExpression( getUnscopedHelperName("__exportStar"), /*typeArguments*/ undefined, - [moduleExpression, exportsExpression] + [moduleExpression, exportsExpression], ); } // Class Fields Helpers - function createClassPrivateFieldGetHelper(receiver: Expression, state: Identifier, kind: PrivateIdentifierKind, f: Identifier | undefined) { + function createClassPrivateFieldGetHelper( + receiver: Expression, + state: Identifier, + kind: PrivateIdentifierKind, + f: Identifier | undefined, + ) { context.requestEmitHelper(classPrivateFieldGetHelper); let args; if (!f) { @@ -659,10 +761,20 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel else { args = [receiver, state, factory.createStringLiteral(kind), f]; } - return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldGet"), /*typeArguments*/ undefined, args); + return factory.createCallExpression( + getUnscopedHelperName("__classPrivateFieldGet"), + /*typeArguments*/ undefined, + args, + ); } - function createClassPrivateFieldSetHelper(receiver: Expression, state: Identifier, value: Expression, kind: PrivateIdentifierKind, f: Identifier | undefined) { + function createClassPrivateFieldSetHelper( + receiver: Expression, + state: Identifier, + value: Expression, + kind: PrivateIdentifierKind, + f: Identifier | undefined, + ) { context.requestEmitHelper(classPrivateFieldSetHelper); let args; if (!f) { @@ -671,12 +783,20 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel else { args = [receiver, state, value, factory.createStringLiteral(kind), f]; } - return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldSet"), /*typeArguments*/ undefined, args); + return factory.createCallExpression( + getUnscopedHelperName("__classPrivateFieldSet"), + /*typeArguments*/ undefined, + args, + ); } function createClassPrivateFieldInHelper(state: Identifier, receiver: Expression) { context.requestEmitHelper(classPrivateFieldInHelper); - return factory.createCallExpression(getUnscopedHelperName("__classPrivateFieldIn"), /*typeArguments*/ undefined, [state, receiver]); + return factory.createCallExpression( + getUnscopedHelperName("__classPrivateFieldIn"), + /*typeArguments*/ undefined, + [state, receiver], + ); } function createAddDisposableResourceHelper(envBinding: Expression, value: Expression, async: boolean): Expression { @@ -684,13 +804,15 @@ export function createEmitHelperFactory(context: TransformationContext): EmitHel return factory.createCallExpression( getUnscopedHelperName("__addDisposableResource"), /*typeArguments*/ undefined, - [envBinding, value, async ? factory.createTrue() : factory.createFalse()] + [envBinding, value, async ? factory.createTrue() : factory.createFalse()], ); } function createDisposeResourcesHelper(envBinding: Expression) { context.requestEmitHelper(disposeResourcesHelper); - return factory.createCallExpression(getUnscopedHelperName("__disposeResources"), /*typeArguments*/ undefined, [envBinding]); + return factory.createCallExpression(getUnscopedHelperName("__disposeResources"), /*typeArguments*/ undefined, [ + envBinding, + ]); } } @@ -735,7 +857,7 @@ export const decorateHelper: UnscopedEmitHelper = { if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; - };` + };`, }; /** @internal */ @@ -747,7 +869,7 @@ export const metadataHelper: UnscopedEmitHelper = { text: ` var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); - };` + };`, }; /** @internal */ @@ -759,7 +881,7 @@ export const paramHelper: UnscopedEmitHelper = { text: ` var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } - };` + };`, }; // ES Decorators Helpers @@ -796,7 +918,7 @@ export const esDecorateHelper: UnscopedEmitHelper = { } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; - };` + };`, }; /** @internal */ @@ -812,7 +934,7 @@ export const runInitializersHelper: UnscopedEmitHelper = { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; - };` + };`, }; // ES2018 Helpers @@ -834,7 +956,7 @@ export const assignHelper: UnscopedEmitHelper = { return t; }; return __assign.apply(this, arguments); - };` + };`, }; /** @internal */ @@ -843,7 +965,7 @@ export const awaitHelper: UnscopedEmitHelper = { importName: "__await", scoped: false, text: ` - var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }` + var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }`, }; /** @internal */ @@ -863,7 +985,7 @@ export const asyncGeneratorHelper: UnscopedEmitHelper = { function fulfill(value) { resume("next", value); } function reject(value) { resume("throw", value); } function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } - };` + };`, }; /** @internal */ @@ -877,7 +999,7 @@ export const asyncDelegator: UnscopedEmitHelper = { var i, p; return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; } - };` + };`, }; /** @internal */ @@ -892,7 +1014,7 @@ export const asyncValues: UnscopedEmitHelper = { return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } - };` + };`, }; // ES2018 Destructuring Helpers @@ -913,7 +1035,7 @@ export const restHelper: UnscopedEmitHelper = { t[p[i]] = s[p[i]]; } return t; - };` + };`, }; // ES2017 Helpers @@ -933,7 +1055,7 @@ export const awaiterHelper: UnscopedEmitHelper = { function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); - };` + };`, }; // ES2015 Helpers @@ -960,7 +1082,7 @@ export const extendsHelper: UnscopedEmitHelper = { function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; - })();` + })();`, }; /** @internal */ @@ -973,7 +1095,7 @@ export const templateObjectHelper: UnscopedEmitHelper = { var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; - };` + };`, }; /** @internal */ @@ -997,7 +1119,7 @@ export const readHelper: UnscopedEmitHelper = { finally { if (e) throw e.error; } } return ar; - };` + };`, }; /** @internal */ @@ -1014,7 +1136,7 @@ export const spreadArrayHelper: UnscopedEmitHelper = { } } return to.concat(ar || Array.prototype.slice.call(from)); - };` + };`, }; /** @internal */ @@ -1025,7 +1147,7 @@ export const propKeyHelper: UnscopedEmitHelper = { text: ` var __propKey = (this && this.__propKey) || function (x) { return typeof x === "symbol" ? x : "".concat(x); - };` + };`, }; // https://tc39.es/ecma262/#sec-setfunctionname @@ -1038,7 +1160,7 @@ export const setFunctionNameHelper: UnscopedEmitHelper = { var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) { if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); - };` + };`, }; // ES2015 Destructuring Helpers @@ -1059,7 +1181,7 @@ export const valuesHelper: UnscopedEmitHelper = { } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); - };` + };`, }; // ES2015 Generator Helpers @@ -1158,7 +1280,7 @@ export const generatorHelper: UnscopedEmitHelper = { } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } - };` + };`, }; // ES Module Helpers @@ -1180,7 +1302,7 @@ export const createBindingHelper: UnscopedEmitHelper = { }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; - }));` + }));`, }; /** @internal */ @@ -1194,7 +1316,7 @@ export const setModuleDefaultHelper: UnscopedEmitHelper = { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; - });` + });`, }; // emit helper for `import * as Name from "foo"` @@ -1212,7 +1334,7 @@ export const importStarHelper: UnscopedEmitHelper = { if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; - };` + };`, }; // emit helper for `import Name from "foo"` @@ -1224,7 +1346,7 @@ export const importDefaultHelper: UnscopedEmitHelper = { text: ` var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; - };` + };`, }; /** @internal */ @@ -1237,7 +1359,7 @@ export const exportStarHelper: UnscopedEmitHelper = { text: ` var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); - };` + };`, }; /** @@ -1299,7 +1421,7 @@ export const classPrivateFieldGetHelper: UnscopedEmitHelper = { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); - };` + };`, }; /** @@ -1365,7 +1487,7 @@ export const classPrivateFieldSetHelper: UnscopedEmitHelper = { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; - };` + };`, }; /** @@ -1390,7 +1512,7 @@ export const classPrivateFieldInHelper: UnscopedEmitHelper = { var __classPrivateFieldIn = (this && this.__classPrivateFieldIn) || function(state, receiver) { if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); return typeof state === "function" ? receiver === state : state.has(receiver); - };` + };`, }; /** @@ -1420,7 +1542,7 @@ export const addDisposableResourceHelper: UnscopedEmitHelper = { env.stack.push({ async: true }); } return value; - };` + };`, }; /** @@ -1455,7 +1577,7 @@ export const disposeResourcesHelper: UnscopedEmitHelper = { })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; - });` + });`, }; let allUnscopedEmitHelpers: ReadonlyMap | undefined; @@ -1501,7 +1623,7 @@ export const asyncSuperHelper: EmitHelper = { name: "typescript:async-super", scoped: true, text: helperString` - const ${"_superIndex"} = name => super[name];` + const ${"_superIndex"} = name => super[name];`, }; /** @internal */ @@ -1512,7 +1634,7 @@ export const advancedAsyncSuperHelper: EmitHelper = { const ${"_superIndex"} = (function (geti, seti) { const cache = Object.create(null); return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } }); - })(name => super[name], (name, value) => super[name] = value);` + })(name => super[name], (name, value) => super[name] = value);`, }; /** @internal */ diff --git a/src/compiler/factory/emitNode.ts b/src/compiler/factory/emitNode.ts index fba507d899ea7..edcbbd0cfb245 100644 --- a/src/compiler/factory/emitNode.ts +++ b/src/compiler/factory/emitNode.ts @@ -43,14 +43,18 @@ export function getOrCreateEmitNode(node: Node): EmitNode { return node.emitNode = { annotatedNodes: [node] } as EmitNode; } - const sourceFile = getSourceFileOfNode(getParseTreeNode(getSourceFileOfNode(node))) ?? Debug.fail("Could not determine parsed source file."); + const sourceFile = getSourceFileOfNode(getParseTreeNode(getSourceFileOfNode(node))) + ?? Debug.fail("Could not determine parsed source file."); getOrCreateEmitNode(sourceFile).annotatedNodes!.push(node); } node.emitNode = {} as EmitNode; } else { - Debug.assert(!(node.emitNode.internalFlags & InternalEmitFlags.Immutable), "Invalid attempt to mutate an immutable node."); + Debug.assert( + !(node.emitNode.internalFlags & InternalEmitFlags.Immutable), + "Invalid attempt to mutate an immutable node.", + ); } return node.emitNode; } @@ -201,8 +205,22 @@ export function setSyntheticLeadingComments(node: T, comments: S return node; } -export function addSyntheticLeadingComment(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) { - return setSyntheticLeadingComments(node, append(getSyntheticLeadingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text })); +export function addSyntheticLeadingComment( + node: T, + kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, + text: string, + hasTrailingNewLine?: boolean, +) { + return setSyntheticLeadingComments( + node, + append(getSyntheticLeadingComments(node), { + kind, + pos: -1, + end: -1, + hasTrailingNewLine, + text, + }), + ); } export function getSyntheticTrailingComments(node: Node): SynthesizedComment[] | undefined { @@ -214,8 +232,22 @@ export function setSyntheticTrailingComments(node: T, comments: return node; } -export function addSyntheticTrailingComment(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) { - return setSyntheticTrailingComments(node, append(getSyntheticTrailingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text })); +export function addSyntheticTrailingComment( + node: T, + kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, + text: string, + hasTrailingNewLine?: boolean, +) { + return setSyntheticTrailingComments( + node, + append(getSyntheticTrailingComments(node), { + kind, + pos: -1, + end: -1, + hasTrailingNewLine, + text, + }), + ); } export function moveSyntheticComments(node: T, original: Node): T { @@ -348,18 +380,26 @@ export function getTypeNode(node: T): TypeNode | undefined { } /** @internal */ -export function setIdentifierTypeArguments(node: T, typeArguments: NodeArray | undefined) { +export function setIdentifierTypeArguments( + node: T, + typeArguments: NodeArray | undefined, +) { getOrCreateEmitNode(node).identifierTypeArguments = typeArguments; return node; } /** @internal */ -export function getIdentifierTypeArguments(node: Identifier): NodeArray | undefined { +export function getIdentifierTypeArguments( + node: Identifier, +): NodeArray | undefined { return node.emitNode?.identifierTypeArguments; } /** @internal */ -export function setIdentifierAutoGenerate(node: T, autoGenerate: AutoGenerateInfo | undefined) { +export function setIdentifierAutoGenerate( + node: T, + autoGenerate: AutoGenerateInfo | undefined, +) { getOrCreateEmitNode(node).autoGenerate = autoGenerate; return node; } @@ -370,12 +410,17 @@ export function getIdentifierAutoGenerate(node: Identifier | PrivateIdentifier): } /** @internal */ -export function setIdentifierGeneratedImportReference(node: T, value: ImportSpecifier | undefined) { +export function setIdentifierGeneratedImportReference( + node: T, + value: ImportSpecifier | undefined, +) { getOrCreateEmitNode(node).generatedImportReference = value; return node; } /** @internal */ -export function getIdentifierGeneratedImportReference(node: Identifier | PrivateIdentifier): ImportSpecifier | undefined { +export function getIdentifierGeneratedImportReference( + node: Identifier | PrivateIdentifier, +): ImportSpecifier | undefined { return node.emitNode?.generatedImportReference; } diff --git a/src/compiler/factory/nodeConverters.ts b/src/compiler/factory/nodeConverters.ts index bc12cb58cc73a..00736b0d1c319 100644 --- a/src/compiler/factory/nodeConverters.ts +++ b/src/compiler/factory/nodeConverters.ts @@ -69,7 +69,7 @@ export function createNodeConverters(factory: NodeFactory): NodeConverters { node.typeParameters, node.parameters, node.type, - node.body + node.body, ); setOriginalNode(updated, node); setTextRange(updated, node); @@ -85,7 +85,7 @@ export function createNodeConverters(factory: NodeFactory): NodeConverters { node.name, node.typeParameters, node.heritageClauses, - node.members + node.members, ); setOriginalNode(updated, node); setTextRange(updated, node); @@ -106,9 +106,9 @@ export function createNodeConverters(factory: NodeFactory): NodeConverters { ? setOriginalNode( setTextRange( factory.createAssignment(expression, element.initializer), - element + element, ), - element + element, ) : expression; } @@ -123,10 +123,23 @@ export function createNodeConverters(factory: NodeFactory): NodeConverters { } if (element.propertyName) { const expression = convertToAssignmentElementTarget(element.name); - return setOriginalNode(setTextRange(factory.createPropertyAssignment(element.propertyName, element.initializer ? factory.createAssignment(expression, element.initializer) : expression), element), element); + return setOriginalNode( + setTextRange( + factory.createPropertyAssignment( + element.propertyName, + element.initializer ? factory.createAssignment(expression, element.initializer) + : expression, + ), + element, + ), + element, + ); } Debug.assertNode(element.name, isIdentifier); - return setOriginalNode(setTextRange(factory.createShorthandPropertyAssignment(element.name, element.initializer), element), element); + return setOriginalNode( + setTextRange(factory.createShorthandPropertyAssignment(element.name, element.initializer), element), + element, + ); } return cast(element, isObjectLiteralElementLike); @@ -149,9 +162,9 @@ export function createNodeConverters(factory: NodeFactory): NodeConverters { return setOriginalNode( setTextRange( factory.createObjectLiteralExpression(map(node.elements, convertToObjectAssignmentElement)), - node + node, ), - node + node, ); } return cast(node, isObjectLiteralExpression); @@ -162,9 +175,9 @@ export function createNodeConverters(factory: NodeFactory): NodeConverters { return setOriginalNode( setTextRange( factory.createArrayLiteralExpression(map(node.elements, convertToArrayAssignmentElement)), - node + node, ), - node + node, ); } return cast(node, isArrayLiteralExpression); diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 5a33d53ed4dc9..1ecfad4277956 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -509,26 +509,73 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const update = flags & NodeFactoryFlags.NoOriginalNode ? updateWithoutOriginal : updateWithOriginal; // Lazily load the parenthesizer, node converters, and some factory methods until they are used. - const parenthesizerRules = memoize(() => flags & NodeFactoryFlags.NoParenthesizerRules ? nullParenthesizerRules : createParenthesizerRules(factory)); - const converters = memoize(() => flags & NodeFactoryFlags.NoNodeConverters ? nullNodeConverters : createNodeConverters(factory)); + const parenthesizerRules = memoize(() => + flags & NodeFactoryFlags.NoParenthesizerRules ? nullParenthesizerRules : createParenthesizerRules(factory) + ); + const converters = memoize(() => + flags & NodeFactoryFlags.NoNodeConverters ? nullNodeConverters : createNodeConverters(factory) + ); // lazy initializaton of common operator factories - const getBinaryCreateFunction = memoizeOne((operator: BinaryOperator) => (left: Expression, right: Expression) => createBinaryExpression(left, operator, right)); - const getPrefixUnaryCreateFunction = memoizeOne((operator: PrefixUnaryOperator) => (operand: Expression) => createPrefixUnaryExpression(operator, operand)); - const getPostfixUnaryCreateFunction = memoizeOne((operator: PostfixUnaryOperator) => (operand: Expression) => createPostfixUnaryExpression(operand, operator)); - const getJSDocPrimaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => () => createJSDocPrimaryTypeWorker(kind)); - const getJSDocUnaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => (type: T["type"]) => createJSDocUnaryTypeWorker(kind, type)); - const getJSDocUnaryTypeUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocUnaryTypeWorker(kind, node, type)); - const getJSDocPrePostfixUnaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => (type: T["type"], postfix?: boolean) => createJSDocPrePostfixUnaryTypeWorker(kind, type, postfix)); - const getJSDocPrePostfixUnaryTypeUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, type: T["type"]) => updateJSDocPrePostfixUnaryTypeWorker(kind, node, type)); - const getJSDocSimpleTagCreateFunction = memoizeOne((kind: T["kind"]) => (tagName: Identifier | undefined, comment?: NodeArray) => createJSDocSimpleTagWorker(kind, tagName, comment)); - const getJSDocSimpleTagUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, tagName: Identifier | undefined, comment?: NodeArray) => updateJSDocSimpleTagWorker(kind, node, tagName, comment)); - const getJSDocTypeLikeTagCreateFunction = memoizeOne((kind: T["kind"]) => (tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: NodeArray) => createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment)); - const getJSDocTypeLikeTagUpdateFunction = memoizeOne((kind: T["kind"]) => (node: T, tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: NodeArray) => updateJSDocTypeLikeTagWorker(kind, node, tagName, typeExpression, comment)); + const getBinaryCreateFunction = memoizeOne((operator: BinaryOperator) => (left: Expression, right: Expression) => + createBinaryExpression(left, operator, right) + ); + const getPrefixUnaryCreateFunction = memoizeOne((operator: PrefixUnaryOperator) => (operand: Expression) => + createPrefixUnaryExpression(operator, operand) + ); + const getPostfixUnaryCreateFunction = memoizeOne((operator: PostfixUnaryOperator) => (operand: Expression) => + createPostfixUnaryExpression(operand, operator) + ); + const getJSDocPrimaryTypeCreateFunction = memoizeOne((kind: T["kind"]) => () => + createJSDocPrimaryTypeWorker(kind) + ); + const getJSDocUnaryTypeCreateFunction = memoizeOne( + (kind: T["kind"]) => (type: T["type"]) => + createJSDocUnaryTypeWorker(kind, type), + ); + const getJSDocUnaryTypeUpdateFunction = memoizeOne( + (kind: T["kind"]) => + (node: T, type: T["type"]) => updateJSDocUnaryTypeWorker(kind, node, type), + ); + const getJSDocPrePostfixUnaryTypeCreateFunction = memoizeOne( + (kind: T["kind"]) => + (type: T["type"], postfix?: boolean) => createJSDocPrePostfixUnaryTypeWorker(kind, type, postfix), + ); + const getJSDocPrePostfixUnaryTypeUpdateFunction = memoizeOne( + (kind: T["kind"]) => + (node: T, type: T["type"]) => updateJSDocPrePostfixUnaryTypeWorker(kind, node, type), + ); + const getJSDocSimpleTagCreateFunction = memoizeOne( + (kind: T["kind"]) => (tagName: Identifier | undefined, comment?: NodeArray) => + createJSDocSimpleTagWorker(kind, tagName, comment), + ); + const getJSDocSimpleTagUpdateFunction = memoizeOne( + (kind: T["kind"]) => + (node: T, tagName: Identifier | undefined, comment?: NodeArray) => + updateJSDocSimpleTagWorker(kind, node, tagName, comment), + ); + const getJSDocTypeLikeTagCreateFunction = memoizeOne( + (kind: T["kind"]) => + (tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: NodeArray) => + createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment), + ); + const getJSDocTypeLikeTagUpdateFunction = memoizeOne( + (kind: T["kind"]) => + ( + node: T, + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + comment?: NodeArray, + ) => updateJSDocTypeLikeTagWorker(kind, node, tagName, typeExpression, comment), + ); const factory: NodeFactory = { - get parenthesizer() { return parenthesizerRules(); }, - get converters() { return converters(); }, + get parenthesizer() { + return parenthesizerRules(); + }, + get converters() { + return converters(); + }, baseFactory, flags, createNodeArray, @@ -644,13 +691,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode updateArrayLiteralExpression, createObjectLiteralExpression, updateObjectLiteralExpression, - createPropertyAccessExpression: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess ? - (expression, name) => setEmitFlags(createPropertyAccessExpression(expression, name), EmitFlags.NoIndentation) : - createPropertyAccessExpression, + createPropertyAccessExpression: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess + ? (expression, name) => + setEmitFlags(createPropertyAccessExpression(expression, name), EmitFlags.NoIndentation) + : createPropertyAccessExpression, updatePropertyAccessExpression, - createPropertyAccessChain: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess ? - (expression, questionDotToken, name: string) => setEmitFlags(createPropertyAccessChain(expression, questionDotToken, name), EmitFlags.NoIndentation) : - createPropertyAccessChain, + createPropertyAccessChain: flags & NodeFactoryFlags.NoIndentationOnFreshPropertyAccess + ? (expression, questionDotToken, name: string) => + setEmitFlags(createPropertyAccessChain(expression, questionDotToken, name), EmitFlags.NoIndentation) + : createPropertyAccessChain, updatePropertyAccessChain, createElementAccessExpression, updateElementAccessExpression, @@ -807,18 +856,42 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode createExternalModuleReference, updateExternalModuleReference, // lazily load factory members for JSDoc types with similar structure - get createJSDocAllType() { return getJSDocPrimaryTypeCreateFunction(SyntaxKind.JSDocAllType); }, - get createJSDocUnknownType() { return getJSDocPrimaryTypeCreateFunction(SyntaxKind.JSDocUnknownType); }, - get createJSDocNonNullableType() { return getJSDocPrePostfixUnaryTypeCreateFunction(SyntaxKind.JSDocNonNullableType); }, - get updateJSDocNonNullableType() { return getJSDocPrePostfixUnaryTypeUpdateFunction(SyntaxKind.JSDocNonNullableType); }, - get createJSDocNullableType() { return getJSDocPrePostfixUnaryTypeCreateFunction(SyntaxKind.JSDocNullableType); }, - get updateJSDocNullableType() { return getJSDocPrePostfixUnaryTypeUpdateFunction(SyntaxKind.JSDocNullableType); }, - get createJSDocOptionalType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocOptionalType); }, - get updateJSDocOptionalType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocOptionalType); }, - get createJSDocVariadicType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocVariadicType); }, - get updateJSDocVariadicType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocVariadicType); }, - get createJSDocNamepathType() { return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocNamepathType); }, - get updateJSDocNamepathType() { return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocNamepathType); }, + get createJSDocAllType() { + return getJSDocPrimaryTypeCreateFunction(SyntaxKind.JSDocAllType); + }, + get createJSDocUnknownType() { + return getJSDocPrimaryTypeCreateFunction(SyntaxKind.JSDocUnknownType); + }, + get createJSDocNonNullableType() { + return getJSDocPrePostfixUnaryTypeCreateFunction(SyntaxKind.JSDocNonNullableType); + }, + get updateJSDocNonNullableType() { + return getJSDocPrePostfixUnaryTypeUpdateFunction(SyntaxKind.JSDocNonNullableType); + }, + get createJSDocNullableType() { + return getJSDocPrePostfixUnaryTypeCreateFunction(SyntaxKind.JSDocNullableType); + }, + get updateJSDocNullableType() { + return getJSDocPrePostfixUnaryTypeUpdateFunction(SyntaxKind.JSDocNullableType); + }, + get createJSDocOptionalType() { + return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocOptionalType); + }, + get updateJSDocOptionalType() { + return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocOptionalType); + }, + get createJSDocVariadicType() { + return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocVariadicType); + }, + get updateJSDocVariadicType() { + return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocVariadicType); + }, + get createJSDocNamepathType() { + return getJSDocUnaryTypeCreateFunction(SyntaxKind.JSDocNamepathType); + }, + get updateJSDocNamepathType() { + return getJSDocUnaryTypeUpdateFunction(SyntaxKind.JSDocNamepathType); + }, createJSDocFunctionType, updateJSDocFunctionType, createJSDocTypeLiteral, @@ -856,32 +929,84 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode createJSDocLinkPlain, updateJSDocLinkPlain, // lazily load factory members for JSDoc tags with similar structure - get createJSDocTypeTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocTypeTag); }, - get updateJSDocTypeTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocTypeTag); }, - get createJSDocReturnTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocReturnTag); }, - get updateJSDocReturnTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocReturnTag); }, - get createJSDocThisTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocThisTag); }, - get updateJSDocThisTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocThisTag); }, - get createJSDocAuthorTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocAuthorTag); }, - get updateJSDocAuthorTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocAuthorTag); }, - get createJSDocClassTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocClassTag); }, - get updateJSDocClassTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocClassTag); }, - get createJSDocPublicTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocPublicTag); }, - get updateJSDocPublicTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocPublicTag); }, - get createJSDocPrivateTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocPrivateTag); }, - get updateJSDocPrivateTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocPrivateTag); }, - get createJSDocProtectedTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocProtectedTag); }, - get updateJSDocProtectedTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocProtectedTag); }, - get createJSDocReadonlyTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocReadonlyTag); }, - get updateJSDocReadonlyTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocReadonlyTag); }, - get createJSDocOverrideTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocOverrideTag); }, - get updateJSDocOverrideTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocOverrideTag); }, - get createJSDocDeprecatedTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocDeprecatedTag); }, - get updateJSDocDeprecatedTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocDeprecatedTag); }, - get createJSDocThrowsTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocThrowsTag); }, - get updateJSDocThrowsTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocThrowsTag); }, - get createJSDocSatisfiesTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocSatisfiesTag); }, - get updateJSDocSatisfiesTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocSatisfiesTag); }, + get createJSDocTypeTag() { + return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocTypeTag); + }, + get updateJSDocTypeTag() { + return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocTypeTag); + }, + get createJSDocReturnTag() { + return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocReturnTag); + }, + get updateJSDocReturnTag() { + return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocReturnTag); + }, + get createJSDocThisTag() { + return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocThisTag); + }, + get updateJSDocThisTag() { + return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocThisTag); + }, + get createJSDocAuthorTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocAuthorTag); + }, + get updateJSDocAuthorTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocAuthorTag); + }, + get createJSDocClassTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocClassTag); + }, + get updateJSDocClassTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocClassTag); + }, + get createJSDocPublicTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocPublicTag); + }, + get updateJSDocPublicTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocPublicTag); + }, + get createJSDocPrivateTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocPrivateTag); + }, + get updateJSDocPrivateTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocPrivateTag); + }, + get createJSDocProtectedTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocProtectedTag); + }, + get updateJSDocProtectedTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocProtectedTag); + }, + get createJSDocReadonlyTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocReadonlyTag); + }, + get updateJSDocReadonlyTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocReadonlyTag); + }, + get createJSDocOverrideTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocOverrideTag); + }, + get updateJSDocOverrideTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocOverrideTag); + }, + get createJSDocDeprecatedTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocDeprecatedTag); + }, + get updateJSDocDeprecatedTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocDeprecatedTag); + }, + get createJSDocThrowsTag() { + return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocThrowsTag); + }, + get updateJSDocThrowsTag() { + return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocThrowsTag); + }, + get createJSDocSatisfiesTag() { + return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocSatisfiesTag); + }, + get updateJSDocSatisfiesTag() { + return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocSatisfiesTag); + }, createJSDocEnumTag, updateJSDocEnumTag, @@ -954,38 +1079,102 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode cloneNode, // Lazily load factory methods for common operator factories and utilities - get createComma() { return getBinaryCreateFunction(SyntaxKind.CommaToken); }, - get createAssignment() { return getBinaryCreateFunction(SyntaxKind.EqualsToken) as NodeFactory["createAssignment"]; }, - get createLogicalOr() { return getBinaryCreateFunction(SyntaxKind.BarBarToken); }, - get createLogicalAnd() { return getBinaryCreateFunction(SyntaxKind.AmpersandAmpersandToken); }, - get createBitwiseOr() { return getBinaryCreateFunction(SyntaxKind.BarToken); }, - get createBitwiseXor() { return getBinaryCreateFunction(SyntaxKind.CaretToken); }, - get createBitwiseAnd() { return getBinaryCreateFunction(SyntaxKind.AmpersandToken); }, - get createStrictEquality() { return getBinaryCreateFunction(SyntaxKind.EqualsEqualsEqualsToken); }, - get createStrictInequality() { return getBinaryCreateFunction(SyntaxKind.ExclamationEqualsEqualsToken); }, - get createEquality() { return getBinaryCreateFunction(SyntaxKind.EqualsEqualsToken); }, - get createInequality() { return getBinaryCreateFunction(SyntaxKind.ExclamationEqualsToken); }, - get createLessThan() { return getBinaryCreateFunction(SyntaxKind.LessThanToken); }, - get createLessThanEquals() { return getBinaryCreateFunction(SyntaxKind.LessThanEqualsToken); }, - get createGreaterThan() { return getBinaryCreateFunction(SyntaxKind.GreaterThanToken); }, - get createGreaterThanEquals() { return getBinaryCreateFunction(SyntaxKind.GreaterThanEqualsToken); }, - get createLeftShift() { return getBinaryCreateFunction(SyntaxKind.LessThanLessThanToken); }, - get createRightShift() { return getBinaryCreateFunction(SyntaxKind.GreaterThanGreaterThanToken); }, - get createUnsignedRightShift() { return getBinaryCreateFunction(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); }, - get createAdd() { return getBinaryCreateFunction(SyntaxKind.PlusToken); }, - get createSubtract() { return getBinaryCreateFunction(SyntaxKind.MinusToken); }, - get createMultiply() { return getBinaryCreateFunction(SyntaxKind.AsteriskToken); }, - get createDivide() { return getBinaryCreateFunction(SyntaxKind.SlashToken); }, - get createModulo() { return getBinaryCreateFunction(SyntaxKind.PercentToken); }, - get createExponent() { return getBinaryCreateFunction(SyntaxKind.AsteriskAsteriskToken); }, - get createPrefixPlus() { return getPrefixUnaryCreateFunction(SyntaxKind.PlusToken); }, - get createPrefixMinus() { return getPrefixUnaryCreateFunction(SyntaxKind.MinusToken); }, - get createPrefixIncrement() { return getPrefixUnaryCreateFunction(SyntaxKind.PlusPlusToken); }, - get createPrefixDecrement() { return getPrefixUnaryCreateFunction(SyntaxKind.MinusMinusToken); }, - get createBitwiseNot() { return getPrefixUnaryCreateFunction(SyntaxKind.TildeToken); }, - get createLogicalNot() { return getPrefixUnaryCreateFunction(SyntaxKind.ExclamationToken); }, - get createPostfixIncrement() { return getPostfixUnaryCreateFunction(SyntaxKind.PlusPlusToken); }, - get createPostfixDecrement() { return getPostfixUnaryCreateFunction(SyntaxKind.MinusMinusToken); }, + get createComma() { + return getBinaryCreateFunction(SyntaxKind.CommaToken); + }, + get createAssignment() { + return getBinaryCreateFunction(SyntaxKind.EqualsToken) as NodeFactory["createAssignment"]; + }, + get createLogicalOr() { + return getBinaryCreateFunction(SyntaxKind.BarBarToken); + }, + get createLogicalAnd() { + return getBinaryCreateFunction(SyntaxKind.AmpersandAmpersandToken); + }, + get createBitwiseOr() { + return getBinaryCreateFunction(SyntaxKind.BarToken); + }, + get createBitwiseXor() { + return getBinaryCreateFunction(SyntaxKind.CaretToken); + }, + get createBitwiseAnd() { + return getBinaryCreateFunction(SyntaxKind.AmpersandToken); + }, + get createStrictEquality() { + return getBinaryCreateFunction(SyntaxKind.EqualsEqualsEqualsToken); + }, + get createStrictInequality() { + return getBinaryCreateFunction(SyntaxKind.ExclamationEqualsEqualsToken); + }, + get createEquality() { + return getBinaryCreateFunction(SyntaxKind.EqualsEqualsToken); + }, + get createInequality() { + return getBinaryCreateFunction(SyntaxKind.ExclamationEqualsToken); + }, + get createLessThan() { + return getBinaryCreateFunction(SyntaxKind.LessThanToken); + }, + get createLessThanEquals() { + return getBinaryCreateFunction(SyntaxKind.LessThanEqualsToken); + }, + get createGreaterThan() { + return getBinaryCreateFunction(SyntaxKind.GreaterThanToken); + }, + get createGreaterThanEquals() { + return getBinaryCreateFunction(SyntaxKind.GreaterThanEqualsToken); + }, + get createLeftShift() { + return getBinaryCreateFunction(SyntaxKind.LessThanLessThanToken); + }, + get createRightShift() { + return getBinaryCreateFunction(SyntaxKind.GreaterThanGreaterThanToken); + }, + get createUnsignedRightShift() { + return getBinaryCreateFunction(SyntaxKind.GreaterThanGreaterThanGreaterThanToken); + }, + get createAdd() { + return getBinaryCreateFunction(SyntaxKind.PlusToken); + }, + get createSubtract() { + return getBinaryCreateFunction(SyntaxKind.MinusToken); + }, + get createMultiply() { + return getBinaryCreateFunction(SyntaxKind.AsteriskToken); + }, + get createDivide() { + return getBinaryCreateFunction(SyntaxKind.SlashToken); + }, + get createModulo() { + return getBinaryCreateFunction(SyntaxKind.PercentToken); + }, + get createExponent() { + return getBinaryCreateFunction(SyntaxKind.AsteriskAsteriskToken); + }, + get createPrefixPlus() { + return getPrefixUnaryCreateFunction(SyntaxKind.PlusToken); + }, + get createPrefixMinus() { + return getPrefixUnaryCreateFunction(SyntaxKind.MinusToken); + }, + get createPrefixIncrement() { + return getPrefixUnaryCreateFunction(SyntaxKind.PlusPlusToken); + }, + get createPrefixDecrement() { + return getPrefixUnaryCreateFunction(SyntaxKind.MinusMinusToken); + }, + get createBitwiseNot() { + return getPrefixUnaryCreateFunction(SyntaxKind.TildeToken); + }, + get createLogicalNot() { + return getPrefixUnaryCreateFunction(SyntaxKind.ExclamationToken); + }, + get createPostfixIncrement() { + return getPostfixUnaryCreateFunction(SyntaxKind.PlusPlusToken); + }, + get createPostfixDecrement() { + return getPostfixUnaryCreateFunction(SyntaxKind.MinusMinusToken); + }, // Compound nodes createImmediatelyInvokedFunctionExpression, @@ -1087,7 +1276,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return node; } - function finishUpdateBaseSignatureDeclaration(updated: Mutable, original: T) { + function finishUpdateBaseSignatureDeclaration( + updated: Mutable, + original: T, + ) { if (updated !== original) { // copy children used for quick info updated.typeArguments = original.typeArguments; @@ -1100,13 +1292,21 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // // @api - function createNumericLiteral(value: string | number, numericLiteralFlags: TokenFlags = TokenFlags.None): NumericLiteral { + function createNumericLiteral( + value: string | number, + numericLiteralFlags: TokenFlags = TokenFlags.None, + ): NumericLiteral { const text = typeof value === "number" ? value + "" : value; - Debug.assert(text.charCodeAt(0) !== CharacterCodes.minus, "Negative numbers should be created in combination with createPrefixUnaryExpression"); + Debug.assert( + text.charCodeAt(0) !== CharacterCodes.minus, + "Negative numbers should be created in combination with createPrefixUnaryExpression", + ); const node = createBaseDeclaration(SyntaxKind.NumericLiteral); node.text = text; node.numericLiteralFlags = numericLiteralFlags; - if (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) node.transformFlags |= TransformFlags.ContainsES2015; + if (numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) { + node.transformFlags |= TransformFlags.ContainsES2015; + } return node; } @@ -1126,7 +1326,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral { + function createStringLiteral( + text: string, + isSingleQuote?: boolean, + hasExtendedUnicodeEscape?: boolean, + ): StringLiteral { const node = createBaseStringLiteral(text, isSingleQuote); node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape; if (hasExtendedUnicodeEscape) node.transformFlags |= TransformFlags.ContainsES2015; @@ -1148,15 +1352,30 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createLiteralLikeNode(kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, text: string): LiteralToken { + function createLiteralLikeNode( + kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, + text: string, + ): LiteralToken { switch (kind) { - case SyntaxKind.NumericLiteral: return createNumericLiteral(text, /*numericLiteralFlags*/ 0); - case SyntaxKind.BigIntLiteral: return createBigIntLiteral(text); - case SyntaxKind.StringLiteral: return createStringLiteral(text, /*isSingleQuote*/ undefined); - case SyntaxKind.JsxText: return createJsxText(text, /*containsOnlyTriviaWhiteSpaces*/ false); - case SyntaxKind.JsxTextAllWhiteSpaces: return createJsxText(text, /*containsOnlyTriviaWhiteSpaces*/ true); - case SyntaxKind.RegularExpressionLiteral: return createRegularExpressionLiteral(text); - case SyntaxKind.NoSubstitutionTemplateLiteral: return createTemplateLiteralLikeNode(kind, text, /*rawText*/ undefined, /*templateFlags*/ 0) as NoSubstitutionTemplateLiteral; + case SyntaxKind.NumericLiteral: + return createNumericLiteral(text, /*numericLiteralFlags*/ 0); + case SyntaxKind.BigIntLiteral: + return createBigIntLiteral(text); + case SyntaxKind.StringLiteral: + return createStringLiteral(text, /*isSingleQuote*/ undefined); + case SyntaxKind.JsxText: + return createJsxText(text, /*containsOnlyTriviaWhiteSpaces*/ false); + case SyntaxKind.JsxTextAllWhiteSpaces: + return createJsxText(text, /*containsOnlyTriviaWhiteSpaces*/ true); + case SyntaxKind.RegularExpressionLiteral: + return createRegularExpressionLiteral(text); + case SyntaxKind.NoSubstitutionTemplateLiteral: + return createTemplateLiteralLikeNode( + kind, + text, + /*rawText*/ undefined, + /*templateFlags*/ 0, + ) as NoSubstitutionTemplateLiteral; } } @@ -1173,20 +1392,29 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return node; } - function createBaseGeneratedIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) { + function createBaseGeneratedIdentifier( + text: string, + autoGenerateFlags: GeneratedIdentifierFlags, + prefix: string | GeneratedNamePart | undefined, + suffix: string | undefined, + ) { const node = createBaseIdentifier(escapeLeadingUnderscores(text)) as Mutable; setIdentifierAutoGenerate(node, { flags: autoGenerateFlags, id: nextAutoGenerateId, prefix, - suffix + suffix, }); nextAutoGenerateId++; return node; } // @api - function createIdentifier(text: string, originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier { + function createIdentifier( + text: string, + originalKeywordKind?: SyntaxKind, + hasExtendedUnicodeEscape?: boolean, + ): Identifier { if (originalKeywordKind === undefined && text) { originalKeywordKind = stringToToken(text); } @@ -1209,7 +1437,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean, prefix?: string | GeneratedNamePart, suffix?: string): GeneratedIdentifier { + function createTempVariable( + recordTempVariable: ((node: Identifier) => void) | undefined, + reservedInNestedScopes?: boolean, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): GeneratedIdentifier { let flags = GeneratedIdentifierFlags.Auto; if (reservedInNestedScopes) flags |= GeneratedIdentifierFlags.ReservedInNestedScopes; const name = createBaseGeneratedIdentifier("", flags, prefix, suffix); @@ -1229,19 +1462,33 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode /** Create a unique name based on the supplied text. */ // @api - function createUniqueName(text: string, flags: GeneratedIdentifierFlags = GeneratedIdentifierFlags.None, prefix?: string | GeneratedNamePart, suffix?: string): Identifier { + function createUniqueName( + text: string, + flags: GeneratedIdentifierFlags = GeneratedIdentifierFlags.None, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier { Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags"); - Debug.assert((flags & (GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)) !== GeneratedIdentifierFlags.FileLevel, "GeneratedIdentifierFlags.FileLevel cannot be set without also setting GeneratedIdentifierFlags.Optimistic"); + Debug.assert( + (flags & (GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)) + !== GeneratedIdentifierFlags.FileLevel, + "GeneratedIdentifierFlags.FileLevel cannot be set without also setting GeneratedIdentifierFlags.Optimistic", + ); return createBaseGeneratedIdentifier(text, GeneratedIdentifierFlags.Unique | flags, prefix, suffix); } /** Create a unique name generated for a node. */ // @api - function getGeneratedNameForNode(node: Node | undefined, flags: GeneratedIdentifierFlags = 0, prefix?: string | GeneratedNamePart, suffix?: string): Identifier { + function getGeneratedNameForNode( + node: Node | undefined, + flags: GeneratedIdentifierFlags = 0, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier { Debug.assert(!(flags & GeneratedIdentifierFlags.KindMask), "Argument out of range: flags"); - const text = !node ? "" : - isMemberName(node) ? formatGeneratedName(/*privateName*/ false, prefix, node, suffix, idText) : - `generated@${getNodeId(node)}`; + const text = !node ? "" + : isMemberName(node) ? formatGeneratedName(/*privateName*/ false, prefix, node, suffix, idText) + : `generated@${getNodeId(node)}`; if (prefix || suffix) flags |= GeneratedIdentifierFlags.Optimistic; const name = createBaseGeneratedIdentifier(text, GeneratedIdentifierFlags.Node | flags, prefix, suffix); name.original = node; @@ -1249,7 +1496,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } function createBasePrivateIdentifier(escapedText: __String) { - const node = baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable; + const node = baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable< + PrivateIdentifier + >; node.escapedText = escapedText; node.transformFlags |= TransformFlags.ContainsClassFields; return node; @@ -1261,7 +1510,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return createBasePrivateIdentifier(escapeLeadingUnderscores(text)); } - function createBaseGeneratedPrivateIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) { + function createBaseGeneratedPrivateIdentifier( + text: string, + autoGenerateFlags: GeneratedIdentifierFlags, + prefix: string | GeneratedNamePart | undefined, + suffix: string | undefined, + ) { const node = createBasePrivateIdentifier(escapeLeadingUnderscores(text)); setIdentifierAutoGenerate(node, { flags: autoGenerateFlags, @@ -1275,17 +1529,25 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode /** Create a unique name based on the supplied text. */ // @api - function createUniquePrivateName(text?: string, prefix?: string | GeneratedNamePart, suffix?: string): PrivateIdentifier { + function createUniquePrivateName( + text?: string, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): PrivateIdentifier { if (text && !startsWith(text, "#")) Debug.fail("First character of private identifier must be #: " + text); - const autoGenerateFlags = GeneratedIdentifierFlags.ReservedInNestedScopes | - (text ? GeneratedIdentifierFlags.Unique : GeneratedIdentifierFlags.Auto); + const autoGenerateFlags = GeneratedIdentifierFlags.ReservedInNestedScopes + | (text ? GeneratedIdentifierFlags.Unique : GeneratedIdentifierFlags.Auto); return createBaseGeneratedPrivateIdentifier(text ?? "", autoGenerateFlags, prefix, suffix); } // @api - function getGeneratedPrivateNameForNode(node: Node, prefix?: string | GeneratedNamePart, suffix?: string): PrivateIdentifier { - const text = isMemberName(node) ? formatGeneratedName(/*privateName*/ true, prefix, node, suffix, idText) : - `#generated@${getNodeId(node)}`; + function getGeneratedPrivateNameForNode( + node: Node, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): PrivateIdentifier { + const text = isMemberName(node) ? formatGeneratedName(/*privateName*/ true, prefix, node, suffix, idText) + : `#generated@${getNodeId(node)}`; const flags = prefix || suffix ? GeneratedIdentifierFlags.Optimistic : GeneratedIdentifierFlags.None; const name = createBaseGeneratedPrivateIdentifier(text, GeneratedIdentifierFlags.Node | flags, prefix, suffix); name.original = node; @@ -1315,17 +1577,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createToken(token: TKind): Token; function createToken(token: TKind) { Debug.assert(token >= SyntaxKind.FirstToken && token <= SyntaxKind.LastToken, "Invalid token"); - Debug.assert(token <= SyntaxKind.FirstTemplateToken || token >= SyntaxKind.LastTemplateToken, "Invalid token. Use 'createTemplateLiteralLikeNode' to create template literals."); - Debug.assert(token <= SyntaxKind.FirstLiteralToken || token >= SyntaxKind.LastLiteralToken, "Invalid token. Use 'createLiteralLikeNode' to create literals."); + Debug.assert( + token <= SyntaxKind.FirstTemplateToken || token >= SyntaxKind.LastTemplateToken, + "Invalid token. Use 'createTemplateLiteralLikeNode' to create template literals.", + ); + Debug.assert( + token <= SyntaxKind.FirstLiteralToken || token >= SyntaxKind.LastLiteralToken, + "Invalid token. Use 'createLiteralLikeNode' to create literals.", + ); Debug.assert(token !== SyntaxKind.Identifier, "Invalid token. Use 'createIdentifier' to create identifiers"); const node = createBaseToken>(token); let transformFlags = TransformFlags.None; switch (token) { case SyntaxKind.AsyncKeyword: // 'async' modifier is ES2017 (async functions) or ES2018 (async generators) - transformFlags = - TransformFlags.ContainsES2017 | - TransformFlags.ContainsES2018; + transformFlags = TransformFlags.ContainsES2017 + | TransformFlags.ContainsES2018; break; case SyntaxKind.UsingKeyword: @@ -1445,9 +1712,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.QualifiedName); node.left = left; node.right = asName(right); - node.transformFlags |= - propagateChildFlags(node.left) | - propagateIdentifierNameFlags(node.right); + node.transformFlags |= propagateChildFlags(node.left) + | propagateIdentifierNameFlags(node.right); node.flowNode = undefined; // initialized by binder (FlowContainer) return node; @@ -1456,7 +1722,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier) { return node.left !== left - || node.right !== right + || node.right !== right ? update(createQualifiedName(left, right), node) : node; } @@ -1465,10 +1731,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createComputedPropertyName(expression: Expression) { const node = createBaseNode(SyntaxKind.ComputedPropertyName); node.expression = parenthesizerRules().parenthesizeExpressionOfComputedPropertyName(expression); - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsComputedPropertyName; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsComputedPropertyName; return node; } @@ -1484,7 +1749,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // // @api - function createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration { + function createTypeParameterDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + constraint?: TypeNode, + defaultType?: TypeNode, + ): TypeParameterDeclaration { const node = createBaseDeclaration(SyntaxKind.TypeParameter); node.modifiers = asNodeArray(modifiers); node.name = asName(name); @@ -1498,11 +1768,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration { + function updateTypeParameterDeclaration( + node: TypeParameterDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + constraint: TypeNode | undefined, + defaultType: TypeNode | undefined, + ): TypeParameterDeclaration { return node.modifiers !== modifiers - || node.name !== name - || node.constraint !== constraint - || node.default !== defaultType + || node.name !== name + || node.constraint !== constraint + || node.default !== defaultType ? update(createTypeParameterDeclaration(modifiers, name, constraint, defaultType), node) : node; } @@ -1514,7 +1790,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, - initializer?: Expression + initializer?: Expression, ) { const node = createBaseDeclaration(SyntaxKind.Parameter); node.modifiers = asNodeArray(modifiers); @@ -1528,15 +1804,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; } else { - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.dotDotDotToken) | - propagateNameFlags(node.name) | - propagateChildFlags(node.questionToken) | - propagateChildFlags(node.initializer) | - (node.questionToken ?? node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) | - (node.dotDotDotToken ?? node.initializer ? TransformFlags.ContainsES2015 : TransformFlags.None) | - (modifiersToFlags(node.modifiers) & ModifierFlags.ParameterPropertyModifier ? TransformFlags.ContainsTypeScriptClassSyntax : TransformFlags.None); + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.dotDotDotToken) + | propagateNameFlags(node.name) + | propagateChildFlags(node.questionToken) + | propagateChildFlags(node.initializer) + | (node.questionToken ?? node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) + | (node.dotDotDotToken ?? node.initializer ? TransformFlags.ContainsES2015 : TransformFlags.None) + | (modifiersToFlags(node.modifiers) & ModifierFlags.ParameterPropertyModifier + ? TransformFlags.ContainsTypeScriptClassSyntax : TransformFlags.None); } node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -1551,15 +1827,18 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, - initializer: Expression | undefined + initializer: Expression | undefined, ) { return node.modifiers !== modifiers - || node.dotDotDotToken !== dotDotDotToken - || node.name !== name - || node.questionToken !== questionToken - || node.type !== type - || node.initializer !== initializer - ? update(createParameterDeclaration(modifiers, dotDotDotToken, name, questionToken, type, initializer), node) + || node.dotDotDotToken !== dotDotDotToken + || node.name !== name + || node.questionToken !== questionToken + || node.type !== type + || node.initializer !== initializer + ? update( + createParameterDeclaration(modifiers, dotDotDotToken, name, questionToken, type, initializer), + node, + ) : node; } @@ -1567,11 +1846,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createDecorator(expression: Expression) { const node = createBaseNode(SyntaxKind.Decorator); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsTypeScript | - TransformFlags.ContainsTypeScriptClassSyntax | - TransformFlags.ContainsDecorators; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsTypeScript + | TransformFlags.ContainsTypeScriptClassSyntax + | TransformFlags.ContainsDecorators; return node; } @@ -1591,7 +1869,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, - type: TypeNode | undefined + type: TypeNode | undefined, ): PropertySignature { const node = createBaseDeclaration(SyntaxKind.PropertySignature); node.modifiers = asNodeArray(modifiers); @@ -1611,12 +1889,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, - type: TypeNode | undefined + type: TypeNode | undefined, ) { return node.modifiers !== modifiers - || node.name !== name - || node.questionToken !== questionToken - || node.type !== type + || node.name !== name + || node.questionToken !== questionToken + || node.type !== type ? finishUpdatePropertySignature(createPropertySignature(modifiers, name, questionToken, type), node) : node; } @@ -1635,25 +1913,29 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, - initializer: Expression | undefined + initializer: Expression | undefined, ) { const node = createBaseDeclaration(SyntaxKind.PropertyDeclaration); node.modifiers = asNodeArray(modifiers); node.name = asName(name); - node.questionToken = questionOrExclamationToken && isQuestionToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined; - node.exclamationToken = questionOrExclamationToken && isExclamationToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined; + node.questionToken = questionOrExclamationToken && isQuestionToken(questionOrExclamationToken) + ? questionOrExclamationToken : undefined; + node.exclamationToken = questionOrExclamationToken && isExclamationToken(questionOrExclamationToken) + ? questionOrExclamationToken : undefined; node.type = type; node.initializer = asInitializer(initializer); const isAmbient = node.flags & NodeFlags.Ambient || modifiersToFlags(node.modifiers) & ModifierFlags.Ambient; - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateNameFlags(node.name) | - propagateChildFlags(node.initializer) | - (isAmbient || node.questionToken || node.exclamationToken || node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) | - (isComputedPropertyName(node.name) || modifiersToFlags(node.modifiers) & ModifierFlags.Static && node.initializer ? TransformFlags.ContainsTypeScriptClassSyntax : TransformFlags.None) | - TransformFlags.ContainsClassFields; + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateNameFlags(node.name) + | propagateChildFlags(node.initializer) + | (isAmbient || node.questionToken || node.exclamationToken || node.type ? TransformFlags.ContainsTypeScript + : TransformFlags.None) + | (isComputedPropertyName(node.name) + || modifiersToFlags(node.modifiers) & ModifierFlags.Static && node.initializer + ? TransformFlags.ContainsTypeScriptClassSyntax : TransformFlags.None) + | TransformFlags.ContainsClassFields; node.jsDoc = undefined; // initialized by parser (JsDocContainer) return node; @@ -1666,14 +1948,18 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, - initializer: Expression | undefined + initializer: Expression | undefined, ) { return node.modifiers !== modifiers - || node.name !== name - || node.questionToken !== (questionOrExclamationToken !== undefined && isQuestionToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined) - || node.exclamationToken !== (questionOrExclamationToken !== undefined && isExclamationToken(questionOrExclamationToken) ? questionOrExclamationToken : undefined) - || node.type !== type - || node.initializer !== initializer + || node.name !== name + || node.questionToken + !== (questionOrExclamationToken !== undefined && isQuestionToken(questionOrExclamationToken) + ? questionOrExclamationToken : undefined) + || node.exclamationToken + !== (questionOrExclamationToken !== undefined && isExclamationToken(questionOrExclamationToken) + ? questionOrExclamationToken : undefined) + || node.type !== type + || node.initializer !== initializer ? update(createPropertyDeclaration(modifiers, name, questionOrExclamationToken, type, initializer), node) : node; } @@ -1685,7 +1971,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], - type: TypeNode | undefined + type: TypeNode | undefined, ) { const node = createBaseDeclaration(SyntaxKind.MethodSignature); node.modifiers = asNodeArray(modifiers); @@ -1711,15 +1997,18 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode questionToken: QuestionToken | undefined, typeParameters: NodeArray | undefined, parameters: NodeArray, - type: TypeNode | undefined + type: TypeNode | undefined, ) { return node.modifiers !== modifiers - || node.name !== name - || node.questionToken !== questionToken - || node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type - ? finishUpdateBaseSignatureDeclaration(createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type), node) + || node.name !== name + || node.questionToken !== questionToken + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + ? finishUpdateBaseSignatureDeclaration( + createMethodSignature(modifiers, name, questionToken, typeParameters, parameters, type), + node, + ) : node; } @@ -1732,7 +2021,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, - body: Block | undefined + body: Block | undefined, ) { const node = createBaseDeclaration(SyntaxKind.MethodDeclaration); node.modifiers = asNodeArray(modifiers); @@ -1753,21 +2042,21 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const isGenerator = !!node.asteriskToken; const isAsyncGenerator = isAsync && isGenerator; - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.asteriskToken) | - propagateNameFlags(node.name) | - propagateChildFlags(node.questionToken) | - propagateChildrenFlags(node.typeParameters) | - propagateChildrenFlags(node.parameters) | - propagateChildFlags(node.type) | - (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) | - (isAsyncGenerator ? TransformFlags.ContainsES2018 : - isAsync ? TransformFlags.ContainsES2017 : - isGenerator ? TransformFlags.ContainsGenerator : - TransformFlags.None) | - (node.questionToken || node.typeParameters || node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) | - TransformFlags.ContainsES2015; + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.asteriskToken) + | propagateNameFlags(node.name) + | propagateChildFlags(node.questionToken) + | propagateChildrenFlags(node.typeParameters) + | propagateChildrenFlags(node.parameters) + | propagateChildFlags(node.type) + | (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) + | (isAsyncGenerator ? TransformFlags.ContainsES2018 + : isAsync ? TransformFlags.ContainsES2017 + : isGenerator ? TransformFlags.ContainsGenerator + : TransformFlags.None) + | (node.questionToken || node.typeParameters || node.type ? TransformFlags.ContainsTypeScript + : TransformFlags.None) + | TransformFlags.ContainsES2015; } node.typeArguments = undefined; // used in quick info @@ -1790,17 +2079,29 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, - body: Block | undefined + body: Block | undefined, ) { return node.modifiers !== modifiers - || node.asteriskToken !== asteriskToken - || node.name !== name - || node.questionToken !== questionToken - || node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type - || node.body !== body - ? finishUpdateMethodDeclaration(createMethodDeclaration(modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node) + || node.asteriskToken !== asteriskToken + || node.name !== name + || node.questionToken !== questionToken + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? finishUpdateMethodDeclaration( + createMethodDeclaration( + modifiers, + asteriskToken, + name, + questionToken, + typeParameters, + parameters, + type, + body, + ), + node, + ) : node; } @@ -1814,7 +2115,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function createClassStaticBlockDeclaration( - body: Block + body: Block, ): ClassStaticBlockDeclaration { const node = createBaseDeclaration(SyntaxKind.ClassStaticBlockDeclaration); node.body = body; @@ -1832,14 +2133,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateClassStaticBlockDeclaration( node: ClassStaticBlockDeclaration, - body: Block + body: Block, ): ClassStaticBlockDeclaration { return node.body !== body ? finishUpdateClassStaticBlockDeclaration(createClassStaticBlockDeclaration(body), node) : node; } - function finishUpdateClassStaticBlockDeclaration(updated: Mutable, original: ClassStaticBlockDeclaration) { + function finishUpdateClassStaticBlockDeclaration( + updated: Mutable, + original: ClassStaticBlockDeclaration, + ) { if (updated !== original) { // copy children used only for error reporting updated.modifiers = original.modifiers; @@ -1851,18 +2155,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createConstructorDeclaration( modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], - body: Block | undefined + body: Block | undefined, ) { const node = createBaseDeclaration(SyntaxKind.Constructor); node.modifiers = asNodeArray(modifiers); node.parameters = createNodeArray(parameters); node.body = body; - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateChildrenFlags(node.parameters) | - (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) | - TransformFlags.ContainsES2015; + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateChildrenFlags(node.parameters) + | (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) + | TransformFlags.ContainsES2015; node.typeParameters = undefined; // initialized by parser for grammar errors node.type = undefined; // initialized by parser for grammar errors @@ -1880,16 +2183,19 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node: ConstructorDeclaration, modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], - body: Block | undefined + body: Block | undefined, ) { return node.modifiers !== modifiers - || node.parameters !== parameters - || node.body !== body + || node.parameters !== parameters + || node.body !== body ? finishUpdateConstructorDeclaration(createConstructorDeclaration(modifiers, parameters, body), node) : node; } - function finishUpdateConstructorDeclaration(updated: Mutable, original: ConstructorDeclaration) { + function finishUpdateConstructorDeclaration( + updated: Mutable, + original: ConstructorDeclaration, + ) { if (updated !== original) { updated.typeParameters = original.typeParameters; updated.type = original.type; @@ -1903,7 +2209,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: string | PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, - body: Block | undefined + body: Block | undefined, ) { const node = createBaseDeclaration(SyntaxKind.GetAccessor); node.modifiers = asNodeArray(modifiers); @@ -1916,13 +2222,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; } else { - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateNameFlags(node.name) | - propagateChildrenFlags(node.parameters) | - propagateChildFlags(node.type) | - (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) | - (node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateNameFlags(node.name) + | propagateChildrenFlags(node.parameters) + | propagateChildFlags(node.type) + | (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) + | (node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); } node.typeArguments = undefined; // used in quick info @@ -1943,18 +2248,24 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, - body: Block | undefined + body: Block | undefined, ) { return node.modifiers !== modifiers - || node.name !== name - || node.parameters !== parameters - || node.type !== type - || node.body !== body - ? finishUpdateGetAccessorDeclaration(createGetAccessorDeclaration(modifiers, name, parameters, type, body), node) + || node.name !== name + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? finishUpdateGetAccessorDeclaration( + createGetAccessorDeclaration(modifiers, name, parameters, type, body), + node, + ) : node; } - function finishUpdateGetAccessorDeclaration(updated: Mutable, original: GetAccessorDeclaration) { + function finishUpdateGetAccessorDeclaration( + updated: Mutable, + original: GetAccessorDeclaration, + ) { if (updated !== original) { // copy children used only for error reporting updated.typeParameters = original.typeParameters; @@ -1967,7 +2278,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], - body: Block | undefined + body: Block | undefined, ) { const node = createBaseDeclaration(SyntaxKind.SetAccessor); node.modifiers = asNodeArray(modifiers); @@ -1979,12 +2290,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; } else { - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateNameFlags(node.name) | - propagateChildrenFlags(node.parameters) | - (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) | - (node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateNameFlags(node.name) + | propagateChildrenFlags(node.parameters) + | (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) + | (node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); } node.typeArguments = undefined; // used in quick info @@ -2005,17 +2315,20 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], - body: Block | undefined + body: Block | undefined, ) { return node.modifiers !== modifiers - || node.name !== name - || node.parameters !== parameters - || node.body !== body + || node.name !== name + || node.parameters !== parameters + || node.body !== body ? finishUpdateSetAccessorDeclaration(createSetAccessorDeclaration(modifiers, name, parameters, body), node) : node; } - function finishUpdateSetAccessorDeclaration(updated: Mutable, original: SetAccessorDeclaration) { + function finishUpdateSetAccessorDeclaration( + updated: Mutable, + original: SetAccessorDeclaration, + ) { if (updated !== original) { // copy children used only for error reporting updated.typeParameters = original.typeParameters; @@ -2028,7 +2341,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createCallSignature( typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], - type: TypeNode | undefined + type: TypeNode | undefined, ): CallSignatureDeclaration { const node = createBaseDeclaration(SyntaxKind.CallSignature); node.typeParameters = asNodeArray(typeParameters); @@ -2048,11 +2361,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node: CallSignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, - type: TypeNode | undefined + type: TypeNode | undefined, ) { return node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type + || node.parameters !== parameters + || node.type !== type ? finishUpdateBaseSignatureDeclaration(createCallSignature(typeParameters, parameters, type), node) : node; } @@ -2061,7 +2374,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createConstructSignature( typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], - type: TypeNode | undefined + type: TypeNode | undefined, ): ConstructSignatureDeclaration { const node = createBaseDeclaration(SyntaxKind.ConstructSignature); node.typeParameters = asNodeArray(typeParameters); @@ -2081,11 +2394,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node: ConstructSignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, - type: TypeNode | undefined + type: TypeNode | undefined, ) { return node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type + || node.parameters !== parameters + || node.type !== type ? finishUpdateBaseSignatureDeclaration(createConstructSignature(typeParameters, parameters, type), node) : node; } @@ -2094,7 +2407,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createIndexSignature( modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], - type: TypeNode | undefined + type: TypeNode | undefined, ): IndexSignatureDeclaration { const node = createBaseDeclaration(SyntaxKind.IndexSignature); node.modifiers = asNodeArray(modifiers); @@ -2114,11 +2427,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node: IndexSignatureDeclaration, modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], - type: TypeNode + type: TypeNode, ) { return node.parameters !== parameters - || node.type !== type - || node.modifiers !== modifiers + || node.type !== type + || node.modifiers !== modifiers ? finishUpdateBaseSignatureDeclaration(createIndexSignature(modifiers, parameters, type), node) : node; } @@ -2133,9 +2446,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail) { + function updateTemplateLiteralTypeSpan( + node: TemplateLiteralTypeSpan, + type: TypeNode, + literal: TemplateMiddle | TemplateTail, + ) { return node.type !== type - || node.literal !== literal + || node.literal !== literal ? update(createTemplateLiteralTypeSpan(type, literal), node) : node; } @@ -2150,7 +2467,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createTypePredicateNode(assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) { + function createTypePredicateNode( + assertsModifier: AssertsKeyword | undefined, + parameterName: Identifier | ThisTypeNode | string, + type: TypeNode | undefined, + ) { const node = createBaseNode(SyntaxKind.TypePredicate); node.assertsModifier = assertsModifier; node.parameterName = asName(parameterName); @@ -2160,10 +2481,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) { + function updateTypePredicateNode( + node: TypePredicateNode, + assertsModifier: AssertsKeyword | undefined, + parameterName: Identifier | ThisTypeNode, + type: TypeNode | undefined, + ) { return node.assertsModifier !== assertsModifier - || node.parameterName !== parameterName - || node.type !== type + || node.parameterName !== parameterName + || node.type !== type ? update(createTypePredicateNode(assertsModifier, parameterName, type), node) : node; } @@ -2172,15 +2498,20 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createTypeReferenceNode(typeName: string | EntityName, typeArguments: readonly TypeNode[] | undefined) { const node = createBaseNode(SyntaxKind.TypeReference); node.typeName = asName(typeName); - node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(createNodeArray(typeArguments)); + node.typeArguments = typeArguments + && parenthesizerRules().parenthesizeTypeArguments(createNodeArray(typeArguments)); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } // @api - function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined) { + function updateTypeReferenceNode( + node: TypeReferenceNode, + typeName: EntityName, + typeArguments: NodeArray | undefined, + ) { return node.typeName !== typeName - || node.typeArguments !== typeArguments + || node.typeArguments !== typeArguments ? update(createTypeReferenceNode(typeName, typeArguments), node) : node; } @@ -2189,7 +2520,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createFunctionTypeNode( typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], - type: TypeNode + type: TypeNode, ): FunctionTypeNode { const node = createBaseDeclaration(SyntaxKind.FunctionType); node.typeParameters = asNodeArray(typeParameters); @@ -2210,11 +2541,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node: FunctionTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, - type: TypeNode + type: TypeNode, ) { return node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type + || node.parameters !== parameters + || node.type !== type ? finishUpdateFunctionTypeNode(createFunctionTypeNode(typeParameters, parameters, type), node) : node; } @@ -2228,17 +2559,19 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createConstructorTypeNode(...args: Parameters) { - return args.length === 4 ? createConstructorTypeNode1(...args) : - args.length === 3 ? createConstructorTypeNode2(...args) : - Debug.fail("Incorrect number of arguments specified."); + function createConstructorTypeNode( + ...args: Parameters + ) { + return args.length === 4 ? createConstructorTypeNode1(...args) + : args.length === 3 ? createConstructorTypeNode2(...args) + : Debug.fail("Incorrect number of arguments specified."); } function createConstructorTypeNode1( modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], - type: TypeNode + type: TypeNode, ): ConstructorTypeNode { const node = createBaseDeclaration(SyntaxKind.ConstructorType); node.modifiers = asNodeArray(modifiers); @@ -2258,16 +2591,18 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createConstructorTypeNode2( typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], - type: TypeNode + type: TypeNode, ): ConstructorTypeNode { return createConstructorTypeNode1(/*modifiers*/ undefined, typeParameters, parameters, type); } // @api - function updateConstructorTypeNode(...args: Parameters) { - return args.length === 5 ? updateConstructorTypeNode1(...args) : - args.length === 4 ? updateConstructorTypeNode2(...args) : - Debug.fail("Incorrect number of arguments specified."); + function updateConstructorTypeNode( + ...args: Parameters + ) { + return args.length === 5 ? updateConstructorTypeNode1(...args) + : args.length === 4 ? updateConstructorTypeNode2(...args) + : Debug.fail("Incorrect number of arguments specified."); } function updateConstructorTypeNode1( @@ -2275,13 +2610,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly Modifier[] | undefined, typeParameters: NodeArray | undefined, parameters: NodeArray, - type: TypeNode + type: TypeNode, ) { return node.modifiers !== modifiers - || node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type - ? finishUpdateBaseSignatureDeclaration(createConstructorTypeNode(modifiers, typeParameters, parameters, type), node) + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + ? finishUpdateBaseSignatureDeclaration( + createConstructorTypeNode(modifiers, typeParameters, parameters, type), + node, + ) : node; } @@ -2290,7 +2628,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node: ConstructorTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, - type: TypeNode + type: TypeNode, ) { return updateConstructorTypeNode1(node, node.modifiers, typeParameters, parameters, type); } @@ -2307,7 +2645,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName, typeArguments?: readonly TypeNode[]) { return node.exprName !== exprName - || node.typeArguments !== typeArguments + || node.typeArguments !== typeArguments ? update(createTypeQueryNode(exprName, typeArguments), node) : node; } @@ -2358,7 +2696,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) { + function createNamedTupleMember( + dotDotDotToken: DotDotDotToken | undefined, + name: Identifier, + questionToken: QuestionToken | undefined, + type: TypeNode, + ) { const node = createBaseDeclaration(SyntaxKind.NamedTupleMember); node.dotDotDotToken = dotDotDotToken; node.name = name; @@ -2371,11 +2714,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) { + function updateNamedTupleMember( + node: NamedTupleMember, + dotDotDotToken: DotDotDotToken | undefined, + name: Identifier, + questionToken: QuestionToken | undefined, + type: TypeNode, + ) { return node.dotDotDotToken !== dotDotDotToken - || node.name !== name - || node.questionToken !== questionToken - || node.type !== type + || node.name !== name + || node.questionToken !== questionToken + || node.type !== type ? update(createNamedTupleMember(dotDotDotToken, name, questionToken, type), node) : node; } @@ -2410,14 +2759,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode : node; } - function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[], parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[]) { + function createUnionOrIntersectionTypeNode( + kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, + types: readonly TypeNode[], + parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[], + ) { const node = createBaseNode(kind); node.types = factory.createNodeArray(parenthesize(types)); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } - function updateUnionOrIntersectionTypeNode(node: T, types: NodeArray, parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[]): T { + function updateUnionOrIntersectionTypeNode( + node: T, + types: NodeArray, + parenthesize: (nodes: readonly TypeNode[]) => readonly TypeNode[], + ): T { return node.types !== types ? update(createUnionOrIntersectionTypeNode(node.kind, types, parenthesize) as T, node) : node; @@ -2425,26 +2782,47 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function createUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode { - return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types, parenthesizerRules().parenthesizeConstituentTypesOfUnionType) as UnionTypeNode; + return createUnionOrIntersectionTypeNode( + SyntaxKind.UnionType, + types, + parenthesizerRules().parenthesizeConstituentTypesOfUnionType, + ) as UnionTypeNode; } // @api function updateUnionTypeNode(node: UnionTypeNode, types: NodeArray) { - return updateUnionOrIntersectionTypeNode(node, types, parenthesizerRules().parenthesizeConstituentTypesOfUnionType); + return updateUnionOrIntersectionTypeNode( + node, + types, + parenthesizerRules().parenthesizeConstituentTypesOfUnionType, + ); } // @api function createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode { - return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types, parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType) as IntersectionTypeNode; + return createUnionOrIntersectionTypeNode( + SyntaxKind.IntersectionType, + types, + parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType, + ) as IntersectionTypeNode; } // @api function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray) { - return updateUnionOrIntersectionTypeNode(node, types, parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType); + return updateUnionOrIntersectionTypeNode( + node, + types, + parenthesizerRules().parenthesizeConstituentTypesOfIntersectionType, + ); } // @api - function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + function createConditionalTypeNode( + checkType: TypeNode, + extendsType: TypeNode, + trueType: TypeNode, + falseType: TypeNode, + ) { const node = createBaseNode(SyntaxKind.ConditionalType); node.checkType = parenthesizerRules().parenthesizeCheckTypeOfConditionalType(checkType); node.extendsType = parenthesizerRules().parenthesizeExtendsTypeOfConditionalType(extendsType); @@ -2458,11 +2836,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) { + function updateConditionalTypeNode( + node: ConditionalTypeNode, + checkType: TypeNode, + extendsType: TypeNode, + trueType: TypeNode, + falseType: TypeNode, + ) { return node.checkType !== checkType - || node.extendsType !== extendsType - || node.trueType !== trueType - || node.falseType !== falseType + || node.extendsType !== extendsType + || node.trueType !== trueType + || node.falseType !== falseType ? update(createConditionalTypeNode(checkType, extendsType, trueType, falseType), node) : node; } @@ -2492,9 +2876,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateTemplateLiteralType(node: TemplateLiteralTypeNode, head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]) { + function updateTemplateLiteralType( + node: TemplateLiteralTypeNode, + head: TemplateHead, + templateSpans: readonly TemplateLiteralTypeSpan[], + ) { return node.head !== head - || node.templateSpans !== templateSpans + || node.templateSpans !== templateSpans ? update(createTemplateLiteralType(head, templateSpans), node) : node; } @@ -2505,7 +2893,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode assertions?: ImportTypeAssertionContainer, qualifier?: EntityName, typeArguments?: readonly TypeNode[], - isTypeOf = false + isTypeOf = false, ): ImportTypeNode { const node = createBaseNode(SyntaxKind.ImportType); node.argument = argument; @@ -2524,13 +2912,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode assertions: ImportTypeAssertionContainer | undefined, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, - isTypeOf: boolean = node.isTypeOf + isTypeOf: boolean = node.isTypeOf, ): ImportTypeNode { return node.argument !== argument - || node.assertions !== assertions - || node.qualifier !== qualifier - || node.typeArguments !== typeArguments - || node.isTypeOf !== isTypeOf + || node.assertions !== assertions + || node.qualifier !== qualifier + || node.typeArguments !== typeArguments + || node.isTypeOf !== isTypeOf ? update(createImportTypeNode(argument, assertions, qualifier, typeArguments, isTypeOf), node) : node; } @@ -2558,12 +2946,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode { + function createTypeOperatorNode( + operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, + type: TypeNode, + ): TypeOperatorNode { const node = createBaseNode(SyntaxKind.TypeOperator); node.operator = operator; - node.type = operator === SyntaxKind.ReadonlyKeyword ? - parenthesizerRules().parenthesizeOperandOfReadonlyTypeOperator(type) : - parenthesizerRules().parenthesizeOperandOfTypeOperator(type); + node.type = operator === SyntaxKind.ReadonlyKeyword + ? parenthesizerRules().parenthesizeOperandOfReadonlyTypeOperator(type) + : parenthesizerRules().parenthesizeOperandOfTypeOperator(type); node.transformFlags = TransformFlags.ContainsTypeScript; return node; } @@ -2587,13 +2978,20 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode) { return node.objectType !== objectType - || node.indexType !== indexType + || node.indexType !== indexType ? update(createIndexedAccessTypeNode(objectType, indexType), node) : node; } // @api - function createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: readonly TypeElement[] | undefined): MappedTypeNode { + function createMappedTypeNode( + readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, + typeParameter: TypeParameterDeclaration, + nameType: TypeNode | undefined, + questionToken: QuestionToken | PlusToken | MinusToken | undefined, + type: TypeNode | undefined, + members: readonly TypeElement[] | undefined, + ): MappedTypeNode { const node = createBaseDeclaration(SyntaxKind.MappedType); node.readonlyToken = readonlyToken; node.typeParameter = typeParameter; @@ -2609,13 +3007,21 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: readonly TypeElement[] | undefined): MappedTypeNode { + function updateMappedTypeNode( + node: MappedTypeNode, + readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, + typeParameter: TypeParameterDeclaration, + nameType: TypeNode | undefined, + questionToken: QuestionToken | PlusToken | MinusToken | undefined, + type: TypeNode | undefined, + members: readonly TypeElement[] | undefined, + ): MappedTypeNode { return node.readonlyToken !== readonlyToken - || node.typeParameter !== typeParameter - || node.nameType !== nameType - || node.questionToken !== questionToken - || node.type !== type - || node.members !== members + || node.typeParameter !== typeParameter + || node.nameType !== nameType + || node.questionToken !== questionToken + || node.type !== type + || node.members !== members ? update(createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), node) : node; } @@ -2643,14 +3049,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createObjectBindingPattern(elements: readonly BindingElement[]) { const node = createBaseNode(SyntaxKind.ObjectBindingPattern); node.elements = createNodeArray(elements); - node.transformFlags |= - propagateChildrenFlags(node.elements) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsBindingPattern; + node.transformFlags |= propagateChildrenFlags(node.elements) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsBindingPattern; if (node.transformFlags & TransformFlags.ContainsRestOrSpread) { - node.transformFlags |= - TransformFlags.ContainsES2018 | - TransformFlags.ContainsObjectRestOrSpread; + node.transformFlags |= TransformFlags.ContainsES2018 + | TransformFlags.ContainsObjectRestOrSpread; } return node; } @@ -2666,10 +3070,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createArrayBindingPattern(elements: readonly ArrayBindingElement[]) { const node = createBaseNode(SyntaxKind.ArrayBindingPattern); node.elements = createNodeArray(elements); - node.transformFlags |= - propagateChildrenFlags(node.elements) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsBindingPattern; + node.transformFlags |= propagateChildrenFlags(node.elements) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsBindingPattern; return node; } @@ -2681,30 +3084,40 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression) { + function createBindingElement( + dotDotDotToken: DotDotDotToken | undefined, + propertyName: string | PropertyName | undefined, + name: string | BindingName, + initializer?: Expression, + ) { const node = createBaseDeclaration(SyntaxKind.BindingElement); node.dotDotDotToken = dotDotDotToken; node.propertyName = asName(propertyName); node.name = asName(name); node.initializer = asInitializer(initializer); - node.transformFlags |= - propagateChildFlags(node.dotDotDotToken) | - propagateNameFlags(node.propertyName) | - propagateNameFlags(node.name) | - propagateChildFlags(node.initializer) | - (node.dotDotDotToken ? TransformFlags.ContainsRestOrSpread : TransformFlags.None) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.dotDotDotToken) + | propagateNameFlags(node.propertyName) + | propagateNameFlags(node.name) + | propagateChildFlags(node.initializer) + | (node.dotDotDotToken ? TransformFlags.ContainsRestOrSpread : TransformFlags.None) + | TransformFlags.ContainsES2015; node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } // @api - function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined) { + function updateBindingElement( + node: BindingElement, + dotDotDotToken: DotDotDotToken | undefined, + propertyName: PropertyName | undefined, + name: BindingName, + initializer: Expression | undefined, + ) { return node.propertyName !== propertyName - || node.dotDotDotToken !== dotDotDotToken - || node.name !== name - || node.initializer !== initializer + || node.dotDotDotToken !== dotDotDotToken + || node.name !== name + || node.initializer !== initializer ? update(createBindingElement(dotDotDotToken, propertyName, name, initializer), node) : node; } @@ -2720,7 +3133,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // we end up with `[1, 2, ,]` instead of `[1, 2, ]` otherwise the `OmittedExpression` will just end up being treated like // a trailing comma. const lastElement = elements && lastOrUndefined(elements); - const elementsArray = createNodeArray(elements, lastElement && isOmittedExpression(lastElement) ? true : undefined); + const elementsArray = createNodeArray( + elements, + lastElement && isOmittedExpression(lastElement) ? true : undefined, + ); node.elements = parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(elementsArray); node.multiLine = multiLine; node.transformFlags |= propagateChildrenFlags(node.elements); @@ -2746,23 +3162,29 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) { + function updateObjectLiteralExpression( + node: ObjectLiteralExpression, + properties: readonly ObjectLiteralElementLike[], + ) { return node.properties !== properties ? update(createObjectLiteralExpression(properties, node.multiLine), node) : node; } - function createBasePropertyAccessExpression(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, name: MemberName) { + function createBasePropertyAccessExpression( + expression: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + name: MemberName, + ) { const node = createBaseDeclaration(SyntaxKind.PropertyAccessExpression); node.expression = expression; node.questionDotToken = questionDotToken; node.name = name; - node.transformFlags = - propagateChildFlags(node.expression) | - propagateChildFlags(node.questionDotToken) | - (isIdentifier(node.name) ? - propagateIdentifierNameFlags(node.name) : - propagateChildFlags(node.name) | TransformFlags.ContainsPrivateIdentifierInExpression); + node.transformFlags = propagateChildFlags(node.expression) + | propagateChildFlags(node.questionDotToken) + | (isIdentifier(node.name) + ? propagateIdentifierNameFlags(node.name) + : propagateChildFlags(node.name) | TransformFlags.ContainsPrivateIdentifierInExpression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -2774,35 +3196,42 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBasePropertyAccessExpression( parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false), /*questionDotToken*/ undefined, - asName(name) + asName(name), ); if (isSuperKeyword(expression)) { // super method calls require a lexical 'this' // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators - node.transformFlags |= - TransformFlags.ContainsES2017 | - TransformFlags.ContainsES2018; + node.transformFlags |= TransformFlags.ContainsES2017 + | TransformFlags.ContainsES2018; } return node; } // @api - function updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) { + function updatePropertyAccessExpression( + node: PropertyAccessExpression, + expression: Expression, + name: Identifier | PrivateIdentifier, + ) { if (isPropertyAccessChain(node)) { return updatePropertyAccessChain(node, expression, node.questionDotToken, cast(name, isIdentifier)); } return node.expression !== expression - || node.name !== name + || node.name !== name ? update(createPropertyAccessExpression(expression, name), node) : node; } // @api - function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) { + function createPropertyAccessChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: string | Identifier | PrivateIdentifier, + ) { const node = createBasePropertyAccessExpression( parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true), questionDotToken, - asName(name) + asName(name), ) as Mutable; node.flags |= NodeFlags.OptionalChain; node.transformFlags |= TransformFlags.ContainsES2020; @@ -2810,26 +3239,37 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier) { - Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a PropertyAccessExpression using updatePropertyAccessChain. Use updatePropertyAccess instead."); + function updatePropertyAccessChain( + node: PropertyAccessChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: Identifier | PrivateIdentifier, + ) { + Debug.assert( + !!(node.flags & NodeFlags.OptionalChain), + "Cannot update a PropertyAccessExpression using updatePropertyAccessChain. Use updatePropertyAccess instead.", + ); // Because we are updating an existing PropertyAccessChain we want to inherit its emitFlags // instead of using the default from createPropertyAccess return node.expression !== expression - || node.questionDotToken !== questionDotToken - || node.name !== name + || node.questionDotToken !== questionDotToken + || node.name !== name ? update(createPropertyAccessChain(expression, questionDotToken, name), node) : node; } - function createBaseElementAccessExpression(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression) { + function createBaseElementAccessExpression( + expression: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + argumentExpression: Expression, + ) { const node = createBaseDeclaration(SyntaxKind.ElementAccessExpression); node.expression = expression; node.questionDotToken = questionDotToken; node.argumentExpression = argumentExpression; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.questionDotToken) | - propagateChildFlags(node.argumentExpression); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.questionDotToken) + | propagateChildFlags(node.argumentExpression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -2841,35 +3281,42 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseElementAccessExpression( parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false), /*questionDotToken*/ undefined, - asExpression(index) + asExpression(index), ); if (isSuperKeyword(expression)) { // super method calls require a lexical 'this' // super method calls require 'super' hoisting in ES2017 and ES2018 async functions and async generators - node.transformFlags |= - TransformFlags.ContainsES2017 | - TransformFlags.ContainsES2018; + node.transformFlags |= TransformFlags.ContainsES2017 + | TransformFlags.ContainsES2018; } return node; } // @api - function updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) { + function updateElementAccessExpression( + node: ElementAccessExpression, + expression: Expression, + argumentExpression: Expression, + ) { if (isElementAccessChain(node)) { return updateElementAccessChain(node, expression, node.questionDotToken, argumentExpression); } return node.expression !== expression - || node.argumentExpression !== argumentExpression + || node.argumentExpression !== argumentExpression ? update(createElementAccessExpression(expression, argumentExpression), node) : node; } // @api - function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression) { + function createElementAccessChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + index: number | Expression, + ) { const node = createBaseElementAccessExpression( parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true), questionDotToken, - asExpression(index) + asExpression(index), ) as Mutable; node.flags |= NodeFlags.OptionalChain; node.transformFlags |= TransformFlags.ContainsES2020; @@ -2877,28 +3324,40 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression) { - Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a ElementAccessExpression using updateElementAccessChain. Use updateElementAccess instead."); + function updateElementAccessChain( + node: ElementAccessChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + argumentExpression: Expression, + ) { + Debug.assert( + !!(node.flags & NodeFlags.OptionalChain), + "Cannot update a ElementAccessExpression using updateElementAccessChain. Use updateElementAccess instead.", + ); // Because we are updating an existing ElementAccessChain we want to inherit its emitFlags // instead of using the default from createElementAccess return node.expression !== expression - || node.questionDotToken !== questionDotToken - || node.argumentExpression !== argumentExpression + || node.questionDotToken !== questionDotToken + || node.argumentExpression !== argumentExpression ? update(createElementAccessChain(expression, questionDotToken, argumentExpression), node) : node; } - function createBaseCallExpression(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray | undefined, argumentsArray: NodeArray) { + function createBaseCallExpression( + expression: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: NodeArray | undefined, + argumentsArray: NodeArray, + ) { const node = createBaseDeclaration(SyntaxKind.CallExpression); node.expression = expression; node.questionDotToken = questionDotToken; node.typeArguments = typeArguments; node.arguments = argumentsArray; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.questionDotToken) | - propagateChildrenFlags(node.typeArguments) | - propagateChildrenFlags(node.arguments); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.questionDotToken) + | propagateChildrenFlags(node.typeArguments) + | propagateChildrenFlags(node.arguments); if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -2909,7 +3368,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function createCallExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ) { const node = createBaseCallExpression( parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false), /*questionDotToken*/ undefined, @@ -2923,24 +3386,34 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateCallExpression(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) { + function updateCallExpression( + node: CallExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[], + ) { if (isCallChain(node)) { return updateCallChain(node, expression, node.questionDotToken, typeArguments, argumentsArray); } return node.expression !== expression - || node.typeArguments !== typeArguments - || node.arguments !== argumentsArray + || node.typeArguments !== typeArguments + || node.arguments !== argumentsArray ? update(createCallExpression(expression, typeArguments, argumentsArray), node) : node; } // @api - function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function createCallChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ) { const node = createBaseCallExpression( parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true), questionDotToken, asNodeArray(typeArguments), - parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray)) + parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(createNodeArray(argumentsArray)), ) as Mutable; node.flags |= NodeFlags.OptionalChain; node.transformFlags |= TransformFlags.ContainsES2020; @@ -2948,27 +3421,40 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) { - Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a CallExpression using updateCallChain. Use updateCall instead."); + function updateCallChain( + node: CallChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[], + ) { + Debug.assert( + !!(node.flags & NodeFlags.OptionalChain), + "Cannot update a CallExpression using updateCallChain. Use updateCall instead.", + ); return node.expression !== expression - || node.questionDotToken !== questionDotToken - || node.typeArguments !== typeArguments - || node.arguments !== argumentsArray + || node.questionDotToken !== questionDotToken + || node.typeArguments !== typeArguments + || node.arguments !== argumentsArray ? update(createCallChain(expression, questionDotToken, typeArguments, argumentsArray), node) : node; } // @api - function createNewExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function createNewExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ) { const node = createBaseDeclaration(SyntaxKind.NewExpression); node.expression = parenthesizerRules().parenthesizeExpressionOfNew(expression); node.typeArguments = asNodeArray(typeArguments); - node.arguments = argumentsArray ? parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(argumentsArray) : undefined; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildrenFlags(node.typeArguments) | - propagateChildrenFlags(node.arguments) | - TransformFlags.ContainsES2020; + node.arguments = argumentsArray + ? parenthesizerRules().parenthesizeExpressionsOfCommaDelimitedList(argumentsArray) : undefined; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildrenFlags(node.typeArguments) + | propagateChildrenFlags(node.arguments) + | TransformFlags.ContainsES2020; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -2976,25 +3462,33 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateNewExpression(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) { + function updateNewExpression( + node: NewExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ) { return node.expression !== expression - || node.typeArguments !== typeArguments - || node.arguments !== argumentsArray + || node.typeArguments !== typeArguments + || node.arguments !== argumentsArray ? update(createNewExpression(expression, typeArguments, argumentsArray), node) : node; } // @api - function createTaggedTemplateExpression(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) { + function createTaggedTemplateExpression( + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ) { const node = createBaseNode(SyntaxKind.TaggedTemplateExpression); node.tag = parenthesizerRules().parenthesizeLeftSideOfAccess(tag, /*optionalChain*/ false); node.typeArguments = asNodeArray(typeArguments); node.template = template; - node.transformFlags |= - propagateChildFlags(node.tag) | - propagateChildrenFlags(node.typeArguments) | - propagateChildFlags(node.template) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.tag) + | propagateChildrenFlags(node.typeArguments) + | propagateChildFlags(node.template) + | TransformFlags.ContainsES2015; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -3005,10 +3499,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateTaggedTemplateExpression(node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral) { + function updateTaggedTemplateExpression( + node: TaggedTemplateExpression, + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ) { return node.tag !== tag - || node.typeArguments !== typeArguments - || node.template !== template + || node.typeArguments !== typeArguments + || node.template !== template ? update(createTaggedTemplateExpression(tag, typeArguments, template), node) : node; } @@ -3018,17 +3517,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.TypeAssertionExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); node.type = type; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.type) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.type) + | TransformFlags.ContainsTypeScript; return node; } // @api function updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression) { return node.type !== type - || node.expression !== expression + || node.expression !== expression ? update(createTypeAssertion(type, expression), node) : node; } @@ -3058,7 +3556,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, - body: Block + body: Block, ) { const node = createBaseDeclaration(SyntaxKind.FunctionExpression); node.modifiers = asNodeArray(modifiers); @@ -3073,20 +3571,19 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const isGenerator = !!node.asteriskToken; const isAsyncGenerator = isAsync && isGenerator; - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.asteriskToken) | - propagateNameFlags(node.name) | - propagateChildrenFlags(node.typeParameters) | - propagateChildrenFlags(node.parameters) | - propagateChildFlags(node.type) | - (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) | - (isAsyncGenerator ? TransformFlags.ContainsES2018 : - isAsync ? TransformFlags.ContainsES2017 : - isGenerator ? TransformFlags.ContainsGenerator : - TransformFlags.None) | - (node.typeParameters || node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.asteriskToken) + | propagateNameFlags(node.name) + | propagateChildrenFlags(node.typeParameters) + | propagateChildrenFlags(node.parameters) + | propagateChildFlags(node.type) + | (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) + | (isAsyncGenerator ? TransformFlags.ContainsES2018 + : isAsync ? TransformFlags.ContainsES2017 + : isGenerator ? TransformFlags.ContainsGenerator + : TransformFlags.None) + | (node.typeParameters || node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; node.typeArguments = undefined; // used in quick info node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -3107,16 +3604,19 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, - body: Block + body: Block, ) { return node.name !== name - || node.modifiers !== modifiers - || node.asteriskToken !== asteriskToken - || node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type - || node.body !== body - ? finishUpdateBaseSignatureDeclaration(createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body), node) + || node.modifiers !== modifiers + || node.asteriskToken !== asteriskToken + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? finishUpdateBaseSignatureDeclaration( + createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body), + node, + ) : node; } @@ -3127,7 +3627,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, - body: ConciseBody + body: ConciseBody, ) { const node = createBaseDeclaration(SyntaxKind.ArrowFunction); node.modifiers = asNodeArray(modifiers); @@ -3139,16 +3639,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const isAsync = modifiersToFlags(node.modifiers) & ModifierFlags.Async; - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateChildrenFlags(node.typeParameters) | - propagateChildrenFlags(node.parameters) | - propagateChildFlags(node.type) | - propagateChildFlags(node.equalsGreaterThanToken) | - (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) | - (node.typeParameters || node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) | - (isAsync ? TransformFlags.ContainsES2017 | TransformFlags.ContainsLexicalThis : TransformFlags.None) | - TransformFlags.ContainsES2015; + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateChildrenFlags(node.typeParameters) + | propagateChildrenFlags(node.parameters) + | propagateChildFlags(node.type) + | propagateChildFlags(node.equalsGreaterThanToken) + | (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) + | (node.typeParameters || node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) + | (isAsync ? TransformFlags.ContainsES2017 | TransformFlags.ContainsLexicalThis : TransformFlags.None) + | TransformFlags.ContainsES2015; node.typeArguments = undefined; // used in quick info node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -3168,15 +3667,18 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, - body: ConciseBody + body: ConciseBody, ): ArrowFunction { return node.modifiers !== modifiers - || node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type - || node.equalsGreaterThanToken !== equalsGreaterThanToken - || node.body !== body - ? finishUpdateBaseSignatureDeclaration(createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body), node) + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + || node.equalsGreaterThanToken !== equalsGreaterThanToken + || node.body !== body + ? finishUpdateBaseSignatureDeclaration( + createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body), + node, + ) : node; } @@ -3229,11 +3731,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createAwaitExpression(expression: Expression) { const node = createBaseNode(SyntaxKind.AwaitExpression); node.expression = parenthesizerRules().parenthesizeOperandOfPrefixUnary(expression); - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsES2017 | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsAwait; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2017 + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsAwait; return node; } @@ -3252,10 +3753,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags |= propagateChildFlags(node.operand); // Only set this flag for non-generated identifiers and non-"local" names. See the // comment in `visitPreOrPostfixUnaryExpression` in module.ts - if ((operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken) && - isIdentifier(node.operand) && - !isGeneratedIdentifier(node.operand) && - !isLocalName(node.operand)) { + if ( + (operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken) + && isIdentifier(node.operand) + && !isGeneratedIdentifier(node.operand) + && !isLocalName(node.operand) + ) { node.transformFlags |= TransformFlags.ContainsUpdateExpressionForIdentifier; } return node; @@ -3276,9 +3779,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags |= propagateChildFlags(node.operand); // Only set this flag for non-generated identifiers and non-"local" names. See the // comment in `visitPreOrPostfixUnaryExpression` in module.ts - if (isIdentifier(node.operand) && - !isGeneratedIdentifier(node.operand) && - !isLocalName(node.operand)) { + if ( + isIdentifier(node.operand) + && !isGeneratedIdentifier(node.operand) + && !isLocalName(node.operand) + ) { node.transformFlags |= TransformFlags.ContainsUpdateExpressionForIdentifier; } return node; @@ -3292,36 +3797,39 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createBinaryExpression(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression) { + function createBinaryExpression( + left: Expression, + operator: BinaryOperator | BinaryOperatorToken, + right: Expression, + ) { const node = createBaseDeclaration(SyntaxKind.BinaryExpression); const operatorToken = asToken(operator); const operatorKind = operatorToken.kind; node.left = parenthesizerRules().parenthesizeLeftSideOfBinary(operatorKind, left); node.operatorToken = operatorToken; node.right = parenthesizerRules().parenthesizeRightSideOfBinary(operatorKind, node.left, right); - node.transformFlags |= - propagateChildFlags(node.left) | - propagateChildFlags(node.operatorToken) | - propagateChildFlags(node.right); + node.transformFlags |= propagateChildFlags(node.left) + | propagateChildFlags(node.operatorToken) + | propagateChildFlags(node.right); if (operatorKind === SyntaxKind.QuestionQuestionToken) { node.transformFlags |= TransformFlags.ContainsES2020; } else if (operatorKind === SyntaxKind.EqualsToken) { if (isObjectLiteralExpression(node.left)) { - node.transformFlags |= - TransformFlags.ContainsES2015 | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsDestructuringAssignment | - propagateAssignmentPatternFlags(node.left); + node.transformFlags |= TransformFlags.ContainsES2015 + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsDestructuringAssignment + | propagateAssignmentPatternFlags(node.left); } else if (isArrayLiteralExpression(node.left)) { - node.transformFlags |= - TransformFlags.ContainsES2015 | - TransformFlags.ContainsDestructuringAssignment | - propagateAssignmentPatternFlags(node.left); + node.transformFlags |= TransformFlags.ContainsES2015 + | TransformFlags.ContainsDestructuringAssignment + | propagateAssignmentPatternFlags(node.left); } } - else if (operatorKind === SyntaxKind.AsteriskAsteriskToken || operatorKind === SyntaxKind.AsteriskAsteriskEqualsToken) { + else if ( + operatorKind === SyntaxKind.AsteriskAsteriskToken || operatorKind === SyntaxKind.AsteriskAsteriskEqualsToken + ) { node.transformFlags |= TransformFlags.ContainsES2016; } else if (isLogicalOrCoalescingAssignmentOperator(operatorKind)) { @@ -3340,28 +3848,38 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateBinaryExpression(node: BinaryExpression, left: Expression, operator: BinaryOperatorToken, right: Expression) { + function updateBinaryExpression( + node: BinaryExpression, + left: Expression, + operator: BinaryOperatorToken, + right: Expression, + ) { return node.left !== left - || node.operatorToken !== operator - || node.right !== right + || node.operatorToken !== operator + || node.right !== right ? update(createBinaryExpression(left, operator, right), node) : node; } // @api - function createConditionalExpression(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression) { + function createConditionalExpression( + condition: Expression, + questionToken: QuestionToken | undefined, + whenTrue: Expression, + colonToken: ColonToken | undefined, + whenFalse: Expression, + ) { const node = createBaseNode(SyntaxKind.ConditionalExpression); node.condition = parenthesizerRules().parenthesizeConditionOfConditionalExpression(condition); node.questionToken = questionToken ?? createToken(SyntaxKind.QuestionToken); node.whenTrue = parenthesizerRules().parenthesizeBranchOfConditionalExpression(whenTrue); node.colonToken = colonToken ?? createToken(SyntaxKind.ColonToken); node.whenFalse = parenthesizerRules().parenthesizeBranchOfConditionalExpression(whenFalse); - node.transformFlags |= - propagateChildFlags(node.condition) | - propagateChildFlags(node.questionToken) | - propagateChildFlags(node.whenTrue) | - propagateChildFlags(node.colonToken) | - propagateChildFlags(node.whenFalse); + node.transformFlags |= propagateChildFlags(node.condition) + | propagateChildFlags(node.questionToken) + | propagateChildFlags(node.whenTrue) + | propagateChildFlags(node.colonToken) + | propagateChildFlags(node.whenFalse); return node; } @@ -3372,13 +3890,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode questionToken: Token, whenTrue: Expression, colonToken: Token, - whenFalse: Expression + whenFalse: Expression, ): ConditionalExpression { return node.condition !== condition - || node.questionToken !== questionToken - || node.whenTrue !== whenTrue - || node.colonToken !== colonToken - || node.whenFalse !== whenFalse + || node.questionToken !== questionToken + || node.whenTrue !== whenTrue + || node.colonToken !== colonToken + || node.whenFalse !== whenFalse ? update(createConditionalExpression(condition, questionToken, whenTrue, colonToken, whenFalse), node) : node; } @@ -3388,22 +3906,30 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.TemplateExpression); node.head = head; node.templateSpans = createNodeArray(templateSpans); - node.transformFlags |= - propagateChildFlags(node.head) | - propagateChildrenFlags(node.templateSpans) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.head) + | propagateChildrenFlags(node.templateSpans) + | TransformFlags.ContainsES2015; return node; } // @api - function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]) { + function updateTemplateExpression( + node: TemplateExpression, + head: TemplateHead, + templateSpans: readonly TemplateSpan[], + ) { return node.head !== head - || node.templateSpans !== templateSpans + || node.templateSpans !== templateSpans ? update(createTemplateExpression(head, templateSpans), node) : node; } - function checkTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string | undefined, rawText: string | undefined, templateFlags = TokenFlags.None) { + function checkTemplateLiteralLikeNode( + kind: TemplateLiteralToken["kind"], + text: string | undefined, + rawText: string | undefined, + templateFlags = TokenFlags.None, + ) { Debug.assert(!(templateFlags & ~TokenFlags.TemplateLiteralLikeFlags), "Unsupported template flags."); // NOTE: without the assignment to `undefined`, we don't narrow the initial type of `cooked`. // eslint-disable-next-line no-undef-init @@ -3421,7 +3947,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode text = cooked; } else if (cooked !== undefined) { - Debug.assert(text === cooked, "Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'."); + Debug.assert( + text === cooked, + "Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.", + ); } return text; } @@ -3437,7 +3966,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // NOTE: `createTemplateLiteralLikeToken` and `createTemplateLiteralLikeDeclaration` are identical except for // the underlying nodes they create. To avoid polymorphism due to two different node shapes, these // functions are intentionally duplicated. - function createTemplateLiteralLikeToken(kind: TemplateLiteralToken["kind"], text: string, rawText: string | undefined, templateFlags: TokenFlags | undefined) { + function createTemplateLiteralLikeToken( + kind: TemplateLiteralToken["kind"], + text: string, + rawText: string | undefined, + templateFlags: TokenFlags | undefined, + ) { const node = createBaseToken(kind); node.text = text; node.rawText = rawText; @@ -3446,7 +3980,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return node; } - function createTemplateLiteralLikeDeclaration(kind: SyntaxKind.NoSubstitutionTemplateLiteral, text: string, rawText: string | undefined, templateFlags: TokenFlags | undefined) { + function createTemplateLiteralLikeDeclaration( + kind: SyntaxKind.NoSubstitutionTemplateLiteral, + text: string, + rawText: string | undefined, + templateFlags: TokenFlags | undefined, + ) { const node = createBaseDeclaration(kind); node.text = text; node.rawText = rawText; @@ -3456,7 +3995,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string, rawText: string | undefined, templateFlags: TokenFlags | undefined) { + function createTemplateLiteralLikeNode( + kind: TemplateLiteralToken["kind"], + text: string, + rawText: string | undefined, + templateFlags: TokenFlags | undefined, + ) { if (kind === SyntaxKind.NoSubstitutionTemplateLiteral) { return createTemplateLiteralLikeDeclaration(kind, text, rawText, templateFlags); } @@ -3482,30 +4026,48 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createNoSubstitutionTemplateLiteral(text: string | undefined, rawText?: string, templateFlags?: TokenFlags) { + function createNoSubstitutionTemplateLiteral( + text: string | undefined, + rawText?: string, + templateFlags?: TokenFlags, + ) { text = checkTemplateLiteralLikeNode(SyntaxKind.TemplateHead, text, rawText, templateFlags); - return createTemplateLiteralLikeDeclaration(SyntaxKind.NoSubstitutionTemplateLiteral, text, rawText, templateFlags) as NoSubstitutionTemplateLiteral; + return createTemplateLiteralLikeDeclaration( + SyntaxKind.NoSubstitutionTemplateLiteral, + text, + rawText, + templateFlags, + ) as NoSubstitutionTemplateLiteral; } // @api - function createYieldExpression(asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression { - Debug.assert(!asteriskToken || !!expression, "A `YieldExpression` with an asteriskToken must have an expression."); + function createYieldExpression( + asteriskToken: AsteriskToken | undefined, + expression: Expression | undefined, + ): YieldExpression { + Debug.assert( + !asteriskToken || !!expression, + "A `YieldExpression` with an asteriskToken must have an expression.", + ); const node = createBaseNode(SyntaxKind.YieldExpression); node.expression = expression && parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.asteriskToken = asteriskToken; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.asteriskToken) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsYield; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.asteriskToken) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsYield; return node; } // @api - function updateYieldExpression(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression) { + function updateYieldExpression( + node: YieldExpression, + asteriskToken: AsteriskToken | undefined, + expression: Expression, + ) { return node.expression !== expression - || node.asteriskToken !== asteriskToken + || node.asteriskToken !== asteriskToken ? update(createYieldExpression(asteriskToken, expression), node) : node; } @@ -3514,10 +4076,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createSpreadElement(expression: Expression) { const node = createBaseNode(SyntaxKind.SpreadElement); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsES2015 | - TransformFlags.ContainsRestOrSpread; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2015 + | TransformFlags.ContainsRestOrSpread; return node; } @@ -3534,7 +4095,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, - members: readonly ClassElement[] + members: readonly ClassElement[], ) { const node = createBaseDeclaration(SyntaxKind.ClassExpression); node.modifiers = asNodeArray(modifiers); @@ -3542,14 +4103,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeParameters = asNodeArray(typeParameters); node.heritageClauses = asNodeArray(heritageClauses); node.members = createNodeArray(members); - node.transformFlags |= - propagateChildrenFlags(node.modifiers) | - propagateNameFlags(node.name) | - propagateChildrenFlags(node.typeParameters) | - propagateChildrenFlags(node.heritageClauses) | - propagateChildrenFlags(node.members) | - (node.typeParameters ? TransformFlags.ContainsTypeScript : TransformFlags.None) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateNameFlags(node.name) + | propagateChildrenFlags(node.typeParameters) + | propagateChildrenFlags(node.heritageClauses) + | propagateChildrenFlags(node.members) + | (node.typeParameters ? TransformFlags.ContainsTypeScript : TransformFlags.None) + | TransformFlags.ContainsES2015; node.jsDoc = undefined; // initialized by parser (JsDocContainer) return node; @@ -3562,13 +4122,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, - members: readonly ClassElement[] + members: readonly ClassElement[], ) { return node.modifiers !== modifiers - || node.name !== name - || node.typeParameters !== typeParameters - || node.heritageClauses !== heritageClauses - || node.members !== members + || node.name !== name + || node.typeParameters !== typeParameters + || node.heritageClauses !== heritageClauses + || node.members !== members ? update(createClassExpression(modifiers, name, typeParameters, heritageClauses, members), node) : node; } @@ -3583,17 +4143,20 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.ExpressionWithTypeArguments); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); node.typeArguments = typeArguments && parenthesizerRules().parenthesizeTypeArguments(typeArguments); - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildrenFlags(node.typeArguments) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildrenFlags(node.typeArguments) + | TransformFlags.ContainsES2015; return node; } // @api - function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, expression: Expression, typeArguments: readonly TypeNode[] | undefined) { + function updateExpressionWithTypeArguments( + node: ExpressionWithTypeArguments, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + ) { return node.expression !== expression - || node.typeArguments !== typeArguments + || node.typeArguments !== typeArguments ? update(createExpressionWithTypeArguments(expression, typeArguments), node) : node; } @@ -3603,17 +4166,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.AsExpression); node.expression = expression; node.type = type; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.type) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.type) + | TransformFlags.ContainsTypeScript; return node; } // @api function updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode) { return node.expression !== expression - || node.type !== type + || node.type !== type ? update(createAsExpression(expression, type), node) : node; } @@ -3622,9 +4184,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createNonNullExpression(expression: Expression) { const node = createBaseNode(SyntaxKind.NonNullExpression); node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ false); - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsTypeScript; return node; } @@ -3643,17 +4204,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.SatisfiesExpression); node.expression = expression; node.type = type; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.type) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.type) + | TransformFlags.ContainsTypeScript; return node; } // @api function updateSatisfiesExpression(node: SatisfiesExpression, expression: Expression, type: TypeNode) { return node.expression !== expression - || node.type !== type + || node.type !== type ? update(createSatisfiesExpression(expression, type), node) : node; } @@ -3663,15 +4223,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.NonNullExpression); node.flags |= NodeFlags.OptionalChain; node.expression = parenthesizerRules().parenthesizeLeftSideOfAccess(expression, /*optionalChain*/ true); - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsTypeScript; return node; } // @api function updateNonNullChain(node: NonNullChain, expression: Expression) { - Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a NonNullExpression using updateNonNullChain. Use updateNonNullExpression instead."); + Debug.assert( + !!(node.flags & NodeFlags.OptionalChain), + "Cannot update a NonNullExpression using updateNonNullChain. Use updateNonNullExpression instead.", + ); return node.expression !== expression ? update(createNonNullChain(expression), node) : node; @@ -3714,17 +4276,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.TemplateSpan); node.expression = expression; node.literal = literal; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.literal) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.literal) + | TransformFlags.ContainsES2015; return node; } // @api function updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail) { return node.expression !== expression - || node.literal !== literal + || node.literal !== literal ? update(createTemplateSpan(expression, literal), node) : node; } @@ -3761,13 +4322,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createVariableStatement(modifiers: readonly ModifierLike[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]) { + function createVariableStatement( + modifiers: readonly ModifierLike[] | undefined, + declarationList: VariableDeclarationList | readonly VariableDeclaration[], + ) { const node = createBaseNode(SyntaxKind.VariableStatement); node.modifiers = asNodeArray(modifiers); - node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList; - node.transformFlags |= - propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.declarationList); + node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) + : declarationList; + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.declarationList); if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) { node.transformFlags = TransformFlags.ContainsTypeScript; } @@ -3778,9 +4342,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateVariableStatement(node: VariableStatement, modifiers: readonly ModifierLike[] | undefined, declarationList: VariableDeclarationList) { + function updateVariableStatement( + node: VariableStatement, + modifiers: readonly ModifierLike[] | undefined, + declarationList: VariableDeclarationList, + ) { return node.modifiers !== modifiers - || node.declarationList !== declarationList + || node.declarationList !== declarationList ? update(createVariableStatement(modifiers, declarationList), node) : node; } @@ -3816,10 +4384,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.expression = expression; node.thenStatement = asEmbeddedStatement(thenStatement); node.elseStatement = asEmbeddedStatement(elseStatement); - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.thenStatement) | - propagateChildFlags(node.elseStatement); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.thenStatement) + | propagateChildFlags(node.elseStatement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -3827,10 +4394,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateIfStatement(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined) { + function updateIfStatement( + node: IfStatement, + expression: Expression, + thenStatement: Statement, + elseStatement: Statement | undefined, + ) { return node.expression !== expression - || node.thenStatement !== thenStatement - || node.elseStatement !== elseStatement + || node.thenStatement !== thenStatement + || node.elseStatement !== elseStatement ? update(createIfStatement(expression, thenStatement, elseStatement), node) : node; } @@ -3840,9 +4412,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.DoStatement); node.statement = asEmbeddedStatement(statement); node.expression = expression; - node.transformFlags |= - propagateChildFlags(node.statement) | - propagateChildFlags(node.expression); + node.transformFlags |= propagateChildFlags(node.statement) + | propagateChildFlags(node.expression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -3852,7 +4423,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateDoStatement(node: DoStatement, statement: Statement, expression: Expression) { return node.statement !== statement - || node.expression !== expression + || node.expression !== expression ? update(createDoStatement(statement, expression), node) : node; } @@ -3862,9 +4433,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.WhileStatement); node.expression = expression; node.statement = asEmbeddedStatement(statement); - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -3874,23 +4444,27 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateWhileStatement(node: WhileStatement, expression: Expression, statement: Statement) { return node.expression !== expression - || node.statement !== statement + || node.statement !== statement ? update(createWhileStatement(expression, statement), node) : node; } // @api - function createForStatement(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) { + function createForStatement( + initializer: ForInitializer | undefined, + condition: Expression | undefined, + incrementor: Expression | undefined, + statement: Statement, + ) { const node = createBaseNode(SyntaxKind.ForStatement); node.initializer = initializer; node.condition = condition; node.incrementor = incrementor; node.statement = asEmbeddedStatement(statement); - node.transformFlags |= - propagateChildFlags(node.initializer) | - propagateChildFlags(node.condition) | - propagateChildFlags(node.incrementor) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.initializer) + | propagateChildFlags(node.condition) + | propagateChildFlags(node.incrementor) + | propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) @@ -3900,11 +4474,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateForStatement(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) { + function updateForStatement( + node: ForStatement, + initializer: ForInitializer | undefined, + condition: Expression | undefined, + incrementor: Expression | undefined, + statement: Statement, + ) { return node.initializer !== initializer - || node.condition !== condition - || node.incrementor !== incrementor - || node.statement !== statement + || node.condition !== condition + || node.incrementor !== incrementor + || node.statement !== statement ? update(createForStatement(initializer, condition, incrementor, statement), node) : node; } @@ -3915,10 +4495,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.initializer = initializer; node.expression = expression; node.statement = asEmbeddedStatement(statement); - node.transformFlags |= - propagateChildFlags(node.initializer) | - propagateChildFlags(node.expression) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.initializer) + | propagateChildFlags(node.expression) + | propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) @@ -3928,27 +4507,36 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateForInStatement(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement) { + function updateForInStatement( + node: ForInStatement, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ) { return node.initializer !== initializer - || node.expression !== expression - || node.statement !== statement + || node.expression !== expression + || node.statement !== statement ? update(createForInStatement(initializer, expression, statement), node) : node; } // @api - function createForOfStatement(awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) { + function createForOfStatement( + awaitModifier: AwaitKeyword | undefined, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ) { const node = createBaseNode(SyntaxKind.ForOfStatement); node.awaitModifier = awaitModifier; node.initializer = initializer; node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.statement = asEmbeddedStatement(statement); - node.transformFlags |= - propagateChildFlags(node.awaitModifier) | - propagateChildFlags(node.initializer) | - propagateChildFlags(node.expression) | - propagateChildFlags(node.statement) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildFlags(node.awaitModifier) + | propagateChildFlags(node.initializer) + | propagateChildFlags(node.expression) + | propagateChildFlags(node.statement) + | TransformFlags.ContainsES2015; if (awaitModifier) node.transformFlags |= TransformFlags.ContainsES2018; node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -3959,11 +4547,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateForOfStatement(node: ForOfStatement, awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) { + function updateForOfStatement( + node: ForOfStatement, + awaitModifier: AwaitKeyword | undefined, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ) { return node.awaitModifier !== awaitModifier - || node.initializer !== initializer - || node.expression !== expression - || node.statement !== statement + || node.initializer !== initializer + || node.expression !== expression + || node.statement !== statement ? update(createForOfStatement(awaitModifier, initializer, expression, statement), node) : node; } @@ -3972,9 +4566,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createContinueStatement(label?: string | Identifier): ContinueStatement { const node = createBaseNode(SyntaxKind.ContinueStatement); node.label = asName(label); - node.transformFlags |= - propagateChildFlags(node.label) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildFlags(node.label) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -3992,9 +4585,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createBreakStatement(label?: string | Identifier): BreakStatement { const node = createBaseNode(SyntaxKind.BreakStatement); node.label = asName(label); - node.transformFlags |= - propagateChildFlags(node.label) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildFlags(node.label) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -4013,10 +4605,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.ReturnStatement); node.expression = expression; // return in an ES2018 async generator must be awaited - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsHoistedDeclarationOrCompletion; node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -4035,9 +4626,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.WithStatement); node.expression = expression; node.statement = asEmbeddedStatement(statement); - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -4047,7 +4637,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateWithStatement(node: WithStatement, expression: Expression, statement: Statement) { return node.expression !== expression - || node.statement !== statement + || node.statement !== statement ? update(createWithStatement(expression, statement), node) : node; } @@ -4057,9 +4647,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.SwitchStatement); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.caseBlock = caseBlock; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.caseBlock); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.caseBlock); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -4070,7 +4659,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateSwitchStatement(node: SwitchStatement, expression: Expression, caseBlock: CaseBlock) { return node.expression !== expression - || node.caseBlock !== caseBlock + || node.caseBlock !== caseBlock ? update(createSwitchStatement(expression, caseBlock), node) : node; } @@ -4080,9 +4669,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.LabeledStatement); node.label = asName(label); node.statement = asEmbeddedStatement(statement); - node.transformFlags |= - propagateChildFlags(node.label) | - propagateChildFlags(node.statement); + node.transformFlags |= propagateChildFlags(node.label) + | propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -4092,7 +4680,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateLabeledStatement(node: LabeledStatement, label: Identifier, statement: Statement) { return node.label !== label - || node.statement !== statement + || node.statement !== statement ? update(createLabeledStatement(label, statement), node) : node; } @@ -4116,15 +4704,18 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createTryStatement(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) { + function createTryStatement( + tryBlock: Block, + catchClause: CatchClause | undefined, + finallyBlock: Block | undefined, + ) { const node = createBaseNode(SyntaxKind.TryStatement); node.tryBlock = tryBlock; node.catchClause = catchClause; node.finallyBlock = finallyBlock; - node.transformFlags |= - propagateChildFlags(node.tryBlock) | - propagateChildFlags(node.catchClause) | - propagateChildFlags(node.finallyBlock); + node.transformFlags |= propagateChildFlags(node.tryBlock) + | propagateChildFlags(node.catchClause) + | propagateChildFlags(node.finallyBlock); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -4132,10 +4723,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateTryStatement(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) { + function updateTryStatement( + node: TryStatement, + tryBlock: Block, + catchClause: CatchClause | undefined, + finallyBlock: Block | undefined, + ) { return node.tryBlock !== tryBlock - || node.catchClause !== catchClause - || node.finallyBlock !== finallyBlock + || node.catchClause !== catchClause + || node.finallyBlock !== finallyBlock ? update(createTryStatement(tryBlock, catchClause, finallyBlock), node) : node; } @@ -4150,27 +4746,37 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createVariableDeclaration(name: string | BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + function createVariableDeclaration( + name: string | BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) { const node = createBaseDeclaration(SyntaxKind.VariableDeclaration); node.name = asName(name); node.exclamationToken = exclamationToken; node.type = type; node.initializer = asInitializer(initializer); - node.transformFlags |= - propagateNameFlags(node.name) | - propagateChildFlags(node.initializer) | - (node.exclamationToken ?? node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); + node.transformFlags |= propagateNameFlags(node.name) + | propagateChildFlags(node.initializer) + | (node.exclamationToken ?? node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); node.jsDoc = undefined; // initialized by parser (JsDocContainer) return node; } // @api - function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { + function updateVariableDeclaration( + node: VariableDeclaration, + name: BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) { return node.name !== name - || node.type !== type - || node.exclamationToken !== exclamationToken - || node.initializer !== initializer + || node.type !== type + || node.exclamationToken !== exclamationToken + || node.initializer !== initializer ? update(createVariableDeclaration(name, exclamationToken, type, initializer), node) : node; } @@ -4180,13 +4786,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.VariableDeclarationList); node.flags |= flags & NodeFlags.BlockScoped; node.declarations = createNodeArray(declarations); - node.transformFlags |= - propagateChildrenFlags(node.declarations) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags |= propagateChildrenFlags(node.declarations) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; if (flags & NodeFlags.BlockScoped) { - node.transformFlags |= - TransformFlags.ContainsES2015 | - TransformFlags.ContainsBlockScopedBinding; + node.transformFlags |= TransformFlags.ContainsES2015 + | TransformFlags.ContainsBlockScopedBinding; } if (flags & NodeFlags.Using) { node.transformFlags |= TransformFlags.ContainsESNext; @@ -4195,7 +4799,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]) { + function updateVariableDeclarationList( + node: VariableDeclarationList, + declarations: readonly VariableDeclaration[], + ) { return node.declarations !== declarations ? update(createVariableDeclarationList(declarations, node.flags), node) : node; @@ -4209,7 +4816,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, - body: Block | undefined + body: Block | undefined, ) { const node = createBaseDeclaration(SyntaxKind.FunctionDeclaration); node.modifiers = asNodeArray(modifiers); @@ -4228,20 +4835,19 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const isGenerator = !!node.asteriskToken; const isAsyncGenerator = isAsync && isGenerator; - node.transformFlags = - propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.asteriskToken) | - propagateNameFlags(node.name) | - propagateChildrenFlags(node.typeParameters) | - propagateChildrenFlags(node.parameters) | - propagateChildFlags(node.type) | - (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) | - (isAsyncGenerator ? TransformFlags.ContainsES2018 : - isAsync ? TransformFlags.ContainsES2017 : - isGenerator ? TransformFlags.ContainsGenerator : - TransformFlags.None) | - (node.typeParameters || node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) | - TransformFlags.ContainsHoistedDeclarationOrCompletion; + node.transformFlags = propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.asteriskToken) + | propagateNameFlags(node.name) + | propagateChildrenFlags(node.typeParameters) + | propagateChildrenFlags(node.parameters) + | propagateChildFlags(node.type) + | (propagateChildFlags(node.body) & ~TransformFlags.ContainsPossibleTopLevelAwait) + | (isAsyncGenerator ? TransformFlags.ContainsES2018 + : isAsync ? TransformFlags.ContainsES2017 + : isGenerator ? TransformFlags.ContainsGenerator + : TransformFlags.None) + | (node.typeParameters || node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None) + | TransformFlags.ContainsHoistedDeclarationOrCompletion; } node.typeArguments = undefined; // used in quick info @@ -4262,16 +4868,19 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, - body: Block | undefined + body: Block | undefined, ) { return node.modifiers !== modifiers - || node.asteriskToken !== asteriskToken - || node.name !== name - || node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type - || node.body !== body - ? finishUpdateFunctionDeclaration(createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body), node) + || node.asteriskToken !== asteriskToken + || node.name !== name + || node.typeParameters !== typeParameters + || node.parameters !== parameters + || node.type !== type + || node.body !== body + ? finishUpdateFunctionDeclaration( + createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body), + node, + ) : node; } @@ -4279,7 +4888,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode if (updated !== original) { // copy children used only for error reporting if (updated.modifiers === original.modifiers) { - updated.modifiers = original.modifiers; + updated.modifiers = original.modifiers; } } return finishUpdateBaseSignatureDeclaration(updated, original); @@ -4291,7 +4900,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, - members: readonly ClassElement[] + members: readonly ClassElement[], ) { const node = createBaseDeclaration(SyntaxKind.ClassDeclaration); node.modifiers = asNodeArray(modifiers); @@ -4304,14 +4913,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; } else { - node.transformFlags |= - propagateChildrenFlags(node.modifiers) | - propagateNameFlags(node.name) | - propagateChildrenFlags(node.typeParameters) | - propagateChildrenFlags(node.heritageClauses) | - propagateChildrenFlags(node.members) | - (node.typeParameters ? TransformFlags.ContainsTypeScript : TransformFlags.None) | - TransformFlags.ContainsES2015; + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateNameFlags(node.name) + | propagateChildrenFlags(node.typeParameters) + | propagateChildrenFlags(node.heritageClauses) + | propagateChildrenFlags(node.members) + | (node.typeParameters ? TransformFlags.ContainsTypeScript : TransformFlags.None) + | TransformFlags.ContainsES2015; if (node.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -4328,13 +4936,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, - members: readonly ClassElement[] + members: readonly ClassElement[], ) { return node.modifiers !== modifiers - || node.name !== name - || node.typeParameters !== typeParameters - || node.heritageClauses !== heritageClauses - || node.members !== members + || node.name !== name + || node.typeParameters !== typeParameters + || node.heritageClauses !== heritageClauses + || node.members !== members ? update(createClassDeclaration(modifiers, name, typeParameters, heritageClauses, members), node) : node; } @@ -4345,7 +4953,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, - members: readonly TypeElement[] + members: readonly TypeElement[], ) { const node = createBaseDeclaration(SyntaxKind.InterfaceDeclaration); node.modifiers = asNodeArray(modifiers); @@ -4366,13 +4974,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, - members: readonly TypeElement[] + members: readonly TypeElement[], ) { return node.modifiers !== modifiers - || node.name !== name - || node.typeParameters !== typeParameters - || node.heritageClauses !== heritageClauses - || node.members !== members + || node.name !== name + || node.typeParameters !== typeParameters + || node.heritageClauses !== heritageClauses + || node.members !== members ? update(createInterfaceDeclaration(modifiers, name, typeParameters, heritageClauses, members), node) : node; } @@ -4382,7 +4990,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, - type: TypeNode + type: TypeNode, ) { const node = createBaseDeclaration(SyntaxKind.TypeAliasDeclaration); node.modifiers = asNodeArray(modifiers); @@ -4403,12 +5011,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, - type: TypeNode + type: TypeNode, ) { return node.modifiers !== modifiers - || node.name !== name - || node.typeParameters !== typeParameters - || node.type !== type + || node.name !== name + || node.typeParameters !== typeParameters + || node.type !== type ? update(createTypeAliasDeclaration(modifiers, name, typeParameters, type), node) : node; } @@ -4417,17 +5025,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createEnumDeclaration( modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, - members: readonly EnumMember[] + members: readonly EnumMember[], ) { const node = createBaseDeclaration(SyntaxKind.EnumDeclaration); node.modifiers = asNodeArray(modifiers); node.name = asName(name); node.members = createNodeArray(members); - node.transformFlags |= - propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.name) | - propagateChildrenFlags(node.members) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.name) + | propagateChildrenFlags(node.members) + | TransformFlags.ContainsTypeScript; node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Enum declarations cannot contain `await` node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -4439,10 +5046,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node: EnumDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, - members: readonly EnumMember[]) { + members: readonly EnumMember[], + ) { return node.modifiers !== modifiers - || node.name !== name - || node.members !== members + || node.name !== name + || node.members !== members ? update(createEnumDeclaration(modifiers, name, members), node) : node; } @@ -4452,7 +5060,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, - flags = NodeFlags.None + flags = NodeFlags.None, ) { const node = createBaseDeclaration(SyntaxKind.ModuleDeclaration); node.modifiers = asNodeArray(modifiers); @@ -4463,11 +5071,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; } else { - node.transformFlags |= - propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.name) | - propagateChildFlags(node.body) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.name) + | propagateChildFlags(node.body) + | TransformFlags.ContainsTypeScript; } node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Module declarations cannot contain `await`. @@ -4482,11 +5089,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, - body: ModuleBody | undefined + body: ModuleBody | undefined, ) { return node.modifiers !== modifiers - || node.name !== name - || node.body !== body + || node.name !== name + || node.body !== body ? update(createModuleDeclaration(modifiers, name, body, node.flags), node) : node; } @@ -4530,9 +5137,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createNamespaceExportDeclaration(name: string | Identifier) { const node = createBaseDeclaration(SyntaxKind.NamespaceExportDeclaration); node.name = asName(name); - node.transformFlags |= - propagateIdentifierNameFlags(node.name) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateIdentifierNameFlags(node.name) + | TransformFlags.ContainsTypeScript; node.modifiers = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -4546,7 +5152,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode : node; } - function finishUpdateNamespaceExportDeclaration(updated: Mutable, original: NamespaceExportDeclaration) { + function finishUpdateNamespaceExportDeclaration( + updated: Mutable, + original: NamespaceExportDeclaration, + ) { if (updated !== original) { // copy children used only for error reporting updated.modifiers = original.modifiers; @@ -4559,17 +5168,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, name: string | Identifier, - moduleReference: ModuleReference + moduleReference: ModuleReference, ) { const node = createBaseDeclaration(SyntaxKind.ImportEqualsDeclaration); node.modifiers = asNodeArray(modifiers); node.name = asName(name); node.isTypeOnly = isTypeOnly; node.moduleReference = moduleReference; - node.transformFlags |= - propagateChildrenFlags(node.modifiers) | - propagateIdentifierNameFlags(node.name) | - propagateChildFlags(node.moduleReference); + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateIdentifierNameFlags(node.name) + | propagateChildFlags(node.moduleReference); if (!isExternalModuleReference(node.moduleReference)) { node.transformFlags |= TransformFlags.ContainsTypeScript; @@ -4587,12 +5195,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, name: Identifier, - moduleReference: ModuleReference + moduleReference: ModuleReference, ) { return node.modifiers !== modifiers - || node.isTypeOnly !== isTypeOnly - || node.name !== name - || node.moduleReference !== moduleReference + || node.isTypeOnly !== isTypeOnly + || node.name !== name + || node.moduleReference !== moduleReference ? update(createImportEqualsDeclaration(modifiers, isTypeOnly, name, moduleReference), node) : node; } @@ -4602,16 +5210,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, - assertClause: AssertClause | undefined + assertClause: AssertClause | undefined, ): ImportDeclaration { const node = createBaseNode(SyntaxKind.ImportDeclaration); node.modifiers = asNodeArray(modifiers); node.importClause = importClause; node.moduleSpecifier = moduleSpecifier; node.assertClause = assertClause; - node.transformFlags |= - propagateChildFlags(node.importClause) | - propagateChildFlags(node.moduleSpecifier); + node.transformFlags |= propagateChildFlags(node.importClause) + | propagateChildFlags(node.moduleSpecifier); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -4624,25 +5231,28 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode modifiers: readonly ModifierLike[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, - assertClause: AssertClause | undefined + assertClause: AssertClause | undefined, ) { return node.modifiers !== modifiers - || node.importClause !== importClause - || node.moduleSpecifier !== moduleSpecifier - || node.assertClause !== assertClause + || node.importClause !== importClause + || node.moduleSpecifier !== moduleSpecifier + || node.assertClause !== assertClause ? update(createImportDeclaration(modifiers, importClause, moduleSpecifier, assertClause), node) : node; } // @api - function createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause { + function createImportClause( + isTypeOnly: boolean, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + ): ImportClause { const node = createBaseDeclaration(SyntaxKind.ImportClause); node.isTypeOnly = isTypeOnly; node.name = name; node.namedBindings = namedBindings; - node.transformFlags |= - propagateChildFlags(node.name) | - propagateChildFlags(node.namedBindings); + node.transformFlags |= propagateChildFlags(node.name) + | propagateChildFlags(node.namedBindings); if (isTypeOnly) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -4651,10 +5261,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined) { + function updateImportClause( + node: ImportClause, + isTypeOnly: boolean, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + ) { return node.isTypeOnly !== isTypeOnly - || node.name !== name - || node.namedBindings !== namedBindings + || node.name !== name + || node.namedBindings !== namedBindings ? update(createImportClause(isTypeOnly, name, namedBindings), node) : node; } @@ -4669,9 +5284,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateAssertClause(node: AssertClause, elements: readonly AssertEntry[], multiLine?: boolean): AssertClause { + function updateAssertClause( + node: AssertClause, + elements: readonly AssertEntry[], + multiLine?: boolean, + ): AssertClause { return node.elements !== elements - || node.multiLine !== multiLine + || node.multiLine !== multiLine ? update(createAssertClause(elements, multiLine), node) : node; } @@ -4688,13 +5307,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateAssertEntry(node: AssertEntry, name: AssertionKey, value: Expression): AssertEntry { return node.name !== name - || node.value !== value + || node.value !== value ? update(createAssertEntry(name, value), node) : node; } // @api - function createImportTypeAssertionContainer(clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer { + function createImportTypeAssertionContainer( + clause: AssertClause, + multiLine?: boolean, + ): ImportTypeAssertionContainer { const node = createBaseNode(SyntaxKind.ImportTypeAssertionContainer); node.assertClause = clause; node.multiLine = multiLine; @@ -4702,9 +5324,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateImportTypeAssertionContainer(node: ImportTypeAssertionContainer, clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer { + function updateImportTypeAssertionContainer( + node: ImportTypeAssertionContainer, + clause: AssertClause, + multiLine?: boolean, + ): ImportTypeAssertionContainer { return node.assertClause !== clause - || node.multiLine !== multiLine + || node.multiLine !== multiLine ? update(createImportTypeAssertionContainer(clause, multiLine), node) : node; } @@ -4729,9 +5355,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createNamespaceExport(name: Identifier): NamespaceExport { const node = createBaseDeclaration(SyntaxKind.NamespaceExport); node.name = name; - node.transformFlags |= - propagateChildFlags(node.name) | - TransformFlags.ContainsES2020; + node.transformFlags |= propagateChildFlags(node.name) + | TransformFlags.ContainsES2020; node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } @@ -4765,18 +5390,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.isTypeOnly = isTypeOnly; node.propertyName = propertyName; node.name = name; - node.transformFlags |= - propagateChildFlags(node.propertyName) | - propagateChildFlags(node.name); + node.transformFlags |= propagateChildFlags(node.propertyName) + | propagateChildFlags(node.name); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context return node; } // @api - function updateImportSpecifier(node: ImportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier) { + function updateImportSpecifier( + node: ImportSpecifier, + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ) { return node.isTypeOnly !== isTypeOnly - || node.propertyName !== propertyName - || node.name !== name + || node.propertyName !== propertyName + || node.name !== name ? update(createImportSpecifier(isTypeOnly, propertyName, name), node) : node; } @@ -4785,13 +5414,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createExportAssignment( modifiers: readonly ModifierLike[] | undefined, isExportEquals: boolean | undefined, - expression: Expression + expression: Expression, ) { const node = createBaseDeclaration(SyntaxKind.ExportAssignment); node.modifiers = asNodeArray(modifiers); node.isExportEquals = isExportEquals; node.expression = isExportEquals - ? parenthesizerRules().parenthesizeRightSideOfBinary(SyntaxKind.EqualsToken, /*leftSide*/ undefined, expression) + ? parenthesizerRules().parenthesizeRightSideOfBinary( + SyntaxKind.EqualsToken, + /*leftSide*/ undefined, + expression, + ) : parenthesizerRules().parenthesizeExpressionOfExportDefault(expression); node.transformFlags |= propagateChildrenFlags(node.modifiers) | propagateChildFlags(node.expression); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context @@ -4804,10 +5437,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function updateExportAssignment( node: ExportAssignment, modifiers: readonly ModifierLike[] | undefined, - expression: Expression + expression: Expression, ) { return node.modifiers !== modifiers - || node.expression !== expression + || node.expression !== expression ? update(createExportAssignment(modifiers, node.isExportEquals, expression), node) : node; } @@ -4818,7 +5451,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, - assertClause?: AssertClause + assertClause?: AssertClause, ) { const node = createBaseDeclaration(SyntaxKind.ExportDeclaration); node.modifiers = asNodeArray(modifiers); @@ -4826,10 +5459,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.exportClause = exportClause; node.moduleSpecifier = moduleSpecifier; node.assertClause = assertClause; - node.transformFlags |= - propagateChildrenFlags(node.modifiers) | - propagateChildFlags(node.exportClause) | - propagateChildFlags(node.moduleSpecifier); + node.transformFlags |= propagateChildrenFlags(node.modifiers) + | propagateChildFlags(node.exportClause) + | propagateChildFlags(node.moduleSpecifier); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -4843,14 +5475,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, - assertClause: AssertClause | undefined + assertClause: AssertClause | undefined, ) { return node.modifiers !== modifiers - || node.isTypeOnly !== isTypeOnly - || node.exportClause !== exportClause - || node.moduleSpecifier !== moduleSpecifier - || node.assertClause !== assertClause - ? finishUpdateExportDeclaration(createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause), node) + || node.isTypeOnly !== isTypeOnly + || node.exportClause !== exportClause + || node.moduleSpecifier !== moduleSpecifier + || node.assertClause !== assertClause + ? finishUpdateExportDeclaration( + createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause), + node, + ) : node; } @@ -4881,14 +5516,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createExportSpecifier(isTypeOnly: boolean, propertyName: string | Identifier | undefined, name: string | Identifier) { + function createExportSpecifier( + isTypeOnly: boolean, + propertyName: string | Identifier | undefined, + name: string | Identifier, + ) { const node = createBaseNode(SyntaxKind.ExportSpecifier); node.isTypeOnly = isTypeOnly; node.propertyName = asName(propertyName); node.name = asName(name); - node.transformFlags |= - propagateChildFlags(node.propertyName) | - propagateChildFlags(node.name); + node.transformFlags |= propagateChildFlags(node.propertyName) + | propagateChildFlags(node.name); node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context node.jsDoc = undefined; // initialized by parser (JsDocContainer) @@ -4896,10 +5534,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateExportSpecifier(node: ExportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier) { + function updateExportSpecifier( + node: ExportSpecifier, + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ) { return node.isTypeOnly !== isTypeOnly - || node.propertyName !== propertyName - || node.name !== name + || node.propertyName !== propertyName + || node.name !== name ? update(createExportSpecifier(isTypeOnly, propertyName, name), node) : node; } @@ -4946,10 +5589,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api // createJSDocNullableType // createJSDocNonNullableType - function createJSDocPrePostfixUnaryTypeWorker(kind: T["kind"], type: T["type"], postfix = false): T { + function createJSDocPrePostfixUnaryTypeWorker< + T extends JSDocType & { readonly type: TypeNode | undefined; readonly postfix: boolean; }, + >(kind: T["kind"], type: T["type"], postfix = false): T { const node = createJSDocUnaryTypeWorker( kind, - postfix ? type && parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(type) : type + postfix ? type && parenthesizerRules().parenthesizeNonArrayTypeOfPostfixType(type) : type, ) as Mutable; node.postfix = postfix; return node; @@ -4959,7 +5604,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // createJSDocOptionalType // createJSDocVariadicType // createJSDocNamepathType - function createJSDocUnaryTypeWorker(kind: T["kind"], type: T["type"]): T { + function createJSDocUnaryTypeWorker( + kind: T["kind"], + type: T["type"], + ): T { const node = createBaseNode(kind); node.type = type; return node; @@ -4968,30 +5616,38 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api // updateJSDocNonNullableType // updateJSDocNullableType - function updateJSDocPrePostfixUnaryTypeWorker(kind: T["kind"], node: T, type: T["type"]): T { + function updateJSDocPrePostfixUnaryTypeWorker< + T extends JSDocType & { readonly type: TypeNode | undefined; readonly postfix: boolean; }, + >(kind: T["kind"], node: T, type: T["type"]): T { return node.type !== type - ? update(createJSDocPrePostfixUnaryTypeWorker(kind, type, node.postfix), node) - : node; + ? update(createJSDocPrePostfixUnaryTypeWorker(kind, type, node.postfix), node) + : node; } // @api // updateJSDocOptionalType // updateJSDocVariadicType // updateJSDocNamepathType - function updateJSDocUnaryTypeWorker(kind: T["kind"], node: T, type: T["type"]): T { + function updateJSDocUnaryTypeWorker( + kind: T["kind"], + node: T, + type: T["type"], + ): T { return node.type !== type ? update(createJSDocUnaryTypeWorker(kind, type), node) : node; } // @api - function createJSDocFunctionType(parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType { + function createJSDocFunctionType( + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): JSDocFunctionType { const node = createBaseDeclaration(SyntaxKind.JSDocFunctionType); node.parameters = asNodeArray(parameters); node.type = type; - node.transformFlags = - propagateChildrenFlags(node.parameters) | - (node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); + node.transformFlags = propagateChildrenFlags(node.parameters) + | (node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) @@ -5001,15 +5657,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocFunctionType(node: JSDocFunctionType, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType { + function updateJSDocFunctionType( + node: JSDocFunctionType, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): JSDocFunctionType { return node.parameters !== parameters - || node.type !== type + || node.type !== type ? update(createJSDocFunctionType(parameters, type), node) : node; } // @api - function createJSDocTypeLiteral(propertyTags?: readonly JSDocPropertyLikeTag[], isArrayType = false): JSDocTypeLiteral { + function createJSDocTypeLiteral( + propertyTags?: readonly JSDocPropertyLikeTag[], + isArrayType = false, + ): JSDocTypeLiteral { const node = createBaseDeclaration(SyntaxKind.JSDocTypeLiteral); node.jsDocPropertyTags = asNodeArray(propertyTags); node.isArrayType = isArrayType; @@ -5017,9 +5680,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocTypeLiteral(node: JSDocTypeLiteral, propertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean): JSDocTypeLiteral { + function updateJSDocTypeLiteral( + node: JSDocTypeLiteral, + propertyTags: readonly JSDocPropertyLikeTag[] | undefined, + isArrayType: boolean, + ): JSDocTypeLiteral { return node.jsDocPropertyTags !== propertyTags - || node.isArrayType !== isArrayType + || node.isArrayType !== isArrayType ? update(createJSDocTypeLiteral(propertyTags, isArrayType), node) : node; } @@ -5039,7 +5706,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature { + function createJSDocSignature( + typeParameters: readonly JSDocTemplateTag[] | undefined, + parameters: readonly JSDocParameterTag[], + type?: JSDocReturnTag, + ): JSDocSignature { const node = createBaseDeclaration(SyntaxKind.JSDocSignature); node.typeParameters = asNodeArray(typeParameters); node.parameters = createNodeArray(parameters); @@ -5052,10 +5723,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocSignature(node: JSDocSignature, typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type: JSDocReturnTag | undefined): JSDocSignature { + function updateJSDocSignature( + node: JSDocSignature, + typeParameters: readonly JSDocTemplateTag[] | undefined, + parameters: readonly JSDocParameterTag[], + type: JSDocReturnTag | undefined, + ): JSDocSignature { return node.typeParameters !== typeParameters - || node.parameters !== parameters - || node.type !== type + || node.parameters !== parameters + || node.type !== type ? update(createJSDocSignature(typeParameters, parameters, type), node) : node; } @@ -5068,14 +5744,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createBaseJSDocTag(kind: T["kind"], tagName: Identifier, comment: string | NodeArray | undefined) { + function createBaseJSDocTag( + kind: T["kind"], + tagName: Identifier, + comment: string | NodeArray | undefined, + ) { const node = createBaseNode(kind); node.tagName = tagName; node.comment = comment; return node; } - function createBaseJSDocTagDeclaration(kind: T["kind"], tagName: Identifier, comment: string | NodeArray | undefined) { + function createBaseJSDocTagDeclaration( + kind: T["kind"], + tagName: Identifier, + comment: string | NodeArray | undefined, + ) { const node = createBaseDeclaration(kind); node.tagName = tagName; node.comment = comment; @@ -5083,26 +5767,50 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string | NodeArray): JSDocTemplateTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocTemplateTag, tagName ?? createIdentifier("template"), comment); + function createJSDocTemplateTag( + tagName: Identifier | undefined, + constraint: JSDocTypeExpression | undefined, + typeParameters: readonly TypeParameterDeclaration[], + comment?: string | NodeArray, + ): JSDocTemplateTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocTemplateTag, + tagName ?? createIdentifier("template"), + comment, + ); node.constraint = constraint; node.typeParameters = createNodeArray(typeParameters); return node; } // @api - function updateJSDocTemplateTag(node: JSDocTemplateTag, tagName: Identifier = getDefaultTagName(node), constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment: string | NodeArray | undefined): JSDocTemplateTag { + function updateJSDocTemplateTag( + node: JSDocTemplateTag, + tagName: Identifier = getDefaultTagName(node), + constraint: JSDocTypeExpression | undefined, + typeParameters: readonly TypeParameterDeclaration[], + comment: string | NodeArray | undefined, + ): JSDocTemplateTag { return node.tagName !== tagName - || node.constraint !== constraint - || node.typeParameters !== typeParameters - || node.comment !== comment + || node.constraint !== constraint + || node.typeParameters !== typeParameters + || node.comment !== comment ? update(createJSDocTemplateTag(tagName, constraint, typeParameters, comment), node) : node; } // @api - function createJSDocTypedefTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray): JSDocTypedefTag { - const node = createBaseJSDocTagDeclaration(SyntaxKind.JSDocTypedefTag, tagName ?? createIdentifier("typedef"), comment); + function createJSDocTypedefTag( + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + fullName?: Identifier | JSDocNamespaceDeclaration, + comment?: string | NodeArray, + ): JSDocTypedefTag { + const node = createBaseJSDocTagDeclaration( + SyntaxKind.JSDocTypedefTag, + tagName ?? createIdentifier("typedef"), + comment, + ); node.typeExpression = typeExpression; node.fullName = fullName; node.name = getJSDocTypeAliasName(fullName); @@ -5113,18 +5821,35 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocTypedefTag(node: JSDocTypedefTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocTypedefTag { + function updateJSDocTypedefTag( + node: JSDocTypedefTag, + tagName: Identifier = getDefaultTagName(node), + typeExpression: JSDocTypeExpression | undefined, + fullName: Identifier | JSDocNamespaceDeclaration | undefined, + comment: string | NodeArray | undefined, + ): JSDocTypedefTag { return node.tagName !== tagName - || node.typeExpression !== typeExpression - || node.fullName !== fullName - || node.comment !== comment + || node.typeExpression !== typeExpression + || node.fullName !== fullName + || node.comment !== comment ? update(createJSDocTypedefTag(tagName, typeExpression, fullName, comment), node) : node; } // @api - function createJSDocParameterTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray): JSDocParameterTag { - const node = createBaseJSDocTagDeclaration(SyntaxKind.JSDocParameterTag, tagName ?? createIdentifier("param"), comment); + function createJSDocParameterTag( + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression, + isNameFirst?: boolean, + comment?: string | NodeArray, + ): JSDocParameterTag { + const node = createBaseJSDocTagDeclaration( + SyntaxKind.JSDocParameterTag, + tagName ?? createIdentifier("param"), + comment, + ); node.typeExpression = typeExpression; node.name = name; node.isNameFirst = !!isNameFirst; @@ -5133,20 +5858,39 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray | undefined): JSDocParameterTag { + function updateJSDocParameterTag( + node: JSDocParameterTag, + tagName: Identifier = getDefaultTagName(node), + name: EntityName, + isBracketed: boolean, + typeExpression: JSDocTypeExpression | undefined, + isNameFirst: boolean, + comment: string | NodeArray | undefined, + ): JSDocParameterTag { return node.tagName !== tagName - || node.name !== name - || node.isBracketed !== isBracketed - || node.typeExpression !== typeExpression - || node.isNameFirst !== isNameFirst - || node.comment !== comment + || node.name !== name + || node.isBracketed !== isBracketed + || node.typeExpression !== typeExpression + || node.isNameFirst !== isNameFirst + || node.comment !== comment ? update(createJSDocParameterTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment), node) : node; } // @api - function createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray): JSDocPropertyTag { - const node = createBaseJSDocTagDeclaration(SyntaxKind.JSDocPropertyTag, tagName ?? createIdentifier("prop"), comment); + function createJSDocPropertyTag( + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression, + isNameFirst?: boolean, + comment?: string | NodeArray, + ): JSDocPropertyTag { + const node = createBaseJSDocTagDeclaration( + SyntaxKind.JSDocPropertyTag, + tagName ?? createIdentifier("prop"), + comment, + ); node.typeExpression = typeExpression; node.name = name; node.isNameFirst = !!isNameFirst; @@ -5155,20 +5899,37 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier = getDefaultTagName(node), name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray | undefined): JSDocPropertyTag { + function updateJSDocPropertyTag( + node: JSDocPropertyTag, + tagName: Identifier = getDefaultTagName(node), + name: EntityName, + isBracketed: boolean, + typeExpression: JSDocTypeExpression | undefined, + isNameFirst: boolean, + comment: string | NodeArray | undefined, + ): JSDocPropertyTag { return node.tagName !== tagName - || node.name !== name - || node.isBracketed !== isBracketed - || node.typeExpression !== typeExpression - || node.isNameFirst !== isNameFirst - || node.comment !== comment + || node.name !== name + || node.isBracketed !== isBracketed + || node.typeExpression !== typeExpression + || node.isNameFirst !== isNameFirst + || node.comment !== comment ? update(createJSDocPropertyTag(tagName, name, isBracketed, typeExpression, isNameFirst, comment), node) : node; } // @api - function createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray): JSDocCallbackTag { - const node = createBaseJSDocTagDeclaration(SyntaxKind.JSDocCallbackTag, tagName ?? createIdentifier("callback"), comment); + function createJSDocCallbackTag( + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + fullName?: Identifier | JSDocNamespaceDeclaration, + comment?: string | NodeArray, + ): JSDocCallbackTag { + const node = createBaseJSDocTagDeclaration( + SyntaxKind.JSDocCallbackTag, + tagName ?? createIdentifier("callback"), + comment, + ); node.typeExpression = typeExpression; node.fullName = fullName; node.name = getJSDocTypeAliasName(fullName); @@ -5179,66 +5940,119 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocCallbackTag { + function updateJSDocCallbackTag( + node: JSDocCallbackTag, + tagName: Identifier = getDefaultTagName(node), + typeExpression: JSDocSignature, + fullName: Identifier | JSDocNamespaceDeclaration | undefined, + comment: string | NodeArray | undefined, + ): JSDocCallbackTag { return node.tagName !== tagName - || node.typeExpression !== typeExpression - || node.fullName !== fullName - || node.comment !== comment + || node.typeExpression !== typeExpression + || node.fullName !== fullName + || node.comment !== comment ? update(createJSDocCallbackTag(tagName, typeExpression, fullName, comment), node) : node; } // @api - function createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray): JSDocOverloadTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocOverloadTag, tagName ?? createIdentifier("overload"), comment); + function createJSDocOverloadTag( + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + comment?: string | NodeArray, + ): JSDocOverloadTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocOverloadTag, + tagName ?? createIdentifier("overload"), + comment, + ); node.typeExpression = typeExpression; return node; } // @api - function updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocSignature, comment: string | NodeArray | undefined): JSDocOverloadTag { + function updateJSDocOverloadTag( + node: JSDocOverloadTag, + tagName: Identifier = getDefaultTagName(node), + typeExpression: JSDocSignature, + comment: string | NodeArray | undefined, + ): JSDocOverloadTag { return node.tagName !== tagName - || node.typeExpression !== typeExpression - || node.comment !== comment + || node.typeExpression !== typeExpression + || node.comment !== comment ? update(createJSDocOverloadTag(tagName, typeExpression, comment), node) : node; } // @api - function createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray): JSDocAugmentsTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocAugmentsTag, tagName ?? createIdentifier("augments"), comment); + function createJSDocAugmentsTag( + tagName: Identifier | undefined, + className: JSDocAugmentsTag["class"], + comment?: string | NodeArray, + ): JSDocAugmentsTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocAugmentsTag, + tagName ?? createIdentifier("augments"), + comment, + ); node.class = className; return node; } // @api - function updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocAugmentsTag["class"], comment: string | NodeArray | undefined): JSDocAugmentsTag { + function updateJSDocAugmentsTag( + node: JSDocAugmentsTag, + tagName: Identifier = getDefaultTagName(node), + className: JSDocAugmentsTag["class"], + comment: string | NodeArray | undefined, + ): JSDocAugmentsTag { return node.tagName !== tagName - || node.class !== className - || node.comment !== comment + || node.class !== className + || node.comment !== comment ? update(createJSDocAugmentsTag(tagName, className, comment), node) : node; } // @api - function createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray): JSDocImplementsTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocImplementsTag, tagName ?? createIdentifier("implements"), comment); + function createJSDocImplementsTag( + tagName: Identifier | undefined, + className: JSDocImplementsTag["class"], + comment?: string | NodeArray, + ): JSDocImplementsTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocImplementsTag, + tagName ?? createIdentifier("implements"), + comment, + ); node.class = className; return node; } // @api - function createJSDocSeeTag(tagName: Identifier | undefined, name: JSDocNameReference | undefined, comment?: string | NodeArray): JSDocSeeTag { - const node = createBaseJSDocTag(SyntaxKind.JSDocSeeTag, tagName ?? createIdentifier("see"), comment); + function createJSDocSeeTag( + tagName: Identifier | undefined, + name: JSDocNameReference | undefined, + comment?: string | NodeArray, + ): JSDocSeeTag { + const node = createBaseJSDocTag( + SyntaxKind.JSDocSeeTag, + tagName ?? createIdentifier("see"), + comment, + ); node.name = name; return node; } // @api - function updateJSDocSeeTag(node: JSDocSeeTag, tagName: Identifier | undefined, name: JSDocNameReference | undefined, comment?: string | NodeArray): JSDocSeeTag { + function updateJSDocSeeTag( + node: JSDocSeeTag, + tagName: Identifier | undefined, + name: JSDocNameReference | undefined, + comment?: string | NodeArray, + ): JSDocSeeTag { return node.tagName !== tagName - || node.name !== name - || node.comment !== comment + || node.name !== name + || node.comment !== comment ? update(createJSDocSeeTag(tagName, name, comment), node) : node; } @@ -5251,7 +6065,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocNameReference(node: JSDocNameReference, name: EntityName | JSDocMemberName): JSDocNameReference { + function updateJSDocNameReference( + node: JSDocNameReference, + name: EntityName | JSDocMemberName, + ): JSDocNameReference { return node.name !== name ? update(createJSDocNameReference(name), node) : node; @@ -5262,16 +6079,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.JSDocMemberName); node.left = left; node.right = right; - node.transformFlags |= - propagateChildFlags(node.left) | - propagateChildFlags(node.right); + node.transformFlags |= propagateChildFlags(node.left) + | propagateChildFlags(node.right); return node; } // @api function updateJSDocMemberName(node: JSDocMemberName, left: EntityName | JSDocMemberName, right: Identifier) { return node.left !== left - || node.right !== right + || node.right !== right ? update(createJSDocMemberName(left, right), node) : node; } @@ -5300,7 +6116,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode { + function updateJSDocLinkCode( + node: JSDocLinkCode, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLinkCode { return node.name !== name ? update(createJSDocLinkCode(name, text), node) : node; @@ -5315,17 +6135,26 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain { + function updateJSDocLinkPlain( + node: JSDocLinkPlain, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLinkPlain { return node.name !== name ? update(createJSDocLinkPlain(name, text), node) : node; } // @api - function updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocImplementsTag["class"], comment: string | NodeArray | undefined): JSDocImplementsTag { + function updateJSDocImplementsTag( + node: JSDocImplementsTag, + tagName: Identifier = getDefaultTagName(node), + className: JSDocImplementsTag["class"], + comment: string | NodeArray | undefined, + ): JSDocImplementsTag { return node.tagName !== tagName - || node.class !== className - || node.comment !== comment + || node.class !== className + || node.comment !== comment ? update(createJSDocImplementsTag(tagName, className, comment), node) : node; } @@ -5338,7 +6167,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // createJSDocProtectedTag // createJSDocReadonlyTag // createJSDocDeprecatedTag - function createJSDocSimpleTagWorker(kind: T["kind"], tagName: Identifier | undefined, comment?: string | NodeArray) { + function createJSDocSimpleTagWorker( + kind: T["kind"], + tagName: Identifier | undefined, + comment?: string | NodeArray, + ) { const node = createBaseJSDocTag(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment); return node; } @@ -5351,11 +6184,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // updateJSDocProtectedTag // updateJSDocReadonlyTag // updateJSDocDeprecatedTag - function updateJSDocSimpleTagWorker(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), comment: string | NodeArray | undefined) { + function updateJSDocSimpleTagWorker( + kind: T["kind"], + node: T, + tagName: Identifier = getDefaultTagName(node), + comment: string | NodeArray | undefined, + ) { return node.tagName !== tagName - || node.comment !== comment - ? update(createJSDocSimpleTagWorker(kind, tagName, comment), node) : - node; + || node.comment !== comment + ? update(createJSDocSimpleTagWorker(kind, tagName, comment), node) + : node; } // @api @@ -5364,7 +6202,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // createJSDocThisTag // createJSDocEnumTag // createJSDocSatisfiesTag - function createJSDocTypeLikeTagWorker(kind: T["kind"], tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string | NodeArray) { + function createJSDocTypeLikeTagWorker( + kind: T["kind"], + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + comment?: string | NodeArray, + ) { const node = createBaseJSDocTag(kind, tagName ?? createIdentifier(getDefaultTagNameForKind(kind)), comment); node.typeExpression = typeExpression; return node; @@ -5376,10 +6219,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // updateJSDocThisTag // updateJSDocEnumTag // updateJSDocSatisfiesTag - function updateJSDocTypeLikeTagWorker(kind: T["kind"], node: T, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray | undefined) { + function updateJSDocTypeLikeTagWorker( + kind: T["kind"], + node: T, + tagName: Identifier = getDefaultTagName(node), + typeExpression: JSDocTypeExpression | undefined, + comment: string | NodeArray | undefined, + ) { return node.tagName !== tagName - || node.typeExpression !== typeExpression - || node.comment !== comment + || node.typeExpression !== typeExpression + || node.comment !== comment ? update(createJSDocTypeLikeTagWorker(kind, tagName, typeExpression, comment), node) : node; } @@ -5391,16 +6240,28 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag { + function updateJSDocUnknownTag( + node: JSDocUnknownTag, + tagName: Identifier, + comment: string | NodeArray | undefined, + ): JSDocUnknownTag { return node.tagName !== tagName - || node.comment !== comment + || node.comment !== comment ? update(createJSDocUnknownTag(tagName, comment), node) : node; } // @api - function createJSDocEnumTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray) { - const node = createBaseJSDocTagDeclaration(SyntaxKind.JSDocEnumTag, tagName ?? createIdentifier(getDefaultTagNameForKind(SyntaxKind.JSDocEnumTag)), comment); + function createJSDocEnumTag( + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment?: string | NodeArray, + ) { + const node = createBaseJSDocTagDeclaration( + SyntaxKind.JSDocEnumTag, + tagName ?? createIdentifier(getDefaultTagNameForKind(SyntaxKind.JSDocEnumTag)), + comment, + ); node.typeExpression = typeExpression; node.locals = undefined; // initialized by binder (LocalsContainer) @@ -5409,10 +6270,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier = getDefaultTagName(node), typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined) { + function updateJSDocEnumTag( + node: JSDocEnumTag, + tagName: Identifier = getDefaultTagName(node), + typeExpression: JSDocTypeExpression, + comment: string | NodeArray | undefined, + ) { return node.tagName !== tagName - || node.typeExpression !== typeExpression - || node.comment !== comment + || node.typeExpression !== typeExpression + || node.comment !== comment ? update(createJSDocEnumTag(tagName, typeExpression, comment), node) : node; } @@ -5432,7 +6298,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined) { + function createJSDocComment( + comment?: string | NodeArray | undefined, + tags?: readonly JSDocTag[] | undefined, + ) { const node = createBaseNode(SyntaxKind.JSDoc); node.comment = comment; node.tags = asNodeArray(tags); @@ -5440,9 +6309,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJSDocComment(node: JSDoc, comment: string | NodeArray | undefined, tags: readonly JSDocTag[] | undefined) { + function updateJSDocComment( + node: JSDoc, + comment: string | NodeArray | undefined, + tags: readonly JSDocTag[] | undefined, + ) { return node.comment !== comment - || node.tags !== tags + || node.tags !== tags ? update(createJSDocComment(comment, tags), node) : node; } @@ -5452,39 +6325,50 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // // @api - function createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) { + function createJsxElement( + openingElement: JsxOpeningElement, + children: readonly JsxChild[], + closingElement: JsxClosingElement, + ) { const node = createBaseNode(SyntaxKind.JsxElement); node.openingElement = openingElement; node.children = createNodeArray(children); node.closingElement = closingElement; - node.transformFlags |= - propagateChildFlags(node.openingElement) | - propagateChildrenFlags(node.children) | - propagateChildFlags(node.closingElement) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.openingElement) + | propagateChildrenFlags(node.children) + | propagateChildFlags(node.closingElement) + | TransformFlags.ContainsJsx; return node; } // @api - function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) { + function updateJsxElement( + node: JsxElement, + openingElement: JsxOpeningElement, + children: readonly JsxChild[], + closingElement: JsxClosingElement, + ) { return node.openingElement !== openingElement - || node.children !== children - || node.closingElement !== closingElement + || node.children !== children + || node.closingElement !== closingElement ? update(createJsxElement(openingElement, children, closingElement), node) : node; } // @api - function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { + function createJsxSelfClosingElement( + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ) { const node = createBaseNode(SyntaxKind.JsxSelfClosingElement); node.tagName = tagName; node.typeArguments = asNodeArray(typeArguments); node.attributes = attributes; - node.transformFlags |= - propagateChildFlags(node.tagName) | - propagateChildrenFlags(node.typeArguments) | - propagateChildFlags(node.attributes) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.tagName) + | propagateChildrenFlags(node.typeArguments) + | propagateChildFlags(node.attributes) + | TransformFlags.ContainsJsx; if (node.typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -5492,25 +6376,33 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { + function updateJsxSelfClosingElement( + node: JsxSelfClosingElement, + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ) { return node.tagName !== tagName - || node.typeArguments !== typeArguments - || node.attributes !== attributes + || node.typeArguments !== typeArguments + || node.attributes !== attributes ? update(createJsxSelfClosingElement(tagName, typeArguments, attributes), node) : node; } // @api - function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { + function createJsxOpeningElement( + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ) { const node = createBaseNode(SyntaxKind.JsxOpeningElement); node.tagName = tagName; node.typeArguments = asNodeArray(typeArguments); node.attributes = attributes; - node.transformFlags |= - propagateChildFlags(node.tagName) | - propagateChildrenFlags(node.typeArguments) | - propagateChildFlags(node.attributes) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.tagName) + | propagateChildrenFlags(node.typeArguments) + | propagateChildFlags(node.attributes) + | TransformFlags.ContainsJsx; if (typeArguments) { node.transformFlags |= TransformFlags.ContainsTypeScript; } @@ -5518,10 +6410,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) { + function updateJsxOpeningElement( + node: JsxOpeningElement, + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ) { return node.tagName !== tagName - || node.typeArguments !== typeArguments - || node.attributes !== attributes + || node.typeArguments !== typeArguments + || node.attributes !== attributes ? update(createJsxOpeningElement(tagName, typeArguments, attributes), node) : node; } @@ -5530,9 +6427,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createJsxClosingElement(tagName: JsxTagNameExpression) { const node = createBaseNode(SyntaxKind.JsxClosingElement); node.tagName = tagName; - node.transformFlags |= - propagateChildFlags(node.tagName) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.tagName) + | TransformFlags.ContainsJsx; return node; } @@ -5544,24 +6440,32 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createJsxFragment(openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) { + function createJsxFragment( + openingFragment: JsxOpeningFragment, + children: readonly JsxChild[], + closingFragment: JsxClosingFragment, + ) { const node = createBaseNode(SyntaxKind.JsxFragment); node.openingFragment = openingFragment; node.children = createNodeArray(children); node.closingFragment = closingFragment; - node.transformFlags |= - propagateChildFlags(node.openingFragment) | - propagateChildrenFlags(node.children) | - propagateChildFlags(node.closingFragment) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.openingFragment) + | propagateChildrenFlags(node.children) + | propagateChildFlags(node.closingFragment) + | TransformFlags.ContainsJsx; return node; } // @api - function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) { + function updateJsxFragment( + node: JsxFragment, + openingFragment: JsxOpeningFragment, + children: readonly JsxChild[], + closingFragment: JsxClosingFragment, + ) { return node.openingFragment !== openingFragment - || node.children !== children - || node.closingFragment !== closingFragment + || node.children !== children + || node.closingFragment !== closingFragment ? update(createJsxFragment(openingFragment, children, closingFragment), node) : node; } @@ -5578,7 +6482,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateJsxText(node: JsxText, text: string, containsOnlyTriviaWhiteSpaces?: boolean) { return node.text !== text - || node.containsOnlyTriviaWhiteSpaces !== containsOnlyTriviaWhiteSpaces + || node.containsOnlyTriviaWhiteSpaces !== containsOnlyTriviaWhiteSpaces ? update(createJsxText(text, containsOnlyTriviaWhiteSpaces), node) : node; } @@ -5602,17 +6506,20 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseDeclaration(SyntaxKind.JsxAttribute); node.name = name; node.initializer = initializer; - node.transformFlags |= - propagateChildFlags(node.name) | - propagateChildFlags(node.initializer) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.name) + | propagateChildFlags(node.initializer) + | TransformFlags.ContainsJsx; return node; } // @api - function updateJsxAttribute(node: JsxAttribute, name: JsxAttributeName, initializer: JsxAttributeValue | undefined) { + function updateJsxAttribute( + node: JsxAttribute, + name: JsxAttributeName, + initializer: JsxAttributeValue | undefined, + ) { return node.name !== name - || node.initializer !== initializer + || node.initializer !== initializer ? update(createJsxAttribute(name, initializer), node) : node; } @@ -5621,9 +6528,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createJsxAttributes(properties: readonly JsxAttributeLike[]) { const node = createBaseDeclaration(SyntaxKind.JsxAttributes); node.properties = createNodeArray(properties); - node.transformFlags |= - propagateChildrenFlags(node.properties) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildrenFlags(node.properties) + | TransformFlags.ContainsJsx; return node; } @@ -5638,9 +6544,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createJsxSpreadAttribute(expression: Expression) { const node = createBaseNode(SyntaxKind.JsxSpreadAttribute); node.expression = expression; - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsJsx; return node; } @@ -5656,10 +6561,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.JsxExpression); node.dotDotDotToken = dotDotDotToken; node.expression = expression; - node.transformFlags |= - propagateChildFlags(node.dotDotDotToken) | - propagateChildFlags(node.expression) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.dotDotDotToken) + | propagateChildFlags(node.expression) + | TransformFlags.ContainsJsx; return node; } @@ -5675,17 +6579,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.JsxNamespacedName); node.namespace = namespace; node.name = name; - node.transformFlags |= - propagateChildFlags(node.namespace) | - propagateChildFlags(node.name) | - TransformFlags.ContainsJsx; + node.transformFlags |= propagateChildFlags(node.namespace) + | propagateChildFlags(node.name) + | TransformFlags.ContainsJsx; return node; } // @api function updateJsxNamespacedName(node: JsxNamespacedName, namespace: Identifier, name: Identifier) { return node.namespace !== namespace - || node.name !== name + || node.name !== name ? update(createJsxNamespacedName(namespace, name), node) : node; } @@ -5699,9 +6602,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.CaseClause); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); node.statements = createNodeArray(statements); - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildrenFlags(node.statements); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildrenFlags(node.statements); node.jsDoc = undefined; // initialized by parser (JsDocContainer) return node; @@ -5710,7 +6612,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateCaseClause(node: CaseClause, expression: Expression, statements: readonly Statement[]) { return node.expression !== expression - || node.statements !== statements + || node.statements !== statements ? update(createCaseClause(expression, statements), node) : node; } @@ -5757,15 +6659,17 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createCatchClause(variableDeclaration: string | BindingName | VariableDeclaration | undefined, block: Block) { + function createCatchClause( + variableDeclaration: string | BindingName | VariableDeclaration | undefined, + block: Block, + ) { const node = createBaseNode(SyntaxKind.CatchClause); node.variableDeclaration = asVariableDeclaration(variableDeclaration); node.block = block; - node.transformFlags |= - propagateChildFlags(node.variableDeclaration) | - propagateChildFlags(node.block) | - (!variableDeclaration ? TransformFlags.ContainsES2019 : TransformFlags.None); + node.transformFlags |= propagateChildFlags(node.variableDeclaration) + | propagateChildFlags(node.block) + | (!variableDeclaration ? TransformFlags.ContainsES2019 : TransformFlags.None); node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) @@ -5775,7 +6679,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block) { return node.variableDeclaration !== variableDeclaration - || node.block !== block + || node.block !== block ? update(createCatchClause(variableDeclaration, block), node) : node; } @@ -5789,9 +6693,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseDeclaration(SyntaxKind.PropertyAssignment); node.name = asName(name); node.initializer = parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); - node.transformFlags |= - propagateNameFlags(node.name) | - propagateChildFlags(node.initializer); + node.transformFlags |= propagateNameFlags(node.name) + | propagateChildFlags(node.initializer); node.modifiers = undefined; // initialized by parser to report grammar errors node.questionToken = undefined; // initialized by parser to report grammar errors @@ -5803,7 +6706,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression) { return node.name !== name - || node.initializer !== initializer + || node.initializer !== initializer ? finishUpdatePropertyAssignment(createPropertyAssignment(name, initializer), node) : node; } @@ -5823,11 +6726,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression) { const node = createBaseDeclaration(SyntaxKind.ShorthandPropertyAssignment); node.name = asName(name); - node.objectAssignmentInitializer = objectAssignmentInitializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(objectAssignmentInitializer); - node.transformFlags |= - propagateIdentifierNameFlags(node.name) | - propagateChildFlags(node.objectAssignmentInitializer) | - TransformFlags.ContainsES2015; + node.objectAssignmentInitializer = objectAssignmentInitializer + && parenthesizerRules().parenthesizeExpressionForDisallowedComma(objectAssignmentInitializer); + node.transformFlags |= propagateIdentifierNameFlags(node.name) + | propagateChildFlags(node.objectAssignmentInitializer) + | TransformFlags.ContainsES2015; node.equalsToken = undefined; // initialized by parser to report grammar errors node.modifiers = undefined; // initialized by parser to report grammar errors @@ -5838,14 +6741,24 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined) { + function updateShorthandPropertyAssignment( + node: ShorthandPropertyAssignment, + name: Identifier, + objectAssignmentInitializer: Expression | undefined, + ) { return node.name !== name - || node.objectAssignmentInitializer !== objectAssignmentInitializer - ? finishUpdateShorthandPropertyAssignment(createShorthandPropertyAssignment(name, objectAssignmentInitializer), node) + || node.objectAssignmentInitializer !== objectAssignmentInitializer + ? finishUpdateShorthandPropertyAssignment( + createShorthandPropertyAssignment(name, objectAssignmentInitializer), + node, + ) : node; } - function finishUpdateShorthandPropertyAssignment(updated: Mutable, original: ShorthandPropertyAssignment) { + function finishUpdateShorthandPropertyAssignment( + updated: Mutable, + original: ShorthandPropertyAssignment, + ) { if (updated !== original) { // copy children used only for error reporting updated.modifiers = original.modifiers; @@ -5860,10 +6773,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createSpreadAssignment(expression: Expression) { const node = createBaseDeclaration(SyntaxKind.SpreadAssignment); node.expression = parenthesizerRules().parenthesizeExpressionForDisallowedComma(expression); - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsES2018 | - TransformFlags.ContainsObjectRestOrSpread; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsES2018 + | TransformFlags.ContainsObjectRestOrSpread; node.jsDoc = undefined; // initialized by parser (JsDocContainer) return node; @@ -5885,10 +6797,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseDeclaration(SyntaxKind.EnumMember); node.name = asName(name); node.initializer = initializer && parenthesizerRules().parenthesizeExpressionForDisallowedComma(initializer); - node.transformFlags |= - propagateChildFlags(node.name) | - propagateChildFlags(node.initializer) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.name) + | propagateChildFlags(node.initializer) + | TransformFlags.ContainsTypeScript; node.jsDoc = undefined; // initialized by parser (JsDocContainer) return node; @@ -5897,7 +6808,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // @api function updateEnumMember(node: EnumMember, name: PropertyName, initializer: Expression | undefined) { return node.name !== name - || node.initializer !== initializer + || node.initializer !== initializer ? update(createEnumMember(name, initializer), node) : node; } @@ -5910,7 +6821,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createSourceFile( statements: readonly Statement[], endOfFileToken: EndOfFileToken, - flags: NodeFlags + flags: NodeFlags, ) { const node = baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as Mutable; node.statements = createNodeArray(statements); @@ -5927,9 +6838,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.isDeclarationFile = false; node.hasNoDefaultLib = false; - node.transformFlags |= - propagateChildrenFlags(node.statements) | - propagateChildFlags(node.endOfFileToken); + node.transformFlags |= propagateChildrenFlags(node.statements) + | propagateChildFlags(node.endOfFileToken); node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) @@ -5967,12 +6877,20 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node: SourceFile = Object.create(redirectInfo.redirectTarget); Object.defineProperties(node, { id: { - get(this: SourceFile) { return this.redirectInfo!.redirectTarget.id; }, - set(this: SourceFile, value: SourceFile["id"]) { this.redirectInfo!.redirectTarget.id = value; }, + get(this: SourceFile) { + return this.redirectInfo!.redirectTarget.id; + }, + set(this: SourceFile, value: SourceFile["id"]) { + this.redirectInfo!.redirectTarget.id = value; + }, }, symbol: { - get(this: SourceFile) { return this.redirectInfo!.redirectTarget.symbol; }, - set(this: SourceFile, value: SourceFile["symbol"]) { this.redirectInfo!.redirectTarget.symbol = value; }, + get(this: SourceFile) { + return this.redirectInfo!.redirectTarget.symbol; + }, + set(this: SourceFile, value: SourceFile["symbol"]) { + this.redirectInfo!.redirectTarget.symbol = value; + }, }, }); node.redirectInfo = redirectInfo; @@ -6023,7 +6941,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode referencedFiles: readonly FileReference[], typeReferences: readonly FileReference[], hasNoDefaultLib: boolean, - libReferences: readonly FileReference[] + libReferences: readonly FileReference[], ) { const node = cloneSourceFile(source); node.statements = createNodeArray(statements); @@ -6032,9 +6950,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeReferenceDirectives = typeReferences; node.hasNoDefaultLib = hasNoDefaultLib; node.libReferenceDirectives = libReferences; - node.transformFlags = - propagateChildrenFlags(node.statements) | - propagateChildFlags(node.endOfFileToken); + node.transformFlags = propagateChildrenFlags(node.statements) + | propagateChildFlags(node.endOfFileToken); return node; } @@ -6046,20 +6963,34 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode referencedFiles = node.referencedFiles, typeReferenceDirectives = node.typeReferenceDirectives, hasNoDefaultLib = node.hasNoDefaultLib, - libReferenceDirectives = node.libReferenceDirectives + libReferenceDirectives = node.libReferenceDirectives, ) { return node.statements !== statements - || node.isDeclarationFile !== isDeclarationFile - || node.referencedFiles !== referencedFiles - || node.typeReferenceDirectives !== typeReferenceDirectives - || node.hasNoDefaultLib !== hasNoDefaultLib - || node.libReferenceDirectives !== libReferenceDirectives - ? update(cloneSourceFileWithChanges(node, statements, isDeclarationFile, referencedFiles, typeReferenceDirectives, hasNoDefaultLib, libReferenceDirectives), node) - : node; - } - - // @api - function createBundle(sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) { + || node.isDeclarationFile !== isDeclarationFile + || node.referencedFiles !== referencedFiles + || node.typeReferenceDirectives !== typeReferenceDirectives + || node.hasNoDefaultLib !== hasNoDefaultLib + || node.libReferenceDirectives !== libReferenceDirectives + ? update( + cloneSourceFileWithChanges( + node, + statements, + isDeclarationFile, + referencedFiles, + typeReferenceDirectives, + hasNoDefaultLib, + libReferenceDirectives, + ), + node, + ) + : node; + } + + // @api + function createBundle( + sourceFiles: readonly SourceFile[], + prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray, + ) { const node = createBaseNode(SyntaxKind.Bundle); node.prepends = prepends; node.sourceFiles = sourceFiles; @@ -6071,15 +7002,23 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateBundle(node: Bundle, sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) { + function updateBundle( + node: Bundle, + sourceFiles: readonly SourceFile[], + prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray, + ) { return node.sourceFiles !== sourceFiles - || node.prepends !== prepends + || node.prepends !== prepends ? update(createBundle(sourceFiles, prepends), node) : node; } // @api - function createUnparsedSource(prologues: readonly UnparsedPrologue[], syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, texts: readonly UnparsedSourceText[]) { + function createUnparsedSource( + prologues: readonly UnparsedPrologue[], + syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, + texts: readonly UnparsedSourceText[], + ) { const node = createBaseNode(SyntaxKind.UnparsedSource); node.prologues = prologues; node.syntheticReferences = syntheticReferences; @@ -6116,7 +7055,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference): UnparsedSyntheticReference { + function createUnparsedSyntheticReference( + section: BundleFileHasNoDefaultLib | BundleFileReference, + ): UnparsedSyntheticReference { const node = createBaseNode(SyntaxKind.UnparsedSyntheticReference); node.data = section.data; node.section = section; @@ -6136,7 +7077,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // // @api - function createSyntheticExpression(type: Type, isSpread = false, tupleNameSource?: ParameterDeclaration | NamedTupleMember) { + function createSyntheticExpression( + type: Type, + isSpread = false, + tupleNameSource?: ParameterDeclaration | NamedTupleMember, + ) { const node = createBaseNode(SyntaxKind.SyntheticExpression); node.type = type; node.isSpread = isSpread; @@ -6181,9 +7126,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.PartiallyEmittedExpression); node.expression = expression; node.original = original; - node.transformFlags |= - propagateChildFlags(node.expression) | - TransformFlags.ContainsTypeScript; + node.transformFlags |= propagateChildFlags(node.expression) + | TransformFlags.ContainsTypeScript; setTextRange(node, original); return node; } @@ -6227,16 +7171,19 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.SyntheticReferenceExpression); node.expression = expression; node.thisArg = thisArg; - node.transformFlags |= - propagateChildFlags(node.expression) | - propagateChildFlags(node.thisArg); + node.transformFlags |= propagateChildFlags(node.expression) + | propagateChildFlags(node.thisArg); return node; } // @api - function updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression) { + function updateSyntheticReferenceExpression( + node: SyntheticReferenceExpression, + expression: Expression, + thisArg: Expression, + ) { return node.expression !== expression - || node.thisArg !== thisArg + || node.thisArg !== thisArg ? update(createSyntheticReferenceExpression(expression, thisArg), node) : node; } @@ -6307,11 +7254,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return clonePrivateIdentifier(node) as T & PrivateIdentifier; } - const clone = - !isNodeKind(node.kind) ? baseFactory.createBaseTokenNode(node.kind) as T : - baseFactory.createBaseNode(node.kind) as T; + const clone = !isNodeKind(node.kind) ? baseFactory.createBaseTokenNode(node.kind) as T + : baseFactory.createBaseNode(node.kind) as T; - (clone as Mutable).flags |= (node.flags & ~NodeFlags.Synthesized); + (clone as Mutable).flags |= node.flags & ~NodeFlags.Synthesized; (clone as Mutable).transformFlags = node.transformFlags; setOriginalNode(clone, node); @@ -6327,9 +7273,19 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // compound nodes - function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): ImmediatelyInvokedFunctionExpression; - function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): ImmediatelyInvokedFunctionExpression; - function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) { + function createImmediatelyInvokedFunctionExpression( + statements: readonly Statement[], + ): ImmediatelyInvokedFunctionExpression; + function createImmediatelyInvokedFunctionExpression( + statements: readonly Statement[], + param: ParameterDeclaration, + paramValue: Expression, + ): ImmediatelyInvokedFunctionExpression; + function createImmediatelyInvokedFunctionExpression( + statements: readonly Statement[], + param?: ParameterDeclaration, + paramValue?: Expression, + ) { return createCallExpression( createFunctionExpression( /*modifiers*/ undefined, @@ -6338,16 +7294,24 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode /*typeParameters*/ undefined, /*parameters*/ param ? [param] : [], /*type*/ undefined, - createBlock(statements, /*multiLine*/ true) + createBlock(statements, /*multiLine*/ true), ), /*typeArguments*/ undefined, - /*argumentsArray*/ paramValue ? [paramValue] : [] + /*argumentsArray*/ paramValue ? [paramValue] : [], ); } function createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): ImmediatelyInvokedArrowFunction; - function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): ImmediatelyInvokedArrowFunction; - function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) { + function createImmediatelyInvokedArrowFunction( + statements: readonly Statement[], + param: ParameterDeclaration, + paramValue: Expression, + ): ImmediatelyInvokedArrowFunction; + function createImmediatelyInvokedArrowFunction( + statements: readonly Statement[], + param?: ParameterDeclaration, + paramValue?: Expression, + ) { return createCallExpression( createArrowFunction( /*modifiers*/ undefined, @@ -6355,10 +7319,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode /*parameters*/ param ? [param] : [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, - createBlock(statements, /*multiLine*/ true) + createBlock(statements, /*multiLine*/ true), ), /*typeArguments*/ undefined, - /*argumentsArray*/ paramValue ? [paramValue] : [] + /*argumentsArray*/ paramValue ? [paramValue] : [], ); } @@ -6370,7 +7334,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return createExportAssignment( /*modifiers*/ undefined, /*isExportEquals*/ false, - expression); + expression, + ); } function createExternalModuleExport(exportName: Identifier) { @@ -6378,8 +7343,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode /*modifiers*/ undefined, /*isTypeOnly*/ false, createNamedExports([ - createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, exportName) - ]) + createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, exportName), + ]), ); } @@ -6388,31 +7353,35 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // function createTypeCheck(value: Expression, tag: TypeOfTag) { - return tag === "null" ? factory.createStrictEquality(value, createNull()) : - tag === "undefined" ? factory.createStrictEquality(value, createVoidZero()) : - factory.createStrictEquality(createTypeOfExpression(value), createStringLiteral(tag)); + return tag === "null" ? factory.createStrictEquality(value, createNull()) + : tag === "undefined" ? factory.createStrictEquality(value, createVoidZero()) + : factory.createStrictEquality(createTypeOfExpression(value), createStringLiteral(tag)); } function createIsNotTypeCheck(value: Expression, tag: TypeOfTag) { - return tag === "null" ? factory.createStrictInequality(value, createNull()) : - tag === "undefined" ? factory.createStrictInequality(value, createVoidZero()) : - factory.createStrictInequality(createTypeOfExpression(value), createStringLiteral(tag)); + return tag === "null" ? factory.createStrictInequality(value, createNull()) + : tag === "undefined" ? factory.createStrictInequality(value, createVoidZero()) + : factory.createStrictInequality(createTypeOfExpression(value), createStringLiteral(tag)); } - function createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]) { + function createMethodCall( + object: Expression, + methodName: string | Identifier, + argumentsList: readonly Expression[], + ) { // Preserve the optionality of `object`. if (isCallChain(object)) { return createCallChain( createPropertyAccessChain(object, /*questionDotToken*/ undefined, methodName), /*questionDotToken*/ undefined, /*typeArguments*/ undefined, - argumentsList + argumentsList, ); } return createCallExpression( createPropertyAccessExpression(object, methodName), /*typeArguments*/ undefined, - argumentsList + argumentsList, ); } @@ -6428,7 +7397,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return createMethodCall(target, "apply", [thisArg, argumentsExpression]); } - function createGlobalMethodCall(globalObjectName: string, methodName: string, argumentsList: readonly Expression[]) { + function createGlobalMethodCall( + globalObjectName: string, + methodName: string, + argumentsList: readonly Expression[], + ) { return createMethodCall(createIdentifier(globalObjectName), methodName, argumentsList); } @@ -6440,7 +7413,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return createMethodCall(array, "concat", argumentsList); } - function createObjectDefinePropertyCall(target: Expression, propertyName: string | Expression, attributes: Expression) { + function createObjectDefinePropertyCall( + target: Expression, + propertyName: string | Expression, + attributes: Expression, + ) { return createGlobalMethodCall("Object", "defineProperty", [target, asExpression(propertyName), attributes]); } @@ -6449,14 +7426,31 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } function createReflectGetCall(target: Expression, propertyKey: Expression, receiver?: Expression): CallExpression { - return createGlobalMethodCall("Reflect", "get", receiver ? [target, propertyKey, receiver] : [target, propertyKey]); + return createGlobalMethodCall( + "Reflect", + "get", + receiver ? [target, propertyKey, receiver] : [target, propertyKey], + ); } - function createReflectSetCall(target: Expression, propertyKey: Expression, value: Expression, receiver?: Expression): CallExpression { - return createGlobalMethodCall("Reflect", "set", receiver ? [target, propertyKey, value, receiver] : [target, propertyKey, value]); + function createReflectSetCall( + target: Expression, + propertyKey: Expression, + value: Expression, + receiver?: Expression, + ): CallExpression { + return createGlobalMethodCall( + "Reflect", + "set", + receiver ? [target, propertyKey, value, receiver] : [target, propertyKey, value], + ); } - function tryAddPropertyAssignment(properties: PropertyAssignment[], propertyName: string, expression: Expression | undefined) { + function tryAddPropertyAssignment( + properties: PropertyAssignment[], + propertyName: string, + expression: Expression | undefined, + ) { if (expression) { properties.push(createPropertyAssignment(propertyName, expression)); return true; @@ -6475,18 +7469,27 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode let isAccessor = tryAddPropertyAssignment(properties, "get", attributes.get); isAccessor = tryAddPropertyAssignment(properties, "set", attributes.set) || isAccessor; - Debug.assert(!(isData && isAccessor), "A PropertyDescriptor may not be both an accessor descriptor and a data descriptor."); + Debug.assert( + !(isData && isAccessor), + "A PropertyDescriptor may not be both an accessor descriptor and a data descriptor.", + ); return createObjectLiteralExpression(properties, !singleLine); } function updateOuterExpression(outerExpression: OuterExpression, expression: Expression) { switch (outerExpression.kind) { - case SyntaxKind.ParenthesizedExpression: return updateParenthesizedExpression(outerExpression, expression); - case SyntaxKind.TypeAssertionExpression: return updateTypeAssertion(outerExpression, outerExpression.type, expression); - case SyntaxKind.AsExpression: return updateAsExpression(outerExpression, expression, outerExpression.type); - case SyntaxKind.SatisfiesExpression: return updateSatisfiesExpression(outerExpression, expression, outerExpression.type); - case SyntaxKind.NonNullExpression: return updateNonNullExpression(outerExpression, expression); - case SyntaxKind.PartiallyEmittedExpression: return updatePartiallyEmittedExpression(outerExpression, expression); + case SyntaxKind.ParenthesizedExpression: + return updateParenthesizedExpression(outerExpression, expression); + case SyntaxKind.TypeAssertionExpression: + return updateTypeAssertion(outerExpression, outerExpression.type, expression); + case SyntaxKind.AsExpression: + return updateAsExpression(outerExpression, expression, outerExpression.type); + case SyntaxKind.SatisfiesExpression: + return updateSatisfiesExpression(outerExpression, expression, outerExpression.type); + case SyntaxKind.NonNullExpression: + return updateNonNullExpression(outerExpression, expression); + case SyntaxKind.PartiallyEmittedExpression: + return updatePartiallyEmittedExpression(outerExpression, expression); } } @@ -6513,17 +7516,25 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode && !some(getSyntheticTrailingComments(node)); } - function restoreOuterExpressions(outerExpression: Expression | undefined, innerExpression: Expression, kinds = OuterExpressionKinds.All): Expression { + function restoreOuterExpressions( + outerExpression: Expression | undefined, + innerExpression: Expression, + kinds = OuterExpressionKinds.All, + ): Expression { if (outerExpression && isOuterExpression(outerExpression, kinds) && !isIgnorableParen(outerExpression)) { return updateOuterExpression( outerExpression, - restoreOuterExpressions(outerExpression.expression, innerExpression) + restoreOuterExpressions(outerExpression.expression, innerExpression), ); } return innerExpression; } - function restoreEnclosingLabel(node: Statement, outermostLabeledStatement: LabeledStatement | undefined, afterRestoreLabelCallback?: (node: LabeledStatement) => void): Statement { + function restoreEnclosingLabel( + node: Statement, + outermostLabeledStatement: LabeledStatement | undefined, + afterRestoreLabelCallback?: (node: LabeledStatement) => void, + ): Statement { if (!outermostLabeledStatement) { return node; } @@ -6532,7 +7543,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode outermostLabeledStatement.label, isLabeledStatement(outermostLabeledStatement.statement) ? restoreEnclosingLabel(node, outermostLabeledStatement.statement) - : node + : node, ); if (afterRestoreLabelCallback) { afterRestoreLabelCallback(outermostLabeledStatement); @@ -6563,7 +7574,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } } - function createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget, cacheIdentifiers = false): CallBinding { + function createCallBinding( + expression: Expression, + recordTempVariable: (temp: Identifier) => void, + languageVersion?: ScriptTarget, + cacheIdentifiers = false, + ): CallBinding { const callee = skipOuterExpressions(expression, OuterExpressionKinds.All); let thisArg: Expression; let target: LeftHandSideExpression; @@ -6589,11 +7605,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode setTextRange( factory.createAssignment( thisArg, - callee.expression + callee.expression, ), - callee.expression + callee.expression, ), - callee.name + callee.name, ); setTextRange(target, callee); } @@ -6610,11 +7626,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode setTextRange( factory.createAssignment( thisArg, - callee.expression + callee.expression, ), - callee.expression + callee.expression, ), - callee.argumentExpression + callee.argumentExpression, ); setTextRange(target, callee); } @@ -6646,15 +7662,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode paramName, /*questionToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined + /*initializer*/ undefined, )], createBlock([ - createExpressionStatement(expression) - ]) - ) - ]) + createExpressionStatement(expression), + ]), + ), + ]), ), - "value" + "value", ); } @@ -6666,8 +7682,15 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode : reduceLeft(expressions, factory.createComma)!; } - function getName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0, ignoreAssignedName?: boolean) { - const nodeName = ignoreAssignedName ? node && getNonAssignedNameOfDeclaration(node) : getNameOfDeclaration(node); + function getName( + node: Declaration | undefined, + allowComments?: boolean, + allowSourceMaps?: boolean, + emitFlags: EmitFlags = 0, + ignoreAssignedName?: boolean, + ) { + const nodeName = ignoreAssignedName ? node && getNonAssignedNameOfDeclaration(node) + : getNameOfDeclaration(node); if (nodeName && isIdentifier(nodeName) && !isGeneratedIdentifier(nodeName)) { // TODO(rbuckton): Does this need to be parented? const name = setParent(setTextRange(cloneNode(nodeName), nodeName), nodeName.parent); @@ -6706,7 +7729,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. * @param ignoreAssignedName Indicates that the assigned name of a declaration shouldn't be considered. */ - function getLocalName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean, ignoreAssignedName?: boolean) { + function getLocalName( + node: Declaration, + allowComments?: boolean, + allowSourceMaps?: boolean, + ignoreAssignedName?: boolean, + ) { return getName(node, allowComments, allowSourceMaps, EmitFlags.LocalName, ignoreAssignedName); } @@ -6743,7 +7771,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - function getNamespaceMemberName(ns: Identifier, name: Identifier, allowComments?: boolean, allowSourceMaps?: boolean): PropertyAccessExpression { + function getNamespaceMemberName( + ns: Identifier, + name: Identifier, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): PropertyAccessExpression { const qualifiedName = createPropertyAccessExpression(ns, nodeIsSynthesized(name) ? name : cloneNode(name)); setTextRange(qualifiedName, name); let emitFlags: EmitFlags = 0; @@ -6764,7 +7797,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode * @param allowComments A value indicating whether comments may be emitted for the name. * @param allowSourceMaps A value indicating whether source maps may be emitted for the name. */ - function getExternalModuleOrNamespaceExportName(ns: Identifier | undefined, node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier | PropertyAccessExpression { + function getExternalModuleOrNamespaceExportName( + ns: Identifier | undefined, + node: Declaration, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): Identifier | PropertyAccessExpression { if (ns && hasSyntacticModifier(node, ModifierFlags.Export)) { return getNamespaceMemberName(ns, getName(node), allowComments, allowSourceMaps); } @@ -6778,7 +7816,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode * @param ensureUseStrict boolean determining whether the function need to add prologue-directives * @param visitor Optional callback used to visit any custom prologue directives. */ - function copyPrologue(source: readonly Statement[], target: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number { + function copyPrologue( + source: readonly Statement[], + target: Statement[], + ensureUseStrict?: boolean, + visitor?: (node: Node) => VisitResult, + ): number { const offset = copyStandardPrologue(source, target, 0, ensureUseStrict); return copyCustomPrologue(source, target, offset, visitor); } @@ -6799,8 +7842,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode * @param ensureUseStrict boolean determining whether the function need to add prologue-directives * @returns Count of how many directive statements were copied. */ - function copyStandardPrologue(source: readonly Statement[], target: Statement[], statementOffset = 0, ensureUseStrict?: boolean): number { - Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array"); + function copyStandardPrologue( + source: readonly Statement[], + target: Statement[], + statementOffset = 0, + ensureUseStrict?: boolean, + ): number { + Debug.assert( + target.length === 0, + "Prologue directives should be at the first statement in the target statements array", + ); let foundUseStrict = false; const numStatements = source.length; while (statementOffset < numStatements) { @@ -6829,9 +7880,27 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode * @param statementOffset The offset at which to begin the copy. * @param visitor Optional callback used to visit any custom prologue directives. */ - function copyCustomPrologue(source: readonly Statement[], target: Statement[], statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Statement) => boolean): number; - function copyCustomPrologue(source: readonly Statement[], target: Statement[], statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Statement) => boolean): number | undefined; - function copyCustomPrologue(source: readonly Statement[], target: Statement[], statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter: (node: Statement) => boolean = returnTrue): number | undefined { + function copyCustomPrologue( + source: readonly Statement[], + target: Statement[], + statementOffset: number, + visitor?: (node: Node) => VisitResult, + filter?: (node: Statement) => boolean, + ): number; + function copyCustomPrologue( + source: readonly Statement[], + target: Statement[], + statementOffset: number | undefined, + visitor?: (node: Node) => VisitResult, + filter?: (node: Statement) => boolean, + ): number | undefined; + function copyCustomPrologue( + source: readonly Statement[], + target: Statement[], + statementOffset: number | undefined, + visitor?: (node: Node) => VisitResult, + filter: (node: Statement) => boolean = returnTrue, + ): number | undefined { const numStatements = source.length; while (statementOffset !== undefined && statementOffset < numStatements) { const statement = source[statementOffset]; @@ -6879,9 +7948,18 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return i; } - function mergeLexicalEnvironment(statements: NodeArray, declarations: readonly Statement[] | undefined): NodeArray; - function mergeLexicalEnvironment(statements: Statement[], declarations: readonly Statement[] | undefined): Statement[]; - function mergeLexicalEnvironment(statements: Statement[] | NodeArray, declarations: readonly Statement[] | undefined) { + function mergeLexicalEnvironment( + statements: NodeArray, + declarations: readonly Statement[] | undefined, + ): NodeArray; + function mergeLexicalEnvironment( + statements: Statement[], + declarations: readonly Statement[] | undefined, + ): Statement[]; + function mergeLexicalEnvironment( + statements: Statement[] | NodeArray, + declarations: readonly Statement[] | undefined, + ) { if (!some(declarations)) { return statements; } @@ -6923,9 +8001,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // find standard prologues on right in the following order: standard directives, hoisted functions, hoisted variables, other custom const rightStandardPrologueEnd = findSpanEnd(declarations, isPrologueDirective, 0); const rightHoistedFunctionsEnd = findSpanEnd(declarations, isHoistedFunction, rightStandardPrologueEnd); - const rightHoistedVariablesEnd = findSpanEnd(declarations, isHoistedVariableStatement, rightHoistedFunctionsEnd); + const rightHoistedVariablesEnd = findSpanEnd( + declarations, + isHoistedVariableStatement, + rightHoistedFunctionsEnd, + ); const rightCustomPrologueEnd = findSpanEnd(declarations, isCustomPrologue, rightHoistedVariablesEnd); - Debug.assert(rightCustomPrologueEnd === declarations.length, "Expected declarations to be valid standard or custom prologues"); + Debug.assert( + rightCustomPrologueEnd === declarations.length, + "Expected declarations to be valid standard or custom prologues", + ); // splice prologues from the right into the left. We do this in reverse order // so that we don't need to recompute the index on the left when we insert items. @@ -6933,17 +8018,29 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // splice other custom prologues from right into left if (rightCustomPrologueEnd > rightHoistedVariablesEnd) { - left.splice(leftHoistedVariablesEnd, 0, ...declarations.slice(rightHoistedVariablesEnd, rightCustomPrologueEnd)); + left.splice( + leftHoistedVariablesEnd, + 0, + ...declarations.slice(rightHoistedVariablesEnd, rightCustomPrologueEnd), + ); } // splice hoisted variables from right into left if (rightHoistedVariablesEnd > rightHoistedFunctionsEnd) { - left.splice(leftHoistedFunctionsEnd, 0, ...declarations.slice(rightHoistedFunctionsEnd, rightHoistedVariablesEnd)); + left.splice( + leftHoistedFunctionsEnd, + 0, + ...declarations.slice(rightHoistedFunctionsEnd, rightHoistedVariablesEnd), + ); } // splice hoisted functions from right into left if (rightHoistedFunctionsEnd > rightStandardPrologueEnd) { - left.splice(leftStandardPrologueEnd, 0, ...declarations.slice(rightStandardPrologueEnd, rightHoistedFunctionsEnd)); + left.splice( + leftStandardPrologueEnd, + 0, + ...declarations.slice(rightStandardPrologueEnd, rightHoistedFunctionsEnd), + ); } // splice standard prologues from right into left (that are not already in left) @@ -6982,44 +8079,197 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode else { modifierArray = modifiers; } - return isTypeParameterDeclaration(node) ? updateTypeParameterDeclaration(node, modifierArray, node.name, node.constraint, node.default) : - isParameter(node) ? updateParameterDeclaration(node, modifierArray, node.dotDotDotToken, node.name, node.questionToken, node.type, node.initializer) : - isConstructorTypeNode(node) ? updateConstructorTypeNode1(node, modifierArray, node.typeParameters, node.parameters, node.type) : - isPropertySignature(node) ? updatePropertySignature(node, modifierArray, node.name, node.questionToken, node.type) : - isPropertyDeclaration(node) ? updatePropertyDeclaration(node, modifierArray, node.name, node.questionToken ?? node.exclamationToken, node.type, node.initializer) : - isMethodSignature(node) ? updateMethodSignature(node, modifierArray, node.name, node.questionToken, node.typeParameters, node.parameters, node.type) : - isMethodDeclaration(node) ? updateMethodDeclaration(node, modifierArray, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, node.body) : - isConstructorDeclaration(node) ? updateConstructorDeclaration(node, modifierArray, node.parameters, node.body) : - isGetAccessorDeclaration(node) ? updateGetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.type, node.body) : - isSetAccessorDeclaration(node) ? updateSetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.body) : - isIndexSignatureDeclaration(node) ? updateIndexSignature(node, modifierArray, node.parameters, node.type) : - isFunctionExpression(node) ? updateFunctionExpression(node, modifierArray, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) : - isArrowFunction(node) ? updateArrowFunction(node, modifierArray, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, node.body) : - isClassExpression(node) ? updateClassExpression(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - isVariableStatement(node) ? updateVariableStatement(node, modifierArray, node.declarationList) : - isFunctionDeclaration(node) ? updateFunctionDeclaration(node, modifierArray, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body) : - isClassDeclaration(node) ? updateClassDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - isInterfaceDeclaration(node) ? updateInterfaceDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, modifierArray, node.name, node.typeParameters, node.type) : - isEnumDeclaration(node) ? updateEnumDeclaration(node, modifierArray, node.name, node.members) : - isModuleDeclaration(node) ? updateModuleDeclaration(node, modifierArray, node.name, node.body) : - isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, modifierArray, node.isTypeOnly, node.name, node.moduleReference) : - isImportDeclaration(node) ? updateImportDeclaration(node, modifierArray, node.importClause, node.moduleSpecifier, node.assertClause) : - isExportAssignment(node) ? updateExportAssignment(node, modifierArray, node.expression) : - isExportDeclaration(node) ? updateExportDeclaration(node, modifierArray, node.isTypeOnly, node.exportClause, node.moduleSpecifier, node.assertClause) : - Debug.assertNever(node); + return isTypeParameterDeclaration(node) + ? updateTypeParameterDeclaration(node, modifierArray, node.name, node.constraint, node.default) + : isParameter(node) + ? updateParameterDeclaration( + node, + modifierArray, + node.dotDotDotToken, + node.name, + node.questionToken, + node.type, + node.initializer, + ) + : isConstructorTypeNode(node) + ? updateConstructorTypeNode1(node, modifierArray, node.typeParameters, node.parameters, node.type) + : isPropertySignature(node) + ? updatePropertySignature(node, modifierArray, node.name, node.questionToken, node.type) + : isPropertyDeclaration(node) + ? updatePropertyDeclaration( + node, + modifierArray, + node.name, + node.questionToken ?? node.exclamationToken, + node.type, + node.initializer, + ) + : isMethodSignature(node) + ? updateMethodSignature( + node, + modifierArray, + node.name, + node.questionToken, + node.typeParameters, + node.parameters, + node.type, + ) + : isMethodDeclaration(node) + ? updateMethodDeclaration( + node, + modifierArray, + node.asteriskToken, + node.name, + node.questionToken, + node.typeParameters, + node.parameters, + node.type, + node.body, + ) + : isConstructorDeclaration(node) + ? updateConstructorDeclaration(node, modifierArray, node.parameters, node.body) + : isGetAccessorDeclaration(node) + ? updateGetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.type, node.body) + : isSetAccessorDeclaration(node) + ? updateSetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.body) + : isIndexSignatureDeclaration(node) ? updateIndexSignature(node, modifierArray, node.parameters, node.type) + : isFunctionExpression(node) + ? updateFunctionExpression( + node, + modifierArray, + node.asteriskToken, + node.name, + node.typeParameters, + node.parameters, + node.type, + node.body, + ) + : isArrowFunction(node) + ? updateArrowFunction( + node, + modifierArray, + node.typeParameters, + node.parameters, + node.type, + node.equalsGreaterThanToken, + node.body, + ) + : isClassExpression(node) + ? updateClassExpression( + node, + modifierArray, + node.name, + node.typeParameters, + node.heritageClauses, + node.members, + ) + : isVariableStatement(node) ? updateVariableStatement(node, modifierArray, node.declarationList) + : isFunctionDeclaration(node) + ? updateFunctionDeclaration( + node, + modifierArray, + node.asteriskToken, + node.name, + node.typeParameters, + node.parameters, + node.type, + node.body, + ) + : isClassDeclaration(node) + ? updateClassDeclaration( + node, + modifierArray, + node.name, + node.typeParameters, + node.heritageClauses, + node.members, + ) + : isInterfaceDeclaration(node) + ? updateInterfaceDeclaration( + node, + modifierArray, + node.name, + node.typeParameters, + node.heritageClauses, + node.members, + ) + : isTypeAliasDeclaration(node) + ? updateTypeAliasDeclaration(node, modifierArray, node.name, node.typeParameters, node.type) + : isEnumDeclaration(node) ? updateEnumDeclaration(node, modifierArray, node.name, node.members) + : isModuleDeclaration(node) ? updateModuleDeclaration(node, modifierArray, node.name, node.body) + : isImportEqualsDeclaration(node) + ? updateImportEqualsDeclaration(node, modifierArray, node.isTypeOnly, node.name, node.moduleReference) + : isImportDeclaration(node) + ? updateImportDeclaration(node, modifierArray, node.importClause, node.moduleSpecifier, node.assertClause) + : isExportAssignment(node) ? updateExportAssignment(node, modifierArray, node.expression) + : isExportDeclaration(node) + ? updateExportDeclaration( + node, + modifierArray, + node.isTypeOnly, + node.exportClause, + node.moduleSpecifier, + node.assertClause, + ) + : Debug.assertNever(node); } function updateModifierLike(node: T, modifiers: readonly ModifierLike[]): T; function updateModifierLike(node: HasModifiers & HasDecorators, modifierArray: readonly ModifierLike[]) { - return isParameter(node) ? updateParameterDeclaration(node, modifierArray, node.dotDotDotToken, node.name, node.questionToken, node.type, node.initializer) : - isPropertyDeclaration(node) ? updatePropertyDeclaration(node, modifierArray, node.name, node.questionToken ?? node.exclamationToken, node.type, node.initializer) : - isMethodDeclaration(node) ? updateMethodDeclaration(node, modifierArray, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, node.body) : - isGetAccessorDeclaration(node) ? updateGetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.type, node.body) : - isSetAccessorDeclaration(node) ? updateSetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.body) : - isClassExpression(node) ? updateClassExpression(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - isClassDeclaration(node) ? updateClassDeclaration(node, modifierArray, node.name, node.typeParameters, node.heritageClauses, node.members) : - Debug.assertNever(node); + return isParameter(node) + ? updateParameterDeclaration( + node, + modifierArray, + node.dotDotDotToken, + node.name, + node.questionToken, + node.type, + node.initializer, + ) + : isPropertyDeclaration(node) + ? updatePropertyDeclaration( + node, + modifierArray, + node.name, + node.questionToken ?? node.exclamationToken, + node.type, + node.initializer, + ) + : isMethodDeclaration(node) + ? updateMethodDeclaration( + node, + modifierArray, + node.asteriskToken, + node.name, + node.questionToken, + node.typeParameters, + node.parameters, + node.type, + node.body, + ) + : isGetAccessorDeclaration(node) + ? updateGetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.type, node.body) + : isSetAccessorDeclaration(node) + ? updateSetAccessorDeclaration(node, modifierArray, node.name, node.parameters, node.body) + : isClassExpression(node) + ? updateClassExpression( + node, + modifierArray, + node.name, + node.typeParameters, + node.heritageClauses, + node.members, + ) + : isClassDeclaration(node) + ? updateClassDeclaration( + node, + modifierArray, + node.name, + node.typeParameters, + node.heritageClauses, + node.members, + ) + : Debug.assertNever(node); } function asNodeArray(array: readonly T[]): NodeArray; @@ -7028,16 +8278,28 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return array ? createNodeArray(array) : undefined; } - function asName(name: string | T): T | Identifier { - return typeof name === "string" ? createIdentifier(name) : - name; + function asName< + T extends + | DeclarationName + | Identifier + | BindingName + | PropertyName + | NoSubstitutionTemplateLiteral + | EntityName + | ThisTypeNode + | undefined, + >(name: string | T): T | Identifier { + return typeof name === "string" ? createIdentifier(name) + : name; } - function asExpression(value: string | number | boolean | T): T | StringLiteral | NumericLiteral | BooleanLiteral { - return typeof value === "string" ? createStringLiteral(value) : - typeof value === "number" ? createNumericLiteral(value) : - typeof value === "boolean" ? value ? createTrue() : createFalse() : - value; + function asExpression( + value: string | number | boolean | T, + ): T | StringLiteral | NumericLiteral | BooleanLiteral { + return typeof value === "string" ? createStringLiteral(value) + : typeof value === "number" ? createNumericLiteral(value) + : typeof value === "boolean" ? value ? createTrue() : createFalse() + : value; } function asInitializer(node: Expression | undefined) { @@ -7051,16 +8313,20 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function asEmbeddedStatement(statement: T): T | EmptyStatement; function asEmbeddedStatement(statement: T | undefined): T | EmptyStatement | undefined; function asEmbeddedStatement(statement: T | undefined): T | EmptyStatement | undefined { - return statement && isNotEmittedStatement(statement) ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement; + return statement && isNotEmittedStatement(statement) + ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement; } function asVariableDeclaration(variableDeclaration: string | BindingName | VariableDeclaration | undefined) { - if (typeof variableDeclaration === "string" || variableDeclaration && !isVariableDeclaration(variableDeclaration)) { + if ( + typeof variableDeclaration === "string" + || variableDeclaration && !isVariableDeclaration(variableDeclaration) + ) { return createVariableDeclaration( variableDeclaration, /*exclamationToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined + /*initializer*/ undefined, ); } return variableDeclaration; @@ -7084,32 +8350,51 @@ function updateWithOriginal(updated: Mutable, original: T): T function getDefaultTagNameForKind(kind: JSDocTag["kind"]): string { switch (kind) { - case SyntaxKind.JSDocTypeTag: return "type"; - case SyntaxKind.JSDocReturnTag: return "returns"; - case SyntaxKind.JSDocThisTag: return "this"; - case SyntaxKind.JSDocEnumTag: return "enum"; - case SyntaxKind.JSDocAuthorTag: return "author"; - case SyntaxKind.JSDocClassTag: return "class"; - case SyntaxKind.JSDocPublicTag: return "public"; - case SyntaxKind.JSDocPrivateTag: return "private"; - case SyntaxKind.JSDocProtectedTag: return "protected"; - case SyntaxKind.JSDocReadonlyTag: return "readonly"; - case SyntaxKind.JSDocOverrideTag: return "override"; - case SyntaxKind.JSDocTemplateTag: return "template"; - case SyntaxKind.JSDocTypedefTag: return "typedef"; - case SyntaxKind.JSDocParameterTag: return "param"; - case SyntaxKind.JSDocPropertyTag: return "prop"; - case SyntaxKind.JSDocCallbackTag: return "callback"; - case SyntaxKind.JSDocOverloadTag: return "overload"; - case SyntaxKind.JSDocAugmentsTag: return "augments"; - case SyntaxKind.JSDocImplementsTag: return "implements"; + case SyntaxKind.JSDocTypeTag: + return "type"; + case SyntaxKind.JSDocReturnTag: + return "returns"; + case SyntaxKind.JSDocThisTag: + return "this"; + case SyntaxKind.JSDocEnumTag: + return "enum"; + case SyntaxKind.JSDocAuthorTag: + return "author"; + case SyntaxKind.JSDocClassTag: + return "class"; + case SyntaxKind.JSDocPublicTag: + return "public"; + case SyntaxKind.JSDocPrivateTag: + return "private"; + case SyntaxKind.JSDocProtectedTag: + return "protected"; + case SyntaxKind.JSDocReadonlyTag: + return "readonly"; + case SyntaxKind.JSDocOverrideTag: + return "override"; + case SyntaxKind.JSDocTemplateTag: + return "template"; + case SyntaxKind.JSDocTypedefTag: + return "typedef"; + case SyntaxKind.JSDocParameterTag: + return "param"; + case SyntaxKind.JSDocPropertyTag: + return "prop"; + case SyntaxKind.JSDocCallbackTag: + return "callback"; + case SyntaxKind.JSDocOverloadTag: + return "overload"; + case SyntaxKind.JSDocAugmentsTag: + return "augments"; + case SyntaxKind.JSDocImplementsTag: + return "implements"; default: return Debug.fail(`Unsupported kind: ${Debug.formatSyntaxKind(kind)}`); } } let rawTextScanner: Scanner | undefined; -const invalidValueSentinel: object = { }; +const invalidValueSentinel: object = {}; function getCookedText(kind: TemplateLiteralToken["kind"], rawText: string) { if (!rawTextScanner) { @@ -7175,7 +8460,8 @@ function propagatePropertyNameFlagsOfChild(node: PropertyName, transformFlags: T function propagateChildFlags(child: Node | undefined): TransformFlags { if (!child) return TransformFlags.None; const childFlags = child.transformFlags & ~getTransformFlagsSubtreeExclusions(child.kind); - return isNamedDeclaration(child) && isPropertyName(child.name) ? propagatePropertyNameFlagsOfChild(child.name, childFlags) : childFlags; + return isNamedDeclaration(child) && isPropertyName(child.name) + ? propagatePropertyNameFlagsOfChild(child.name, childFlags) : childFlags; } function propagateChildrenFlags(children: NodeArray | undefined): TransformFlags { @@ -7287,10 +8573,22 @@ export const factory = createNodeFactory(NodeFactoryFlags.NoIndentationOnFreshPr /** @deprecated */ export function createUnparsedSourceFile(text: string): UnparsedSource; /** @deprecated */ -export function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts", stripInternal?: boolean): UnparsedSource; +export function createUnparsedSourceFile( + inputFile: InputFiles, + type: "js" | "dts", + stripInternal?: boolean, +): UnparsedSource; /** @deprecated */ -export function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource; -export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, mapPathOrType?: string, mapTextOrStripInternal?: string | boolean): UnparsedSource { +export function createUnparsedSourceFile( + text: string, + mapPath: string | undefined, + map: string | undefined, +): UnparsedSource; +export function createUnparsedSourceFile( + textOrInputFiles: string | InputFiles, + mapPathOrType?: string, + mapTextOrStripInternal?: string | boolean, +): UnparsedSource { let stripInternal: boolean | undefined; let bundleFileInfo: BundleFileInfo | undefined; let fileName: string; @@ -7305,14 +8603,17 @@ export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, if (!isString(textOrInputFiles)) { Debug.assert(mapPathOrType === "js" || mapPathOrType === "dts"); fileName = (mapPathOrType === "js" ? textOrInputFiles.javascriptPath : textOrInputFiles.declarationPath) || ""; - sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath : textOrInputFiles.declarationMapPath; + sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath + : textOrInputFiles.declarationMapPath; getText = () => mapPathOrType === "js" ? textOrInputFiles.javascriptText : textOrInputFiles.declarationText; - getSourceMapText = () => mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText; + getSourceMapText = () => + mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText; length = () => getText!().length; if (textOrInputFiles.buildInfo && textOrInputFiles.buildInfo.bundle) { Debug.assert(mapTextOrStripInternal === undefined || typeof mapTextOrStripInternal === "boolean"); stripInternal = mapTextOrStripInternal; - bundleFileInfo = mapPathOrType === "js" ? textOrInputFiles.buildInfo.bundle.js : textOrInputFiles.buildInfo.bundle.dts; + bundleFileInfo = mapPathOrType === "js" ? textOrInputFiles.buildInfo.bundle.js + : textOrInputFiles.buildInfo.bundle.dts; oldFileOfCurrentEmit = textOrInputFiles.oldFileOfCurrentEmit; } } @@ -7323,9 +8624,9 @@ export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, sourceMapPath = mapPathOrType; sourceMapText = mapTextOrStripInternal as string; } - const node = oldFileOfCurrentEmit ? - parseOldFileOfCurrentEmit(Debug.checkDefined(bundleFileInfo)) : - parseUnparsedSourceFile(bundleFileInfo, stripInternal, length); + const node = oldFileOfCurrentEmit + ? parseOldFileOfCurrentEmit(Debug.checkDefined(bundleFileInfo)) + : parseUnparsedSourceFile(bundleFileInfo, stripInternal, length); node.fileName = fileName; node.sourceMapPath = sourceMapPath; node.oldFileOfCurrentEmit = oldFileOfCurrentEmit; @@ -7342,7 +8643,11 @@ export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, return node; } -function parseUnparsedSourceFile(bundleFileInfo: BundleFileInfo | undefined, stripInternal: boolean | undefined, length: number | (() => number)) { +function parseUnparsedSourceFile( + bundleFileInfo: BundleFileInfo | undefined, + stripInternal: boolean | undefined, + length: number | (() => number), +) { let prologues: UnparsedPrologue[] | undefined; let helpers: UnscopedEmitHelper[] | undefined; let referencedFiles: FileReference[] | undefined; @@ -7370,10 +8675,20 @@ function parseUnparsedSourceFile(bundleFileInfo: BundleFileInfo | undefined, str typeReferenceDirectives = append(typeReferenceDirectives, { pos: -1, end: -1, fileName: section.data }); break; case BundleFileSectionKind.TypeResolutionModeImport: - typeReferenceDirectives = append(typeReferenceDirectives, { pos: -1, end: -1, fileName: section.data, resolutionMode: ModuleKind.ESNext }); + typeReferenceDirectives = append(typeReferenceDirectives, { + pos: -1, + end: -1, + fileName: section.data, + resolutionMode: ModuleKind.ESNext, + }); break; case BundleFileSectionKind.TypeResolutionModeRequire: - typeReferenceDirectives = append(typeReferenceDirectives, { pos: -1, end: -1, fileName: section.data, resolutionMode: ModuleKind.CommonJS }); + typeReferenceDirectives = append(typeReferenceDirectives, { + pos: -1, + end: -1, + fileName: section.data, + resolutionMode: ModuleKind.CommonJS, + }); break; case BundleFileSectionKind.Lib: libReferenceDirectives = append(libReferenceDirectives, { pos: -1, end: -1, fileName: section.data }); @@ -7382,7 +8697,13 @@ function parseUnparsedSourceFile(bundleFileInfo: BundleFileInfo | undefined, str let prependTexts: UnparsedTextLike[] | undefined; for (const text of section.texts) { if (!stripInternal || text.kind !== BundleFileSectionKind.Internal) { - prependTexts = append(prependTexts, setTextRange(factory.createUnparsedTextLike(text.data, text.kind === BundleFileSectionKind.Internal), text)); + prependTexts = append( + prependTexts, + setTextRange( + factory.createUnparsedTextLike(text.data, text.kind === BundleFileSectionKind.Internal), + text, + ), + ); } } prependChildren = addRange(prependChildren, prependTexts); @@ -7396,7 +8717,13 @@ function parseUnparsedSourceFile(bundleFileInfo: BundleFileInfo | undefined, str // falls through case BundleFileSectionKind.Text: - texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section)); + texts = append( + texts, + setTextRange( + factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), + section, + ), + ); break; default: Debug.assertNever(section); @@ -7409,7 +8736,11 @@ function parseUnparsedSourceFile(bundleFileInfo: BundleFileInfo | undefined, str texts = [textNode]; } - const node = parseNodeFactory.createUnparsedSource(prologues ?? emptyArray, /*syntheticReferences*/ undefined, texts); + const node = parseNodeFactory.createUnparsedSource( + prologues ?? emptyArray, + /*syntheticReferences*/ undefined, + texts, + ); setEachParent(prologues, node); setEachParent(texts, node); setEachParent(prependChildren, node); @@ -7428,7 +8759,13 @@ function parseOldFileOfCurrentEmit(bundleFileInfo: BundleFileInfo) { switch (section.kind) { case BundleFileSectionKind.Internal: case BundleFileSectionKind.Text: - texts = append(texts, setTextRange(factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), section)); + texts = append( + texts, + setTextRange( + factory.createUnparsedTextLike(section.data, section.kind === BundleFileSectionKind.Internal), + section, + ), + ); break; case BundleFileSectionKind.NoDefaultLib: @@ -7437,7 +8774,10 @@ function parseOldFileOfCurrentEmit(bundleFileInfo: BundleFileInfo) { case BundleFileSectionKind.TypeResolutionModeImport: case BundleFileSectionKind.TypeResolutionModeRequire: case BundleFileSectionKind.Lib: - syntheticReferences = append(syntheticReferences, setTextRange(factory.createUnparsedSyntheticReference(section), section)); + syntheticReferences = append( + syntheticReferences, + setTextRange(factory.createUnparsedSyntheticReference(section), section), + ); break; // Ignore @@ -7454,7 +8794,10 @@ function parseOldFileOfCurrentEmit(bundleFileInfo: BundleFileInfo) { const node = factory.createUnparsedSource(emptyArray, syntheticReferences, texts ?? emptyArray); setEachParent(syntheticReferences, node); setEachParent(texts, node); - node.helpers = map(bundleFileInfo.sources && bundleFileInfo.sources.helpers, name => getAllUnscopedEmitHelpers().get(name)!); + node.helpers = map( + bundleFileInfo.sources && bundleFileInfo.sources.helpers, + name => getAllUnscopedEmitHelpers().get(name)!, + ); return node; } @@ -7462,7 +8805,7 @@ function parseOldFileOfCurrentEmit(bundleFileInfo: BundleFileInfo) { /** @deprecated */ export function createInputFiles( javascriptText: string, - declarationText: string + declarationText: string, ): InputFiles; /** @deprecated */ export function createInputFiles( @@ -7471,7 +8814,7 @@ export function createInputFiles( javascriptMapPath: string | undefined, javascriptMapText: string | undefined, declarationMapPath: string | undefined, - declarationMapText: string | undefined + declarationMapText: string | undefined, ): InputFiles; /** @deprecated */ export function createInputFiles( @@ -7480,7 +8823,7 @@ export function createInputFiles( javascriptMapPath: string | undefined, declarationPath: string, declarationMapPath: string | undefined, - buildInfoPath: string | undefined + buildInfoPath: string | undefined, ): InputFiles; export function createInputFiles( javascriptTextOrReadFileText: string | ((path: string) => string | undefined), @@ -7490,16 +8833,16 @@ export function createInputFiles( declarationMapPath?: string, declarationMapTextOrBuildInfoPath?: string, ): InputFiles { - return !isString(javascriptTextOrReadFileText) ? - createInputFilesWithFilePaths( + return !isString(javascriptTextOrReadFileText) + ? createInputFilesWithFilePaths( javascriptTextOrReadFileText, declarationTextOrJavascriptPath, javascriptMapPath, javascriptMapTextOrDeclarationPath!, declarationMapPath, declarationMapTextOrBuildInfoPath, - ) : - createInputFilesWithFileTexts( + ) + : createInputFilesWithFileTexts( /*javascriptPath*/ undefined, javascriptTextOrReadFileText, javascriptMapPath, @@ -7597,8 +8940,16 @@ let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: num /** * Create an external source map source file reference */ -export function createSourceMapSource(fileName: string, text: string, skipTrivia?: (pos: number) => number): SourceMapSource { - return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))(fileName, text, skipTrivia); +export function createSourceMapSource( + fileName: string, + text: string, + skipTrivia?: (pos: number) => number, +): SourceMapSource { + return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))( + fileName, + text, + skipTrivia, + ); } // Utilities @@ -7671,7 +9022,10 @@ function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode | undefi // `tokenSourceMapRanges` are merged with the destination if (tokenSourceMapRanges) { - destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges(tokenSourceMapRanges, destEmitNode.tokenSourceMapRanges!); + destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges( + tokenSourceMapRanges, + destEmitNode.tokenSourceMapRanges!, + ); } // `constantValue` overwrites the destination diff --git a/src/compiler/factory/parenthesizerRules.ts b/src/compiler/factory/parenthesizerRules.ts index 5a1386d567b3f..736259e17837b 100644 --- a/src/compiler/factory/parenthesizerRules.ts +++ b/src/compiler/factory/parenthesizerRules.ts @@ -120,7 +120,12 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the * BinaryExpression. */ - function binaryOperandNeedsParentheses(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand: Expression | undefined) { + function binaryOperandNeedsParentheses( + binaryOperator: SyntaxKind, + operand: Expression, + isLeftSideOfBinary: boolean, + leftOperand: Expression | undefined, + ) { // If the operand has lower precedence, then it needs to be parenthesized to preserve the // intent of the expression. For example, if the operand is `a + b` and the operator is // `*`, then we need to parenthesize the operand to preserve the intended order of @@ -141,7 +146,10 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator); const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator); const emittedOperand = skipPartiallyEmittedExpressions(operand); - if (!isLeftSideOfBinary && operand.kind === SyntaxKind.ArrowFunction && binaryOperatorPrecedence > OperatorPrecedence.Assignment) { + if ( + !isLeftSideOfBinary && operand.kind === SyntaxKind.ArrowFunction + && binaryOperatorPrecedence > OperatorPrecedence.Assignment + ) { // We need to parenthesize arrow functions on the right side to avoid it being // parsed as parenthesized expression: `a && (() => {})` return true; @@ -151,9 +159,11 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul case Comparison.LessThan: // If the operand is the right side of a right-associative binary operation // and is a yield expression, then we do not need parentheses. - if (!isLeftSideOfBinary + if ( + !isLeftSideOfBinary && binaryOperatorAssociativity === Associativity.Right - && operand.kind === SyntaxKind.YieldExpression) { + && operand.kind === SyntaxKind.YieldExpression + ) { return false; } @@ -176,8 +186,10 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul return binaryOperatorAssociativity === Associativity.Right; } else { - if (isBinaryExpression(emittedOperand) - && emittedOperand.operatorToken.kind === binaryOperator) { + if ( + isBinaryExpression(emittedOperand) + && emittedOperand.operatorToken.kind === binaryOperator + ) { // No need to parenthesize the right operand when the binary operator and // operand are the same and one of the following: // x*(a*b) => x*a*b @@ -195,8 +207,12 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul // "a"+(1+2) => "a"+(1+2) // "a"+("b"+"c") => "a"+"b"+"c" if (binaryOperator === SyntaxKind.PlusToken) { - const leftKind = leftOperand ? getLiteralKindOfBinaryPlusOperand(leftOperand) : SyntaxKind.Unknown; - if (isLiteralKind(leftKind) && leftKind === getLiteralKindOfBinaryPlusOperand(emittedOperand)) { + const leftKind = leftOperand ? getLiteralKindOfBinaryPlusOperand(leftOperand) + : SyntaxKind.Unknown; + if ( + isLiteralKind(leftKind) + && leftKind === getLiteralKindOfBinaryPlusOperand(emittedOperand) + ) { return false; } } @@ -252,16 +268,19 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul return node.kind; } - if (node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken) { + if ( + node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken + ) { if ((node as BinaryPlusExpression).cachedLiteralKind !== undefined) { return (node as BinaryPlusExpression).cachedLiteralKind; } const leftKind = getLiteralKindOfBinaryPlusOperand((node as BinaryExpression).left); const literalKind = isLiteralKind(leftKind) - && leftKind === getLiteralKindOfBinaryPlusOperand((node as BinaryExpression).right) - ? leftKind - : SyntaxKind.Unknown; + && leftKind === getLiteralKindOfBinaryPlusOperand((node as BinaryExpression).right) + ? leftKind + : SyntaxKind.Unknown; (node as BinaryPlusExpression).cachedLiteralKind = literalKind; return literalKind; @@ -279,7 +298,12 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the * BinaryExpression. */ - function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean, leftOperand?: Expression) { + function parenthesizeBinaryOperand( + binaryOperator: SyntaxKind, + operand: Expression, + isLeftSideOfBinary: boolean, + leftOperand?: Expression, + ) { const skipped = skipPartiallyEmittedExpressions(operand); // If the resulting expression is already parenthesized, we do not need to do any further processing. @@ -292,12 +316,15 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul : operand; } - function parenthesizeLeftSideOfBinary(binaryOperator: SyntaxKind, leftSide: Expression): Expression { return parenthesizeBinaryOperand(binaryOperator, leftSide, /*isLeftSideOfBinary*/ true); } - function parenthesizeRightSideOfBinary(binaryOperator: SyntaxKind, leftSide: Expression | undefined, rightSide: Expression): Expression { + function parenthesizeRightSideOfBinary( + binaryOperator: SyntaxKind, + leftSide: Expression | undefined, + rightSide: Expression, + ): Expression { return parenthesizeBinaryOperand(binaryOperator, rightSide, /*isLeftSideOfBinary*/ false, leftSide); } @@ -380,9 +407,11 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul // new C.x -> not the same as (new C).x // const emittedExpression = skipPartiallyEmittedExpressions(expression); - if (isLeftHandSideExpression(emittedExpression) + if ( + isLeftHandSideExpression(emittedExpression) && (emittedExpression.kind !== SyntaxKind.NewExpression || (emittedExpression as NewExpression).arguments) - && (optionalChain || !isOptionalChain(emittedExpression))) { + && (optionalChain || !isOptionalChain(emittedExpression)) + ) { // TODO(rbuckton): Verify whether this assertion holds. return expression as LeftHandSideExpression; } @@ -393,12 +422,14 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul function parenthesizeOperandOfPostfixUnary(operand: Expression): LeftHandSideExpression { // TODO(rbuckton): Verifiy whether `setTextRange` is needed. - return isLeftHandSideExpression(operand) ? operand : setTextRange(factory.createParenthesizedExpression(operand), operand); + return isLeftHandSideExpression(operand) ? operand + : setTextRange(factory.createParenthesizedExpression(operand), operand); } function parenthesizeOperandOfPrefixUnary(operand: Expression): UnaryExpression { // TODO(rbuckton): Verifiy whether `setTextRange` is needed. - return isUnaryExpression(operand) ? operand : setTextRange(factory.createParenthesizedExpression(operand), operand); + return isUnaryExpression(operand) ? operand + : setTextRange(factory.createParenthesizedExpression(operand), operand); } function parenthesizeExpressionsOfCommaDelimitedList(elements: NodeArray): NodeArray { @@ -411,7 +442,8 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul const expressionPrecedence = getExpressionPrecedence(emittedExpression); const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken); // TODO(rbuckton): Verifiy whether `setTextRange` is needed. - return expressionPrecedence > commaPrecedence ? expression : setTextRange(factory.createParenthesizedExpression(expression), expression); + return expressionPrecedence > commaPrecedence ? expression + : setTextRange(factory.createParenthesizedExpression(expression), expression); } function parenthesizeExpressionOfExpressionStatement(expression: Expression): Expression { @@ -425,14 +457,21 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul emittedExpression, setTextRange(factory.createParenthesizedExpression(callee), callee), emittedExpression.typeArguments, - emittedExpression.arguments + emittedExpression.arguments, + ); + return factory.restoreOuterExpressions( + expression, + updated, + OuterExpressionKinds.PartiallyEmittedExpressions, ); - return factory.restoreOuterExpressions(expression, updated, OuterExpressionKinds.PartiallyEmittedExpressions); } } const leftmostExpressionKind = getLeftmostExpression(emittedExpression, /*stopAtCallExpressions*/ false).kind; - if (leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression || leftmostExpressionKind === SyntaxKind.FunctionExpression) { + if ( + leftmostExpressionKind === SyntaxKind.ObjectLiteralExpression + || leftmostExpressionKind === SyntaxKind.FunctionExpression + ) { // TODO(rbuckton): Verifiy whether `setTextRange` is needed. return setTextRange(factory.createParenthesizedExpression(expression), expression); } @@ -443,7 +482,12 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul function parenthesizeConciseBodyOfArrowFunction(body: Expression): Expression; function parenthesizeConciseBodyOfArrowFunction(body: ConciseBody): ConciseBody; function parenthesizeConciseBodyOfArrowFunction(body: ConciseBody): ConciseBody { - if (!isBlock(body) && (isCommaSequence(body) || getLeftmostExpression(body, /*stopAtCallExpressions*/ false).kind === SyntaxKind.ObjectLiteralExpression)) { + if ( + !isBlock(body) + && (isCommaSequence(body) + || getLeftmostExpression(body, /*stopAtCallExpressions*/ false).kind + === SyntaxKind.ObjectLiteralExpression) + ) { // TODO(rbuckton): Verifiy whether `setTextRange` is needed. return setTextRange(factory.createParenthesizedExpression(body), body); } @@ -604,11 +648,15 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul function hasJSDocPostfixQuestion(type: TypeNode | NamedTupleMember): boolean { if (isJSDocNullableType(type)) return type.postfix; if (isNamedTupleMember(type)) return hasJSDocPostfixQuestion(type.type); - if (isFunctionTypeNode(type) || isConstructorTypeNode(type) || isTypeOperatorNode(type)) return hasJSDocPostfixQuestion(type.type); + if (isFunctionTypeNode(type) || isConstructorTypeNode(type) || isTypeOperatorNode(type)) { + return hasJSDocPostfixQuestion(type.type); + } if (isConditionalTypeNode(type)) return hasJSDocPostfixQuestion(type.falseType); if (isUnionTypeNode(type)) return hasJSDocPostfixQuestion(last(type.types)); if (isIntersectionTypeNode(type)) return hasJSDocPostfixQuestion(last(type.types)); - if (isInferTypeNode(type)) return !!type.typeParameter.constraint && hasJSDocPostfixQuestion(type.typeParameter.constraint); + if (isInferTypeNode(type)) { + return !!type.typeParameter.constraint && hasJSDocPostfixQuestion(type.typeParameter.constraint); + } return false; } @@ -639,14 +687,17 @@ export function createParenthesizerRules(factory: NodeFactory): ParenthesizerRul // } function parenthesizeLeadingTypeArgument(node: TypeNode) { - return isFunctionOrConstructorTypeNode(node) && node.typeParameters ? factory.createParenthesizedType(node) : node; + return isFunctionOrConstructorTypeNode(node) && node.typeParameters ? factory.createParenthesizedType(node) + : node; } function parenthesizeOrdinalTypeArgument(node: TypeNode, i: number) { return i === 0 ? parenthesizeLeadingTypeArgument(node) : node; } - function parenthesizeTypeArguments(typeArguments: NodeArray | undefined): NodeArray | undefined { + function parenthesizeTypeArguments( + typeArguments: NodeArray | undefined, + ): NodeArray | undefined { if (some(typeArguments)) { return factory.createNodeArray(sameMap(typeArguments, parenthesizeOrdinalTypeArgument)); } diff --git a/src/compiler/factory/utilities.ts b/src/compiler/factory/utilities.ts index 221d4874d5226..e7410a3f58d0b 100644 --- a/src/compiler/factory/utilities.ts +++ b/src/compiler/factory/utilities.ts @@ -178,27 +178,37 @@ import { Token, TransformFlags, TypeNode, - WrappedExpression + WrappedExpression, } from "../_namespaces/ts"; // Compound nodes /** @internal */ export function createEmptyExports(factory: NodeFactory) { - return factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports([]), /*moduleSpecifier*/ undefined); + return factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([]), + /*moduleSpecifier*/ undefined, + ); } /** @internal */ -export function createMemberAccessForPropertyName(factory: NodeFactory, target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression { +export function createMemberAccessForPropertyName( + factory: NodeFactory, + target: Expression, + memberName: PropertyName, + location?: TextRange, +): MemberExpression { if (isComputedPropertyName(memberName)) { - return setTextRange(factory.createElementAccessExpression(target, memberName.expression), location); + return setTextRange(factory.createElementAccessExpression(target, memberName.expression), location); } else { const expression = setTextRange( isMemberName(memberName) ? factory.createPropertyAccessExpression(target, memberName) : factory.createElementAccessExpression(target, memberName), - memberName + memberName, ); addEmitFlags(expression, EmitFlags.NoNestedSourceMaps); return expression; @@ -216,7 +226,11 @@ function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElem return react; } -function createJsxFactoryExpressionFromEntityName(factory: NodeFactory, jsxFactory: EntityName, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { +function createJsxFactoryExpressionFromEntityName( + factory: NodeFactory, + jsxFactory: EntityName, + parent: JsxOpeningLikeElement | JsxOpeningFragment, +): Expression { if (isQualifiedName(jsxFactory)) { const left = createJsxFactoryExpressionFromEntityName(factory, jsxFactory.left, parent); const right = factory.createIdentifier(idText(jsxFactory.right)) as Mutable; @@ -229,26 +243,43 @@ function createJsxFactoryExpressionFromEntityName(factory: NodeFactory, jsxFacto } /** @internal */ -export function createJsxFactoryExpression(factory: NodeFactory, jsxFactoryEntity: EntityName | undefined, reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { - return jsxFactoryEntity ? - createJsxFactoryExpressionFromEntityName(factory, jsxFactoryEntity, parent) : - factory.createPropertyAccessExpression( +export function createJsxFactoryExpression( + factory: NodeFactory, + jsxFactoryEntity: EntityName | undefined, + reactNamespace: string, + parent: JsxOpeningLikeElement | JsxOpeningFragment, +): Expression { + return jsxFactoryEntity + ? createJsxFactoryExpressionFromEntityName(factory, jsxFactoryEntity, parent) + : factory.createPropertyAccessExpression( createReactNamespace(reactNamespace, parent), - "createElement" + "createElement", ); } -function createJsxFragmentFactoryExpression(factory: NodeFactory, jsxFragmentFactoryEntity: EntityName | undefined, reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { - return jsxFragmentFactoryEntity ? - createJsxFactoryExpressionFromEntityName(factory, jsxFragmentFactoryEntity, parent) : - factory.createPropertyAccessExpression( +function createJsxFragmentFactoryExpression( + factory: NodeFactory, + jsxFragmentFactoryEntity: EntityName | undefined, + reactNamespace: string, + parent: JsxOpeningLikeElement | JsxOpeningFragment, +): Expression { + return jsxFragmentFactoryEntity + ? createJsxFactoryExpressionFromEntityName(factory, jsxFragmentFactoryEntity, parent) + : factory.createPropertyAccessExpression( createReactNamespace(reactNamespace, parent), - "Fragment" + "Fragment", ); } /** @internal */ -export function createExpressionForJsxElement(factory: NodeFactory, callee: Expression, tagName: Expression, props: Expression | undefined, children: readonly Expression[] | undefined, location: TextRange): LeftHandSideExpression { +export function createExpressionForJsxElement( + factory: NodeFactory, + callee: Expression, + tagName: Expression, + props: Expression | undefined, + children: readonly Expression[] | undefined, + location: TextRange, +): LeftHandSideExpression { const argumentsList = [tagName]; if (props) { argumentsList.push(props); @@ -274,15 +305,28 @@ export function createExpressionForJsxElement(factory: NodeFactory, callee: Expr factory.createCallExpression( callee, /*typeArguments*/ undefined, - argumentsList + argumentsList, ), - location + location, ); } /** @internal */ -export function createExpressionForJsxFragment(factory: NodeFactory, jsxFactoryEntity: EntityName | undefined, jsxFragmentFactoryEntity: EntityName | undefined, reactNamespace: string, children: readonly Expression[], parentElement: JsxOpeningFragment, location: TextRange): LeftHandSideExpression { - const tagName = createJsxFragmentFactoryExpression(factory, jsxFragmentFactoryEntity, reactNamespace, parentElement); +export function createExpressionForJsxFragment( + factory: NodeFactory, + jsxFactoryEntity: EntityName | undefined, + jsxFragmentFactoryEntity: EntityName | undefined, + reactNamespace: string, + children: readonly Expression[], + parentElement: JsxOpeningFragment, + location: TextRange, +): LeftHandSideExpression { + const tagName = createJsxFragmentFactoryExpression( + factory, + jsxFragmentFactoryEntity, + reactNamespace, + parentElement, + ); const argumentsList = [tagName, factory.createNull()]; if (children && children.length > 0) { @@ -301,16 +345,20 @@ export function createExpressionForJsxFragment(factory: NodeFactory, jsxFactoryE factory.createCallExpression( createJsxFactoryExpression(factory, jsxFactoryEntity, reactNamespace, parentElement), /*typeArguments*/ undefined, - argumentsList + argumentsList, ), - location + location, ); } // Utilities /** @internal */ -export function createForOfBindingStatement(factory: NodeFactory, node: ForInitializer, boundValue: Expression): Statement { +export function createForOfBindingStatement( + factory: NodeFactory, + node: ForInitializer, + boundValue: Expression, +): Statement { if (isVariableDeclarationList(node)) { const firstDeclaration = first(node.declarations); const updatedDeclaration = factory.updateVariableDeclaration( @@ -318,14 +366,14 @@ export function createForOfBindingStatement(factory: NodeFactory, node: ForIniti firstDeclaration.name, /*exclamationToken*/ undefined, /*type*/ undefined, - boundValue + boundValue, ); return setTextRange( factory.createVariableStatement( /*modifiers*/ undefined, - factory.updateVariableDeclarationList(node, [updatedDeclaration]) + factory.updateVariableDeclarationList(node, [updatedDeclaration]), ), - /*location*/ node + /*location*/ node, ); } else { @@ -337,7 +385,10 @@ 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)); + return factory.updateBlock( + dest, + setTextRange(factory.createNodeArray([source, ...dest.statements]), dest.statements), + ); } else { return factory.createBlock(factory.createNodeArray([dest, source]), /*multiLine*/ true); @@ -359,13 +410,19 @@ export function createExpressionFromEntityName(factory: NodeFactory, node: Entit } /** @internal */ -export function createExpressionForPropertyName(factory: NodeFactory, memberName: Exclude): Expression { +export function createExpressionForPropertyName( + factory: NodeFactory, + memberName: Exclude, +): Expression { if (isIdentifier(memberName)) { return factory.createStringLiteralFromNode(memberName); } else if (isComputedPropertyName(memberName)) { // TODO(rbuckton): Does this need to be parented? - return setParent(setTextRange(factory.cloneNode(memberName.expression), memberName.expression), memberName.expression.parent); + return setParent( + setTextRange(factory.cloneNode(memberName.expression), memberName.expression), + memberName.expression.parent, + ); } else { // TODO(rbuckton): Does this need to be parented? @@ -373,7 +430,13 @@ export function createExpressionForPropertyName(factory: NodeFactory, memberName } } -function createExpressionForAccessorDeclaration(factory: NodeFactory, properties: NodeArray, property: AccessorDeclaration & { readonly name: Exclude; }, receiver: Expression, multiLine: boolean) { +function createExpressionForAccessorDeclaration( + factory: NodeFactory, + properties: NodeArray, + property: AccessorDeclaration & { readonly name: Exclude; }, + receiver: Expression, + multiLine: boolean, +) { const { firstAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations(properties, property); if (property === firstAccessor) { return setTextRange( @@ -392,11 +455,11 @@ function createExpressionForAccessorDeclaration(factory: NodeFactory, properties /*typeParameters*/ undefined, getAccessor.parameters, /*type*/ undefined, - getAccessor.body! // TODO: GH#18217 + getAccessor.body!, // TODO: GH#18217 ), - getAccessor + getAccessor, ), - getAccessor + getAccessor, ), set: setAccessor && setTextRange( setOriginalNode( @@ -407,44 +470,52 @@ function createExpressionForAccessorDeclaration(factory: NodeFactory, properties /*typeParameters*/ undefined, setAccessor.parameters, /*type*/ undefined, - setAccessor.body! // TODO: GH#18217 + setAccessor.body!, // TODO: GH#18217 ), - setAccessor + setAccessor, ), - setAccessor - ) - }, !multiLine) + setAccessor, + ), + }, !multiLine), ), - firstAccessor + firstAccessor, ); } return undefined; } -function createExpressionForPropertyAssignment(factory: NodeFactory, property: PropertyAssignment, receiver: Expression) { +function createExpressionForPropertyAssignment( + factory: NodeFactory, + property: PropertyAssignment, + receiver: Expression, +) { return setOriginalNode( setTextRange( factory.createAssignment( createMemberAccessForPropertyName(factory, receiver, property.name, /*location*/ property.name), - property.initializer + property.initializer, ), - property + property, ), - property + property, ); } -function createExpressionForShorthandPropertyAssignment(factory: NodeFactory, property: ShorthandPropertyAssignment, receiver: Expression) { +function createExpressionForShorthandPropertyAssignment( + factory: NodeFactory, + property: ShorthandPropertyAssignment, + receiver: Expression, +) { return setOriginalNode( setTextRange( factory.createAssignment( createMemberAccessForPropertyName(factory, receiver, property.name, /*location*/ property.name), - factory.cloneNode(property.name) + factory.cloneNode(property.name), ), - /*location*/ property + /*location*/ property, ), - /*original*/ property + /*original*/ property, ); } @@ -462,28 +533,39 @@ function createExpressionForMethodDeclaration(factory: NodeFactory, method: Meth /*typeParameters*/ undefined, method.parameters, /*type*/ undefined, - method.body! // TODO: GH#18217 + method.body!, // TODO: GH#18217 ), - /*location*/ method + /*location*/ method, ), - /*original*/ method - ) + /*original*/ method, + ), ), - /*location*/ method + /*location*/ method, ), - /*original*/ method + /*original*/ method, ); } /** @internal */ -export function createExpressionForObjectLiteralElementLike(factory: NodeFactory, node: ObjectLiteralExpression, property: ObjectLiteralElementLike, receiver: Expression): Expression | undefined { +export function createExpressionForObjectLiteralElementLike( + factory: NodeFactory, + node: ObjectLiteralExpression, + property: ObjectLiteralElementLike, + receiver: Expression, +): Expression | undefined { if (property.name && isPrivateIdentifier(property.name)) { Debug.failBadSyntaxKind(property.name, "Private identifiers are not allowed in object literals."); } switch (property.kind) { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return createExpressionForAccessorDeclaration(factory, node.properties, property as typeof property & { readonly name: Exclude }, receiver, !!node.multiLine); + return createExpressionForAccessorDeclaration( + factory, + node.properties, + property as typeof property & { readonly name: Exclude; }, + receiver, + !!node.multiLine, + ); case SyntaxKind.PropertyAssignment: return createExpressionForPropertyAssignment(factory, property, receiver); case SyntaxKind.ShorthandPropertyAssignment: @@ -527,17 +609,26 @@ export function createExpressionForObjectLiteralElementLike(factory: NodeFactory * * @internal */ -export function expandPreOrPostfixIncrementOrDecrementExpression(factory: NodeFactory, node: PrefixUnaryExpression | PostfixUnaryExpression, expression: Expression, recordTempVariable: (node: Identifier) => void, resultVariable: Identifier | undefined) { +export function expandPreOrPostfixIncrementOrDecrementExpression( + factory: NodeFactory, + node: PrefixUnaryExpression | PostfixUnaryExpression, + expression: Expression, + recordTempVariable: (node: Identifier) => void, + resultVariable: Identifier | undefined, +) { const operator = node.operator; - Debug.assert(operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken, "Expected 'node' to be a pre- or post-increment or pre- or post-decrement expression"); + Debug.assert( + operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken, + "Expected 'node' to be a pre- or post-increment or pre- or post-decrement expression", + ); const temp = factory.createTempVariable(recordTempVariable); expression = factory.createAssignment(temp, expression); setTextRange(expression, node.operand); - let operation: Expression = isPrefixUnaryExpression(node) ? - factory.createPrefixUnaryExpression(operator, temp) : - factory.createPostfixUnaryExpression(temp, operator); + let operation: Expression = isPrefixUnaryExpression(node) + ? factory.createPrefixUnaryExpression(operator, temp) + : factory.createPostfixUnaryExpression(temp, operator); setTextRange(operation, node); if (resultVariable) { @@ -612,12 +703,17 @@ export function startsWithUseStrict(statements: readonly Statement[]) { } /** @internal */ -export function isCommaExpression(node: Expression): node is BinaryExpression & { operatorToken: Token } { - return node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken; +export function isCommaExpression( + node: Expression, +): node is BinaryExpression & { operatorToken: Token; } { + return node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.CommaToken; } /** @internal */ -export function isCommaSequence(node: Expression): node is BinaryExpression & {operatorToken: Token} | CommaListExpression { +export function isCommaSequence( + node: Expression, +): node is BinaryExpression & { operatorToken: Token; } | CommaListExpression { return isCommaExpression(node) || isCommaListExpression(node); } @@ -709,11 +805,22 @@ export function hasRecordedExternalHelpers(sourceFile: SourceFile) { } /** @internal */ -export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: NodeFactory, helperFactory: EmitHelperFactory, sourceFile: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean, hasImportStar?: boolean, hasImportDefault?: boolean) { +export function createExternalHelpersImportDeclarationIfNeeded( + nodeFactory: NodeFactory, + helperFactory: EmitHelperFactory, + sourceFile: SourceFile, + compilerOptions: CompilerOptions, + hasExportStarsToExportValues?: boolean, + hasImportStar?: boolean, + hasImportDefault?: boolean, +) { if (compilerOptions.importHelpers && isEffectiveExternalModule(sourceFile, compilerOptions)) { let namedBindings: NamedImportBindings | undefined; const moduleKind = getEmitModuleKind(compilerOptions); - if ((moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) || sourceFile.impliedNodeFormat === ModuleKind.ESNext) { + if ( + (moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) + || sourceFile.impliedNodeFormat === ModuleKind.ESNext + ) { // use named imports const helpers = getEmitHelpers(sourceFile); if (helpers) { @@ -731,10 +838,18 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node // Alias the imports if the names are used somewhere in the file. // NOTE: We don't need to care about global import collisions as this is a module. namedBindings = nodeFactory.createNamedImports( - map(helperNames, name => isFileLevelUniqueName(sourceFile, name) - ? nodeFactory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, nodeFactory.createIdentifier(name)) - : nodeFactory.createImportSpecifier(/*isTypeOnly*/ false, nodeFactory.createIdentifier(name), helperFactory.getUnscopedHelperName(name)) - ) + map(helperNames, name => + isFileLevelUniqueName(sourceFile, name) + ? nodeFactory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + nodeFactory.createIdentifier(name), + ) + : nodeFactory.createImportSpecifier( + /*isTypeOnly*/ false, + nodeFactory.createIdentifier(name), + helperFactory.getUnscopedHelperName(name), + )), ); const parseNode = getOriginalNode(sourceFile, isSourceFile); const emitNode = getOrCreateEmitNode(parseNode); @@ -744,7 +859,13 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node } else { // use a namespace import - const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(nodeFactory, sourceFile, compilerOptions, hasExportStarsToExportValues, hasImportStar || hasImportDefault); + const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded( + nodeFactory, + sourceFile, + compilerOptions, + hasExportStarsToExportValues, + hasImportStar || hasImportDefault, + ); if (externalHelpersModuleName) { namedBindings = nodeFactory.createNamespaceImport(externalHelpersModuleName); } @@ -754,7 +875,7 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node /*modifiers*/ undefined, nodeFactory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, namedBindings), nodeFactory.createStringLiteral(externalHelpersModuleNameText), - /*assertClause*/ undefined + /*assertClause*/ undefined, ); addInternalEmitFlags(externalHelpersImportDeclaration, InternalEmitFlags.NeverApplyImportHelper); return externalHelpersImportDeclaration; @@ -763,7 +884,13 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node } /** @internal */ -export function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactory, node: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean, hasImportStarOrImportDefault?: boolean) { +export function getOrCreateExternalHelpersModuleNameIfNeeded( + factory: NodeFactory, + node: SourceFile, + compilerOptions: CompilerOptions, + hasExportStarsToExportValues?: boolean, + hasImportStarOrImportDefault?: boolean, +) { if (compilerOptions.importHelpers && isEffectiveExternalModule(node, compilerOptions)) { const externalHelpersModuleName = getExternalHelpersModuleName(node); if (externalHelpersModuleName) { @@ -771,7 +898,8 @@ export function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactor } const moduleKind = getEmitModuleKind(compilerOptions); - let create = (hasExportStarsToExportValues || (getESModuleInterop(compilerOptions) && hasImportStarOrImportDefault)) + let create = + (hasExportStarsToExportValues || (getESModuleInterop(compilerOptions) && hasImportStarOrImportDefault)) && moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || node.impliedNodeFormat === ModuleKind.CommonJS); if (!create) { @@ -789,7 +917,8 @@ export function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactor if (create) { const parseNode = getOriginalNode(node, isSourceFile); const emitNode = getOrCreateEmitNode(parseNode); - return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = factory.createUniqueName(externalHelpersModuleNameText)); + return emitNode.externalHelpersModuleName + || (emitNode.externalHelpersModuleName = factory.createUniqueName(externalHelpersModuleNameText)); } } } @@ -799,11 +928,16 @@ export function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactor * * @internal */ -export function getLocalNameForExternalImport(factory: NodeFactory, node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration, sourceFile: SourceFile): Identifier | undefined { +export function getLocalNameForExternalImport( + factory: NodeFactory, + node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration, + sourceFile: SourceFile, +): Identifier | undefined { const namespaceDeclaration = getNamespaceDeclarationNode(node); if (namespaceDeclaration && !isDefaultImport(node) && !isExportNamespaceAsDefaultDeclaration(node)) { const name = namespaceDeclaration.name; - return isGeneratedIdentifier(name) ? name : factory.createIdentifier(getSourceTextOfNodeFromSourceFile(sourceFile, name) || idText(name)); + return isGeneratedIdentifier(name) ? name + : factory.createIdentifier(getSourceTextOfNodeFromSourceFile(sourceFile, name) || idText(name)); } if (node.kind === SyntaxKind.ImportDeclaration && node.importClause) { return factory.getGeneratedNameForNode(node); @@ -824,7 +958,14 @@ export function getLocalNameForExternalImport(factory: NodeFactory, node: Import * * @internal */ -export function getExternalModuleNameLiteral(factory: NodeFactory, importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportCall, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) { +export function getExternalModuleNameLiteral( + factory: NodeFactory, + importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration | ImportCall, + sourceFile: SourceFile, + host: EmitHost, + resolver: EmitResolver, + compilerOptions: CompilerOptions, +) { const moduleName = getExternalModuleName(importNode); if (moduleName && isStringLiteral(moduleName)) { return tryGetModuleNameFromDeclaration(importNode, host, factory, resolver, compilerOptions) @@ -853,7 +994,12 @@ function tryRenameExternalModule(factory: NodeFactory, moduleName: LiteralExpres * * @internal */ -export function tryGetModuleNameFromFile(factory: NodeFactory, file: SourceFile | undefined, host: EmitHost, options: CompilerOptions): StringLiteral | undefined { +export function tryGetModuleNameFromFile( + factory: NodeFactory, + file: SourceFile | undefined, + host: EmitHost, + options: CompilerOptions, +): StringLiteral | undefined { if (!file) { return undefined; } @@ -866,8 +1012,19 @@ export function tryGetModuleNameFromFile(factory: NodeFactory, file: SourceFile return undefined; } -function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ImportCall, host: EmitHost, factory: NodeFactory, resolver: EmitResolver, compilerOptions: CompilerOptions) { - return tryGetModuleNameFromFile(factory, resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions); +function tryGetModuleNameFromDeclaration( + declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ImportCall, + host: EmitHost, + factory: NodeFactory, + resolver: EmitResolver, + compilerOptions: CompilerOptions, +) { + return tryGetModuleNameFromFile( + factory, + resolver.getExternalModuleFileFromDeclaration(declaration), + host, + compilerOptions, + ); } /** @@ -875,7 +1032,9 @@ function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | * * @internal */ -export function getInitializerOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): Expression | undefined { +export function getInitializerOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, +): Expression | undefined { if (isDeclarationBindingElement(bindingElement)) { // `1` in `let { a = 1 } = ...` // `1` in `let { a: b = 1 } = ...` @@ -920,7 +1079,9 @@ export function getInitializerOfBindingOrAssignmentElement(bindingElement: Bindi * * @internal */ -export function getTargetOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): BindingOrAssignmentElementTarget | undefined { +export function getTargetOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, +): BindingOrAssignmentElementTarget | undefined { if (isDeclarationBindingElement(bindingElement)) { // `a` in `let { a } = ...` // `a` in `let { a = 1 } = ...` @@ -997,7 +1158,9 @@ export function getTargetOfBindingOrAssignmentElement(bindingElement: BindingOrA * * @internal */ -export function getRestIndicatorOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): BindingOrAssignmentElementRestIndicator | undefined { +export function getRestIndicatorOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, +): BindingOrAssignmentElementRestIndicator | undefined { switch (bindingElement.kind) { case SyntaxKind.Parameter: case SyntaxKind.BindingElement: @@ -1018,14 +1181,18 @@ export function getRestIndicatorOfBindingOrAssignmentElement(bindingElement: Bin * * @internal */ -export function getPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): Exclude | undefined { +export function getPropertyNameOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, +): Exclude | undefined { const propertyName = tryGetPropertyNameOfBindingOrAssignmentElement(bindingElement); Debug.assert(!!propertyName || isSpreadAssignment(bindingElement), "Invalid property name for binding element."); return propertyName; } /** @internal */ -export function tryGetPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): Exclude | undefined { +export function tryGetPropertyNameOfBindingOrAssignmentElement( + bindingElement: BindingOrAssignmentElement, +): Exclude | undefined { switch (bindingElement.kind) { case SyntaxKind.BindingElement: // `a` in `let { a: b } = ...` @@ -1086,7 +1253,9 @@ function isStringOrNumericLiteral(node: Node): node is StringLiteral | NumericLi * * @internal */ -export function getElementsOfBindingOrAssignmentPattern(name: BindingOrAssignmentPattern): readonly BindingOrAssignmentElement[] { +export function getElementsOfBindingOrAssignmentPattern( + name: BindingOrAssignmentPattern, +): readonly BindingOrAssignmentElement[] { switch (name.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: @@ -1182,7 +1351,9 @@ export function isModuleName(node: Node): node is ModuleName { } /** @internal */ -export function isLiteralTypeLikeExpression(node: Node): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression { +export function isLiteralTypeLikeExpression( + node: Node, +): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression { const kind = node.kind; return kind === SyntaxKind.NullKeyword || kind === SyntaxKind.TrueKeyword @@ -1291,7 +1462,15 @@ export function isBinaryOperatorToken(node: Node): node is BinaryOperatorToken { return isBinaryOperator(node.kind); } -type BinaryExpressionState = (machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], resultHolder: { value: TResult }, outerState: TOuterState) => number; +type BinaryExpressionState = ( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + resultHolder: { value: TResult; }, + outerState: TOuterState, +) => number; namespace BinaryExpressionState { /** @@ -1300,7 +1479,15 @@ namespace BinaryExpressionState { * @param frame The current frame * @returns The new frame */ - export function enter(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }, outerState: TOuterState): number { + export function enter( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + _resultHolder: { value: TResult; }, + outerState: TOuterState, + ): number { const prevUserState = stackIndex > 0 ? userStateStack[stackIndex - 1] : undefined; Debug.assertEqual(stateStack[stackIndex], enter); userStateStack[stackIndex] = machine.onEnter(nodeStack[stackIndex], prevUserState, outerState); @@ -1314,7 +1501,15 @@ namespace BinaryExpressionState { * @param frame The current frame * @returns The new frame */ - export function left(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }, _outerState: TOuterState): number { + export function left( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + _resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], left); Debug.assertIsDefined(machine.onLeft); stateStack[stackIndex] = nextState(machine, left); @@ -1332,7 +1527,15 @@ namespace BinaryExpressionState { * @param frame The current frame * @returns The new frame */ - export function operator(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }, _outerState: TOuterState): number { + export function operator( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + _resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], operator); Debug.assertIsDefined(machine.onOperator); stateStack[stackIndex] = nextState(machine, operator); @@ -1346,11 +1549,23 @@ namespace BinaryExpressionState { * @param frame The current frame * @returns The new frame */ - export function right(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }, _outerState: TOuterState): number { + export function right( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + _resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], right); Debug.assertIsDefined(machine.onRight); stateStack[stackIndex] = nextState(machine, right); - const nextNode = machine.onRight(nodeStack[stackIndex].right, userStateStack[stackIndex], nodeStack[stackIndex]); + const nextNode = machine.onRight( + nodeStack[stackIndex].right, + userStateStack[stackIndex], + nodeStack[stackIndex], + ); if (nextNode) { checkCircularity(stackIndex, nodeStack, nextNode); return pushStack(stackIndex, stateStack, nodeStack, userStateStack, nextNode); @@ -1364,7 +1579,15 @@ namespace BinaryExpressionState { * @param frame The current frame * @returns The new frame */ - export function exit(machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], resultHolder: { value: TResult }, _outerState: TOuterState): number { + export function exit( + machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], exit); stateStack[stackIndex] = nextState(machine, exit); const result = machine.onExit(nodeStack[stackIndex], userStateStack[stackIndex]); @@ -1385,12 +1608,23 @@ namespace BinaryExpressionState { * Handles a frame that is already done. * @returns The `done` state. */ - export function done(_machine: BinaryExpressionStateMachine, stackIndex: number, stateStack: BinaryExpressionState[], _nodeStack: BinaryExpression[], _userStateStack: TState[], _resultHolder: { value: TResult }, _outerState: TOuterState): number { + export function done( + _machine: BinaryExpressionStateMachine, + stackIndex: number, + stateStack: BinaryExpressionState[], + _nodeStack: BinaryExpression[], + _userStateStack: TState[], + _resultHolder: { value: TResult; }, + _outerState: TOuterState, + ): number { Debug.assertEqual(stateStack[stackIndex], done); return stackIndex; } - export function nextState(machine: BinaryExpressionStateMachine, currentState: BinaryExpressionState) { + export function nextState( + machine: BinaryExpressionStateMachine, + currentState: BinaryExpressionState, + ) { switch (currentState) { case enter: if (machine.onLeft) return left; @@ -1401,14 +1635,24 @@ namespace BinaryExpressionState { case operator: if (machine.onRight) return right; // falls through - case right: return exit; - case exit: return done; - case done: return done; - default: Debug.fail("Invalid state"); + case right: + return exit; + case exit: + return done; + case done: + return done; + default: + Debug.fail("Invalid state"); } } - function pushStack(stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], node: BinaryExpression) { + function pushStack( + stackIndex: number, + stateStack: BinaryExpressionState[], + nodeStack: BinaryExpression[], + userStateStack: TState[], + node: BinaryExpression, + ) { stackIndex++; stateStack[stackIndex] = enter; nodeStack[stackIndex] = node; @@ -1432,9 +1676,15 @@ namespace BinaryExpressionState { class BinaryExpressionStateMachine { constructor( readonly onEnter: (node: BinaryExpression, prev: TState | undefined, outerState: TOuterState) => TState, - readonly onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, - readonly onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined, - readonly onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, + readonly onLeft: + | ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) + | undefined, + readonly onOperator: + | ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) + | undefined, + readonly onRight: + | ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) + | undefined, readonly onExit: (node: BinaryExpression, userState: TState) => TResult, readonly foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined, ) { @@ -1452,7 +1702,7 @@ class BinaryExpressionStateMachine { * * @internal */ - export function createBinaryExpressionTrampoline( +export function createBinaryExpressionTrampoline( onEnter: (node: BinaryExpression, prev: TState | undefined) => TState, onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined, onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined, @@ -1492,13 +1742,21 @@ export function createBinaryExpressionTrampoline( return trampoline; function trampoline(node: BinaryExpression, outerState: TOuterState) { - const resultHolder: { value: TResult } = { value: undefined! }; + const resultHolder: { value: TResult; } = { value: undefined! }; const stateStack: BinaryExpressionState[] = [BinaryExpressionState.enter]; const nodeStack: BinaryExpression[] = [node]; const userStateStack: TState[] = [undefined!]; let stackIndex = 0; while (stateStack[stackIndex] !== BinaryExpressionState.done) { - stackIndex = stateStack[stackIndex](machine, stackIndex, stateStack, nodeStack, userStateStack, resultHolder, outerState); + stackIndex = stateStack[stackIndex]( + machine, + stackIndex, + stateStack, + nodeStack, + userStateStack, + resultHolder, + outerState, + ); } Debug.assertEqual(stackIndex, 0); return resultHolder.value; @@ -1527,9 +1785,15 @@ export function isNonExportDefaultModifier(node: Node): node is Exclude(factory: NodeFactory, nodes: NodeArray): NodeArray; /** @internal */ -export function elideNodes(factory: NodeFactory, nodes: NodeArray | undefined): NodeArray | undefined; +export function elideNodes( + factory: NodeFactory, + nodes: NodeArray | undefined, +): NodeArray | undefined; /** @internal */ -export function elideNodes(factory: NodeFactory, nodes: NodeArray | undefined): NodeArray | undefined { +export function elideNodes( + factory: NodeFactory, + nodes: NodeArray | undefined, +): NodeArray | undefined { if (nodes === undefined) return undefined; if (nodes.length === 0) return nodes; return setTextRange(factory.createNodeArray([], nodes.hasTrailingComma), nodes); @@ -1550,10 +1814,13 @@ export function getNodeForGeneratedName(name: GeneratedIdentifier | GeneratedPri node = original; const autoGenerate = node.emitNode?.autoGenerate; // if "node" is a different generated name (having a different "autoGenerateId"), use it and stop traversing. - if (isMemberName(node) && ( - autoGenerate === undefined || - !!(autoGenerate.flags & GeneratedIdentifierFlags.Node) && - autoGenerate.id !== autoGenerateId)) { + if ( + isMemberName(node) && ( + autoGenerate === undefined + || !!(autoGenerate.flags & GeneratedIdentifierFlags.Node) + && autoGenerate.id !== autoGenerateId + ) + ) { break; } @@ -1576,24 +1843,38 @@ export function formatGeneratedNamePart(part: string | undefined): string; * * @internal */ -export function formatGeneratedNamePart(part: string | GeneratedNamePart | undefined, generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string): string; +export function formatGeneratedNamePart( + part: string | GeneratedNamePart | undefined, + generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, +): string; /** @internal */ -export function formatGeneratedNamePart(part: string | GeneratedNamePart | undefined, generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string): string { - return typeof part === "object" ? formatGeneratedName(/*privateName*/ false, part.prefix, part.node, part.suffix, generateName!) : - typeof part === "string" ? part.length > 0 && part.charCodeAt(0) === CharacterCodes.hash ? part.slice(1) : part : - ""; -} - -function formatIdentifier(name: string | Identifier | PrivateIdentifier, generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string) { - return typeof name === "string" ? name : - formatIdentifierWorker(name, Debug.checkDefined(generateName)); +export function formatGeneratedNamePart( + part: string | GeneratedNamePart | undefined, + generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, +): string { + return typeof part === "object" + ? formatGeneratedName(/*privateName*/ false, part.prefix, part.node, part.suffix, generateName!) + : typeof part === "string" + ? part.length > 0 && part.charCodeAt(0) === CharacterCodes.hash ? part.slice(1) : part + : ""; +} + +function formatIdentifier( + name: string | Identifier | PrivateIdentifier, + generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, +) { + return typeof name === "string" ? name + : formatIdentifierWorker(name, Debug.checkDefined(generateName)); } -function formatIdentifierWorker(node: Identifier | PrivateIdentifier, generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string) { - return isGeneratedPrivateIdentifier(node) ? generateName(node).slice(1) : - isGeneratedIdentifier(node) ? generateName(node) : - isPrivateIdentifier(node) ? (node.escapedText as string).slice(1) : - idText(node); +function formatIdentifierWorker( + node: Identifier | PrivateIdentifier, + generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, +) { + return isGeneratedPrivateIdentifier(node) ? generateName(node).slice(1) + : isGeneratedIdentifier(node) ? generateName(node) + : isPrivateIdentifier(node) ? (node.escapedText as string).slice(1) + : idText(node); } /** @@ -1605,7 +1886,12 @@ function formatIdentifierWorker(node: Identifier | PrivateIdentifier, generateNa * * @internal */ -export function formatGeneratedName(privateName: boolean, prefix: string | undefined, baseName: string, suffix: string | undefined): string; +export function formatGeneratedName( + privateName: boolean, + prefix: string | undefined, + baseName: string, + suffix: string | undefined, +): string; /** * Formats a generated name. * @param privateName When `true`, inserts a `#` character at the start of the result. @@ -1616,9 +1902,21 @@ export function formatGeneratedName(privateName: boolean, prefix: string | undef * * @internal */ -export function formatGeneratedName(privateName: boolean, prefix: string | GeneratedNamePart | undefined, baseName: string | Identifier | PrivateIdentifier, suffix: string | GeneratedNamePart | undefined, generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string): string; +export function formatGeneratedName( + privateName: boolean, + prefix: string | GeneratedNamePart | undefined, + baseName: string | Identifier | PrivateIdentifier, + suffix: string | GeneratedNamePart | undefined, + generateName: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, +): string; /** @internal */ -export function formatGeneratedName(privateName: boolean, prefix: string | GeneratedNamePart | undefined, baseName: string | Identifier | PrivateIdentifier, suffix: string | GeneratedNamePart | undefined, generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string) { +export function formatGeneratedName( + privateName: boolean, + prefix: string | GeneratedNamePart | undefined, + baseName: string | Identifier | PrivateIdentifier, + suffix: string | GeneratedNamePart | undefined, + generateName?: (name: GeneratedIdentifier | GeneratedPrivateIdentifier) => string, +) { prefix = formatGeneratedNamePart(prefix, generateName!); suffix = formatGeneratedNamePart(suffix, generateName!); baseName = formatIdentifier(baseName, generateName); @@ -1630,14 +1928,19 @@ export function formatGeneratedName(privateName: boolean, prefix: string | Gener * * @internal */ -export function createAccessorPropertyBackingField(factory: NodeFactory, node: PropertyDeclaration, modifiers: ModifiersArray | undefined, initializer: Expression | undefined) { +export function createAccessorPropertyBackingField( + factory: NodeFactory, + node: PropertyDeclaration, + modifiers: ModifiersArray | undefined, + initializer: Expression | undefined, +) { return factory.updatePropertyDeclaration( node, modifiers, factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage"), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - initializer + initializer, ); } @@ -1646,7 +1949,13 @@ export function createAccessorPropertyBackingField(factory: NodeFactory, node: P * * @internal */ -export function createAccessorPropertyGetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: readonly Modifier[] | undefined, name: PropertyName, receiver: Expression = factory.createThis()): GetAccessorDeclaration { +export function createAccessorPropertyGetRedirector( + factory: NodeFactory, + node: PropertyDeclaration, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + receiver: Expression = factory.createThis(), +): GetAccessorDeclaration { return factory.createGetAccessorDeclaration( modifiers, name, @@ -1656,10 +1965,10 @@ export function createAccessorPropertyGetRedirector(factory: NodeFactory, node: factory.createReturnStatement( factory.createPropertyAccessExpression( receiver, - factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage") - ) - ) - ]) + factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage"), + ), + ), + ]), ); } @@ -1668,26 +1977,32 @@ export function createAccessorPropertyGetRedirector(factory: NodeFactory, node: * * @internal */ -export function createAccessorPropertySetRedirector(factory: NodeFactory, node: PropertyDeclaration, modifiers: readonly Modifier[] | undefined, name: PropertyName, receiver: Expression = factory.createThis()) { +export function createAccessorPropertySetRedirector( + factory: NodeFactory, + node: PropertyDeclaration, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + receiver: Expression = factory.createThis(), +) { return factory.createSetAccessorDeclaration( modifiers, name, [factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, - "value" + "value", )], factory.createBlock([ factory.createExpressionStatement( factory.createAssignment( factory.createPropertyAccessExpression( receiver, - factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage") + factory.getGeneratedPrivateNameForNode(node.name, /*prefix*/ undefined, "_accessor_storage"), ), - factory.createIdentifier("value") - ) - ) - ]) + factory.createIdentifier("value"), + ), + ), + ]), ); } @@ -1707,7 +2022,7 @@ export function findComputedPropertyNameCacheAssignment(name: ComputedPropertyNa } if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true) && isGeneratedIdentifier(node.left)) { - return node as AssignmentExpression & { readonly left: GeneratedIdentifier }; + return node as AssignmentExpression & { readonly left: GeneratedIdentifier; }; } break; diff --git a/src/compiler/factory/utilitiesPublic.ts b/src/compiler/factory/utilitiesPublic.ts index 8afd72574c0fb..5380a4a1604e0 100644 --- a/src/compiler/factory/utilitiesPublic.ts +++ b/src/compiler/factory/utilitiesPublic.ts @@ -49,4 +49,4 @@ export function canHaveDecorators(node: Node): node is HasDecorators { || kind === SyntaxKind.SetAccessor || kind === SyntaxKind.ClassExpression || kind === SyntaxKind.ClassDeclaration; -} \ No newline at end of file +} diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index c229d42be1b36..2cdb2d62f6391 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -124,7 +124,10 @@ export function isTraceEnabled(compilerOptions: CompilerOptions, host: ModuleRes return !!compilerOptions.traceResolution && host.trace !== undefined; } -function withPackageId(packageInfo: PackageJsonInfo | undefined, r: PathAndExtension | undefined): Resolved | undefined { +function withPackageId( + packageInfo: PackageJsonInfo | undefined, + r: PathAndExtension | undefined, +): Resolved | undefined { let packageId: PackageId | undefined; if (r && packageInfo) { const packageJsonContent = packageInfo.contents.packageJsonContent as PackageJson; @@ -132,7 +135,7 @@ function withPackageId(packageInfo: PackageJsonInfo | undefined, r: PathAndExten packageId = { name: packageJsonContent.name, subModuleName: r.path.slice(packageInfo.packageDirectory.length + directorySeparator.length), - version: packageJsonContent.version + version: packageJsonContent.version, }; } } @@ -176,6 +179,7 @@ interface PathAndExtension { resolvedUsingTsExtension: boolean | undefined; } +// dprint-ignore /** * Kinds of file that we are currently looking for. */ @@ -230,14 +234,19 @@ function createResolvedModuleWithFailedLookupLocationsHandlingSymlink( legacyResult?: string, ): ResolvedModuleWithFailedLookupLocations { // If this is from node_modules for non relative name, always respect preserveSymlinks - if (!state.resultFromCache && - !state.compilerOptions.preserveSymlinks && - resolved && - isExternalLibraryImport && - !resolved.originalPath && - !isExternalModuleNameRelative(moduleName) + if ( + !state.resultFromCache + && !state.compilerOptions.preserveSymlinks + && resolved + && isExternalLibraryImport + && !resolved.originalPath + && !isExternalModuleNameRelative(moduleName) ) { - const { resolvedFileName, originalPath } = getOriginalAndResolvedFileName(resolved.path, state.host, state.traceEnabled); + const { resolvedFileName, originalPath } = getOriginalAndResolvedFileName( + resolved.path, + state.host, + state.traceEnabled, + ); if (originalPath) resolved = { ...resolved, path: resolvedFileName, originalPath }; } return createResolvedModuleWithFailedLookupLocations( @@ -261,9 +270,18 @@ function createResolvedModuleWithFailedLookupLocations( legacyResult?: string, ): ResolvedModuleWithFailedLookupLocations { if (resultFromCache) { - resultFromCache.failedLookupLocations = updateResolutionField(resultFromCache.failedLookupLocations, failedLookupLocations); - resultFromCache.affectingLocations = updateResolutionField(resultFromCache.affectingLocations, affectingLocations); - resultFromCache.resolutionDiagnostics = updateResolutionField(resultFromCache.resolutionDiagnostics, diagnostics); + resultFromCache.failedLookupLocations = updateResolutionField( + resultFromCache.failedLookupLocations, + failedLookupLocations, + ); + resultFromCache.affectingLocations = updateResolutionField( + resultFromCache.affectingLocations, + affectingLocations, + ); + resultFromCache.resolutionDiagnostics = updateResolutionField( + resultFromCache.resolutionDiagnostics, + diagnostics, + ); return resultFromCache; } return { @@ -330,9 +348,24 @@ interface PackageJson extends PackageJsonPathFields { version?: string; } -function readPackageJsonField>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined; -function readPackageJsonField>(jsonContent: PackageJson, fieldName: K, typeOfTag: "object", state: ModuleResolutionState): PackageJson[K] | undefined; -function readPackageJsonField(jsonContent: PackageJson, fieldName: K, typeOfTag: "string" | "object", state: ModuleResolutionState): PackageJson[K] | undefined { +function readPackageJsonField>( + jsonContent: PackageJson, + fieldName: K, + typeOfTag: "string", + state: ModuleResolutionState, +): PackageJson[K] | undefined; +function readPackageJsonField>( + jsonContent: PackageJson, + fieldName: K, + typeOfTag: "object", + state: ModuleResolutionState, +): PackageJson[K] | undefined; +function readPackageJsonField( + jsonContent: PackageJson, + fieldName: K, + typeOfTag: "string" | "object", + state: ModuleResolutionState, +): PackageJson[K] | undefined { if (!hasProperty(jsonContent, fieldName)) { if (state.traceEnabled) { trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName); @@ -343,14 +376,25 @@ function readPackageJsonField(jsonContent: PackageJ if (typeof value !== typeOfTag || value === null) { // eslint-disable-line no-null/no-null if (state.traceEnabled) { // eslint-disable-next-line no-null/no-null - trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, fieldName, typeOfTag, value === null ? "null" : typeof value); + trace( + state.host, + Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, + fieldName, + typeOfTag, + value === null ? "null" : typeof value, + ); } return; } return value; } -function readPackageJsonPathField(jsonContent: PackageJson, fieldName: K, baseDirectory: string, state: ModuleResolutionState): PackageJson[K] | undefined { +function readPackageJsonPathField( + jsonContent: PackageJson, + fieldName: K, + baseDirectory: string, + state: ModuleResolutionState, +): PackageJson[K] | undefined { const fileName = readPackageJsonField(jsonContent, fieldName, "string", state); if (fileName === undefined) { return; @@ -398,14 +442,21 @@ export interface VersionPaths { paths: MapLike; } -function readPackageJsonTypesVersionPaths(jsonContent: PackageJson, state: ModuleResolutionState): VersionPaths | undefined { +function readPackageJsonTypesVersionPaths( + jsonContent: PackageJson, + state: ModuleResolutionState, +): VersionPaths | undefined { const typesVersions = readPackageJsonTypesVersionsField(jsonContent, state); if (typesVersions === undefined) return; if (state.traceEnabled) { for (const key in typesVersions) { if (hasProperty(typesVersions, key) && !VersionRange.tryParse(key)) { - trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range, key); + trace( + state.host, + Diagnostics.package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range, + key, + ); } } } @@ -413,7 +464,11 @@ function readPackageJsonTypesVersionPaths(jsonContent: PackageJson, state: Modul const result = getPackageJsonTypesVersionsPaths(typesVersions); if (!result) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, versionMajorMinor); + trace( + state.host, + Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, + versionMajorMinor, + ); } return; } @@ -421,7 +476,13 @@ function readPackageJsonTypesVersionPaths(jsonContent: PackageJson, state: Modul const { version: bestVersionKey, paths: bestVersionPaths } = result; if (typeof bestVersionPaths !== "object") { if (state.traceEnabled) { - trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, `typesVersions['${bestVersionKey}']`, "object", typeof bestVersionPaths); + trace( + state.host, + Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, + `typesVersions['${bestVersionKey}']`, + "object", + typeof bestVersionPaths, + ); } return; } @@ -483,7 +544,8 @@ function getDefaultTypeRoots(currentDirectory: string): string[] | undefined { const nodeModulesAtTypes = combinePaths("node_modules", "@types"); function arePathsEqual(path1: string, path2: string, host: ModuleResolutionHost): boolean { - const useCaseSensitiveFileNames = typeof host.useCaseSensitiveFileNames === "function" ? host.useCaseSensitiveFileNames() : host.useCaseSensitiveFileNames; + const useCaseSensitiveFileNames = typeof host.useCaseSensitiveFileNames === "function" + ? host.useCaseSensitiveFileNames() : host.useCaseSensitiveFileNames; return comparePaths(path1, path2, !useCaseSensitiveFileNames) === Comparison.EqualTo; } @@ -497,10 +559,14 @@ function getOriginalAndResolvedFileName(fileName: string, host: ModuleResolution }; } -function getCandidateFromTypeRoot(typeRoot: string, typeReferenceDirectiveName: string, moduleResolutionState: ModuleResolutionState) { - const nameForLookup = endsWith(typeRoot, "/node_modules/@types") || endsWith(typeRoot, "/node_modules/@types/") ? - mangleScopedPackageNameWithTrace(typeReferenceDirectiveName, moduleResolutionState) : - typeReferenceDirectiveName; +function getCandidateFromTypeRoot( + typeRoot: string, + typeReferenceDirectiveName: string, + moduleResolutionState: ModuleResolutionState, +) { + const nameForLookup = endsWith(typeRoot, "/node_modules/@types") || endsWith(typeRoot, "/node_modules/@types/") + ? mangleScopedPackageNameWithTrace(typeReferenceDirectiveName, moduleResolutionState) + : typeReferenceDirectiveName; return combinePaths(typeRoot, nameForLookup); } @@ -509,50 +575,111 @@ function getCandidateFromTypeRoot(typeRoot: string, typeReferenceDirectiveName: * This is possible in case if resolution is performed for directives specified via 'types' parameter. In this case initial path for secondary lookups * is assumed to be the same as root directory of the project. */ -export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost, redirectedReference?: ResolvedProjectReference, cache?: TypeReferenceDirectiveResolutionCache, resolutionMode?: ResolutionMode): ResolvedTypeReferenceDirectiveWithFailedLookupLocations { - Debug.assert(typeof typeReferenceDirectiveName === "string", "Non-string value passed to `ts.resolveTypeReferenceDirective`, likely by a wrapping package working with an outdated `resolveTypeReferenceDirectives` signature. This is probably not a problem in TS itself."); +export function resolveTypeReferenceDirective( + typeReferenceDirectiveName: string, + containingFile: string | undefined, + options: CompilerOptions, + host: ModuleResolutionHost, + redirectedReference?: ResolvedProjectReference, + cache?: TypeReferenceDirectiveResolutionCache, + resolutionMode?: ResolutionMode, +): ResolvedTypeReferenceDirectiveWithFailedLookupLocations { + Debug.assert( + typeof typeReferenceDirectiveName === "string", + "Non-string value passed to `ts.resolveTypeReferenceDirective`, likely by a wrapping package working with an outdated `resolveTypeReferenceDirectives` signature. This is probably not a problem in TS itself.", + ); const traceEnabled = isTraceEnabled(options, host); if (redirectedReference) { options = redirectedReference.commandLine.options; } const containingDirectory = containingFile ? getDirectoryPath(containingFile) : undefined; - let result = containingDirectory ? cache?.getFromDirectoryCache(typeReferenceDirectiveName, resolutionMode, containingDirectory, redirectedReference) : undefined; + let result = containingDirectory + ? cache?.getFromDirectoryCache( + typeReferenceDirectiveName, + resolutionMode, + containingDirectory, + redirectedReference, + ) : undefined; if (!result && containingDirectory && !isExternalModuleNameRelative(typeReferenceDirectiveName)) { - result = cache?.getFromNonRelativeNameCache(typeReferenceDirectiveName, resolutionMode, containingDirectory, redirectedReference); + result = cache?.getFromNonRelativeNameCache( + typeReferenceDirectiveName, + resolutionMode, + containingDirectory, + redirectedReference, + ); } if (result) { if (traceEnabled) { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1, typeReferenceDirectiveName, containingFile); - if (redirectedReference) trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName); - trace(host, Diagnostics.Resolution_for_type_reference_directive_0_was_found_in_cache_from_location_1, typeReferenceDirectiveName, containingDirectory); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_1, + typeReferenceDirectiveName, + containingFile, + ); + if (redirectedReference) { + trace( + host, + Diagnostics.Using_compiler_options_of_project_reference_redirect_0, + redirectedReference.sourceFile.fileName, + ); + } + trace( + host, + Diagnostics.Resolution_for_type_reference_directive_0_was_found_in_cache_from_location_1, + typeReferenceDirectiveName, + containingDirectory, + ); traceResult(result); } return result; } - const typeRoots = getEffectiveTypeRoots(options, host); if (traceEnabled) { if (containingFile === undefined) { if (typeRoots === undefined) { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set, typeReferenceDirectiveName); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set, + typeReferenceDirectiveName, + ); } else { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, typeReferenceDirectiveName, typeRoots); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, + typeReferenceDirectiveName, + typeRoots, + ); } } else { if (typeRoots === undefined) { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set, typeReferenceDirectiveName, containingFile); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set, + typeReferenceDirectiveName, + containingFile, + ); } else { - trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, typeReferenceDirectiveName, containingFile, typeRoots); + trace( + host, + Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, + typeReferenceDirectiveName, + containingFile, + typeRoots, + ); } } if (redirectedReference) { - trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName); + trace( + host, + Diagnostics.Using_compiler_options_of_project_reference_redirect_0, + redirectedReference.sourceFile.fileName, + ); } } @@ -566,10 +693,15 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string // in practice, not every cache has the options available to intelligently make the choice to ignore the mode request, and it's unclear how modern "faithful modern // resolution" should be (`node16`? `nodenext`?). As such, witnessing a mode-overriding triple-slash reference in a non-modal module resolution // context should _probably_ be an error - and that should likely be handled by the `Program` (which is what we do). - if (resolutionMode === ModuleKind.ESNext && (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext)) { + if ( + resolutionMode === ModuleKind.ESNext + && (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 + || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext) + ) { features |= NodeResolutionFeatures.EsmMode; } - const conditions = features & NodeResolutionFeatures.Exports ? getConditions(options, !!(features & NodeResolutionFeatures.EsmMode)) : []; + const conditions = features & NodeResolutionFeatures.Exports + ? getConditions(options, !!(features & NodeResolutionFeatures.EsmMode)) : []; const diagnostics: Diagnostic[] = []; const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, @@ -596,7 +728,9 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string if (resolved) { const { fileName, packageId } = resolved; let resolvedFileName = fileName, originalPath: string | undefined; - if (!options.preserveSymlinks) ({ resolvedFileName, originalPath } = getOriginalAndResolvedFileName(fileName, host, traceEnabled)); + if (!options.preserveSymlinks) { + ({ resolvedFileName, originalPath } = getOriginalAndResolvedFileName(fileName, host, traceEnabled)); + } resolvedTypeReferenceDirective = { primary, resolvedFileName, @@ -612,9 +746,14 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string resolutionDiagnostics: initializeResolutionField(diagnostics), }; if (containingDirectory) { - cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result); + cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set( + typeReferenceDirectiveName, + /*mode*/ resolutionMode, + result, + ); if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) { - cache?.getOrCreateCacheForNonRelativeName(typeReferenceDirectiveName, resolutionMode, redirectedReference).set(containingDirectory, result); + cache?.getOrCreateCacheForNonRelativeName(typeReferenceDirectiveName, resolutionMode, redirectedReference) + .set(containingDirectory, result); } } if (traceEnabled) traceResult(result); @@ -625,10 +764,23 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName); } else if (result.resolvedTypeReferenceDirective.packageId) { - trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_with_Package_ID_2_primary_Colon_3, typeReferenceDirectiveName, result.resolvedTypeReferenceDirective.resolvedFileName, packageIdToString(result.resolvedTypeReferenceDirective.packageId), result.resolvedTypeReferenceDirective.primary); + trace( + host, + Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_with_Package_ID_2_primary_Colon_3, + typeReferenceDirectiveName, + result.resolvedTypeReferenceDirective.resolvedFileName, + packageIdToString(result.resolvedTypeReferenceDirective.packageId), + result.resolvedTypeReferenceDirective.primary, + ); } else { - trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, result.resolvedTypeReferenceDirective.resolvedFileName, result.resolvedTypeReferenceDirective.primary); + trace( + host, + Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, + typeReferenceDirectiveName, + result.resolvedTypeReferenceDirective.resolvedFileName, + result.resolvedTypeReferenceDirective.primary, + ); } } @@ -646,16 +798,28 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string } if (options.typeRoots) { // Custom typeRoots resolve as file or directory just like we do modules - const resolvedFromFile = loadModuleFromFile(Extensions.Declaration, candidate, !directoryExists, moduleResolutionState); + const resolvedFromFile = loadModuleFromFile( + Extensions.Declaration, + candidate, + !directoryExists, + moduleResolutionState, + ); if (resolvedFromFile) { const packageDirectory = parseNodeModuleFromPath(resolvedFromFile.path); - const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, moduleResolutionState) : undefined; + const packageInfo = packageDirectory + ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, moduleResolutionState) + : undefined; return resolvedTypeScriptOnly(withPackageId(packageInfo, resolvedFromFile)); } } return resolvedTypeScriptOnly( - loadNodeModuleFromDirectory(Extensions.Declaration, candidate, - !directoryExists, moduleResolutionState)); + loadNodeModuleFromDirectory( + Extensions.Declaration, + candidate, + !directoryExists, + moduleResolutionState, + ), + ); }); } else { @@ -672,25 +836,53 @@ export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string if (!options.typeRoots || !endsWith(containingFile!, inferredTypesContainingFile)) { // check secondary locations if (traceEnabled) { - trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup); + trace( + host, + Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, + initialLocationForSecondaryLookup, + ); } if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) { - const searchResult = loadModuleFromNearestNodeModulesDirectory(Extensions.Declaration, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined, /*redirectedReference*/ undefined); + const searchResult = loadModuleFromNearestNodeModulesDirectory( + Extensions.Declaration, + typeReferenceDirectiveName, + initialLocationForSecondaryLookup, + moduleResolutionState, + /*cache*/ undefined, + /*redirectedReference*/ undefined, + ); result = searchResult && searchResult.value; } else { - const { path: candidate } = normalizePathForCJSResolution(initialLocationForSecondaryLookup, typeReferenceDirectiveName); - result = nodeLoadModuleByRelativeName(Extensions.Declaration, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true); + const { path: candidate } = normalizePathForCJSResolution( + initialLocationForSecondaryLookup, + typeReferenceDirectiveName, + ); + result = nodeLoadModuleByRelativeName( + Extensions.Declaration, + candidate, + /*onlyRecordFailures*/ false, + moduleResolutionState, + /*considerPackageJson*/ true, + ); } } else if (traceEnabled) { - trace(host, Diagnostics.Resolving_type_reference_directive_for_program_that_specifies_custom_typeRoots_skipping_lookup_in_node_modules_folder); + trace( + host, + Diagnostics + .Resolving_type_reference_directive_for_program_that_specifies_custom_typeRoots_skipping_lookup_in_node_modules_folder, + ); } return resolvedTypeScriptOnly(result); } else { if (traceEnabled) { - trace(host, Diagnostics.Containing_file_is_not_specified_and_root_directory_cannot_be_determined_skipping_lookup_in_node_modules_folder); + trace( + host, + Diagnostics + .Containing_file_is_not_specified_and_root_directory_cannot_be_determined_skipping_lookup_in_node_modules_folder, + ); } } } @@ -789,7 +981,8 @@ export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: M // `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types. // See `createNotNeededPackageJSON` in the types-publisher` repo. // eslint-disable-next-line no-null/no-null - const isNotNeededPackage = host.fileExists(packageJsonPath) && (readJson(packageJsonPath, host) as PackageJson).typings === null; + const isNotNeededPackage = host.fileExists(packageJsonPath) + && (readJson(packageJsonPath, host) as PackageJson).typings === null; if (!isNotNeededPackage) { const baseFileName = getBaseFileName(normalized); @@ -807,7 +1000,12 @@ export function getAutomaticTypeDirectiveNames(options: CompilerOptions, host: M return result; } -export interface TypeReferenceDirectiveResolutionCache extends PerDirectoryResolutionCache, NonRelativeNameResolutionCache, PackageJsonInfoCache { +export interface TypeReferenceDirectiveResolutionCache + extends + PerDirectoryResolutionCache, + NonRelativeNameResolutionCache, + PackageJsonInfoCache +{ /** @internal */ clearAllExceptPackageJsonInfoCache(): void; } @@ -825,8 +1023,16 @@ export interface ModeAwareCache { * This assumes that any module id will have the same resolution for sibling files located in the same folder. */ export interface PerDirectoryResolutionCache { - getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined; - getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): ModeAwareCache; + getFromDirectoryCache( + name: string, + mode: ResolutionMode, + directoryName: string, + redirectedReference: ResolvedProjectReference | undefined, + ): T | undefined; + getOrCreateCacheForDirectory( + directoryName: string, + redirectedReference?: ResolvedProjectReference, + ): ModeAwareCache; clear(): void; /** * Updates with the current compilerOptions the cache will operate with. @@ -836,8 +1042,17 @@ export interface PerDirectoryResolutionCache { } export interface NonRelativeNameResolutionCache { - getFromNonRelativeNameCache(nonRelativeName: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined): T | undefined; - getOrCreateCacheForNonRelativeName(nonRelativeName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache; + getFromNonRelativeNameCache( + nonRelativeName: string, + mode: ResolutionMode, + directoryName: string, + redirectedReference: ResolvedProjectReference | undefined, + ): T | undefined; + getOrCreateCacheForNonRelativeName( + nonRelativeName: string, + mode: ResolutionMode, + redirectedReference?: ResolvedProjectReference, + ): PerNonRelativeNameCache; clear(): void; /** * Updates with the current compilerOptions the cache will operate with. @@ -851,7 +1066,12 @@ export interface PerNonRelativeNameCache { set(directory: string, result: T): void; } -export interface ModuleResolutionCache extends PerDirectoryResolutionCache, NonRelativeModuleNameResolutionCache, PackageJsonInfoCache { +export interface ModuleResolutionCache + extends + PerDirectoryResolutionCache, + NonRelativeModuleNameResolutionCache, + PackageJsonInfoCache +{ getPackageJsonInfoCache(): PackageJsonInfoCache; /** @internal */ clearAllExceptPackageJsonInfoCache(): void; /** @internal */ optionsToRedirectsKey: Map; @@ -861,9 +1081,15 @@ export interface ModuleResolutionCache extends PerDirectoryResolutionCache result of module lookup in this directory * We support only non-relative module names because resolution of relative module names is usually more deterministic and thus less expensive. */ -export interface NonRelativeModuleNameResolutionCache extends NonRelativeNameResolutionCache, PackageJsonInfoCache { +export interface NonRelativeModuleNameResolutionCache + extends NonRelativeNameResolutionCache, PackageJsonInfoCache +{ /** @deprecated Use getOrCreateCacheForNonRelativeName */ - getOrCreateCacheForModuleName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerModuleNameCache; + getOrCreateCacheForModuleName( + nonRelativeModuleName: string, + mode: ResolutionMode, + redirectedReference?: ResolvedProjectReference, + ): PerModuleNameCache; } export interface PackageJsonInfoCache { @@ -893,8 +1119,13 @@ function compilerOptionValueToString(value: unknown): string { } /** @internal */ -export function getKeyForCompilerOptions(options: CompilerOptions, affectingOptionDeclarations: readonly CommandLineOption[]) { - return affectingOptionDeclarations.map(option => compilerOptionValueToString(getCompilerOptionValue(options, option))).join("|") + `|${options.pathsBasePath}`; +export function getKeyForCompilerOptions( + options: CompilerOptions, + affectingOptionDeclarations: readonly CommandLineOption[], +) { + return affectingOptionDeclarations.map(option => + compilerOptionValueToString(getCompilerOptionValue(options, option)) + ).join("|") + `|${options.pathsBasePath}`; } /** @internal */ @@ -909,7 +1140,10 @@ export interface CacheWithRedirects { export type RedirectsCacheKey = string & { __compilerOptionsKey: any; }; /** @internal */ -export function createCacheWithRedirects(ownOptions: CompilerOptions | undefined, optionsToRedirectsKey: Map): CacheWithRedirects { +export function createCacheWithRedirects( + ownOptions: CompilerOptions | undefined, + optionsToRedirectsKey: Map, +): CacheWithRedirects { const redirectsMap = new Map>(); const redirectsKeyToMap = new Map>(); let ownMap = new Map(); @@ -922,15 +1156,15 @@ export function createCacheWithRedirects(ownOptions: CompilerOptions | und }; function getMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map | undefined { - return redirectedReference ? - getOrCreateMap(redirectedReference.commandLine.options, /*create*/ false) : - ownMap; + return redirectedReference + ? getOrCreateMap(redirectedReference.commandLine.options, /*create*/ false) + : ownMap; } function getOrCreateMapOfCacheRedirects(redirectedReference: ResolvedProjectReference | undefined): Map { - return redirectedReference ? - getOrCreateMap(redirectedReference.commandLine.options, /*create*/ true) : - ownMap; + return redirectedReference + ? getOrCreateMap(redirectedReference.commandLine.options, /*create*/ true) + : ownMap; } function update(newOptions: CompilerOptions) { @@ -976,13 +1210,19 @@ export function createCacheWithRedirects(ownOptions: CompilerOptions | und function getRedirectsCacheKey(options: CompilerOptions) { let result = optionsToRedirectsKey.get(options); if (!result) { - optionsToRedirectsKey.set(options, result = getKeyForCompilerOptions(options, moduleResolutionOptionDeclarations) as RedirectsCacheKey); + optionsToRedirectsKey.set( + options, + result = getKeyForCompilerOptions(options, moduleResolutionOptionDeclarations) as RedirectsCacheKey, + ); } return result; } } -function createPackageJsonInfoCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): PackageJsonInfoCache { +function createPackageJsonInfoCache( + currentDirectory: string, + getCanonicalFileName: (s: string) => string, +): PackageJsonInfoCache { let cache: Map | undefined; return { getPackageJsonInfo, setPackageJsonInfo, clear, entries, getInternalMap }; function getPackageJsonInfo(packageJsonPath: string) { @@ -1003,7 +1243,12 @@ function createPackageJsonInfoCache(currentDirectory: string, getCanonicalFileNa } } -function getOrCreateCache(cacheWithRedirects: CacheWithRedirects, redirectedReference: ResolvedProjectReference | undefined, key: K, create: () => V): V { +function getOrCreateCache( + cacheWithRedirects: CacheWithRedirects, + redirectedReference: ResolvedProjectReference | undefined, + key: K, + create: () => V, +): V { const cache = cacheWithRedirects.getOrCreateMapOfCacheRedirects(redirectedReference); let result = cache.get(key); if (!result) { @@ -1040,7 +1285,12 @@ function createPerDirectoryResolutionCache( return getOrCreateCache(directoryToModuleNameMap, redirectedReference, path, () => createModeAwareCache()); } - function getFromDirectoryCache(name: string, mode: ResolutionMode, directoryName: string, redirectedReference: ResolvedProjectReference | undefined) { + function getFromDirectoryCache( + name: string, + mode: ResolutionMode, + directoryName: string, + redirectedReference: ResolvedProjectReference | undefined, + ) { const path = toPath(directoryName, currentDirectory, getCanonicalFileName); return directoryToModuleNameMap.getMapOfCacheRedirects(redirectedReference)?.get(path)?.get(name, mode); } @@ -1080,7 +1330,7 @@ export function createModeAwareCache(): ModeAwareCache { }, size() { return underlying.size; - } + }, }; return cache; @@ -1112,8 +1362,9 @@ function getOriginalOrResolvedModuleFileName(result: ResolvedModuleWithFailedLoo } function getOriginalOrResolvedTypeReferenceFileName(result: ResolvedTypeReferenceDirectiveWithFailedLookupLocations) { - return result.resolvedTypeReferenceDirective && - (result.resolvedTypeReferenceDirective.originalPath || result.resolvedTypeReferenceDirective.resolvedFileName); + return result.resolvedTypeReferenceDirective + && (result.resolvedTypeReferenceDirective.originalPath + || result.resolvedTypeReferenceDirective.resolvedFileName); } function createNonRelativeNameResolutionCache( @@ -1123,7 +1374,10 @@ function createNonRelativeNameResolutionCache( getResolvedFileName: (result: T) => string | undefined, optionsToRedirectsKey: Map, ): NonRelativeNameResolutionCache { - const moduleNameToDirectoryMap = createCacheWithRedirects>(options, optionsToRedirectsKey); + const moduleNameToDirectoryMap = createCacheWithRedirects>( + options, + optionsToRedirectsKey, + ); return { getFromNonRelativeNameCache, getOrCreateCacheForNonRelativeName, @@ -1139,14 +1393,30 @@ function createNonRelativeNameResolutionCache( moduleNameToDirectoryMap.update(options); } - function getFromNonRelativeNameCache(nonRelativeModuleName: string, mode: ResolutionMode, directoryName: string, redirectedReference?: ResolvedProjectReference): T | undefined { + function getFromNonRelativeNameCache( + nonRelativeModuleName: string, + mode: ResolutionMode, + directoryName: string, + redirectedReference?: ResolvedProjectReference, + ): T | undefined { Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName)); - return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get(createModeAwareCacheKey(nonRelativeModuleName, mode))?.get(directoryName); + return moduleNameToDirectoryMap.getMapOfCacheRedirects(redirectedReference)?.get( + createModeAwareCacheKey(nonRelativeModuleName, mode), + )?.get(directoryName); } - function getOrCreateCacheForNonRelativeName(nonRelativeModuleName: string, mode: ResolutionMode, redirectedReference?: ResolvedProjectReference): PerNonRelativeNameCache { + function getOrCreateCacheForNonRelativeName( + nonRelativeModuleName: string, + mode: ResolutionMode, + redirectedReference?: ResolvedProjectReference, + ): PerNonRelativeNameCache { Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName)); - return getOrCreateCache(moduleNameToDirectoryMap, redirectedReference, createModeAwareCacheKey(nonRelativeModuleName, mode), createPerModuleNameCache); + return getOrCreateCache( + moduleNameToDirectoryMap, + redirectedReference, + createModeAwareCacheKey(nonRelativeModuleName, mode), + createPerModuleNameCache, + ); } function createPerModuleNameCache(): PerNonRelativeNameCache { @@ -1205,7 +1475,10 @@ function createNonRelativeNameResolutionCache( while (i < limit && directory.charCodeAt(i) === resolutionDirectory.charCodeAt(i)) { i++; } - if (i === directory.length && (resolutionDirectory.length === i || resolutionDirectory[i] === directorySeparator)) { + if ( + i === directory.length + && (resolutionDirectory.length === i || resolutionDirectory[i] === directorySeparator) + ) { return directory; } const rootLength = getRootLength(directory); @@ -1221,7 +1494,9 @@ function createNonRelativeNameResolutionCache( } } -interface ModuleOrTypeReferenceResolutionCache extends PerDirectoryResolutionCache, NonRelativeNameResolutionCache, PackageJsonInfoCache { +interface ModuleOrTypeReferenceResolutionCache + extends PerDirectoryResolutionCache, NonRelativeNameResolutionCache, PackageJsonInfoCache +{ getPackageJsonInfoCache(): PackageJsonInfoCache; clearAllExceptPackageJsonInfoCache(): void; optionsToRedirectsKey: Map; @@ -1306,7 +1581,8 @@ export function createModuleResolutionCache( getOriginalOrResolvedModuleFileName, optionsToRedirectsKey, ) as ModuleResolutionCache; - result.getOrCreateCacheForModuleName = (nonRelativeName, mode, redirectedReference) => result.getOrCreateCacheForNonRelativeName(nonRelativeName, mode, redirectedReference); + result.getOrCreateCacheForModuleName = (nonRelativeName, mode, redirectedReference) => + result.getOrCreateCacheForNonRelativeName(nonRelativeName, mode, redirectedReference); return result; } @@ -1347,16 +1623,35 @@ export function getOptionsForLibraryResolution(options: CompilerOptions) { } /** @internal */ -export function resolveLibrary(libraryName: string, resolveFrom: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations { +export function resolveLibrary( + libraryName: string, + resolveFrom: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, +): ResolvedModuleWithFailedLookupLocations { return resolveModuleName(libraryName, resolveFrom, getOptionsForLibraryResolution(compilerOptions), host, cache); } -export function resolveModuleNameFromCache(moduleName: string, containingFile: string, cache: ModuleResolutionCache, mode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations | undefined { +export function resolveModuleNameFromCache( + moduleName: string, + containingFile: string, + cache: ModuleResolutionCache, + mode?: ResolutionMode, +): ResolvedModuleWithFailedLookupLocations | undefined { const containingDirectory = getDirectoryPath(containingFile); return cache.getFromDirectoryCache(moduleName, mode, containingDirectory, /*redirectedReference*/ undefined); } -export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations { +export function resolveModuleName( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + resolutionMode?: ResolutionMode, +): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); if (redirectedReference) { compilerOptions = redirectedReference.commandLine.options; @@ -1364,7 +1659,11 @@ export function resolveModuleName(moduleName: string, containingFile: string, co if (traceEnabled) { trace(host, Diagnostics.Resolving_module_0_from_1, moduleName, containingFile); if (redirectedReference) { - trace(host, Diagnostics.Using_compiler_options_of_project_reference_redirect_0, redirectedReference.sourceFile.fileName); + trace( + host, + Diagnostics.Using_compiler_options_of_project_reference_redirect_0, + redirectedReference.sourceFile.fileName, + ); } } const containingDirectory = getDirectoryPath(containingFile); @@ -1372,7 +1671,12 @@ export function resolveModuleName(moduleName: string, containingFile: string, co if (result) { if (traceEnabled) { - trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory); + trace( + host, + Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, + moduleName, + containingDirectory, + ); } } else { @@ -1393,52 +1697,119 @@ export function resolveModuleName(moduleName: string, containingFile: string, co break; } if (traceEnabled) { - trace(host, Diagnostics.Module_resolution_kind_is_not_specified_using_0, ModuleResolutionKind[moduleResolution]); + trace( + host, + Diagnostics.Module_resolution_kind_is_not_specified_using_0, + ModuleResolutionKind[moduleResolution], + ); } } else { if (traceEnabled) { - trace(host, Diagnostics.Explicitly_specified_module_resolution_kind_Colon_0, ModuleResolutionKind[moduleResolution]); + trace( + host, + Diagnostics.Explicitly_specified_module_resolution_kind_Colon_0, + ModuleResolutionKind[moduleResolution], + ); } } perfLogger?.logStartResolveModule(moduleName /* , containingFile, ModuleResolutionKind[moduleResolution]*/); switch (moduleResolution) { case ModuleResolutionKind.Node16: - result = node16ModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode); + result = node16ModuleNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + resolutionMode, + ); break; case ModuleResolutionKind.NodeNext: - result = nodeNextModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference, resolutionMode); + result = nodeNextModuleNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + resolutionMode, + ); break; case ModuleResolutionKind.Node10: - result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference); + result = nodeModuleNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + ); break; case ModuleResolutionKind.Classic: - result = classicNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference); + result = classicNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + ); break; case ModuleResolutionKind.Bundler: - result = bundlerModuleNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference); + result = bundlerModuleNameResolver( + moduleName, + containingFile, + compilerOptions, + host, + cache, + redirectedReference, + ); break; default: return Debug.fail(`Unexpected moduleResolution: ${moduleResolution}`); } - if (result && result.resolvedModule) perfLogger?.logInfoEvent(`Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`); - perfLogger?.logStopResolveModule((result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null"); + if (result && result.resolvedModule) { + perfLogger?.logInfoEvent(`Module "${moduleName}" resolved to "${result.resolvedModule.resolvedFileName}"`); + } + perfLogger?.logStopResolveModule( + (result && result.resolvedModule) ? "" + result.resolvedModule.resolvedFileName : "null", + ); - cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set(moduleName, resolutionMode, result); + cache?.getOrCreateCacheForDirectory(containingDirectory, redirectedReference).set( + moduleName, + resolutionMode, + result, + ); if (!isExternalModuleNameRelative(moduleName)) { // put result in per-module name cache - cache?.getOrCreateCacheForNonRelativeName(moduleName, resolutionMode, redirectedReference).set(containingDirectory, result); + cache?.getOrCreateCacheForNonRelativeName(moduleName, resolutionMode, redirectedReference).set( + containingDirectory, + result, + ); } } if (traceEnabled) { if (result.resolvedModule) { if (result.resolvedModule.packageId) { - trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1_with_Package_ID_2, moduleName, result.resolvedModule.resolvedFileName, packageIdToString(result.resolvedModule.packageId)); + trace( + host, + Diagnostics.Module_name_0_was_successfully_resolved_to_1_with_Package_ID_2, + moduleName, + result.resolvedModule.resolvedFileName, + packageIdToString(result.resolvedModule.packageId), + ); } else { - trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1, moduleName, result.resolvedModule.resolvedFileName); + trace( + host, + Diagnostics.Module_name_0_was_successfully_resolved_to_1, + moduleName, + result.resolvedModule.resolvedFileName, + ); } } else { @@ -1457,7 +1828,12 @@ export function resolveModuleName(moduleName: string, containingFile: string, co * 'typings' entry or file 'index' with some supported extension * - Classic loader will only try to interpret '/a/b/c' as file. */ -type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined; +type ResolutionKindSpecificLoader = ( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +) => Resolved | undefined; /** * Any module resolution kind can be augmented with optional settings: 'baseUrl', 'paths' and 'rootDirs' - they are used to @@ -1519,9 +1895,13 @@ type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, * be converted to a path relative to found rootDir entry './content/protocols/file2' (*). As a last step compiler will check all remaining * entries in 'rootDirs', use them to build absolute path out of (*) and try to resolve module from this location. */ -function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader, - state: ModuleResolutionState): Resolved | undefined { - +function tryLoadModuleUsingOptionalResolutionSettings( + extensions: Extensions, + moduleName: string, + containingDirectory: string, + loader: ResolutionKindSpecificLoader, + state: ModuleResolutionState, +): Resolved | undefined { const resolved = tryLoadModuleUsingPathsIfEligible(extensions, moduleName, loader, state); if (resolved) return resolved.value; @@ -1533,24 +1913,52 @@ function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, mo } } -function tryLoadModuleUsingPathsIfEligible(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState) { +function tryLoadModuleUsingPathsIfEligible( + extensions: Extensions, + moduleName: string, + loader: ResolutionKindSpecificLoader, + state: ModuleResolutionState, +) { const { baseUrl, paths, configFile } = state.compilerOptions; if (paths && !pathIsRelative(moduleName)) { if (state.traceEnabled) { if (baseUrl) { - trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName); + trace( + state.host, + Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, + baseUrl, + moduleName, + ); } - trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName); + trace( + state.host, + Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, + moduleName, + ); } const baseDirectory = getPathsBasePath(state.compilerOptions, state.host)!; // Always defined when 'paths' is defined - const pathPatterns = configFile?.configFileSpecs ? configFile.configFileSpecs.pathPatterns ||= tryParsePatterns(paths) : undefined; - return tryLoadModuleUsingPaths(extensions, moduleName, baseDirectory, paths, pathPatterns, loader, /*onlyRecordFailures*/ false, state); + const pathPatterns = configFile?.configFileSpecs + ? configFile.configFileSpecs.pathPatterns ||= tryParsePatterns(paths) : undefined; + return tryLoadModuleUsingPaths( + extensions, + moduleName, + baseDirectory, + paths, + pathPatterns, + loader, + /*onlyRecordFailures*/ false, + state, + ); } } -function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader, - state: ModuleResolutionState): Resolved | undefined { - +function tryLoadModuleUsingRootDirs( + extensions: Extensions, + moduleName: string, + containingDirectory: string, + loader: ResolutionKindSpecificLoader, + state: ModuleResolutionState, +): Resolved | undefined { if (!state.compilerOptions.rootDirs) { return undefined; } @@ -1571,12 +1979,17 @@ function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, if (!endsWith(normalizedRoot, directorySeparator)) { normalizedRoot += directorySeparator; } - const isLongestMatchingPrefix = - startsWith(candidate, normalizedRoot) && - (matchedNormalizedPrefix === undefined || matchedNormalizedPrefix.length < normalizedRoot.length); + const isLongestMatchingPrefix = startsWith(candidate, normalizedRoot) + && (matchedNormalizedPrefix === undefined || matchedNormalizedPrefix.length < normalizedRoot.length); if (state.traceEnabled) { - trace(state.host, Diagnostics.Checking_if_0_is_the_longest_matching_prefix_for_1_2, normalizedRoot, candidate, isLongestMatchingPrefix); + trace( + state.host, + Diagnostics.Checking_if_0_is_the_longest_matching_prefix_for_1_2, + normalizedRoot, + candidate, + isLongestMatchingPrefix, + ); } if (isLongestMatchingPrefix) { @@ -1592,9 +2005,20 @@ function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, // first - try to load from a initial location if (state.traceEnabled) { - trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, matchedNormalizedPrefix, candidate); + trace( + state.host, + Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, + suffix, + matchedNormalizedPrefix, + candidate, + ); } - const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(containingDirectory, state.host), state); + const resolvedFileName = loader( + extensions, + candidate, + !directoryProbablyExists(containingDirectory, state.host), + state, + ); if (resolvedFileName) { return resolvedFileName; } @@ -1610,10 +2034,21 @@ function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, } const candidate = combinePaths(normalizePath(rootDir), suffix); if (state.traceEnabled) { - trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, rootDir, candidate); + trace( + state.host, + Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, + suffix, + rootDir, + candidate, + ); } const baseDirectory = getDirectoryPath(candidate); - const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(baseDirectory, state.host), state); + const resolvedFileName = loader( + extensions, + candidate, + !directoryProbablyExists(baseDirectory, state.host), + state, + ); if (resolvedFileName) { return resolvedFileName; } @@ -1625,13 +2060,23 @@ function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, return undefined; } -function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined { +function tryLoadModuleUsingBaseUrl( + extensions: Extensions, + moduleName: string, + loader: ResolutionKindSpecificLoader, + state: ModuleResolutionState, +): Resolved | undefined { const { baseUrl } = state.compilerOptions; if (!baseUrl) { return undefined; } if (state.traceEnabled) { - trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName); + trace( + state.host, + Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, + baseUrl, + moduleName, + ); } const candidate = normalizePath(combinePaths(baseUrl, moduleName)); if (state.traceEnabled) { @@ -1650,7 +2095,11 @@ function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, l export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string { const { resolvedModule, failedLookupLocations } = tryResolveJSModuleWorker(moduleName, initialDir, host); if (!resolvedModule) { - throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations?.join(", ")}`); + throw new Error( + `Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${ + failedLookupLocations?.join(", ") + }`, + ); } return resolvedModule.resolvedFileName; } @@ -1678,9 +2127,15 @@ export enum NodeResolutionFeatures { EsmMode = 1 << 5, } -function node16ModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, - host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, - resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations { +function node16ModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + resolutionMode?: ResolutionMode, +): ResolvedModuleWithFailedLookupLocations { return nodeNextModuleNameResolverWorker( NodeResolutionFeatures.Node16Default, moduleName, @@ -1689,13 +2144,19 @@ function node16ModuleNameResolver(moduleName: string, containingFile: string, co host, cache, redirectedReference, - resolutionMode + resolutionMode, ); } -function nodeNextModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, - host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, - resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations { +function nodeNextModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + resolutionMode?: ResolutionMode, +): ResolvedModuleWithFailedLookupLocations { return nodeNextModuleNameResolverWorker( NodeResolutionFeatures.NodeNextDefault, moduleName, @@ -1704,23 +2165,47 @@ function nodeNextModuleNameResolver(moduleName: string, containingFile: string, host, cache, redirectedReference, - resolutionMode + resolutionMode, ); } -function nodeNextModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations { +function nodeNextModuleNameResolverWorker( + features: NodeResolutionFeatures, + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + resolutionMode?: ResolutionMode, +): ResolvedModuleWithFailedLookupLocations { const containingDirectory = getDirectoryPath(containingFile); // es module file or cjs-like input file, use a variant of the legacy cjs resolver that supports the selected modern features const esmMode = resolutionMode === ModuleKind.ESNext ? NodeResolutionFeatures.EsmMode : 0; - let extensions = compilerOptions.noDtsResolution ? Extensions.ImplementationFiles : Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration; + let extensions = compilerOptions.noDtsResolution ? Extensions.ImplementationFiles + : Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration; if (getResolveJsonModule(compilerOptions)) { extensions |= Extensions.Json; } - return nodeModuleNameResolverWorker(features | esmMode, moduleName, containingDirectory, compilerOptions, host, cache, extensions, /*isConfigLookup*/ false, redirectedReference); + return nodeModuleNameResolverWorker( + features | esmMode, + moduleName, + containingDirectory, + compilerOptions, + host, + cache, + extensions, + /*isConfigLookup*/ false, + redirectedReference, + ); } -function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { +function tryResolveJSModuleWorker( + moduleName: string, + initialDir: string, + host: ModuleResolutionHost, +): ResolvedModuleWithFailedLookupLocations { return nodeModuleNameResolverWorker( NodeResolutionFeatures.None, moduleName, @@ -1730,21 +2215,63 @@ function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: /*cache*/ undefined, Extensions.JavaScript, /*isConfigLookup*/ false, - /*redirectedReference*/ undefined); + /*redirectedReference*/ undefined, + ); } -export function bundlerModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations { +export function bundlerModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, +): ResolvedModuleWithFailedLookupLocations { const containingDirectory = getDirectoryPath(containingFile); - let extensions = compilerOptions.noDtsResolution ? Extensions.ImplementationFiles : Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration; + let extensions = compilerOptions.noDtsResolution ? Extensions.ImplementationFiles + : Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration; if (getResolveJsonModule(compilerOptions)) { extensions |= Extensions.Json; } - return nodeModuleNameResolverWorker(getNodeResolutionFeatures(compilerOptions), moduleName, containingDirectory, compilerOptions, host, cache, extensions, /*isConfigLookup*/ false, redirectedReference); + return nodeModuleNameResolverWorker( + getNodeResolutionFeatures(compilerOptions), + moduleName, + containingDirectory, + compilerOptions, + host, + cache, + extensions, + /*isConfigLookup*/ false, + redirectedReference, + ); } -export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; -/** @internal */ export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, lookupConfig?: boolean): ResolvedModuleWithFailedLookupLocations; // eslint-disable-line @typescript-eslint/unified-signatures -export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, isConfigLookup?: boolean): ResolvedModuleWithFailedLookupLocations { +export function nodeModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, +): ResolvedModuleWithFailedLookupLocations; +/** @internal */ export function nodeModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + lookupConfig?: boolean, +): ResolvedModuleWithFailedLookupLocations; // eslint-disable-line @typescript-eslint/unified-signatures +export function nodeModuleNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: ModuleResolutionCache, + redirectedReference?: ResolvedProjectReference, + isConfigLookup?: boolean, +): ResolvedModuleWithFailedLookupLocations { let extensions; if (isConfigLookup) { extensions = Extensions.Json; @@ -1758,15 +2285,49 @@ export function nodeModuleNameResolver(moduleName: string, containingFile: strin ? Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration | Extensions.Json : Extensions.TypeScript | Extensions.JavaScript | Extensions.Declaration; } - return nodeModuleNameResolverWorker(NodeResolutionFeatures.None, moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, extensions, !!isConfigLookup, redirectedReference); + return nodeModuleNameResolverWorker( + NodeResolutionFeatures.None, + moduleName, + getDirectoryPath(containingFile), + compilerOptions, + host, + cache, + extensions, + !!isConfigLookup, + redirectedReference, + ); } /** @internal */ -export function nodeNextJsonConfigResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { - return nodeModuleNameResolverWorker(NodeResolutionFeatures.NodeNextDefault, moduleName, getDirectoryPath(containingFile), { moduleResolution: ModuleResolutionKind.NodeNext }, host, /*cache*/ undefined, Extensions.Json, /*isConfigLookup*/ true, /*redirectedReference*/ undefined); +export function nodeNextJsonConfigResolver( + moduleName: string, + containingFile: string, + host: ModuleResolutionHost, +): ResolvedModuleWithFailedLookupLocations { + return nodeModuleNameResolverWorker( + NodeResolutionFeatures.NodeNextDefault, + moduleName, + getDirectoryPath(containingFile), + { moduleResolution: ModuleResolutionKind.NodeNext }, + host, + /*cache*/ undefined, + Extensions.Json, + /*isConfigLookup*/ true, + /*redirectedReference*/ undefined, + ); } -function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleName: string, containingDirectory: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache: ModuleResolutionCache | undefined, extensions: Extensions, isConfigLookup: boolean, redirectedReference: ResolvedProjectReference | undefined): ResolvedModuleWithFailedLookupLocations { +function nodeModuleNameResolverWorker( + features: NodeResolutionFeatures, + moduleName: string, + containingDirectory: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache: ModuleResolutionCache | undefined, + extensions: Extensions, + isConfigLookup: boolean, + redirectedReference: ResolvedProjectReference | undefined, +): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); const failedLookupLocations: string[] = []; @@ -1789,18 +2350,25 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa candidateIsFromPackageJsonField: false, }; - if (traceEnabled && moduleResolutionSupportsPackageJsonExportsAndImports(getEmitModuleResolutionKind(compilerOptions))) { - trace(host, Diagnostics.Resolving_in_0_mode_with_conditions_1, features & NodeResolutionFeatures.EsmMode ? "ESM" : "CJS", conditions.map(c => `'${c}'`).join(", ")); + if ( + traceEnabled + && moduleResolutionSupportsPackageJsonExportsAndImports(getEmitModuleResolutionKind(compilerOptions)) + ) { + trace( + host, + Diagnostics.Resolving_in_0_mode_with_conditions_1, + features & NodeResolutionFeatures.EsmMode ? "ESM" : "CJS", + conditions.map(c => `'${c}'`).join(", "), + ); } let result; if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node10) { const priorityExtensions = extensions & (Extensions.TypeScript | Extensions.Declaration); const secondaryExtensions = extensions & ~(Extensions.TypeScript | Extensions.Declaration); - result = - priorityExtensions && tryResolve(priorityExtensions, state) || - secondaryExtensions && tryResolve(secondaryExtensions, state) || - undefined; + result = priorityExtensions && tryResolve(priorityExtensions, state) + || secondaryExtensions && tryResolve(secondaryExtensions, state) + || undefined; } else { result = tryResolve(extensions, state); @@ -1809,7 +2377,8 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa // For non-relative names that resolved to JS but no types in modes that look up an "import" condition in package.json "exports", // try again with "exports" disabled to try to detect if this is likely a configuration error in a dependency's package.json. let legacyResult; - if (result?.value?.isExternalLibraryImport + if ( + result?.value?.isExternalLibraryImport && !isConfigLookup && extensions & (Extensions.TypeScript | Extensions.Declaration) && features & NodeResolutionFeatures.Exports @@ -1817,13 +2386,20 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa && !extensionIsOk(Extensions.TypeScript | Extensions.Declaration, result.value.resolved.extension) && conditions.indexOf("import") > -1 ) { - traceIfEnabled(state, Diagnostics.Resolution_of_non_relative_name_failed_trying_with_modern_Node_resolution_features_disabled_to_see_if_npm_library_needs_configuration_update); + traceIfEnabled( + state, + Diagnostics + .Resolution_of_non_relative_name_failed_trying_with_modern_Node_resolution_features_disabled_to_see_if_npm_library_needs_configuration_update, + ); const diagnosticState = { ...state, features: state.features & ~NodeResolutionFeatures.Exports, reportDiagnostic: noop, }; - const diagnosticResult = tryResolve(extensions & (Extensions.TypeScript | Extensions.Declaration), diagnosticState); + const diagnosticResult = tryResolve( + extensions & (Extensions.TypeScript | Extensions.Declaration), + diagnosticState, + ); if (diagnosticResult?.value?.isExternalLibraryImport) { legacyResult = diagnosticResult.value.resolved.path; } @@ -1840,9 +2416,25 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa legacyResult, ); - function tryResolve(extensions: Extensions, state: ModuleResolutionState): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> { - const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true); - const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, state); + function tryResolve( + extensions: Extensions, + state: ModuleResolutionState, + ): SearchResult<{ resolved: Resolved; isExternalLibraryImport: boolean; }> { + const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => + nodeLoadModuleByRelativeName( + extensions, + candidate, + onlyRecordFailures, + state, + /*considerPackageJson*/ true, + ); + const resolved = tryLoadModuleUsingOptionalResolutionSettings( + extensions, + moduleName, + containingDirectory, + loader, + state, + ); if (resolved) { return toSearchResult({ resolved, isExternalLibraryImport: pathContainsNodeModules(resolved.path) }); } @@ -1850,22 +2442,53 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa if (!isExternalModuleNameRelative(moduleName)) { let resolved: SearchResult | undefined; if (features & NodeResolutionFeatures.Imports && startsWith(moduleName, "#")) { - resolved = loadModuleFromImports(extensions, moduleName, containingDirectory, state, cache, redirectedReference); + resolved = loadModuleFromImports( + extensions, + moduleName, + containingDirectory, + state, + cache, + redirectedReference, + ); } if (!resolved && features & NodeResolutionFeatures.SelfName) { - resolved = loadModuleFromSelfNameReference(extensions, moduleName, containingDirectory, state, cache, redirectedReference); + resolved = loadModuleFromSelfNameReference( + extensions, + moduleName, + containingDirectory, + state, + cache, + redirectedReference, + ); } if (!resolved) { if (moduleName.indexOf(":") > -1) { if (traceEnabled) { - trace(host, Diagnostics.Skipping_module_0_that_looks_like_an_absolute_URI_target_file_types_Colon_1, moduleName, formatExtensions(extensions)); + trace( + host, + Diagnostics.Skipping_module_0_that_looks_like_an_absolute_URI_target_file_types_Colon_1, + moduleName, + formatExtensions(extensions), + ); } return undefined; } if (traceEnabled) { - trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_types_Colon_1, moduleName, formatExtensions(extensions)); + trace( + host, + Diagnostics.Loading_module_0_from_node_modules_folder_target_file_types_Colon_1, + moduleName, + formatExtensions(extensions), + ); } - resolved = loadModuleFromNearestNodeModulesDirectory(extensions, moduleName, containingDirectory, state, cache, redirectedReference); + resolved = loadModuleFromNearestNodeModulesDirectory( + extensions, + moduleName, + containingDirectory, + state, + cache, + redirectedReference, + ); } if (extensions & Extensions.Declaration) { resolved ??= resolveFromTypeRoot(moduleName, state); @@ -1875,12 +2498,17 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa } else { const { path: candidate, parts } = normalizePathForCJSResolution(containingDirectory, moduleName); - const resolved = nodeLoadModuleByRelativeName(extensions, candidate, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true); + const resolved = nodeLoadModuleByRelativeName( + extensions, + candidate, + /*onlyRecordFailures*/ false, + state, + /*considerPackageJson*/ true, + ); // Treat explicit "node_modules" import as an external library import. return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") }); } } - } // If you import from "." inside a containing directory "/foo", the result of `normalizePath` @@ -1892,7 +2520,8 @@ function normalizePathForCJSResolution(containingDirectory: string, moduleName: const combined = combinePaths(containingDirectory, moduleName); const parts = getPathComponents(combined); const lastPart = lastOrUndefined(parts); - const path = lastPart === "." || lastPart === ".." ? ensureTrailingDirectorySeparator(normalizePath(combined)) : normalizePath(combined); + const path = lastPart === "." || lastPart === ".." ? ensureTrailingDirectorySeparator(normalizePath(combined)) + : normalizePath(combined); return { path, parts }; } @@ -1909,16 +2538,31 @@ function realPath(path: string, host: ModuleResolutionHost, traceEnabled: boolea return real; } -function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined { +function nodeLoadModuleByRelativeName( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + considerPackageJson: boolean, +): Resolved | undefined { if (state.traceEnabled) { - trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_types_Colon_1, candidate, formatExtensions(extensions)); + trace( + state.host, + Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_types_Colon_1, + candidate, + formatExtensions(extensions), + ); } if (!hasTrailingDirectorySeparator(candidate)) { if (!onlyRecordFailures) { const parentOfCandidate = getDirectoryPath(candidate); if (!directoryProbablyExists(parentOfCandidate, state.host)) { if (state.traceEnabled) { - trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, parentOfCandidate); + trace( + state.host, + Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, + parentOfCandidate, + ); } onlyRecordFailures = true; } @@ -1926,7 +2570,8 @@ function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, const resolvedFromFile = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state); if (resolvedFromFile) { const packageDirectory = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile.path) : undefined; - const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined; + const packageInfo = packageDirectory + ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined; return withPackageId(packageInfo, resolvedFromFile); } } @@ -1982,12 +2627,21 @@ export function parseNodeModuleFromPath(resolved: string, isFolder?: boolean): s return path.slice(0, indexAfterPackageName); } -function moveToNextDirectorySeparatorIfAvailable(path: string, prevSeparatorIndex: number, isFolder: boolean | undefined): number { +function moveToNextDirectorySeparatorIfAvailable( + path: string, + prevSeparatorIndex: number, + isFolder: boolean | undefined, +): number { const nextSeparatorIndex = path.indexOf(directorySeparator, prevSeparatorIndex + 1); return nextSeparatorIndex === -1 ? isFolder ? path.length : prevSeparatorIndex : nextSeparatorIndex; } -function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined { +function loadModuleFromFileNoPackageId( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +): Resolved | undefined { return noPackageId(loadModuleFromFile(extensions, candidate, onlyRecordFailures, state)); } @@ -1995,9 +2649,19 @@ function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string * @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary * in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations. */ -function loadModuleFromFile(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { +function loadModuleFromFile( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +): PathAndExtension | undefined { // ./foo.js -> ./foo.ts - const resolvedByReplacingExtension = loadModuleFromFileNoImplicitExtensions(extensions, candidate, onlyRecordFailures, state); + const resolvedByReplacingExtension = loadModuleFromFileNoImplicitExtensions( + extensions, + candidate, + onlyRecordFailures, + state, + ); if (resolvedByReplacingExtension) { return resolvedByReplacingExtension; } @@ -2012,7 +2676,12 @@ function loadModuleFromFile(extensions: Extensions, candidate: string, onlyRecor } } -function loadModuleFromFileNoImplicitExtensions(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { +function loadModuleFromFileNoImplicitExtensions( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +): PathAndExtension | undefined { const filename = getBaseFileName(candidate); if (filename.indexOf(".") === -1) { return undefined; // extensionless import, no lookups performed, since we don't support extensionless files @@ -2036,24 +2705,42 @@ function loadModuleFromFileNoImplicitExtensions(extensions: Extensions, candidat * candidate to end with a TS extension (but will also try substituting a JS extension for a TS extension). */ -function loadFileNameFromPackageJsonField(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { - if (extensions & Extensions.TypeScript && fileExtensionIsOneOf(candidate, supportedTSImplementationExtensions) || - extensions & Extensions.Declaration && fileExtensionIsOneOf(candidate, supportedDeclarationExtensions) +function loadFileNameFromPackageJsonField( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +): PathAndExtension | undefined { + if ( + extensions & Extensions.TypeScript && fileExtensionIsOneOf(candidate, supportedTSImplementationExtensions) + || extensions & Extensions.Declaration && fileExtensionIsOneOf(candidate, supportedDeclarationExtensions) ) { const result = tryFile(candidate, onlyRecordFailures, state); - return result !== undefined ? { path: candidate, ext: tryExtractTSExtension(candidate) as Extension, resolvedUsingTsExtension: undefined } : undefined; + return result !== undefined + ? { + path: candidate, + ext: tryExtractTSExtension(candidate) as Extension, + resolvedUsingTsExtension: undefined, + } : undefined; } if (state.isConfigLookup && extensions === Extensions.Json && fileExtensionIs(candidate, Extension.Json)) { const result = tryFile(candidate, onlyRecordFailures, state); - return result !== undefined ? { path: candidate, ext: Extension.Json, resolvedUsingTsExtension: undefined } : undefined; + return result !== undefined ? { path: candidate, ext: Extension.Json, resolvedUsingTsExtension: undefined } + : undefined; } return loadModuleFromFileNoImplicitExtensions(extensions, candidate, onlyRecordFailures, state); } /** Try to return an existing file that adds one of the `extensions` to `candidate`. */ -function tryAddingExtensions(candidate: string, extensions: Extensions, originalExtension: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { +function tryAddingExtensions( + candidate: string, + extensions: Extensions, + originalExtension: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +): PathAndExtension | undefined { if (!onlyRecordFailures) { // check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing const directory = getDirectoryPath(candidate); @@ -2066,15 +2753,31 @@ function tryAddingExtensions(candidate: string, extensions: Extensions, original case Extension.Mjs: case Extension.Mts: case Extension.Dmts: - return extensions & Extensions.TypeScript && tryExtension(Extension.Mts, originalExtension === Extension.Mts || originalExtension === Extension.Dmts) - || extensions & Extensions.Declaration && tryExtension(Extension.Dmts, originalExtension === Extension.Mts || originalExtension === Extension.Dmts) + return extensions & Extensions.TypeScript + && tryExtension( + Extension.Mts, + originalExtension === Extension.Mts || originalExtension === Extension.Dmts, + ) + || extensions & Extensions.Declaration + && tryExtension( + Extension.Dmts, + originalExtension === Extension.Mts || originalExtension === Extension.Dmts, + ) || extensions & Extensions.JavaScript && tryExtension(Extension.Mjs) || undefined; case Extension.Cjs: case Extension.Cts: case Extension.Dcts: - return extensions & Extensions.TypeScript && tryExtension(Extension.Cts, originalExtension === Extension.Cts || originalExtension === Extension.Dcts) - || extensions & Extensions.Declaration && tryExtension(Extension.Dcts, originalExtension === Extension.Cts || originalExtension === Extension.Dcts) + return extensions & Extensions.TypeScript + && tryExtension( + Extension.Cts, + originalExtension === Extension.Cts || originalExtension === Extension.Dcts, + ) + || extensions & Extensions.Declaration + && tryExtension( + Extension.Dcts, + originalExtension === Extension.Cts || originalExtension === Extension.Dcts, + ) || extensions & Extensions.JavaScript && tryExtension(Extension.Cjs) || undefined; case Extension.Json: @@ -2086,28 +2789,48 @@ function tryAddingExtensions(candidate: string, extensions: Extensions, original // basically idendical to the ts/js case below, but prefers matching tsx and jsx files exactly before falling back to the ts or js file path // (historically, we disallow having both a a.ts and a.tsx file in the same compilation, since their outputs clash) // TODO: We should probably error if `"./a.tsx"` resolved to `"./a.ts"`, right? - return extensions & Extensions.TypeScript && (tryExtension(Extension.Tsx, originalExtension === Extension.Tsx) || tryExtension(Extension.Ts, originalExtension === Extension.Tsx)) - || extensions & Extensions.Declaration && tryExtension(Extension.Dts, originalExtension === Extension.Tsx) + return extensions & Extensions.TypeScript + && (tryExtension(Extension.Tsx, originalExtension === Extension.Tsx) + || tryExtension(Extension.Ts, originalExtension === Extension.Tsx)) + || extensions & Extensions.Declaration + && tryExtension(Extension.Dts, originalExtension === Extension.Tsx) || extensions & Extensions.JavaScript && (tryExtension(Extension.Jsx) || tryExtension(Extension.Js)) || undefined; case Extension.Ts: case Extension.Dts: case Extension.Js: case "": - return extensions & Extensions.TypeScript && (tryExtension(Extension.Ts, originalExtension === Extension.Ts || originalExtension === Extension.Dts) || tryExtension(Extension.Tsx, originalExtension === Extension.Ts || originalExtension === Extension.Dts)) - || extensions & Extensions.Declaration && tryExtension(Extension.Dts, originalExtension === Extension.Ts || originalExtension === Extension.Dts) + return extensions & Extensions.TypeScript + && (tryExtension( + Extension.Ts, + originalExtension === Extension.Ts || originalExtension === Extension.Dts, + ) + || tryExtension( + Extension.Tsx, + originalExtension === Extension.Ts || originalExtension === Extension.Dts, + )) + || extensions & Extensions.Declaration + && tryExtension( + Extension.Dts, + originalExtension === Extension.Ts || originalExtension === Extension.Dts, + ) || extensions & Extensions.JavaScript && (tryExtension(Extension.Js) || tryExtension(Extension.Jsx)) || state.isConfigLookup && tryExtension(Extension.Json) || undefined; default: - return extensions & Extensions.Declaration && !isDeclarationFileName(candidate + originalExtension) && tryExtension(`.d${originalExtension}.ts`) + return extensions & Extensions.Declaration && !isDeclarationFileName(candidate + originalExtension) + && tryExtension(`.d${originalExtension}.ts`) || undefined; - } function tryExtension(ext: string, resolvedUsingTsExtension?: boolean): PathAndExtension | undefined { const path = tryFile(candidate + ext, onlyRecordFailures, state); - return path === undefined ? undefined : { path, ext, resolvedUsingTsExtension: !state.candidateIsFromPackageJsonField && resolvedUsingTsExtension }; + return path === undefined ? undefined + : { + path, + ext, + resolvedUsingTsExtension: !state.candidateIsFromPackageJsonField && resolvedUsingTsExtension, + }; } } @@ -2119,10 +2842,17 @@ function tryFile(fileName: string, onlyRecordFailures: boolean, state: ModuleRes const ext = tryGetExtensionFromPath(fileName) ?? ""; const fileNameNoExtension = ext ? removeExtension(fileName, ext) : fileName; - return forEach(state.compilerOptions.moduleSuffixes, suffix => tryFileLookup(fileNameNoExtension + suffix + ext, onlyRecordFailures, state)); + return forEach( + state.compilerOptions.moduleSuffixes, + suffix => tryFileLookup(fileNameNoExtension + suffix + ext, onlyRecordFailures, state), + ); } -function tryFileLookup(fileName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined { +function tryFileLookup( + fileName: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +): string | undefined { if (!onlyRecordFailures) { if (state.host.fileExists(fileName)) { if (state.traceEnabled) { @@ -2140,11 +2870,27 @@ function tryFileLookup(fileName: string, onlyRecordFailures: boolean, state: Mod return undefined; } -function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) { +function loadNodeModuleFromDirectory( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + considerPackageJson = true, +) { const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, onlyRecordFailures, state) : undefined; const packageJsonContent = packageInfo && packageInfo.contents.packageJsonContent; const versionPaths = packageInfo && getVersionPathsOfPackageJsonInfo(packageInfo, state); - return withPackageId(packageInfo, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths)); + return withPackageId( + packageInfo, + loadNodeModuleFromDirectoryWorker( + extensions, + candidate, + onlyRecordFailures, + state, + packageJsonContent, + versionPaths, + ), + ); } /** @internal */ @@ -2178,21 +2924,28 @@ export function getEntrypointsFromPackageJsonInfo( /*onlyRecordFailures*/ false, loadPackageJsonMainState, packageJsonInfo.contents.packageJsonContent, - getVersionPathsOfPackageJsonInfo(packageJsonInfo, loadPackageJsonMainState)); + getVersionPathsOfPackageJsonInfo(packageJsonInfo, loadPackageJsonMainState), + ); entrypoints = append(entrypoints, mainResolution?.path); if (features & NodeResolutionFeatures.Exports && packageJsonInfo.contents.packageJsonContent.exports) { const conditionSets = deduplicate( [getConditions(options, /*esmMode*/ true), getConditions(options, /*esmMode*/ false)], - arrayIsEqualTo + arrayIsEqualTo, ); for (const conditions of conditionSets) { - const loadPackageJsonExportsState = { ...loadPackageJsonMainState, failedLookupLocations: [], conditions, host }; + const loadPackageJsonExportsState = { + ...loadPackageJsonMainState, + failedLookupLocations: [], + conditions, + host, + }; const exportResolutions = loadEntrypointsFromExportMap( packageJsonInfo, packageJsonInfo.contents.packageJsonContent.exports, loadPackageJsonExportsState, - extensions); + extensions, + ); if (exportResolutions) { for (const resolution of exportResolutions) { entrypoints = appendIfUnique(entrypoints, resolution.path); @@ -2207,7 +2960,7 @@ export function getEntrypointsFromPackageJsonInfo( function loadEntrypointsFromExportMap( scope: PackageJsonInfo, exports: object, - state: ModuleResolutionState & { host: GetPackageJsonEntrypointsHost }, + state: ModuleResolutionState & { host: GetPackageJsonEntrypointsHost; }, extensions: Extensions, ): PathAndExtension[] | undefined { let entrypoints: PathAndExtension[] | undefined; @@ -2238,23 +2991,31 @@ function loadEntrypointsFromExportMap( scope.packageDirectory, extensionsToExtensionsArray(extensions), /*excludes*/ undefined, - [changeAnyExtension(target.replace("*", "**/*"), getDeclarationEmitExtensionForPath(target))] + [changeAnyExtension(target.replace("*", "**/*"), getDeclarationEmitExtensionForPath(target))], ).forEach(entry => { entrypoints = appendIfUnique(entrypoints, { path: entry, ext: getAnyExtensionFromPath(entry), - resolvedUsingTsExtension: undefined + resolvedUsingTsExtension: undefined, }); }); } else { const partsAfterFirst = getPathComponents(target).slice(2); - if (partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 || partsAfterFirst.indexOf("node_modules") >= 0) { + if ( + partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 + || partsAfterFirst.indexOf("node_modules") >= 0 + ) { return false; } const resolvedTarget = combinePaths(scope.packageDirectory, target); const finalPath = getNormalizedAbsolutePath(resolvedTarget, state.host.getCurrentDirectory?.()); - const result = loadFileNameFromPackageJsonField(extensions, finalPath, /*onlyRecordFailures*/ false, state); + const result = loadFileNameFromPackageJsonField( + extensions, + finalPath, + /*onlyRecordFailures*/ false, + state, + ); if (result) { entrypoints = appendIfUnique(entrypoints, result, (a, b) => a.path === b.path); return true; @@ -2272,7 +3033,10 @@ function loadEntrypointsFromExportMap( // eslint-disable-next-line no-null/no-null else if (typeof target === "object" && target !== null) { return forEach(getOwnKeys(target as MapLike), key => { - if (key === "default" || contains(state.conditions, key) || isApplicableVersionedTypesKey(state.conditions, key)) { + if ( + key === "default" || contains(state.conditions, key) + || isApplicableVersionedTypesKey(state.conditions, key) + ) { loadEntrypointsFromTargetExports((target as MapLike)[key]); return true; } @@ -2282,7 +3046,11 @@ function loadEntrypointsFromExportMap( } /** @internal */ -export function getTemporaryModuleResolutionState(packageJsonInfoCache: PackageJsonInfoCache | undefined, host: ModuleResolutionHost, options: CompilerOptions): ModuleResolutionState { +export function getTemporaryModuleResolutionState( + packageJsonInfoCache: PackageJsonInfoCache | undefined, + host: ModuleResolutionHost, + options: CompilerOptions, +): ModuleResolutionState { return { host, compilerOptions: options, @@ -2331,15 +3099,23 @@ export function getPackageScopeForPath(fileName: string, state: ModuleResolution return undefined; } -function getVersionPathsOfPackageJsonInfo(packageJsonInfo: PackageJsonInfo, state: ModuleResolutionState): VersionPaths | undefined { +function getVersionPathsOfPackageJsonInfo( + packageJsonInfo: PackageJsonInfo, + state: ModuleResolutionState, +): VersionPaths | undefined { if (packageJsonInfo.contents.versionPaths === undefined) { - packageJsonInfo.contents.versionPaths = readPackageJsonTypesVersionPaths(packageJsonInfo.contents.packageJsonContent, state) || false; + packageJsonInfo.contents.versionPaths = + readPackageJsonTypesVersionPaths(packageJsonInfo.contents.packageJsonContent, state) || false; } return packageJsonInfo.contents.versionPaths || undefined; } /** @internal */ -export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined { +export function getPackageJsonInfo( + packageDirectory: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +): PackageJsonInfo | undefined { const { host, traceEnabled } = state; const packageJsonPath = combinePaths(packageDirectory, "package.json"); if (onlyRecordFailures) { @@ -2350,14 +3126,18 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: const existing = state.packageJsonInfoCache?.getPackageJsonInfo(packageJsonPath); if (existing !== undefined) { if (typeof existing !== "boolean") { - if (traceEnabled) trace(host, Diagnostics.File_0_exists_according_to_earlier_cached_lookups, packageJsonPath); + if (traceEnabled) { + trace(host, Diagnostics.File_0_exists_according_to_earlier_cached_lookups, packageJsonPath); + } state.affectingLocations?.push(packageJsonPath); - return existing.packageDirectory === packageDirectory ? - existing : - { packageDirectory, contents: existing.contents }; + return existing.packageDirectory === packageDirectory + ? existing + : { packageDirectory, contents: existing.contents }; } else { - if (existing && traceEnabled) trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath); + if (existing && traceEnabled) { + trace(host, Diagnostics.File_0_does_not_exist_according_to_earlier_cached_lookups, packageJsonPath); + } state.failedLookupLocations?.push(packageJsonPath); return undefined; } @@ -2368,7 +3148,10 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: if (traceEnabled) { trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath); } - const result: PackageJsonInfo = { packageDirectory, contents: { packageJsonContent, versionPaths: undefined, resolvedEntrypoints: undefined } }; + const result: PackageJsonInfo = { + packageDirectory, + contents: { packageJsonContent, versionPaths: undefined, resolvedEntrypoints: undefined }, + }; state.packageJsonInfoCache?.setPackageJsonInfo(packageJsonPath, result); state.affectingLocations?.push(packageJsonPath); return result; @@ -2383,7 +3166,14 @@ export function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: } } -function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, jsonContent: PackageJsonPathFields | undefined, versionPaths: VersionPaths | undefined): PathAndExtension | undefined { +function loadNodeModuleFromDirectoryWorker( + extensions: Extensions, + candidate: string, + onlyRecordFailures: boolean, + state: ModuleResolutionState, + jsonContent: PackageJsonPathFields | undefined, + versionPaths: VersionPaths | undefined, +): PathAndExtension | undefined { let packageFile: string | undefined; if (jsonContent) { if (state.isConfigLookup) { @@ -2391,9 +3181,10 @@ function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: st } else { packageFile = - extensions & Extensions.Declaration && readPackageJsonTypesFields(jsonContent, candidate, state) || - extensions & (Extensions.ImplementationFiles | Extensions.Declaration) && readPackageJsonMainField(jsonContent, candidate, state) || - undefined; + extensions & Extensions.Declaration && readPackageJsonTypesFields(jsonContent, candidate, state) + || extensions & (Extensions.ImplementationFiles | Extensions.Declaration) + && readPackageJsonMainField(jsonContent, candidate, state) + || undefined; } } @@ -2410,7 +3201,8 @@ function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: st } // Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types" - const expandedExtensions = extensions === Extensions.Declaration ? Extensions.TypeScript | Extensions.Declaration : extensions; + const expandedExtensions = extensions === Extensions.Declaration + ? Extensions.TypeScript | Extensions.Declaration : extensions; // Don't do package.json lookup recursively, because Node.js' package lookup doesn't. // Disable `EsmMode` for the resolution of the package path for cjs-mode packages (so the `main` field can omit extensions) @@ -2422,29 +3214,53 @@ function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: st if (jsonContent?.type !== "module") { state.features &= ~NodeResolutionFeatures.EsmMode; } - const result = nodeLoadModuleByRelativeName(expandedExtensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ false); + const result = nodeLoadModuleByRelativeName( + expandedExtensions, + candidate, + onlyRecordFailures, + state, + /*considerPackageJson*/ false, + ); state.features = features; state.candidateIsFromPackageJsonField = candidateIsFromPackageJsonField; return result; }; - const onlyRecordFailuresForPackageFile = packageFile ? !directoryProbablyExists(getDirectoryPath(packageFile), state.host) : undefined; + const onlyRecordFailuresForPackageFile = packageFile + ? !directoryProbablyExists(getDirectoryPath(packageFile), state.host) : undefined; const onlyRecordFailuresForIndex = onlyRecordFailures || !directoryProbablyExists(candidate, state.host); const indexPath = combinePaths(candidate, state.isConfigLookup ? "tsconfig" : "index"); if (versionPaths && (!packageFile || containsPath(candidate, packageFile))) { const moduleName = getRelativePathFromDirectory(candidate, packageFile || indexPath, /*ignoreCase*/ false); if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, moduleName); + trace( + state.host, + Diagnostics + .package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, + versionPaths.version, + version, + moduleName, + ); } - const result = tryLoadModuleUsingPaths(extensions, moduleName, candidate, versionPaths.paths, /*pathPatterns*/ undefined, loader, onlyRecordFailuresForPackageFile || onlyRecordFailuresForIndex, state); + const result = tryLoadModuleUsingPaths( + extensions, + moduleName, + candidate, + versionPaths.paths, + /*pathPatterns*/ undefined, + loader, + onlyRecordFailuresForPackageFile || onlyRecordFailuresForIndex, + state, + ); if (result) { return removeIgnoredPackageId(result.value); } } // It won't have a `packageId` set, because we disabled `considerPackageJson`. - const packageFileResult = packageFile && removeIgnoredPackageId(loader(extensions, packageFile, onlyRecordFailuresForPackageFile!, state)); + const packageFileResult = packageFile + && removeIgnoredPackageId(loader(extensions, packageFile, onlyRecordFailuresForPackageFile!, state)); if (packageFileResult) return packageFileResult; // esm mode resolutions don't do package `index` lookups @@ -2454,27 +3270,37 @@ function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: st } /** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */ -function resolvedIfExtensionMatches(extensions: Extensions, path: string, resolvedUsingTsExtension?: boolean): PathAndExtension | undefined { +function resolvedIfExtensionMatches( + extensions: Extensions, + path: string, + resolvedUsingTsExtension?: boolean, +): PathAndExtension | undefined { const ext = tryGetExtensionFromPath(path); return ext !== undefined && extensionIsOk(extensions, ext) ? { path, ext, resolvedUsingTsExtension } : undefined; } /** True if `extension` is one of the supported `extensions`. */ function extensionIsOk(extensions: Extensions, extension: string): boolean { - return extensions & Extensions.JavaScript && (extension === Extension.Js || extension === Extension.Jsx || extension === Extension.Mjs || extension === Extension.Cjs) - || extensions & Extensions.TypeScript && (extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts || extension === Extension.Cts) - || extensions & Extensions.Declaration && (extension === Extension.Dts || extension === Extension.Dmts || extension === Extension.Dcts) + return extensions & Extensions.JavaScript + && (extension === Extension.Js || extension === Extension.Jsx || extension === Extension.Mjs + || extension === Extension.Cjs) + || extensions & Extensions.TypeScript + && (extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Mts + || extension === Extension.Cts) + || extensions & Extensions.Declaration + && (extension === Extension.Dts || extension === Extension.Dmts || extension === Extension.Dcts) || extensions & Extensions.Json && extension === Extension.Json || false; } /** @internal */ -export function parsePackageName(moduleName: string): { packageName: string, rest: string } { +export function parsePackageName(moduleName: string): { packageName: string; rest: string; } { let idx = moduleName.indexOf(directorySeparator); if (moduleName[0] === "@") { idx = moduleName.indexOf(directorySeparator, idx + 1); } - return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) }; + return idx === -1 ? { packageName: moduleName, rest: "" } + : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) }; } /** @internal */ @@ -2486,8 +3312,18 @@ function noKeyStartsWithDot(obj: MapLike) { return !some(getOwnKeys(obj), k => startsWith(k, ".")); } -function loadModuleFromSelfNameReference(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { - const directoryPath = getNormalizedAbsolutePath(combinePaths(directory, "dummy"), state.host.getCurrentDirectory?.()); +function loadModuleFromSelfNameReference( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, +): SearchResult { + const directoryPath = getNormalizedAbsolutePath( + combinePaths(directory, "dummy"), + state.host.getCurrentDirectory?.(), + ); const scope = getPackageScopeForPath(directoryPath, state); if (!scope || !scope.contents.packageJsonContent.exports) { return undefined; @@ -2524,55 +3360,108 @@ function loadModuleFromSelfNameReference(extensions: Extensions, moduleName: str || loadModuleFromExports(scope, secondaryExtensions, subpath, state, cache, redirectedReference); } -function loadModuleFromExports(scope: PackageJsonInfo, extensions: Extensions, subpath: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { +function loadModuleFromExports( + scope: PackageJsonInfo, + extensions: Extensions, + subpath: string, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, +): SearchResult { if (!scope.contents.packageJsonContent.exports) { return undefined; } if (subpath === ".") { let mainExport; - if (typeof scope.contents.packageJsonContent.exports === "string" || Array.isArray(scope.contents.packageJsonContent.exports) || (typeof scope.contents.packageJsonContent.exports === "object" && noKeyStartsWithDot(scope.contents.packageJsonContent.exports as MapLike))) { + if ( + typeof scope.contents.packageJsonContent.exports === "string" + || Array.isArray(scope.contents.packageJsonContent.exports) + || (typeof scope.contents.packageJsonContent.exports === "object" + && noKeyStartsWithDot(scope.contents.packageJsonContent.exports as MapLike)) + ) { mainExport = scope.contents.packageJsonContent.exports; } else if (hasProperty(scope.contents.packageJsonContent.exports as MapLike, ".")) { mainExport = (scope.contents.packageJsonContent.exports as MapLike)["."]; } if (mainExport) { - const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport(extensions, state, cache, redirectedReference, subpath, scope, /*isImports*/ false); + const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport( + extensions, + state, + cache, + redirectedReference, + subpath, + scope, + /*isImports*/ false, + ); return loadModuleFromTargetImportOrExport(mainExport, "", /*pattern*/ false, "."); } } else if (allKeysStartWithDot(scope.contents.packageJsonContent.exports as MapLike)) { if (typeof scope.contents.packageJsonContent.exports !== "object") { if (state.traceEnabled) { - trace(state.host, Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, subpath, scope.packageDirectory); + trace( + state.host, + Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, + subpath, + scope.packageDirectory, + ); } return toSearchResult(/*value*/ undefined); } - const result = loadModuleFromImportsOrExports(extensions, state, cache, redirectedReference, subpath, scope.contents.packageJsonContent.exports, scope, /*isImports*/ false); + const result = loadModuleFromImportsOrExports( + extensions, + state, + cache, + redirectedReference, + subpath, + scope.contents.packageJsonContent.exports, + scope, + /*isImports*/ false, + ); if (result) { return result; } } if (state.traceEnabled) { - trace(state.host, Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, subpath, scope.packageDirectory); + trace( + state.host, + Diagnostics.Export_specifier_0_does_not_exist_in_package_json_scope_at_path_1, + subpath, + scope.packageDirectory, + ); } return toSearchResult(/*value*/ undefined); } -function loadModuleFromImports(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { +function loadModuleFromImports( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, +): SearchResult { if (moduleName === "#" || startsWith(moduleName, "#/")) { if (state.traceEnabled) { trace(state.host, Diagnostics.Invalid_import_specifier_0_has_no_possible_resolutions, moduleName); } return toSearchResult(/*value*/ undefined); } - const directoryPath = getNormalizedAbsolutePath(combinePaths(directory, "dummy"), state.host.getCurrentDirectory?.()); + const directoryPath = getNormalizedAbsolutePath( + combinePaths(directory, "dummy"), + state.host.getCurrentDirectory?.(), + ); const scope = getPackageScopeForPath(directoryPath, state); if (!scope) { if (state.traceEnabled) { - trace(state.host, Diagnostics.Directory_0_has_no_containing_package_json_scope_Imports_will_not_resolve, directoryPath); + trace( + state.host, + Diagnostics.Directory_0_has_no_containing_package_json_scope_Imports_will_not_resolve, + directoryPath, + ); } return toSearchResult(/*value*/ undefined); } @@ -2583,13 +3472,27 @@ function loadModuleFromImports(extensions: Extensions, moduleName: string, direc return toSearchResult(/*value*/ undefined); } - const result = loadModuleFromImportsOrExports(extensions, state, cache, redirectedReference, moduleName, scope.contents.packageJsonContent.imports, scope, /*isImports*/ true); + const result = loadModuleFromImportsOrExports( + extensions, + state, + cache, + redirectedReference, + moduleName, + scope.contents.packageJsonContent.imports, + scope, + /*isImports*/ true, + ); if (result) { return result; } if (state.traceEnabled) { - trace(state.host, Diagnostics.Import_specifier_0_does_not_exist_in_package_json_scope_at_path_1, moduleName, scope.packageDirectory); + trace( + state.host, + Diagnostics.Import_specifier_0_does_not_exist_in_package_json_scope_at_path_1, + moduleName, + scope.packageDirectory, + ); } return toSearchResult(/*value*/ undefined); } @@ -2613,28 +3516,60 @@ export function comparePatternKeys(a: string, b: string) { return 0; } -function loadModuleFromImportsOrExports(extensions: Extensions, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined, moduleName: string, lookupTable: object, scope: PackageJsonInfo, isImports: boolean): SearchResult | undefined { - const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport(extensions, state, cache, redirectedReference, moduleName, scope, isImports); +function loadModuleFromImportsOrExports( + extensions: Extensions, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + moduleName: string, + lookupTable: object, + scope: PackageJsonInfo, + isImports: boolean, +): SearchResult | undefined { + const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport( + extensions, + state, + cache, + redirectedReference, + moduleName, + scope, + isImports, + ); - if (!endsWith(moduleName, directorySeparator) && moduleName.indexOf("*") === -1 && hasProperty(lookupTable, moduleName)) { - const target = (lookupTable as { [idx: string]: unknown })[moduleName]; + if ( + !endsWith(moduleName, directorySeparator) && moduleName.indexOf("*") === -1 + && hasProperty(lookupTable, moduleName) + ) { + const target = (lookupTable as { [idx: string]: unknown; })[moduleName]; return loadModuleFromTargetImportOrExport(target, /*subpath*/ "", /*pattern*/ false, moduleName); } - const expandingKeys = sort(filter(getOwnKeys(lookupTable as MapLike), k => k.indexOf("*") !== -1 || endsWith(k, "/")), comparePatternKeys); + const expandingKeys = sort( + filter(getOwnKeys(lookupTable as MapLike), k => k.indexOf("*") !== -1 || endsWith(k, "/")), + comparePatternKeys, + ); for (const potentialTarget of expandingKeys) { - if (state.features & NodeResolutionFeatures.ExportsPatternTrailers && matchesPatternWithTrailer(potentialTarget, moduleName)) { - const target = (lookupTable as { [idx: string]: unknown })[potentialTarget]; + if ( + state.features & NodeResolutionFeatures.ExportsPatternTrailers + && matchesPatternWithTrailer(potentialTarget, moduleName) + ) { + const target = (lookupTable as { [idx: string]: unknown; })[potentialTarget]; const starPos = potentialTarget.indexOf("*"); - const subpath = moduleName.substring(potentialTarget.substring(0, starPos).length, moduleName.length - (potentialTarget.length - 1 - starPos)); + const subpath = moduleName.substring( + potentialTarget.substring(0, starPos).length, + moduleName.length - (potentialTarget.length - 1 - starPos), + ); return loadModuleFromTargetImportOrExport(target, subpath, /*pattern*/ true, potentialTarget); } - else if (endsWith(potentialTarget, "*") && startsWith(moduleName, potentialTarget.substring(0, potentialTarget.length - 1))) { - const target = (lookupTable as { [idx: string]: unknown })[potentialTarget]; + else if ( + endsWith(potentialTarget, "*") + && startsWith(moduleName, potentialTarget.substring(0, potentialTarget.length - 1)) + ) { + const target = (lookupTable as { [idx: string]: unknown; })[potentialTarget]; const subpath = moduleName.substring(potentialTarget.length - 1); return loadModuleFromTargetImportOrExport(target, subpath, /*pattern*/ true, potentialTarget); } else if (startsWith(moduleName, potentialTarget)) { - const target = (lookupTable as { [idx: string]: unknown })[potentialTarget]; + const target = (lookupTable as { [idx: string]: unknown; })[potentialTarget]; const subpath = moduleName.substring(potentialTarget.length); return loadModuleFromTargetImportOrExport(target, subpath, /*pattern*/ false, potentialTarget); } @@ -2651,13 +3586,31 @@ function loadModuleFromImportsOrExports(extensions: Extensions, state: ModuleRes /** * Gets the self-recursive function specialized to retrieving the targeted import/export element for the given resolution configuration */ -function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined, moduleName: string, scope: PackageJsonInfo, isImports: boolean) { +function getLoadModuleFromTargetImportOrExport( + extensions: Extensions, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, + moduleName: string, + scope: PackageJsonInfo, + isImports: boolean, +) { return loadModuleFromTargetImportOrExport; - function loadModuleFromTargetImportOrExport(target: unknown, subpath: string, pattern: boolean, key: string): SearchResult | undefined { + function loadModuleFromTargetImportOrExport( + target: unknown, + subpath: string, + pattern: boolean, + key: string, + ): SearchResult | undefined { if (typeof target === "string") { if (!pattern && subpath.length > 0 && !endsWith(target, "/")) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } @@ -2665,26 +3618,56 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo if (isImports && !startsWith(target, "../") && !startsWith(target, "/") && !isRootedDiskPath(target)) { const combinedLookup = pattern ? target.replace(/\*/g, subpath) : target + subpath; traceIfEnabled(state, Diagnostics.Using_0_subpath_1_with_target_2, "imports", key, combinedLookup); - traceIfEnabled(state, Diagnostics.Resolving_module_0_from_1, combinedLookup, scope.packageDirectory + "/"); - const result = nodeModuleNameResolverWorker(state.features, combinedLookup, scope.packageDirectory + "/", state.compilerOptions, state.host, cache, extensions, /*isConfigLookup*/ false, redirectedReference); - return toSearchResult(result.resolvedModule ? { - path: result.resolvedModule.resolvedFileName, - extension: result.resolvedModule.extension, - packageId: result.resolvedModule.packageId, - originalPath: result.resolvedModule.originalPath, - resolvedUsingTsExtension: result.resolvedModule.resolvedUsingTsExtension - } : undefined); + traceIfEnabled( + state, + Diagnostics.Resolving_module_0_from_1, + combinedLookup, + scope.packageDirectory + "/", + ); + const result = nodeModuleNameResolverWorker( + state.features, + combinedLookup, + scope.packageDirectory + "/", + state.compilerOptions, + state.host, + cache, + extensions, + /*isConfigLookup*/ false, + redirectedReference, + ); + return toSearchResult( + result.resolvedModule ? { + path: result.resolvedModule.resolvedFileName, + extension: result.resolvedModule.extension, + packageId: result.resolvedModule.packageId, + originalPath: result.resolvedModule.originalPath, + resolvedUsingTsExtension: result.resolvedModule.resolvedUsingTsExtension, + } : undefined, + ); } if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } const parts = pathIsRelative(target) ? getPathComponents(target).slice(1) : getPathComponents(target); const partsAfterFirst = parts.slice(1); - if (partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 || partsAfterFirst.indexOf("node_modules") >= 0) { + if ( + partsAfterFirst.indexOf("..") >= 0 || partsAfterFirst.indexOf(".") >= 0 + || partsAfterFirst.indexOf("node_modules") >= 0 + ) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } @@ -2692,31 +3675,61 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo // TODO: Assert that `resolvedTarget` is actually within the package directory? That's what the spec says.... but I'm not sure we need // to be in the business of validating everyone's import and export map correctness. const subpathParts = getPathComponents(subpath); - if (subpathParts.indexOf("..") >= 0 || subpathParts.indexOf(".") >= 0 || subpathParts.indexOf("node_modules") >= 0) { + if ( + subpathParts.indexOf("..") >= 0 || subpathParts.indexOf(".") >= 0 + || subpathParts.indexOf("node_modules") >= 0 + ) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } if (state.traceEnabled) { - trace(state.host, + trace( + state.host, Diagnostics.Using_0_subpath_1_with_target_2, isImports ? "imports" : "exports", key, - pattern ? target.replace(/\*/g, subpath) : target + subpath); + pattern ? target.replace(/\*/g, subpath) : target + subpath, + ); } - const finalPath = toAbsolutePath(pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath); - const inputLink = tryLoadInputFileForPath(finalPath, subpath, combinePaths(scope.packageDirectory, "package.json"), isImports); + const finalPath = toAbsolutePath( + pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath, + ); + const inputLink = tryLoadInputFileForPath( + finalPath, + subpath, + combinePaths(scope.packageDirectory, "package.json"), + isImports, + ); if (inputLink) return inputLink; - return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, finalPath, /*onlyRecordFailures*/ false, state))); + return toSearchResult( + withPackageId( + scope, + loadFileNameFromPackageJsonField(extensions, finalPath, /*onlyRecordFailures*/ false, state), + ), + ); } else if (typeof target === "object" && target !== null) { // eslint-disable-line no-null/no-null if (!Array.isArray(target)) { traceIfEnabled(state, Diagnostics.Entering_conditional_exports); for (const condition of getOwnKeys(target as MapLike)) { - if (condition === "default" || state.conditions.indexOf(condition) >= 0 || isApplicableVersionedTypesKey(state.conditions, condition)) { - traceIfEnabled(state, Diagnostics.Matched_0_condition_1, isImports ? "imports" : "exports", condition); + if ( + condition === "default" || state.conditions.indexOf(condition) >= 0 + || isApplicableVersionedTypesKey(state.conditions, condition) + ) { + traceIfEnabled( + state, + Diagnostics.Matched_0_condition_1, + isImports ? "imports" : "exports", + condition, + ); const subTarget = (target as MapLike)[condition]; const result = loadModuleFromTargetImportOrExport(subTarget, subpath, pattern, key); if (result) { @@ -2738,7 +3751,12 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo else { if (!length(target)) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } @@ -2752,12 +3770,22 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo } else if (target === null) { // eslint-disable-line no-null/no-null if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_explicitly_maps_specifier_1_to_null, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_explicitly_maps_specifier_1_to_null, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); } if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); + trace( + state.host, + Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, + scope.packageDirectory, + moduleName, + ); } return toSearchResult(/*value*/ undefined); @@ -2778,21 +3806,39 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo // we reproduce into the output directory is based on the set of input files, which we're still in the process of traversing and resolving! // _Given that_, we have to guess what the base of the output directory is (obviously the user wrote the export map, so has some idea what it is!). // We are going to probe _so many_ possible paths. We limit where we'll do this to try to reduce the possibilities of false positive lookups. - if (!state.isConfigLookup + if ( + !state.isConfigLookup && (state.compilerOptions.declarationDir || state.compilerOptions.outDir) && finalPath.indexOf("/node_modules/") === -1 - && (state.compilerOptions.configFile ? containsPath(scope.packageDirectory, toAbsolutePath(state.compilerOptions.configFile.fileName), !useCaseSensitiveFileNames(state)) : true) + && (state.compilerOptions.configFile + ? containsPath( + scope.packageDirectory, + toAbsolutePath(state.compilerOptions.configFile.fileName), + !useCaseSensitiveFileNames(state), + ) : true) ) { // So that all means we'll only try these guesses for files outside `node_modules` in a directory where the `package.json` and `tsconfig.json` are siblings. // Even with all that, we still don't know if the root of the output file structure will be (relative to the package file) // `.`, `./src` or any other deeper directory structure. (If project references are used, it's definitely `.` by fiat, so that should be pretty common.) - const getCanonicalFileName = hostGetCanonicalFileName({ useCaseSensitiveFileNames: () => useCaseSensitiveFileNames(state) }); + const getCanonicalFileName = hostGetCanonicalFileName({ + useCaseSensitiveFileNames: () => useCaseSensitiveFileNames(state), + }); const commonSourceDirGuesses: string[] = []; // A `rootDir` compiler option strongly indicates the root location // A `composite` project is using project references and has it's common src dir set to `.`, so it shouldn't need to check any other locations - if (state.compilerOptions.rootDir || (state.compilerOptions.composite && state.compilerOptions.configFilePath)) { - const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [], state.host.getCurrentDirectory?.() || "", getCanonicalFileName)); + if ( + state.compilerOptions.rootDir + || (state.compilerOptions.composite && state.compilerOptions.configFilePath) + ) { + const commonDir = toAbsolutePath( + getCommonSourceDirectory( + state.compilerOptions, + () => [], + state.host.getCurrentDirectory?.() || "", + getCanonicalFileName, + ), + ); commonSourceDirGuesses.push(commonDir); } else if (state.requestContainingDirectory) { @@ -2818,7 +3864,14 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo // be a file outside of `./src/sub` in the program (the file we resolved to), making us de-facto right. So this fallback lookup // logic may influence what files are pulled in by self-names, which in turn influences the output path shape, but it's all // internally consistent so the paths should be stable so long as we prefer the "most general" (meaning: top-most-level directory) possible results first. - const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [requestingFile, toAbsolutePath(packagePath)], state.host.getCurrentDirectory?.() || "", getCanonicalFileName)); + const commonDir = toAbsolutePath( + getCommonSourceDirectory( + state.compilerOptions, + () => [requestingFile, toAbsolutePath(packagePath)], + state.host.getCurrentDirectory?.() || "", + getCanonicalFileName, + ), + ); commonSourceDirGuesses.push(commonDir); let fragment = ensureTrailingDirectorySeparator(commonDir); @@ -2833,10 +3886,12 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo if (commonSourceDirGuesses.length > 1) { state.reportDiagnostic(createCompilerDiagnostic( isImports - ? Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_import_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate - : Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_export_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate, + ? Diagnostics + .The_project_root_is_ambiguous_but_is_required_to_resolve_import_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate + : Diagnostics + .The_project_root_is_ambiguous_but_is_required_to_resolve_export_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate, entry === "" ? "." : entry, // replace empty string with `.` - the reverse of the operation done when entries are built - so main entrypoint errors don't look weird - packagePath + packagePath, )); } for (const commonSourceDirGuess of commonSourceDirGuesses) { @@ -2846,15 +3901,38 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo // The matched export is looking up something in either the out declaration or js dir, now map the written path back into the source dir and source extension const pathFragment = finalPath.slice(candidateDir.length + 1); // +1 to also remove directory seperator const possibleInputBase = combinePaths(commonSourceDirGuess, pathFragment); - const jsAndDtsExtensions = [Extension.Mjs, Extension.Cjs, Extension.Js, Extension.Json, Extension.Dmts, Extension.Dcts, Extension.Dts]; + const jsAndDtsExtensions = [ + Extension.Mjs, + Extension.Cjs, + Extension.Js, + Extension.Json, + Extension.Dmts, + Extension.Dcts, + Extension.Dts, + ]; for (const ext of jsAndDtsExtensions) { if (fileExtensionIs(possibleInputBase, ext)) { const inputExts = getPossibleOriginalInputExtensionForExtension(possibleInputBase); for (const possibleExt of inputExts) { if (!extensionIsOk(extensions, possibleExt)) continue; - const possibleInputWithInputExtension = changeAnyExtension(possibleInputBase, possibleExt, ext, !useCaseSensitiveFileNames(state)); + const possibleInputWithInputExtension = changeAnyExtension( + possibleInputBase, + possibleExt, + ext, + !useCaseSensitiveFileNames(state), + ); if (state.host.fileExists(possibleInputWithInputExtension)) { - return toSearchResult(withPackageId(scope, loadFileNameFromPackageJsonField(extensions, possibleInputWithInputExtension, /*onlyRecordFailures*/ false, state))); + return toSearchResult( + withPackageId( + scope, + loadFileNameFromPackageJsonField( + extensions, + possibleInputWithInputExtension, + /*onlyRecordFailures*/ false, + state, + ), + ), + ); } } } @@ -2868,13 +3946,21 @@ function getLoadModuleFromTargetImportOrExport(extensions: Extensions, state: Mo function getOutputDirectoriesForBaseDirectory(commonSourceDirGuess: string) { // Config file ouput paths are processed to be relative to the host's current directory, while // otherwise the paths are resolved relative to the common source dir the compiler puts together - const currentDir = state.compilerOptions.configFile ? state.host.getCurrentDirectory?.() || "" : commonSourceDirGuess; + const currentDir = state.compilerOptions.configFile ? state.host.getCurrentDirectory?.() || "" + : commonSourceDirGuess; const candidateDirectories = []; if (state.compilerOptions.declarationDir) { - candidateDirectories.push(toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.declarationDir))); + candidateDirectories.push( + toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.declarationDir)), + ); } - if (state.compilerOptions.outDir && state.compilerOptions.outDir !== state.compilerOptions.declarationDir) { - candidateDirectories.push(toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.outDir))); + if ( + state.compilerOptions.outDir + && state.compilerOptions.outDir !== state.compilerOptions.declarationDir + ) { + candidateDirectories.push( + toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.outDir)), + ); } return candidateDirectories; } @@ -2891,17 +3977,53 @@ export function isApplicableVersionedTypesKey(conditions: readonly string[], key return range.test(version); } -function loadModuleFromNearestNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { - return loadModuleFromNearestNodeModulesDirectoryWorker(extensions, moduleName, directory, state, /*typesScopeOnly*/ false, cache, redirectedReference); +function loadModuleFromNearestNodeModulesDirectory( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, +): SearchResult { + return loadModuleFromNearestNodeModulesDirectoryWorker( + extensions, + moduleName, + directory, + state, + /*typesScopeOnly*/ false, + cache, + redirectedReference, + ); } -function loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName: string, directory: string, state: ModuleResolutionState): SearchResult { +function loadModuleFromNearestNodeModulesDirectoryTypesScope( + moduleName: string, + directory: string, + state: ModuleResolutionState, +): SearchResult { // Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly. - return loadModuleFromNearestNodeModulesDirectoryWorker(Extensions.Declaration, moduleName, directory, state, /*typesScopeOnly*/ true, /*cache*/ undefined, /*redirectedReference*/ undefined); + return loadModuleFromNearestNodeModulesDirectoryWorker( + Extensions.Declaration, + moduleName, + directory, + state, + /*typesScopeOnly*/ true, + /*cache*/ undefined, + /*redirectedReference*/ undefined, + ); } -function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): SearchResult { - const mode = state.features === 0 ? undefined : state.features & NodeResolutionFeatures.EsmMode ? ModuleKind.ESNext : ModuleKind.CommonJS; +function loadModuleFromNearestNodeModulesDirectoryWorker( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + typesScopeOnly: boolean, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, +): SearchResult { + const mode = state.features === 0 ? undefined + : state.features & NodeResolutionFeatures.EsmMode ? ModuleKind.ESNext : ModuleKind.CommonJS; // Do (up to) two passes through node_modules: // 1. For each ancestor node_modules directory, try to find: // i. TS/DTS files in the implementation package @@ -2912,30 +4034,63 @@ function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, const secondaryExtensions = extensions & ~(Extensions.TypeScript | Extensions.Declaration); // (1) if (priorityExtensions) { - traceIfEnabled(state, Diagnostics.Searching_all_ancestor_node_modules_directories_for_preferred_extensions_Colon_0, formatExtensions(priorityExtensions)); + traceIfEnabled( + state, + Diagnostics.Searching_all_ancestor_node_modules_directories_for_preferred_extensions_Colon_0, + formatExtensions(priorityExtensions), + ); const result = lookup(priorityExtensions); if (result) return result; } // (2) if (secondaryExtensions && !typesScopeOnly) { - traceIfEnabled(state, Diagnostics.Searching_all_ancestor_node_modules_directories_for_fallback_extensions_Colon_0, formatExtensions(secondaryExtensions)); + traceIfEnabled( + state, + Diagnostics.Searching_all_ancestor_node_modules_directories_for_fallback_extensions_Colon_0, + formatExtensions(secondaryExtensions), + ); return lookup(secondaryExtensions); } function lookup(extensions: Extensions) { return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => { if (getBaseFileName(ancestorDirectory) !== "node_modules") { - const resolutionFromCache = tryFindNonRelativeModuleNameInCache(cache, moduleName, mode, ancestorDirectory, redirectedReference, state); + const resolutionFromCache = tryFindNonRelativeModuleNameInCache( + cache, + moduleName, + mode, + ancestorDirectory, + redirectedReference, + state, + ); if (resolutionFromCache) { return resolutionFromCache; } - return toSearchResult(loadModuleFromImmediateNodeModulesDirectory(extensions, moduleName, ancestorDirectory, state, typesScopeOnly, cache, redirectedReference)); + return toSearchResult( + loadModuleFromImmediateNodeModulesDirectory( + extensions, + moduleName, + ancestorDirectory, + state, + typesScopeOnly, + cache, + redirectedReference, + ), + ); } }); } } -function loadModuleFromImmediateNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): Resolved | undefined { +function loadModuleFromImmediateNodeModulesDirectory( + extensions: Extensions, + moduleName: string, + directory: string, + state: ModuleResolutionState, + typesScopeOnly: boolean, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, +): Resolved | undefined { const nodeModulesFolder = combinePaths(directory, "node_modules"); const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host); if (!nodeModulesFolderExists && state.traceEnabled) { @@ -2943,7 +4098,15 @@ function loadModuleFromImmediateNodeModulesDirectory(extensions: Extensions, mod } if (!typesScopeOnly) { - const packageResult = loadModuleFromSpecificNodeModulesDirectory(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, state, cache, redirectedReference); + const packageResult = loadModuleFromSpecificNodeModulesDirectory( + extensions, + moduleName, + nodeModulesFolder, + nodeModulesFolderExists, + state, + cache, + redirectedReference, + ); if (packageResult) { return packageResult; } @@ -2954,15 +4117,35 @@ function loadModuleFromImmediateNodeModulesDirectory(extensions: Extensions, mod let nodeModulesAtTypesExists = nodeModulesFolderExists; if (nodeModulesFolderExists && !directoryProbablyExists(nodeModulesAtTypes, state.host)) { if (state.traceEnabled) { - trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, nodeModulesAtTypes); + trace( + state.host, + Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, + nodeModulesAtTypes, + ); } nodeModulesAtTypesExists = false; } - return loadModuleFromSpecificNodeModulesDirectory(Extensions.Declaration, mangleScopedPackageNameWithTrace(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, state, cache, redirectedReference); + return loadModuleFromSpecificNodeModulesDirectory( + Extensions.Declaration, + mangleScopedPackageNameWithTrace(moduleName, state), + nodeModulesAtTypes, + nodeModulesAtTypesExists, + state, + cache, + redirectedReference, + ); } } -function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, moduleName: string, nodeModulesDirectory: string, nodeModulesDirectoryExists: boolean, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined): Resolved | undefined { +function loadModuleFromSpecificNodeModulesDirectory( + extensions: Extensions, + moduleName: string, + nodeModulesDirectory: string, + nodeModulesDirectoryExists: boolean, + state: ModuleResolutionState, + cache: ModuleResolutionCache | undefined, + redirectedReference: ResolvedProjectReference | undefined, +): Resolved | undefined { const candidate = normalizePath(combinePaths(nodeModulesDirectory, moduleName)); const { packageName, rest } = parsePackageName(moduleName); const packageDirectory = combinePaths(nodeModulesDirectory, packageName); @@ -2971,10 +4154,16 @@ function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, modu // First look for a nested package.json, as in `node_modules/foo/bar/package.json`. let packageInfo = getPackageJsonInfo(candidate, !nodeModulesDirectoryExists, state); // But only if we're not respecting export maps (if we are, we might redirect around this location) - if (rest !== "" && packageInfo && ( - !(state.features & NodeResolutionFeatures.Exports) || - !hasProperty((rootPackageInfo = getPackageJsonInfo(packageDirectory, !nodeModulesDirectoryExists, state))?.contents.packageJsonContent ?? emptyArray, "exports") - )) { + if ( + rest !== "" && packageInfo && ( + !(state.features & NodeResolutionFeatures.Exports) + || !hasProperty( + (rootPackageInfo = getPackageJsonInfo(packageDirectory, !nodeModulesDirectoryExists, state))?.contents + .packageJsonContent ?? emptyArray, + "exports", + ) + ) + ) { const fromFile = loadModuleFromFile(extensions, candidate, !nodeModulesDirectoryExists, state); if (fromFile) { return noPackageId(fromFile); @@ -2992,9 +4181,9 @@ function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, modu } const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => { - let pathAndExtension = - (rest || !(state.features & NodeResolutionFeatures.EsmMode)) && loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) || - loadNodeModuleFromDirectoryWorker( + let pathAndExtension = (rest || !(state.features & NodeResolutionFeatures.EsmMode)) + && loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) + || loadNodeModuleFromDirectoryWorker( extensions, candidate, onlyRecordFailures, @@ -3005,12 +4194,18 @@ function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, modu if ( !pathAndExtension && packageInfo // eslint-disable-next-line no-null/no-null - && (packageInfo.contents.packageJsonContent.exports === undefined || packageInfo.contents.packageJsonContent.exports === null) + && (packageInfo.contents.packageJsonContent.exports === undefined + || packageInfo.contents.packageJsonContent.exports === null) && state.features & NodeResolutionFeatures.EsmMode ) { // EsmMode disables index lookup in `loadNodeModuleFromDirectoryWorker` generally, however non-relative package resolutions still assume // a default `index.js` entrypoint if no `main` or `exports` are present - pathAndExtension = loadModuleFromFile(extensions, combinePaths(candidate, "index.js"), onlyRecordFailures, state); + pathAndExtension = loadModuleFromFile( + extensions, + combinePaths(candidate, "index.js"), + onlyRecordFailures, + state, + ); } return withPackageId(packageInfo, pathAndExtension); }; @@ -3020,16 +4215,43 @@ function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, modu packageInfo = rootPackageInfo ?? getPackageJsonInfo(packageDirectory, !nodeModulesDirectoryExists, state); } // package exports are higher priority than file/directory/typesVersions lookups and (and, if there's exports present, blocks them) - if (packageInfo && packageInfo.contents.packageJsonContent.exports && state.features & NodeResolutionFeatures.Exports) { - return loadModuleFromExports(packageInfo, extensions, combinePaths(".", rest), state, cache, redirectedReference)?.value; + if ( + packageInfo && packageInfo.contents.packageJsonContent.exports + && state.features & NodeResolutionFeatures.Exports + ) { + return loadModuleFromExports( + packageInfo, + extensions, + combinePaths(".", rest), + state, + cache, + redirectedReference, + )?.value; } const versionPaths = rest !== "" && packageInfo ? getVersionPathsOfPackageJsonInfo(packageInfo, state) : undefined; if (versionPaths) { if (state.traceEnabled) { - trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, rest); + trace( + state.host, + Diagnostics + .package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, + versionPaths.version, + version, + rest, + ); } - const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host); - const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, versionPaths.paths, /*pathPatterns*/ undefined, loader, !packageDirectoryExists, state); + const packageDirectoryExists = nodeModulesDirectoryExists + && directoryProbablyExists(packageDirectory, state.host); + const fromPaths = tryLoadModuleUsingPaths( + extensions, + rest, + packageDirectory, + versionPaths.paths, + /*pathPatterns*/ undefined, + loader, + !packageDirectoryExists, + state, + ); if (fromPaths) { return fromPaths.value; } @@ -3037,7 +4259,16 @@ function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, modu return loader(extensions, candidate, !nodeModulesDirectoryExists, state); } -function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, baseDirectory: string, paths: MapLike, pathPatterns: readonly (string | Pattern)[] | undefined, loader: ResolutionKindSpecificLoader, onlyRecordFailures: boolean, state: ModuleResolutionState): SearchResult { +function tryLoadModuleUsingPaths( + extensions: Extensions, + moduleName: string, + baseDirectory: string, + paths: MapLike, + pathPatterns: readonly (string | Pattern)[] | undefined, + loader: ResolutionKindSpecificLoader, + onlyRecordFailures: boolean, + state: ModuleResolutionState, +): SearchResult { pathPatterns ||= tryParsePatterns(paths); const matchedPattern = matchPatternOrExact(pathPatterns, moduleName); if (matchedPattern) { @@ -3061,7 +4292,12 @@ function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, bas return noPackageId({ path, ext: extension, resolvedUsingTsExtension: undefined }); } } - return loader(extensions, candidate, onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), state); + return loader( + extensions, + candidate, + onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), + state, + ); }); return { value: resolved }; } @@ -3106,16 +4342,29 @@ export function getPackageNameFromTypesPackageName(mangledName: string): string /** @internal */ export function unmangleScopedPackageName(typesPackageName: string): string { - return stringContains(typesPackageName, mangledScopedPackageSeparator) ? - "@" + typesPackageName.replace(mangledScopedPackageSeparator, directorySeparator) : - typesPackageName; + return stringContains(typesPackageName, mangledScopedPackageSeparator) + ? "@" + typesPackageName.replace(mangledScopedPackageSeparator, directorySeparator) + : typesPackageName; } -function tryFindNonRelativeModuleNameInCache(cache: NonRelativeModuleNameResolutionCache | undefined, moduleName: string, mode: ResolutionMode, containingDirectory: string, redirectedReference: ResolvedProjectReference | undefined, state: ModuleResolutionState): SearchResult { - const result = cache && cache.getFromNonRelativeNameCache(moduleName, mode, containingDirectory, redirectedReference); +function tryFindNonRelativeModuleNameInCache( + cache: NonRelativeModuleNameResolutionCache | undefined, + moduleName: string, + mode: ResolutionMode, + containingDirectory: string, + redirectedReference: ResolvedProjectReference | undefined, + state: ModuleResolutionState, +): SearchResult { + const result = cache + && cache.getFromNonRelativeNameCache(moduleName, mode, containingDirectory, redirectedReference); if (result) { if (state.traceEnabled) { - trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory); + trace( + state.host, + Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, + moduleName, + containingDirectory, + ); } state.resultFromCache = result; return { @@ -3124,13 +4373,20 @@ function tryFindNonRelativeModuleNameInCache(cache: NonRelativeModuleNameResolut originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId, - resolvedUsingTsExtension: result.resolvedModule.resolvedUsingTsExtension - } + resolvedUsingTsExtension: result.resolvedModule.resolvedUsingTsExtension, + }, }; } } -export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations { +export function classicNameResolver( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + cache?: NonRelativeModuleNameResolutionCache, + redirectedReference?: ResolvedProjectReference, +): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); const failedLookupLocations: string[] = []; const affectingLocations: string[] = []; @@ -3141,7 +4397,8 @@ export function classicNameResolver(moduleName: string, containingFile: string, host, traceEnabled, failedLookupLocations, - affectingLocations, packageJsonInfoCache: cache, + affectingLocations, + packageJsonInfoCache: cache, features: NodeResolutionFeatures.None, conditions: [], requestContainingDirectory: containingDirectory, @@ -3150,9 +4407,8 @@ export function classicNameResolver(moduleName: string, containingFile: string, candidateIsFromPackageJsonField: false, }; - const resolved = - tryResolve(Extensions.TypeScript | Extensions.Declaration) || - tryResolve(Extensions.JavaScript | (compilerOptions.resolveJsonModule ? Extensions.Json : 0)); + const resolved = tryResolve(Extensions.TypeScript | Extensions.Declaration) + || tryResolve(Extensions.JavaScript | (compilerOptions.resolveJsonModule ? Extensions.Json : 0)); // No originalPath because classic resolution doesn't resolve realPath return createResolvedModuleWithFailedLookupLocationsHandlingSymlink( moduleName, @@ -3165,7 +4421,13 @@ export function classicNameResolver(moduleName: string, containingFile: string, ); function tryResolve(extensions: Extensions): SearchResult { - const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, state); + const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings( + extensions, + moduleName, + containingDirectory, + loadModuleFromFileNoPackageId, + state, + ); if (resolvedUsingSettings) { return { value: resolvedUsingSettings }; } @@ -3173,24 +4435,39 @@ export function classicNameResolver(moduleName: string, containingFile: string, if (!isExternalModuleNameRelative(moduleName)) { // Climb up parent directories looking for a module. const resolved = forEachAncestorDirectory(containingDirectory, directory => { - const resolutionFromCache = tryFindNonRelativeModuleNameInCache(cache, moduleName, /*mode*/ undefined, directory, redirectedReference, state); + const resolutionFromCache = tryFindNonRelativeModuleNameInCache( + cache, + moduleName, + /*mode*/ undefined, + directory, + redirectedReference, + state, + ); if (resolutionFromCache) { return resolutionFromCache; } const searchName = normalizePath(combinePaths(directory, moduleName)); - return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, /*onlyRecordFailures*/ false, state)); + return toSearchResult( + loadModuleFromFileNoPackageId(extensions, searchName, /*onlyRecordFailures*/ false, state), + ); }); if (resolved) return resolved; if (extensions & (Extensions.TypeScript | Extensions.Declaration)) { // If we didn't find the file normally, look it up in @types. - let resolved = loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName, containingDirectory, state); + let resolved = loadModuleFromNearestNodeModulesDirectoryTypesScope( + moduleName, + containingDirectory, + state, + ); if (extensions & Extensions.Declaration) resolved ??= resolveFromTypeRoot(moduleName, state); return resolved; } } else { const candidate = normalizePath(combinePaths(containingDirectory, moduleName)); - return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, /*onlyRecordFailures*/ false, state)); + return toSearchResult( + loadModuleFromFileNoPackageId(extensions, candidate, /*onlyRecordFailures*/ false, state), + ); } } } @@ -3206,7 +4483,8 @@ function resolveFromTypeRoot(moduleName: string, state: ModuleResolutionState) { const resolvedFromFile = loadModuleFromFile(Extensions.Declaration, candidate, !directoryExists, state); if (resolvedFromFile) { const packageDirectory = parseNodeModuleFromPath(resolvedFromFile.path); - const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined; + const packageInfo = packageDirectory + ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined; return toSearchResult(withPackageId(packageInfo, resolvedFromFile)); } const resolved = loadNodeModuleFromDirectory(Extensions.Declaration, candidate, !directoryExists, state); @@ -3227,10 +4505,24 @@ export function shouldAllowImportingTsExtension(compilerOptions: CompilerOptions * * @internal */ -export function loadModuleFromGlobalCache(moduleName: string, projectName: string | undefined, compilerOptions: CompilerOptions, host: ModuleResolutionHost, globalCache: string, packageJsonInfoCache: PackageJsonInfoCache): ResolvedModuleWithFailedLookupLocations { +export function loadModuleFromGlobalCache( + moduleName: string, + projectName: string | undefined, + compilerOptions: CompilerOptions, + host: ModuleResolutionHost, + globalCache: string, + packageJsonInfoCache: PackageJsonInfoCache, +): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); if (traceEnabled) { - trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName, moduleName, globalCache); + trace( + host, + Diagnostics + .Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, + projectName, + moduleName, + globalCache, + ); } const failedLookupLocations: string[] = []; const affectingLocations: string[] = []; @@ -3249,14 +4541,22 @@ export function loadModuleFromGlobalCache(moduleName: string, projectName: strin isConfigLookup: false, candidateIsFromPackageJsonField: false, }; - const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.Declaration, moduleName, globalCache, state, /*typesScopeOnly*/ false, /*cache*/ undefined, /*redirectedReference*/ undefined); + const resolved = loadModuleFromImmediateNodeModulesDirectory( + Extensions.Declaration, + moduleName, + globalCache, + state, + /*typesScopeOnly*/ false, + /*cache*/ undefined, + /*redirectedReference*/ undefined, + ); return createResolvedModuleWithFailedLookupLocations( resolved, /*isExternalLibraryImport*/ true, failedLookupLocations, affectingLocations, diagnostics, - state.resultFromCache + state.resultFromCache, ); } @@ -3269,7 +4569,7 @@ export function loadModuleFromGlobalCache(moduleName: string, projectName: strin * - { value: undefined } - not found - stop searching * - { value: } - found - stop searching */ -type SearchResult = { value: T | undefined } | undefined; +type SearchResult = { value: T | undefined; } | undefined; /** * Wraps value to SearchResult. @@ -3286,7 +4586,7 @@ function traceIfEnabled(state: ModuleResolutionState, diagnostic: DiagnosticMess } function useCaseSensitiveFileNames(state: ModuleResolutionState) { - return !state.host.useCaseSensitiveFileNames ? true : - typeof state.host.useCaseSensitiveFileNames === "boolean" ? state.host.useCaseSensitiveFileNames : - state.host.useCaseSensitiveFileNames(); + return !state.host.useCaseSensitiveFileNames ? true + : typeof state.host.useCaseSensitiveFileNames === "boolean" ? state.host.useCaseSensitiveFileNames + : state.host.useCaseSensitiveFileNames(); } diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts index eeeeb75615994..3382190611576 100644 --- a/src/compiler/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -114,7 +114,12 @@ import { // Used by importFixes, getEditsForFileRename, and declaration emit to synthesize import module specifiers. -const enum RelativePreference { Relative, NonRelative, Shortest, ExternalNonRelative } +const enum RelativePreference { + Relative, + NonRelative, + Shortest, + ExternalNonRelative, +} // Processed preferences interface Preferences { @@ -122,7 +127,9 @@ interface Preferences { /** * @param syntaxImpliedNodeFormat Used when the import syntax implies ESM or CJS irrespective of the mode of the file. */ - getAllowedEndingsInPreferredOrder(syntaxImpliedNodeFormat?: SourceFile["impliedNodeFormat"]): ModuleSpecifierEnding[]; + getAllowedEndingsInPreferredOrder( + syntaxImpliedNodeFormat?: SourceFile["impliedNodeFormat"], + ): ModuleSpecifierEnding[]; } function getPreferences( @@ -133,14 +140,13 @@ function getPreferences( ): Preferences { const preferredEnding = getPreferredEnding(); return { - relativePreference: - oldImportSpecifier !== undefined ? (isExternalModuleNameRelative(oldImportSpecifier) ? - RelativePreference.Relative : - RelativePreference.NonRelative) : - importModuleSpecifierPreference === "relative" ? RelativePreference.Relative : - importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative : - importModuleSpecifierPreference === "project-relative" ? RelativePreference.ExternalNonRelative : - RelativePreference.Shortest, + relativePreference: oldImportSpecifier !== undefined ? (isExternalModuleNameRelative(oldImportSpecifier) + ? RelativePreference.Relative + : RelativePreference.NonRelative) + : importModuleSpecifierPreference === "relative" ? RelativePreference.Relative + : importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative + : importModuleSpecifierPreference === "project-relative" ? RelativePreference.ExternalNonRelative + : RelativePreference.Shortest, getAllowedEndingsInPreferredOrder: syntaxImpliedNodeFormat => { if ((syntaxImpliedNodeFormat ?? importingSourceFile.impliedNodeFormat) === ModuleKind.ESNext) { if (shouldAllowImportingTsExtension(compilerOptions, importingSourceFile.fileName)) { @@ -153,19 +159,59 @@ function getPreferences( ? [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Index] : [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.JsExtension]; } - const allowImportingTsExtension = shouldAllowImportingTsExtension(compilerOptions, importingSourceFile.fileName); + const allowImportingTsExtension = shouldAllowImportingTsExtension( + compilerOptions, + importingSourceFile.fileName, + ); switch (preferredEnding) { - case ModuleSpecifierEnding.JsExtension: return allowImportingTsExtension - ? [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index] - : [ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index]; - case ModuleSpecifierEnding.TsExtension: return [ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.JsExtension, ModuleSpecifierEnding.Index]; - case ModuleSpecifierEnding.Index: return allowImportingTsExtension - ? [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.JsExtension] - : [ModuleSpecifierEnding.Index, ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.JsExtension]; - case ModuleSpecifierEnding.Minimal: return allowImportingTsExtension - ? [ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index, ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.JsExtension] - : [ModuleSpecifierEnding.Minimal, ModuleSpecifierEnding.Index, ModuleSpecifierEnding.JsExtension]; - default: Debug.assertNever(preferredEnding); + case ModuleSpecifierEnding.JsExtension: + return allowImportingTsExtension + ? [ + ModuleSpecifierEnding.JsExtension, + ModuleSpecifierEnding.TsExtension, + ModuleSpecifierEnding.Minimal, + ModuleSpecifierEnding.Index, + ] + : [ + ModuleSpecifierEnding.JsExtension, + ModuleSpecifierEnding.Minimal, + ModuleSpecifierEnding.Index, + ]; + case ModuleSpecifierEnding.TsExtension: + return [ + ModuleSpecifierEnding.TsExtension, + ModuleSpecifierEnding.Minimal, + ModuleSpecifierEnding.JsExtension, + ModuleSpecifierEnding.Index, + ]; + case ModuleSpecifierEnding.Index: + return allowImportingTsExtension + ? [ + ModuleSpecifierEnding.Index, + ModuleSpecifierEnding.Minimal, + ModuleSpecifierEnding.TsExtension, + ModuleSpecifierEnding.JsExtension, + ] + : [ + ModuleSpecifierEnding.Index, + ModuleSpecifierEnding.Minimal, + ModuleSpecifierEnding.JsExtension, + ]; + case ModuleSpecifierEnding.Minimal: + return allowImportingTsExtension + ? [ + ModuleSpecifierEnding.Minimal, + ModuleSpecifierEnding.Index, + ModuleSpecifierEnding.TsExtension, + ModuleSpecifierEnding.JsExtension, + ] + : [ + ModuleSpecifierEnding.Minimal, + ModuleSpecifierEnding.Index, + ModuleSpecifierEnding.JsExtension, + ]; + default: + Debug.assertNever(preferredEnding); } }, }; @@ -179,7 +225,8 @@ function getPreferences( importModuleSpecifierEnding, importingSourceFile.impliedNodeFormat, compilerOptions, - importingSourceFile); + importingSourceFile, + ); } } @@ -197,7 +244,16 @@ export function updateModuleSpecifier( oldImportSpecifier: string, options: ModuleSpecifierOptions = {}, ): string | undefined { - const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getPreferences({}, compilerOptions, importingSourceFile, oldImportSpecifier), {}, options); + const res = getModuleSpecifierWorker( + compilerOptions, + importingSourceFile, + importingSourceFileName, + toFileName, + host, + getPreferences({}, compilerOptions, importingSourceFile, oldImportSpecifier), + {}, + options, + ); if (res === oldImportSpecifier) return undefined; return res; } @@ -217,7 +273,16 @@ export function getModuleSpecifier( host: ModuleSpecifierResolutionHost, options: ModuleSpecifierOptions = {}, ): string { - return getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getPreferences({}, compilerOptions, importingSourceFile), {}, options); + return getModuleSpecifierWorker( + compilerOptions, + importingSourceFile, + importingSourceFileName, + toFileName, + host, + getPreferences({}, compilerOptions, importingSourceFile), + {}, + options, + ); } /** @internal */ @@ -231,8 +296,20 @@ export function getNodeModulesPackageName( ): string | undefined { const info = getInfo(importingSourceFile.path, host); const modulePaths = getAllModulePaths(importingSourceFile.path, nodeModulesFileName, host, preferences, options); - return firstDefined(modulePaths, - modulePath => tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, preferences, /*packageNameOnly*/ true, options.overrideImportMode)); + return firstDefined( + modulePaths, + modulePath => + tryGetModuleNameAsNodeModule( + modulePath, + info, + importingSourceFile, + host, + compilerOptions, + preferences, + /*packageNameOnly*/ true, + options.overrideImportMode, + ), + ); } function getModuleSpecifierWorker( @@ -243,12 +320,32 @@ function getModuleSpecifierWorker( host: ModuleSpecifierResolutionHost, preferences: Preferences, userPreferences: UserPreferences, - options: ModuleSpecifierOptions = {} + options: ModuleSpecifierOptions = {}, ): string { const info = getInfo(importingSourceFileName, host); const modulePaths = getAllModulePaths(importingSourceFileName, toFileName, host, userPreferences, options); - return firstDefined(modulePaths, modulePath => tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, userPreferences, /*packageNameOnly*/ undefined, options.overrideImportMode)) || - getLocalModuleSpecifier(toFileName, info, compilerOptions, host, options.overrideImportMode || importingSourceFile.impliedNodeFormat, preferences); + return firstDefined( + modulePaths, + modulePath => + tryGetModuleNameAsNodeModule( + modulePath, + info, + importingSourceFile, + host, + compilerOptions, + userPreferences, + /*packageNameOnly*/ undefined, + options.overrideImportMode, + ), + ) + || getLocalModuleSpecifier( + toFileName, + info, + compilerOptions, + host, + options.overrideImportMode || importingSourceFile.impliedNodeFormat, + preferences, + ); } /** @internal */ @@ -264,7 +361,8 @@ export function tryGetModuleSpecifiersFromCache( importingSourceFile, host, userPreferences, - options)[0]; + options, + )[0]; } function tryGetModuleSpecifiersFromCacheWorker( @@ -273,7 +371,12 @@ function tryGetModuleSpecifiersFromCacheWorker( host: ModuleSpecifierResolutionHost, userPreferences: UserPreferences, options: ModuleSpecifierOptions = {}, -): readonly [specifiers?: readonly string[], moduleFile?: SourceFile, modulePaths?: readonly ModulePath[], cache?: ModuleSpecifierCache] { +): readonly [ + specifiers?: readonly string[], + moduleFile?: SourceFile, + modulePaths?: readonly ModulePath[], + cache?: ModuleSpecifierCache, +] { const moduleSourceFile = getSourceFileOfModule(moduleSymbol); if (!moduleSourceFile) { return emptyArray as []; @@ -305,7 +408,7 @@ export function getModuleSpecifiers( importingSourceFile, host, userPreferences, - options + options, ).moduleSpecifiers; } @@ -318,7 +421,7 @@ export function getModuleSpecifiersWithCacheInfo( host: ModuleSpecifierResolutionHost, userPreferences: UserPreferences, options: ModuleSpecifierOptions = {}, -): { moduleSpecifiers: readonly string[], computedWithoutCache: boolean } { +): { moduleSpecifiers: readonly string[]; computedWithoutCache: boolean; } { let computedWithoutCache = false; const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol, checker); if (ambient) return { moduleSpecifiers: [ambient], computedWithoutCache }; @@ -329,14 +432,21 @@ export function getModuleSpecifiersWithCacheInfo( importingSourceFile, host, userPreferences, - options + options, ); if (specifiers) return { moduleSpecifiers: specifiers, computedWithoutCache }; if (!moduleSourceFile) return { moduleSpecifiers: emptyArray, computedWithoutCache }; computedWithoutCache = true; modulePaths ||= getAllModulePathsWorker(importingSourceFile.path, moduleSourceFile.originalFileName, host); - const result = computeModuleSpecifiers(modulePaths, compilerOptions, importingSourceFile, host, userPreferences, options); + const result = computeModuleSpecifiers( + modulePaths, + compilerOptions, + importingSourceFile, + host, + userPreferences, + options, + ); cache?.set(importingSourceFile.path, moduleSourceFile.path, userPreferences, options, modulePaths, result); return { moduleSpecifiers: result, computedWithoutCache }; } @@ -351,20 +461,29 @@ function computeModuleSpecifiers( ): readonly string[] { const info = getInfo(importingSourceFile.path, host); const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile); - const existingSpecifier = forEach(modulePaths, modulePath => forEach( - host.getFileIncludeReasons().get(toPath(modulePath.path, host.getCurrentDirectory(), info.getCanonicalFileName)), - reason => { - if (reason.kind !== FileIncludeKind.Import || reason.file !== importingSourceFile.path) return undefined; - // If the candidate import mode doesn't match the mode we're generating for, don't consider it - // TODO: maybe useful to keep around as an alternative option for certain contexts where the mode is overridable - if (importingSourceFile.impliedNodeFormat && importingSourceFile.impliedNodeFormat !== getModeForResolutionAtIndex(importingSourceFile, reason.index)) return undefined; - const specifier = getModuleNameStringLiteralAt(importingSourceFile, reason.index).text; - // If the preference is for non relative and the module specifier is relative, ignore it - return preferences.relativePreference !== RelativePreference.NonRelative || !pathIsRelative(specifier) ? - specifier : - undefined; - } - )); + const existingSpecifier = forEach(modulePaths, modulePath => + forEach( + host.getFileIncludeReasons().get( + toPath(modulePath.path, host.getCurrentDirectory(), info.getCanonicalFileName), + ), + reason => { + if (reason.kind !== FileIncludeKind.Import || reason.file !== importingSourceFile.path) { + return undefined; + } + // If the candidate import mode doesn't match the mode we're generating for, don't consider it + // TODO: maybe useful to keep around as an alternative option for certain contexts where the mode is overridable + if ( + importingSourceFile.impliedNodeFormat + && importingSourceFile.impliedNodeFormat + !== getModeForResolutionAtIndex(importingSourceFile, reason.index) + ) return undefined; + const specifier = getModuleNameStringLiteralAt(importingSourceFile, reason.index).text; + // If the preference is for non relative and the module specifier is relative, ignore it + return preferences.relativePreference !== RelativePreference.NonRelative || !pathIsRelative(specifier) + ? specifier + : undefined; + }, + )); if (existingSpecifier) { const moduleSpecifiers = [existingSpecifier]; return moduleSpecifiers; @@ -383,7 +502,16 @@ function computeModuleSpecifiers( let relativeSpecifiers: string[] | undefined; for (const modulePath of modulePaths) { const specifier = modulePath.isInNodeModules - ? tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, userPreferences, /*packageNameOnly*/ undefined, options.overrideImportMode) + ? tryGetModuleNameAsNodeModule( + modulePath, + info, + importingSourceFile, + host, + compilerOptions, + userPreferences, + /*packageNameOnly*/ undefined, + options.overrideImportMode, + ) : undefined; nodeModulesSpecifiers = append(nodeModulesSpecifiers, specifier); if (specifier && modulePath.isRedirect) { @@ -426,27 +554,52 @@ function computeModuleSpecifiers( } } - return pathsSpecifiers?.length ? pathsSpecifiers : - redirectPathsSpecifiers?.length ? redirectPathsSpecifiers : - nodeModulesSpecifiers?.length ? nodeModulesSpecifiers : - Debug.checkDefined(relativeSpecifiers); + return pathsSpecifiers?.length ? pathsSpecifiers + : redirectPathsSpecifiers?.length ? redirectPathsSpecifiers + : nodeModulesSpecifiers?.length ? nodeModulesSpecifiers + : Debug.checkDefined(relativeSpecifiers); } interface Info { readonly getCanonicalFileName: GetCanonicalFileName; - readonly importingSourceFileName: Path + readonly importingSourceFileName: Path; readonly sourceDirectory: Path; } // importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path function getInfo(importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info { - const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true); + const getCanonicalFileName = createGetCanonicalFileName( + host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true, + ); const sourceDirectory = getDirectoryPath(importingSourceFileName); return { getCanonicalFileName, importingSourceFileName, sourceDirectory }; } -function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOptions: CompilerOptions, host: ModuleSpecifierResolutionHost, importMode: ResolutionMode, preferences: Preferences): string; -function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOptions: CompilerOptions, host: ModuleSpecifierResolutionHost, importMode: ResolutionMode, preferences: Preferences, pathsOnly?: boolean): string | undefined; -function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOptions: CompilerOptions, host: ModuleSpecifierResolutionHost, importMode: ResolutionMode, { getAllowedEndingsInPreferredOrder: getAllowedEndingsInPrefererredOrder, relativePreference }: Preferences, pathsOnly?: boolean): string | undefined { +function getLocalModuleSpecifier( + moduleFileName: string, + info: Info, + compilerOptions: CompilerOptions, + host: ModuleSpecifierResolutionHost, + importMode: ResolutionMode, + preferences: Preferences, +): string; +function getLocalModuleSpecifier( + moduleFileName: string, + info: Info, + compilerOptions: CompilerOptions, + host: ModuleSpecifierResolutionHost, + importMode: ResolutionMode, + preferences: Preferences, + pathsOnly?: boolean, +): string | undefined; +function getLocalModuleSpecifier( + moduleFileName: string, + info: Info, + compilerOptions: CompilerOptions, + host: ModuleSpecifierResolutionHost, + importMode: ResolutionMode, + { getAllowedEndingsInPreferredOrder: getAllowedEndingsInPrefererredOrder, relativePreference }: Preferences, + pathsOnly?: boolean, +): string | undefined { const { baseUrl, paths, rootDirs } = compilerOptions; if (pathsOnly && !paths) { return undefined; @@ -454,24 +607,43 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt const { sourceDirectory, getCanonicalFileName } = info; const allowedEndings = getAllowedEndingsInPrefererredOrder(importMode); - const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName, allowedEndings, compilerOptions) || - processEnding(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), allowedEndings, compilerOptions); + const relativePath = rootDirs + && tryGetModuleNameFromRootDirs( + rootDirs, + moduleFileName, + sourceDirectory, + getCanonicalFileName, + allowedEndings, + compilerOptions, + ) + || processEnding( + ensurePathIsNonModuleName( + getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName), + ), + allowedEndings, + compilerOptions, + ); if (!baseUrl && !paths || relativePreference === RelativePreference.Relative) { return pathsOnly ? undefined : relativePath; } - const baseDirectory = getNormalizedAbsolutePath(getPathsBasePath(compilerOptions, host) || baseUrl!, host.getCurrentDirectory()); + const baseDirectory = getNormalizedAbsolutePath( + getPathsBasePath(compilerOptions, host) || baseUrl!, + host.getCurrentDirectory(), + ); const relativeToBaseUrl = getRelativePathIfInSameVolume(moduleFileName, baseDirectory, getCanonicalFileName); if (!relativeToBaseUrl) { return pathsOnly ? undefined : relativePath; } - const fromPaths = paths && tryGetModuleNameFromPaths(relativeToBaseUrl, paths, allowedEndings, host, compilerOptions); + const fromPaths = paths + && tryGetModuleNameFromPaths(relativeToBaseUrl, paths, allowedEndings, host, compilerOptions); if (pathsOnly) { return fromPaths; } - const maybeNonRelative = fromPaths === undefined && baseUrl !== undefined ? processEnding(relativeToBaseUrl, allowedEndings, compilerOptions) : fromPaths; + const maybeNonRelative = fromPaths === undefined && baseUrl !== undefined + ? processEnding(relativeToBaseUrl, allowedEndings, compilerOptions) : fromPaths; if (!maybeNonRelative) { return relativePath; } @@ -481,9 +653,13 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt } if (relativePreference === RelativePreference.ExternalNonRelative && !pathIsRelative(maybeNonRelative)) { - const projectDirectory = compilerOptions.configFilePath ? - toPath(getDirectoryPath(compilerOptions.configFilePath), host.getCurrentDirectory(), info.getCanonicalFileName) : - info.getCanonicalFileName(host.getCurrentDirectory()); + const projectDirectory = compilerOptions.configFilePath + ? toPath( + getDirectoryPath(compilerOptions.configFilePath), + host.getCurrentDirectory(), + info.getCanonicalFileName, + ) + : info.getCanonicalFileName(host.getCurrentDirectory()); const modulePath = toPath(moduleFileName, projectDirectory, getCanonicalFileName); const sourceIsInternal = startsWith(sourceDirectory, projectDirectory); const targetIsInternal = startsWith(modulePath, projectDirectory); @@ -518,7 +694,9 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt } // Prefer a relative import over a baseUrl import if it has fewer components. - return isPathRelativeToParent(maybeNonRelative) || countPathComponents(relativePath) < countPathComponents(maybeNonRelative) ? relativePath : maybeNonRelative; + return isPathRelativeToParent(maybeNonRelative) + || countPathComponents(relativePath) < countPathComponents(maybeNonRelative) ? relativePath + : maybeNonRelative; } /** @internal */ @@ -549,51 +727,65 @@ export function forEachFileNameOfModule( importedFileName: string, host: ModuleSpecifierResolutionHost, preferSymlinks: boolean, - cb: (fileName: string, isRedirect: boolean) => T | undefined + cb: (fileName: string, isRedirect: boolean) => T | undefined, ): T | undefined { const getCanonicalFileName = hostGetCanonicalFileName(host); const cwd = host.getCurrentDirectory(); - const referenceRedirect = host.isSourceOfProjectReferenceRedirect(importedFileName) ? host.getProjectReferenceRedirect(importedFileName) : undefined; + const referenceRedirect = host.isSourceOfProjectReferenceRedirect(importedFileName) + ? host.getProjectReferenceRedirect(importedFileName) : undefined; const importedPath = toPath(importedFileName, cwd, getCanonicalFileName); const redirects = host.redirectTargetsMap.get(importedPath) || emptyArray; - const importedFileNames = [...(referenceRedirect ? [referenceRedirect] : emptyArray), importedFileName, ...redirects]; + const importedFileNames = [ + ...(referenceRedirect ? [referenceRedirect] : emptyArray), + importedFileName, + ...redirects, + ]; const targets = importedFileNames.map(f => getNormalizedAbsolutePath(f, cwd)); let shouldFilterIgnoredPaths = !every(targets, containsIgnoredPath); if (!preferSymlinks) { // Symlinks inside ignored paths are already filtered out of the symlink cache, // so we only need to remove them from the realpath filenames. - const result = forEach(targets, p => !(shouldFilterIgnoredPaths && containsIgnoredPath(p)) && cb(p, referenceRedirect === p)); + const result = forEach( + targets, + p => !(shouldFilterIgnoredPaths && containsIgnoredPath(p)) && cb(p, referenceRedirect === p), + ); if (result) return result; } const symlinkedDirectories = host.getSymlinkCache?.().getSymlinkedDirectoriesByRealpath(); const fullImportedFileName = getNormalizedAbsolutePath(importedFileName, cwd); - const result = symlinkedDirectories && forEachAncestorDirectory(getDirectoryPath(fullImportedFileName), realPathDirectory => { - const symlinkDirectories = symlinkedDirectories.get(ensureTrailingDirectorySeparator(toPath(realPathDirectory, cwd, getCanonicalFileName))); - if (!symlinkDirectories) return undefined; // Continue to ancestor directory - - // Don't want to a package to globally import from itself (importNameCodeFix_symlink_own_package.ts) - if (startsWithDirectory(importingFileName, realPathDirectory, getCanonicalFileName)) { - return false; // Stop search, each ancestor directory will also hit this condition - } + const result = symlinkedDirectories + && forEachAncestorDirectory(getDirectoryPath(fullImportedFileName), realPathDirectory => { + const symlinkDirectories = symlinkedDirectories.get( + ensureTrailingDirectorySeparator(toPath(realPathDirectory, cwd, getCanonicalFileName)), + ); + if (!symlinkDirectories) return undefined; // Continue to ancestor directory - return forEach(targets, target => { - if (!startsWithDirectory(target, realPathDirectory, getCanonicalFileName)) { - return; + // Don't want to a package to globally import from itself (importNameCodeFix_symlink_own_package.ts) + if (startsWithDirectory(importingFileName, realPathDirectory, getCanonicalFileName)) { + return false; // Stop search, each ancestor directory will also hit this condition } - const relative = getRelativePathFromDirectory(realPathDirectory, target, getCanonicalFileName); - for (const symlinkDirectory of symlinkDirectories) { - const option = resolvePath(symlinkDirectory, relative); - const result = cb(option, target === referenceRedirect); - shouldFilterIgnoredPaths = true; // We found a non-ignored path in symlinks, so we can reject ignored-path realpaths - if (result) return result; - } + return forEach(targets, target => { + if (!startsWithDirectory(target, realPathDirectory, getCanonicalFileName)) { + return; + } + + const relative = getRelativePathFromDirectory(realPathDirectory, target, getCanonicalFileName); + for (const symlinkDirectory of symlinkDirectories) { + const option = resolvePath(symlinkDirectory, relative); + const result = cb(option, target === referenceRedirect); + shouldFilterIgnoredPaths = true; // We found a non-ignored path in symlinks, so we can reject ignored-path realpaths + if (result) return result; + } + }); }); - }); return result || (preferSymlinks - ? forEach(targets, p => shouldFilterIgnoredPaths && containsIgnoredPath(p) ? undefined : cb(p, p === referenceRedirect)) + ? forEach( + targets, + p => shouldFilterIgnoredPaths && containsIgnoredPath(p) ? undefined : cb(p, p === referenceRedirect), + ) : undefined); } @@ -621,9 +813,13 @@ function getAllModulePaths( return modulePaths; } -function getAllModulePathsWorker(importingFileName: Path, importedFileName: string, host: ModuleSpecifierResolutionHost): readonly ModulePath[] { +function getAllModulePathsWorker( + importingFileName: Path, + importedFileName: string, + host: ModuleSpecifierResolutionHost, +): readonly ModulePath[] { const getCanonicalFileName = hostGetCanonicalFileName(host); - const allFileNames = new Map(); + const allFileNames = new Map(); let importedFileFromNodeModules = false; forEachFileNameOfModule( importingFileName, @@ -635,7 +831,7 @@ function getAllModulePathsWorker(importingFileName: Path, importedFileName: stri allFileNames.set(path, { path: getCanonicalFileName(path), isRedirect, isInNodeModules }); importedFileFromNodeModules = importedFileFromNodeModules || isInNodeModules; // don't return value, so we collect everything - } + }, ); // Sort by paths closest to importing file Name directory @@ -673,8 +869,10 @@ function getAllModulePathsWorker(importingFileName: Path, importedFileName: stri function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol, checker: TypeChecker): string | undefined { const decl = moduleSymbol.declarations?.find( - d => isNonGlobalAmbientModule(d) && (!isExternalModuleAugmentation(d) || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name))) - ) as (ModuleDeclaration & { name: StringLiteral }) | undefined; + d => isNonGlobalAmbientModule(d) + && (!isExternalModuleAugmentation(d) + || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name))), + ) as (ModuleDeclaration & { name: StringLiteral; }) | undefined; if (decl) { return decl.name.text; } @@ -689,34 +887,46 @@ function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol, checker: TypeCh * } */ // `import {c} from "m";` is valid, in which case, `moduleSymbol` is "ns", but the module name should be "m" - const ambientModuleDeclareCandidates = mapDefined(moduleSymbol.declarations, - d => { - if (!isModuleDeclaration(d)) return; - const topNamespace = getTopNamespace(d); - if (!(topNamespace?.parent?.parent - && isModuleBlock(topNamespace.parent) && isAmbientModule(topNamespace.parent.parent) && isSourceFile(topNamespace.parent.parent.parent))) return; - const exportAssignment = ((topNamespace.parent.parent.symbol.exports?.get("export=" as __String)?.valueDeclaration as ExportAssignment)?.expression as PropertyAccessExpression | Identifier); - if (!exportAssignment) return; - const exportSymbol = checker.getSymbolAtLocation(exportAssignment); - if (!exportSymbol) return; - const originalExportSymbol = exportSymbol?.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(exportSymbol) : exportSymbol; - if (originalExportSymbol === d.symbol) return topNamespace.parent.parent; - - function getTopNamespace(namespaceDeclaration: ModuleDeclaration) { - while (namespaceDeclaration.flags & NodeFlags.NestedNamespace) { - namespaceDeclaration = namespaceDeclaration.parent as ModuleDeclaration; - } - return namespaceDeclaration; + const ambientModuleDeclareCandidates = mapDefined(moduleSymbol.declarations, d => { + if (!isModuleDeclaration(d)) return; + const topNamespace = getTopNamespace(d); + if ( + !(topNamespace?.parent?.parent + && isModuleBlock(topNamespace.parent) + && isAmbientModule(topNamespace.parent.parent) + && isSourceFile(topNamespace.parent.parent.parent)) + ) return; + const exportAssignment = (topNamespace.parent.parent.symbol.exports?.get("export=" as __String) + ?.valueDeclaration as ExportAssignment)?.expression as PropertyAccessExpression | Identifier; + if (!exportAssignment) return; + const exportSymbol = checker.getSymbolAtLocation(exportAssignment); + if (!exportSymbol) return; + const originalExportSymbol = exportSymbol?.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(exportSymbol) + : exportSymbol; + if (originalExportSymbol === d.symbol) return topNamespace.parent.parent; + + function getTopNamespace(namespaceDeclaration: ModuleDeclaration) { + while (namespaceDeclaration.flags & NodeFlags.NestedNamespace) { + namespaceDeclaration = namespaceDeclaration.parent as ModuleDeclaration; } + return namespaceDeclaration; } - ); - const ambientModuleDeclare = ambientModuleDeclareCandidates[0] as (AmbientModuleDeclaration & { name: StringLiteral }) | undefined; + }); + const ambientModuleDeclare = ambientModuleDeclareCandidates[0] as + | (AmbientModuleDeclaration & { name: StringLiteral; }) + | undefined; if (ambientModuleDeclare) { return ambientModuleDeclare.name.text; } } -function tryGetModuleNameFromPaths(relativeToBaseUrl: string, paths: MapLike, allowedEndings: ModuleSpecifierEnding[], host: ModuleSpecifierResolutionHost, compilerOptions: CompilerOptions): string | undefined { +function tryGetModuleNameFromPaths( + relativeToBaseUrl: string, + paths: MapLike, + allowedEndings: ModuleSpecifierEnding[], + host: ModuleSpecifierResolutionHost, + compilerOptions: CompilerOptions, +): string | undefined { for (const key in paths) { for (const patternText of paths[key]) { const pattern = normalizePath(patternText); @@ -757,10 +967,12 @@ function tryGetModuleNameFromPaths(relativeToBaseUrl: string, paths: MapLike ({ - ending, - value: processEnding(relativeToBaseUrl, [ending], compilerOptions) - })); + const candidates: { ending: ModuleSpecifierEnding | undefined; value: string; }[] = allowedEndings.map( + ending => ({ + ending, + value: processEnding(relativeToBaseUrl, [ending], compilerOptions), + }), + ); if (tryGetExtensionFromPath(pattern)) { candidates.push({ ending: undefined, value: relativeToBaseUrl }); } @@ -769,10 +981,11 @@ function tryGetModuleNameFromPaths(relativeToBaseUrl: string, paths: MapLike= prefix.length + suffix.length && - startsWith(value, prefix) && - endsWith(value, suffix) && - validateEnding({ ending, value }) + if ( + value.length >= prefix.length + suffix.length + && startsWith(value, prefix) + && endsWith(value, suffix) + && validateEnding({ ending, value }) ) { const matchedStar = value.substring(prefix.length, value.length - suffix.length); if (!pathIsRelative(matchedStar)) { @@ -782,15 +995,18 @@ function tryGetModuleNameFromPaths(relativeToBaseUrl: string, paths: MapLike c.ending !== ModuleSpecifierEnding.Minimal && pattern === c.value) || - some(candidates, c => c.ending === ModuleSpecifierEnding.Minimal && pattern === c.value && validateEnding(c)) + some(candidates, c => c.ending !== ModuleSpecifierEnding.Minimal && pattern === c.value) + || some( + candidates, + c => c.ending === ModuleSpecifierEnding.Minimal && pattern === c.value && validateEnding(c), + ) ) { return key; } } } - function validateEnding({ ending, value }: { ending: ModuleSpecifierEnding | undefined, value: string }) { + function validateEnding({ ending, value }: { ending: ModuleSpecifierEnding | undefined; value: string; }) { // Optimization: `removeExtensionAndIndexPostFix` can query the file system (a good bit) if `ending` is `Minimal`, the basename // is 'index', and a `host` is provided. To avoid that until it's unavoidable, we ran the function with no `host` above. Only // here, after we've checked that the minimal ending is indeed a match (via the length and prefix/suffix checks / `some` calls), @@ -798,30 +1014,52 @@ function tryGetModuleNameFromPaths(relativeToBaseUrl: string, paths: MapLike tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, packageName, e, conditions)); + return forEach( + exports, + e => tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, packageName, e, conditions), + ); } else if (typeof exports === "object" && exports !== null) { // eslint-disable-line no-null/no-null if (allKeysStartWithDot(exports as MapLike)) { @@ -850,19 +1100,40 @@ function tryGetModuleNameFromExports(options: CompilerOptions, targetFilePath: s // * pattern mappings (contains a *) // * exact mappings (no *, does not end with /) return forEach(getOwnKeys(exports as MapLike), k => { - const subPackageName = getNormalizedAbsolutePath(combinePaths(packageName, k), /*currentDirectory*/ undefined); + const subPackageName = getNormalizedAbsolutePath( + combinePaths(packageName, k), + /*currentDirectory*/ undefined, + ); const mode = endsWith(k, "/") ? MatchingMode.Directory : stringContains(k, "*") ? MatchingMode.Pattern : MatchingMode.Exact; - return tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, subPackageName, (exports as MapLike)[k], conditions, mode); + return tryGetModuleNameFromExports( + options, + targetFilePath, + packageDirectory, + subPackageName, + (exports as MapLike)[k], + conditions, + mode, + ); }); } else { // conditional mapping for (const key of getOwnKeys(exports as MapLike)) { - if (key === "default" || conditions.indexOf(key) >= 0 || isApplicableVersionedTypesKey(conditions, key)) { + if ( + key === "default" || conditions.indexOf(key) >= 0 || isApplicableVersionedTypesKey(conditions, key) + ) { const subTarget = (exports as MapLike)[key]; - const result = tryGetModuleNameFromExports(options, targetFilePath, packageDirectory, packageName, subTarget, conditions, mode); + const result = tryGetModuleNameFromExports( + options, + targetFilePath, + packageDirectory, + packageName, + subTarget, + conditions, + mode, + ); if (result) { return result; } @@ -873,7 +1144,14 @@ function tryGetModuleNameFromExports(options: CompilerOptions, targetFilePath: s return undefined; } -function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string, allowedEndings: readonly ModuleSpecifierEnding[], compilerOptions: CompilerOptions): string | undefined { +function tryGetModuleNameFromRootDirs( + rootDirs: readonly string[], + moduleFileName: string, + sourceDirectory: string, + getCanonicalFileName: (file: string) => string, + allowedEndings: readonly ModuleSpecifierEnding[], + compilerOptions: CompilerOptions, +): string | undefined { const normalizedTargetPaths = getPathsRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName); if (normalizedTargetPaths === undefined) { return undefined; @@ -881,7 +1159,11 @@ function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileNam const normalizedSourcePaths = getPathsRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName); const relativePaths = flatMap(normalizedSourcePaths, sourcePath => { - return map(normalizedTargetPaths, targetPath => ensurePathIsNonModuleName(getRelativePathFromDirectory(sourcePath, targetPath, getCanonicalFileName))); + return map( + normalizedTargetPaths, + targetPath => + ensurePathIsNonModuleName(getRelativePathFromDirectory(sourcePath, targetPath, getCanonicalFileName)), + ); }); const shortest = min(relativePaths, compareNumberOfDirectorySeparators); if (!shortest) { @@ -890,7 +1172,16 @@ function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileNam return processEnding(shortest, allowedEndings, compilerOptions); } -function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCanonicalFileName, sourceDirectory }: Info, importingSourceFile: SourceFile, host: ModuleSpecifierResolutionHost, options: CompilerOptions, userPreferences: UserPreferences, packageNameOnly?: boolean, overrideMode?: ResolutionMode): string | undefined { +function tryGetModuleNameAsNodeModule( + { path, isRedirect }: ModulePath, + { getCanonicalFileName, sourceDirectory }: Info, + importingSourceFile: SourceFile, + host: ModuleSpecifierResolutionHost, + options: CompilerOptions, + userPreferences: UserPreferences, + packageNameOnly?: boolean, + overrideMode?: ResolutionMode, +): string | undefined { if (!host.fileExists || !host.readFile) { return undefined; } @@ -910,7 +1201,8 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan let moduleFileName: string | undefined; while (true) { // If the module could be imported by a directory name, use that directory's name - const { moduleFileToTry, packageRootPath, blockedByExports, verbatimFromExports } = tryDirectoryWithPackageJson(packageRootIndex); + const { moduleFileToTry, packageRootPath, blockedByExports, verbatimFromExports } = + tryDirectoryWithPackageJson(packageRootIndex); if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Classic) { if (blockedByExports) { return undefined; // File is under this package.json, but is not publicly exported - there's no way to name it via `node_modules` resolution @@ -942,8 +1234,14 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan const globalTypingsCacheLocation = host.getGlobalTypingsCacheLocation && host.getGlobalTypingsCacheLocation(); // Get a path that's relative to node_modules or the importing file's path // if node_modules folder is in this folder or any of its parent folders, no need to keep it. - const pathToTopLevelNodeModules = getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex)); - if (!(startsWith(sourceDirectory, pathToTopLevelNodeModules) || globalTypingsCacheLocation && startsWith(getCanonicalFileName(globalTypingsCacheLocation), pathToTopLevelNodeModules))) { + const pathToTopLevelNodeModules = getCanonicalFileName( + moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex), + ); + if ( + !(startsWith(sourceDirectory, pathToTopLevelNodeModules) + || globalTypingsCacheLocation + && startsWith(getCanonicalFileName(globalTypingsCacheLocation), pathToTopLevelNodeModules)) + ) { return undefined; } @@ -951,16 +1249,22 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1); const packageName = getPackageNameFromTypesPackageName(nodeModulesDirectoryName); // For classic resolution, only allow importing from node_modules/@types, not other node_modules - return getEmitModuleResolutionKind(options) === ModuleResolutionKind.Classic && packageName === nodeModulesDirectoryName ? undefined : packageName; + return getEmitModuleResolutionKind(options) === ModuleResolutionKind.Classic + && packageName === nodeModulesDirectoryName ? undefined : packageName; - function tryDirectoryWithPackageJson(packageRootIndex: number): { moduleFileToTry: string, packageRootPath?: string, blockedByExports?: true, verbatimFromExports?: true } { + function tryDirectoryWithPackageJson( + packageRootIndex: number, + ): { moduleFileToTry: string; packageRootPath?: string; blockedByExports?: true; verbatimFromExports?: true; } { const packageRootPath = path.substring(0, packageRootIndex); const packageJsonPath = combinePaths(packageRootPath, "package.json"); let moduleFileToTry = path; let maybeBlockedByTypesVersions = false; const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath); - if (typeof cachedPackageJson === "object" || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) { - const packageJsonContent = cachedPackageJson?.contents.packageJsonContent || JSON.parse(host.readFile!(packageJsonPath)!); + if ( + typeof cachedPackageJson === "object" || cachedPackageJson === undefined && host.fileExists(packageJsonPath) + ) { + const packageJsonContent = cachedPackageJson?.contents.packageJsonContent + || JSON.parse(host.readFile!(packageJsonPath)!); const importMode = overrideMode || importingSourceFile.impliedNodeFormat; if (getResolvePackageJsonExports(options)) { // The package name that we found in node_modules could be different from the package @@ -970,12 +1274,22 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan const packageName = getPackageNameFromTypesPackageName(nodeModulesDirectoryName); const conditions = getConditions(options, importMode === ModuleKind.ESNext); const fromExports = packageJsonContent.exports - ? tryGetModuleNameFromExports(options, path, packageRootPath, packageName, packageJsonContent.exports, conditions) + ? tryGetModuleNameFromExports( + options, + path, + packageRootPath, + packageName, + packageJsonContent.exports, + conditions, + ) : undefined; if (fromExports) { const withJsExtension = !hasTSFileExtension(fromExports.moduleFileToTry) ? fromExports - : { moduleFileToTry: removeFileExtension(fromExports.moduleFileToTry) + tryGetJSExtensionForFile(fromExports.moduleFileToTry, options) }; + : { + moduleFileToTry: removeFileExtension(fromExports.moduleFileToTry) + + tryGetJSExtensionForFile(fromExports.moduleFileToTry, options), + }; return { ...withJsExtension, verbatimFromExports: true }; } if (packageJsonContent.exports) { @@ -992,7 +1306,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan versionPaths.paths, allowedEndings, host, - options + options, ); if (fromPaths === undefined) { maybeBlockedByTypesVersions = true; @@ -1002,8 +1316,13 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan } } // If the file is the main module, it can be imported by the package name - const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main || "index.js"; - if (isString(mainFileRelative) && !(maybeBlockedByTypesVersions && matchPatternOrExact(tryParsePatterns(versionPaths!.paths), mainFileRelative))) { + const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main + || "index.js"; + if ( + isString(mainFileRelative) + && !(maybeBlockedByTypesVersions + && matchPatternOrExact(tryParsePatterns(versionPaths!.paths), mainFileRelative)) + ) { // The 'main' file is also subject to mapping through typesVersions, and we couldn't come up with a path // explicitly through typesVersions, so if it matches a key in typesVersions now, it's not reachable. // (The only way this can happen is if some file in a package that's not resolvable from outside the @@ -1017,11 +1336,11 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan return { packageRootPath, moduleFileToTry }; } else if ( - packageJsonContent.type !== "module" && - !fileExtensionIsOneOf(canonicalModuleFileToTry, extensionsNotSupportingExtensionlessResolution) && - startsWith(canonicalModuleFileToTry, mainExportFile) && - getDirectoryPath(canonicalModuleFileToTry) === removeTrailingDirectorySeparator(mainExportFile) && - removeFileExtension(getBaseFileName(canonicalModuleFileToTry)) === "index" + packageJsonContent.type !== "module" + && !fileExtensionIsOneOf(canonicalModuleFileToTry, extensionsNotSupportingExtensionlessResolution) + && startsWith(canonicalModuleFileToTry, mainExportFile) + && getDirectoryPath(canonicalModuleFileToTry) === removeTrailingDirectorySeparator(mainExportFile) + && removeFileExtension(getBaseFileName(canonicalModuleFileToTry)) === "index" ) { // if mainExportFile is a directory, which contains moduleFileToTry, we just try index file // example mainExportFile: `pkg/lib` and moduleFileToTry: `pkg/lib/index`, we can use packageRootPath @@ -1034,7 +1353,10 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan else { // No package.json exists; an index.js will still resolve as the package name const fileName = getCanonicalFileName(moduleFileToTry.substring(parts.packageRootIndex + 1)); - if (fileName === "index.d.ts" || fileName === "index.js" || fileName === "index.ts" || fileName === "index.tsx") { + if ( + fileName === "index.d.ts" || fileName === "index.js" || fileName === "index.ts" + || fileName === "index.tsx" + ) { return { moduleFileToTry, packageRootPath }; } } @@ -1045,7 +1367,13 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan function tryGetAnyFileFromPath(host: ModuleSpecifierResolutionHost, path: string) { if (!host.fileExists) return; // We check all js, `node` and `json` extensions in addition to TS, since node module resolution would also choose those over the directory - const extensions = flatten(getSupportedExtensions({ allowJs: true }, [{ extension: "node", isMixedContent: false }, { extension: "json", isMixedContent: false, scriptKind: ScriptKind.JSON }])); + const extensions = flatten( + getSupportedExtensions({ allowJs: true }, [{ extension: "node", isMixedContent: false }, { + extension: "json", + isMixedContent: false, + scriptKind: ScriptKind.JSON, + }]), + ); for (const e of extensions) { const fullPath = path + e; if (host.fileExists(fullPath)) { @@ -1054,14 +1382,23 @@ function tryGetAnyFileFromPath(host: ModuleSpecifierResolutionHost, path: string } } -function getPathsRelativeToRootDirs(path: string, rootDirs: readonly string[], getCanonicalFileName: GetCanonicalFileName): string[] | undefined { +function getPathsRelativeToRootDirs( + path: string, + rootDirs: readonly string[], + getCanonicalFileName: GetCanonicalFileName, +): string[] | undefined { return mapDefined(rootDirs, rootDir => { const relativePath = getRelativePathIfInSameVolume(path, rootDir, getCanonicalFileName); return relativePath !== undefined && isPathRelativeToParent(relativePath) ? undefined : relativePath; }); } -function processEnding(fileName: string, allowedEndings: readonly ModuleSpecifierEnding[], options: CompilerOptions, host?: ModuleSpecifierResolutionHost): string { +function processEnding( + fileName: string, + allowedEndings: readonly ModuleSpecifierEnding[], + options: CompilerOptions, + host?: ModuleSpecifierResolutionHost, +): string { if (fileExtensionIsOneOf(fileName, [Extension.Json, Extension.Mjs, Extension.Cjs])) { return fileName; } @@ -1073,13 +1410,18 @@ function processEnding(fileName: string, allowedEndings: readonly ModuleSpecifie const jsPriority = allowedEndings.indexOf(ModuleSpecifierEnding.JsExtension); const tsPriority = allowedEndings.indexOf(ModuleSpecifierEnding.TsExtension); - if (fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Cts]) && tsPriority !== -1 && tsPriority < jsPriority) { + if ( + fileExtensionIsOneOf(fileName, [Extension.Mts, Extension.Cts]) && tsPriority !== -1 && tsPriority < jsPriority + ) { return fileName; } else if (fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Dcts, Extension.Cts])) { return noExtension + getJSExtensionForFile(fileName, options); } - else if (!fileExtensionIsOneOf(fileName, [Extension.Dts]) && fileExtensionIsOneOf(fileName, [Extension.Ts]) && stringContains(fileName, ".d.")) { + else if ( + !fileExtensionIsOneOf(fileName, [Extension.Dts]) && fileExtensionIsOneOf(fileName, [Extension.Ts]) + && stringContains(fileName, ".d.") + ) { // `foo.d.json.ts` and the like - remap back to `foo.json` return tryGetRealFileNameForNonJsDeclarationFileName(fileName)!; } @@ -1101,7 +1443,9 @@ function processEnding(fileName: string, allowedEndings: readonly ModuleSpecifie // For now, we don't know if this import is going to be type-only, which means we don't // know if a .d.ts extension is valid, so use no extension or a .js extension if (isDeclarationFileName(fileName)) { - const extensionlessPriority = allowedEndings.findIndex(e => e === ModuleSpecifierEnding.Minimal || e === ModuleSpecifierEnding.Index); + const extensionlessPriority = allowedEndings.findIndex(e => + e === ModuleSpecifierEnding.Minimal || e === ModuleSpecifierEnding.Index + ); return extensionlessPriority !== -1 && extensionlessPriority < jsPriority ? noExtension : noExtension + getJSExtensionForFile(fileName, options); @@ -1115,14 +1459,18 @@ function processEnding(fileName: string, allowedEndings: readonly ModuleSpecifie /** @internal */ export function tryGetRealFileNameForNonJsDeclarationFileName(fileName: string) { const baseName = getBaseFileName(fileName); - if (!endsWith(fileName, Extension.Ts) || !stringContains(baseName, ".d.") || fileExtensionIsOneOf(baseName, [Extension.Dts])) return undefined; + if ( + !endsWith(fileName, Extension.Ts) || !stringContains(baseName, ".d.") + || fileExtensionIsOneOf(baseName, [Extension.Dts]) + ) return undefined; const noExtension = removeExtension(fileName, Extension.Ts); const ext = noExtension.substring(noExtension.lastIndexOf(".")); return noExtension.substring(0, noExtension.indexOf(".d.")) + ext; } function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension { - return tryGetJSExtensionForFile(fileName, options) ?? Debug.fail(`Extension ${extensionFromPath(fileName)} is unsupported:: FileName:: ${fileName}`); + return tryGetJSExtensionForFile(fileName, options) + ?? Debug.fail(`Extension ${extensionFromPath(fileName)} is unsupported:: FileName:: ${fileName}`); } /** @internal */ @@ -1151,8 +1499,18 @@ export function tryGetJSExtensionForFile(fileName: string, options: CompilerOpti } } -function getRelativePathIfInSameVolume(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined { - const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); +function getRelativePathIfInSameVolume( + path: string, + directoryPath: string, + getCanonicalFileName: GetCanonicalFileName, +): string | undefined { + const relativePath = getRelativePathToDirectoryOrUrl( + directoryPath, + path, + directoryPath, + getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false, + ); return isRootedDiskPath(relativePath) ? undefined : relativePath; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 103a1b08fa837..7ae5b429c57bb 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -403,7 +403,7 @@ const enum SignatureFlags { None = 0, Yield = 1 << 0, Await = 1 << 1, - Type = 1 << 2, + Type = 1 << 2, IgnoreMissingOpenBrace = 1 << 4, JSDoc = 1 << 5, } @@ -411,7 +411,7 @@ const enum SignatureFlags { const enum SpeculationKind { TryParse, Lookahead, - Reparse + Reparse, } let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; @@ -426,21 +426,42 @@ let SourceFileConstructor: new (kind: SyntaxKind.SourceFile, pos: number, end: n * @internal */ export const parseBaseNodeFactory: BaseNodeFactory = { - createBaseSourceFileNode: kind => new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, -1, -1), - createBaseIdentifierNode: kind => new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, -1, -1), - createBasePrivateIdentifierNode: kind => new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1), - createBaseTokenNode: kind => new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1), - createBaseNode: kind => new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1), + createBaseSourceFileNode: kind => + new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))( + kind, + -1, + -1, + ), + createBaseIdentifierNode: kind => + new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))( + kind, + -1, + -1, + ), + createBasePrivateIdentifierNode: kind => + new (PrivateIdentifierConstructor + || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, -1, -1), + createBaseTokenNode: kind => + new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, -1, -1), + createBaseNode: kind => + new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, -1, -1), }; /** @internal */ -export const parseNodeFactory: NodeFactory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules, parseBaseNodeFactory); +export const parseNodeFactory: NodeFactory = createNodeFactory( + NodeFactoryFlags.NoParenthesizerRules, + parseBaseNodeFactory, +); function visitNode(cbNode: (node: Node) => T, node: Node | undefined): T | undefined { return node && cbNode(node); } -function visitNodes(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray) => T | undefined) | undefined, nodes: NodeArray | undefined): T | undefined { +function visitNodes( + cbNode: (node: Node) => T, + cbNodes: ((node: NodeArray) => T | undefined) | undefined, + nodes: NodeArray | undefined, +): T | undefined { if (nodes) { if (cbNodes) { return cbNodes(nodes); @@ -456,31 +477,31 @@ function visitNodes(cbNode: (node: Node) => T, cbNodes: ((node: NodeArray = (node: TNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined) => T | undefined; -type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction }; +type ForEachChildFunction = ( + node: TNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +) => T | undefined; +type ForEachChildTable = { [TNode in ForEachChildNodes as TNode["kind"]]: ForEachChildFunction; }; const forEachChildTable: ForEachChildTable = { - [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName(node: QualifiedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.left) || - visitNode(cbNode, node.right); + [SyntaxKind.QualifiedName]: function forEachChildInQualifiedName( + node: QualifiedName, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.left) + || visitNode(cbNode, node.right); }, - [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter(node: TypeParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.constraint) || - visitNode(cbNode, node.default) || - visitNode(cbNode, node.expression); + [SyntaxKind.TypeParameter]: function forEachChildInTypeParameter( + node: TypeParameterDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.constraint) + || visitNode(cbNode, node.default) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment(node: ShorthandPropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.exclamationToken) || - visitNode(cbNode, node.equalsToken) || - visitNode(cbNode, node.objectAssignmentInitializer); + [SyntaxKind.ShorthandPropertyAssignment]: function forEachChildInShorthandPropertyAssignment( + node: ShorthandPropertyAssignment, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.exclamationToken) + || visitNode(cbNode, node.equalsToken) + || visitNode(cbNode, node.objectAssignmentInitializer); }, - [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment(node: SpreadAssignment, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.SpreadAssignment]: function forEachChildInSpreadAssignment( + node: SpreadAssignment, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.Parameter]: function forEachChildInParameter(node: ParameterDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.dotDotDotToken) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.initializer); + [SyntaxKind.Parameter]: function forEachChildInParameter( + node: ParameterDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.dotDotDotToken) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration(node: PropertyDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.exclamationToken) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.initializer); + [SyntaxKind.PropertyDeclaration]: function forEachChildInPropertyDeclaration( + node: PropertyDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.exclamationToken) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature(node: PropertySignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.initializer); + [SyntaxKind.PropertySignature]: function forEachChildInPropertySignature( + node: PropertySignature, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment(node: PropertyAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.exclamationToken) || - visitNode(cbNode, node.initializer); + [SyntaxKind.PropertyAssignment]: function forEachChildInPropertyAssignment( + node: PropertyAssignment, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.exclamationToken) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration(node: VariableDeclaration, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.exclamationToken) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.initializer); + [SyntaxKind.VariableDeclaration]: function forEachChildInVariableDeclaration( + node: VariableDeclaration, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.exclamationToken) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.BindingElement]: function forEachChildInBindingElement(node: BindingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.dotDotDotToken) || - visitNode(cbNode, node.propertyName) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.initializer); + [SyntaxKind.BindingElement]: function forEachChildInBindingElement( + node: BindingElement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.dotDotDotToken) + || visitNode(cbNode, node.propertyName) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature(node: IndexSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.IndexSignature]: function forEachChildInIndexSignature( + node: IndexSignatureDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.ConstructorType]: function forEachChildInConstructorType(node: ConstructorTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.ConstructorType]: function forEachChildInConstructorType( + node: ConstructorTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.FunctionType]: function forEachChildInFunctionType(node: FunctionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.FunctionType]: function forEachChildInFunctionType( + node: FunctionTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, [SyntaxKind.CallSignature]: forEachChildInCallOrConstructSignature, [SyntaxKind.ConstructSignature]: forEachChildInCallOrConstructSignature, - [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration(node: MethodDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.asteriskToken) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.exclamationToken) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.MethodDeclaration]: function forEachChildInMethodDeclaration( + node: MethodDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.asteriskToken) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.exclamationToken) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature(node: MethodSignature, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.MethodSignature]: function forEachChildInMethodSignature( + node: MethodSignature, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.Constructor]: function forEachChildInConstructor(node: ConstructorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.Constructor]: function forEachChildInConstructor( + node: ConstructorDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor(node: GetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.GetAccessor]: function forEachChildInGetAccessor( + node: GetAccessorDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor(node: SetAccessorDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.SetAccessor]: function forEachChildInSetAccessor( + node: SetAccessorDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration(node: FunctionDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.asteriskToken) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.FunctionDeclaration]: function forEachChildInFunctionDeclaration( + node: FunctionDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.asteriskToken) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression(node: FunctionExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.asteriskToken) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.body); + [SyntaxKind.FunctionExpression]: function forEachChildInFunctionExpression( + node: FunctionExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.asteriskToken) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.body); }, - [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction(node: ArrowFunction, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type) || - visitNode(cbNode, node.equalsGreaterThanToken) || - visitNode(cbNode, node.body); + [SyntaxKind.ArrowFunction]: function forEachChildInArrowFunction( + node: ArrowFunction, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type) + || visitNode(cbNode, node.equalsGreaterThanToken) + || visitNode(cbNode, node.body); }, - [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.body); + [SyntaxKind.ClassStaticBlockDeclaration]: function forEachChildInClassStaticBlockDeclaration( + node: ClassStaticBlockDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.body); }, - [SyntaxKind.TypeReference]: function forEachChildInTypeReference(node: TypeReferenceNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.typeName) || - visitNodes(cbNode, cbNodes, node.typeArguments); + [SyntaxKind.TypeReference]: function forEachChildInTypeReference( + node: TypeReferenceNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.typeName) + || visitNodes(cbNode, cbNodes, node.typeArguments); }, - [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate(node: TypePredicateNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.assertsModifier) || - visitNode(cbNode, node.parameterName) || - visitNode(cbNode, node.type); + [SyntaxKind.TypePredicate]: function forEachChildInTypePredicate( + node: TypePredicateNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.assertsModifier) + || visitNode(cbNode, node.parameterName) + || visitNode(cbNode, node.type); }, - [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery(node: TypeQueryNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.exprName) || - visitNodes(cbNode, cbNodes, node.typeArguments); + [SyntaxKind.TypeQuery]: function forEachChildInTypeQuery( + node: TypeQueryNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.exprName) + || visitNodes(cbNode, cbNodes, node.typeArguments); }, - [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral(node: TypeLiteralNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.TypeLiteral]: function forEachChildInTypeLiteral( + node: TypeLiteralNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.members); }, - [SyntaxKind.ArrayType]: function forEachChildInArrayType(node: ArrayTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ArrayType]: function forEachChildInArrayType( + node: ArrayTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.elementType); }, - [SyntaxKind.TupleType]: function forEachChildInTupleType(node: TupleTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.TupleType]: function forEachChildInTupleType( + node: TupleTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); }, [SyntaxKind.UnionType]: forEachChildInUnionOrIntersectionType, [SyntaxKind.IntersectionType]: forEachChildInUnionOrIntersectionType, - [SyntaxKind.ConditionalType]: function forEachChildInConditionalType(node: ConditionalTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.checkType) || - visitNode(cbNode, node.extendsType) || - visitNode(cbNode, node.trueType) || - visitNode(cbNode, node.falseType); + [SyntaxKind.ConditionalType]: function forEachChildInConditionalType( + node: ConditionalTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.checkType) + || visitNode(cbNode, node.extendsType) + || visitNode(cbNode, node.trueType) + || visitNode(cbNode, node.falseType); }, - [SyntaxKind.InferType]: function forEachChildInInferType(node: InferTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.InferType]: function forEachChildInInferType( + node: InferTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.typeParameter); }, - [SyntaxKind.ImportType]: function forEachChildInImportType(node: ImportTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.argument) || - visitNode(cbNode, node.assertions) || - visitNode(cbNode, node.qualifier) || - visitNodes(cbNode, cbNodes, node.typeArguments); + [SyntaxKind.ImportType]: function forEachChildInImportType( + node: ImportTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.argument) + || visitNode(cbNode, node.assertions) + || visitNode(cbNode, node.qualifier) + || visitNodes(cbNode, cbNodes, node.typeArguments); }, - [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer(node: ImportTypeAssertionContainer, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ImportTypeAssertionContainer]: function forEachChildInImportTypeAssertionContainer( + node: ImportTypeAssertionContainer, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.assertClause); }, [SyntaxKind.ParenthesizedType]: forEachChildInParenthesizedTypeOrTypeOperator, [SyntaxKind.TypeOperator]: forEachChildInParenthesizedTypeOrTypeOperator, - [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType(node: IndexedAccessTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.objectType) || - visitNode(cbNode, node.indexType); + [SyntaxKind.IndexedAccessType]: function forEachChildInIndexedAccessType( + node: IndexedAccessTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.objectType) + || visitNode(cbNode, node.indexType); }, - [SyntaxKind.MappedType]: function forEachChildInMappedType(node: MappedTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.readonlyToken) || - visitNode(cbNode, node.typeParameter) || - visitNode(cbNode, node.nameType) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.type) || - visitNodes(cbNode, cbNodes, node.members); + [SyntaxKind.MappedType]: function forEachChildInMappedType( + node: MappedTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.readonlyToken) + || visitNode(cbNode, node.typeParameter) + || visitNode(cbNode, node.nameType) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.type) + || visitNodes(cbNode, cbNodes, node.members); }, - [SyntaxKind.LiteralType]: function forEachChildInLiteralType(node: LiteralTypeNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.LiteralType]: function forEachChildInLiteralType( + node: LiteralTypeNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.literal); }, - [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember(node: NamedTupleMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.dotDotDotToken) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.type); + [SyntaxKind.NamedTupleMember]: function forEachChildInNamedTupleMember( + node: NamedTupleMember, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.dotDotDotToken) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.type); }, [SyntaxKind.ObjectBindingPattern]: forEachChildInObjectOrArrayBindingPattern, [SyntaxKind.ArrayBindingPattern]: forEachChildInObjectOrArrayBindingPattern, - [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression(node: ArrayLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ArrayLiteralExpression]: function forEachChildInArrayLiteralExpression( + node: ArrayLiteralExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); }, - [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression(node: ObjectLiteralExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ObjectLiteralExpression]: function forEachChildInObjectLiteralExpression( + node: ObjectLiteralExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.properties); }, - [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression(node: PropertyAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.questionDotToken) || - visitNode(cbNode, node.name); + [SyntaxKind.PropertyAccessExpression]: function forEachChildInPropertyAccessExpression( + node: PropertyAccessExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.questionDotToken) + || visitNode(cbNode, node.name); }, - [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression(node: ElementAccessExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.questionDotToken) || - visitNode(cbNode, node.argumentExpression); + [SyntaxKind.ElementAccessExpression]: function forEachChildInElementAccessExpression( + node: ElementAccessExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.questionDotToken) + || visitNode(cbNode, node.argumentExpression); }, [SyntaxKind.CallExpression]: forEachChildInCallOrNewExpression, [SyntaxKind.NewExpression]: forEachChildInCallOrNewExpression, - [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression(node: TaggedTemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tag) || - visitNode(cbNode, node.questionDotToken) || - visitNodes(cbNode, cbNodes, node.typeArguments) || - visitNode(cbNode, node.template); + [SyntaxKind.TaggedTemplateExpression]: function forEachChildInTaggedTemplateExpression( + node: TaggedTemplateExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tag) + || visitNode(cbNode, node.questionDotToken) + || visitNodes(cbNode, cbNodes, node.typeArguments) + || visitNode(cbNode, node.template); }, - [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression(node: TypeAssertion, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.type) || - visitNode(cbNode, node.expression); + [SyntaxKind.TypeAssertionExpression]: function forEachChildInTypeAssertionExpression( + node: TypeAssertion, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.type) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression(node: ParenthesizedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ParenthesizedExpression]: function forEachChildInParenthesizedExpression( + node: ParenthesizedExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression(node: DeleteExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.DeleteExpression]: function forEachChildInDeleteExpression( + node: DeleteExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression(node: TypeOfExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.TypeOfExpression]: function forEachChildInTypeOfExpression( + node: TypeOfExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression(node: VoidExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.VoidExpression]: function forEachChildInVoidExpression( + node: VoidExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression(node: PrefixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.PrefixUnaryExpression]: function forEachChildInPrefixUnaryExpression( + node: PrefixUnaryExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.operand); }, - [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression(node: YieldExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.asteriskToken) || - visitNode(cbNode, node.expression); + [SyntaxKind.YieldExpression]: function forEachChildInYieldExpression( + node: YieldExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.asteriskToken) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression(node: AwaitExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.AwaitExpression]: function forEachChildInAwaitExpression( + node: AwaitExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression(node: PostfixUnaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.PostfixUnaryExpression]: function forEachChildInPostfixUnaryExpression( + node: PostfixUnaryExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.operand); }, - [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression(node: BinaryExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.left) || - visitNode(cbNode, node.operatorToken) || - visitNode(cbNode, node.right); + [SyntaxKind.BinaryExpression]: function forEachChildInBinaryExpression( + node: BinaryExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.left) + || visitNode(cbNode, node.operatorToken) + || visitNode(cbNode, node.right); }, - [SyntaxKind.AsExpression]: function forEachChildInAsExpression(node: AsExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.type); + [SyntaxKind.AsExpression]: function forEachChildInAsExpression( + node: AsExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.type); }, - [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression(node: NonNullExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.NonNullExpression]: function forEachChildInNonNullExpression( + node: NonNullExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression(node: SatisfiesExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.SatisfiesExpression]: function forEachChildInSatisfiesExpression( + node: SatisfiesExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression) || visitNode(cbNode, node.type); }, - [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty(node: MetaProperty, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.MetaProperty]: function forEachChildInMetaProperty( + node: MetaProperty, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); }, - [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression(node: ConditionalExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.condition) || - visitNode(cbNode, node.questionToken) || - visitNode(cbNode, node.whenTrue) || - visitNode(cbNode, node.colonToken) || - visitNode(cbNode, node.whenFalse); + [SyntaxKind.ConditionalExpression]: function forEachChildInConditionalExpression( + node: ConditionalExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.condition) + || visitNode(cbNode, node.questionToken) + || visitNode(cbNode, node.whenTrue) + || visitNode(cbNode, node.colonToken) + || visitNode(cbNode, node.whenFalse); }, - [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement(node: SpreadElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.SpreadElement]: function forEachChildInSpreadElement( + node: SpreadElement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, [SyntaxKind.Block]: forEachChildInBlock, [SyntaxKind.ModuleBlock]: forEachChildInBlock, - [SyntaxKind.SourceFile]: function forEachChildInSourceFile(node: SourceFile, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.statements) || - visitNode(cbNode, node.endOfFileToken); + [SyntaxKind.SourceFile]: function forEachChildInSourceFile( + node: SourceFile, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.statements) + || visitNode(cbNode, node.endOfFileToken); }, - [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement(node: VariableStatement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.declarationList); + [SyntaxKind.VariableStatement]: function forEachChildInVariableStatement( + node: VariableStatement, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.declarationList); }, - [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList(node: VariableDeclarationList, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.VariableDeclarationList]: function forEachChildInVariableDeclarationList( + node: VariableDeclarationList, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.declarations); }, - [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement(node: ExpressionStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ExpressionStatement]: function forEachChildInExpressionStatement( + node: ExpressionStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.IfStatement]: function forEachChildInIfStatement(node: IfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.thenStatement) || - visitNode(cbNode, node.elseStatement); + [SyntaxKind.IfStatement]: function forEachChildInIfStatement( + node: IfStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.thenStatement) + || visitNode(cbNode, node.elseStatement); }, - [SyntaxKind.DoStatement]: function forEachChildInDoStatement(node: DoStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.statement) || - visitNode(cbNode, node.expression); + [SyntaxKind.DoStatement]: function forEachChildInDoStatement( + node: DoStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.statement) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement(node: WhileStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.statement); + [SyntaxKind.WhileStatement]: function forEachChildInWhileStatement( + node: WhileStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.ForStatement]: function forEachChildInForStatement(node: ForStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.initializer) || - visitNode(cbNode, node.condition) || - visitNode(cbNode, node.incrementor) || - visitNode(cbNode, node.statement); + [SyntaxKind.ForStatement]: function forEachChildInForStatement( + node: ForStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.initializer) + || visitNode(cbNode, node.condition) + || visitNode(cbNode, node.incrementor) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.ForInStatement]: function forEachChildInForInStatement(node: ForInStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.initializer) || - visitNode(cbNode, node.expression) || - visitNode(cbNode, node.statement); + [SyntaxKind.ForInStatement]: function forEachChildInForInStatement( + node: ForInStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.initializer) + || visitNode(cbNode, node.expression) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement(node: ForOfStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.awaitModifier) || - visitNode(cbNode, node.initializer) || - visitNode(cbNode, node.expression) || - visitNode(cbNode, node.statement); + [SyntaxKind.ForOfStatement]: function forEachChildInForOfStatement( + node: ForOfStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.awaitModifier) + || visitNode(cbNode, node.initializer) + || visitNode(cbNode, node.expression) + || visitNode(cbNode, node.statement); }, [SyntaxKind.ContinueStatement]: forEachChildInContinueOrBreakStatement, [SyntaxKind.BreakStatement]: forEachChildInContinueOrBreakStatement, - [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement(node: ReturnStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ReturnStatement]: function forEachChildInReturnStatement( + node: ReturnStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.WithStatement]: function forEachChildInWithStatement(node: WithStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.statement); + [SyntaxKind.WithStatement]: function forEachChildInWithStatement( + node: WithStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement(node: SwitchStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.caseBlock); + [SyntaxKind.SwitchStatement]: function forEachChildInSwitchStatement( + node: SwitchStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.caseBlock); }, - [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock(node: CaseBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.CaseBlock]: function forEachChildInCaseBlock( + node: CaseBlock, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.clauses); }, - [SyntaxKind.CaseClause]: function forEachChildInCaseClause(node: CaseClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNodes(cbNode, cbNodes, node.statements); + [SyntaxKind.CaseClause]: function forEachChildInCaseClause( + node: CaseClause, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNodes(cbNode, cbNodes, node.statements); }, - [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause(node: DefaultClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.DefaultClause]: function forEachChildInDefaultClause( + node: DefaultClause, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.statements); }, - [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement(node: LabeledStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.label) || - visitNode(cbNode, node.statement); + [SyntaxKind.LabeledStatement]: function forEachChildInLabeledStatement( + node: LabeledStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.label) + || visitNode(cbNode, node.statement); }, - [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement(node: ThrowStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ThrowStatement]: function forEachChildInThrowStatement( + node: ThrowStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.TryStatement]: function forEachChildInTryStatement(node: TryStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tryBlock) || - visitNode(cbNode, node.catchClause) || - visitNode(cbNode, node.finallyBlock); + [SyntaxKind.TryStatement]: function forEachChildInTryStatement( + node: TryStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tryBlock) + || visitNode(cbNode, node.catchClause) + || visitNode(cbNode, node.finallyBlock); }, - [SyntaxKind.CatchClause]: function forEachChildInCatchClause(node: CatchClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.variableDeclaration) || - visitNode(cbNode, node.block); + [SyntaxKind.CatchClause]: function forEachChildInCatchClause( + node: CatchClause, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.variableDeclaration) + || visitNode(cbNode, node.block); }, - [SyntaxKind.Decorator]: function forEachChildInDecorator(node: Decorator, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.Decorator]: function forEachChildInDecorator( + node: Decorator, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, [SyntaxKind.ClassDeclaration]: forEachChildInClassDeclarationOrExpression, [SyntaxKind.ClassExpression]: forEachChildInClassDeclarationOrExpression, - [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration(node: InterfaceDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.heritageClauses) || - visitNodes(cbNode, cbNodes, node.members); + [SyntaxKind.InterfaceDeclaration]: function forEachChildInInterfaceDeclaration( + node: InterfaceDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.heritageClauses) + || visitNodes(cbNode, cbNodes, node.members); }, - [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration(node: TypeAliasDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNode(cbNode, node.type); + [SyntaxKind.TypeAliasDeclaration]: function forEachChildInTypeAliasDeclaration( + node: TypeAliasDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration(node: EnumDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.members); + [SyntaxKind.EnumDeclaration]: function forEachChildInEnumDeclaration( + node: EnumDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.members); }, - [SyntaxKind.EnumMember]: function forEachChildInEnumMember(node: EnumMember, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.initializer); + [SyntaxKind.EnumMember]: function forEachChildInEnumMember( + node: EnumMember, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration(node: ModuleDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.body); + [SyntaxKind.ModuleDeclaration]: function forEachChildInModuleDeclaration( + node: ModuleDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.body); }, - [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration(node: ImportEqualsDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNode(cbNode, node.moduleReference); + [SyntaxKind.ImportEqualsDeclaration]: function forEachChildInImportEqualsDeclaration( + node: ImportEqualsDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNode(cbNode, node.moduleReference); }, - [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration(node: ImportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.importClause) || - visitNode(cbNode, node.moduleSpecifier) || - visitNode(cbNode, node.assertClause); + [SyntaxKind.ImportDeclaration]: function forEachChildInImportDeclaration( + node: ImportDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.importClause) + || visitNode(cbNode, node.moduleSpecifier) + || visitNode(cbNode, node.assertClause); }, - [SyntaxKind.ImportClause]: function forEachChildInImportClause(node: ImportClause, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.namedBindings); + [SyntaxKind.ImportClause]: function forEachChildInImportClause( + node: ImportClause, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.namedBindings); }, - [SyntaxKind.AssertClause]: function forEachChildInAssertClause(node: AssertClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.AssertClause]: function forEachChildInAssertClause( + node: AssertClause, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); }, - [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry(node: AssertEntry, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.value); + [SyntaxKind.AssertEntry]: function forEachChildInAssertEntry( + node: AssertEntry, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.value); }, - [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration(node: NamespaceExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name); + [SyntaxKind.NamespaceExportDeclaration]: function forEachChildInNamespaceExportDeclaration( + node: NamespaceExportDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name); }, - [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport(node: NamespaceImport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.NamespaceImport]: function forEachChildInNamespaceImport( + node: NamespaceImport, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); }, - [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport(node: NamespaceExport, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.NamespaceExport]: function forEachChildInNamespaceExport( + node: NamespaceExport, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); }, [SyntaxKind.NamedImports]: forEachChildInNamedImportsOrExports, [SyntaxKind.NamedExports]: forEachChildInNamedImportsOrExports, - [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration(node: ExportDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.exportClause) || - visitNode(cbNode, node.moduleSpecifier) || - visitNode(cbNode, node.assertClause); + [SyntaxKind.ExportDeclaration]: function forEachChildInExportDeclaration( + node: ExportDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.exportClause) + || visitNode(cbNode, node.moduleSpecifier) + || visitNode(cbNode, node.assertClause); }, [SyntaxKind.ImportSpecifier]: forEachChildInImportOrExportSpecifier, [SyntaxKind.ExportSpecifier]: forEachChildInImportOrExportSpecifier, - [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment(node: ExportAssignment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.expression); + [SyntaxKind.ExportAssignment]: function forEachChildInExportAssignment( + node: ExportAssignment, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression(node: TemplateExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.head) || - visitNodes(cbNode, cbNodes, node.templateSpans); + [SyntaxKind.TemplateExpression]: function forEachChildInTemplateExpression( + node: TemplateExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.head) + || visitNodes(cbNode, cbNodes, node.templateSpans); }, - [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan(node: TemplateSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNode(cbNode, node.literal); + [SyntaxKind.TemplateSpan]: function forEachChildInTemplateSpan( + node: TemplateSpan, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNode(cbNode, node.literal); }, - [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType(node: TemplateLiteralTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.head) || - visitNodes(cbNode, cbNodes, node.templateSpans); + [SyntaxKind.TemplateLiteralType]: function forEachChildInTemplateLiteralType( + node: TemplateLiteralTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.head) + || visitNodes(cbNode, cbNodes, node.templateSpans); }, - [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.type) || - visitNode(cbNode, node.literal); + [SyntaxKind.TemplateLiteralTypeSpan]: function forEachChildInTemplateLiteralTypeSpan( + node: TemplateLiteralTypeSpan, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.type) + || visitNode(cbNode, node.literal); }, - [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName(node: ComputedPropertyName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ComputedPropertyName]: function forEachChildInComputedPropertyName( + node: ComputedPropertyName, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause(node: HeritageClause, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.HeritageClause]: function forEachChildInHeritageClause( + node: HeritageClause, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.types); }, - [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments(node: ExpressionWithTypeArguments, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || - visitNodes(cbNode, cbNodes, node.typeArguments); + [SyntaxKind.ExpressionWithTypeArguments]: function forEachChildInExpressionWithTypeArguments( + node: ExpressionWithTypeArguments, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.expression) + || visitNodes(cbNode, cbNodes, node.typeArguments); }, - [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference(node: ExternalModuleReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.ExternalModuleReference]: function forEachChildInExternalModuleReference( + node: ExternalModuleReference, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration(node: MissingDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.MissingDeclaration]: function forEachChildInMissingDeclaration( + node: MissingDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.modifiers); }, - [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression(node: CommaListExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.CommaListExpression]: function forEachChildInCommaListExpression( + node: CommaListExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); }, - [SyntaxKind.JsxElement]: function forEachChildInJsxElement(node: JsxElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.openingElement) || - visitNodes(cbNode, cbNodes, node.children) || - visitNode(cbNode, node.closingElement); + [SyntaxKind.JsxElement]: function forEachChildInJsxElement( + node: JsxElement, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.openingElement) + || visitNodes(cbNode, cbNodes, node.children) + || visitNode(cbNode, node.closingElement); }, - [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment(node: JsxFragment, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.openingFragment) || - visitNodes(cbNode, cbNodes, node.children) || - visitNode(cbNode, node.closingFragment); + [SyntaxKind.JsxFragment]: function forEachChildInJsxFragment( + node: JsxFragment, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.openingFragment) + || visitNodes(cbNode, cbNodes, node.children) + || visitNode(cbNode, node.closingFragment); }, [SyntaxKind.JsxSelfClosingElement]: forEachChildInJsxOpeningOrSelfClosingElement, [SyntaxKind.JsxOpeningElement]: forEachChildInJsxOpeningOrSelfClosingElement, - [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes(node: JsxAttributes, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JsxAttributes]: function forEachChildInJsxAttributes( + node: JsxAttributes, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNodes(cbNode, cbNodes, node.properties); }, - [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute(node: JsxAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.name) || - visitNode(cbNode, node.initializer); + [SyntaxKind.JsxAttribute]: function forEachChildInJsxAttribute( + node: JsxAttribute, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.name) + || visitNode(cbNode, node.initializer); }, - [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute(node: JsxSpreadAttribute, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JsxSpreadAttribute]: function forEachChildInJsxSpreadAttribute( + node: JsxSpreadAttribute, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.expression); }, - [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression(node: JsxExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.dotDotDotToken) || - visitNode(cbNode, node.expression); + [SyntaxKind.JsxExpression]: function forEachChildInJsxExpression( + node: JsxExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.dotDotDotToken) + || visitNode(cbNode, node.expression); }, - [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement(node: JsxClosingElement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JsxClosingElement]: function forEachChildInJsxClosingElement( + node: JsxClosingElement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.tagName); }, - [SyntaxKind.JsxNamespacedName]: function forEachChildInJsxNamespacedName(node: JsxNamespacedName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.namespace) || - visitNode(cbNode, node.name); + [SyntaxKind.JsxNamespacedName]: function forEachChildInJsxNamespacedName( + node: JsxNamespacedName, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.namespace) + || visitNode(cbNode, node.name); }, [SyntaxKind.OptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, [SyntaxKind.RestType]: forEachChildInOptionalRestOrJSDocParameterModifier, @@ -1042,64 +1511,108 @@ const forEachChildTable: ForEachChildTable = { [SyntaxKind.JSDocNullableType]: forEachChildInOptionalRestOrJSDocParameterModifier, [SyntaxKind.JSDocOptionalType]: forEachChildInOptionalRestOrJSDocParameterModifier, [SyntaxKind.JSDocVariadicType]: forEachChildInOptionalRestOrJSDocParameterModifier, - [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType(node: JSDocFunctionType, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); + [SyntaxKind.JSDocFunctionType]: function forEachChildInJSDocFunctionType( + node: JSDocFunctionType, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); }, - [SyntaxKind.JSDoc]: function forEachChildInJSDoc(node: JSDoc, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JSDoc]: function forEachChildInJSDoc( + node: JSDoc, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) || visitNodes(cbNode, cbNodes, node.tags); }, - [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag(node: JSDocSeeTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.name) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocSeeTag]: function forEachChildInJSDocSeeTag( + node: JSDocSeeTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.name) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference(node: JSDocNameReference, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JSDocNameReference]: function forEachChildInJSDocNameReference( + node: JSDocNameReference, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return visitNode(cbNode, node.name); }, - [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName(node: JSDocMemberName, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.left) || - visitNode(cbNode, node.right); + [SyntaxKind.JSDocMemberName]: function forEachChildInJSDocMemberName( + node: JSDocMemberName, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.left) + || visitNode(cbNode, node.right); }, [SyntaxKind.JSDocParameterTag]: forEachChildInJSDocParameterOrPropertyTag, [SyntaxKind.JSDocPropertyTag]: forEachChildInJSDocParameterOrPropertyTag, - [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag(node: JSDocAuthorTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocAuthorTag]: function forEachChildInJSDocAuthorTag( + node: JSDocAuthorTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag(node: JSDocImplementsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.class) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocImplementsTag]: function forEachChildInJSDocImplementsTag( + node: JSDocImplementsTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.class) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag(node: JSDocAugmentsTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.class) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocAugmentsTag]: function forEachChildInJSDocAugmentsTag( + node: JSDocAugmentsTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.class) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag(node: JSDocTemplateTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.constraint) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocTemplateTag]: function forEachChildInJSDocTemplateTag( + node: JSDocTemplateTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.constraint) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, - [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag(node: JSDocTypedefTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - (node.typeExpression && - node.typeExpression.kind === SyntaxKind.JSDocTypeExpression - ? visitNode(cbNode, node.typeExpression) || - visitNode(cbNode, node.fullName) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) - : visitNode(cbNode, node.fullName) || - visitNode(cbNode, node.typeExpression) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))); + [SyntaxKind.JSDocTypedefTag]: function forEachChildInJSDocTypedefTag( + node: JSDocTypedefTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || (node.typeExpression + && node.typeExpression.kind === SyntaxKind.JSDocTypeExpression + ? visitNode(cbNode, node.typeExpression) + || visitNode(cbNode, node.fullName) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)) + : visitNode(cbNode, node.fullName) + || visitNode(cbNode, node.typeExpression) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment))); }, - [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag(node: JSDocCallbackTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.fullName) || - visitNode(cbNode, node.typeExpression) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + [SyntaxKind.JSDocCallbackTag]: function forEachChildInJSDocCallbackTag( + node: JSDocCallbackTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.fullName) + || visitNode(cbNode, node.typeExpression) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); }, [SyntaxKind.JSDocReturnTag]: forEachChildInJSDocTypeLikeTag, [SyntaxKind.JSDocTypeTag]: forEachChildInJSDocTypeLikeTag, @@ -1108,15 +1621,23 @@ const forEachChildTable: ForEachChildTable = { [SyntaxKind.JSDocSatisfiesTag]: forEachChildInJSDocTypeLikeTag, [SyntaxKind.JSDocThrowsTag]: forEachChildInJSDocTypeLikeTag, [SyntaxKind.JSDocOverloadTag]: forEachChildInJSDocTypeLikeTag, - [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature(node: JSDocSignature, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return forEach(node.typeParameters, cbNode) || - forEach(node.parameters, cbNode) || - visitNode(cbNode, node.type); + [SyntaxKind.JSDocSignature]: function forEachChildInJSDocSignature( + node: JSDocSignature, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { + return forEach(node.typeParameters, cbNode) + || forEach(node.parameters, cbNode) + || visitNode(cbNode, node.type); }, [SyntaxKind.JSDocLink]: forEachChildInJSDocLinkCodeOrPlain, [SyntaxKind.JSDocLinkCode]: forEachChildInJSDocLinkCodeOrPlain, [SyntaxKind.JSDocLinkPlain]: forEachChildInJSDocLinkCodeOrPlain, - [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral(node: JSDocTypeLiteral, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { + [SyntaxKind.JSDocTypeLiteral]: function forEachChildInJSDocTypeLiteral( + node: JSDocTypeLiteral, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, + ): T | undefined { return forEach(node.jsDocPropertyTags, cbNode); }, [SyntaxKind.JSDocTag]: forEachChildInJSDocTag, @@ -1132,91 +1653,181 @@ const forEachChildTable: ForEachChildTable = { // shared -function forEachChildInCallOrConstructSignature(node: CallSignatureDeclaration | ConstructSignatureDeclaration, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.parameters) || - visitNode(cbNode, node.type); +function forEachChildInCallOrConstructSignature( + node: CallSignatureDeclaration | ConstructSignatureDeclaration, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { + return visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.parameters) + || visitNode(cbNode, node.type); } -function forEachChildInUnionOrIntersectionType(node: UnionTypeNode | IntersectionTypeNode, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInUnionOrIntersectionType( + node: UnionTypeNode | IntersectionTypeNode, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNodes(cbNode, cbNodes, node.types); } -function forEachChildInParenthesizedTypeOrTypeOperator(node: ParenthesizedTypeNode | TypeOperatorNode, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInParenthesizedTypeOrTypeOperator( + node: ParenthesizedTypeNode | TypeOperatorNode, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNode(cbNode, node.type); } -function forEachChildInObjectOrArrayBindingPattern(node: BindingPattern, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInObjectOrArrayBindingPattern( + node: BindingPattern, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); } -function forEachChildInCallOrNewExpression(node: CallExpression | NewExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.expression) || +function forEachChildInCallOrNewExpression( + node: CallExpression | NewExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { + return visitNode(cbNode, node.expression) // TODO: should we separate these branches out? - visitNode(cbNode, (node as CallExpression).questionDotToken) || - visitNodes(cbNode, cbNodes, node.typeArguments) || - visitNodes(cbNode, cbNodes, node.arguments); + || visitNode(cbNode, (node as CallExpression).questionDotToken) + || visitNodes(cbNode, cbNodes, node.typeArguments) + || visitNodes(cbNode, cbNodes, node.arguments); } -function forEachChildInBlock(node: Block | ModuleBlock, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInBlock( + node: Block | ModuleBlock, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNodes(cbNode, cbNodes, node.statements); } -function forEachChildInContinueOrBreakStatement(node: ContinueStatement | BreakStatement, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInContinueOrBreakStatement( + node: ContinueStatement | BreakStatement, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNode(cbNode, node.label); } -function forEachChildInClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNodes(cbNode, cbNodes, node.modifiers) || - visitNode(cbNode, node.name) || - visitNodes(cbNode, cbNodes, node.typeParameters) || - visitNodes(cbNode, cbNodes, node.heritageClauses) || - visitNodes(cbNode, cbNodes, node.members); +function forEachChildInClassDeclarationOrExpression( + node: ClassDeclaration | ClassExpression, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { + return visitNodes(cbNode, cbNodes, node.modifiers) + || visitNode(cbNode, node.name) + || visitNodes(cbNode, cbNodes, node.typeParameters) + || visitNodes(cbNode, cbNodes, node.heritageClauses) + || visitNodes(cbNode, cbNodes, node.members); } -function forEachChildInNamedImportsOrExports(node: NamedImports | NamedExports, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInNamedImportsOrExports( + node: NamedImports | NamedExports, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNodes(cbNode, cbNodes, node.elements); } -function forEachChildInImportOrExportSpecifier(node: ImportSpecifier | ExportSpecifier, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.propertyName) || - visitNode(cbNode, node.name); +function forEachChildInImportOrExportSpecifier( + node: ImportSpecifier | ExportSpecifier, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { + return visitNode(cbNode, node.propertyName) + || visitNode(cbNode, node.name); } -function forEachChildInJsxOpeningOrSelfClosingElement(node: JsxOpeningLikeElement, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNodes(cbNode, cbNodes, node.typeArguments) || - visitNode(cbNode, node.attributes); +function forEachChildInJsxOpeningOrSelfClosingElement( + node: JsxOpeningLikeElement, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNodes(cbNode, cbNodes, node.typeArguments) + || visitNode(cbNode, node.attributes); } -function forEachChildInOptionalRestOrJSDocParameterModifier(node: OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocNullableType | JSDocNonNullableType | JSDocOptionalType | JSDocVariadicType, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInOptionalRestOrJSDocParameterModifier( + node: + | OptionalTypeNode + | RestTypeNode + | JSDocTypeExpression + | JSDocNullableType + | JSDocNonNullableType + | JSDocOptionalType + | JSDocVariadicType, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNode(cbNode, node.type); } -function forEachChildInJSDocParameterOrPropertyTag(node: JSDocParameterTag | JSDocPropertyTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - (node.isNameFirst +function forEachChildInJSDocParameterOrPropertyTag( + node: JSDocParameterTag | JSDocPropertyTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { + return visitNode(cbNode, node.tagName) + || (node.isNameFirst ? visitNode(cbNode, node.name) || visitNode(cbNode, node.typeExpression) - : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); + : visitNode(cbNode, node.typeExpression) || visitNode(cbNode, node.name)) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } -function forEachChildInJSDocTypeLikeTag(node: JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocThrowsTag | JSDocOverloadTag | JSDocSatisfiesTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { - return visitNode(cbNode, node.tagName) || - visitNode(cbNode, node.typeExpression) || - (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); +function forEachChildInJSDocTypeLikeTag( + node: + | JSDocReturnTag + | JSDocTypeTag + | JSDocThisTag + | JSDocEnumTag + | JSDocThrowsTag + | JSDocOverloadTag + | JSDocSatisfiesTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { + return visitNode(cbNode, node.tagName) + || visitNode(cbNode, node.typeExpression) + || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } -function forEachChildInJSDocLinkCodeOrPlain(node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInJSDocLinkCodeOrPlain( + node: JSDocLink | JSDocLinkCode | JSDocLinkPlain, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNode(cbNode, node.name); } -function forEachChildInJSDocTag(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInJSDocTag( + node: + | JSDocUnknownTag + | JSDocClassTag + | JSDocPublicTag + | JSDocPrivateTag + | JSDocProtectedTag + | JSDocReadonlyTag + | JSDocDeprecatedTag + | JSDocOverrideTag, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNode(cbNode, node.tagName) || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } -function forEachChildInPartiallyEmittedExpression(node: PartiallyEmittedExpression, cbNode: (node: Node) => T | undefined, _cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInPartiallyEmittedExpression( + node: PartiallyEmittedExpression, + cbNode: (node: Node) => T | undefined, + _cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { return visitNode(cbNode, node.expression); } @@ -1233,7 +1844,11 @@ function forEachChildInPartiallyEmittedExpression(node: PartiallyEmittedExpre * @remarks `forEachChild` must visit the children of a node in the order * that they appear in the source code. The language service depends on this property to locate nodes by position. */ -export function forEachChild(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +export function forEachChild( + node: Node, + cbNode: (node: Node) => T | undefined, + cbNodes?: (nodes: NodeArray) => T | undefined, +): T | undefined { if (node === undefined || node.kind <= SyntaxKind.LastToken) { return; } @@ -1256,7 +1871,11 @@ export function forEachChild(node: Node, cbNode: (node: Node) => T | undefine * * @internal */ -export function forEachChildRecursively(rootNode: Node, cbNode: (node: Node, parent: Node) => T | "skip" | undefined, cbNodes?: (nodes: NodeArray, parent: Node) => T | "skip" | undefined): T | undefined { +export function forEachChildRecursively( + rootNode: Node, + cbNode: (node: Node, parent: Node) => T | "skip" | undefined, + cbNodes?: (nodes: NodeArray, parent: Node) => T | "skip" | undefined, +): T | undefined { const queue: (Node | NodeArray)[] = gatherPossibleChildren(rootNode); const parents: Node[] = []; // tracks parent references for elements in queue while (parents.length < queue.length) { @@ -1327,7 +1946,13 @@ function setExternalModuleIndicator(sourceFile: SourceFile) { sourceFile.externalModuleIndicator = isFileProbablyExternalModule(sourceFile); } -export function createSourceFile(fileName: string, sourceText: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, setParentNodes = false, scriptKind?: ScriptKind): SourceFile { +export function createSourceFile( + fileName: string, + sourceText: string, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + setParentNodes = false, + scriptKind?: ScriptKind, +): SourceFile { tracing?.push(tracing.Phase.Parse, "createSourceFile", { path: fileName }, /*separateBeginAndEnd*/ true); performance.mark("beforeParse"); let result: SourceFile; @@ -1336,17 +1961,34 @@ export function createSourceFile(fileName: string, sourceText: string, languageV const { languageVersion, setExternalModuleIndicator: overrideSetExternalModuleIndicator, - impliedNodeFormat: format - } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions); + impliedNodeFormat: format, + } = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions + : ({ languageVersion: languageVersionOrOptions } as CreateSourceFileOptions); if (languageVersion === ScriptTarget.JSON) { - result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON, noop); + result = Parser.parseSourceFile( + fileName, + sourceText, + languageVersion, + /*syntaxCursor*/ undefined, + setParentNodes, + ScriptKind.JSON, + noop, + ); } else { const setIndicator = format === undefined ? overrideSetExternalModuleIndicator : (file: SourceFile) => { file.impliedNodeFormat = format; return (overrideSetExternalModuleIndicator || setExternalModuleIndicator)(file); }; - result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind, setIndicator); + result = Parser.parseSourceFile( + fileName, + sourceText, + languageVersion, + /*syntaxCursor*/ undefined, + setParentNodes, + scriptKind, + setIndicator, + ); } perfLogger?.logStopParseSourceFile(); @@ -1383,11 +2025,16 @@ export function isExternalModule(file: SourceFile): boolean { // from this SourceFile that are being held onto may change as a result (including // becoming detached from any SourceFile). It is recommended that this SourceFile not // be used once 'update' is called on it. -export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks = false): SourceFile { +export function updateSourceFile( + sourceFile: SourceFile, + newText: string, + textChangeRange: TextChangeRange, + aggressiveChecks = false, +): SourceFile { const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import. // We will manually port the flag to the new source file. - (newSourceFile as Mutable).flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags); + (newSourceFile as Mutable).flags |= sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags; return newSourceFile; } @@ -1427,7 +2074,11 @@ namespace Parser { var NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; var TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; var IdentifierConstructor: new (kind: SyntaxKind.Identifier, pos: number, end: number) => Identifier; - var PrivateIdentifierConstructor: new (kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) => PrivateIdentifier; + var PrivateIdentifierConstructor: new ( + kind: SyntaxKind.PrivateIdentifier, + pos: number, + end: number, + ) => PrivateIdentifier; var SourceFileConstructor: new (kind: SyntaxKind.SourceFile, pos: number, end: number) => SourceFile; function countNode(node: Node) { @@ -1440,12 +2091,16 @@ namespace Parser { var baseNodeFactory: BaseNodeFactory = { createBaseSourceFileNode: kind => countNode(new SourceFileConstructor(kind, /*pos*/ 0, /*end*/ 0)), createBaseIdentifierNode: kind => countNode(new IdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), - createBasePrivateIdentifierNode: kind => countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), + createBasePrivateIdentifierNode: kind => + countNode(new PrivateIdentifierConstructor(kind, /*pos*/ 0, /*end*/ 0)), createBaseTokenNode: kind => countNode(new TokenConstructor(kind, /*pos*/ 0, /*end*/ 0)), - createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0)) + createBaseNode: kind => countNode(new NodeConstructor(kind, /*pos*/ 0, /*end*/ 0)), }; - var factory = createNodeFactory(NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, baseNodeFactory); + var factory = createNodeFactory( + NodeFactoryFlags.NoParenthesizerRules | NodeFactoryFlags.NoNodeConverters | NodeFactoryFlags.NoOriginalNode, + baseNodeFactory, + ); var { createNodeArray: factoryCreateNodeArray, @@ -1578,11 +2233,25 @@ namespace Parser { var parseErrorBeforeNextFinishedNode = false; /* eslint-enable no-var */ - export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind, setExternalModuleIndicatorOverride?: (file: SourceFile) => void): SourceFile { + export function parseSourceFile( + fileName: string, + sourceText: string, + languageVersion: ScriptTarget, + syntaxCursor: IncrementalParser.SyntaxCursor | undefined, + setParentNodes = false, + scriptKind?: ScriptKind, + setExternalModuleIndicatorOverride?: (file: SourceFile) => void, + ): SourceFile { scriptKind = ensureScriptKind(fileName, scriptKind); if (scriptKind === ScriptKind.JSON) { const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes); - convertToJson(result, result.statements[0]?.expression, result.parseDiagnostics, /*returnValue*/ false, /*jsonConversionNotifier*/ undefined); + convertToJson( + result, + result.statements[0]?.expression, + result.parseDiagnostics, + /*returnValue*/ false, + /*jsonConversionNotifier*/ undefined, + ); result.referencedFiles = emptyArray; result.typeReferenceDirectives = emptyArray; result.libReferenceDirectives = emptyArray; @@ -1594,7 +2263,12 @@ namespace Parser { initializeState(fileName, sourceText, languageVersion, syntaxCursor, scriptKind); - const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind, setExternalModuleIndicatorOverride || setExternalModuleIndicator); + const result = parseSourceFileWorker( + languageVersion, + setParentNodes, + scriptKind, + setExternalModuleIndicatorOverride || setExternalModuleIndicator, + ); clearState(); @@ -1612,7 +2286,13 @@ namespace Parser { return isInvalid ? entityName : undefined; } - export function parseJsonText(fileName: string, sourceText: string, languageVersion: ScriptTarget = ScriptTarget.ES2015, syntaxCursor?: IncrementalParser.SyntaxCursor, setParentNodes = false): JsonSourceFile { + export function parseJsonText( + fileName: string, + sourceText: string, + languageVersion: ScriptTarget = ScriptTarget.ES2015, + syntaxCursor?: IncrementalParser.SyntaxCursor, + setParentNodes = false, + ): JsonSourceFile { initializeState(fileName, sourceText, languageVersion, syntaxCursor, ScriptKind.JSON); sourceFlags = contextFlags; @@ -1640,7 +2320,11 @@ namespace Parser { expression = parseTokenNode(); break; case SyntaxKind.MinusToken: - if (lookAhead(() => nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken)) { + if ( + lookAhead(() => + nextToken() === SyntaxKind.NumericLiteral && nextToken() !== SyntaxKind.ColonToken + ) + ) { expression = parsePrefixUnaryExpression() as JsonMinusNumericLiteral; } else { @@ -1674,15 +2358,28 @@ namespace Parser { } } - const expression = isArray(expressions) ? finishNode(factoryCreateArrayLiteralExpression(expressions), pos) : Debug.checkDefined(expressions); + const expression = isArray(expressions) ? finishNode(factoryCreateArrayLiteralExpression(expressions), pos) + : Debug.checkDefined(expressions); const statement = factoryCreateExpressionStatement(expression) as JsonObjectExpressionStatement; finishNode(statement, pos); statements = createNodeArray([statement], pos); - endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token) as EndOfFileToken; + endOfFileToken = parseExpectedToken( + SyntaxKind.EndOfFileToken, + Diagnostics.Unexpected_token, + ) as EndOfFileToken; } // Set source file so that errors will be reported with this file name - const sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclarationFile*/ false, statements, endOfFileToken, sourceFlags, noop); + const sourceFile = createSourceFile( + fileName, + ScriptTarget.ES2015, + ScriptKind.JSON, + /*isDeclarationFile*/ false, + statements, + endOfFileToken, + sourceFlags, + noop, + ); if (setParentNodes) { fixupParentReferences(sourceFile); @@ -1701,7 +2398,13 @@ namespace Parser { return result; } - function initializeState(_fileName: string, _sourceText: string, _languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, _scriptKind: ScriptKind) { + function initializeState( + _fileName: string, + _sourceText: string, + _languageVersion: ScriptTarget, + _syntaxCursor: IncrementalParser.SyntaxCursor | undefined, + _scriptKind: ScriptKind, + ) { NodeConstructor = objectAllocator.getNodeConstructor(); TokenConstructor = objectAllocator.getTokenConstructor(); IdentifierConstructor = objectAllocator.getIdentifierConstructor(); @@ -1765,7 +2468,12 @@ namespace Parser { topLevel = true; } - function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind, setExternalModuleIndicator: (file: SourceFile) => void): SourceFile { + function parseSourceFileWorker( + languageVersion: ScriptTarget, + setParentNodes: boolean, + scriptKind: ScriptKind, + setExternalModuleIndicator: (file: SourceFile) => void, + ): SourceFile { const isDeclarationFile = isDeclarationFileName(fileName); if (isDeclarationFile) { contextFlags |= NodeFlags.Ambient; @@ -1781,7 +2489,16 @@ namespace Parser { const endHasJSDoc = hasPrecedingJSDocComment(); const endOfFileToken = withJSDoc(parseTokenNode(), endHasJSDoc); - const sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile, statements, endOfFileToken, sourceFlags, setExternalModuleIndicator); + const sourceFile = createSourceFile( + fileName, + languageVersion, + scriptKind, + isDeclarationFile, + statements, + endOfFileToken, + sourceFlags, + setExternalModuleIndicator, + ); // A member of ReadonlyArray isn't assignable to a member of T[] (and prevents a direct cast) - but this is where we set up those members so they can be readonly in the future processCommentPragmas(sourceFile as {} as PragmaContext, sourceText); @@ -1814,7 +2531,10 @@ namespace Parser { } Debug.assert(!node.jsDoc); // Should only be called once per node - const jsDoc = mapDefined(getJSDocCommentRanges(node, sourceText), comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos)); + const jsDoc = mapDefined( + getJSDocCommentRanges(node, sourceText), + comment => JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos), + ); if (jsDoc.length) node.jsDoc = jsDoc; if (hasDeprecatedTag) { hasDeprecatedTag = false; @@ -1843,10 +2563,19 @@ namespace Parser { pos = findNextStatementWithoutAwait(sourceFile.statements, start); // append all diagnostics associated with the copied range - const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); - const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= nextStatement.pos, diagnosticStart) : -1; + const diagnosticStart = findIndex( + savedParseDiagnostics, + diagnostic => diagnostic.start >= prevStatement.pos, + ); + const diagnosticEnd = diagnosticStart >= 0 ? findIndex(savedParseDiagnostics, diagnostic => + diagnostic.start >= nextStatement.pos, diagnosticStart) : -1; if (diagnosticStart >= 0) { - addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart, diagnosticEnd >= 0 ? diagnosticEnd : undefined); + addRange( + parseDiagnostics, + savedParseDiagnostics, + diagnosticStart, + diagnosticEnd >= 0 ? diagnosticEnd : undefined, + ); } // reparse all statements between start and pos. We skip existing diagnostics for the same range and allow the parser to generate new ones. @@ -1890,14 +2619,20 @@ namespace Parser { addRange(statements, sourceFile.statements, pos); // append all diagnostics associated with the copied range - const diagnosticStart = findIndex(savedParseDiagnostics, diagnostic => diagnostic.start >= prevStatement.pos); + const diagnosticStart = findIndex( + savedParseDiagnostics, + diagnostic => diagnostic.start >= prevStatement.pos, + ); if (diagnosticStart >= 0) { addRange(parseDiagnostics, savedParseDiagnostics, diagnosticStart); } } syntaxCursor = savedSyntaxCursor; - return factory.updateSourceFile(sourceFile, setTextRange(factoryCreateNodeArray(statements), sourceFile.statements)); + return factory.updateSourceFile( + sourceFile, + setTextRange(factoryCreateNodeArray(statements), sourceFile.statements), + ); function containsPossibleTopLevelAwait(node: Node) { return !(node.flags & NodeFlags.AwaitContext) @@ -1929,7 +2664,6 @@ namespace Parser { } return node; } - } export function fixupParentReferences(rootNode: Node) { @@ -1948,7 +2682,8 @@ namespace Parser { statements: readonly Statement[], endOfFileToken: EndOfFileToken, flags: NodeFlags, - setExternalModuleIndicator: (sourceFile: SourceFile) => void): SourceFile { + setExternalModuleIndicator: (sourceFile: SourceFile) => void, + ): SourceFile { // code from createNode is inlined here so createNode won't have to deal with special case of creating source files // this is quite rare comparing to other nodes and createNode should be as fast as possible let sourceFile = factory.createSourceFile(statements, endOfFileToken, flags); @@ -1956,7 +2691,10 @@ namespace Parser { setFields(sourceFile); // If we parsed this as an external module, it may contain top-level await - if (!isDeclarationFile && isExternalModule(sourceFile) && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait) { + if ( + !isDeclarationFile && isExternalModule(sourceFile) + && sourceFile.transformFlags & TransformFlags.ContainsPossibleTopLevelAwait + ) { sourceFile = reparseTopLevelAwait(sourceFile); setFields(sourceFile); } @@ -2109,11 +2847,19 @@ namespace Parser { return inContext(NodeFlags.AwaitContext); } - function parseErrorAtCurrentToken(message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined { + function parseErrorAtCurrentToken( + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): DiagnosticWithDetachedLocation | undefined { return parseErrorAt(scanner.getTokenStart(), scanner.getTokenEnd(), message, ...args); } - function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined { + function parseErrorAtPosition( + start: number, + length: number, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): DiagnosticWithDetachedLocation | undefined { // Don't report another error if it would just be at the same position as the last error. const lastError = lastOrUndefined(parseDiagnostics); let result: DiagnosticWithDetachedLocation | undefined; @@ -2128,7 +2874,12 @@ namespace Parser { return result; } - function parseErrorAt(start: number, end: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined { + function parseErrorAt( + start: number, + end: number, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): DiagnosticWithDetachedLocation | undefined { return parseErrorAtPosition(start, end - start, message, ...args); } @@ -2171,7 +2922,11 @@ namespace Parser { // if the keyword had an escape if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) { // issue a parse error for the escape - parseErrorAt(scanner.getTokenStart(), scanner.getTokenEnd(), Diagnostics.Keywords_cannot_contain_escape_characters); + parseErrorAt( + scanner.getTokenStart(), + scanner.getTokenEnd(), + Diagnostics.Keywords_cannot_contain_escape_characters, + ); } return nextTokenWithoutCheck(); } @@ -2298,7 +3053,11 @@ namespace Parser { return token() > SyntaxKind.LastReservedWord; } - function parseExpected(kind: PunctuationOrKeywordSyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean { + function parseExpected( + kind: PunctuationOrKeywordSyntaxKind, + diagnosticMessage?: DiagnosticMessage, + shouldAdvance = true, + ): boolean { if (token() === kind) { if (shouldAdvance) { nextToken(); @@ -2329,7 +3088,11 @@ namespace Parser { // module `M1` { // ^^^^^^^^^^^ This block is parsed as a template literal like module`M1`. if (isTaggedTemplateExpression(node)) { - parseErrorAt(skipTrivia(sourceText, node.template.pos), node.template.end, Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings); + parseErrorAt( + skipTrivia(sourceText, node.template.pos), + node.template.end, + Diagnostics.Module_declaration_names_may_only_use_or_quoted_strings, + ); return; } @@ -2355,25 +3118,42 @@ namespace Parser { return; case "interface": - parseErrorForInvalidName(Diagnostics.Interface_name_cannot_be_0, Diagnostics.Interface_must_be_given_a_name, SyntaxKind.OpenBraceToken); + parseErrorForInvalidName( + Diagnostics.Interface_name_cannot_be_0, + Diagnostics.Interface_must_be_given_a_name, + SyntaxKind.OpenBraceToken, + ); return; case "is": - parseErrorAt(pos, scanner.getTokenStart(), Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); + parseErrorAt( + pos, + scanner.getTokenStart(), + Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods, + ); return; case "module": case "namespace": - parseErrorForInvalidName(Diagnostics.Namespace_name_cannot_be_0, Diagnostics.Namespace_must_be_given_a_name, SyntaxKind.OpenBraceToken); + parseErrorForInvalidName( + Diagnostics.Namespace_name_cannot_be_0, + Diagnostics.Namespace_must_be_given_a_name, + SyntaxKind.OpenBraceToken, + ); return; case "type": - parseErrorForInvalidName(Diagnostics.Type_alias_name_cannot_be_0, Diagnostics.Type_alias_must_be_given_a_name, SyntaxKind.EqualsToken); + parseErrorForInvalidName( + Diagnostics.Type_alias_name_cannot_be_0, + Diagnostics.Type_alias_must_be_given_a_name, + SyntaxKind.EqualsToken, + ); return; } // The user alternatively might have misspelled or forgotten to add a space after a common keyword. - const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) ?? getSpaceSuggestion(expressionText); + const suggestion = getSpellingSuggestion(expressionText, viableKeywordSuggestions, n => n) + ?? getSpaceSuggestion(expressionText); if (suggestion) { parseErrorAt(pos, node.end, Diagnostics.Unknown_keyword_or_identifier_Did_you_mean_0, suggestion); return; @@ -2395,7 +3175,11 @@ namespace Parser { * @param nameDiagnostic Diagnostic to report for all other cases. * @param tokenIfBlankName Current token if the name was invalid for being blank (not provided / skipped). */ - function parseErrorForInvalidName(nameDiagnostic: DiagnosticMessage, blankDiagnostic: DiagnosticMessage, tokenIfBlankName: SyntaxKind) { + function parseErrorForInvalidName( + nameDiagnostic: DiagnosticMessage, + blankDiagnostic: DiagnosticMessage, + tokenIfBlankName: SyntaxKind, + ) { if (token() === tokenIfBlankName) { parseErrorAtCurrentToken(blankDiagnostic); } @@ -2414,9 +3198,15 @@ namespace Parser { return undefined; } - function parseSemicolonAfterPropertyName(name: PropertyName, type: TypeNode | undefined, initializer: Expression | undefined) { + function parseSemicolonAfterPropertyName( + name: PropertyName, + type: TypeNode | undefined, + initializer: Expression | undefined, + ) { if (token() === SyntaxKind.AtToken && !scanner.hasPrecedingLineBreak()) { - parseErrorAtCurrentToken(Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations); + parseErrorAtCurrentToken( + Diagnostics.Decorators_must_precede_the_name_and_all_keywords_of_property_declarations, + ); return; } @@ -2458,7 +3248,12 @@ namespace Parser { return false; } - function parseExpectedMatchingBrackets(openKind: PunctuationSyntaxKind, closeKind: PunctuationSyntaxKind, openParsed: boolean, openPosition: number) { + function parseExpectedMatchingBrackets( + openKind: PunctuationSyntaxKind, + closeKind: PunctuationSyntaxKind, + openParsed: boolean, + openPosition: number, + ) { if (token() === closeKind) { nextToken(); return; @@ -2470,7 +3265,15 @@ namespace Parser { if (lastError) { addRelatedInfo( lastError, - createDetachedDiagnostic(fileName, sourceText, openPosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, tokenToString(openKind), tokenToString(closeKind)) + createDetachedDiagnostic( + fileName, + sourceText, + openPosition, + 1, + Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, + tokenToString(openKind), + tokenToString(closeKind), + ), ); } } @@ -2499,10 +3302,19 @@ namespace Parser { return undefined; } - function parseExpectedToken(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: string): Token; + function parseExpectedToken( + t: TKind, + diagnosticMessage?: DiagnosticMessage, + arg0?: string, + ): Token; function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: string): Node { - return parseOptionalToken(t) || - createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)!); + return parseOptionalToken(t) + || createMissingNode( + t, + /*reportAtCurrentPosition*/ false, + diagnosticMessage || Diagnostics._0_expected, + arg0 || tokenToString(t)!, + ); } function parseExpectedTokenJSDoc(t: TKind): Token; @@ -2534,7 +3346,8 @@ namespace Parser { } // We can parse out an optional semicolon in ASI cases in the following cases. - return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); + return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.EndOfFileToken + || scanner.hasPrecedingLineBreak(); } function tryParseSemicolon() { @@ -2554,7 +3367,12 @@ namespace Parser { return tryParseSemicolon() || parseExpected(SyntaxKind.SemicolonToken); } - function createNodeArray(elements: T[], pos: number, end?: number, hasTrailingComma?: boolean): NodeArray { + function createNodeArray( + elements: T[], + pos: number, + end?: number, + hasTrailingComma?: boolean, + ): NodeArray { const array = factoryCreateNodeArray(elements, hasTrailingComma); setTextRangePosEnd(array, pos, end ?? scanner.getTokenFullStart()); return array; @@ -2577,9 +3395,24 @@ namespace Parser { return node; } - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): T; - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, ...args: DiagnosticArguments): T; - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): T { + function createMissingNode( + kind: T["kind"], + reportAtCurrentPosition: false, + diagnosticMessage?: DiagnosticMessage, + ...args: DiagnosticArguments + ): T; + function createMissingNode( + kind: T["kind"], + reportAtCurrentPosition: boolean, + diagnosticMessage: DiagnosticMessage, + ...args: DiagnosticArguments + ): T; + function createMissingNode( + kind: T["kind"], + reportAtCurrentPosition: boolean, + diagnosticMessage?: DiagnosticMessage, + ...args: DiagnosticArguments + ): T { if (reportAtCurrentPosition) { parseErrorAtPosition(scanner.getTokenFullStart(), 0, diagnosticMessage!, ...args); } @@ -2588,13 +3421,13 @@ namespace Parser { } const pos = getNodePos(); - const result = - kind === SyntaxKind.Identifier ? factoryCreateIdentifier("", /*originalKeywordKind*/ undefined) : - isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) : - kind === SyntaxKind.NumericLiteral ? factoryCreateNumericLiteral("", /*numericLiteralFlags*/ undefined) : - kind === SyntaxKind.StringLiteral ? factoryCreateStringLiteral("", /*isSingleQuote*/ undefined) : - kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() : - factoryCreateToken(kind); + const result = kind === SyntaxKind.Identifier ? factoryCreateIdentifier("", /*originalKeywordKind*/ undefined) + : isTemplateLiteralKind(kind) + ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) + : kind === SyntaxKind.NumericLiteral ? factoryCreateNumericLiteral("", /*numericLiteralFlags*/ undefined) + : kind === SyntaxKind.StringLiteral ? factoryCreateStringLiteral("", /*isSingleQuote*/ undefined) + : kind === SyntaxKind.MissingDeclaration ? factory.createMissingDeclaration() + : factoryCreateToken(kind); return finishNode(result, pos) as T; } @@ -2609,7 +3442,11 @@ namespace Parser { // An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues // with magic property names like '__proto__'. The 'identifiers' object is used to share a single string instance for // each identifier in order to reduce memory consumption. - function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { + function createIdentifier( + isIdentifier: boolean, + diagnosticMessage?: DiagnosticMessage, + privateIdentifierDiagnosticMessage?: DiagnosticMessage, + ): Identifier { if (isIdentifier) { identifierCount++; const pos = getNodePos(); @@ -2622,11 +3459,17 @@ namespace Parser { } if (token() === SyntaxKind.PrivateIdentifier) { - parseErrorAtCurrentToken(privateIdentifierDiagnosticMessage || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies); + parseErrorAtCurrentToken( + privateIdentifierDiagnosticMessage + || Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies, + ); return createIdentifier(/*isIdentifier*/ true); } - if (token() === SyntaxKind.Unknown && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier)) { + if ( + token() === SyntaxKind.Unknown + && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.Identifier) + ) { // Scanner has already recorded an 'Invalid character' error, so no need to add another from the parser. return createIdentifier(/*isIdentifier*/ true); } @@ -2638,18 +3481,30 @@ namespace Parser { const isReservedWord = scanner.isReservedWord(); const msgArg = scanner.getTokenText(); - const defaultMessage = isReservedWord ? - Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here : - Diagnostics.Identifier_expected; + const defaultMessage = isReservedWord + ? Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here + : Diagnostics.Identifier_expected; - return createMissingNode(SyntaxKind.Identifier, reportAtCurrentPosition, diagnosticMessage || defaultMessage, msgArg); + return createMissingNode( + SyntaxKind.Identifier, + reportAtCurrentPosition, + diagnosticMessage || defaultMessage, + msgArg, + ); } function parseBindingIdentifier(privateIdentifierDiagnosticMessage?: DiagnosticMessage) { - return createIdentifier(isBindingIdentifier(), /*diagnosticMessage*/ undefined, privateIdentifierDiagnosticMessage); + return createIdentifier( + isBindingIdentifier(), + /*diagnosticMessage*/ undefined, + privateIdentifierDiagnosticMessage, + ); } - function parseIdentifier(diagnosticMessage?: DiagnosticMessage, privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier { + function parseIdentifier( + diagnosticMessage?: DiagnosticMessage, + privateIdentifierDiagnosticMessage?: DiagnosticMessage, + ): Identifier { return createIdentifier(isIdentifier(), diagnosticMessage, privateIdentifierDiagnosticMessage); } @@ -2665,14 +3520,14 @@ namespace Parser { } function isLiteralPropertyName(): boolean { - return tokenIsIdentifierOrKeyword(token()) || - token() === SyntaxKind.StringLiteral || - token() === SyntaxKind.NumericLiteral; + return tokenIsIdentifierOrKeyword(token()) + || token() === SyntaxKind.StringLiteral + || token() === SyntaxKind.NumericLiteral; } function isAssertionKey(): boolean { - return tokenIsIdentifierOrKeyword(token()) || - token() === SyntaxKind.StringLiteral; + return tokenIsIdentifierOrKeyword(token()) + || token() === SyntaxKind.StringLiteral; } function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { @@ -2756,9 +3611,9 @@ namespace Parser { function canFollowExportModifier(): boolean { return token() === SyntaxKind.AtToken || token() !== SyntaxKind.AsteriskToken - && token() !== SyntaxKind.AsKeyword - && token() !== SyntaxKind.OpenBraceToken - && canFollowModifier(); + && token() !== SyntaxKind.AsKeyword + && token() !== SyntaxKind.OpenBraceToken + && canFollowModifier(); } function nextTokenCanFollowExportModifier(): boolean { @@ -2833,7 +3688,8 @@ namespace Parser { case ParsingContext.RestProperties: return isLiteralPropertyName(); case ParsingContext.ObjectBindingElements: - return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName(); + return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken + || isLiteralPropertyName(); case ParsingContext.AssertEntries: return isAssertionKey(); case ParsingContext.HeritageClauseElement: @@ -2855,7 +3711,8 @@ namespace Parser { case ParsingContext.VariableDeclarations: return isBindingIdentifierOrPrivateIdentifierOrPattern(); case ParsingContext.ArrayBindingElements: - return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern(); + return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken + || isBindingIdentifierOrPrivateIdentifierOrPattern(); case ParsingContext.TypeParameters: return token() === SyntaxKind.InKeyword || token() === SyntaxKind.ConstKeyword || isIdentifier(); case ParsingContext.ArrayLiteralMembers: @@ -2908,7 +3765,8 @@ namespace Parser { // extends {} implements const next = nextToken(); - return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; + return next === SyntaxKind.CommaToken || next === SyntaxKind.OpenBraceToken + || next === SyntaxKind.ExtendsKeyword || next === SyntaxKind.ImplementsKeyword; } return true; @@ -2930,9 +3788,10 @@ namespace Parser { } function isHeritageClauseExtendsOrImplementsKeyword(): boolean { - if (token() === SyntaxKind.ImplementsKeyword || - token() === SyntaxKind.ExtendsKeyword) { - + if ( + token() === SyntaxKind.ImplementsKeyword + || token() === SyntaxKind.ExtendsKeyword + ) { return lookAhead(nextTokenIsStartOfExpression); } @@ -2968,14 +3827,18 @@ namespace Parser { case ParsingContext.AssertEntries: return token() === SyntaxKind.CloseBraceToken; case ParsingContext.SwitchClauseStatements: - return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword; + return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword + || token() === SyntaxKind.DefaultKeyword; case ParsingContext.HeritageClauseElement: - return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; + return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword + || token() === SyntaxKind.ImplementsKeyword; case ParsingContext.VariableDeclarations: return isVariableDeclaratorListTerminator(); case ParsingContext.TypeParameters: // Tokens other than '>' are here for better error recovery - return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword; + return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken + || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword + || token() === SyntaxKind.ImplementsKeyword; case ParsingContext.ArgumentExpressions: // Tokens other than ')' are here for better error recovery return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken; @@ -2987,7 +3850,8 @@ namespace Parser { case ParsingContext.Parameters: case ParsingContext.RestProperties: // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery - return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; + return token() === SyntaxKind.CloseParenToken + || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/; case ParsingContext.TypeArguments: // All other tokens should cause the type-argument to terminate except comma token return token() !== SyntaxKind.CommaToken; @@ -3179,54 +4043,53 @@ namespace Parser { case ParsingContext.Parameters: return isReusableParameter(node); - // Any other lists we do not care about reusing nodes in. But feel free to add if - // you can do so safely. Danger areas involve nodes that may involve speculative - // parsing. If speculative parsing is involved with the node, then the range the - // parser reached while looking ahead might be in the edited range (see the example - // in canReuseVariableDeclaratorNode for a good case of this). - - // case ParsingContext.HeritageClauses: - // This would probably be safe to reuse. There is no speculative parsing with - // heritage clauses. - - // case ParsingContext.TypeParameters: - // This would probably be safe to reuse. There is no speculative parsing with - // type parameters. Note that that's because type *parameters* only occur in - // unambiguous *type* contexts. While type *arguments* occur in very ambiguous - // *expression* contexts. - - // case ParsingContext.TupleElementTypes: - // This would probably be safe to reuse. There is no speculative parsing with - // tuple types. - - // Technically, type argument list types are probably safe to reuse. While - // speculative parsing is involved with them (since type argument lists are only - // produced from speculative parsing a < as a type argument list), we only have - // the types because speculative parsing succeeded. Thus, the lookahead never - // went past the end of the list and rewound. - // case ParsingContext.TypeArguments: - - // Note: these are almost certainly not safe to ever reuse. Expressions commonly - // need a large amount of lookahead, and we should not reuse them as they may - // have actually intersected the edit. - // case ParsingContext.ArgumentExpressions: - - // This is not safe to reuse for the same reason as the 'AssignmentExpression' - // cases. i.e. a property assignment may end with an expression, and thus might - // have lookahead far beyond it's old node. - // case ParsingContext.ObjectLiteralMembers: - - // This is probably not safe to reuse. There can be speculative parsing with - // type names in a heritage clause. There can be generic names in the type - // name list, and there can be left hand side expressions (which can have type - // arguments.) - // case ParsingContext.HeritageClauseElement: - - // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes - // on any given element. Same for children. - // case ParsingContext.JsxAttributes: - // case ParsingContext.JsxChildren: - + // Any other lists we do not care about reusing nodes in. But feel free to add if + // you can do so safely. Danger areas involve nodes that may involve speculative + // parsing. If speculative parsing is involved with the node, then the range the + // parser reached while looking ahead might be in the edited range (see the example + // in canReuseVariableDeclaratorNode for a good case of this). + + // case ParsingContext.HeritageClauses: + // This would probably be safe to reuse. There is no speculative parsing with + // heritage clauses. + + // case ParsingContext.TypeParameters: + // This would probably be safe to reuse. There is no speculative parsing with + // type parameters. Note that that's because type *parameters* only occur in + // unambiguous *type* contexts. While type *arguments* occur in very ambiguous + // *expression* contexts. + + // case ParsingContext.TupleElementTypes: + // This would probably be safe to reuse. There is no speculative parsing with + // tuple types. + + // Technically, type argument list types are probably safe to reuse. While + // speculative parsing is involved with them (since type argument lists are only + // produced from speculative parsing a < as a type argument list), we only have + // the types because speculative parsing succeeded. Thus, the lookahead never + // went past the end of the list and rewound. + // case ParsingContext.TypeArguments: + + // Note: these are almost certainly not safe to ever reuse. Expressions commonly + // need a large amount of lookahead, and we should not reuse them as they may + // have actually intersected the edit. + // case ParsingContext.ArgumentExpressions: + + // This is not safe to reuse for the same reason as the 'AssignmentExpression' + // cases. i.e. a property assignment may end with an expression, and thus might + // have lookahead far beyond it's old node. + // case ParsingContext.ObjectLiteralMembers: + + // This is probably not safe to reuse. There can be speculative parsing with + // type names in a heritage clause. There can be generic names in the type + // name list, and there can be left hand side expressions (which can have type + // arguments.) + // case ParsingContext.HeritageClauseElement: + + // Perhaps safe to reuse, but it's unlikely we'd see more than a dozen attributes + // on any given element. Same for children. + // case ParsingContext.JsxAttributes: + // case ParsingContext.JsxChildren: } return false; @@ -3247,8 +4110,8 @@ namespace Parser { // may have a method calls "constructor(...)" and we must reparse that // into an actual .ConstructorDeclaration. const methodDeclaration = node as MethodDeclaration; - const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier && - methodDeclaration.name.escapedText === "constructor"; + const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier + && methodDeclaration.name.escapedText === "constructor"; return !nameIsConstructor; } @@ -3377,50 +4240,93 @@ namespace Parser { return token() === SyntaxKind.DefaultKeyword ? parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.ExportKeyword)) : parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); - case ParsingContext.BlockStatements: return parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); - case ParsingContext.SwitchClauses: return parseErrorAtCurrentToken(Diagnostics.case_or_default_expected); - case ParsingContext.SwitchClauseStatements: return parseErrorAtCurrentToken(Diagnostics.Statement_expected); + case ParsingContext.BlockStatements: + return parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected); + case ParsingContext.SwitchClauses: + return parseErrorAtCurrentToken(Diagnostics.case_or_default_expected); + case ParsingContext.SwitchClauseStatements: + return parseErrorAtCurrentToken(Diagnostics.Statement_expected); case ParsingContext.RestProperties: // fallthrough - case ParsingContext.TypeMembers: return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected); - case ParsingContext.ClassMembers: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected); - case ParsingContext.EnumMembers: return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected); - case ParsingContext.HeritageClauseElement: return parseErrorAtCurrentToken(Diagnostics.Expression_expected); + case ParsingContext.TypeMembers: + return parseErrorAtCurrentToken(Diagnostics.Property_or_signature_expected); + case ParsingContext.ClassMembers: + return parseErrorAtCurrentToken( + Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected, + ); + case ParsingContext.EnumMembers: + return parseErrorAtCurrentToken(Diagnostics.Enum_member_expected); + case ParsingContext.HeritageClauseElement: + return parseErrorAtCurrentToken(Diagnostics.Expression_expected); case ParsingContext.VariableDeclarations: return isKeyword(token()) - ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token())!) + ? parseErrorAtCurrentToken( + Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, + tokenToString(token())!, + ) : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected); - case ParsingContext.ObjectBindingElements: return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected); - case ParsingContext.ArrayBindingElements: return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected); - case ParsingContext.ArgumentExpressions: return parseErrorAtCurrentToken(Diagnostics.Argument_expression_expected); - case ParsingContext.ObjectLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Property_assignment_expected); - case ParsingContext.ArrayLiteralMembers: return parseErrorAtCurrentToken(Diagnostics.Expression_or_comma_expected); - case ParsingContext.JSDocParameters: return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); + case ParsingContext.ObjectBindingElements: + return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected); + case ParsingContext.ArrayBindingElements: + return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected); + case ParsingContext.ArgumentExpressions: + return parseErrorAtCurrentToken(Diagnostics.Argument_expression_expected); + case ParsingContext.ObjectLiteralMembers: + return parseErrorAtCurrentToken(Diagnostics.Property_assignment_expected); + case ParsingContext.ArrayLiteralMembers: + return parseErrorAtCurrentToken(Diagnostics.Expression_or_comma_expected); + case ParsingContext.JSDocParameters: + return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); case ParsingContext.Parameters: return isKeyword(token()) - ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token())!) + ? parseErrorAtCurrentToken( + Diagnostics._0_is_not_allowed_as_a_parameter_name, + tokenToString(token())!, + ) : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); - case ParsingContext.TypeParameters: return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected); - case ParsingContext.TypeArguments: return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected); - case ParsingContext.TupleElementTypes: return parseErrorAtCurrentToken(Diagnostics.Type_expected); - case ParsingContext.HeritageClauses: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected); + case ParsingContext.TypeParameters: + return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected); + case ParsingContext.TypeArguments: + return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected); + case ParsingContext.TupleElementTypes: + return parseErrorAtCurrentToken(Diagnostics.Type_expected); + case ParsingContext.HeritageClauses: + return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected); case ParsingContext.ImportOrExportSpecifiers: if (token() === SyntaxKind.FromKeyword) { return parseErrorAtCurrentToken(Diagnostics._0_expected, "}"); } return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); - case ParsingContext.JsxAttributes: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); - case ParsingContext.JsxChildren: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); - case ParsingContext.AssertEntries: return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey. - case ParsingContext.JSDocComment: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); - case ParsingContext.Count: return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker. - default: Debug.assertNever(context); + case ParsingContext.JsxAttributes: + return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); + case ParsingContext.JsxChildren: + return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); + case ParsingContext.AssertEntries: + return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey. + case ParsingContext.JSDocComment: + return parseErrorAtCurrentToken(Diagnostics.Identifier_expected); + case ParsingContext.Count: + return Debug.fail("ParsingContext.Count used as a context"); // Not a real context, only a marker. + default: + Debug.assertNever(context); } } // Parses a comma-delimited list of elements - function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray; - function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray> | undefined; - function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray> | undefined { + function parseDelimitedList( + kind: ParsingContext, + parseElement: () => T, + considerSemicolonAsDelimiter?: boolean, + ): NodeArray; + function parseDelimitedList( + kind: ParsingContext, + parseElement: () => T, + considerSemicolonAsDelimiter?: boolean, + ): NodeArray> | undefined; + function parseDelimitedList( + kind: ParsingContext, + parseElement: () => T, + considerSemicolonAsDelimiter?: boolean, + ): NodeArray> | undefined { const saveParsingContext = parsingContext; parsingContext |= 1 << kind; const list: NonNullable[] = []; @@ -3457,7 +4363,10 @@ namespace Parser { // parse errors. For example, this can happen when people do things like use // a semicolon to delimit object literal members. Note: we'll have already // reported an error when we called parseExpected above. - if (considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken && !scanner.hasPrecedingLineBreak()) { + if ( + considerSemicolonAsDelimiter && token() === SyntaxKind.SemicolonToken + && !scanner.hasPrecedingLineBreak() + ) { nextToken(); } if (startPos === scanner.getTokenFullStart()) { @@ -3490,7 +4399,8 @@ namespace Parser { } function getExpectedCommaDiagnostic(kind: ParsingContext) { - return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or : undefined; + return kind === ParsingContext.EnumMembers ? Diagnostics.An_enum_member_name_must_be_followed_by_a_or + : undefined; } interface MissingList extends NodeArray { @@ -3507,7 +4417,12 @@ namespace Parser { return !!(arr as MissingList).isMissingList; } - function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: PunctuationSyntaxKind, close: PunctuationSyntaxKind): NodeArray { + function parseBracketedList( + kind: ParsingContext, + parseElement: () => T, + open: PunctuationSyntaxKind, + close: PunctuationSyntaxKind, + ): NodeArray { if (parseExpected(open)) { const result = parseDelimitedList(kind, parseElement); parseExpected(close); @@ -3519,7 +4434,8 @@ namespace Parser { function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { const pos = getNodePos(); - let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage); + let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) + : parseIdentifier(diagnosticMessage); while (parseOptional(SyntaxKind.DotToken)) { if (token() === SyntaxKind.LessThanToken) { // The entity is part of a JSDoc-style generic. We will use the gap between `typeName` and @@ -3529,9 +4445,13 @@ namespace Parser { entity = finishNode( factory.createQualifiedName( entity, - parseRightSideOfDot(allowReservedWords, /*allowPrivateIdentifiers*/ false, /*allowUnicodeEscapeSequenceInIdentifierName*/ true) as Identifier + parseRightSideOfDot( + allowReservedWords, + /*allowPrivateIdentifiers*/ false, + /*allowUnicodeEscapeSequenceInIdentifierName*/ true, + ) as Identifier, ), - pos + pos, ); } return entity; @@ -3541,7 +4461,11 @@ namespace Parser { return finishNode(factory.createQualifiedName(entity, name), entity.pos); } - function parseRightSideOfDot(allowIdentifierNames: boolean, allowPrivateIdentifiers: boolean, allowUnicodeEscapeSequenceInIdentifierName: boolean): Identifier | PrivateIdentifier { + function parseRightSideOfDot( + allowIdentifierNames: boolean, + allowPrivateIdentifiers: boolean, + allowUnicodeEscapeSequenceInIdentifierName: boolean, + ): Identifier | PrivateIdentifier { // Technically a keyword is valid here as all identifiers and keywords are identifier names. // However, often we'll encounter this in error situations when the identifier or keyword // is actually starting another valid construct. @@ -3568,17 +4492,27 @@ namespace Parser { // Report that we need an identifier. However, report it right after the dot, // and not on the next token. This is because the next token might actually // be an identifier and the error would be quite confusing. - return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); + return createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ true, + Diagnostics.Identifier_expected, + ); } } if (token() === SyntaxKind.PrivateIdentifier) { const node = parsePrivateIdentifier(); - return allowPrivateIdentifiers ? node : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); + return allowPrivateIdentifiers ? node + : createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ true, + Diagnostics.Identifier_expected, + ); } if (allowIdentifierNames) { - return allowUnicodeEscapeSequenceInIdentifierName ? parseIdentifierName() : parseIdentifierNameErrorOnUnicodeEscapeSequence(); + return allowUnicodeEscapeSequenceInIdentifierName ? parseIdentifierName() + : parseIdentifierNameErrorOnUnicodeEscapeSequence(); } return parseIdentifier(); @@ -3601,9 +4535,9 @@ namespace Parser { return finishNode( factory.createTemplateExpression( parseTemplateHead(isTaggedTemplate), - parseTemplateSpans(isTaggedTemplate) + parseTemplateSpans(isTaggedTemplate), ), - pos + pos, ); } @@ -3612,9 +4546,9 @@ namespace Parser { return finishNode( factory.createTemplateLiteralType( parseTemplateHead(/*isTaggedTemplate*/ false), - parseTemplateTypeSpans() + parseTemplateTypeSpans(), ), - pos + pos, ); } @@ -3635,9 +4569,9 @@ namespace Parser { return finishNode( factory.createTemplateLiteralTypeSpan( parseType(), - parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false) + parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false), ), - pos + pos, ); } @@ -3648,7 +4582,11 @@ namespace Parser { } else { // TODO(rbuckton): Do we need to call `parseExpectedToken` or can we just call `createMissingNode` directly? - return parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)) as TemplateTail; + return parseExpectedToken( + SyntaxKind.TemplateTail, + Diagnostics._0_expected, + tokenToString(SyntaxKind.CloseBraceToken), + ) as TemplateTail; } } @@ -3657,9 +4595,9 @@ namespace Parser { return finishNode( factory.createTemplateSpan( allowInAnd(parseExpression), - parseLiteralOfTemplateSpan(isTaggedTemplate) + parseLiteralOfTemplateSpan(isTaggedTemplate), ), - pos + pos, ); } @@ -3678,7 +4616,10 @@ namespace Parser { function parseTemplateMiddleOrTemplateTail(): TemplateMiddle | TemplateTail { const fragment = parseLiteralLikeNode(token()); - Debug.assert(fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, "Template fragment has wrong token kind"); + Debug.assert( + fragment.kind === SyntaxKind.TemplateMiddle || fragment.kind === SyntaxKind.TemplateTail, + "Template fragment has wrong token kind", + ); return fragment as TemplateMiddle | TemplateTail; } @@ -3690,17 +4631,28 @@ namespace Parser { function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode { const pos = getNodePos(); - const node = - isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, scanner.getTokenValue(), getTemplateLiteralRawText(kind), scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags) : + const node = isTemplateLiteralKind(kind) + ? factory.createTemplateLiteralLikeNode( + kind, + scanner.getTokenValue(), + getTemplateLiteralRawText(kind), + scanner.getTokenFlags() & TokenFlags.TemplateLiteralLikeFlags, + ) // Note that theoretically the following condition would hold true literals like 009, // which is not octal. But because of how the scanner separates the tokens, we would // never get a token like this. Instead, we would get 00 and 9 as two separate tokens. // We also do not need to check for negatives because any prefix operator would be part of a // parent unary expression. - kind === SyntaxKind.NumericLiteral ? factoryCreateNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) : - kind === SyntaxKind.StringLiteral ? factoryCreateStringLiteral(scanner.getTokenValue(), /*isSingleQuote*/ undefined, scanner.hasExtendedUnicodeEscape()) : - isLiteralKind(kind) ? factoryCreateLiteralLikeNode(kind, scanner.getTokenValue()) : - Debug.fail(); + : kind === SyntaxKind.NumericLiteral + ? factoryCreateNumericLiteral(scanner.getTokenValue(), scanner.getNumericLiteralFlags()) + : kind === SyntaxKind.StringLiteral + ? factoryCreateStringLiteral( + scanner.getTokenValue(), + /*isSingleQuote*/ undefined, + scanner.hasExtendedUnicodeEscape(), + ) + : isLiteralKind(kind) ? factoryCreateLiteralLikeNode(kind, scanner.getTokenValue()) + : Debug.fail(); if (scanner.hasExtendedUnicodeEscape()) { node.hasExtendedUnicodeEscape = true; @@ -3722,7 +4674,12 @@ namespace Parser { function parseTypeArgumentsOfTypeReference() { if (!scanner.hasPrecedingLineBreak() && reScanLessThanToken() === SyntaxKind.LessThanToken) { - return parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + return parseBracketedList( + ParsingContext.TypeArguments, + parseType, + SyntaxKind.LessThanToken, + SyntaxKind.GreaterThanToken, + ); } } @@ -3731,9 +4688,9 @@ namespace Parser { return finishNode( factory.createTypeReferenceNode( parseEntityNameOfTypeReference(), - parseTypeArgumentsOfTypeReference() + parseTypeArgumentsOfTypeReference(), ), - pos + pos, ); } @@ -3792,12 +4749,14 @@ namespace Parser { // Foo // Foo(?= // (?| - if (token() === SyntaxKind.CommaToken || - token() === SyntaxKind.CloseBraceToken || - token() === SyntaxKind.CloseParenToken || - token() === SyntaxKind.GreaterThanToken || - token() === SyntaxKind.EqualsToken || - token() === SyntaxKind.BarToken) { + if ( + token() === SyntaxKind.CommaToken + || token() === SyntaxKind.CloseBraceToken + || token() === SyntaxKind.CloseParenToken + || token() === SyntaxKind.GreaterThanToken + || token() === SyntaxKind.EqualsToken + || token() === SyntaxKind.BarToken + ) { return finishNode(factory.createJSDocUnknownType(), pos); } else { @@ -3832,9 +4791,9 @@ namespace Parser { name!, /*questionToken*/ undefined, parseJSDocType(), - /*initializer*/ undefined + /*initializer*/ undefined, ), - pos + pos, ); } @@ -3844,7 +4803,8 @@ namespace Parser { if (parseOptional(SyntaxKind.ModuleKeyword)) { // TODO(rbuckton): We never set the type for a JSDocNamepathType. What should we put here? const moduleTag = factory.createJSDocNamepathType(/*type*/ undefined!); - terminate: while (true) { + terminate: + while (true) { switch (token()) { case SyntaxKind.CloseBraceToken: case SyntaxKind.EndOfFileToken: @@ -3916,16 +4876,21 @@ namespace Parser { function parseTypeParameters(): NodeArray | undefined { if (token() === SyntaxKind.LessThanToken) { - return parseBracketedList(ParsingContext.TypeParameters, parseTypeParameter, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken); + return parseBracketedList( + ParsingContext.TypeParameters, + parseTypeParameter, + SyntaxKind.LessThanToken, + SyntaxKind.GreaterThanToken, + ); } } function isStartOfParameter(isJSDocParameter: boolean): boolean { - return token() === SyntaxKind.DotDotDotToken || - isBindingIdentifierOrPrivateIdentifierOrPattern() || - isModifierKind(token()) || - token() === SyntaxKind.AtToken || - isStartOfType(/*inStartOfParameter*/ !isJSDocParameter); + return token() === SyntaxKind.DotDotDotToken + || isBindingIdentifierOrPrivateIdentifierOrPattern() + || isModifierKind(token()) + || token() === SyntaxKind.AtToken + || isStartOfType(/*inStartOfParameter*/ !isJSDocParameter); } function parseNameOfParameter(modifiers: NodeArray | undefined) { @@ -3950,7 +4915,8 @@ namespace Parser { // Be permissive about await and yield by calling isBindingIdentifier instead of isIdentifier; disallowing // them during a speculative parse leads to many more follow-on errors than allowing the function to parse then later // complaining about the use of the keywords. - return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.OpenBraceToken; + return isBindingIdentifier() || token() === SyntaxKind.OpenBracketToken + || token() === SyntaxKind.OpenBraceToken; } function parseParameter(inOuterAwaitContext: boolean): ParameterDeclaration { @@ -3962,8 +4928,14 @@ namespace Parser { } function parseParameterWorker(inOuterAwaitContext: boolean): ParameterDeclaration; - function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity: false): ParameterDeclaration | undefined; - function parseParameterWorker(inOuterAwaitContext: boolean, allowAmbiguity = true): ParameterDeclaration | undefined { + function parseParameterWorker( + inOuterAwaitContext: boolean, + allowAmbiguity: false, + ): ParameterDeclaration | undefined; + function parseParameterWorker( + inOuterAwaitContext: boolean, + allowAmbiguity = true, + ): ParameterDeclaration | undefined { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); @@ -3971,9 +4943,9 @@ namespace Parser { // BindingElement[?Yield,?Await] // Decorators are parsed in the outer [Await] context, the rest of the parameter is parsed in the function's [Await] context. - const modifiers = inOuterAwaitContext ? - doInAwaitContext(() => parseModifiers(/*allowDecorators*/ true)) : - doOutsideOfAwaitContext(() => parseModifiers(/*allowDecorators*/ true)); + const modifiers = inOuterAwaitContext + ? doInAwaitContext(() => parseModifiers(/*allowDecorators*/ true)) + : doOutsideOfAwaitContext(() => parseModifiers(/*allowDecorators*/ true)); if (token() === SyntaxKind.ThisKeyword) { const node = factory.createParameterDeclaration( @@ -3982,12 +4954,15 @@ namespace Parser { createIdentifier(/*isIdentifier*/ true), /*questionToken*/ undefined, parseTypeAnnotation(), - /*initializer*/ undefined + /*initializer*/ undefined, ); const modifier = firstOrUndefined(modifiers); if (modifier) { - parseErrorAtRange(modifier, Diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters); + parseErrorAtRange( + modifier, + Diagnostics.Neither_decorators_nor_modifiers_may_be_applied_to_this_parameters, + ); } return withJSDoc(finishNode(node, pos), hasJSDoc); @@ -4010,25 +4985,31 @@ namespace Parser { parseNameOfParameter(modifiers), parseOptionalToken(SyntaxKind.QuestionToken), parseTypeAnnotation(), - parseInitializer() + parseInitializer(), ), - pos + pos, ), - hasJSDoc + hasJSDoc, ); topLevel = savedTopLevel; return node; } function parseReturnType(returnToken: SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode; - function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined; + function parseReturnType( + returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, + isType: boolean, + ): TypeNode | undefined; function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean) { if (shouldParseReturnType(returnToken, isType)) { return allowConditionalTypesAnd(parseTypeOrTypePredicate); } } - function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean { + function shouldParseReturnType( + returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, + isType: boolean, + ): boolean { if (returnToken === SyntaxKind.EqualsGreaterThanToken) { parseExpected(returnToken); return true; @@ -4046,8 +5027,14 @@ namespace Parser { } function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: true): NodeArray; - function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: false): NodeArray | undefined; - function parseParametersWorker(flags: SignatureFlags, allowAmbiguity: boolean): NodeArray | undefined { + function parseParametersWorker( + flags: SignatureFlags, + allowAmbiguity: false, + ): NodeArray | undefined; + function parseParametersWorker( + flags: SignatureFlags, + allowAmbiguity: boolean, + ): NodeArray | undefined { // FormalParameters [Yield,Await]: (modified) // [empty] // FormalParameterList[?Yield,Await] @@ -4067,9 +5054,14 @@ namespace Parser { setYieldContext(!!(flags & SignatureFlags.Yield)); setAwaitContext(!!(flags & SignatureFlags.Await)); - const parameters = flags & SignatureFlags.JSDoc ? - parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) : - parseDelimitedList(ParsingContext.Parameters, () => allowAmbiguity ? parseParameter(savedAwaitContext) : parseParameterForSpeculation(savedAwaitContext)); + const parameters = flags & SignatureFlags.JSDoc + ? parseDelimitedList(ParsingContext.JSDocParameters, parseJSDocParameter) + : parseDelimitedList( + ParsingContext.Parameters, + () => + allowAmbiguity ? parseParameter(savedAwaitContext) + : parseParameterForSpeculation(savedAwaitContext), + ); setYieldContext(savedYieldContext); setAwaitContext(savedAwaitContext); @@ -4111,7 +5103,9 @@ namespace Parser { parseSemicolon(); } - function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration { + function parseSignatureMember( + kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature, + ): CallSignatureDeclaration | ConstructSignatureDeclaration { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); if (kind === SyntaxKind.ConstructSignature) { @@ -4184,18 +5178,32 @@ namespace Parser { // If any of the following tokens are after the question mark, it cannot // be a conditional expression, so treat it as an indexer. nextToken(); - return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.CloseBracketToken; + return token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken + || token() === SyntaxKind.CloseBracketToken; } - function parseIndexSignatureDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): IndexSignatureDeclaration { - const parameters = parseBracketedList(ParsingContext.Parameters, () => parseParameter(/*inOuterAwaitContext*/ false), SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + function parseIndexSignatureDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): IndexSignatureDeclaration { + const parameters = parseBracketedList( + ParsingContext.Parameters, + () => parseParameter(/*inOuterAwaitContext*/ false), + SyntaxKind.OpenBracketToken, + SyntaxKind.CloseBracketToken, + ); const type = parseTypeAnnotation(); parseTypeMemberSemicolon(); const node = factory.createIndexSignature(modifiers, parameters, type); return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parsePropertyOrMethodSignature(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): PropertySignature | MethodSignature { + function parsePropertyOrMethodSignature( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): PropertySignature | MethodSignature { const name = parsePropertyName(); const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); let node: PropertySignature | MethodSignature; @@ -4213,7 +5221,9 @@ namespace Parser { // Although type literal properties cannot not have initializers, we attempt // to parse an initializer so we can report in the checker that an interface // property or type literal property cannot have an initializer. - if (token() === SyntaxKind.EqualsToken) (node as Mutable).initializer = parseInitializer(); + if (token() === SyntaxKind.EqualsToken) { + (node as Mutable).initializer = parseInitializer(); + } } parseTypeMemberSemicolon(); return withJSDoc(finishNode(node, pos), hasJSDoc); @@ -4221,10 +5231,12 @@ namespace Parser { function isTypeMemberStart(): boolean { // Return true if we have the start of a signature member - if (token() === SyntaxKind.OpenParenToken || - token() === SyntaxKind.LessThanToken || - token() === SyntaxKind.GetKeyword || - token() === SyntaxKind.SetKeyword) { + if ( + token() === SyntaxKind.OpenParenToken + || token() === SyntaxKind.LessThanToken + || token() === SyntaxKind.GetKeyword + || token() === SyntaxKind.SetKeyword + ) { return true; } let idToken = false; @@ -4245,12 +5257,12 @@ namespace Parser { // If we were able to get any potential identifier, check that it is // the start of a member declaration if (idToken) { - return token() === SyntaxKind.OpenParenToken || - token() === SyntaxKind.LessThanToken || - token() === SyntaxKind.QuestionToken || - token() === SyntaxKind.ColonToken || - token() === SyntaxKind.CommaToken || - canParseSemicolon(); + return token() === SyntaxKind.OpenParenToken + || token() === SyntaxKind.LessThanToken + || token() === SyntaxKind.QuestionToken + || token() === SyntaxKind.ColonToken + || token() === SyntaxKind.CommaToken + || canParseSemicolon(); } return false; } @@ -4324,7 +5336,8 @@ namespace Parser { if (token() === SyntaxKind.ReadonlyKeyword) { nextToken(); } - return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() && nextToken() === SyntaxKind.InKeyword; + return token() === SyntaxKind.OpenBracketToken && nextTokenIsIdentifier() + && nextToken() === SyntaxKind.InKeyword; } function parseMappedTypeParameter() { @@ -4332,14 +5345,20 @@ namespace Parser { const name = parseIdentifierName(); parseExpected(SyntaxKind.InKeyword); const type = parseType(); - return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), pos); + return finishNode( + factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, type, /*defaultType*/ undefined), + pos, + ); } function parseMappedType() { const pos = getNodePos(); parseExpected(SyntaxKind.OpenBraceToken); let readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined; - if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { + if ( + token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken + || token() === SyntaxKind.MinusToken + ) { readonlyToken = parseTokenNode(); if (readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) { parseExpected(SyntaxKind.ReadonlyKeyword); @@ -4350,7 +5369,10 @@ namespace Parser { const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined; parseExpected(SyntaxKind.CloseBracketToken); let questionToken: QuestionToken | PlusToken | MinusToken | undefined; - if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) { + if ( + token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken + || token() === SyntaxKind.MinusToken + ) { questionToken = parseTokenNode(); if (questionToken.kind !== SyntaxKind.QuestionToken) { parseExpected(SyntaxKind.QuestionToken); @@ -4360,7 +5382,10 @@ namespace Parser { parseSemicolon(); const members = parseList(ParsingContext.TypeMembers, parseTypeMember); parseExpected(SyntaxKind.CloseBraceToken); - return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), pos); + return finishNode( + factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type, members), + pos, + ); } function parseTupleElementType() { @@ -4379,7 +5404,8 @@ namespace Parser { } function isNextTokenColonOrQuestionColon() { - return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); + return nextToken() === SyntaxKind.ColonToken + || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); } function isTupleElementName() { @@ -4408,9 +5434,14 @@ namespace Parser { const pos = getNodePos(); return finishNode( factory.createTupleTypeNode( - parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken) + parseBracketedList( + ParsingContext.TupleElementTypes, + parseTupleElementNameOrTupleElementType, + SyntaxKind.OpenBracketToken, + SyntaxKind.CloseBracketToken, + ), ), - pos + pos, ); } @@ -4438,7 +5469,10 @@ namespace Parser { const hasJSDoc = hasPrecedingJSDocComment(); const modifiers = parseModifiersForConstructorType(); const isConstructorType = parseOptional(SyntaxKind.NewKeyword); - Debug.assert(!modifiers || isConstructorType, "Per isStartOfFunctionOrConstructorType, a function type cannot have modifiers."); + Debug.assert( + !modifiers || isConstructorType, + "Per isStartOfFunctionOrConstructorType, a function type cannot have modifiers.", + ); const typeParameters = parseTypeParameters(); const parameters = parseParameters(SignatureFlags.Type); const type = parseReturnType(SyntaxKind.EqualsGreaterThanToken, /*isType*/ false); @@ -4459,9 +5493,10 @@ namespace Parser { nextToken(); } let expression: BooleanLiteral | NullLiteral | LiteralExpression | PrefixUnaryExpression = - token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword || token() === SyntaxKind.NullKeyword ? - parseTokenNode() : - parseLiteralLikeNode(token()) as LiteralExpression; + token() === SyntaxKind.TrueKeyword || token() === SyntaxKind.FalseKeyword + || token() === SyntaxKind.NullKeyword + ? parseTokenNode() + : parseLiteralLikeNode(token()) as LiteralExpression; if (negative) { expression = finishNode(factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, expression), pos); } @@ -4486,7 +5521,15 @@ namespace Parser { if (lastError && lastError.code === Diagnostics._0_expected.code) { addRelatedInfo( lastError, - createDetachedDiagnostic(fileName, sourceText, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}") + createDetachedDiagnostic( + fileName, + sourceText, + openBracePosition, + 1, + Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, + "{", + "}", + ), ); } } @@ -4554,7 +5597,8 @@ namespace Parser { case SyntaxKind.NullKeyword: return parseLiteralTypeNode(); case SyntaxKind.MinusToken: - return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference(); + return lookAhead(nextTokenIsNumericOrBigIntLiteral) ? parseLiteralTypeNode(/*negative*/ true) + : parseTypeReference(); case SyntaxKind.VoidKeyword: return parseTokenNode(); case SyntaxKind.ThisKeyword: { @@ -4577,7 +5621,8 @@ namespace Parser { case SyntaxKind.ImportKeyword: return parseImportType(); case SyntaxKind.AssertsKeyword: - return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference(); + return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() + : parseTypeReference(); case SyntaxKind.TemplateHead: return parseTemplateType(); default: @@ -4639,7 +5684,8 @@ namespace Parser { function isStartOfParenthesizedOrFunctionType() { nextToken(); - return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) || isStartOfType(); + return token() === SyntaxKind.CloseParenToken || isStartOfParameter(/*isJSDocParameter*/ false) + || isStartOfType(); } function parsePostfixTypeOrHigher(): TypeNode { @@ -4678,7 +5724,9 @@ namespace Parser { return type; } - function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) { + function parseTypeOperator( + operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, + ) { const pos = getNodePos(); parseExpected(operator); return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos); @@ -4721,7 +5769,7 @@ namespace Parser { } function parseFunctionOrConstructorTypeToError( - isInUnionType: boolean + isInUnionType: boolean, ): TypeNode | undefined { // the function type and constructor type shorthand notation // are not allowed directly in unions and intersections, but we'll @@ -4738,7 +5786,6 @@ namespace Parser { diagnostic = isInUnionType ? Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type : Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type; - } parseErrorAtRange(type, diagnostic); return type; @@ -4749,7 +5796,7 @@ namespace Parser { function parseUnionOrIntersectionType( operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken, parseConstituentType: () => TypeNode, - createTypeNode: (types: NodeArray) => UnionOrIntersectionTypeNode + createTypeNode: (types: NodeArray) => UnionOrIntersectionTypeNode, ): TypeNode { const pos = getNodePos(); const isUnionType = operator === SyntaxKind.BarToken; @@ -4767,11 +5814,19 @@ namespace Parser { } function parseIntersectionTypeOrHigher(): TypeNode { - return parseUnionOrIntersectionType(SyntaxKind.AmpersandToken, parseTypeOperatorOrHigher, factory.createIntersectionTypeNode); + return parseUnionOrIntersectionType( + SyntaxKind.AmpersandToken, + parseTypeOperatorOrHigher, + factory.createIntersectionTypeNode, + ); } function parseUnionTypeOrHigher(): TypeNode { - return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode); + return parseUnionOrIntersectionType( + SyntaxKind.BarToken, + parseIntersectionTypeOrHigher, + factory.createUnionTypeNode, + ); } function nextTokenIsNewKeyword(): boolean { @@ -4786,8 +5841,8 @@ namespace Parser { if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) { return true; } - return token() === SyntaxKind.NewKeyword || - token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword); + return token() === SyntaxKind.NewKeyword + || token() === SyntaxKind.AbstractKeyword && lookAhead(nextTokenIsNewKeyword); } function skipParameterStart(): boolean { @@ -4818,8 +5873,10 @@ namespace Parser { if (skipParameterStart()) { // We successfully skipped modifiers (if any) and an identifier or binding pattern, // now see if we have something that indicates a parameter declaration - if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || - token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken) { + if ( + token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken + || token() === SyntaxKind.QuestionToken || token() === SyntaxKind.EqualsToken + ) { // ( xxx : // ( xxx , // ( xxx ? @@ -4842,7 +5899,10 @@ namespace Parser { const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); const type = parseType(); if (typePredicateVariable) { - return finishNode(factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), pos); + return finishNode( + factory.createTypePredicateNode(/*assertsModifier*/ undefined, typePredicateVariable, type), + pos, + ); } else { return type; @@ -4874,7 +5934,10 @@ namespace Parser { } const pos = getNodePos(); const type = parseUnionTypeOrHigher(); - if (!inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) { + if ( + !inDisallowConditionalTypesContext() && !scanner.hasPrecedingLineBreak() + && parseOptional(SyntaxKind.ExtendsKeyword) + ) { // The type following 'extends' is not permitted to be another conditional type const extendsType = disallowConditionalTypesAnd(parseType); parseExpected(SyntaxKind.QuestionToken); @@ -4959,11 +6022,11 @@ namespace Parser { function isStartOfExpressionStatement(): boolean { // As per the grammar, none of '{' or 'function' or 'class' can start an expression statement. - return token() !== SyntaxKind.OpenBraceToken && - token() !== SyntaxKind.FunctionKeyword && - token() !== SyntaxKind.ClassKeyword && - token() !== SyntaxKind.AtToken && - isStartOfExpression(); + return token() !== SyntaxKind.OpenBraceToken + && token() !== SyntaxKind.FunctionKeyword + && token() !== SyntaxKind.ClassKeyword + && token() !== SyntaxKind.AtToken + && isStartOfExpression(); } function parseExpression(): Expression { @@ -4981,7 +6044,12 @@ namespace Parser { let expr = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); let operatorToken: BinaryOperatorToken; while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) { - expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), pos); + expr = makeBinaryExpression( + expr, + operatorToken, + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), + pos, + ); } if (saveDecoratorContext) { @@ -4991,7 +6059,8 @@ namespace Parser { } function parseInitializer(): Expression | undefined { - return parseOptional(SyntaxKind.EqualsToken) ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined; + return parseOptional(SyntaxKind.EqualsToken) + ? parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) : undefined; } function parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction: boolean): Expression { @@ -5022,7 +6091,8 @@ namespace Parser { // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done // with AssignmentExpression if we see one. - const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction); + const arrowExpression = tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction) + || tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction); if (arrowExpression) { return arrowExpression; } @@ -5044,7 +6114,13 @@ namespace Parser { // parameter ('x => ...') above. We handle it here by checking if the parsed expression was a single // identifier and the current token is an arrow. if (expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { - return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, hasJSDoc, /*asyncModifier*/ undefined); + return parseSimpleArrowFunctionExpression( + pos, + expr as Identifier, + allowReturnTypeInArrowFunction, + hasJSDoc, + /*asyncModifier*/ undefined, + ); } // Now see if we might be in cases '2' or '3'. @@ -5054,7 +6130,12 @@ namespace Parser { // Note: we call reScanGreaterToken so that we get an appropriately merged token // for cases like `> > =` becoming `>>=` if (isLeftHandSideExpression(expr) && isAssignmentOperator(reScanGreaterToken())) { - return makeBinaryExpression(expr, parseTokenNode(), parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), pos); + return makeBinaryExpression( + expr, + parseTokenNode(), + parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction), + pos, + ); } // It wasn't an assignment or a lambda. This is a conditional expression: @@ -5103,43 +6184,66 @@ namespace Parser { // yield [no LineTerminator here] * [Lexical goal InputElementRegExp]AssignmentExpression[?In, Yield] nextToken(); - if (!scanner.hasPrecedingLineBreak() && - (token() === SyntaxKind.AsteriskToken || isStartOfExpression())) { + if ( + !scanner.hasPrecedingLineBreak() + && (token() === SyntaxKind.AsteriskToken || isStartOfExpression()) + ) { return finishNode( factory.createYieldExpression( parseOptionalToken(SyntaxKind.AsteriskToken), - parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true), ), - pos + pos, ); } else { // if the next token is not on the same line as yield. or we don't have an '*' or // the start of an expression, then this is just a simple "yield" expression. - return finishNode(factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), pos); + return finishNode( + factory.createYieldExpression(/*asteriskToken*/ undefined, /*expression*/ undefined), + pos, + ); } } - function parseSimpleArrowFunctionExpression(pos: number, identifier: Identifier, allowReturnTypeInArrowFunction: boolean, hasJSDoc: boolean, asyncModifier?: NodeArray | undefined): ArrowFunction { - Debug.assert(token() === SyntaxKind.EqualsGreaterThanToken, "parseSimpleArrowFunctionExpression should only have been called if we had a =>"); + function parseSimpleArrowFunctionExpression( + pos: number, + identifier: Identifier, + allowReturnTypeInArrowFunction: boolean, + hasJSDoc: boolean, + asyncModifier?: NodeArray | undefined, + ): ArrowFunction { + Debug.assert( + token() === SyntaxKind.EqualsGreaterThanToken, + "parseSimpleArrowFunctionExpression should only have been called if we had a =>", + ); const parameter = factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, identifier, /*questionToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined + /*initializer*/ undefined, ); finishNode(parameter, identifier.pos); const parameters = createNodeArray([parameter], parameter.pos, parameter.end); const equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken); const body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier, allowReturnTypeInArrowFunction); - const node = factory.createArrowFunction(asyncModifier, /*typeParameters*/ undefined, parameters, /*type*/ undefined, equalsGreaterThanToken, body); + const node = factory.createArrowFunction( + asyncModifier, + /*typeParameters*/ undefined, + parameters, + /*type*/ undefined, + equalsGreaterThanToken, + body, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } - function tryParseParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): Expression | undefined { + function tryParseParenthesizedArrowFunctionExpression( + allowReturnTypeInArrowFunction: boolean, + ): Expression | undefined { const triState = isParenthesizedArrowFunctionExpression(); if (triState === Tristate.False) { // It's definitely not a parenthesized arrow function expression. @@ -5150,9 +6254,12 @@ namespace Parser { // following => or { token. Otherwise, we *might* have an arrow function. Try to parse // it out, but don't allow any ambiguity, and return 'undefined' if this could be an // expression instead. - return triState === Tristate.True ? - parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ true, /*allowReturnTypeInArrowFunction*/ true) : - tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)); + return triState === Tristate.True + ? parseParenthesizedArrowFunctionExpression( + /*allowAmbiguity*/ true, + /*allowReturnTypeInArrowFunction*/ true, + ) + : tryParse(() => parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction)); } // True -> We definitely expect a parenthesized arrow function here. @@ -5160,7 +6267,10 @@ namespace Parser { // Unknown -> There *might* be a parenthesized arrow function here. // Speculatively look ahead to be sure, and rollback if not. function isParenthesizedArrowFunctionExpression(): Tristate { - if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken || token() === SyntaxKind.AsyncKeyword) { + if ( + token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken + || token() === SyntaxKind.AsyncKeyword + ) { return lookAhead(isParenthesizedArrowFunctionExpressionWorker); } @@ -5247,7 +6357,10 @@ namespace Parser { case SyntaxKind.QuestionToken: nextToken(); // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda. - if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) { + if ( + token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken + || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken + ) { return Tristate.True; } // Otherwise it is definitely not a lambda. @@ -5304,13 +6417,18 @@ namespace Parser { } } - function parsePossibleParenthesizedArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { + function parsePossibleParenthesizedArrowFunctionExpression( + allowReturnTypeInArrowFunction: boolean, + ): ArrowFunction | undefined { const tokenPos = scanner.getTokenStart(); if (notParenthesizedArrow?.has(tokenPos)) { return undefined; } - const result = parseParenthesizedArrowFunctionExpression(/*allowAmbiguity*/ false, allowReturnTypeInArrowFunction); + const result = parseParenthesizedArrowFunctionExpression( + /*allowAmbiguity*/ false, + allowReturnTypeInArrowFunction, + ); if (!result) { (notParenthesizedArrow || (notParenthesizedArrow = new Set())).add(tokenPos); } @@ -5318,7 +6436,9 @@ namespace Parser { return result; } - function tryParseAsyncSimpleArrowFunctionExpression(allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { + function tryParseAsyncSimpleArrowFunctionExpression( + allowReturnTypeInArrowFunction: boolean, + ): ArrowFunction | undefined { // We do a check here so that we won't be doing unnecessarily call to "lookAhead" if (token() === SyntaxKind.AsyncKeyword) { if (lookAhead(isUnParenthesizedAsyncArrowFunctionWorker) === Tristate.True) { @@ -5326,7 +6446,13 @@ namespace Parser { const hasJSDoc = hasPrecedingJSDocComment(); const asyncModifier = parseModifiersForArrowFunction(); const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); - return parseSimpleArrowFunctionExpression(pos, expr as Identifier, allowReturnTypeInArrowFunction, hasJSDoc, asyncModifier); + return parseSimpleArrowFunctionExpression( + pos, + expr as Identifier, + allowReturnTypeInArrowFunction, + hasJSDoc, + asyncModifier, + ); } } return undefined; @@ -5345,7 +6471,10 @@ namespace Parser { } // Check for un-parenthesized AsyncArrowFunction const expr = parseBinaryExpressionOrHigher(OperatorPrecedence.Lowest); - if (!scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier && token() === SyntaxKind.EqualsGreaterThanToken) { + if ( + !scanner.hasPrecedingLineBreak() && expr.kind === SyntaxKind.Identifier + && token() === SyntaxKind.EqualsGreaterThanToken + ) { return Tristate.True; } } @@ -5353,7 +6482,10 @@ namespace Parser { return Tristate.False; } - function parseParenthesizedArrowFunctionExpression(allowAmbiguity: boolean, allowReturnTypeInArrowFunction: boolean): ArrowFunction | undefined { + function parseParenthesizedArrowFunctionExpression( + allowAmbiguity: boolean, + allowReturnTypeInArrowFunction: boolean, + ): ArrowFunction | undefined { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); const modifiers = parseModifiersForArrowFunction(); @@ -5409,13 +6541,16 @@ namespace Parser { let unwrappedType = type; while (unwrappedType?.kind === SyntaxKind.ParenthesizedType) { - unwrappedType = (unwrappedType as ParenthesizedTypeNode).type; // Skip parens if need be + unwrappedType = (unwrappedType as ParenthesizedTypeNode).type; // Skip parens if need be } const hasJSDocFunctionType = unwrappedType && isJSDocFunctionType(unwrappedType); - if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) { + if ( + !allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken + && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken) + ) { // Returning undefined here will cause our caller to rewind to where we started from. - return undefined; + return undefined; } // If we have an arrow, then try to parse the body. Even if not, try to parse if we @@ -5452,20 +6587,32 @@ namespace Parser { } } - const node = factory.createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body); + const node = factory.createArrowFunction( + modifiers, + typeParameters, + parameters, + type, + equalsGreaterThanToken, + body, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseArrowFunctionExpressionBody(isAsync: boolean, allowReturnTypeInArrowFunction: boolean): Block | Expression { + function parseArrowFunctionExpressionBody( + isAsync: boolean, + allowReturnTypeInArrowFunction: boolean, + ): Block | Expression { if (token() === SyntaxKind.OpenBraceToken) { return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None); } - if (token() !== SyntaxKind.SemicolonToken && - token() !== SyntaxKind.FunctionKeyword && - token() !== SyntaxKind.ClassKeyword && - isStartOfStatement() && - !isStartOfExpressionStatement()) { + if ( + token() !== SyntaxKind.SemicolonToken + && token() !== SyntaxKind.FunctionKeyword + && token() !== SyntaxKind.ClassKeyword + && isStartOfStatement() + && !isStartOfExpressionStatement() + ) { // Check if we got a plain statement (i.e. no expression-statements, no function/class expressions/declarations) // // Here we try to recover from a potential error situation in the case where the @@ -5480,7 +6627,9 @@ namespace Parser { // up preemptively closing the containing construct. // // Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error. - return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None)); + return parseFunctionBlock( + SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None), + ); } const savedTopLevel = topLevel; @@ -5492,7 +6641,11 @@ namespace Parser { return node; } - function parseConditionalExpressionRest(leftOperand: Expression, pos: number, allowReturnTypeInArrowFunction: boolean): Expression { + function parseConditionalExpressionRest( + leftOperand: Expression, + pos: number, + allowReturnTypeInArrowFunction: boolean, + ): Expression { // Note: we are passed in an expression which was produced from parseBinaryExpressionOrHigher. const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); if (!questionToken) { @@ -5506,13 +6659,21 @@ namespace Parser { factory.createConditionalExpression( leftOperand, questionToken, - doOutsideOfContext(disallowInAndDecoratorContext, () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false)), + doOutsideOfContext( + disallowInAndDecoratorContext, + () => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ false), + ), colonToken = parseExpectedToken(SyntaxKind.ColonToken), nodeIsPresent(colonToken) ? parseAssignmentExpressionOrHigher(allowReturnTypeInArrowFunction) - : createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken)) + : createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ false, + Diagnostics._0_expected, + tokenToString(SyntaxKind.ColonToken), + ), ), - pos + pos, ); } @@ -5526,7 +6687,11 @@ namespace Parser { return t === SyntaxKind.InKeyword || t === SyntaxKind.OfKeyword; } - function parseBinaryExpressionRest(precedence: OperatorPrecedence, leftOperand: Expression, pos: number): Expression { + function parseBinaryExpressionRest( + precedence: OperatorPrecedence, + leftOperand: Expression, + pos: number, + ): Expression { while (true) { // We either have a binary operator here, or we're finished. We call // reScanGreaterToken so that we merge token sequences like > and = into >= @@ -5555,9 +6720,9 @@ namespace Parser { // ^^token; leftOperand = b. Return b ** c to the caller as a rightOperand // a ** b - c // ^token; leftOperand = b. Return b to the caller as a rightOperand - const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken ? - newPrecedence >= precedence : - newPrecedence > precedence; + const consumeCurrentOperator = token() === SyntaxKind.AsteriskAsteriskToken + ? newPrecedence >= precedence + : newPrecedence > precedence; if (!consumeCurrentOperator) { break; @@ -5579,12 +6744,18 @@ namespace Parser { else { const keywordKind = token(); nextToken(); - leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword ? makeSatisfiesExpression(leftOperand, parseType()) : - makeAsExpression(leftOperand, parseType()); + leftOperand = keywordKind === SyntaxKind.SatisfiesKeyword + ? makeSatisfiesExpression(leftOperand, parseType()) + : makeAsExpression(leftOperand, parseType()); } } else { - leftOperand = makeBinaryExpression(leftOperand, parseTokenNode(), parseBinaryExpressionOrHigher(newPrecedence), pos); + leftOperand = makeBinaryExpression( + leftOperand, + parseTokenNode(), + parseBinaryExpressionOrHigher(newPrecedence), + pos, + ); } } @@ -5603,7 +6774,12 @@ namespace Parser { return finishNode(factory.createSatisfiesExpression(left, right), left.pos); } - function makeBinaryExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, pos: number): BinaryExpression { + function makeBinaryExpression( + left: Expression, + operatorToken: BinaryOperatorToken, + right: Expression, + pos: number, + ): BinaryExpression { return finishNode(factory.createBinaryExpression(left, operatorToken, right), pos); } @@ -5613,7 +6789,13 @@ namespace Parser { function parsePrefixUnaryExpression() { const pos = getNodePos(); - return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseSimpleUnaryExpression)), pos); + return finishNode( + factory.createPrefixUnaryExpression( + token() as PrefixUnaryOperator, + nextTokenAnd(parseSimpleUnaryExpression), + ), + pos, + ); } function parseDeleteExpression() { @@ -5655,7 +6837,6 @@ namespace Parser { * ES7 ExponentiationExpression: * 1) UnaryExpression[?Yield] * 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield] - * */ function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression { /** @@ -5669,9 +6850,13 @@ namespace Parser { if (isUpdateExpression()) { const pos = getNodePos(); const updateExpression = parseUpdateExpression(); - return token() === SyntaxKind.AsteriskAsteriskToken ? - parseBinaryExpressionRest(getBinaryOperatorPrecedence(token()), updateExpression, pos) as BinaryExpression : - updateExpression; + return token() === SyntaxKind.AsteriskAsteriskToken + ? parseBinaryExpressionRest( + getBinaryOperatorPrecedence(token()), + updateExpression, + pos, + ) as BinaryExpression + : updateExpression; } /** @@ -5691,11 +6876,22 @@ namespace Parser { const pos = skipTrivia(sourceText, simpleUnaryExpression.pos); const { end } = simpleUnaryExpression; if (simpleUnaryExpression.kind === SyntaxKind.TypeAssertionExpression) { - parseErrorAt(pos, end, Diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses); + parseErrorAt( + pos, + end, + Diagnostics + .A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, + ); } else { Debug.assert(isKeywordOrPunctuation(unaryOperator)); - parseErrorAt(pos, end, Diagnostics.An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, tokenToString(unaryOperator)); + parseErrorAt( + pos, + end, + Diagnostics + .An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, + tokenToString(unaryOperator), + ); } } return simpleUnaryExpression; @@ -5732,7 +6928,12 @@ namespace Parser { // Just like in parseUpdateExpression, we need to avoid parsing type assertions when // in JSX and we see an expression like "+ bar". if (languageVariant === LanguageVariant.JSX) { - return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, /*topInvalidNodePosition*/ undefined, /*openingTag*/ undefined, /*mustBeUnary*/ true); + return parseJsxElementOrSelfClosingElementOrFragment( + /*inExpressionContext*/ true, + /*topInvalidNodePosition*/ undefined, + /*openingTag*/ undefined, + /*mustBeUnary*/ true, + ); } // This is modified UnaryExpression grammar in TypeScript // UnaryExpression (modified): @@ -5797,9 +6998,18 @@ namespace Parser { function parseUpdateExpression(): UpdateExpression { if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) { const pos = getNodePos(); - return finishNode(factory.createPrefixUnaryExpression(token() as PrefixUnaryOperator, nextTokenAnd(parseLeftHandSideExpressionOrHigher)), pos); + return finishNode( + factory.createPrefixUnaryExpression( + token() as PrefixUnaryOperator, + nextTokenAnd(parseLeftHandSideExpressionOrHigher), + ), + pos, + ); } - else if (languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { + else if ( + languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken + && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan) + ) { // JSXElement is part of primaryExpression return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); } @@ -5807,7 +7017,10 @@ namespace Parser { const expression = parseLeftHandSideExpressionOrHigher(); Debug.assert(isLeftHandSideExpression(expression)); - if ((token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { + if ( + (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) + && !scanner.hasPrecedingLineBreak() + ) { const operator = token() as PostfixUnaryOperator; nextToken(); return finishNode(factory.createPostfixUnaryExpression(expression, operator), expression.pos); @@ -5864,7 +7077,10 @@ namespace Parser { // This is an 'import.*' metaproperty (i.e. 'import.meta') nextToken(); // advance past the 'import' nextToken(); // advance past the dot - expression = finishNode(factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), pos); + expression = finishNode( + factory.createMetaProperty(SyntaxKind.ImportKeyword, parseIdentifierName()), + pos, + ); sourceFlags |= NodeFlags.PossiblyContainsImportMeta; } else { @@ -5948,18 +7164,39 @@ namespace Parser { } } - if (token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken || token() === SyntaxKind.OpenBracketToken) { + if ( + token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.DotToken + || token() === SyntaxKind.OpenBracketToken + ) { return expression; } // If we have seen "super" it must be followed by '(' or '.'. // If it wasn't then just try to parse out a '.' and report an error. - parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); + parseExpectedToken( + SyntaxKind.DotToken, + Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access, + ); // private names will never work with `super` (`super.#foo`), but that's a semantic error, not syntactic - return finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true, /*allowUnicodeEscapeSequenceInIdentifierName*/ true)), pos); + return finishNode( + factoryCreatePropertyAccessExpression( + expression, + parseRightSideOfDot( + /*allowIdentifierNames*/ true, + /*allowPrivateIdentifiers*/ true, + /*allowUnicodeEscapeSequenceInIdentifierName*/ true, + ), + ), + pos, + ); } - function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean, topInvalidNodePosition?: number, openingTag?: JsxOpeningElement | JsxOpeningFragment, mustBeUnary = false): JsxElement | JsxSelfClosingElement | JsxFragment { + function parseJsxElementOrSelfClosingElementOrFragment( + inExpressionContext: boolean, + topInvalidNodePosition?: number, + openingTag?: JsxOpeningElement | JsxOpeningFragment, + mustBeUnary = false, + ): JsxElement | JsxSelfClosingElement | JsxFragment { const pos = getNodePos(); const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); let result: JsxElement | JsxSelfClosingElement | JsxFragment; @@ -5968,19 +7205,28 @@ namespace Parser { let closingElement: JsxClosingElement; const lastChild: JsxChild | undefined = children[children.length - 1]; - if (lastChild?.kind === SyntaxKind.JsxElement + if ( + lastChild?.kind === SyntaxKind.JsxElement && !tagNamesAreEquivalent(lastChild.openingElement.tagName, lastChild.closingElement.tagName) - && tagNamesAreEquivalent(opening.tagName, lastChild.closingElement.tagName)) { + && tagNamesAreEquivalent(opening.tagName, lastChild.closingElement.tagName) + ) { // when an unclosed JsxOpeningElement incorrectly parses its parent's JsxClosingElement, // restructure (
(......
)) --> (
(......)
) // (no need to error; the parent will error) const end = lastChild.children.end; - const newLast = finishNode(factory.createJsxElement( - lastChild.openingElement, - lastChild.children, - finishNode(factory.createJsxClosingElement(finishNode(factoryCreateIdentifier(""), end, end)), end, end)), - lastChild.openingElement.pos, - end); + const newLast = finishNode( + factory.createJsxElement( + lastChild.openingElement, + lastChild.children, + finishNode( + factory.createJsxClosingElement(finishNode(factoryCreateIdentifier(""), end, end)), + end, + end, + ), + ), + lastChild.openingElement.pos, + end, + ); children = createNodeArray([...children.slice(0, children.length - 1), newLast], children.pos, end); closingElement = lastChild.closingElement; @@ -5988,20 +7234,38 @@ namespace Parser { else { closingElement = parseJsxClosingElement(opening, inExpressionContext); if (!tagNamesAreEquivalent(opening.tagName, closingElement.tagName)) { - if (openingTag && isJsxOpeningElement(openingTag) && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName)) { + if ( + openingTag && isJsxOpeningElement(openingTag) + && tagNamesAreEquivalent(closingElement.tagName, openingTag.tagName) + ) { // opening incorrectly matched with its parent's closing -- put error on opening - parseErrorAtRange(opening.tagName, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, opening.tagName)); + parseErrorAtRange( + opening.tagName, + Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, + getTextOfNodeFromSourceText(sourceText, opening.tagName), + ); } else { // other opening/closing mismatches -- put error on closing - parseErrorAtRange(closingElement.tagName, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, opening.tagName)); + parseErrorAtRange( + closingElement.tagName, + Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, + getTextOfNodeFromSourceText(sourceText, opening.tagName), + ); } } } result = finishNode(factory.createJsxElement(opening, children, closingElement), pos); } else if (opening.kind === SyntaxKind.JsxOpeningFragment) { - result = finishNode(factory.createJsxFragment(opening, parseJsxChildren(opening), parseJsxClosingFragment(inExpressionContext)), pos); + result = finishNode( + factory.createJsxFragment( + opening, + parseJsxChildren(opening), + parseJsxClosingFragment(inExpressionContext), + ), + pos, + ); } else { Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); @@ -6020,12 +7284,25 @@ namespace Parser { // a valid UnaryExpression and will cause problems later. if (!mustBeUnary && inExpressionContext && token() === SyntaxKind.LessThanToken) { const topBadPos = typeof topInvalidNodePosition === "undefined" ? result.pos : topInvalidNodePosition; - const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos)); + const invalidElement = tryParse(() => + parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true, topBadPos) + ); if (invalidElement) { const operatorToken = createMissingNode(SyntaxKind.CommaToken, /*reportAtCurrentPosition*/ false); setTextRangePosWidth(operatorToken, invalidElement.pos, 0); - parseErrorAt(skipTrivia(sourceText, topBadPos), invalidElement.end, Diagnostics.JSX_expressions_must_have_one_parent_element); - return finishNode(factory.createBinaryExpression(result, operatorToken as Token, invalidElement), pos) as Node as JsxElement; + parseErrorAt( + skipTrivia(sourceText, topBadPos), + invalidElement.end, + Diagnostics.JSX_expressions_must_have_one_parent_element, + ); + return finishNode( + factory.createBinaryExpression( + result, + operatorToken as Token, + invalidElement, + ), + pos, + ) as Node as JsxElement; } } @@ -6039,7 +7316,10 @@ namespace Parser { return finishNode(node, pos); } - function parseJsxChild(openingTag: JsxOpeningElement | JsxOpeningFragment, token: JsxTokenSyntaxKind): JsxChild | undefined { + function parseJsxChild( + openingTag: JsxOpeningElement | JsxOpeningFragment, + token: JsxTokenSyntaxKind, + ): JsxChild | undefined { switch (token) { case SyntaxKind.EndOfFileToken: // If we hit EOF, issue the error at the tag that lacks the closing element @@ -6052,7 +7332,12 @@ namespace Parser { // or to cover only 'Foo' in < Foo > const tag = openingTag.tagName; const start = Math.min(skipTrivia(sourceText, tag.pos), tag.end); - parseErrorAt(start, tag.end, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTag.tagName)); + parseErrorAt( + start, + tag.end, + Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, + getTextOfNodeFromSourceText(sourceText, openingTag.tagName), + ); } return undefined; case SyntaxKind.LessThanSlashToken: @@ -6064,7 +7349,11 @@ namespace Parser { case SyntaxKind.OpenBraceToken: return parseJsxExpression(/*inExpressionContext*/ false); case SyntaxKind.LessThanToken: - return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false, /*topInvalidNodePosition*/ undefined, openingTag); + return parseJsxElementOrSelfClosingElementOrFragment( + /*inExpressionContext*/ false, + /*topInvalidNodePosition*/ undefined, + openingTag, + ); default: return Debug.assertNever(token); } @@ -6080,10 +7369,12 @@ namespace Parser { const child = parseJsxChild(openingTag, currentToken = scanner.reScanJsxToken()); if (!child) break; list.push(child); - if (isJsxOpeningElement(openingTag) + if ( + isJsxOpeningElement(openingTag) && child?.kind === SyntaxKind.JsxElement && !tagNamesAreEquivalent(child.openingElement.tagName, child.closingElement.tagName) - && tagNamesAreEquivalent(openingTag.tagName, child.closingElement.tagName)) { + && tagNamesAreEquivalent(openingTag.tagName, child.closingElement.tagName) + ) { // stop after parsing a mismatched child like
...(
) in order to reattach the higher break; } @@ -6098,7 +7389,9 @@ namespace Parser { return finishNode(factory.createJsxAttributes(parseList(ParsingContext.JsxAttributes, parseJsxAttribute)), pos); } - function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { + function parseJsxOpeningOrSelfClosingElementOrOpeningFragment( + inExpressionContext: boolean, + ): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { const pos = getNodePos(); parseExpected(SyntaxKind.LessThanToken); @@ -6151,7 +7444,17 @@ namespace Parser { } let expression: PropertyAccessExpression | Identifier | ThisExpression = initialExpression; while (parseOptional(SyntaxKind.DotToken)) { - expression = finishNode(factoryCreatePropertyAccessExpression(expression, parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ false, /*allowUnicodeEscapeSequenceInIdentifierName*/ false)), pos); + expression = finishNode( + factoryCreatePropertyAccessExpression( + expression, + parseRightSideOfDot( + /*allowIdentifierNames*/ true, + /*allowPrivateIdentifiers*/ false, + /*allowUnicodeEscapeSequenceInIdentifierName*/ false, + ), + ), + pos, + ); } return expression as JsxTagNameExpression; } @@ -6164,7 +7467,10 @@ namespace Parser { const tagName = parseIdentifierNameErrorOnUnicodeEscapeSequence(); if (parseOptional(SyntaxKind.ColonToken)) { scanJsxIdentifier(); - return finishNode(factory.createJsxNamespacedName(tagName, parseIdentifierNameErrorOnUnicodeEscapeSequence()), pos); + return finishNode( + factory.createJsxNamespacedName(tagName, parseIdentifierNameErrorOnUnicodeEscapeSequence()), + pos, + ); } return isThis ? finishNode(factory.createToken(SyntaxKind.ThisKeyword), pos) : tagName; } @@ -6228,7 +7534,10 @@ namespace Parser { const attrName = parseIdentifierNameErrorOnUnicodeEscapeSequence(); if (parseOptional(SyntaxKind.ColonToken)) { scanJsxIdentifier(); - return finishNode(factory.createJsxNamespacedName(attrName, parseIdentifierNameErrorOnUnicodeEscapeSequence()), pos); + return finishNode( + factory.createJsxNamespacedName(attrName, parseIdentifierNameErrorOnUnicodeEscapeSequence()), + pos, + ); } return attrName; } @@ -6261,7 +7570,13 @@ namespace Parser { function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment { const pos = getNodePos(); parseExpected(SyntaxKind.LessThanSlashToken); - if (parseExpected(SyntaxKind.GreaterThanToken, Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment, /*shouldAdvance*/ false)) { + if ( + parseExpected( + SyntaxKind.GreaterThanToken, + Diagnostics.Expected_corresponding_closing_tag_for_JSX_fragment, + /*shouldAdvance*/ false, + ) + ) { // manually advance the scanner in order to look for jsx text inside jsx if (inExpressionContext) { nextToken(); @@ -6274,7 +7589,10 @@ namespace Parser { } function parseTypeAssertion(): TypeAssertion { - Debug.assert(languageVariant !== LanguageVariant.JSX, "Type assertions should never be parsed in JSX; they should be parsed as comparisons or JSX elements/fragments."); + Debug.assert( + languageVariant !== LanguageVariant.JSX, + "Type assertions should never be parsed in JSX; they should be parsed as comparisons or JSX elements/fragments.", + ); const pos = getNodePos(); parseExpected(SyntaxKind.LessThanToken); const type = parseType(); @@ -6317,12 +7635,20 @@ namespace Parser { return false; } - function parsePropertyAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { - const name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true, /*allowUnicodeEscapeSequenceInIdentifierName*/ true); + function parsePropertyAccessExpressionRest( + pos: number, + expression: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + ) { + const name = parseRightSideOfDot( + /*allowIdentifierNames*/ true, + /*allowPrivateIdentifiers*/ true, + /*allowUnicodeEscapeSequenceInIdentifierName*/ true, + ); const isOptionalChain = questionDotToken || tryReparseOptionalChain(expression); - const propertyAccess = isOptionalChain ? - factoryCreatePropertyAccessChain(expression, questionDotToken, name) : - factoryCreatePropertyAccessExpression(expression, name); + const propertyAccess = isOptionalChain + ? factoryCreatePropertyAccessChain(expression, questionDotToken, name) + : factoryCreatePropertyAccessExpression(expression, name); if (isOptionalChain && isPrivateIdentifier(propertyAccess.name)) { parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers); } @@ -6334,10 +7660,18 @@ namespace Parser { return finishNode(propertyAccess, pos); } - function parseElementAccessExpressionRest(pos: number, expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) { + function parseElementAccessExpressionRest( + pos: number, + expression: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + ) { let argumentExpression: Expression; if (token() === SyntaxKind.CloseBracketToken) { - argumentExpression = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.An_element_access_expression_should_take_an_argument); + argumentExpression = createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ true, + Diagnostics.An_element_access_expression_should_take_an_argument, + ); } else { const argument = allowInAnd(parseExpression); @@ -6349,13 +7683,17 @@ namespace Parser { parseExpected(SyntaxKind.CloseBracketToken); - const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) ? - factoryCreateElementAccessChain(expression, questionDotToken, argumentExpression) : - factoryCreateElementAccessExpression(expression, argumentExpression); + const indexedAccess = questionDotToken || tryReparseOptionalChain(expression) + ? factoryCreateElementAccessChain(expression, questionDotToken, argumentExpression) + : factoryCreateElementAccessExpression(expression, argumentExpression); return finishNode(indexedAccess, pos); } - function parseMemberExpressionRest(pos: number, expression: LeftHandSideExpression, allowOptionalChain: boolean): MemberExpression { + function parseMemberExpressionRest( + pos: number, + expression: LeftHandSideExpression, + allowOptionalChain: boolean, + ): MemberExpression { while (true) { let questionDotToken: QuestionDotToken | undefined; let isPropertyAccess = false; @@ -6380,9 +7718,14 @@ namespace Parser { if (isTemplateStartOfTaggedTemplate()) { // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments - expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments ? - parseTaggedTemplateRest(pos, (expression as ExpressionWithTypeArguments).expression, questionDotToken, (expression as ExpressionWithTypeArguments).typeArguments) : - parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined); + expression = !questionDotToken && expression.kind === SyntaxKind.ExpressionWithTypeArguments + ? parseTaggedTemplateRest( + pos, + (expression as ExpressionWithTypeArguments).expression, + questionDotToken, + (expression as ExpressionWithTypeArguments).typeArguments, + ) + : parseTaggedTemplateRest(pos, expression, questionDotToken, /*typeArguments*/ undefined); continue; } @@ -6407,13 +7750,18 @@ namespace Parser { return token() === SyntaxKind.NoSubstitutionTemplateLiteral || token() === SyntaxKind.TemplateHead; } - function parseTaggedTemplateRest(pos: number, tag: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined, typeArguments: NodeArray | undefined) { + function parseTaggedTemplateRest( + pos: number, + tag: LeftHandSideExpression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: NodeArray | undefined, + ) { const tagExpression = factory.createTaggedTemplateExpression( tag, typeArguments, - token() === SyntaxKind.NoSubstitutionTemplateLiteral ? - (reScanTemplateToken(/*isTaggedTemplate*/ true), parseLiteralNode() as NoSubstitutionTemplateLiteral) : - parseTemplateExpression(/*isTaggedTemplate*/ true) + token() === SyntaxKind.NoSubstitutionTemplateLiteral + ? (reScanTemplateToken(/*isTaggedTemplate*/ true), parseLiteralNode() as NoSubstitutionTemplateLiteral) + : parseTemplateExpression(/*isTaggedTemplate*/ true), ); if (questionDotToken || tag.flags & NodeFlags.OptionalChain) { (tagExpression as Mutable).flags |= NodeFlags.OptionalChain; @@ -6441,15 +7789,19 @@ namespace Parser { expression = (expression as ExpressionWithTypeArguments).expression; } const argumentList = parseArgumentList(); - const callExpr = questionDotToken || tryReparseOptionalChain(expression) ? - factoryCreateCallChain(expression, questionDotToken, typeArguments, argumentList) : - factoryCreateCallExpression(expression, typeArguments, argumentList); + const callExpr = questionDotToken || tryReparseOptionalChain(expression) + ? factoryCreateCallChain(expression, questionDotToken, typeArguments, argumentList) + : factoryCreateCallExpression(expression, typeArguments, argumentList); expression = finishNode(callExpr, pos); continue; } if (questionDotToken) { // We parsed `?.` but then failed to parse anything, so report a missing identifier here. - const name = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics.Identifier_expected); + const name = createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ false, + Diagnostics.Identifier_expected, + ); expression = finishNode(factoryCreatePropertyAccessChain(expression, questionDotToken, name), pos); } break; @@ -6492,9 +7844,9 @@ namespace Parser { function canFollowTypeArgumentsInExpression(): boolean { switch (token()) { // These tokens can follow a type argument list in a call expression. - case SyntaxKind.OpenParenToken: // foo( - case SyntaxKind.NoSubstitutionTemplateLiteral: // foo `...` - case SyntaxKind.TemplateHead: // foo `...${100}...` + case SyntaxKind.OpenParenToken: // foo( + case SyntaxKind.NoSubstitutionTemplateLiteral: // foo `...` + case SyntaxKind.TemplateHead: // foo `...${100}...` return true; // A type argument list followed by `<` never makes sense, and a type argument list followed // by `>` is ambiguous with a (re-scanned) `>>` operator, so we disqualify both. Also, in @@ -6582,9 +7934,9 @@ namespace Parser { } function parseArgumentOrArrayLiteralElement(): Expression { - return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() : - token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) : - parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); + return token() === SyntaxKind.DotDotDotToken ? parseSpreadElement() + : token() === SyntaxKind.CommaToken ? finishNode(factory.createOmittedExpression(), getNodePos()) + : parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); } function parseArgumentExpression(): Expression { @@ -6597,7 +7949,12 @@ namespace Parser { const openBracketParsed = parseExpected(SyntaxKind.OpenBracketToken); const multiLine = scanner.hasPrecedingLineBreak(); const elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement); - parseExpectedMatchingBrackets(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, openBracketParsed, openBracketPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenBracketToken, + SyntaxKind.CloseBracketToken, + openBracketParsed, + openBracketPosition, + ); return finishNode(factoryCreateArrayLiteralExpression(elements, multiLine), pos); } @@ -6627,7 +7984,15 @@ namespace Parser { const exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken); if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { - return parseMethodDeclaration(pos, hasJSDoc, modifiers, asteriskToken, name, questionToken, exclamationToken); + return parseMethodDeclaration( + pos, + hasJSDoc, + modifiers, + asteriskToken, + name, + questionToken, + exclamationToken, + ); } // check if it is short-hand property assignment or normal property assignment @@ -6639,7 +8004,9 @@ namespace Parser { const isShorthandPropertyAssignment = tokenIsIdentifier && (token() !== SyntaxKind.ColonToken); if (isShorthandPropertyAssignment) { const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken); - const objectAssignmentInitializer = equalsToken ? allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)) : undefined; + const objectAssignmentInitializer = equalsToken ? allowInAnd(() => + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) + ) : undefined; node = factory.createShorthandPropertyAssignment(name as Identifier, objectAssignmentInitializer); // Save equals token for error reporting. // TODO(rbuckton): Consider manufacturing this when we need to report an error as it is otherwise not useful. @@ -6647,7 +8014,9 @@ namespace Parser { } else { parseExpected(SyntaxKind.ColonToken); - const initializer = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); + const initializer = allowInAnd(() => + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) + ); node = factory.createPropertyAssignment(name, initializer); } // Decorators, Modifiers, questionToken, and exclamationToken are not supported by property assignments and are reported in the grammar checker @@ -6662,8 +8031,17 @@ namespace Parser { const openBracePosition = scanner.getTokenStart(); const openBraceParsed = parseExpected(SyntaxKind.OpenBraceToken); const multiLine = scanner.hasPrecedingLineBreak(); - const properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralElement, /*considerSemicolonAsDelimiter*/ true); - parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); + const properties = parseDelimitedList( + ParsingContext.ObjectLiteralMembers, + parseObjectLiteralElement, + /*considerSemicolonAsDelimiter*/ true, + ); + parseExpectedMatchingBrackets( + SyntaxKind.OpenBraceToken, + SyntaxKind.CloseBraceToken, + openBraceParsed, + openBracePosition, + ); return finishNode(factoryCreateObjectLiteralExpression(properties, multiLine), pos); } @@ -6683,10 +8061,10 @@ namespace Parser { const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; - const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) : - isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) : - isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) : - parseOptionalBindingIdentifier(); + const name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalBindingIdentifier) + : isGenerator ? doInYieldContext(parseOptionalBindingIdentifier) + : isAsync ? doInAwaitContext(parseOptionalBindingIdentifier) + : parseOptionalBindingIdentifier(); const typeParameters = parseTypeParameters(); const parameters = parseParameters(isGenerator | isAsync); @@ -6695,7 +8073,15 @@ namespace Parser { setDecoratorContext(savedDecoratorContext); - const node = factory.createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body); + const node = factory.createFunctionExpression( + modifiers, + asteriskToken, + name, + typeParameters, + parameters, + type, + body, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } @@ -6711,7 +8097,11 @@ namespace Parser { return finishNode(factory.createMetaProperty(SyntaxKind.NewKeyword, name), pos); } const expressionPos = getNodePos(); - let expression: LeftHandSideExpression = parseMemberExpressionRest(expressionPos, parsePrimaryExpression(), /*allowOptionalChain*/ false); + let expression: LeftHandSideExpression = parseMemberExpressionRest( + expressionPos, + parsePrimaryExpression(), + /*allowOptionalChain*/ false, + ); let typeArguments: NodeArray | undefined; // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments if (expression.kind === SyntaxKind.ExpressionWithTypeArguments) { @@ -6719,7 +8109,10 @@ namespace Parser { expression = (expression as ExpressionWithTypeArguments).expression; } if (token() === SyntaxKind.QuestionDotToken) { - parseErrorAtCurrentToken(Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, getTextOfNodeFromSourceText(sourceText, expression)); + parseErrorAtCurrentToken( + Diagnostics.Invalid_optional_chain_from_new_expression_Did_you_mean_to_call_0, + getTextOfNodeFromSourceText(sourceText, expression), + ); } const argumentList = token() === SyntaxKind.OpenParenToken ? parseArgumentList() : undefined; return finishNode(factoryCreateNewExpression(expression, typeArguments, argumentList), pos); @@ -6734,10 +8127,18 @@ namespace Parser { if (openBraceParsed || ignoreMissingOpenBrace) { const multiLine = scanner.hasPrecedingLineBreak(); const statements = parseList(ParsingContext.BlockStatements, parseStatement); - parseExpectedMatchingBrackets(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, openBraceParsed, openBracePosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenBraceToken, + SyntaxKind.CloseBraceToken, + openBraceParsed, + openBracePosition, + ); const result = withJSDoc(finishNode(factoryCreateBlock(statements, multiLine), pos), hasJSDoc); if (token() === SyntaxKind.EqualsToken) { - parseErrorAtCurrentToken(Diagnostics.Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_whole_assignment_in_parentheses); + parseErrorAtCurrentToken( + Diagnostics + .Declaration_or_statement_expected_This_follows_a_block_of_statements_so_if_you_intended_to_write_a_destructuring_assignment_you_might_need_to_wrap_the_whole_assignment_in_parentheses, + ); nextToken(); } @@ -6793,7 +8194,12 @@ namespace Parser { const openParenPosition = scanner.getTokenStart(); const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); const expression = allowInAnd(parseExpression); - parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenParenToken, + SyntaxKind.CloseParenToken, + openParenParsed, + openParenPosition, + ); const thenStatement = parseStatement(); const elseStatement = parseOptional(SyntaxKind.ElseKeyword) ? parseStatement() : undefined; return withJSDoc(finishNode(factoryCreateIfStatement(expression, thenStatement, elseStatement), pos), hasJSDoc); @@ -6808,7 +8214,12 @@ namespace Parser { const openParenPosition = scanner.getTokenStart(); const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); const expression = allowInAnd(parseExpression); - parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenParenToken, + SyntaxKind.CloseParenToken, + openParenParsed, + openParenPosition, + ); // From: https://mail.mozilla.org/pipermail/es-discuss/2011-August/016188.html // 157 min --- All allen at wirfs-brock.com CONF --- "do{;}while(false)false" prohibited in @@ -6825,7 +8236,12 @@ namespace Parser { const openParenPosition = scanner.getTokenStart(); const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); const expression = allowInAnd(parseExpression); - parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenParenToken, + SyntaxKind.CloseParenToken, + openParenParsed, + openParenPosition, + ); const statement = parseStatement(); return withJSDoc(finishNode(factoryCreateWhileStatement(expression, statement), pos), hasJSDoc); } @@ -6839,9 +8255,16 @@ namespace Parser { let initializer!: VariableDeclarationList | Expression; if (token() !== SyntaxKind.SemicolonToken) { - if (token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword || token() === SyntaxKind.ConstKeyword || - token() === SyntaxKind.UsingKeyword && lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLineDisallowOf) || - token() === SyntaxKind.AwaitKeyword && lookAhead(nextTokenIsUsingKeywordThenBindingIdentifierOrStartOfObjectDestructuringOnSameLineDisallowOf)) { + if ( + token() === SyntaxKind.VarKeyword || token() === SyntaxKind.LetKeyword + || token() === SyntaxKind.ConstKeyword + || token() === SyntaxKind.UsingKeyword + && lookAhead(nextTokenIsBindingIdentifierOrStartOfDestructuringOnSameLineDisallowOf) + || token() === SyntaxKind.AwaitKeyword + && lookAhead( + nextTokenIsUsingKeywordThenBindingIdentifierOrStartOfObjectDestructuringOnSameLineDisallowOf, + ) + ) { initializer = parseVariableDeclarationList(/*inForStatementInitializer*/ true); } else { @@ -6851,7 +8274,9 @@ namespace Parser { let node: IterationStatement; if (awaitToken ? parseExpected(SyntaxKind.OfKeyword) : parseOptional(SyntaxKind.OfKeyword)) { - const expression = allowInAnd(() => parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true)); + const expression = allowInAnd(() => + parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true) + ); parseExpected(SyntaxKind.CloseParenToken); node = factoryCreateForOfStatement(awaitToken, initializer, expression, parseStatement()); } @@ -6906,7 +8331,12 @@ namespace Parser { const openParenPosition = scanner.getTokenStart(); const openParenParsed = parseExpected(SyntaxKind.OpenParenToken); const expression = allowInAnd(parseExpression); - parseExpectedMatchingBrackets(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, openParenParsed, openParenPosition); + parseExpectedMatchingBrackets( + SyntaxKind.OpenParenToken, + SyntaxKind.CloseParenToken, + openParenParsed, + openParenPosition, + ); const statement = doInsideOfContext(NodeFlags.InWithStatement, parseStatement); return withJSDoc(finishNode(factory.createWithStatement(expression, statement), pos), hasJSDoc); } @@ -7064,7 +8494,9 @@ namespace Parser { function nextTokenIsIdentifierOrKeywordOrLiteralOnSameLine() { nextToken(); - return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) && !scanner.hasPrecedingLineBreak(); + return (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NumericLiteral + || token() === SyntaxKind.BigIntLiteral || token() === SyntaxKind.StringLiteral) + && !scanner.hasPrecedingLineBreak(); } function isDeclaration(): boolean { @@ -7132,20 +8564,23 @@ namespace Parser { case SyntaxKind.GlobalKeyword: nextToken(); - return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier || token() === SyntaxKind.ExportKeyword; + return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.Identifier + || token() === SyntaxKind.ExportKeyword; case SyntaxKind.ImportKeyword: nextToken(); - return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken || - token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); + return token() === SyntaxKind.StringLiteral || token() === SyntaxKind.AsteriskToken + || token() === SyntaxKind.OpenBraceToken || tokenIsIdentifierOrKeyword(token()); case SyntaxKind.ExportKeyword: let currentToken = nextToken(); if (currentToken === SyntaxKind.TypeKeyword) { currentToken = lookAhead(nextToken); } - if (currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken || - currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword || - currentToken === SyntaxKind.AsKeyword || currentToken === SyntaxKind.AtToken) { + if ( + currentToken === SyntaxKind.EqualsToken || currentToken === SyntaxKind.AsteriskToken + || currentToken === SyntaxKind.OpenBraceToken || currentToken === SyntaxKind.DefaultKeyword + || currentToken === SyntaxKind.AsKeyword || currentToken === SyntaxKind.AtToken + ) { return true; } continue; @@ -7228,7 +8663,8 @@ namespace Parser { function nextTokenIsBindingIdentifierOrStartOfDestructuring() { nextToken(); - return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken; + return isBindingIdentifier() || token() === SyntaxKind.OpenBraceToken + || token() === SyntaxKind.OpenBracketToken; } function isLetDeclaration() { @@ -7394,7 +8830,11 @@ namespace Parser { }); } - function parseDeclarationWorker(pos: number, hasJSDoc: boolean, modifiersIn: NodeArray | undefined): Statement { + function parseDeclarationWorker( + pos: number, + hasJSDoc: boolean, + modifiersIn: NodeArray | undefined, + ): Statement { switch (token()) { case SyntaxKind.VarKeyword: case SyntaxKind.LetKeyword: @@ -7433,7 +8873,11 @@ namespace Parser { if (modifiersIn) { // We reached this point because we encountered decorators and/or modifiers and assumed a declaration // would follow. For recovery and error reporting purposes, return an incomplete declaration. - const missing = createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); + const missing = createMissingNode( + SyntaxKind.MissingDeclaration, + /*reportAtCurrentPosition*/ true, + Diagnostics.Declaration_expected, + ); setTextRangePos(missing, pos); (missing as Mutable).modifiers = modifiersIn; return missing; @@ -7450,7 +8894,10 @@ namespace Parser { return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral); } - function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block | undefined { + function parseFunctionBlockOrSemicolon( + flags: SignatureFlags, + diagnosticMessage?: DiagnosticMessage, + ): Block | undefined { if (token() !== SyntaxKind.OpenBraceToken) { if (flags & SignatureFlags.Type) { parseTypeMemberSemicolon(); @@ -7474,7 +8921,10 @@ namespace Parser { const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); const name = parseIdentifierOrPattern(); const initializer = parseInitializer(); - return finishNode(factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), pos); + return finishNode( + factory.createBindingElement(dotDotDotToken, /*propertyName*/ undefined, name, initializer), + pos, + ); } function parseObjectBindingElement(): BindingElement { @@ -7498,7 +8948,9 @@ namespace Parser { function parseObjectBindingPattern(): ObjectBindingPattern { const pos = getNodePos(); parseExpected(SyntaxKind.OpenBraceToken); - const elements = allowInAnd(() => parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement)); + const elements = allowInAnd(() => + parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement) + ); parseExpected(SyntaxKind.CloseBraceToken); return finishNode(factory.createObjectBindingPattern(elements), pos); } @@ -7506,7 +8958,9 @@ namespace Parser { function parseArrayBindingPattern(): ArrayBindingPattern { const pos = getNodePos(); parseExpected(SyntaxKind.OpenBracketToken); - const elements = allowInAnd(() => parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement)); + const elements = allowInAnd(() => + parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement) + ); parseExpected(SyntaxKind.CloseBracketToken); return finishNode(factory.createArrayBindingPattern(elements), pos); } @@ -7518,7 +8972,9 @@ namespace Parser { || isBindingIdentifier(); } - function parseIdentifierOrPattern(privateIdentifierDiagnosticMessage?: DiagnosticMessage): Identifier | BindingPattern { + function parseIdentifierOrPattern( + privateIdentifierDiagnosticMessage?: DiagnosticMessage, + ): Identifier | BindingPattern { if (token() === SyntaxKind.OpenBracketToken) { return parseArrayBindingPattern(); } @@ -7537,8 +8993,10 @@ namespace Parser { const hasJSDoc = hasPrecedingJSDocComment(); const name = parseIdentifierOrPattern(Diagnostics.Private_identifiers_are_not_allowed_in_variable_declarations); let exclamationToken: ExclamationToken | undefined; - if (allowExclamation && name.kind === SyntaxKind.Identifier && - token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { + if ( + allowExclamation && name.kind === SyntaxKind.Identifier + && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak() + ) { exclamationToken = parseTokenNode>(); } const type = parseTypeAnnotation(); @@ -7591,8 +9049,10 @@ namespace Parser { const savedDisallowIn = inDisallowInContext(); setDisallowInContext(inForStatementInitializer); - declarations = parseDelimitedList(ParsingContext.VariableDeclarations, - inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation); + declarations = parseDelimitedList( + ParsingContext.VariableDeclarations, + inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation, + ); setDisallowInContext(savedDisallowIn); } @@ -7604,20 +9064,29 @@ namespace Parser { return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; } - function parseVariableStatement(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): VariableStatement { + function parseVariableStatement( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): VariableStatement { const declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false); parseSemicolon(); const node = factoryCreateVariableStatement(modifiers, declarationList); return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseFunctionDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): FunctionDeclaration { + function parseFunctionDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): FunctionDeclaration { const savedAwaitContext = inAwaitContext(); const modifierFlags = modifiersToFlags(modifiers); parseExpected(SyntaxKind.FunctionKeyword); const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); // We don't parse the name here in await context, instead we will report a grammar error in the checker. - const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() : parseBindingIdentifier(); + const name = modifierFlags & ModifierFlags.Default ? parseOptionalBindingIdentifier() + : parseBindingIdentifier(); const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; const isAsync = modifierFlags & ModifierFlags.Async ? SignatureFlags.Await : SignatureFlags.None; const typeParameters = parseTypeParameters(); @@ -7626,7 +9095,15 @@ namespace Parser { const type = parseReturnType(SyntaxKind.ColonToken, /*isType*/ false); const body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected); setAwaitContext(savedAwaitContext); - const node = factory.createFunctionDeclaration(modifiers, asteriskToken, name, typeParameters, parameters, type, body); + const node = factory.createFunctionDeclaration( + modifiers, + asteriskToken, + name, + typeParameters, + parameters, + type, + body, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } @@ -7642,7 +9119,11 @@ namespace Parser { } } - function tryParseConstructorDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): ConstructorDeclaration | undefined { + function tryParseConstructorDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): ConstructorDeclaration | undefined { return tryParse(() => { if (parseConstructorName()) { const typeParameters = parseTypeParameters(); @@ -7667,7 +9148,7 @@ namespace Parser { name: PropertyName, questionToken: QuestionToken | undefined, exclamationToken: ExclamationToken | undefined, - diagnosticMessage?: DiagnosticMessage + diagnosticMessage?: DiagnosticMessage, ): MethodDeclaration { const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None; const isAsync = some(modifiers, isAsyncModifier) ? SignatureFlags.Await : SignatureFlags.None; @@ -7683,7 +9164,7 @@ namespace Parser { typeParameters, parameters, type, - body + body, ); // An exclamation token on a method is invalid syntax and will be handled by the grammar checker @@ -7696,25 +9177,30 @@ namespace Parser { hasJSDoc: boolean, modifiers: NodeArray | undefined, name: PropertyName, - questionToken: QuestionToken | undefined + questionToken: QuestionToken | undefined, ): PropertyDeclaration { - const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined; + const exclamationToken = !questionToken && !scanner.hasPrecedingLineBreak() + ? parseOptionalToken(SyntaxKind.ExclamationToken) : undefined; const type = parseTypeAnnotation(); - const initializer = doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, parseInitializer); + const initializer = doOutsideOfContext( + NodeFlags.YieldContext | NodeFlags.AwaitContext | NodeFlags.DisallowInContext, + parseInitializer, + ); parseSemicolonAfterPropertyName(name, type, initializer); const node = factory.createPropertyDeclaration( modifiers, name, questionToken || exclamationToken, type, - initializer); + initializer, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } function parsePropertyOrMethodDeclaration( pos: number, hasJSDoc: boolean, - modifiers: NodeArray | undefined + modifiers: NodeArray | undefined, ): PropertyDeclaration | MethodDeclaration { const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); const name = parsePropertyName(); @@ -7722,12 +9208,27 @@ namespace Parser { // report an error in the grammar checker. const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) { - return parseMethodDeclaration(pos, hasJSDoc, modifiers, asteriskToken, name, questionToken, /*exclamationToken*/ undefined, Diagnostics.or_expected); + return parseMethodDeclaration( + pos, + hasJSDoc, + modifiers, + asteriskToken, + name, + questionToken, + /*exclamationToken*/ undefined, + Diagnostics.or_expected, + ); } return parsePropertyDeclaration(pos, hasJSDoc, modifiers, name, questionToken); } - function parseAccessorDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined, kind: AccessorDeclaration["kind"], flags: SignatureFlags): AccessorDeclaration { + function parseAccessorDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + kind: AccessorDeclaration["kind"], + flags: SignatureFlags, + ): AccessorDeclaration { const name = parsePropertyName(); const typeParameters = parseTypeParameters(); const parameters = parseParameters(SignatureFlags.None); @@ -7791,12 +9292,12 @@ namespace Parser { // If it *is* a keyword, but not an accessor, check a little farther along // to see if it should actually be parsed as a class member. switch (token()) { - case SyntaxKind.OpenParenToken: // Method declaration - case SyntaxKind.LessThanToken: // Generic Method declaration - case SyntaxKind.ExclamationToken: // Non-null assertion on property name - case SyntaxKind.ColonToken: // Type Annotation for declaration - case SyntaxKind.EqualsToken: // Initializer for declaration - case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on. + case SyntaxKind.OpenParenToken: // Method declaration + case SyntaxKind.LessThanToken: // Generic Method declaration + case SyntaxKind.ExclamationToken: // Non-null assertion on property name + case SyntaxKind.ColonToken: // Type Annotation for declaration + case SyntaxKind.EqualsToken: // Initializer for declaration + case SyntaxKind.QuestionToken: // Not valid, but permitted so that it gets caught later on. return true; default: // Covers @@ -7811,7 +9312,11 @@ namespace Parser { return false; } - function parseClassStaticBlockDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): ClassStaticBlockDeclaration { + function parseClassStaticBlockDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): ClassStaticBlockDeclaration { parseExpectedToken(SyntaxKind.StaticKeyword); const body = parseClassStaticBlockBody(); const node = withJSDoc(finishNode(factory.createClassStaticBlockDeclaration(body), pos), hasJSDoc); @@ -7856,7 +9361,11 @@ namespace Parser { return finishNode(factory.createDecorator(expression), pos); } - function tryParseModifier(hasSeenStaticModifier: boolean, permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): Modifier | undefined { + function tryParseModifier( + hasSeenStaticModifier: boolean, + permitConstAsModifier?: boolean, + stopOnStartOfClassStaticBlock?: boolean, + ): Modifier | undefined { const pos = getNodePos(); const kind = token(); @@ -7867,7 +9376,9 @@ namespace Parser { return undefined; } } - else if (stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { + else if ( + stopOnStartOfClassStaticBlock && token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace) + ) { return undefined; } else if (hasSeenStaticModifier && token() === SyntaxKind.StaticKeyword) { @@ -7883,18 +9394,34 @@ namespace Parser { } /* - * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member. - * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect - * and turns it into a standalone declaration), then it is better to parse it and report an error later. - * - * In such situations, 'permitConstAsModifier' should be set to true. - */ - function parseModifiers(allowDecorators: false, permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray | undefined; - function parseModifiers(allowDecorators: true, permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray | undefined; - function parseModifiers(allowDecorators: boolean, permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray | undefined { + * There are situations in which a modifier like 'const' will appear unexpectedly, such as on a class member. + * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect + * and turns it into a standalone declaration), then it is better to parse it and report an error later. + * + * In such situations, 'permitConstAsModifier' should be set to true. + */ + function parseModifiers( + allowDecorators: false, + permitConstAsModifier?: boolean, + stopOnStartOfClassStaticBlock?: boolean, + ): NodeArray | undefined; + function parseModifiers( + allowDecorators: true, + permitConstAsModifier?: boolean, + stopOnStartOfClassStaticBlock?: boolean, + ): NodeArray | undefined; + function parseModifiers( + allowDecorators: boolean, + permitConstAsModifier?: boolean, + stopOnStartOfClassStaticBlock?: boolean, + ): NodeArray | undefined { const pos = getNodePos(); let list: ModifierLike[] | undefined; - let decorator, modifier, hasSeenStaticModifier = false, hasLeadingModifier = false, hasTrailingDecorator = false; + let decorator, + modifier, + hasSeenStaticModifier = false, + hasLeadingModifier = false, + hasTrailingDecorator = false; // Decorators should be contiguous in a list of modifiers but can potentially appear in two places (i.e., `[...leadingDecorators, ...leadingModifiers, ...trailingDecorators, ...trailingModifiers]`). // The leading modifiers *should* only contain `export` and `default` when trailingDecorators are present, but we'll handle errors for any other leading modifiers in the checker. @@ -7908,7 +9435,9 @@ namespace Parser { } // parse leading modifiers - while (modifier = tryParseModifier(hasSeenStaticModifier, permitConstAsModifier, stopOnStartOfClassStaticBlock)) { + while ( + modifier = tryParseModifier(hasSeenStaticModifier, permitConstAsModifier, stopOnStartOfClassStaticBlock) + ) { if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStaticModifier = true; list = append(list, modifier); hasLeadingModifier = true; @@ -7924,7 +9453,9 @@ namespace Parser { // parse trailing modifiers, but only if we parsed any trailing decorators if (hasTrailingDecorator) { - while (modifier = tryParseModifier(hasSeenStaticModifier, permitConstAsModifier, stopOnStartOfClassStaticBlock)) { + while ( + modifier = tryParseModifier(hasSeenStaticModifier, permitConstAsModifier, stopOnStartOfClassStaticBlock) + ) { if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStaticModifier = true; list = append(list, modifier); } @@ -7952,7 +9483,11 @@ namespace Parser { return withJSDoc(finishNode(factory.createSemicolonClassElement(), pos), hasJSDoc); } - const modifiers = parseModifiers(/*allowDecorators*/ true, /*permitConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true); + const modifiers = parseModifiers( + /*allowDecorators*/ true, + /*permitConstAsModifier*/ true, + /*stopOnStartOfClassStaticBlock*/ true, + ); if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { return parseClassStaticBlockDeclaration(pos, hasJSDoc, modifiers); } @@ -7978,17 +9513,22 @@ namespace Parser { // It is very important that we check this *after* checking indexers because // the [ token can start an index signature or a computed property name - if (tokenIsIdentifierOrKeyword(token()) || - token() === SyntaxKind.StringLiteral || - token() === SyntaxKind.NumericLiteral || - token() === SyntaxKind.AsteriskToken || - token() === SyntaxKind.OpenBracketToken) { + if ( + tokenIsIdentifierOrKeyword(token()) + || token() === SyntaxKind.StringLiteral + || token() === SyntaxKind.NumericLiteral + || token() === SyntaxKind.AsteriskToken + || token() === SyntaxKind.OpenBracketToken + ) { const isAmbient = some(modifiers, isDeclareModifier); if (isAmbient) { for (const m of modifiers!) { (m as Mutable).flags |= NodeFlags.Ambient; } - return doInsideOfContext(NodeFlags.Ambient, () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, modifiers)); + return doInsideOfContext( + NodeFlags.Ambient, + () => parsePropertyOrMethodDeclaration(pos, hasJSDoc, modifiers), + ); } else { return parsePropertyOrMethodDeclaration(pos, hasJSDoc, modifiers); @@ -7997,7 +9537,11 @@ namespace Parser { if (modifiers) { // treat this as a property declaration with a missing name. - const name = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); + const name = createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ true, + Diagnostics.Declaration_expected, + ); return parsePropertyDeclaration(pos, hasJSDoc, modifiers, name, /*questionToken*/ undefined); } @@ -8010,24 +9554,52 @@ namespace Parser { const hasJSDoc = hasPrecedingJSDocComment(); const modifiers = parseModifiers(/*allowDecorators*/ true); if (token() === SyntaxKind.ClassKeyword) { - return parseClassDeclarationOrExpression(pos, hasJSDoc, modifiers, SyntaxKind.ClassExpression) as ClassExpression; + return parseClassDeclarationOrExpression( + pos, + hasJSDoc, + modifiers, + SyntaxKind.ClassExpression, + ) as ClassExpression; } - const missing = createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Expression_expected); + const missing = createMissingNode( + SyntaxKind.MissingDeclaration, + /*reportAtCurrentPosition*/ true, + Diagnostics.Expression_expected, + ); setTextRangePos(missing, pos); (missing as Mutable).modifiers = modifiers; return missing; } function parseClassExpression(): ClassExpression { - return parseClassDeclarationOrExpression(getNodePos(), hasPrecedingJSDocComment(), /*modifiers*/ undefined, SyntaxKind.ClassExpression) as ClassExpression; + return parseClassDeclarationOrExpression( + getNodePos(), + hasPrecedingJSDocComment(), + /*modifiers*/ undefined, + SyntaxKind.ClassExpression, + ) as ClassExpression; } - function parseClassDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): ClassDeclaration { - return parseClassDeclarationOrExpression(pos, hasJSDoc, modifiers, SyntaxKind.ClassDeclaration) as ClassDeclaration; + function parseClassDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): ClassDeclaration { + return parseClassDeclarationOrExpression( + pos, + hasJSDoc, + modifiers, + SyntaxKind.ClassDeclaration, + ) as ClassDeclaration; } - function parseClassDeclarationOrExpression(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined, kind: ClassLikeDeclaration["kind"]): ClassLikeDeclaration { + function parseClassDeclarationOrExpression( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + kind: ClassLikeDeclaration["kind"], + ): ClassLikeDeclaration { const savedAwaitContext = inAwaitContext(); parseExpected(SyntaxKind.ClassKeyword); @@ -8100,8 +9672,13 @@ namespace Parser { } function tryParseTypeArguments(): NodeArray | undefined { - return token() === SyntaxKind.LessThanToken ? - parseBracketedList(ParsingContext.TypeArguments, parseType, SyntaxKind.LessThanToken, SyntaxKind.GreaterThanToken) : undefined; + return token() === SyntaxKind.LessThanToken + ? parseBracketedList( + ParsingContext.TypeArguments, + parseType, + SyntaxKind.LessThanToken, + SyntaxKind.GreaterThanToken, + ) : undefined; } function isHeritageClause(): boolean { @@ -8112,7 +9689,11 @@ namespace Parser { return parseList(ParsingContext.ClassMembers, parseClassElement); } - function parseInterfaceDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): InterfaceDeclaration { + function parseInterfaceDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): InterfaceDeclaration { parseExpected(SyntaxKind.InterfaceKeyword); const name = parseIdentifier(); const typeParameters = parseTypeParameters(); @@ -8122,7 +9703,11 @@ namespace Parser { return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseTypeAliasDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): TypeAliasDeclaration { + function parseTypeAliasDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): TypeAliasDeclaration { parseExpected(SyntaxKind.TypeKeyword); if (scanner.hasPrecedingLineBreak()) { parseErrorAtCurrentToken(Diagnostics.Line_break_not_permitted_here); @@ -8148,12 +9733,18 @@ namespace Parser { return withJSDoc(finishNode(factory.createEnumMember(name, initializer), pos), hasJSDoc); } - function parseEnumDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): EnumDeclaration { + function parseEnumDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): EnumDeclaration { parseExpected(SyntaxKind.EnumKeyword); const name = parseIdentifier(); let members; if (parseExpected(SyntaxKind.OpenBraceToken)) { - members = doOutsideOfYieldAndAwaitContext(() => parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember)); + members = doOutsideOfYieldAndAwaitContext(() => + parseDelimitedList(ParsingContext.EnumMembers, parseEnumMember) + ); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -8176,19 +9767,33 @@ namespace Parser { return finishNode(factory.createModuleBlock(statements), pos); } - function parseModuleOrNamespaceDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined, flags: NodeFlags): ModuleDeclaration { + function parseModuleOrNamespaceDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + flags: NodeFlags, + ): ModuleDeclaration { // If we are parsing a dotted namespace name, we want to // propagate the 'Namespace' flag across the names if set. const namespaceFlag = flags & NodeFlags.Namespace; const name = parseIdentifier(); const body = parseOptional(SyntaxKind.DotToken) - ? parseModuleOrNamespaceDeclaration(getNodePos(), /*hasJSDoc*/ false, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) as NamespaceDeclaration + ? parseModuleOrNamespaceDeclaration( + getNodePos(), + /*hasJSDoc*/ false, + /*modifiers*/ undefined, + NodeFlags.NestedNamespace | namespaceFlag, + ) as NamespaceDeclaration : parseModuleBlock(); const node = factory.createModuleDeclaration(modifiers, name, body, flags); return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseAmbientExternalModuleDeclaration(pos: number, hasJSDoc: boolean, modifiersIn: NodeArray | undefined): ModuleDeclaration { + function parseAmbientExternalModuleDeclaration( + pos: number, + hasJSDoc: boolean, + modifiersIn: NodeArray | undefined, + ): ModuleDeclaration { let flags: NodeFlags = 0; let name; if (token() === SyntaxKind.GlobalKeyword) { @@ -8211,7 +9816,11 @@ namespace Parser { return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseModuleDeclaration(pos: number, hasJSDoc: boolean, modifiersIn: NodeArray | undefined): ModuleDeclaration { + function parseModuleDeclaration( + pos: number, + hasJSDoc: boolean, + modifiersIn: NodeArray | undefined, + ): ModuleDeclaration { let flags: NodeFlags = 0; if (token() === SyntaxKind.GlobalKeyword) { // global augmentation @@ -8230,8 +9839,8 @@ namespace Parser { } function isExternalModuleReference() { - return token() === SyntaxKind.RequireKeyword && - lookAhead(nextTokenIsOpenParen); + return token() === SyntaxKind.RequireKeyword + && lookAhead(nextTokenIsOpenParen); } function nextTokenIsOpenParen() { @@ -8246,7 +9855,11 @@ namespace Parser { return nextToken() === SyntaxKind.SlashToken; } - function parseNamespaceExportDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): NamespaceExportDeclaration { + function parseNamespaceExportDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): NamespaceExportDeclaration { parseExpected(SyntaxKind.AsKeyword); parseExpected(SyntaxKind.NamespaceKeyword); const name = parseIdentifier(); @@ -8257,7 +9870,11 @@ namespace Parser { return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseImportDeclarationOrImportEqualsDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): ImportEqualsDeclaration | ImportDeclaration { + function parseImportDeclarationOrImportEqualsDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): ImportEqualsDeclaration | ImportDeclaration { parseExpected(SyntaxKind.ImportKeyword); const afterImportPos = scanner.getTokenFullStart(); @@ -8269,9 +9886,10 @@ namespace Parser { } let isTypeOnly = false; - if (token() !== SyntaxKind.FromKeyword && - identifier?.escapedText === "type" && - (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration()) + if ( + token() !== SyntaxKind.FromKeyword + && identifier?.escapedText === "type" + && (isIdentifier() || tokenAfterImportDefinitelyProducesImportDeclaration()) ) { isTypeOnly = true; identifier = isIdentifier() ? parseIdentifier() : undefined; @@ -8285,9 +9903,10 @@ namespace Parser { // import ImportClause from ModuleSpecifier ; // import ModuleSpecifier; let importClause: ImportClause | undefined; - if (identifier || // import id - token() === SyntaxKind.AsteriskToken || // import * - token() === SyntaxKind.OpenBraceToken // import { + if ( + identifier // import id + || token() === SyntaxKind.AsteriskToken // import * + || token() === SyntaxKind.OpenBraceToken // import { ) { importClause = parseImportClause(identifier, afterImportPos, isTypeOnly); parseExpected(SyntaxKind.FromKeyword); @@ -8306,7 +9925,8 @@ namespace Parser { function parseAssertEntry() { const pos = getNodePos(); - const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral; + const name = tokenIsIdentifierOrKeyword(token()) ? parseIdentifierName() + : parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral; parseExpected(SyntaxKind.ColonToken); const value = parseAssignmentExpressionOrHigher(/*allowReturnTypeInArrowFunction*/ true); return finishNode(factory.createAssertEntry(name, value), pos); @@ -8320,13 +9940,25 @@ namespace Parser { const openBracePosition = scanner.getTokenStart(); if (parseExpected(SyntaxKind.OpenBraceToken)) { const multiLine = scanner.hasPrecedingLineBreak(); - const elements = parseDelimitedList(ParsingContext.AssertEntries, parseAssertEntry, /*considerSemicolonAsDelimiter*/ true); + const elements = parseDelimitedList( + ParsingContext.AssertEntries, + parseAssertEntry, + /*considerSemicolonAsDelimiter*/ true, + ); if (!parseExpected(SyntaxKind.CloseBraceToken)) { const lastError = lastOrUndefined(parseDiagnostics); if (lastError && lastError.code === Diagnostics._0_expected.code) { addRelatedInfo( lastError, - createDetachedDiagnostic(fileName, sourceText, openBracePosition, 1, Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, "{", "}") + createDetachedDiagnostic( + fileName, + sourceText, + openBracePosition, + 1, + Diagnostics.The_parser_expected_to_find_a_1_to_match_the_0_token_here, + "{", + "}", + ), ); } } @@ -8348,7 +9980,13 @@ namespace Parser { return token() === SyntaxKind.CommaToken || token() === SyntaxKind.FromKeyword; } - function parseImportEqualsDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined, identifier: Identifier, isTypeOnly: boolean): ImportEqualsDeclaration { + function parseImportEqualsDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + identifier: Identifier, + isTypeOnly: boolean, + ): ImportEqualsDeclaration { parseExpected(SyntaxKind.EqualsToken); const moduleReference = parseModuleReference(); parseSemicolon(); @@ -8368,9 +10006,12 @@ namespace Parser { // If there was no default import or if there is comma token after default import // parse namespace or named imports let namedBindings: NamespaceImport | NamedImports | undefined; - if (!identifier || - parseOptional(SyntaxKind.CommaToken)) { - namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() : parseNamedImportsOrExports(SyntaxKind.NamedImports); + if ( + !identifier + || parseOptional(SyntaxKind.CommaToken) + ) { + namedBindings = token() === SyntaxKind.AsteriskToken ? parseNamespaceImport() + : parseNamedImportsOrExports(SyntaxKind.NamedImports); } return finishNode(factory.createImportClause(isTypeOnly, identifier, namedBindings), pos); @@ -8429,8 +10070,22 @@ namespace Parser { // ImportSpecifier // ImportsList, ImportSpecifier const node = kind === SyntaxKind.NamedImports - ? factory.createNamedImports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseImportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)) - : factory.createNamedExports(parseBracketedList(ParsingContext.ImportOrExportSpecifiers, parseExportSpecifier, SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken)); + ? factory.createNamedImports( + parseBracketedList( + ParsingContext.ImportOrExportSpecifiers, + parseImportSpecifier, + SyntaxKind.OpenBraceToken, + SyntaxKind.CloseBraceToken, + ), + ) + : factory.createNamedExports( + parseBracketedList( + ParsingContext.ImportOrExportSpecifiers, + parseExportSpecifier, + SyntaxKind.OpenBraceToken, + SyntaxKind.CloseBraceToken, + ), + ); return finishNode(node, pos); } @@ -8530,7 +10185,11 @@ namespace Parser { return finishNode(factory.createNamespaceExport(parseIdentifierName()), pos); } - function parseExportDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): ExportDeclaration { + function parseExportDeclaration( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): ExportDeclaration { const savedAwaitContext = inAwaitContext(); setAwaitContext(/*value*/ true); let exportClause: NamedExportBindings | undefined; @@ -8550,7 +10209,10 @@ namespace Parser { // It is not uncommon to accidentally omit the 'from' keyword. Additionally, in editing scenarios, // the 'from' keyword can be parsed as a named export when the export clause is unterminated (i.e. `export { from "moduleName";`) // If we don't have a 'from' keyword, see if we have a string literal such that ASI won't take effect. - if (token() === SyntaxKind.FromKeyword || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak())) { + if ( + token() === SyntaxKind.FromKeyword + || (token() === SyntaxKind.StringLiteral && !scanner.hasPrecedingLineBreak()) + ) { parseExpected(SyntaxKind.FromKeyword); moduleSpecifier = parseModuleSpecifier(); } @@ -8560,11 +10222,21 @@ namespace Parser { } parseSemicolon(); setAwaitContext(savedAwaitContext); - const node = factory.createExportDeclaration(modifiers, isTypeOnly, exportClause, moduleSpecifier, assertClause); + const node = factory.createExportDeclaration( + modifiers, + isTypeOnly, + exportClause, + moduleSpecifier, + assertClause, + ); return withJSDoc(finishNode(node, pos), hasJSDoc); } - function parseExportAssignment(pos: number, hasJSDoc: boolean, modifiers: NodeArray | undefined): ExportAssignment { + function parseExportAssignment( + pos: number, + hasJSDoc: boolean, + modifiers: NodeArray | undefined, + ): ExportAssignment { const savedAwaitContext = inAwaitContext(); setAwaitContext(/*value*/ true); let isExportEquals: boolean | undefined; @@ -8581,6 +10253,7 @@ namespace Parser { return withJSDoc(finishNode(node, pos), hasJSDoc); } + // dprint-ignore const enum ParsingContext { SourceElements, // Elements in source file BlockStatements, // Statements in block @@ -8608,23 +10281,36 @@ namespace Parser { ImportOrExportSpecifiers, // Named import clause's import specifier list, AssertEntries, // Import entries list. JSDocComment, // Parsing via JSDocParser - Count // Number of parsing contexts + Count, // Number of parsing contexts } const enum Tristate { False, True, - Unknown + Unknown, } export namespace JSDocParser { - export function parseJSDocTypeExpressionForTests(content: string, start: number | undefined, length: number | undefined): { jsDocTypeExpression: JSDocTypeExpression, diagnostics: Diagnostic[] } | undefined { + export function parseJSDocTypeExpressionForTests( + content: string, + start: number | undefined, + length: number | undefined, + ): { jsDocTypeExpression: JSDocTypeExpression; diagnostics: Diagnostic[]; } | undefined { initializeState("file.js", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS); scanner.setText(content, start, length); currentToken = scanner.scan(); const jsDocTypeExpression = parseJSDocTypeExpression(); - const sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS, /*isDeclarationFile*/ false, [], factoryCreateToken(SyntaxKind.EndOfFileToken), NodeFlags.None, noop); + const sourceFile = createSourceFile( + "file.js", + ScriptTarget.Latest, + ScriptKind.JS, + /*isDeclarationFile*/ false, + [], + factoryCreateToken(SyntaxKind.EndOfFileToken), + NodeFlags.None, + noop, + ); const diagnostics = attachFileToDiagnostics(parseDiagnostics, sourceFile); if (jsDocDiagnostics) { sourceFile.jsDocDiagnostics = attachFileToDiagnostics(jsDocDiagnostics, sourceFile); @@ -8668,7 +10354,11 @@ namespace Parser { return finishNode(result, pos); } - export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined { + export function parseIsolatedJSDocComment( + content: string, + start: number | undefined, + length: number | undefined, + ): { jsDoc: JSDoc; diagnostics: Diagnostic[]; } | undefined { initializeState("", content, ScriptTarget.Latest, /*syntaxCursor*/ undefined, ScriptKind.JS); const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length)); @@ -8764,7 +10454,8 @@ namespace Parser { state = JSDocState.BeginningOfLine; indent = 0; } - loop: while (true) { + loop: + while (true) { switch (token()) { case SyntaxKind.AtToken: removeTrailingWhitespace(comments); @@ -8796,7 +10487,10 @@ namespace Parser { } break; case SyntaxKind.WhitespaceTrivia: - Debug.assert(state !== JSDocState.SavingComments, "whitespace shouldn't come from the scanner while saving top-level comment text"); + Debug.assert( + state !== JSDocState.SavingComments, + "whitespace shouldn't come from the scanner while saving top-level comment text", + ); // only collect whitespace if we're already saving comments or have just crossed the comment indent margin const whitespace = scanner.getTokenText(); if (margin !== undefined && indent + whitespace.length > margin) { @@ -8819,7 +10513,13 @@ namespace Parser { if (!linkEnd) { removeLeadingNewlines(comments); } - parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentEnd)); + parts.push( + finishNode( + factory.createJSDocText(comments.join("")), + linkEnd ?? start, + commentEnd, + ), + ); parts.push(link); comments = []; linkEnd = scanner.getTokenEnd(); @@ -8845,9 +10545,22 @@ namespace Parser { if (parts.length && trimmedComments.length) { parts.push(finishNode(factory.createJSDocText(trimmedComments), linkEnd ?? start, commentsPos)); } - if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set"); + if (parts.length && tags) { + Debug.assertIsDefined( + commentsPos, + "having parsed tags implies that the end of the comment span should be set", + ); + } const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd); - return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : trimmedComments.length ? trimmedComments : undefined, tagsArray), start, end); + return finishNode( + factory.createJSDocComment( + parts.length ? createNodeArray(parts, start, commentsPos) + : trimmedComments.length ? trimmedComments : undefined, + tagsArray, + ), + start, + end, + ); } function removeLeadingNewlines(comments: string[]) { @@ -8906,7 +10619,10 @@ namespace Parser { let precedingLineBreak = scanner.hasPrecedingLineBreak(); let seenLineBreak = false; let indentText = ""; - while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) { + while ( + (precedingLineBreak && token() === SyntaxKind.AsteriskToken) + || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia + ) { indentText += scanner.getTokenText(); if (token() === SyntaxKind.NewLineTrivia) { precedingLineBreak = true; @@ -9018,7 +10734,10 @@ namespace Parser { return parseTagComments(margin, indentText.slice(margin)); } - function parseTagComments(indent: number, initialMargin?: string): string | NodeArray | undefined { + function parseTagComments( + indent: number, + initialMargin?: string, + ): string | NodeArray | undefined { const commentsPos = getNodePos(); let comments: string[] = []; const parts: JSDocComment[] = []; @@ -9040,7 +10759,8 @@ namespace Parser { state = JSDocState.SawAsterisk; } let tok = token() as JSDocSyntaxKind | SyntaxKind.JSDocCommentTextToken; - loop: while (true) { + loop: + while (true) { switch (tok) { case SyntaxKind.NewLineTrivia: state = JSDocState.BeginningOfLine; @@ -9055,7 +10775,10 @@ namespace Parser { // Done break loop; case SyntaxKind.WhitespaceTrivia: - Debug.assert(state !== JSDocState.SavingComments && state !== JSDocState.SavingBackticks, "whitespace shouldn't come from the scanner while saving comment text"); + Debug.assert( + state !== JSDocState.SavingComments && state !== JSDocState.SavingBackticks, + "whitespace shouldn't come from the scanner while saving comment text", + ); const whitespace = scanner.getTokenText(); // if the whitespace crosses the margin, take only the whitespace that passes the margin if (margin !== undefined && indent + whitespace.length > margin) { @@ -9070,7 +10793,13 @@ namespace Parser { const linkStart = scanner.getTokenEnd() - 1; const link = parseJSDocLink(linkStart); if (link) { - parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos, commentEnd)); + parts.push( + finishNode( + factory.createJSDocText(comments.join("")), + linkEnd ?? commentsPos, + commentEnd, + ), + ); parts.push(link); comments = []; linkEnd = scanner.getTokenEnd(); @@ -9151,7 +10880,10 @@ namespace Parser { } } const text = []; - while (token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia && token() !== SyntaxKind.EndOfFileToken) { + while ( + token() !== SyntaxKind.CloseBraceToken && token() !== SyntaxKind.NewLineTrivia + && token() !== SyntaxKind.EndOfFileToken + ) { text.push(scanner.getTokenText()); nextTokenJSDoc(); } @@ -9163,9 +10895,11 @@ namespace Parser { function parseJSDocLinkPrefix() { skipWhitespaceOrAsterisk(); - if (token() === SyntaxKind.OpenBraceToken + if ( + token() === SyntaxKind.OpenBraceToken && nextTokenJSDoc() === SyntaxKind.AtToken - && tokenIsIdentifierOrKeyword(nextTokenJSDoc())) { + && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) + ) { const kind = scanner.getTokenValue(); if (isJSDocLinkTag(kind)) return kind; } @@ -9176,7 +10910,13 @@ namespace Parser { } function parseUnknownTag(start: number, tagName: Identifier, indent: number, indentText: string) { - return finishNode(factory.createJSDocUnknownTag(tagName, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); + return finishNode( + factory.createJSDocUnknownTag( + tagName, + parseTrailingTagComments(start, getNodePos(), indent, indentText), + ), + start, + ); } function addTag(tag: JSDocTag | undefined): void { @@ -9198,7 +10938,7 @@ namespace Parser { return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; } - function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } { + function parseBracketNameInPropertyAndParamTag(): { name: EntityName; isBracketed: boolean; } { // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar' const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken); if (isBracketed) { @@ -9230,11 +10970,17 @@ namespace Parser { case SyntaxKind.ArrayType: return isObjectOrObjectArrayTypeReference((node as ArrayTypeNode).elementType); default: - return isTypeReferenceNode(node) && isIdentifierNode(node.typeName) && node.typeName.escapedText === "Object" && !node.typeArguments; + return isTypeReferenceNode(node) && isIdentifierNode(node.typeName) + && node.typeName.escapedText === "Object" && !node.typeArguments; } } - function parseParameterOrPropertyTag(start: number, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag { + function parseParameterOrPropertyTag( + start: number, + tagName: Identifier, + target: PropertyLikeParse, + indent: number, + ): JSDocParameterTag | JSDocPropertyTag { let typeExpression = tryParseTypeExpression(); let isNameFirst = !typeExpression; skipWhitespaceOrAsterisk(); @@ -9259,7 +11005,12 @@ namespace Parser { return finishNode(result, start); } - function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) { + function parseNestedTypeLiteral( + typeExpression: JSDocTypeExpression | undefined, + name: EntityName, + target: PropertyLikeParse, + indent: number, + ) { if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) { const pos = getNodePos(); let child: JSDocPropertyLikeTag | JSDocTypeTag | JSDocTemplateTag | false; @@ -9269,50 +11020,103 @@ namespace Parser { children = append(children, child); } else if (child.kind === SyntaxKind.JSDocTemplateTag) { - parseErrorAtRange(child.tagName, Diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag); + parseErrorAtRange( + child.tagName, + Diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag, + ); } } if (children) { - const literal = finishNode(factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), pos); + const literal = finishNode( + factory.createJSDocTypeLiteral(children, typeExpression.type.kind === SyntaxKind.ArrayType), + pos, + ); return finishNode(factory.createJSDocTypeExpression(literal), pos); } } } - function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag { + function parseReturnTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocReturnTag { if (some(tags, isJSDocReturnTag)) { - parseErrorAt(tagName.pos, scanner.getTokenStart(), Diagnostics._0_tag_already_specified, unescapeLeadingUnderscores(tagName.escapedText)); + parseErrorAt( + tagName.pos, + scanner.getTokenStart(), + Diagnostics._0_tag_already_specified, + unescapeLeadingUnderscores(tagName.escapedText), + ); } const typeExpression = tryParseTypeExpression(); - return finishNode(factory.createJSDocReturnTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); + return finishNode( + factory.createJSDocReturnTag( + tagName, + typeExpression, + parseTrailingTagComments(start, getNodePos(), indent, indentText), + ), + start, + ); } - function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag { + function parseTypeTag( + start: number, + tagName: Identifier, + indent?: number, + indentText?: string, + ): JSDocTypeTag { if (some(tags, isJSDocTypeTag)) { - parseErrorAt(tagName.pos, scanner.getTokenStart(), Diagnostics._0_tag_already_specified, unescapeLeadingUnderscores(tagName.escapedText)); + parseErrorAt( + tagName.pos, + scanner.getTokenStart(), + Diagnostics._0_tag_already_specified, + unescapeLeadingUnderscores(tagName.escapedText), + ); } const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); - const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; + const comments = indent !== undefined && indentText !== undefined + ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start); } - function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag { + function parseSeeTag( + start: number, + tagName: Identifier, + indent?: number, + indentText?: string, + ): JSDocSeeTag { const isMarkdownOrJSDocLink = token() === SyntaxKind.OpenBracketToken - || lookAhead(() => nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) && isJSDocLinkTag(scanner.getTokenValue())); + || lookAhead(() => + nextTokenJSDoc() === SyntaxKind.AtToken && tokenIsIdentifierOrKeyword(nextTokenJSDoc()) + && isJSDocLinkTag(scanner.getTokenValue()) + ); const nameExpression = isMarkdownOrJSDocLink ? undefined : parseJSDocNameReference(); - const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; + const comments = indent !== undefined && indentText !== undefined + ? parseTrailingTagComments(start, getNodePos(), indent, indentText) : undefined; return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start); } - function parseThrowsTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocThrowsTag { + function parseThrowsTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocThrowsTag { const typeExpression = tryParseTypeExpression(); const comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); return finishNode(factory.createJSDocThrowsTag(tagName, typeExpression, comment), start); } - function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag { + function parseAuthorTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocAuthorTag { const commentStart = getNodePos(); const textOnly = parseAuthorNameAndEmail(); let commentEnd = scanner.getTokenFullStart(); @@ -9321,7 +11125,10 @@ namespace Parser { commentEnd = scanner.getTokenFullStart(); } const allParts = typeof comments !== "string" - ? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], commentStart) // cast away readonly + ? createNodeArray( + concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as JSDocComment[], + commentStart, + ) // cast away readonly : textOnly.text + comments; return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start); } @@ -9349,30 +11156,64 @@ namespace Parser { return factory.createJSDocText(comments.join("")); } - function parseImplementsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocImplementsTag { + function parseImplementsTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocImplementsTag { const className = parseExpressionWithTypeArgumentsForAugments(); - return finishNode(factory.createJSDocImplementsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + return finishNode( + factory.createJSDocImplementsTag( + tagName, + className, + parseTrailingTagComments(start, getNodePos(), margin, indentText), + ), + start, + ); } - function parseAugmentsTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocAugmentsTag { + function parseAugmentsTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocAugmentsTag { const className = parseExpressionWithTypeArgumentsForAugments(); - return finishNode(factory.createJSDocAugmentsTag(tagName, className, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + return finishNode( + factory.createJSDocAugmentsTag( + tagName, + className, + parseTrailingTagComments(start, getNodePos(), margin, indentText), + ), + start, + ); } - function parseSatisfiesTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocSatisfiesTag { + function parseSatisfiesTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocSatisfiesTag { const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ false); - const comments = margin !== undefined && indentText !== undefined ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined; + const comments = margin !== undefined && indentText !== undefined + ? parseTrailingTagComments(start, getNodePos(), margin, indentText) : undefined; return finishNode(factory.createJSDocSatisfiesTag(tagName, typeExpression, comments), start); } - function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression } { + function parseExpressionWithTypeArgumentsForAugments(): ExpressionWithTypeArguments & { + expression: Identifier | PropertyAccessEntityNameExpression; + } { const usedBrace = parseOptional(SyntaxKind.OpenBraceToken); const pos = getNodePos(); const expression = parsePropertyAccessEntityNameExpression(); scanner.setInJSDocType(true); const typeArguments = tryParseTypeArguments(); scanner.setInJSDocType(false); - const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression }; + const node = factory.createExpressionWithTypeArguments(expression, typeArguments) as + & ExpressionWithTypeArguments + & { expression: Identifier | PropertyAccessEntityNameExpression; }; const res = finishNode(node, pos); if (usedBrace) { parseExpected(SyntaxKind.CloseBraceToken); @@ -9385,28 +11226,69 @@ namespace Parser { let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(); while (parseOptional(SyntaxKind.DotToken)) { const name = parseJSDocIdentifierName(); - node = finishNode(factoryCreatePropertyAccessExpression(node, name), pos) as PropertyAccessEntityNameExpression; + node = finishNode( + factoryCreatePropertyAccessExpression(node, name), + pos, + ) as PropertyAccessEntityNameExpression; } return node; } - function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag { - return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + function parseSimpleTag( + start: number, + createTag: (tagName: Identifier | undefined, comment?: string | NodeArray) => JSDocTag, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocTag { + return finishNode( + createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), + start, + ); } - function parseThisTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocThisTag { + function parseThisTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocThisTag { const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); skipWhitespace(); - return finishNode(factory.createJSDocThisTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + return finishNode( + factory.createJSDocThisTag( + tagName, + typeExpression, + parseTrailingTagComments(start, getNodePos(), margin, indentText), + ), + start, + ); } - function parseEnumTag(start: number, tagName: Identifier, margin: number, indentText: string): JSDocEnumTag { + function parseEnumTag( + start: number, + tagName: Identifier, + margin: number, + indentText: string, + ): JSDocEnumTag { const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); skipWhitespace(); - return finishNode(factory.createJSDocEnumTag(tagName, typeExpression, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start); + return finishNode( + factory.createJSDocEnumTag( + tagName, + typeExpression, + parseTrailingTagComments(start, getNodePos(), margin, indentText), + ), + start, + ); } - function parseTypedefTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTypedefTag { + function parseTypedefTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocTypedefTag { let typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined = tryParseTypeExpression(); skipWhitespaceOrAsterisk(); @@ -9427,9 +11309,20 @@ namespace Parser { hasChildren = true; if (child.kind === SyntaxKind.JSDocTypeTag) { if (childTypeTag) { - const lastError = parseErrorAtCurrentToken(Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags); + const lastError = parseErrorAtCurrentToken( + Diagnostics.A_JSDoc_typedef_comment_may_not_contain_multiple_type_tags, + ); if (lastError) { - addRelatedInfo(lastError, createDetachedDiagnostic(fileName, sourceText, 0, 0, Diagnostics.The_tag_was_first_specified_here)); + addRelatedInfo( + lastError, + createDetachedDiagnostic( + fileName, + sourceText, + 0, + 0, + Diagnostics.The_tag_was_first_specified_here, + ), + ); } break; } @@ -9444,17 +11337,18 @@ namespace Parser { if (hasChildren) { const isArrayType = typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType; const jsdocTypeLiteral = factory.createJSDocTypeLiteral(jsDocPropertyTags, isArrayType); - typeExpression = childTypeTag && childTypeTag.typeExpression && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ? - childTypeTag.typeExpression : - finishNode(jsdocTypeLiteral, start); + typeExpression = childTypeTag && childTypeTag.typeExpression + && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) + ? childTypeTag.typeExpression + : finishNode(jsdocTypeLiteral, start); end = typeExpression.end; } } // Only include the characters between the name end and the next token if a comment was actually parsed out - otherwise it's just whitespace - end = end || comment !== undefined ? - getNodePos() : - (fullName ?? typeExpression ?? tagName).end; + end = end || comment !== undefined + ? getNodePos() + : (fullName ?? typeExpression ?? tagName).end; if (!comment) { comment = parseTrailingTagComments(start, end, indent, indentText); @@ -9476,7 +11370,7 @@ namespace Parser { /*modifiers*/ undefined, typeNameOrNamespaceName, body, - nested ? NodeFlags.NestedNamespace : undefined + nested ? NodeFlags.NestedNamespace : undefined, ) as JSDocNamespaceDeclaration; return finishNode(jsDocNamespaceNode, start); } @@ -9491,9 +11385,18 @@ namespace Parser { const pos = getNodePos(); let child: JSDocParameterTag | JSDocTemplateTag | false; let parameters; - while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag | JSDocTemplateTag)) { + while ( + child = tryParse(() => + parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as + | JSDocParameterTag + | JSDocTemplateTag + ) + ) { if (child.kind === SyntaxKind.JSDocTemplateTag) { - parseErrorAtRange(child.tagName, Diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag); + parseErrorAtRange( + child.tagName, + Diagnostics.A_JSDoc_template_tag_may_not_follow_a_typedef_callback_or_overload_tag, + ); break; } parameters = append(parameters, child); @@ -9511,10 +11414,18 @@ namespace Parser { } } }); - return finishNode(factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), start); + return finishNode( + factory.createJSDocSignature(/*typeParameters*/ undefined, parameters, returnTag), + start, + ); } - function parseCallbackTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocCallbackTag { + function parseCallbackTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocCallbackTag { const fullName = parseJSDocTypeNameWithNamespace(); skipWhitespace(); let comment = parseTagComments(indent); @@ -9523,10 +11434,19 @@ namespace Parser { comment = parseTrailingTagComments(start, getNodePos(), indent, indentText); } const end = comment !== undefined ? getNodePos() : typeExpression.end; - return finishNode(factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), start, end); + return finishNode( + factory.createJSDocCallbackTag(tagName, typeExpression, fullName, comment), + start, + end, + ); } - function parseOverloadTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocOverloadTag { + function parseOverloadTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocOverloadTag { skipWhitespace(); let comment = parseTagComments(indent); const typeExpression = parseJSDocSignature(start, indent); @@ -9551,10 +11471,18 @@ namespace Parser { } function parseChildPropertyTag(indent: number) { - return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | JSDocTemplateTag | false; - } - - function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | false { + return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as + | JSDocTypeTag + | JSDocPropertyTag + | JSDocTemplateTag + | false; + } + + function parseChildParameterOrPropertyTag( + target: PropertyLikeParse, + indent: number, + name?: EntityName, + ): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | false { let canParseTag = true; let seenAsterisk = false; while (true) { @@ -9562,8 +11490,13 @@ namespace Parser { case SyntaxKind.AtToken: if (canParseTag) { const child = tryParseChildTag(target, indent); - if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) && - name && (isIdentifierNode(child.name) || !escapedTextsEqual(name, child.name.left))) { + if ( + child + && (child.kind === SyntaxKind.JSDocParameterTag + || child.kind === SyntaxKind.JSDocPropertyTag) + && name + && (isIdentifierNode(child.name) || !escapedTextsEqual(name, child.name.left)) + ) { return false; } return child; @@ -9589,7 +11522,10 @@ namespace Parser { } } - function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | false { + function tryParseChildTag( + target: PropertyLikeParse, + indent: number, + ): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | false { Debug.assert(token() === SyntaxKind.AtToken); const start = scanner.getTokenFullStart(); nextTokenJSDoc(); @@ -9626,7 +11562,9 @@ namespace Parser { if (isBracketed) { skipWhitespace(); } - const name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces); + const name = parseJSDocIdentifierName( + Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces, + ); let defaultType: TypeNode | undefined; if (isBracketed) { @@ -9639,7 +11577,15 @@ namespace Parser { if (nodeIsMissing(name)) { return undefined; } - return finishNode(factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, /*constraint*/ undefined, defaultType), typeParameterPos); + return finishNode( + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + name, + /*constraint*/ undefined, + defaultType, + ), + typeParameterPos, + ); } function parseTemplateTagTypeParameters() { @@ -9652,11 +11598,17 @@ namespace Parser { typeParameters.push(node); } skipWhitespaceOrAsterisk(); - } while (parseOptionalJsdoc(SyntaxKind.CommaToken)); + } + while (parseOptionalJsdoc(SyntaxKind.CommaToken)); return createNodeArray(typeParameters, pos); } - function parseTemplateTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocTemplateTag { + function parseTemplateTag( + start: number, + tagName: Identifier, + indent: number, + indentText: string, + ): JSDocTemplateTag { // The template tag looks like one of the following: // @template T,U,V // @template {Constraint} T @@ -9670,7 +11622,15 @@ namespace Parser { // TODO: Consider only parsing a single type parameter if there is a constraint. const constraint = token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined; const typeParameters = parseTemplateTagTypeParameters(); - return finishNode(factory.createJSDocTemplateTag(tagName, constraint, typeParameters, parseTrailingTagComments(start, getNodePos(), indent, indentText)), start); + return finishNode( + factory.createJSDocTemplateTag( + tagName, + constraint, + typeParameters, + parseTrailingTagComments(start, getNodePos(), indent, indentText), + ), + start, + ); } function parseOptionalJsdoc(t: JSDocSyntaxKind): boolean { @@ -9701,7 +11661,11 @@ namespace Parser { function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier { if (!tokenIsIdentifierOrKeyword(token())) { - return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected); + return createMissingNode( + SyntaxKind.Identifier, + /*reportAtCurrentPosition*/ !message, + message || Diagnostics.Identifier_expected, + ); } identifierCount++; @@ -9718,7 +11682,12 @@ namespace Parser { } namespace IncrementalParser { - export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean): SourceFile { + export function updateSourceFile( + sourceFile: SourceFile, + newText: string, + textChangeRange: TextChangeRange, + aggressiveChecks: boolean, + ): SourceFile { aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive); checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks); @@ -9730,7 +11699,15 @@ namespace IncrementalParser { if (sourceFile.statements.length === 0) { // If we don't have any statements in the current source file, then there's no real // way to incrementally parse. So just do a full parse instead. - return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); + return Parser.parseSourceFile( + sourceFile.fileName, + newText, + sourceFile.languageVersion, + /*syntaxCursor*/ undefined, + /*setParentNodes*/ true, + sourceFile.scriptKind, + sourceFile.setExternalModuleIndicator, + ); } // Make sure we're not trying to incrementally update a source file more than once. Once @@ -9755,7 +11732,9 @@ namespace IncrementalParser { // earlier in the file. Debug.assert(changeRange.span.start <= textChangeRange.span.start); Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span)); - Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange))); + Debug.assert( + textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange)), + ); // The is the amount the nodes after the edit range need to be adjusted. It can be // positive (if the edit added characters), negative (if the edit deleted characters) @@ -9781,8 +11760,16 @@ namespace IncrementalParser { // // Also, mark any syntax elements that intersect the changed span. We know, up front, // that we cannot reuse these elements. - updateTokenPositionsAndMarkElements(incrementalSourceFile, - changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks); + updateTokenPositionsAndMarkElements( + incrementalSourceFile, + changeRange.span.start, + textSpanEnd(changeRange.span), + textSpanEnd(textChangeRangeNewSpan(changeRange)), + delta, + oldText, + newText, + aggressiveChecks, + ); // Now that we've set up our internal incremental state just proceed and parse the // source file in the normal fashion. When possible the parser will retrieve and @@ -9794,7 +11781,15 @@ namespace IncrementalParser { // inconsistent tree. Setting the parents on the new tree should be very fast. We // will immediately bail out of walking any subtrees when we can see that their parents // are already correct. - const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind, sourceFile.setExternalModuleIndicator); + const result = Parser.parseSourceFile( + sourceFile.fileName, + newText, + sourceFile.languageVersion, + syntaxCursor, + /*setParentNodes*/ true, + sourceFile.scriptKind, + sourceFile.setExternalModuleIndicator, + ); result.commentDirectives = getNewCommentDirectives( sourceFile.commentDirectives, result.commentDirectives, @@ -9803,7 +11798,7 @@ namespace IncrementalParser { delta, oldText, newText, - aggressiveChecks + aggressiveChecks, ); result.impliedNodeFormat = sourceFile.impliedNodeFormat; return result; @@ -9817,7 +11812,7 @@ namespace IncrementalParser { delta: number, oldText: string, newText: string, - aggressiveChecks: boolean + aggressiveChecks: boolean, ): CommentDirective[] | undefined { if (!oldDirectives) return newDirectives; let commentDirectives: CommentDirective[] | undefined; @@ -9834,11 +11829,14 @@ namespace IncrementalParser { // end, forward or backward appropriately. const updatedDirective: CommentDirective = { range: { pos: range.pos + delta, end: range.end + delta }, - type + type, }; commentDirectives = append(commentDirectives, updatedDirective); if (aggressiveChecks) { - Debug.assert(oldText.substring(range.pos, range.end) === newText.substring(updatedDirective.range.pos, updatedDirective.range.end)); + Debug.assert( + oldText.substring(range.pos, range.end) + === newText.substring(updatedDirective.range.pos, updatedDirective.range.end), + ); } } // Ignore ranges that fall in change range @@ -9858,9 +11856,30 @@ namespace IncrementalParser { } } - function moveElementEntirelyPastChangeRange(element: IncrementalNode, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void; - function moveElementEntirelyPastChangeRange(element: IncrementalNodeArray, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void; - function moveElementEntirelyPastChangeRange(element: IncrementalNode | IncrementalNodeArray, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { + function moveElementEntirelyPastChangeRange( + element: IncrementalNode, + isArray: false, + delta: number, + oldText: string, + newText: string, + aggressiveChecks: boolean, + ): void; + function moveElementEntirelyPastChangeRange( + element: IncrementalNodeArray, + isArray: true, + delta: number, + oldText: string, + newText: string, + aggressiveChecks: boolean, + ): void; + function moveElementEntirelyPastChangeRange( + element: IncrementalNode | IncrementalNodeArray, + isArray: boolean, + delta: number, + oldText: string, + newText: string, + aggressiveChecks: boolean, + ) { if (isArray) { visitArray(element as IncrementalNodeArray); } @@ -9917,7 +11936,13 @@ namespace IncrementalParser { return false; } - function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { + function adjustIntersectingElement( + element: IncrementalElement, + changeStart: number, + changeRangeOldEnd: number, + changeRangeNewEnd: number, + delta: number, + ) { Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); Debug.assert(element.pos <= element.end); @@ -9975,12 +12000,12 @@ namespace IncrementalParser { // However any element that ended after that will have their pos adjusted to be // at the end of the new range. i.e. any node that ended in the 'Y' range will // be adjusted to have their end at the end of the 'Z' range. - const end = element.end >= changeRangeOldEnd ? + const end = element.end >= changeRangeOldEnd // Element ends after the change range. Always adjust the end pos. - element.end + delta : + ? element.end + delta // Element ends in the change range. The element will keep its position if // possible. Or Move backward to the new-end if it's in the 'Y' range. - Math.min(element.end, changeRangeNewEnd); + : Math.min(element.end, changeRangeNewEnd); Debug.assert(pos <= end); if (element.parent) { @@ -10016,8 +12041,8 @@ namespace IncrementalParser { delta: number, oldText: string, newText: string, - aggressiveChecks: boolean): void { - + aggressiveChecks: boolean, + ): void { visitNode(sourceFile); return; @@ -10201,7 +12226,12 @@ namespace IncrementalParser { } } - function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) { + function checkChangeRange( + sourceFile: SourceFile, + newText: string, + textChangeRange: TextChangeRange, + aggressiveChecks: boolean, + ) { const oldText = sourceFile.text; if (textChangeRange) { Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length); @@ -10212,7 +12242,10 @@ namespace IncrementalParser { Debug.assert(oldTextPrefix === newTextPrefix); const oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length); - const newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length); + const newTextSuffix = newText.substring( + textSpanEnd(textChangeRangeNewSpan(textChangeRange)), + newText.length, + ); Debug.assert(oldTextSuffix === newTextSuffix); } } @@ -10280,7 +12313,7 @@ namespace IncrementalParser { // Either we don'd have a node, or we have a node at the position being asked for. Debug.assert(!current || current.pos === position); return current as IncrementalNode; - } + }, }; // Finds the highest element in the tree we can find that starts at the provided position. @@ -10342,16 +12375,22 @@ namespace IncrementalParser { } const enum InvalidPosition { - Value = -1 + Value = -1, } } /** @internal */ export function isDeclarationFileName(fileName: string): boolean { - return fileExtensionIsOneOf(fileName, supportedDeclarationExtensions) || (fileExtensionIs(fileName, Extension.Ts) && stringContains(getBaseFileName(fileName), ".d.")); + return fileExtensionIsOneOf(fileName, supportedDeclarationExtensions) + || (fileExtensionIs(fileName, Extension.Ts) && stringContains(getBaseFileName(fileName), ".d.")); } -function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ResolutionMode { +function parseResolutionMode( + mode: string | undefined, + pos: number, + end: number, + reportDiagnostic: PragmaDiagnosticReporter, +): ResolutionMode { if (!mode) { return undefined; } @@ -10416,7 +12455,12 @@ export function processPragmasIntoFields(context: PragmaContext, reportDiagnosti } else if (types) { const parsed = parseResolutionMode(res, types.pos, types.end, reportDiagnostic); - typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value, ...(parsed ? { resolutionMode: parsed } : {}) }); + typeReferenceDirectives.push({ + pos: types.pos, + end: types.end, + fileName: types.value, + ...(parsed ? { resolutionMode: parsed } : {}), + }); } else if (lib) { libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value }); @@ -10425,7 +12469,11 @@ export function processPragmasIntoFields(context: PragmaContext, reportDiagnosti referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value }); } else { - reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax); + reportDiagnostic( + arg.range.pos, + arg.range.end - arg.range.pos, + Diagnostics.Invalid_reference_directive_syntax, + ); } }); break; @@ -10433,7 +12481,8 @@ export function processPragmasIntoFields(context: PragmaContext, reportDiagnosti case "amd-dependency": { context.amdDependencies = map( toArray(entryOrList) as PragmaPseudoMap["amd-dependency"][], - x => ({ name: x.arguments.name, path: x.arguments.path })); + x => ({ name: x.arguments.name, path: x.arguments.path }), + ); break; } case "amd-module": { @@ -10441,7 +12490,11 @@ export function processPragmasIntoFields(context: PragmaContext, reportDiagnosti for (const entry of entryOrList) { if (context.moduleName) { // TODO: It's probably fine to issue this diagnostic on all instances of the pragma - reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments); + reportDiagnostic( + entry.range.pos, + entry.range.end - entry.range.pos, + Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments, + ); } context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name; } @@ -10459,7 +12512,7 @@ export function processPragmasIntoFields(context: PragmaContext, reportDiagnosti context.checkJsDirective = { enabled: key === "ts-check", end: entry.range.end, - pos: entry.range.pos + pos: entry.range.pos, }; } }); @@ -10470,7 +12523,8 @@ export function processPragmasIntoFields(context: PragmaContext, reportDiagnosti case "jsximportsource": case "jsxruntime": return; // Accessed directly - default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future? + default: + Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future? } }); } @@ -10496,7 +12550,7 @@ function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, te return; } if (pragma.args) { - const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {}; + const argument: { [index: string]: string | { value: string; pos: number; end: number; }; } = {}; for (const arg of pragma.args) { const matcher = getNamedArgRegEx(arg.name); const matchResult = matcher.exec(text); @@ -10510,7 +12564,7 @@ function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, te argument[arg.name] = { value, pos: startPos, - end: startPos + value.length + end: startPos + value.length, }; } else { @@ -10540,7 +12594,12 @@ function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, te } } -function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) { +function addPragmaForMatch( + pragmas: PragmaPseudoMapEntry[], + range: CommentRange, + kind: PragmaKindFlags, + match: RegExpExecArray, +) { if (!match) return; const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks const pragma = commentPragmas[name] as PragmaDefinition; @@ -10554,11 +12613,14 @@ function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, return; } -function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" { +function getNamedPragmaArguments( + pragma: PragmaDefinition, + text: string | undefined, +): { [index: string]: string; } | "fail" { if (!text) return {}; if (!pragma.args) return {}; const args = trimString(text).split(/\s+/); - const argMap: {[index: string]: string} = {}; + const argMap: { [index: string]: string; } = {}; for (let i = 0; i < pragma.args.length; i++) { const argument = pragma.args[i]; if (!args[i] && !argument.optional) { @@ -10587,13 +12649,16 @@ export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagName } if (lhs.kind === SyntaxKind.JsxNamespacedName) { - return lhs.namespace.escapedText === (rhs as JsxNamespacedName).namespace.escapedText && - lhs.name.escapedText === (rhs as JsxNamespacedName).name.escapedText; + return lhs.namespace.escapedText === (rhs as JsxNamespacedName).namespace.escapedText + && lhs.name.escapedText === (rhs as JsxNamespacedName).name.escapedText; } // If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only // take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression // it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element - return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText && - tagNamesAreEquivalent((lhs as PropertyAccessExpression).expression as JsxTagNameExpression, (rhs as PropertyAccessExpression).expression as JsxTagNameExpression); + return (lhs as PropertyAccessExpression).name.escapedText === (rhs as PropertyAccessExpression).name.escapedText + && tagNamesAreEquivalent( + (lhs as PropertyAccessExpression).expression as JsxTagNameExpression, + (rhs as PropertyAccessExpression).expression as JsxTagNameExpression, + ); } diff --git a/src/compiler/path.ts b/src/compiler/path.ts index 661997d28d354..e4856aaf259f2 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -144,8 +144,8 @@ export function hasTrailingDirectorySeparator(path: string) { //// Path Parsing function isVolumeCharacter(charCode: number) { - return (charCode >= CharacterCodes.a && charCode <= CharacterCodes.z) || - (charCode >= CharacterCodes.A && charCode <= CharacterCodes.Z); + return (charCode >= CharacterCodes.a && charCode <= CharacterCodes.z) + || (charCode >= CharacterCodes.A && charCode <= CharacterCodes.Z); } function getFileUrlVolumeSeparatorEnd(url: string, start: number) { @@ -194,8 +194,10 @@ function getEncodedRootLength(path: string): number { // special case interpreted as "the machine from which the URL is being interpreted". const scheme = path.slice(0, schemeEnd); const authority = path.slice(authorityStart, authorityEnd); - if (scheme === "file" && (authority === "" || authority === "localhost") && - isVolumeCharacter(path.charCodeAt(authorityEnd + 1))) { + if ( + scheme === "file" && (authority === "" || authority === "localhost") + && isVolumeCharacter(path.charCodeAt(authorityEnd + 1)) + ) { const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2); if (volumeSeparatorEnd !== -1) { if (path.charCodeAt(volumeSeparatorEnd) === CharacterCodes.slash) { @@ -379,11 +381,16 @@ export function getBaseFileName(path: string, extensions?: string | readonly str // separator but not including any trailing directory separator. path = removeTrailingDirectorySeparator(path); const name = path.slice(Math.max(getRootLength(path), path.lastIndexOf(directorySeparator) + 1)); - const extension = extensions !== undefined && ignoreCase !== undefined ? getAnyExtensionFromPath(name, extensions, ignoreCase) : undefined; + const extension = extensions !== undefined && ignoreCase !== undefined + ? getAnyExtensionFromPath(name, extensions, ignoreCase) : undefined; return extension ? name.slice(0, name.length - extension.length) : name; } -function tryGetExtensionFromPath(path: string, extension: string, stringEqualityComparer: (a: string, b: string) => boolean) { +function tryGetExtensionFromPath( + path: string, + extension: string, + stringEqualityComparer: (a: string, b: string) => boolean, +) { if (!startsWith(extension, ".")) extension = "." + extension; if (path.length >= extension.length && path.charCodeAt(path.length - extension.length) === CharacterCodes.dot) { const pathExtension = path.slice(path.length - extension.length); @@ -393,7 +400,11 @@ function tryGetExtensionFromPath(path: string, extension: string, stringEquality } } -function getAnyExtensionFromPathWorker(path: string, extensions: string | readonly string[], stringEqualityComparer: (a: string, b: string) => boolean) { +function getAnyExtensionFromPathWorker( + path: string, + extensions: string | readonly string[], + stringEqualityComparer: (a: string, b: string) => boolean, +) { if (typeof extensions === "string") { return tryGetExtensionFromPath(path, extensions, stringEqualityComparer) || ""; } @@ -428,13 +439,25 @@ export function getAnyExtensionFromPath(path: string): string; * * @internal */ -export function getAnyExtensionFromPath(path: string, extensions: string | readonly string[], ignoreCase: boolean): string; +export function getAnyExtensionFromPath( + path: string, + extensions: string | readonly string[], + ignoreCase: boolean, +): string; /** @internal */ -export function getAnyExtensionFromPath(path: string, extensions?: string | readonly string[], ignoreCase?: boolean): string { +export function getAnyExtensionFromPath( + path: string, + extensions?: string | readonly string[], + ignoreCase?: boolean, +): string { // Retrieves any string from the final "." onwards from a base file name. // Unlike extensionFromPath, which throws an exception on unrecognized extensions. if (extensions) { - return getAnyExtensionFromPathWorker(removeTrailingDirectorySeparator(path), extensions, ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive); + return getAnyExtensionFromPathWorker( + removeTrailingDirectorySeparator(path), + extensions, + ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive, + ); } const baseFileName = getBaseFileName(path); const extensionIndex = baseFileName.lastIndexOf("."); @@ -452,7 +475,7 @@ function pathComponents(path: string, rootLength: number) { } /** @internal */ -export type PathPathComponents = Path[] & { __pathComponensBrand: any }; +export type PathPathComponents = Path[] & { __pathComponensBrand: any; }; /** * Parse a path into an array containing a root component (at index 0) and zero or more path @@ -643,7 +666,8 @@ export function normalizePath(path: string): string { } // Other paths require full normalization const normalized = getPathFromPathComponents(reducePathComponents(getPathComponents(path))); - return normalized && hasTrailingDirectorySeparator(path) ? ensureTrailingDirectorySeparator(normalized) : normalized; + return normalized && hasTrailingDirectorySeparator(path) ? ensureTrailingDirectorySeparator(normalized) + : normalized; } function getPathWithoutRoot(pathComponents: readonly string[]) { @@ -657,7 +681,11 @@ export function getNormalizedAbsolutePathWithoutRoot(fileName: string, currentDi } /** @internal */ -export function toPath(fileName: string, basePath: string | undefined, getCanonicalFileName: (path: string) => string): Path { +export function toPath( + fileName: string, + basePath: string | undefined, + getCanonicalFileName: (path: string) => string, +): Path { const nonCanonicalizedPath = isRootedDiskPath(fileName) ? normalizePath(fileName) : getNormalizedAbsolutePath(fileName, basePath); @@ -748,10 +776,21 @@ export function changeAnyExtension(path: string, ext: string): string; * * @internal */ -export function changeAnyExtension(path: string, ext: string, extensions: string | readonly string[], ignoreCase: boolean): string; +export function changeAnyExtension( + path: string, + ext: string, + extensions: string | readonly string[], + ignoreCase: boolean, +): string; /** @internal */ -export function changeAnyExtension(path: string, ext: string, extensions?: string | readonly string[], ignoreCase?: boolean) { - const pathext = extensions !== undefined && ignoreCase !== undefined ? getAnyExtensionFromPath(path, extensions, ignoreCase) : getAnyExtensionFromPath(path); +export function changeAnyExtension( + path: string, + ext: string, + extensions?: string | readonly string[], + ignoreCase?: boolean, +) { + const pathext = extensions !== undefined && ignoreCase !== undefined + ? getAnyExtensionFromPath(path, extensions, ignoreCase) : getAnyExtensionFromPath(path); return pathext ? path.slice(0, path.length - pathext.length) + (startsWith(ext, ".") ? ext : "." + ext) : path; } @@ -878,16 +917,26 @@ export function containsPath(parent: string, child: string, currentDirectory?: s * * @internal */ -export function startsWithDirectory(fileName: string, directoryName: string, getCanonicalFileName: GetCanonicalFileName): boolean { +export function startsWithDirectory( + fileName: string, + directoryName: string, + getCanonicalFileName: GetCanonicalFileName, +): boolean { const canonicalFileName = getCanonicalFileName(fileName); const canonicalDirectoryName = getCanonicalFileName(directoryName); - return startsWith(canonicalFileName, canonicalDirectoryName + "/") || startsWith(canonicalFileName, canonicalDirectoryName + "\\"); + return startsWith(canonicalFileName, canonicalDirectoryName + "/") + || startsWith(canonicalFileName, canonicalDirectoryName + "\\"); } //// Relative Paths /** @internal */ -export function getPathComponentsRelativeTo(from: string, to: string, stringEqualityComparer: (a: string, b: string) => boolean, getCanonicalFileName: GetCanonicalFileName) { +export function getPathComponentsRelativeTo( + from: string, + to: string, + stringEqualityComparer: (a: string, b: string) => boolean, + getCanonicalFileName: GetCanonicalFileName, +) { const fromComponents = reducePathComponents(getPathComponents(from)); const toComponents = reducePathComponents(getPathComponents(to)); @@ -922,21 +971,48 @@ export function getRelativePathFromDirectory(from: string, to: string, ignoreCas * * @internal */ -export function getRelativePathFromDirectory(fromDirectory: string, to: string, getCanonicalFileName: GetCanonicalFileName): string; // eslint-disable-line @typescript-eslint/unified-signatures +export function getRelativePathFromDirectory( + fromDirectory: string, + to: string, + getCanonicalFileName: GetCanonicalFileName, +): string; // eslint-disable-line @typescript-eslint/unified-signatures /** @internal */ -export function getRelativePathFromDirectory(fromDirectory: string, to: string, getCanonicalFileNameOrIgnoreCase: GetCanonicalFileName | boolean) { - Debug.assert((getRootLength(fromDirectory) > 0) === (getRootLength(to) > 0), "Paths must either both be absolute or both be relative"); - const getCanonicalFileName = typeof getCanonicalFileNameOrIgnoreCase === "function" ? getCanonicalFileNameOrIgnoreCase : identity; +export function getRelativePathFromDirectory( + fromDirectory: string, + to: string, + getCanonicalFileNameOrIgnoreCase: GetCanonicalFileName | boolean, +) { + Debug.assert( + (getRootLength(fromDirectory) > 0) === (getRootLength(to) > 0), + "Paths must either both be absolute or both be relative", + ); + const getCanonicalFileName = typeof getCanonicalFileNameOrIgnoreCase === "function" + ? getCanonicalFileNameOrIgnoreCase : identity; const ignoreCase = typeof getCanonicalFileNameOrIgnoreCase === "boolean" ? getCanonicalFileNameOrIgnoreCase : false; - const pathComponents = getPathComponentsRelativeTo(fromDirectory, to, ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive, getCanonicalFileName); + const pathComponents = getPathComponentsRelativeTo( + fromDirectory, + to, + ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive, + getCanonicalFileName, + ); return getPathFromPathComponents(pathComponents); } /** @internal */ -export function convertToRelativePath(absoluteOrRelativePath: string, basePath: string, getCanonicalFileName: (path: string) => string): string { +export function convertToRelativePath( + absoluteOrRelativePath: string, + basePath: string, + getCanonicalFileName: (path: string) => string, +): string { return !isRootedDiskPath(absoluteOrRelativePath) ? absoluteOrRelativePath - : getRelativePathToDirectoryOrUrl(basePath, absoluteOrRelativePath, basePath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); + : getRelativePathToDirectoryOrUrl( + basePath, + absoluteOrRelativePath, + basePath, + getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false, + ); } /** @internal */ @@ -945,12 +1021,18 @@ export function getRelativePathFromFile(from: string, to: string, getCanonicalFi } /** @internal */ -export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, isAbsolutePathAnUrl: boolean) { +export function getRelativePathToDirectoryOrUrl( + directoryPathOrUrl: string, + relativeOrAbsolutePath: string, + currentDirectory: string, + getCanonicalFileName: GetCanonicalFileName, + isAbsolutePathAnUrl: boolean, +) { const pathComponents = getPathComponentsRelativeTo( resolvePath(currentDirectory, directoryPathOrUrl), resolvePath(currentDirectory, relativeOrAbsolutePath), equateStringsCaseSensitive, - getCanonicalFileName + getCanonicalFileName, ); const firstComponent = pathComponents[0]; @@ -969,11 +1051,20 @@ export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, rela * * @internal */ -export function forEachAncestorDirectory(directory: Path, callback: (directory: Path) => T | undefined): T | undefined; +export function forEachAncestorDirectory( + directory: Path, + callback: (directory: Path) => T | undefined, +): T | undefined; /** @internal */ -export function forEachAncestorDirectory(directory: string, callback: (directory: string) => T | undefined): T | undefined; +export function forEachAncestorDirectory( + directory: string, + callback: (directory: string) => T | undefined, +): T | undefined; /** @internal */ -export function forEachAncestorDirectory(directory: P, callback: (directory: P) => T | undefined): T | undefined { +export function forEachAncestorDirectory( + directory: P, + callback: (directory: P) => T | undefined, +): T | undefined { while (true) { const result = callback(directory); if (result !== undefined) { diff --git a/src/compiler/perfLogger.ts b/src/compiler/perfLogger.ts index 20ec69d035af2..f2476db967541 100644 --- a/src/compiler/perfLogger.ts +++ b/src/compiler/perfLogger.ts @@ -22,7 +22,6 @@ export interface PerfLogger { logStopScheduledOperation(): void; } - // Load optional module to enable Event Tracing for Windows // See https://github.com/microsoft/typescript-etw for more information let etwModule: typeof import("@microsoft/typescript-etw") | undefined; diff --git a/src/compiler/performance.ts b/src/compiler/performance.ts index 4f2096ec7204f..1605fa5e3562a 100644 --- a/src/compiler/performance.ts +++ b/src/compiler/performance.ts @@ -35,7 +35,7 @@ export function createTimer(measureName: string, startMarkName: string, endMarkN let enterCount = 0; return { enter, - exit + exit, }; function enter() { diff --git a/src/compiler/performanceCore.ts b/src/compiler/performanceCore.ts index 3f8a459bb0d75..022ba21d44938 100644 --- a/src/compiler/performanceCore.ts +++ b/src/compiler/performanceCore.ts @@ -41,11 +41,13 @@ export interface PerformanceObserverEntryList { /** @internal */ export interface PerformanceObserver { disconnect(): void; - observe(options: { entryTypes: readonly ("mark" | "measure")[] }): void; + observe(options: { entryTypes: readonly ("mark" | "measure")[]; }): void; } /** @internal */ -export type PerformanceObserverConstructor = new (callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void) => PerformanceObserver; +export type PerformanceObserverConstructor = new ( + callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void, +) => PerformanceObserver; /** @internal */ export type PerformanceEntryList = PerformanceEntry[]; @@ -54,28 +56,33 @@ declare const performance: Performance | undefined; declare const PerformanceObserver: PerformanceObserverConstructor | undefined; // eslint-disable-next-line @typescript-eslint/naming-convention -function hasRequiredAPI(performance: Performance | undefined, PerformanceObserver: PerformanceObserverConstructor | undefined) { - return typeof performance === "object" && - typeof performance.timeOrigin === "number" && - typeof performance.mark === "function" && - typeof performance.measure === "function" && - typeof performance.now === "function" && - typeof performance.clearMarks === "function" && - typeof performance.clearMeasures === "function" && - typeof PerformanceObserver === "function"; +function hasRequiredAPI( + performance: Performance | undefined, + PerformanceObserver: PerformanceObserverConstructor | undefined, +) { + return typeof performance === "object" + && typeof performance.timeOrigin === "number" + && typeof performance.mark === "function" + && typeof performance.measure === "function" + && typeof performance.now === "function" + && typeof performance.clearMarks === "function" + && typeof performance.clearMeasures === "function" + && typeof PerformanceObserver === "function"; } function tryGetWebPerformanceHooks(): PerformanceHooks | undefined { - if (typeof performance === "object" && - typeof PerformanceObserver === "function" && - hasRequiredAPI(performance, PerformanceObserver)) { + if ( + typeof performance === "object" + && typeof PerformanceObserver === "function" + && hasRequiredAPI(performance, PerformanceObserver) + ) { return { // For now we always write native performance events when running in the browser. We may // make this conditional in the future if we find that native web performance hooks // in the browser also slow down compilation. shouldWriteNativeEvents: true, performance, - PerformanceObserver + PerformanceObserver, }; } } @@ -89,7 +96,7 @@ function tryGetNodePerformanceHooks(): PerformanceHooks | undefined { // By default, only write native events when generating a cpu profile or using the v8 profiler. shouldWriteNativeEvents: false, performance, - PerformanceObserver + PerformanceObserver, }; } } @@ -114,7 +121,6 @@ export function tryGetNativePerformanceHooks() { * * @internal */ -export const timestamp = - nativePerformance ? () => nativePerformance.now() : - Date.now ? Date.now : - () => +(new Date()); +export const timestamp = nativePerformance ? () => nativePerformance.now() + : Date.now ? Date.now + : () => +(new Date()); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 9d1c258cec3e5..d1ef6aa1bcb33 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -337,7 +337,11 @@ import { } from "./_namespaces/ts"; import * as performance from "./_namespaces/ts.performance"; -export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string | undefined { +export function findConfigFile( + searchPath: string, + fileExists: (fileName: string) => boolean, + configName = "tsconfig.json", +): string | undefined { return forEachAncestorDirectory(searchPath, ancestor => { const fileName = combinePaths(ancestor, configName); return fileExists(fileName) ? fileName : undefined; @@ -351,7 +355,11 @@ export function resolveTripleslashReference(moduleName: string, containingFile: } /** @internal */ -export function computeCommonSourceDirectoryOfFilenames(fileNames: readonly string[], currentDirectory: string, getCanonicalFileName: GetCanonicalFileName): string { +export function computeCommonSourceDirectoryOfFilenames( + fileNames: readonly string[], + currentDirectory: string, + getCanonicalFileName: GetCanonicalFileName, +): string { let commonPathComponents: string[] | undefined; const failed = forEach(fileNames, sourceFile => { // Each file contributes into common source file path @@ -404,7 +412,7 @@ export function createCompilerHost(options: CompilerOptions, setParentNodes?: bo export function createGetSourceFile( readFile: ProgramHost["readFile"], getCompilerOptions: () => CompilerOptions, - setParentNodes: boolean | undefined + setParentNodes: boolean | undefined, ): CompilerHost["getSourceFile"] { return (fileName, languageVersionOrOptions, onError) => { let text: string | undefined; @@ -420,7 +428,8 @@ export function createGetSourceFile( } text = ""; } - return text !== undefined ? createSourceFile(fileName, text, languageVersionOrOptions, setParentNodes) : undefined; + return text !== undefined ? createSourceFile(fileName, text, languageVersionOrOptions, setParentNodes) + : undefined; }; } @@ -428,7 +437,7 @@ export function createGetSourceFile( export function createWriteFileMeasuringIO( actualWriteFile: (path: string, data: string, writeByteOrderMark: boolean) => void, createDirectory: (path: string) => void, - directoryExists: (path: string) => boolean + directoryExists: (path: string) => boolean, ): CompilerHost["writeFile"] { return (fileName, data, writeByteOrderMark, onError) => { try { @@ -443,7 +452,7 @@ export function createWriteFileMeasuringIO( writeByteOrderMark, actualWriteFile, createDirectory, - directoryExists + directoryExists, ); performance.mark("afterIOWrite"); @@ -458,7 +467,11 @@ export function createWriteFileMeasuringIO( } /** @internal */ -export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system: System = sys): CompilerHost { +export function createCompilerHostWorker( + options: CompilerOptions, + setParentNodes?: boolean, + system: System = sys, +): CompilerHost { const existingDirectories = new Map(); const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames); function directoryExists(directoryPath: string): boolean { @@ -498,9 +511,10 @@ export function createCompilerHostWorker(options: CompilerOptions, setParentNode getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "", getDirectories: (path: string) => system.getDirectories(path), realpath, - readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth), + readDirectory: (path, extensions, include, exclude, depth) => + system.readDirectory(path, extensions, include, exclude, depth), createDirectory: d => system.createDirectory(d), - createHash: maybeBind(system, system.createHash) + createHash: maybeBind(system, system.createHash), }; return compilerHost; } @@ -518,7 +532,7 @@ export interface CompilerHostLikeForCache { export function changeCompilerHostLikeToUseCache( host: CompilerHostLikeForCache, toPath: (fileName: string) => Path, - getSourceFile?: CompilerHost["getSourceFile"] + getSourceFile?: CompilerHost["getSourceFile"], ) { const originalReadFile = host.readFile; const originalFileExists = host.fileExists; @@ -553,19 +567,21 @@ export function changeCompilerHostLikeToUseCache( return setReadFileCache(key, fileName); }; - const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile ? (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => { - const key = toPath(fileName); - const impliedNodeFormat: ResolutionMode = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined; - const forImpliedNodeFormat = sourceFileCache.get(impliedNodeFormat); - const value = forImpliedNodeFormat?.get(key); - if (value) return value; + const getSourceFileWithCache: CompilerHost["getSourceFile"] | undefined = getSourceFile + ? (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => { + const key = toPath(fileName); + const impliedNodeFormat: ResolutionMode = typeof languageVersionOrOptions === "object" + ? languageVersionOrOptions.impliedNodeFormat : undefined; + const forImpliedNodeFormat = sourceFileCache.get(impliedNodeFormat); + const value = forImpliedNodeFormat?.get(key); + if (value) return value; - const sourceFile = getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile); - if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) { - sourceFileCache.set(impliedNodeFormat, (forImpliedNodeFormat || new Map()).set(key, sourceFile)); - } - return sourceFile; - } : undefined; + const sourceFile = getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile); + if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) { + sourceFileCache.set(impliedNodeFormat, (forImpliedNodeFormat || new Map()).set(key, sourceFile)); + } + return sourceFile; + } : undefined; // fileExists for any kind of extension host.fileExists = fileName => { @@ -625,13 +641,25 @@ export function changeCompilerHostLikeToUseCache( originalCreateDirectory, originalWriteFile, getSourceFileWithCache, - readFileWithCache + readFileWithCache, }; } -export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; -/** @internal */ export function getPreEmitDiagnostics(program: BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; // eslint-disable-line @typescript-eslint/unified-signatures -export function getPreEmitDiagnostics(program: Program | BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { +export function getPreEmitDiagnostics( + program: Program, + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, +): readonly Diagnostic[]; +/** @internal */ export function getPreEmitDiagnostics( + program: BuilderProgram, + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, +): readonly Diagnostic[]; // eslint-disable-line @typescript-eslint/unified-signatures +export function getPreEmitDiagnostics( + program: Program | BuilderProgram, + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, +): readonly Diagnostic[] { let diagnostics: Diagnostic[] | undefined; diagnostics = addRange(diagnostics, program.getConfigFileParsingDiagnostics()); diagnostics = addRange(diagnostics, program.getOptionsDiagnostics(cancellationToken)); @@ -662,12 +690,18 @@ export function formatDiagnostics(diagnostics: readonly Diagnostic[], host: Form } export function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string { - const errorMessage = `${diagnosticCategoryName(diagnostic)} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`; + const errorMessage = `${diagnosticCategoryName(diagnostic)} TS${diagnostic.code}: ${ + flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()) + }${host.getNewLine()}`; if (diagnostic.file) { const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); // TODO: GH#18217 const fileName = diagnostic.file.fileName; - const relativeFileName = convertToRelativePath(fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName)); + const relativeFileName = convertToRelativePath( + fileName, + host.getCurrentDirectory(), + fileName => host.getCanonicalFileName(fileName), + ); return `${relativeFileName}(${line + 1},${character + 1}): ` + errorMessage; } @@ -680,7 +714,7 @@ export enum ForegroundColorEscapeSequences { Red = "\u001b[91m", Yellow = "\u001b[93m", Blue = "\u001b[94m", - Cyan = "\u001b[96m" + Cyan = "\u001b[96m", } const gutterStyleSequence = "\u001b[7m"; const gutterSeparator = " "; @@ -690,10 +724,14 @@ const halfIndent = " "; const indent = " "; function getCategoryFormat(category: DiagnosticCategory): ForegroundColorEscapeSequences { switch (category) { - case DiagnosticCategory.Error: return ForegroundColorEscapeSequences.Red; - case DiagnosticCategory.Warning: return ForegroundColorEscapeSequences.Yellow; - case DiagnosticCategory.Suggestion: return Debug.fail("Should never get an Info diagnostic on the command line."); - case DiagnosticCategory.Message: return ForegroundColorEscapeSequences.Blue; + case DiagnosticCategory.Error: + return ForegroundColorEscapeSequences.Red; + case DiagnosticCategory.Warning: + return ForegroundColorEscapeSequences.Yellow; + case DiagnosticCategory.Suggestion: + return Debug.fail("Should never get an Info diagnostic on the command line."); + case DiagnosticCategory.Message: + return ForegroundColorEscapeSequences.Blue; } } @@ -702,7 +740,14 @@ export function formatColorAndReset(text: string, formatStyle: string) { return formatStyle + text + resetEscapeSequence; } -function formatCodeSpan(file: SourceFile, start: number, length: number, indent: string, squiggleColor: ForegroundColorEscapeSequences, host: FormatDiagnosticsHost) { +function formatCodeSpan( + file: SourceFile, + start: number, + length: number, + indent: string, + squiggleColor: ForegroundColorEscapeSequences, + host: FormatDiagnosticsHost, +) { const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start); const { line: lastLine, character: lastLineChar } = getLineAndCharacterOfPosition(file, start + length); const lastLineInFile = getLineAndCharacterOfPosition(file, file.text.length).line; @@ -719,18 +764,20 @@ function formatCodeSpan(file: SourceFile, start: number, length: number, indent: // If the error spans over 5 lines, we'll only show the first 2 and last 2 lines, // so we'll skip ahead to the second-to-last line. if (hasMoreThanFiveLines && firstLine + 1 < i && i < lastLine - 1) { - context += indent + formatColorAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + host.getNewLine(); + context += indent + formatColorAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + + gutterSeparator + host.getNewLine(); i = lastLine - 1; } const lineStart = getPositionOfLineAndCharacter(file, i, 0); const lineEnd = i < lastLineInFile ? getPositionOfLineAndCharacter(file, i + 1, 0) : file.text.length; let lineContent = file.text.slice(lineStart, lineEnd); - lineContent = trimStringEnd(lineContent); // trim from end - lineContent = lineContent.replace(/\t/g, " "); // convert tabs to single spaces + lineContent = trimStringEnd(lineContent); // trim from end + lineContent = lineContent.replace(/\t/g, " "); // convert tabs to single spaces // Output the gutter and the actual contents of the line. - context += indent + formatColorAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator; + context += indent + formatColorAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + + gutterSeparator; context += lineContent + host.getNewLine(); // Output the gutter and the error span for the line using tildes. @@ -757,9 +804,19 @@ function formatCodeSpan(file: SourceFile, start: number, length: number, indent: } /** @internal */ -export function formatLocation(file: SourceFile, start: number, host: FormatDiagnosticsHost, color = formatColorAndReset) { +export function formatLocation( + file: SourceFile, + start: number, + host: FormatDiagnosticsHost, + color = formatColorAndReset, +) { const { line: firstLine, character: firstLineChar } = getLineAndCharacterOfPosition(file, start); // TODO: GH#18217 - const relativeFileName = host ? convertToRelativePath(file.fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName)) : file.fileName; + const relativeFileName = host + ? convertToRelativePath( + file.fileName, + host.getCurrentDirectory(), + fileName => host.getCanonicalFileName(fileName), + ) : file.fileName; let output = ""; output += color(relativeFileName, ForegroundColorEscapeSequences.Cyan); @@ -770,7 +827,10 @@ export function formatLocation(file: SourceFile, start: number, host: FormatDiag return output; } -export function formatDiagnosticsWithColorAndContext(diagnostics: readonly Diagnostic[], host: FormatDiagnosticsHost): string { +export function formatDiagnosticsWithColorAndContext( + diagnostics: readonly Diagnostic[], + host: FormatDiagnosticsHost, +): string { let output = ""; for (const diagnostic of diagnostics) { if (diagnostic.file) { @@ -785,7 +845,14 @@ export function formatDiagnosticsWithColorAndContext(diagnostics: readonly Diagn if (diagnostic.file && diagnostic.code !== Diagnostics.File_appears_to_be_binary.code) { output += host.getNewLine(); - output += formatCodeSpan(diagnostic.file, diagnostic.start!, diagnostic.length!, "", getCategoryFormat(diagnostic.category), host); // TODO: GH#18217 + output += formatCodeSpan( + diagnostic.file, + diagnostic.start!, + diagnostic.length!, + "", + getCategoryFormat(diagnostic.category), + host, + ); // TODO: GH#18217 } if (diagnostic.relatedInformation) { output += host.getNewLine(); @@ -804,7 +871,11 @@ export function formatDiagnosticsWithColorAndContext(diagnostics: readonly Diagn return output; } -export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageChain | undefined, newLine: string, indent = 0): string { +export function flattenDiagnosticMessageText( + diag: string | DiagnosticMessageChain | undefined, + newLine: string, + indent = 0, +): string { if (isString(diag)) { return diag; } @@ -888,7 +959,7 @@ export function isExclusivelyTypeOnlyImportOrExport(decl: ImportDeclaration | Ex * @param usage The module reference string * @returns The final resolution mode of the import */ -export function getModeForUsageLocation(file: { impliedNodeFormat?: ResolutionMode }, usage: StringLiteralLike) { +export function getModeForUsageLocation(file: { impliedNodeFormat?: ResolutionMode; }, usage: StringLiteralLike) { if (file.impliedNodeFormat === undefined) return undefined; if ((isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent))) { const isTypeOnly = isExclusivelyTypeOnlyImportOrExport(usage.parent); @@ -916,10 +987,16 @@ export function getModeForUsageLocation(file: { impliedNodeFormat?: ResolutionMo } /** @internal */ -export function getResolutionModeOverrideForClause(clause: AssertClause | undefined, grammarErrorOnNode?: (node: Node, diagnostic: DiagnosticMessage) => void) { +export function getResolutionModeOverrideForClause( + clause: AssertClause | undefined, + grammarErrorOnNode?: (node: Node, diagnostic: DiagnosticMessage) => void, +) { if (!clause) return undefined; if (length(clause.elements) !== 1) { - grammarErrorOnNode?.(clause, Diagnostics.Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require); + grammarErrorOnNode?.( + clause, + Diagnostics.Type_import_assertions_should_have_exactly_one_key_resolution_mode_with_value_import_or_require, + ); return undefined; } const elem = clause.elements[0]; @@ -936,10 +1013,12 @@ export function getResolutionModeOverrideForClause(clause: AssertClause | undefi return elem.value.text === "import" ? ModuleKind.ESNext : ModuleKind.CommonJS; } -const emptyResolution: ResolvedModuleWithFailedLookupLocations & ResolvedTypeReferenceDirectiveWithFailedLookupLocations = { - resolvedModule: undefined, - resolvedTypeReferenceDirective: undefined, -}; +const emptyResolution: + & ResolvedModuleWithFailedLookupLocations + & ResolvedTypeReferenceDirectiveWithFailedLookupLocations = { + resolvedModule: undefined, + resolvedTypeReferenceDirective: undefined, + }; /** @internal */ export interface ResolutionNameAndModeGetter { @@ -947,7 +1026,6 @@ export interface ResolutionNameAndModeGetter { getMode(entry: Entry, file: SourceFile): ResolutionMode; } - /** @internal */ export interface ResolutionLoader { nameAndMode: ResolutionNameAndModeGetter; @@ -974,15 +1052,16 @@ export function createModuleResolutionLoader( ): ResolutionLoader { return { nameAndMode: moduleResolutionNameAndModeGetter, - resolve: (moduleName, resolutionMode) => resolveModuleName( - moduleName, - containingFile, - options, - host, - cache, - redirectedReference, - resolutionMode, - ), + resolve: (moduleName, resolutionMode) => + resolveModuleName( + moduleName, + containingFile, + options, + host, + cache, + redirectedReference, + resolutionMode, + ), }; } @@ -992,7 +1071,10 @@ function getTypeReferenceResolutionName(entry: } /** @internal */ -export const typeReferenceResolutionNameAndModeGetter: ResolutionNameAndModeGetter = { +export const typeReferenceResolutionNameAndModeGetter: ResolutionNameAndModeGetter< + FileReference | string, + SourceFile | undefined +> = { getName: getTypeReferenceResolutionName, getMode: (entry, file) => getModeForFileReference(entry, file?.impliedNodeFormat), }; @@ -1007,15 +1089,16 @@ export function createTypeReferenceResolutionLoader { return { nameAndMode: typeReferenceResolutionNameAndModeGetter, - resolve: (typeRef, resoluionMode) => resolveTypeReferenceDirective( - typeRef, - containingFile, - options, - host, - redirectedReference, - cache, - resoluionMode, - ), + resolve: (typeRef, resoluionMode) => + resolveTypeReferenceDirective( + typeRef, + containingFile, + options, + host, + redirectedReference, + cache, + resoluionMode, + ), }; } @@ -1056,16 +1139,30 @@ export function loadWithModeAwareCache( resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined, - cb: (resolvedProjectReference: ResolvedProjectReference, parent: ResolvedProjectReference | undefined) => T | undefined + cb: ( + resolvedProjectReference: ResolvedProjectReference, + parent: ResolvedProjectReference | undefined, + ) => T | undefined, ): T | undefined { - return forEachProjectReference(/*projectReferences*/ undefined, resolvedProjectReferences, (resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent)); + return forEachProjectReference( + /*projectReferences*/ undefined, + resolvedProjectReferences, + (resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent), + ); } function forEachProjectReference( projectReferences: readonly ProjectReference[] | undefined, resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined, - cbResolvedRef: (resolvedRef: ResolvedProjectReference | undefined, parent: ResolvedProjectReference | undefined, index: number) => T | undefined, - cbRef?: (projectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) => T | undefined + cbResolvedRef: ( + resolvedRef: ResolvedProjectReference | undefined, + parent: ResolvedProjectReference | undefined, + index: number, + ) => T | undefined, + cbRef?: ( + projectReferences: readonly ProjectReference[] | undefined, + parent: ResolvedProjectReference | undefined, + ) => T | undefined, ): T | undefined { let seenResolvedRefs: Set | undefined; @@ -1076,7 +1173,6 @@ function forEachProjectReference( resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined, parent: ResolvedProjectReference | undefined, ): T | undefined { - // Visit project references first if (cbRef) { const result = cbRef(projectReferences, parent); @@ -1102,7 +1198,11 @@ function forEachProjectReference( export const inferredTypesContainingFile = "__inferred type names__.ts"; /** @internal */ -export function getInferredLibraryNameResolveFrom(options: CompilerOptions, currentDirectory: string, libFileName: string) { +export function getInferredLibraryNameResolveFrom( + options: CompilerOptions, + currentDirectory: string, + libFileName: string, +) { const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : currentDirectory; return combinePaths(containingDirectory, `__lib_node_modules_lookup_${libFileName}__.ts`); } @@ -1161,19 +1261,28 @@ export interface SyntheticReferenceFileLocation { } /** @internal */ -export function isReferenceFileLocation(location: ReferenceFileLocation | SyntheticReferenceFileLocation): location is ReferenceFileLocation { +export function isReferenceFileLocation( + location: ReferenceFileLocation | SyntheticReferenceFileLocation, +): location is ReferenceFileLocation { return (location as ReferenceFileLocation).pos !== undefined; } /** @internal */ -export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => SourceFile | undefined, ref: ReferencedFile): ReferenceFileLocation | SyntheticReferenceFileLocation { +export function getReferencedFileLocation( + getSourceFileByPath: (path: Path) => SourceFile | undefined, + ref: ReferencedFile, +): ReferenceFileLocation | SyntheticReferenceFileLocation { const file = Debug.checkDefined(getSourceFileByPath(ref.file)); const { kind, index } = ref; - let pos: number | undefined, end: number | undefined, packageId: PackageId | undefined, resolutionMode: FileReference["resolutionMode"] | undefined; + let pos: number | undefined, + end: number | undefined, + packageId: PackageId | undefined, + resolutionMode: FileReference["resolutionMode"] | undefined; switch (kind) { case FileIncludeKind.Import: const importLiteral = getModuleNameStringLiteralAt(file, index); - packageId = file.resolvedModules?.get(importLiteral.text, getModeForResolutionAtIndex(file, index))?.resolvedModule?.packageId; + packageId = file.resolvedModules?.get(importLiteral.text, getModeForResolutionAtIndex(file, index)) + ?.resolvedModule?.packageId; if (importLiteral.pos === -1) return { file, packageId, text: importLiteral.text }; pos = skipTrivia(file.text, importLiteral.pos); end = importLiteral.end; @@ -1183,7 +1292,10 @@ export function getReferencedFileLocation(getSourceFileByPath: (path: Path) => S break; case FileIncludeKind.TypeReferenceDirective: ({ pos, end, resolutionMode } = file.typeReferenceDirectives[index]); - packageId = file.resolvedTypeReferenceDirectiveNames?.get(toFileNameLowerCase(file.typeReferenceDirectives[index].fileName), resolutionMode || file.impliedNodeFormat)?.resolvedTypeReferenceDirective?.packageId; + packageId = file.resolvedTypeReferenceDirectiveNames?.get( + toFileNameLowerCase(file.typeReferenceDirectives[index].fileName), + resolutionMode || file.impliedNodeFormat, + )?.resolvedTypeReferenceDirective?.packageId; break; case FileIncludeKind.LibReferenceDirective: ({ pos, end } = file.libReferenceDirectives[index]); @@ -1209,7 +1321,7 @@ export function isProgramUptoDate( hasInvalidatedLibResolutions: HasInvalidatedLibResolutions, hasChangedAutomaticTypeDirectiveNames: HasChangedAutomaticTypeDirectiveNames | undefined, getParsedCommandLine: (fileName: string) => ParsedCommandLine | undefined, - projectReferences: readonly ProjectReference[] | undefined + projectReferences: readonly ProjectReference[] | undefined, ): boolean { // If we haven't created a program yet or have changed automatic type directives, then it is not up-to-date if (!program || hasChangedAutomaticTypeDirectiveNames?.()) return false; @@ -1233,17 +1345,25 @@ export function isProgramUptoDate( if (!compareDataObjects(currentOptions, newOptions)) return false; // If library resolution is invalidated, then the program is not up-to-date - if (program.resolvedLibReferences && forEachEntry(program.resolvedLibReferences, (_value, libFileName) => hasInvalidatedLibResolutions(libFileName))) return false; + if ( + program.resolvedLibReferences + && forEachEntry( + program.resolvedLibReferences, + (_value, libFileName) => hasInvalidatedLibResolutions(libFileName), + ) + ) return false; // If everything matches but the text of config file is changed, // error locations can change for program options, so update the program - if (currentOptions.configFile && newOptions.configFile) return currentOptions.configFile.text === newOptions.configFile.text; + if (currentOptions.configFile && newOptions.configFile) { + return currentOptions.configFile.text === newOptions.configFile.text; + } return true; function sourceFileNotUptoDate(sourceFile: SourceFile) { - return !sourceFileVersionUptoDate(sourceFile) || - hasInvalidatedResolutions(sourceFile.path); + return !sourceFileVersionUptoDate(sourceFile) + || hasInvalidatedResolutions(sourceFile.path); } function sourceFileVersionUptoDate(sourceFile: SourceFile) { @@ -1251,13 +1371,16 @@ export function isProgramUptoDate( } function projectReferenceUptoDate(oldRef: ProjectReference, newRef: ProjectReference, index: number) { - return projectReferenceIsEqualTo(oldRef, newRef) && - resolvedProjectReferenceUptoDate(program!.getResolvedProjectReferences()![index], oldRef); + return projectReferenceIsEqualTo(oldRef, newRef) + && resolvedProjectReferenceUptoDate(program!.getResolvedProjectReferences()![index], oldRef); } - function resolvedProjectReferenceUptoDate(oldResolvedRef: ResolvedProjectReference | undefined, oldRef: ProjectReference): boolean { + function resolvedProjectReferenceUptoDate( + oldResolvedRef: ResolvedProjectReference | undefined, + oldRef: ProjectReference, + ): boolean { if (oldResolvedRef) { - // Assume true + // Assume true if (contains(seenResolvedRefs, oldResolvedRef)) return true; const refPath = resolveProjectReferencePath(oldRef); @@ -1276,8 +1399,14 @@ export function isProgramUptoDate( (seenResolvedRefs || (seenResolvedRefs = [])).push(oldResolvedRef); // If child project references are upto date, this project reference is uptodate - return !forEach(oldResolvedRef.references, (childResolvedRef, index) => - !resolvedProjectReferenceUptoDate(childResolvedRef, oldResolvedRef.commandLine.projectReferences![index])); + return !forEach( + oldResolvedRef.references, + (childResolvedRef, index) => + !resolvedProjectReferenceUptoDate( + childResolvedRef, + oldResolvedRef.commandLine.projectReferences![index], + ), + ); } // In old program, not able to resolve project reference path, @@ -1288,9 +1417,9 @@ export function isProgramUptoDate( } export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCommandLine): readonly Diagnostic[] { - return configFileParseResult.options.configFile ? - [...configFileParseResult.options.configFile.parseDiagnostics, ...configFileParseResult.errors] : - configFileParseResult.errors; + return configFileParseResult.options.configFile + ? [...configFileParseResult.options.configFile.parseDiagnostics, ...configFileParseResult.errors] + : configFileParseResult.errors; } /** @@ -1303,7 +1432,12 @@ export function getConfigFileParsingDiagnostics(configFileParseResult: ParsedCom * @param options The compiler options to perform the analysis under - relevant options are `moduleResolution` and `traceResolution` * @returns `undefined` if the path has no relevant implied format, `ModuleKind.ESNext` for esm format, and `ModuleKind.CommonJS` for cjs format */ -export function getImpliedNodeFormatForFile(fileName: Path, packageJsonInfoCache: PackageJsonInfoCache | undefined, host: ModuleResolutionHost, options: CompilerOptions): ResolutionMode { +export function getImpliedNodeFormatForFile( + fileName: Path, + packageJsonInfoCache: PackageJsonInfoCache | undefined, + host: ModuleResolutionHost, + options: CompilerOptions, +): ResolutionMode { const result = getImpliedNodeFormatForFileWorker(fileName, packageJsonInfoCache, host, options); return typeof result === "object" ? result.impliedNodeFormat : result; } @@ -1318,10 +1452,16 @@ export function getImpliedNodeFormatForFileWorker( switch (getEmitModuleResolutionKind(options)) { case ModuleResolutionKind.Node16: case ModuleResolutionKind.NodeNext: - return fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Mjs]) ? ModuleKind.ESNext : - fileExtensionIsOneOf(fileName, [Extension.Dcts, Extension.Cts, Extension.Cjs]) ? ModuleKind.CommonJS : - fileExtensionIsOneOf(fileName, [Extension.Dts, Extension.Ts, Extension.Tsx, Extension.Js, Extension.Jsx]) ? lookupFromPackageJson() : - undefined; // other extensions, like `json` or `tsbuildinfo`, are set as `undefined` here but they should never be fed through the transformer pipeline + return fileExtensionIsOneOf(fileName, [Extension.Dmts, Extension.Mts, Extension.Mjs]) ? ModuleKind.ESNext + : fileExtensionIsOneOf(fileName, [Extension.Dcts, Extension.Cts, Extension.Cjs]) ? ModuleKind.CommonJS + : fileExtensionIsOneOf(fileName, [ + Extension.Dts, + Extension.Ts, + Extension.Tsx, + Extension.Js, + Extension.Jsx, + ]) ? lookupFromPackageJson() + : undefined; // other extensions, like `json` or `tsbuildinfo`, are set as `undefined` here but they should never be fed through the transformer pipeline default: return undefined; } @@ -1331,7 +1471,8 @@ export function getImpliedNodeFormatForFileWorker( state.failedLookupLocations = packageJsonLocations; state.affectingLocations = packageJsonLocations; const packageJsonScope = getPackageScopeForPath(fileName, state); - const impliedNodeFormat = packageJsonScope?.contents.packageJsonContent.type === "module" ? ModuleKind.ESNext : ModuleKind.CommonJS; + const impliedNodeFormat = packageJsonScope?.contents.packageJsonContent.type === "module" ? ModuleKind.ESNext + : ModuleKind.CommonJS; return { impliedNodeFormat, packageJsonLocations, packageJsonScope }; } } @@ -1348,7 +1489,9 @@ export const plainJSErrors = new Set([ Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here.code, Diagnostics.constructor_is_a_reserved_word.code, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode.code, - Diagnostics.Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode.code, + Diagnostics + .Code_contained_in_a_class_is_evaluated_in_JavaScript_s_strict_mode_which_does_not_allow_this_use_of_0_For_more_information_see_https_Colon_Slash_Slashdeveloper_mozilla_org_Slashen_US_Slashdocs_SlashWeb_SlashJavaScript_SlashReference_SlashStrict_mode + .code, Diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode.code, Diagnostics.Invalid_use_of_0_in_strict_mode.code, Diagnostics.A_label_is_not_allowed_here.code, @@ -1386,10 +1529,14 @@ export const plainJSErrors = new Set([ Diagnostics.Cannot_assign_to_private_method_0_Private_methods_are_not_writable.code, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause.code, Diagnostics.Catch_clause_variable_cannot_have_an_initializer.code, - Diagnostics.Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator.code, + Diagnostics + .Class_decorators_can_t_be_used_with_static_private_identifier_Consider_removing_the_experimental_decorator + .code, Diagnostics.Classes_can_only_extend_a_single_class.code, Diagnostics.Classes_may_not_have_a_field_named_constructor.code, - Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern.code, + Diagnostics + .Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern + .code, Diagnostics.Duplicate_label_0.code, Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments.code, Diagnostics.for_await_loops_cannot_be_used_inside_a_class_static_block.code, @@ -1403,7 +1550,9 @@ export const plainJSErrors = new Set([ Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement.code, Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_of_statement.code, Diagnostics.Private_identifiers_are_not_allowed_outside_class_bodies.code, - Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression.code, + Diagnostics + .Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression + .code, Diagnostics.Property_0_is_not_accessible_outside_class_1_because_it_has_a_private_identifier.code, Diagnostics.Tagged_template_expressions_are_not_permitted_in_an_optional_chain.code, Diagnostics.The_left_hand_side_of_a_for_of_statement_may_not_be_async.code, @@ -1445,7 +1594,14 @@ function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOpti return optionsHaveChanges(program.getCompilerOptions(), newOptions, sourceFileAffectingCompilerOptions); } -function createCreateProgramOptions(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[], typeScriptVersion?: string): CreateProgramOptions { +function createCreateProgramOptions( + rootNames: readonly string[], + options: CompilerOptions, + host?: CompilerHost, + oldProgram?: Program, + configFileParsingDiagnostics?: readonly Diagnostic[], + typeScriptVersion?: string, +): CreateProgramOptions { return { rootNames, options, @@ -1481,13 +1637,30 @@ export function createProgram(createProgramOptions: CreateProgramOptions): Progr * @param configFileParsingDiagnostics - error during config file parsing * @returns A 'Program' object. */ -export function createProgram(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[]): Program; -export function createProgram(rootNamesOrOptions: readonly string[] | CreateProgramOptions, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: readonly Diagnostic[]): Program { - const createProgramOptions = isArray(rootNamesOrOptions) ? createCreateProgramOptions(rootNamesOrOptions, _options!, _host, _oldProgram, _configFileParsingDiagnostics) : rootNamesOrOptions; // TODO: GH#18217 - const { rootNames, options, configFileParsingDiagnostics, projectReferences, typeScriptVersion } = createProgramOptions; +export function createProgram( + rootNames: readonly string[], + options: CompilerOptions, + host?: CompilerHost, + oldProgram?: Program, + configFileParsingDiagnostics?: readonly Diagnostic[], +): Program; +export function createProgram( + rootNamesOrOptions: readonly string[] | CreateProgramOptions, + _options?: CompilerOptions, + _host?: CompilerHost, + _oldProgram?: Program, + _configFileParsingDiagnostics?: readonly Diagnostic[], +): Program { + const createProgramOptions = isArray(rootNamesOrOptions) + ? createCreateProgramOptions(rootNamesOrOptions, _options!, _host, _oldProgram, _configFileParsingDiagnostics) + : rootNamesOrOptions; // TODO: GH#18217 + const { rootNames, options, configFileParsingDiagnostics, projectReferences, typeScriptVersion } = + createProgramOptions; let { oldProgram } = createProgramOptions; - const reportInvalidIgnoreDeprecations = memoize(() => createOptionValueDiagnostic("ignoreDeprecations", Diagnostics.Invalid_value_for_ignoreDeprecations)); + const reportInvalidIgnoreDeprecations = memoize(() => + createOptionValueDiagnostic("ignoreDeprecations", Diagnostics.Invalid_value_for_ignoreDeprecations) + ); let processingDefaultLibFiles: SourceFile[] | undefined; let processingOtherFiles: SourceFile[] | undefined; @@ -1501,7 +1674,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const cachedBindAndCheckDiagnosticsForFile: DiagnosticCache = {}; const cachedDeclarationDiagnosticsForFile: DiagnosticCache = {}; - let resolvedTypeReferenceDirectives = createModeAwareCache(); + let resolvedTypeReferenceDirectives = createModeAwareCache< + ResolvedTypeReferenceDirectiveWithFailedLookupLocations + >(); let fileProcessingDiagnostics: FilePreprocessingDiagnostics[] | undefined; let automaticTypeDirectiveNames: string[] | undefined; let automaticTypeDirectiveResolutions: ModeAwareCache; @@ -1511,7 +1686,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg let packageMap: Map | undefined; - // The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules. // This works as imported modules are discovered recursively in a depth first manner, specifically: // - For each root file, findSourceFile is called. @@ -1529,7 +1703,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // Track source files that are source files found by searching under node_modules, as these shouldn't be compiled. const sourceFilesFoundSearchingNodeModules = new Map(); - tracing?.push(tracing.Phase.Program, "createProgram", { configFilePath: options.configFilePath, rootDir: options.rootDir }, /*separateBeginAndEnd*/ true); + tracing?.push(tracing.Phase.Program, "createProgram", { + configFilePath: options.configFilePath, + rootDir: options.rootDir, + }, /*separateBeginAndEnd*/ true); performance.mark("beforeProgram"); const host = createProgramOptions.host || createCompilerHost(options); @@ -1537,7 +1714,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg let skipDefaultLib = options.noLib; const getDefaultLibraryFileName = memoize(() => host.getDefaultLibFileName(options)); - const defaultLibraryPath = host.getDefaultLibLocation ? host.getDefaultLibLocation() : getDirectoryPath(getDefaultLibraryFileName()); + const defaultLibraryPath = host.getDefaultLibLocation ? host.getDefaultLibLocation() + : getDirectoryPath(getDefaultLibraryFileName()); /** * Diagnostics for the program * Only add diagnostics directly if it always would be done irrespective of program structure reuse. @@ -1546,7 +1724,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const programDiagnostics = createDiagnosticCollection(); const currentDirectory = host.getCurrentDirectory(); const supportedExtensions = getSupportedExtensions(options); - const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions); + const supportedExtensionsWithJsonIfResolveJsonModule = getSupportedExtensionsWithJsonIfResolveJsonModule( + options, + supportedExtensions, + ); // Map storing if there is emit blocking diagnostics for given input const hasEmitBlockingDiagnostics = new Map(); @@ -1567,36 +1748,48 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg moduleResolutionCache = host.getModuleResolutionCache?.(); } else if (host.resolveModuleNames) { - actualResolveModuleNamesWorker = (moduleNames, containingFile, redirectedReference, options, containingSourceFile, reusedNames) => - host.resolveModuleNames!( - moduleNames.map(getModuleResolutionName), - containingFile, - reusedNames?.map(getModuleResolutionName), - redirectedReference, - options, - containingSourceFile, - ).map(resolved => resolved ? - ((resolved as ResolvedModuleFull).extension !== undefined) ? - { resolvedModule: resolved as ResolvedModuleFull } : + actualResolveModuleNamesWorker = ( + moduleNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + reusedNames, + ) => host.resolveModuleNames!( + moduleNames.map(getModuleResolutionName), + containingFile, + reusedNames?.map(getModuleResolutionName), + redirectedReference, + options, + containingSourceFile, + ).map(resolved => + resolved + ? ((resolved as ResolvedModuleFull).extension !== undefined) + ? { resolvedModule: resolved as ResolvedModuleFull } // An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName. - { resolvedModule: { ...resolved, extension: extensionFromPath(resolved.resolvedFileName) } } : - emptyResolution - ); + : { resolvedModule: { ...resolved, extension: extensionFromPath(resolved.resolvedFileName) } } + : emptyResolution + ); moduleResolutionCache = host.getModuleResolutionCache?.(); } else { moduleResolutionCache = createModuleResolutionCache(currentDirectory, getCanonicalFileName, options); - actualResolveModuleNamesWorker = (moduleNames, containingFile, redirectedReference, options, containingSourceFile) => - loadWithModeAwareCache( - moduleNames, - containingFile, - redirectedReference, - options, - containingSourceFile, - host, - moduleResolutionCache, - createModuleResolutionLoader, - ); + actualResolveModuleNamesWorker = ( + moduleNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + ) => loadWithModeAwareCache( + moduleNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + host, + moduleResolutionCache, + createModuleResolutionLoader, + ); } let actualResolveTypeReferenceDirectiveNamesWorker: ( @@ -1611,14 +1804,19 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg actualResolveTypeReferenceDirectiveNamesWorker = host.resolveTypeReferenceDirectiveReferences.bind(host); } else if (host.resolveTypeReferenceDirectives) { - actualResolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference, options, containingSourceFile) => - host.resolveTypeReferenceDirectives!( - typeDirectiveNames.map(getTypeReferenceResolutionName), - containingFile, - redirectedReference, - options, - containingSourceFile?.impliedNodeFormat, - ).map(resolvedTypeReferenceDirective => ({ resolvedTypeReferenceDirective })); + actualResolveTypeReferenceDirectiveNamesWorker = ( + typeDirectiveNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + ) => host.resolveTypeReferenceDirectives!( + typeDirectiveNames.map(getTypeReferenceResolutionName), + containingFile, + redirectedReference, + options, + containingSourceFile?.impliedNodeFormat, + ).map(resolvedTypeReferenceDirective => ({ resolvedTypeReferenceDirective })); } else { const typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache( @@ -1628,26 +1826,41 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg moduleResolutionCache?.getPackageJsonInfoCache(), moduleResolutionCache?.optionsToRedirectsKey, ); - actualResolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile, redirectedReference, options, containingSourceFile) => - loadWithModeAwareCache( - typeDirectiveNames, - containingFile, - redirectedReference, - options, - containingSourceFile, - host, - typeReferenceDirectiveResolutionCache, - createTypeReferenceResolutionLoader, - ); + actualResolveTypeReferenceDirectiveNamesWorker = ( + typeDirectiveNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + ) => loadWithModeAwareCache( + typeDirectiveNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + host, + typeReferenceDirectiveResolutionCache, + createTypeReferenceResolutionLoader, + ); } const hasInvalidatedLibResolutions = host.hasInvalidatedLibResolutions || returnFalse; - let actualResolveLibrary: (libraryName: string, resolveFrom: string, options: CompilerOptions, libFileName: string) => ResolvedModuleWithFailedLookupLocations; + let actualResolveLibrary: ( + libraryName: string, + resolveFrom: string, + options: CompilerOptions, + libFileName: string, + ) => ResolvedModuleWithFailedLookupLocations; if (host.resolveLibrary) { actualResolveLibrary = host.resolveLibrary.bind(host); } else { - const libraryResolutionCache = createModuleResolutionCache(currentDirectory, getCanonicalFileName, options, moduleResolutionCache?.getPackageJsonInfoCache()); + const libraryResolutionCache = createModuleResolutionCache( + currentDirectory, + getCanonicalFileName, + options, + moduleResolutionCache?.getPackageJsonInfoCache(), + ); actualResolveLibrary = (libraryName, resolveFrom, options) => resolveLibrary(libraryName, resolveFrom, options, host, libraryResolutionCache); } @@ -1680,8 +1893,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg let mapFromFileToProjectReferenceRedirects: Map | undefined; let mapFromToProjectReferenceRedirectSource: Map | undefined; - const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() && - !options.disableSourceOfProjectReferenceRedirect; + const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() + && !options.disableSourceOfProjectReferenceRedirect; const { onProgramCreateComplete, fileExists, directoryExists } = updateHostForUseSourceOfProjectReferenceRedirect({ compilerHost: host, getSymlinkCache, @@ -1689,7 +1902,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg toPath, getResolvedProjectReferences, getSourceOfProjectReferenceRedirect, - forEachResolvedProjectReference + forEachResolvedProjectReference, }); const readFile = host.readFile.bind(host) as typeof host.readFile; @@ -1717,19 +1930,38 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (useSourceOfProjectReferenceRedirect) { if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { for (const fileName of parsedRef.commandLine.fileNames) { - processProjectReferenceFile(fileName, { kind: FileIncludeKind.SourceFromProjectReference, index }); + processProjectReferenceFile(fileName, { + kind: FileIncludeKind.SourceFromProjectReference, + index, + }); } } } else { if (out) { - processProjectReferenceFile(changeExtension(out, ".d.ts"), { kind: FileIncludeKind.OutputFromProjectReference, index }); + processProjectReferenceFile(changeExtension(out, ".d.ts"), { + kind: FileIncludeKind.OutputFromProjectReference, + index, + }); } else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) { - const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(parsedRef.commandLine, !host.useCaseSensitiveFileNames())); + const getCommonSourceDirectory = memoize(() => + getCommonSourceDirectoryOfConfig( + parsedRef.commandLine, + !host.useCaseSensitiveFileNames(), + ) + ); for (const fileName of parsedRef.commandLine.fileNames) { if (!isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json)) { - processProjectReferenceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory), { kind: FileIncludeKind.OutputFromProjectReference, index }); + processProjectReferenceFile( + getOutputDeclarationFileName( + fileName, + parsedRef.commandLine, + !host.useCaseSensitiveFileNames(), + getCommonSourceDirectory, + ), + { kind: FileIncludeKind.OutputFromProjectReference, index }, + ); } } } @@ -1739,21 +1971,38 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } tracing?.push(tracing.Phase.Program, "processRootFiles", { count: rootNames.length }); - forEach(rootNames, (name, index) => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.RootFile, index })); + forEach( + rootNames, + (name, index) => + processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { + kind: FileIncludeKind.RootFile, + index, + }), + ); tracing?.pop(); // load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders automaticTypeDirectiveNames ??= rootNames.length ? getAutomaticTypeDirectiveNames(options, host) : emptyArray; automaticTypeDirectiveResolutions = createModeAwareCache(); if (automaticTypeDirectiveNames.length) { - tracing?.push(tracing.Phase.Program, "processTypeReferences", { count: automaticTypeDirectiveNames.length }); + tracing?.push(tracing.Phase.Program, "processTypeReferences", { + count: automaticTypeDirectiveNames.length, + }); // This containingFilename needs to match with the one used in managed-side - const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) : currentDirectory; + const containingDirectory = options.configFilePath ? getDirectoryPath(options.configFilePath) + : currentDirectory; const containingFilename = combinePaths(containingDirectory, inferredTypesContainingFile); - const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState(automaticTypeDirectiveNames, containingFilename); + const resolutions = resolveTypeReferenceDirectiveNamesReusingOldState( + automaticTypeDirectiveNames, + containingFilename, + ); for (let i = 0; i < automaticTypeDirectiveNames.length; i++) { // under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode - automaticTypeDirectiveResolutions.set(automaticTypeDirectiveNames[i], /*mode*/ undefined, resolutions[i]); + automaticTypeDirectiveResolutions.set( + automaticTypeDirectiveNames[i], + /*mode*/ undefined, + resolutions[i], + ); processTypeReferenceDirective( automaticTypeDirectiveNames[i], /*mode*/ undefined, @@ -1777,16 +2026,23 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // otherwise, using options specified in '--lib' instead of '--target' default library file const defaultLibraryFileName = getDefaultLibraryFileName(); if (!options.lib && defaultLibraryFileName) { - processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile }); + processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { + kind: FileIncludeKind.LibFile, + }); } else { forEach(options.lib, (libFileName, index) => { - processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile, index }); + processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { + kind: FileIncludeKind.LibFile, + index, + }); }); } } - missingFilePaths = arrayFrom(mapDefinedIterator(filesByName.entries(), ([path, file]) => file === undefined ? path as Path : undefined)); + missingFilePaths = arrayFrom( + mapDefinedIterator(filesByName.entries(), ([path, file]) => file === undefined ? path as Path : undefined), + ); files = stableSort(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles); processingDefaultLibFiles = undefined; processingOtherFiles = undefined; @@ -1800,16 +2056,26 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const oldSourceFiles = oldProgram.getSourceFiles(); for (const oldSourceFile of oldSourceFiles) { const newFile = getSourceFileByPath(oldSourceFile.resolvedPath); - if (shouldCreateNewSourceFile || !newFile || newFile.impliedNodeFormat !== oldSourceFile.impliedNodeFormat || + if ( + shouldCreateNewSourceFile || !newFile || newFile.impliedNodeFormat !== oldSourceFile.impliedNodeFormat // 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)); + || (oldSourceFile.resolvedPath === oldSourceFile.path && newFile.resolvedPath !== oldSourceFile.path) + ) { + host.onReleaseOldSourceFile( + oldSourceFile, + oldProgram.getCompilerOptions(), + !!getSourceFileByPath(oldSourceFile.path), + ); } } 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, + ); } }); } @@ -1821,12 +2087,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg oldProgram.getProjectReferences(), oldProgram.getResolvedProjectReferences(), (oldResolvedRef, parent, index) => { - const oldReference = parent?.commandLine.projectReferences![index] || oldProgram!.getProjectReferences()![index]; + const oldReference = parent?.commandLine.projectReferences![index] + || oldProgram!.getProjectReferences()![index]; const oldRefPath = resolveProjectReferencePath(oldReference); if (!projectReferenceRedirects?.has(toPath(oldRefPath))) { host.onReleaseParsedCommandLine!(oldRefPath, oldResolvedRef, oldProgram!.getCompilerOptions()); } - } + }, ); } @@ -1906,10 +2173,28 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg fileProcessingDiagnostics?.forEach(diagnostic => { switch (diagnostic.kind) { case FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic: - return programDiagnostics.add(createDiagnosticExplainingFile(diagnostic.file && getSourceFileByPath(diagnostic.file), diagnostic.fileProcessingReason, diagnostic.diagnostic, diagnostic.args || emptyArray)); + return programDiagnostics.add( + createDiagnosticExplainingFile( + diagnostic.file && getSourceFileByPath(diagnostic.file), + diagnostic.fileProcessingReason, + diagnostic.diagnostic, + diagnostic.args || emptyArray, + ), + ); case FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic: - const { file, pos, end } = getReferencedFileLocation(getSourceFileByPath, diagnostic.reason) as ReferenceFileLocation; - return programDiagnostics.add(createFileDiagnostic(file, Debug.checkDefined(pos), Debug.checkDefined(end) - pos, diagnostic.diagnostic, ...diagnostic.args || emptyArray)); + const { file, pos, end } = getReferencedFileLocation( + getSourceFileByPath, + diagnostic.reason, + ) as ReferenceFileLocation; + return programDiagnostics.add( + createFileDiagnostic( + file, + Debug.checkDefined(pos), + Debug.checkDefined(end) - pos, + diagnostic.diagnostic, + ...diagnostic.args || emptyArray, + ), + ); case FilePreprocessingDiagnosticsKind.ResolutionDiagnostics: return diagnostic.diagnostics.forEach(d => programDiagnostics.add(d)); default: @@ -1935,7 +2220,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (!sf.resolvedModules) return; sf.resolvedModules.forEach(({ resolvedModule }) => { - if (resolvedModule?.packageId) packageMap!.set(resolvedModule.packageId.name, resolvedModule.extension === Extension.Dts || !!packageMap!.get(resolvedModule.packageId.name)); + if (resolvedModule?.packageId) { + packageMap!.set( + resolvedModule.packageId.name, + resolvedModule.extension === Extension.Dts || !!packageMap!.get(resolvedModule.packageId.name), + ); + } }); }); return packageMap; @@ -1948,15 +2238,22 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return !!getPackagesMap().get(packageName); } - function addResolutionDiagnostics(resolution: ResolvedModuleWithFailedLookupLocations | ResolvedTypeReferenceDirectiveWithFailedLookupLocations) { + function addResolutionDiagnostics( + resolution: ResolvedModuleWithFailedLookupLocations | ResolvedTypeReferenceDirectiveWithFailedLookupLocations, + ) { if (!resolution.resolutionDiagnostics?.length) return; (fileProcessingDiagnostics ??= []).push({ kind: FilePreprocessingDiagnosticsKind.ResolutionDiagnostics, - diagnostics: resolution.resolutionDiagnostics + diagnostics: resolution.resolutionDiagnostics, }); } - function addResolutionDiagnosticsFromResolutionOrCache(containingFile: SourceFile, name: string, resolution: ResolvedModuleWithFailedLookupLocations, mode: ResolutionMode) { + function addResolutionDiagnosticsFromResolutionOrCache( + containingFile: SourceFile, + name: string, + resolution: ResolvedModuleWithFailedLookupLocations, + mode: ResolutionMode, + ) { // diagnostics directly from the resolution if (host.resolveModuleNameLiterals || !host.resolveModuleNames) return addResolutionDiagnostics(resolution); if (!moduleResolutionCache || isExternalModuleNameRelative(name)) return; @@ -1968,31 +2265,59 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // This may totally change if/when the issue of output paths not mapping to input files is fixed in a broader context // When it is, how we extract diagnostics from the module name resolver will have the be refined - the current cache // APIs wrapping the underlying resolver make it almost impossible to smuggle the diagnostics out in a generalized way - const fromCache = moduleResolutionCache.getFromNonRelativeNameCache(name, mode, containingDir, redirectedReference); + const fromCache = moduleResolutionCache.getFromNonRelativeNameCache( + name, + mode, + containingDir, + redirectedReference, + ); if (fromCache) addResolutionDiagnostics(fromCache); } - function resolveModuleNamesWorker(moduleNames: readonly StringLiteralLike[], containingFile: SourceFile, reusedNames: readonly StringLiteralLike[] | undefined): readonly ResolvedModuleWithFailedLookupLocations[] { + function resolveModuleNamesWorker( + moduleNames: readonly StringLiteralLike[], + containingFile: SourceFile, + reusedNames: readonly StringLiteralLike[] | undefined, + ): readonly ResolvedModuleWithFailedLookupLocations[] { if (!moduleNames.length) return emptyArray; 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(typeDirectiveNames: readonly T[], containingFile: string | SourceFile, reusedNames: readonly T[] | undefined): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { + function resolveTypeReferenceDirectiveNamesWorker( + typeDirectiveNames: readonly T[], + containingFile: string | SourceFile, + reusedNames: readonly T[] | undefined, + ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { if (!typeDirectiveNames.length) return []; const containingSourceFile = !isString(containingFile) ? containingFile : undefined; - const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile; + 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(); @@ -2012,9 +2337,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // but the resolved real path may be the .d.ts from project reference // Note:: Currently we try the real path only if the // file is from node_modules to avoid having to run real path on all file paths - if (!host.realpath || !options.preserveSymlinks || !stringContains(file.originalFileName, nodeModulesPathPart)) return undefined; + if ( + !host.realpath || !options.preserveSymlinks || !stringContains(file.originalFileName, nodeModulesPathPart) + ) return undefined; const realDeclarationPath = toPath(host.realpath(file.originalFileName)); - return realDeclarationPath === file.path ? undefined : getRedirectReferenceForResolutionFromSourceOfProject(realDeclarationPath); + return realDeclarationPath === file.path ? undefined + : getRedirectReferenceForResolutionFromSourceOfProject(realDeclarationPath); } function getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path) { @@ -2056,7 +2384,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg () => mapDefined(emittedFiles, file => file.isDeclarationFile ? undefined : file.fileName), currentDirectory, getCanonicalFileName, - commonSourceDirectory => checkSourceFilesBelongToPath(emittedFiles, commonSourceDirectory) + commonSourceDirectory => checkSourceFilesBelongToPath(emittedFiles, commonSourceDirectory), ); } return commonSourceDirectory; @@ -2076,7 +2404,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return classifiableNames; } - function resolveModuleNamesReusingOldState(moduleNames: readonly StringLiteralLike[], file: SourceFile): readonly ResolvedModuleWithFailedLookupLocations[] { + 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. @@ -2095,7 +2426,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // it is safe to reuse resolutions from the earlier call. const result: ResolvedModuleWithFailedLookupLocations[] = []; for (const moduleName of moduleNames) { - const resolvedModule = file.resolvedModules.get(moduleName.text, getModeForUsageLocation(file, moduleName))!; + const resolvedModule = file.resolvedModules.get( + moduleName.text, + getModeForUsageLocation(file, moduleName), + )!; result.push(resolvedModule); } return result; @@ -2129,14 +2463,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const oldResolution = oldSourceFile.resolvedModules?.get(moduleName.text, mode); 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, + 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) + oldResolution.resolvedModule.packageId + && packageIdToString(oldResolution.resolvedModule.packageId), ); } (result ??= new Array(moduleNames.length))[i] = oldResolution; @@ -2152,11 +2490,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg 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)); + 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); + resolvesToAmbientModuleInNonModifiedFile = moduleNameResolvesToAmbientModuleInNonModifiedFile( + moduleName, + ); } if (resolvesToAmbientModuleInNonModifiedFile) { @@ -2193,7 +2538,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // If we change our policy of rechecking failed lookups on each program create, // we should adjust the value returned here. function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: StringLiteralLike): boolean { - const resolutionToFile = getResolvedModule(oldSourceFile, moduleName.text, getModeForUsageLocation(file, moduleName)); + const resolutionToFile = getResolvedModule( + oldSourceFile, + moduleName.text, + getModeForUsageLocation(file, moduleName), + ); 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 @@ -2211,22 +2560,41 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } 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_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 T[], containingFile: string | SourceFile): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { + function resolveTypeReferenceDirectiveNamesReusingOldState( + typeDirectiveNames: readonly FileReference[], + containingFile: SourceFile, + ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; + function resolveTypeReferenceDirectiveNamesReusingOldState( + typeDirectiveNames: string[], + containingFile: string, + ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; + function resolveTypeReferenceDirectiveNamesReusingOldState( + typeDirectiveNames: readonly T[], + containingFile: string | SourceFile, + ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { if (structureIsReused === StructureIsReused.Not) { // 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 resolveTypeReferenceDirectiveNamesWorker( + typeDirectiveNames, + containingFile, + /*reusedNames*/ undefined, + ); } - const oldSourceFile = !isString(containingFile) ? oldProgram && oldProgram.getSourceFile(containingFile.fileName) : undefined; + const oldSourceFile = !isString(containingFile) + ? oldProgram && oldProgram.getSourceFile(containingFile.fileName) : undefined; if (!isString(containingFile)) { if (oldSourceFile !== containingFile && containingFile.resolvedTypeReferenceDirectiveNames) { // `file` was created for the new program. @@ -2240,7 +2608,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const result: ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] = []; for (const typeDirectiveName of typeDirectiveNames as readonly FileReference[]) { // We lower-case all type references because npm automatically lowercases all packages. See GH#9824. - const resolvedTypeReferenceDirective = containingFile.resolvedTypeReferenceDirectiveNames.get(getTypeReferenceResolutionName(typeDirectiveName), getModeForFileReference(typeDirectiveName, containingFile.impliedNodeFormat))!; + const resolvedTypeReferenceDirective = containingFile.resolvedTypeReferenceDirectiveNames.get( + getTypeReferenceResolutionName(typeDirectiveName), + getModeForFileReference(typeDirectiveName, containingFile.impliedNodeFormat), + )!; result.push(resolvedTypeReferenceDirective); } return result; @@ -2252,25 +2623,32 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg let result: ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] | undefined; let reusedNames: T[] | undefined; const containingSourceFile = !isString(containingFile) ? containingFile : undefined; - const canReuseResolutions = !isString(containingFile) ? - containingFile === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path) : - !hasInvalidatedResolutions(toPath(containingFile)); + const canReuseResolutions = !isString(containingFile) + ? containingFile === oldSourceFile && !hasInvalidatedResolutions(oldSourceFile.path) + : !hasInvalidatedResolutions(toPath(containingFile)); for (let i = 0; i < typeDirectiveNames.length; i++) { const entry = typeDirectiveNames[i]; if (canReuseResolutions) { const typeDirectiveName = getTypeReferenceResolutionName(entry); const mode = getModeForFileReference(entry, containingSourceFile?.impliedNodeFormat); - const oldResolution = (!isString(containingFile) ? oldSourceFile?.resolvedTypeReferenceDirectiveNames : oldProgram?.getAutomaticTypeDirectiveResolutions())?.get(typeDirectiveName, mode); + const oldResolution = (!isString(containingFile) ? oldSourceFile?.resolvedTypeReferenceDirectiveNames + : oldProgram?.getAutomaticTypeDirectiveResolutions())?.get(typeDirectiveName, mode); if (oldResolution?.resolvedTypeReferenceDirective) { if (isTraceEnabled(options, host)) { - trace(host, - oldResolution.resolvedTypeReferenceDirective.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, + trace( + host, + oldResolution.resolvedTypeReferenceDirective.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, + !isString(containingFile) + ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) + : containingFile, oldResolution.resolvedTypeReferenceDirective.resolvedFileName, - oldResolution.resolvedTypeReferenceDirective.packageId && packageIdToString(oldResolution.resolvedTypeReferenceDirective.packageId) + oldResolution.resolvedTypeReferenceDirective.packageId + && packageIdToString(oldResolution.resolvedTypeReferenceDirective.packageId), ); } (result ??= new Array(typeDirectiveNames.length))[i] = oldResolution; @@ -2316,9 +2694,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const newResolvedRef = parseProjectReferenceConfigFile(newRef); if (oldResolvedRef) { // Resolved project reference has gone missing or changed - return !newResolvedRef || - newResolvedRef.sourceFile !== oldResolvedRef.sourceFile || - !arrayIsEqualTo(oldResolvedRef.commandLine.fileNames, newResolvedRef.commandLine.fileNames); + return !newResolvedRef + || newResolvedRef.sourceFile !== oldResolvedRef.sourceFile + || !arrayIsEqualTo(oldResolvedRef.commandLine.fileNames, newResolvedRef.commandLine.fileNames); } else { // A previously-unresolved reference may be resolved now @@ -2327,9 +2705,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg }, (oldProjectReferences, parent) => { // If array of references is changed, we cant resue old program - const newReferences = parent ? getResolvedProjectReferenceByPath(parent.sourceFile.path)!.commandLine.projectReferences : projectReferences; + const newReferences = parent + ? getResolvedProjectReferenceByPath(parent.sourceFile.path)!.commandLine.projectReferences + : projectReferences; return !arrayIsEqualTo(oldProjectReferences, newReferences, projectReferenceIsEqualTo); - } + }, ); } @@ -2361,7 +2741,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // check if program source files has changed in the way that can affect structure of the program const newSourceFiles: SourceFile[] = []; - const modifiedSourceFiles: { oldFile: SourceFile, newFile: SourceFile }[] = []; + const modifiedSourceFiles: { oldFile: SourceFile; newFile: SourceFile; }[] = []; structureIsReused = StructureIsReused.Completely; // If the missing file paths are now present, it can change the progam structure, @@ -2372,22 +2752,45 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } const oldSourceFiles = oldProgram.getSourceFiles(); - const enum SeenPackageName { Exists, Modified } + const enum SeenPackageName { + Exists, + Modified, + } const seenPackageNames = new Map(); for (const oldSourceFile of oldSourceFiles) { - const sourceFileOptions = getCreateSourceFileOptions(oldSourceFile.fileName, moduleResolutionCache, host, options); + const sourceFileOptions = getCreateSourceFileOptions( + oldSourceFile.fileName, + moduleResolutionCache, + host, + options, + ); let newSourceFile = host.getSourceFileByPath - ? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.resolvedPath, sourceFileOptions, /*onError*/ undefined, shouldCreateNewSourceFile) - : host.getSourceFile(oldSourceFile.fileName, sourceFileOptions, /*onError*/ undefined, shouldCreateNewSourceFile); // TODO: GH#18217 + ? host.getSourceFileByPath( + oldSourceFile.fileName, + oldSourceFile.resolvedPath, + sourceFileOptions, + /*onError*/ undefined, + shouldCreateNewSourceFile, + ) + : host.getSourceFile( + oldSourceFile.fileName, + sourceFileOptions, + /*onError*/ undefined, + shouldCreateNewSourceFile, + ); // TODO: GH#18217 if (!newSourceFile) { return StructureIsReused.Not; } - newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; + newSourceFile.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length + ? sourceFileOptions.packageJsonLocations : undefined; newSourceFile.packageJsonScope = sourceFileOptions.packageJsonScope; - Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`"); + Debug.assert( + !newSourceFile.redirectInfo, + "Host should not return a redirect source file from `getSourceFile`", + ); let fileChanged: boolean; if (oldSourceFile.redirectInfo) { @@ -2423,7 +2826,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // they might become redirects. So we must rebuild the program. const prevKind = seenPackageNames.get(packageName); const newKind = fileChanged ? SeenPackageName.Modified : SeenPackageName.Exists; - if ((prevKind !== undefined && newKind === SeenPackageName.Modified) || prevKind === SeenPackageName.Modified) { + if ( + (prevKind !== undefined && newKind === SeenPackageName.Modified) + || prevKind === SeenPackageName.Modified + ) { return StructureIsReused.Not; } seenPackageNames.set(packageName, newKind); @@ -2434,7 +2840,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg structureIsReused = StructureIsReused.SafeModules; } // The `newSourceFile` object was created for the new program. - else if (!arrayIsEqualTo(oldSourceFile.libReferenceDirectives, newSourceFile.libReferenceDirectives, fileReferenceIsEqualTo)) { + else if ( + !arrayIsEqualTo( + oldSourceFile.libReferenceDirectives, + newSourceFile.libReferenceDirectives, + fileReferenceIsEqualTo, + ) + ) { // 'lib' references has changed. Matches behavior in changesAffectModuleResolution structureIsReused = StructureIsReused.SafeModules; } @@ -2444,7 +2856,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg structureIsReused = StructureIsReused.SafeModules; } // check tripleslash references - else if (!arrayIsEqualTo(oldSourceFile.referencedFiles, newSourceFile.referencedFiles, fileReferenceIsEqualTo)) { + else if ( + !arrayIsEqualTo( + oldSourceFile.referencedFiles, + newSourceFile.referencedFiles, + fileReferenceIsEqualTo, + ) + ) { // tripleslash references has changed structureIsReused = StructureIsReused.SafeModules; } @@ -2455,15 +2873,30 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // imports has changed structureIsReused = StructureIsReused.SafeModules; } - else if (!arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations, moduleNameIsEqualTo)) { + else if ( + !arrayIsEqualTo( + oldSourceFile.moduleAugmentations, + newSourceFile.moduleAugmentations, + moduleNameIsEqualTo, + ) + ) { // moduleAugmentations has changed structureIsReused = StructureIsReused.SafeModules; } - else if ((oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags)) { + else if ( + (oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) + !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) + ) { // dynamicImport has changed structureIsReused = StructureIsReused.SafeModules; } - else if (!arrayIsEqualTo(oldSourceFile.typeReferenceDirectives, newSourceFile.typeReferenceDirectives, fileReferenceIsEqualTo)) { + else if ( + !arrayIsEqualTo( + oldSourceFile.typeReferenceDirectives, + newSourceFile.typeReferenceDirectives, + fileReferenceIsEqualTo, + ) + ) { // 'types' references has changed structureIsReused = StructureIsReused.SafeModules; } @@ -2501,21 +2934,48 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const moduleNames = getModuleNames(newSourceFile); const resolutions = resolveModuleNamesReusingOldState(moduleNames, newSourceFile); // ensure that module resolution results are still correct - const resolutionsChanged = hasChangesInResolutions(moduleNames, newSourceFile, resolutions, oldSourceFile.resolvedModules, moduleResolutionIsEqualTo, moduleResolutionNameAndModeGetter); + const resolutionsChanged = hasChangesInResolutions( + moduleNames, + newSourceFile, + resolutions, + oldSourceFile.resolvedModules, + moduleResolutionIsEqualTo, + moduleResolutionNameAndModeGetter, + ); if (resolutionsChanged) { structureIsReused = StructureIsReused.SafeModules; - newSourceFile.resolvedModules = zipToModeAwareCache(newSourceFile, moduleNames, resolutions, moduleResolutionNameAndModeGetter); + newSourceFile.resolvedModules = zipToModeAwareCache( + newSourceFile, + moduleNames, + resolutions, + moduleResolutionNameAndModeGetter, + ); } else { newSourceFile.resolvedModules = oldSourceFile.resolvedModules; } const typesReferenceDirectives = newSourceFile.typeReferenceDirectives; - const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesReusingOldState(typesReferenceDirectives, newSourceFile); + const typeReferenceResolutions = resolveTypeReferenceDirectiveNamesReusingOldState( + typesReferenceDirectives, + newSourceFile, + ); // ensure that types resolutions are still correct - const typeReferenceResolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, newSourceFile, typeReferenceResolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, typeDirectiveIsEqualTo, typeReferenceResolutionNameAndModeGetter); + const typeReferenceResolutionsChanged = hasChangesInResolutions( + typesReferenceDirectives, + newSourceFile, + typeReferenceResolutions, + oldSourceFile.resolvedTypeReferenceDirectiveNames, + typeDirectiveIsEqualTo, + typeReferenceResolutionNameAndModeGetter, + ); if (typeReferenceResolutionsChanged) { structureIsReused = StructureIsReused.SafeModules; - newSourceFile.resolvedTypeReferenceDirectiveNames = zipToModeAwareCache(newSourceFile, typesReferenceDirectives, typeReferenceResolutions, typeReferenceResolutionNameAndModeGetter); + newSourceFile.resolvedTypeReferenceDirectiveNames = zipToModeAwareCache( + newSourceFile, + typesReferenceDirectives, + typeReferenceResolutions, + typeReferenceResolutionNameAndModeGetter, + ); } else { newSourceFile.resolvedTypeReferenceDirectiveNames = oldSourceFile.resolvedTypeReferenceDirectiveNames; @@ -2530,8 +2990,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return StructureIsReused.SafeModules; } - if (oldProgram.resolvedLibReferences && - forEachEntry(oldProgram.resolvedLibReferences, (resolution, libFileName) => pathForLibFileWorker(libFileName).actual !== resolution.actual)) { + if ( + oldProgram.resolvedLibReferences + && forEachEntry( + oldProgram.resolvedLibReferences, + (resolution, libFileName) => pathForLibFileWorker(libFileName).actual !== resolution.actual, + ) + ) { return StructureIsReused.SafeModules; } @@ -2540,7 +3005,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } else { automaticTypeDirectiveNames = getAutomaticTypeDirectiveNames(options, host); - if (!arrayIsEqualTo(oldProgram.getAutomaticTypeDirectiveNames(), automaticTypeDirectiveNames)) return StructureIsReused.SafeModules; + if (!arrayIsEqualTo(oldProgram.getAutomaticTypeDirectiveNames(), automaticTypeDirectiveNames)) { + return StructureIsReused.SafeModules; + } } missingFilePaths = oldProgram.getMissingFilePaths(); @@ -2623,7 +3090,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg writeByteOrderMark: boolean, onError?: (message: string) => void, sourceFiles?: readonly SourceFile[], - data?: WriteFileCallbackData + data?: WriteFileCallbackData, ) { host.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data); } @@ -2638,7 +3105,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg /*targetSourceFile*/ undefined, /*transformers*/ noTransformers, /*emitOnly*/ false, - /*onlyBuildInfo*/ true + /*onlyBuildInfo*/ true, ); performance.mark("afterEmit"); @@ -2687,12 +3154,16 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // If '--lib' is not specified, include default library file according to '--target' // otherwise, using options specified in '--lib' instead of '--target' default library file - const equalityComparer = host.useCaseSensitiveFileNames() ? equateStringsCaseSensitive : equateStringsCaseInsensitive; + const equalityComparer = host.useCaseSensitiveFileNames() ? equateStringsCaseSensitive + : equateStringsCaseInsensitive; if (!options.lib) { return equalityComparer(file.fileName, getDefaultLibraryFileName()); } else { - return some(options.lib, libFileName => equalityComparer(file.fileName, resolvedLibReferences!.get(libFileName)!.actual)); + return some( + options.lib, + libFileName => equalityComparer(file.fileName, resolvedLibReferences!.get(libFileName)!.actual), + ); } } @@ -2700,9 +3171,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return typeChecker || (typeChecker = createTypeChecker(program)); } - function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnly?: boolean | EmitOnly, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult { + function emit( + sourceFile?: SourceFile, + writeFileCallback?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnly?: boolean | EmitOnly, + transformers?: CustomTransformers, + forceDtsEmit?: boolean, + ): EmitResult { tracing?.push(tracing.Phase.Emit, "emit", { path: sourceFile?.path }, /*separateBeginAndEnd*/ true); - const result = runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnly, transformers, forceDtsEmit)); + const result = runWithCancellationToken(() => + emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnly, transformers, forceDtsEmit) + ); tracing?.pop(); return result; } @@ -2711,7 +3191,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return hasEmitBlockingDiagnostics.has(toPath(emitFileName)); } - function emitWorker(program: Program, sourceFile: SourceFile | undefined, writeFileCallback: WriteFileCallback | undefined, cancellationToken: CancellationToken | undefined, emitOnly?: boolean | EmitOnly, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult { + function emitWorker( + program: Program, + sourceFile: SourceFile | undefined, + writeFileCallback: WriteFileCallback | undefined, + cancellationToken: CancellationToken | undefined, + emitOnly?: boolean | EmitOnly, + customTransformers?: CustomTransformers, + forceDtsEmit?: boolean, + ): EmitResult { if (!forceDtsEmit) { const result = handleNoEmitOptions(program, sourceFile, writeFileCallback, cancellationToken); if (result) return result; @@ -2725,7 +3213,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // This is because in the -out scenario all files need to be emitted, and therefore all // files need to be type checked. And the way to specify that all files need to be type // checked is to not pass the file to getEmitResolver. - const emitResolver = getTypeChecker().getEmitResolver(outFile(options) ? undefined : sourceFile, cancellationToken); + const emitResolver = getTypeChecker().getEmitResolver( + outFile(options) ? undefined : sourceFile, + cancellationToken, + ); performance.mark("beforeEmit"); @@ -2736,7 +3227,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg getTransformers(options, customTransformers, emitOnly), emitOnly, /*onlyBuildInfo*/ false, - forceDtsEmit + forceDtsEmit, ); performance.mark("afterEmit"); @@ -2755,7 +3246,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function getDiagnosticsHelper( sourceFile: SourceFile | undefined, getDiagnostics: (sourceFile: SourceFile, cancellationToken: CancellationToken | undefined) => readonly T[], - cancellationToken: CancellationToken | undefined): readonly T[] { + cancellationToken: CancellationToken | undefined, + ): readonly T[] { if (sourceFile) { return sortAndDeduplicateDiagnostics(getDiagnostics(sourceFile, cancellationToken)); } @@ -2767,21 +3259,30 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg })); } - function getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] { + function getSyntacticDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[] { return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile, cancellationToken); } - function getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + function getSemanticDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile, cancellationToken); } function getCachedSemanticDiagnostics(sourceFile?: SourceFile): readonly Diagnostic[] | undefined { - return sourceFile + return sourceFile ? cachedBindAndCheckDiagnosticsForFile.perFile?.get(sourceFile.path) : cachedBindAndCheckDiagnosticsForFile.allDiagnostics; } - function getBindAndCheckDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[] { + function getBindAndCheckDiagnostics( + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[] { return getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken); } @@ -2795,10 +3296,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return programDiagnosticsInFile; } - return getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, programDiagnosticsInFile).diagnostics; + return getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, programDiagnosticsInFile) + .diagnostics; } - function getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[] { + 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 || outFile(options)) { @@ -2836,18 +3341,32 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function getSemanticDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] { + function getSemanticDiagnosticsForFile( + sourceFile: SourceFile, + cancellationToken: CancellationToken | undefined, + ): readonly Diagnostic[] { return concatenate( filterSemanticDiagnostics(getBindAndCheckDiagnosticsForFile(sourceFile, cancellationToken), options), - getProgramDiagnostics(sourceFile) + getProgramDiagnostics(sourceFile), ); } - function getBindAndCheckDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] { - return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedBindAndCheckDiagnosticsForFile, getBindAndCheckDiagnosticsForFileNoCache); + function getBindAndCheckDiagnosticsForFile( + sourceFile: SourceFile, + cancellationToken: CancellationToken | undefined, + ): readonly Diagnostic[] { + return getAndCacheDiagnostics( + sourceFile, + cancellationToken, + cachedBindAndCheckDiagnosticsForFile, + getBindAndCheckDiagnosticsForFileNoCache, + ); } - function getBindAndCheckDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly Diagnostic[] { + function getBindAndCheckDiagnosticsForFileNoCache( + sourceFile: SourceFile, + cancellationToken: CancellationToken | undefined, + ): readonly Diagnostic[] { return runWithCancellationToken(() => { if (skipTypeChecking(sourceFile, options, program)) { return emptyArray; @@ -2866,29 +3385,53 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // - plain JS: .js files with no // ts-check and checkJs: undefined // - check JS: .js files with either // ts-check or checkJs: true // - external: files that are added by plugins - const includeBindAndCheckDiagnostics = !isTsNoCheck && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX - || sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred); - let bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray; - let checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray; + const includeBindAndCheckDiagnostics = !isTsNoCheck + && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX + || sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs + || sourceFile.scriptKind === ScriptKind.Deferred); + let bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics + : emptyArray; + let checkDiagnostics = includeBindAndCheckDiagnostics + ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray; if (isPlainJs) { bindDiagnostics = filter(bindDiagnostics, d => plainJSErrors.has(d.code)); checkDiagnostics = filter(checkDiagnostics, d => plainJSErrors.has(d.code)); } // skip ts-expect-error errors in plain JS files, and skip JSDoc errors except in checked JS - return getMergedBindAndCheckDiagnostics(sourceFile, includeBindAndCheckDiagnostics && !isPlainJs, bindDiagnostics, checkDiagnostics, isCheckJs ? sourceFile.jsDocDiagnostics : undefined); + return getMergedBindAndCheckDiagnostics( + sourceFile, + includeBindAndCheckDiagnostics && !isPlainJs, + bindDiagnostics, + checkDiagnostics, + isCheckJs ? sourceFile.jsDocDiagnostics : undefined, + ); }); } - function getMergedBindAndCheckDiagnostics(sourceFile: SourceFile, includeBindAndCheckDiagnostics: boolean, ...allDiagnostics: (readonly Diagnostic[] | undefined)[]) { + function getMergedBindAndCheckDiagnostics( + sourceFile: SourceFile, + includeBindAndCheckDiagnostics: boolean, + ...allDiagnostics: (readonly Diagnostic[] | undefined)[] + ) { const flatDiagnostics = flatten(allDiagnostics); if (!includeBindAndCheckDiagnostics || !sourceFile.commentDirectives?.length) { return flatDiagnostics; } - const { diagnostics, directives } = getDiagnosticsWithPrecedingDirectives(sourceFile, sourceFile.commentDirectives, flatDiagnostics); + const { diagnostics, directives } = getDiagnosticsWithPrecedingDirectives( + sourceFile, + sourceFile.commentDirectives, + flatDiagnostics, + ); for (const errorExpectation of directives.getUnusedExpectations()) { - diagnostics.push(createDiagnosticForRange(sourceFile, errorExpectation.range, Diagnostics.Unused_ts_expect_error_directive)); + diagnostics.push( + createDiagnosticForRange( + sourceFile, + errorExpectation.range, + Diagnostics.Unused_ts_expect_error_directive, + ), + ); } return diagnostics; @@ -2898,16 +3441,25 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg * Creates a map of comment directives along with the diagnostics immediately preceded by one of them. * Comments that match to any of those diagnostics are marked as used. */ - function getDiagnosticsWithPrecedingDirectives(sourceFile: SourceFile, commentDirectives: CommentDirective[], flatDiagnostics: Diagnostic[]) { + function getDiagnosticsWithPrecedingDirectives( + sourceFile: SourceFile, + commentDirectives: CommentDirective[], + flatDiagnostics: Diagnostic[], + ) { // Diagnostics are only reported if there is no comment directive preceding them // This will modify the directives map by marking "used" ones with a corresponding diagnostic const directives = createCommentDirectivesMap(sourceFile, commentDirectives); - const diagnostics = flatDiagnostics.filter(diagnostic => markPrecedingCommentDirectiveLine(diagnostic, directives) === -1); + const diagnostics = flatDiagnostics.filter(diagnostic => + markPrecedingCommentDirectiveLine(diagnostic, directives) === -1 + ); return { diagnostics, directives }; } - function getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] { + function getSuggestionDiagnostics( + sourceFile: SourceFile, + cancellationToken: CancellationToken, + ): readonly DiagnosticWithLocation[] { return runWithCancellationToken(() => { return getTypeChecker().getSuggestionDiagnostics(sourceFile, cancellationToken); }); @@ -2959,8 +3511,17 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodDeclaration: - if ((parent as ParameterDeclaration | PropertyDeclaration | MethodDeclaration).questionToken === node) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, "?")); + if ( + (parent as ParameterDeclaration | PropertyDeclaration | MethodDeclaration).questionToken + === node + ) { + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, + "?", + ), + ); return "skip"; } // falls through @@ -2973,8 +3534,19 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg case SyntaxKind.ArrowFunction: case SyntaxKind.VariableDeclaration: // type annotation - if ((parent as FunctionLikeDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration).type === node) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files)); + if ( + (parent as + | FunctionLikeDeclaration + | VariableDeclaration + | ParameterDeclaration + | PropertyDeclaration).type === node + ) { + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Type_annotations_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } } @@ -2982,72 +3554,143 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg switch (node.kind) { case SyntaxKind.ImportClause: if ((node as ImportClause).isTypeOnly) { - diagnostics.push(createDiagnosticForNode(parent, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "import type")); + diagnostics.push( + createDiagnosticForNode( + parent, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + "import type", + ), + ); return "skip"; } break; case SyntaxKind.ExportDeclaration: if ((node as ExportDeclaration).isTypeOnly) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, "export type")); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + "export type", + ), + ); return "skip"; } break; case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: if ((node as ImportOrExportSpecifier).isTypeOnly) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, isImportSpecifier(node) ? "import...type" : "export...type")); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + isImportSpecifier(node) ? "import...type" : "export...type", + ), + ); return "skip"; } break; case SyntaxKind.ImportEqualsDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_TypeScript_files), + ); return "skip"; case SyntaxKind.ExportAssignment: if ((node as ExportAssignment).isExportEquals) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_TypeScript_files), + ); return "skip"; } break; case SyntaxKind.HeritageClause: const heritageClause = node as HeritageClause; if (heritageClause.token === SyntaxKind.ImplementsKeyword) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.implements_clauses_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } break; case SyntaxKind.InterfaceDeclaration: const interfaceKeyword = tokenToString(SyntaxKind.InterfaceKeyword); Debug.assertIsDefined(interfaceKeyword); - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, interfaceKeyword)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + interfaceKeyword, + ), + ); return "skip"; case SyntaxKind.ModuleDeclaration: - const moduleKeyword = node.flags & NodeFlags.Namespace ? tokenToString(SyntaxKind.NamespaceKeyword) : tokenToString(SyntaxKind.ModuleKeyword); + const moduleKeyword = node.flags & NodeFlags.Namespace + ? tokenToString(SyntaxKind.NamespaceKeyword) : tokenToString(SyntaxKind.ModuleKeyword); Debug.assertIsDefined(moduleKeyword); - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, moduleKeyword)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + moduleKeyword, + ), + ); return "skip"; case SyntaxKind.TypeAliasDeclaration: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Type_aliases_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; case SyntaxKind.Constructor: case SyntaxKind.MethodDeclaration: case SyntaxKind.FunctionDeclaration: if (!(node as FunctionLikeDeclaration).body) { - diagnostics.push(createDiagnosticForNode(node, Diagnostics.Signature_declarations_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Signature_declarations_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } return; case SyntaxKind.EnumDeclaration: const enumKeyword = Debug.checkDefined(tokenToString(SyntaxKind.EnumKeyword)); - diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, enumKeyword)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics._0_declarations_can_only_be_used_in_TypeScript_files, + enumKeyword, + ), + ); return "skip"; case SyntaxKind.NonNullExpression: - diagnostics.push(createDiagnosticForNode(node, Diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + node, + Diagnostics.Non_null_assertions_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; case SyntaxKind.AsExpression: - diagnostics.push(createDiagnosticForNode((node as AsExpression).type, Diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + (node as AsExpression).type, + Diagnostics.Type_assertion_expressions_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; case SyntaxKind.SatisfiesExpression: - diagnostics.push(createDiagnosticForNode((node as SatisfiesExpression).type, Diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNode( + (node as SatisfiesExpression).type, + Diagnostics.Type_satisfaction_expressions_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; case SyntaxKind.TypeAssertionExpression: Debug.fail(); // Won't parse these in a JS file anyway, as they are interpreted as JSX. @@ -3067,22 +3710,45 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (decoratorIndex >= 0) { if (isParameter(parent) && !options.experimentalDecorators) { // report illegall decorator on parameter - diagnostics.push(createDiagnosticForNode(parent.modifiers[decoratorIndex], Diagnostics.Decorators_are_not_valid_here)); + diagnostics.push( + createDiagnosticForNode( + parent.modifiers[decoratorIndex], + Diagnostics.Decorators_are_not_valid_here, + ), + ); } else if (isClassDeclaration(parent)) { const exportIndex = findIndex(parent.modifiers, isExportModifier); if (exportIndex >= 0) { const defaultIndex = findIndex(parent.modifiers, isDefaultModifier); - if (decoratorIndex > exportIndex && defaultIndex >= 0 && decoratorIndex < defaultIndex) { + if ( + decoratorIndex > exportIndex && defaultIndex >= 0 && decoratorIndex < defaultIndex + ) { // report illegal decorator between `export` and `default` - diagnostics.push(createDiagnosticForNode(parent.modifiers[decoratorIndex], Diagnostics.Decorators_are_not_valid_here)); + diagnostics.push( + createDiagnosticForNode( + parent.modifiers[decoratorIndex], + Diagnostics.Decorators_are_not_valid_here, + ), + ); } else if (exportIndex >= 0 && decoratorIndex < exportIndex) { - const trailingDecoratorIndex = findIndex(parent.modifiers, isDecorator, exportIndex); + const trailingDecoratorIndex = findIndex( + parent.modifiers, + isDecorator, + exportIndex, + ); if (trailingDecoratorIndex >= 0) { diagnostics.push(addRelatedInfo( - createDiagnosticForNode(parent.modifiers[trailingDecoratorIndex], Diagnostics.Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear_before_export), - createDiagnosticForNode(parent.modifiers[decoratorIndex], Diagnostics.Decorator_used_before_export_here), + createDiagnosticForNode( + parent.modifiers[trailingDecoratorIndex], + Diagnostics + .Decorators_may_not_appear_after_export_or_export_default_if_they_also_appear_before_export, + ), + createDiagnosticForNode( + parent.modifiers[decoratorIndex], + Diagnostics.Decorator_used_before_export_here, + ), )); } } @@ -3103,7 +3769,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg case SyntaxKind.ArrowFunction: // Check type parameters if (nodes === (parent as DeclarationWithTypeParameterChildren).typeParameters) { - diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNodeArray( + nodes, + Diagnostics.Type_parameter_declarations_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } // falls through @@ -3111,7 +3782,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg case SyntaxKind.VariableStatement: // Check modifiers if (nodes === (parent as VariableStatement).modifiers) { - checkModifiers((parent as VariableStatement).modifiers!, parent.kind === SyntaxKind.VariableStatement); + checkModifiers( + (parent as VariableStatement).modifiers!, + parent.kind === SyntaxKind.VariableStatement, + ); return "skip"; } break; @@ -3119,10 +3793,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // Check modifiers of property declaration if (nodes === (parent as PropertyDeclaration).modifiers) { for (const modifier of nodes as NodeArray) { - if (isModifier(modifier) + if ( + isModifier(modifier) && modifier.kind !== SyntaxKind.StaticKeyword - && modifier.kind !== SyntaxKind.AccessorKeyword) { - diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind))); + && modifier.kind !== SyntaxKind.AccessorKeyword + ) { + diagnostics.push( + createDiagnosticForNode( + modifier, + Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, + tokenToString(modifier.kind), + ), + ); } } return "skip"; @@ -3131,7 +3813,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg case SyntaxKind.Parameter: // Check modifiers of parameter declaration if (nodes === (parent as ParameterDeclaration).modifiers && some(nodes, isModifier)) { - diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNodeArray( + nodes, + Diagnostics.Parameter_modifiers_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } break; @@ -3143,7 +3830,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg case SyntaxKind.TaggedTemplateExpression: // Check type arguments if (nodes === (parent as NodeWithTypeArguments).typeArguments) { - diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files)); + diagnostics.push( + createDiagnosticForNodeArray( + nodes, + Diagnostics.Type_arguments_can_only_be_used_in_TypeScript_files, + ), + ); return "skip"; } break; @@ -3168,7 +3860,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg case SyntaxKind.OverrideKeyword: case SyntaxKind.InKeyword: case SyntaxKind.OutKeyword: - diagnostics.push(createDiagnosticForNode(modifier, Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, tokenToString(modifier.kind))); + diagnostics.push( + createDiagnosticForNode( + modifier, + Diagnostics.The_0_modifier_can_only_be_used_in_TypeScript_files, + tokenToString(modifier.kind), + ), + ); break; // These are all legal modifiers. @@ -3180,24 +3878,43 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function createDiagnosticForNodeArray(nodes: NodeArray, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { + function createDiagnosticForNodeArray( + nodes: NodeArray, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): DiagnosticWithLocation { const start = nodes.pos; return createFileDiagnostic(sourceFile, start, nodes.end - start, message, ...args); } // Since these are syntactic diagnostics, parent might not have been set // this means the sourceFile cannot be infered from the node - function createDiagnosticForNode(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { + function createDiagnosticForNode( + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): DiagnosticWithLocation { return createDiagnosticForNodeInSourceFile(sourceFile, node, message, ...args); } }); } - function getDeclarationDiagnosticsWorker(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] { - return getAndCacheDiagnostics(sourceFile, cancellationToken, cachedDeclarationDiagnosticsForFile, getDeclarationDiagnosticsForFileNoCache); + function getDeclarationDiagnosticsWorker( + sourceFile: SourceFile | undefined, + cancellationToken: CancellationToken | undefined, + ): readonly DiagnosticWithLocation[] { + return getAndCacheDiagnostics( + sourceFile, + cancellationToken, + cachedDeclarationDiagnosticsForFile, + getDeclarationDiagnosticsForFileNoCache, + ); } - function getDeclarationDiagnosticsForFileNoCache(sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] { + function getDeclarationDiagnosticsForFileNoCache( + sourceFile: SourceFile | undefined, + 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. @@ -3211,7 +3928,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg cache: DiagnosticCache, getDiagnostics: (sourceFile: T, cancellationToken: CancellationToken | undefined) => readonly U[], ): readonly U[] { - const cachedResult = sourceFile ? cache.perFile?.get(sourceFile.path) : cache.allDiagnostics; @@ -3229,14 +3945,17 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return result; } - function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] { + function getDeclarationDiagnosticsForFile( + sourceFile: SourceFile, + cancellationToken: CancellationToken | undefined, + ): readonly DiagnosticWithLocation[] { return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken); } function getOptionsDiagnostics(): SortedReadonlyArray { return sortAndDeduplicateDiagnostics(concatenate( programDiagnostics.getGlobalDiagnostics(), - getOptionsDiagnosticsOfConfigFile() + getOptionsDiagnosticsOfConfigFile(), )); } @@ -3250,14 +3969,20 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function getGlobalDiagnostics(): SortedReadonlyArray { - return rootNames.length ? sortAndDeduplicateDiagnostics(getTypeChecker().getGlobalDiagnostics().slice()) : emptyArray as any as SortedReadonlyArray; + return rootNames.length ? sortAndDeduplicateDiagnostics(getTypeChecker().getGlobalDiagnostics().slice()) + : emptyArray as any as SortedReadonlyArray; } function getConfigFileParsingDiagnostics(): readonly Diagnostic[] { return configFileParsingDiagnostics || emptyArray; } - function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason) { + function processRootFile( + fileName: string, + isDefaultLib: boolean, + ignoreNoDefaultLib: boolean, + reason: FileIncludeReason, + ) { processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined, reason); } @@ -3273,7 +3998,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function createSyntheticImport(text: string, file: SourceFile) { const externalHelpersModuleReference = factory.createStringLiteral(text); - const importDecl = factory.createImportDeclaration(/*modifiers*/ undefined, /*importClause*/ undefined, externalHelpersModuleReference, /*assertClause*/ undefined); + const importDecl = factory.createImportDeclaration( + /*modifiers*/ undefined, + /*importClause*/ undefined, + externalHelpersModuleReference, + /*assertClause*/ undefined, + ); addInternalEmitFlags(importDecl, InternalEmitFlags.NeverApplyImportHelper); setParent(externalHelpersModuleReference, importDecl); setParent(importDecl, file); @@ -3299,8 +4029,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // If we are importing helpers, we need to add a synthetic reference to resolve the // helpers library. - if ((getIsolatedModules(options) || isExternalModuleFile) - && !file.isDeclarationFile) { + if ( + (getIsolatedModules(options) || isExternalModuleFile) + && !file.isDeclarationFile + ) { if (options.importHelpers) { // synthesize 'import "tslib"' declaration imports = [createSyntheticImport(externalHelpersModuleNameText, file)]; @@ -3333,7 +4065,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // TypeScript 1.0 spec (April 2014): 12.1.6 // An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules // only through top - level external module names. Relative external module names are not permitted. - if (moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text && (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text))) { + if ( + moduleNameExpr && isStringLiteral(moduleNameExpr) && moduleNameExpr.text + && (!inAmbientModule || !isExternalModuleNameRelative(moduleNameExpr.text)) + ) { setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here imports = append(imports, moduleNameExpr); if (!usesUriStyleNodeCoreModules && currentNodeModulesDepth === 0 && !file.isDeclarationFile) { @@ -3342,7 +4077,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } else if (isModuleDeclaration(node)) { - if (isAmbientModule(node) && (inAmbientModule || hasSyntacticModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile)) { + if ( + isAmbientModule(node) + && (inAmbientModule || hasSyntacticModifier(node, ModifierFlags.Ambient) || file.isDeclarationFile) + ) { (node.name as Mutable).parent = node; const nameText = getTextOfIdentifierOrLiteral(node.name); // Ambient module declarations can be interpreted as augmentations for some existing external modules. @@ -3399,12 +4137,16 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function getNodeAtPosition(sourceFile: SourceFile, position: number): Node { let current: Node = sourceFile; const getContainingChild = (child: Node) => { - if (child.pos <= position && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken)))) { + if ( + child.pos <= position + && (position < child.end || (position === child.end && (child.kind === SyntaxKind.EndOfFileToken))) + ) { return child; } }; while (true) { - const child = isJavaScriptFile && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) || forEachChild(current, getContainingChild); + const child = isJavaScriptFile && hasJSDocNodes(current) && forEach(current.jsDoc, getContainingChild) + || forEachChild(current, getContainingChild); if (!child) { return current; } @@ -3420,25 +4162,44 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } /** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */ - function getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined { - return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), getSourceFile); + function getSourceFileFromReference( + referencingFile: SourceFile | UnparsedSource, + ref: FileReference, + ): SourceFile | undefined { + return getSourceFileFromReferenceWorker( + resolveTripleslashReference(ref.fileName, referencingFile.fileName), + getSourceFile, + ); } function getSourceFileFromReferenceWorker( fileName: string, getSourceFile: (fileName: string) => SourceFile | undefined, fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void, - reason?: FileIncludeReason): SourceFile | undefined { - + reason?: FileIncludeReason, + ): SourceFile | undefined { if (hasExtension(fileName)) { const canonicalFileName = host.getCanonicalFileName(fileName); - if (!options.allowNonTsExtensions && !forEach(flatten(supportedExtensionsWithJsonIfResolveJsonModule), extension => fileExtensionIs(canonicalFileName, extension))) { + if ( + !options.allowNonTsExtensions + && !forEach( + flatten(supportedExtensionsWithJsonIfResolveJsonModule), + extension => fileExtensionIs(canonicalFileName, extension), + ) + ) { if (fail) { if (hasJSFileExtension(canonicalFileName)) { - fail(Diagnostics.File_0_is_a_JavaScript_file_Did_you_mean_to_enable_the_allowJs_option, fileName); + fail( + Diagnostics.File_0_is_a_JavaScript_file_Did_you_mean_to_enable_the_allowJs_option, + fileName, + ); } else { - fail(Diagnostics.File_0_has_an_unsupported_extension_The_only_supported_extensions_are_1, fileName, "'" + flatten(supportedExtensions).join("', '") + "'"); + fail( + Diagnostics.File_0_has_an_unsupported_extension_The_only_supported_extensions_are_1, + fileName, + "'" + flatten(supportedExtensions).join("', '") + "'", + ); } } return undefined; @@ -3455,7 +4216,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg fail(Diagnostics.File_0_not_found, fileName); } } - else if (isReferencedFile(reason) && canonicalFileName === host.getCanonicalFileName(getSourceFileByPath(reason.file)!.fileName)) { + else if ( + isReferencedFile(reason) + && canonicalFileName === host.getCanonicalFileName(getSourceFileByPath(reason.file)!.fileName) + ) { fail(Diagnostics.A_file_cannot_have_a_reference_to_itself); } } @@ -3471,50 +4235,102 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } // Only try adding extensions from the first supported group (which should be .ts/.tsx/.d.ts) - const sourceFileWithAddedExtension = forEach(supportedExtensions[0], extension => getSourceFile(fileName + extension)); - if (fail && !sourceFileWithAddedExtension) fail(Diagnostics.Could_not_resolve_the_path_0_with_the_extensions_Colon_1, fileName, "'" + flatten(supportedExtensions).join("', '") + "'"); + const sourceFileWithAddedExtension = forEach( + supportedExtensions[0], + extension => getSourceFile(fileName + extension), + ); + if (fail && !sourceFileWithAddedExtension) { + fail( + Diagnostics.Could_not_resolve_the_path_0_with_the_extensions_Colon_1, + fileName, + "'" + flatten(supportedExtensions).join("', '") + "'", + ); + } return sourceFileWithAddedExtension; } } /** This has side effects through `findSourceFile`. */ - function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, reason: FileIncludeReason): void { + function processSourceFile( + fileName: string, + isDefaultLib: boolean, + ignoreNoDefaultLib: boolean, + packageId: PackageId | undefined, + reason: FileIncludeReason, + ): void { getSourceFileFromReferenceWorker( fileName, fileName => findSourceFile(fileName, isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217 - (diagnostic, ...args) => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args), - reason + (diagnostic, ...args) => + addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args), + reason, ); } function processProjectReferenceFile(fileName: string, reason: ProjectReferenceFile) { - return processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, reason); + return processSourceFile( + fileName, + /*isDefaultLib*/ false, + /*ignoreNoDefaultLib*/ false, + /*packageId*/ undefined, + reason, + ); } - function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFile: SourceFile, reason: FileIncludeReason): void { - const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) && some(fileReasons.get(existingFile.path), isReferencedFile); + function reportFileNamesDifferOnlyInCasingError( + fileName: string, + existingFile: SourceFile, + reason: FileIncludeReason, + ): void { + const hasExistingReasonToReportErrorOn = !isReferencedFile(reason) + && some(fileReasons.get(existingFile.path), isReferencedFile); if (hasExistingReasonToReportErrorOn) { - addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, [existingFile.fileName, fileName]); + addFilePreprocessingFileExplainingDiagnostic( + existingFile, + reason, + Diagnostics.Already_included_file_name_0_differs_from_file_name_1_only_in_casing, + [existingFile.fileName, fileName], + ); } else { - addFilePreprocessingFileExplainingDiagnostic(existingFile, reason, Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, [fileName, existingFile.fileName]); + addFilePreprocessingFileExplainingDiagnostic( + existingFile, + reason, + Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, + [fileName, existingFile.fileName], + ); } } - function createRedirectedSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path, resolvedPath: Path, originalFileName: string, sourceFileOptions: CreateSourceFileOptions): SourceFile { + function createRedirectedSourceFile( + redirectTarget: SourceFile, + unredirected: SourceFile, + fileName: string, + path: Path, + resolvedPath: Path, + originalFileName: string, + sourceFileOptions: CreateSourceFileOptions, + ): SourceFile { const redirect = parseNodeFactory.createRedirectedSourceFile({ redirectTarget, unredirected }); redirect.fileName = fileName; redirect.path = path; redirect.resolvedPath = resolvedPath; redirect.originalFileName = originalFileName; - redirect.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; + redirect.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length + ? sourceFileOptions.packageJsonLocations : undefined; redirect.packageJsonScope = sourceFileOptions.packageJsonScope; sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0); return redirect; } // Get source file from normalized fileName - function findSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined { + function findSourceFile( + fileName: string, + isDefaultLib: boolean, + ignoreNoDefaultLib: boolean, + reason: FileIncludeReason, + packageId: PackageId | undefined, + ): SourceFile | undefined { tracing?.push(tracing.Phase.Program, "findSourceFile", { fileName, isDefaultLib: isDefaultLib || undefined, @@ -3525,19 +4341,35 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return result; } - function getCreateSourceFileOptions(fileName: string, moduleResolutionCache: ModuleResolutionCache | undefined, host: CompilerHost, options: CompilerOptions): CreateSourceFileOptions { + function getCreateSourceFileOptions( + fileName: string, + moduleResolutionCache: ModuleResolutionCache | undefined, + host: CompilerHost, + options: CompilerOptions, + ): CreateSourceFileOptions { // It's a _little odd_ that we can't set `impliedNodeFormat` until the program step - but it's the first and only time we have a resolution cache // and a freshly made source file node on hand at the same time, and we need both to set the field. Persisting the resolution cache all the way // to the check and emit steps would be bad - so we much prefer detecting and storing the format information on the source file node upfront. - const result = getImpliedNodeFormatForFileWorker(getNormalizedAbsolutePath(fileName, currentDirectory), moduleResolutionCache?.getPackageJsonInfoCache(), host, options); + const result = getImpliedNodeFormatForFileWorker( + getNormalizedAbsolutePath(fileName, currentDirectory), + moduleResolutionCache?.getPackageJsonInfoCache(), + host, + options, + ); const languageVersion = getEmitScriptTarget(options); const setExternalModuleIndicator = getSetExternalModuleIndicator(options); - return typeof result === "object" ? - { ...result, languageVersion, setExternalModuleIndicator } : - { languageVersion, impliedNodeFormat: result, setExternalModuleIndicator }; + return typeof result === "object" + ? { ...result, languageVersion, setExternalModuleIndicator } + : { languageVersion, impliedNodeFormat: result, setExternalModuleIndicator }; } - function findSourceFileWorker(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined { + function findSourceFileWorker( + fileName: string, + isDefaultLib: boolean, + ignoreNoDefaultLib: boolean, + reason: FileIncludeReason, + packageId: PackageId | undefined, + ): SourceFile | undefined { const path = toPath(fileName); if (useSourceOfProjectReferenceRedirect) { let source = getSourceOfProjectReferenceRedirect(path); @@ -3545,18 +4377,20 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // but the resolved real path may be the .d.ts from project reference // Note:: Currently we try the real path only if the // file is from node_modules to avoid having to run real path on all file paths - if (!source && - host.realpath && - options.preserveSymlinks && - isDeclarationFileName(fileName) && - stringContains(fileName, nodeModulesPathPart)) { + if ( + !source + && host.realpath + && options.preserveSymlinks + && isDeclarationFileName(fileName) + && stringContains(fileName, nodeModulesPathPart) + ) { const realPath = toPath(host.realpath(fileName)); if (realPath !== path) source = getSourceOfProjectReferenceRedirect(realPath); } if (source) { - const file = isString(source) ? - findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId) : - undefined; + const file = isString(source) + ? findSourceFile(source, isDefaultLib, ignoreNoDefaultLib, reason, packageId) + : undefined; if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined); return file; } @@ -3631,7 +4465,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const file = host.getSourceFile( fileName, sourceFileOptions, - hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]), + hostErrorMessage => + addFilePreprocessingFileExplainingDiagnostic( + /*file*/ undefined, + reason, + Diagnostics.Cannot_read_file_0_Colon_1, + [fileName, hostErrorMessage], + ), shouldCreateNewSourceFile, ); @@ -3641,7 +4481,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (fileFromPackageId) { // Some other SourceFile already exists with this package name and version. // Instead of creating a duplicate, just redirect to the existing one. - const dupFile = createRedirectedSourceFile(fileFromPackageId, file!, fileName, path, toPath(fileName), originalFileName, sourceFileOptions); + const dupFile = createRedirectedSourceFile( + fileFromPackageId, + file!, + fileName, + path, + toPath(fileName), + originalFileName, + sourceFileOptions, + ); redirectTargetsMap.add(fileFromPackageId.path, fileName); addFileToFilesByName(dupFile, path, redirectedPath); addFileIncludeReason(dupFile, reason); @@ -3663,7 +4511,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg file.path = path; file.resolvedPath = toPath(fileName); file.originalFileName = originalFileName; - file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length ? sourceFileOptions.packageJsonLocations : undefined; + file.packageJsonLocations = sourceFileOptions.packageJsonLocations?.length + ? sourceFileOptions.packageJsonLocations : undefined; file.packageJsonScope = sourceFileOptions.packageJsonScope; addFileIncludeReason(file, reason); @@ -3689,7 +4538,6 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg processLibReferenceDirectives(file); } - // always process imported modules to record module name resolutions processImportedModules(file); @@ -3724,7 +4572,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function getProjectReferenceRedirectProject(fileName: string) { // Ignore dts or any json files - if (!resolvedProjectReferences || !resolvedProjectReferences.length || isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json)) { + if ( + !resolvedProjectReferences || !resolvedProjectReferences.length || isDeclarationFileName(fileName) + || fileExtensionIs(fileName, Extension.Json) + ) { return undefined; } @@ -3733,12 +4584,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return getResolvedProjectReferenceToRedirect(fileName); } - function getProjectReferenceOutputName(referencedProject: ResolvedProjectReference, fileName: string) { const out = outFile(referencedProject.commandLine.options); - return out ? - changeExtension(out, Extension.Dts) : - getOutputDeclarationFileName(fileName, referencedProject.commandLine, !host.useCaseSensitiveFileNames()); + return out + ? changeExtension(out, Extension.Dts) + : getOutputDeclarationFileName(fileName, referencedProject.commandLine, !host.useCaseSensitiveFileNames()); } /** @@ -3751,7 +4601,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // not input file from the referenced project, ignore if (toPath(options.configFilePath!) !== referencedProject.sourceFile.path) { referencedProject.commandLine.fileNames.forEach(f => - mapFromFileToProjectReferenceRedirects!.set(toPath(f), referencedProject.sourceFile.path)); + mapFromFileToProjectReferenceRedirects!.set(toPath(f), referencedProject.sourceFile.path) + ); } }); } @@ -3761,7 +4612,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function forEachResolvedProjectReference( - cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined + cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, ): T | undefined { return ts_forEachResolvedProjectReference(resolvedProjectReferences, cb); } @@ -3778,10 +4629,17 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), true); } else { - const getCommonSourceDirectory = memoize(() => getCommonSourceDirectoryOfConfig(resolvedRef.commandLine, !host.useCaseSensitiveFileNames())); + const getCommonSourceDirectory = memoize(() => + getCommonSourceDirectoryOfConfig(resolvedRef.commandLine, !host.useCaseSensitiveFileNames()) + ); forEach(resolvedRef.commandLine.fileNames, fileName => { if (!isDeclarationFileName(fileName) && !fileExtensionIs(fileName, Extension.Json)) { - const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, !host.useCaseSensitiveFileNames(), getCommonSourceDirectory); + const outputDts = getOutputDeclarationFileName( + fileName, + resolvedRef.commandLine, + !host.useCaseSensitiveFileNames(), + getCommonSourceDirectory, + ); mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName); } }); @@ -3810,7 +4668,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg isDefaultLib, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, - { kind: FileIncludeKind.ReferenceFile, file: file.path, index, } + { kind: FileIncludeKind.ReferenceFile, file: file.path, index }, ); }); } @@ -3828,17 +4686,34 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const resolvedTypeReferenceDirective = resolutions[index]; // store resolved type directive on the file const fileName = toFileNameLowerCase(ref.fileName); - setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective, getModeForFileReference(ref, file.impliedNodeFormat)); + setResolvedTypeReferenceDirective( + file, + fileName, + resolvedTypeReferenceDirective, + getModeForFileReference(ref, file.impliedNodeFormat), + ); const mode = ref.resolutionMode || file.impliedNodeFormat; - if (mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext) { + if ( + mode && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Node16 + && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeNext + ) { (fileProcessingDiagnostics ??= []).push({ kind: FilePreprocessingDiagnosticsKind.ResolutionDiagnostics, diagnostics: [ - createDiagnosticForRange(file, ref, Diagnostics.resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext) - ] + createDiagnosticForRange( + file, + ref, + Diagnostics + .resolution_mode_assertions_are_only_supported_when_moduleResolution_is_node16_or_nodenext, + ), + ], }); } - processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { kind: FileIncludeKind.TypeReferenceDirective, file: file.path, index, }); + processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { + kind: FileIncludeKind.TypeReferenceDirective, + file: file.path, + index, + }); } } @@ -3846,9 +4721,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg typeReferenceDirective: string, mode: ResolutionMode, resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, - reason: FileIncludeReason + reason: FileIncludeReason, ): void { - tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { directive: typeReferenceDirective, hasResolved: !!resolution.resolvedTypeReferenceDirective, refKind: reason.kind, refPath: isReferencedFile(reason) ? reason.file : undefined }); + tracing?.push(tracing.Phase.Program, "processTypeReferenceDirective", { + directive: typeReferenceDirective, + hasResolved: !!resolution.resolvedTypeReferenceDirective, + refKind: reason.kind, + refPath: isReferencedFile(reason) ? reason.file : undefined, + }); processTypeReferenceDirectiveWorker(typeReferenceDirective, mode, resolution, reason); tracing?.pop(); } @@ -3857,11 +4737,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg typeReferenceDirective: string, mode: ResolutionMode, resolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, - reason: FileIncludeReason + reason: FileIncludeReason, ): void { addResolutionDiagnostics(resolution); // If we already found this library as a primary reference - nothing to do - const previousResolution = resolvedTypeReferenceDirectives.get(typeReferenceDirective, mode)?.resolvedTypeReferenceDirective; + const previousResolution = resolvedTypeReferenceDirectives.get(typeReferenceDirective, mode) + ?.resolvedTypeReferenceDirective; if (previousResolution && previousResolution.primary) { return; } @@ -3872,7 +4753,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (resolvedTypeReferenceDirective.primary) { // resolved from the primary path - processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason); // TODO: GH#18217 + processSourceFile( + resolvedTypeReferenceDirective.resolvedFileName!, + /*isDefaultLib*/ false, + /*ignoreNoDefaultLib*/ false, + resolvedTypeReferenceDirective.packageId, + reason, + ); // TODO: GH#18217 } else { // If we already resolved to this file, it must have been a secondary reference. Check file contents @@ -3886,8 +4773,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg addFilePreprocessingFileExplainingDiagnostic( existingFile, reason, - Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict, - [typeReferenceDirective, resolvedTypeReferenceDirective.resolvedFileName!, previousResolution.resolvedFileName!] + Diagnostics + .Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict, + [ + typeReferenceDirective, + resolvedTypeReferenceDirective.resolvedFileName!, + previousResolution.resolvedFileName!, + ], ); } } @@ -3896,14 +4788,25 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } else { // First resolution of this library - processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, reason); + processSourceFile( + resolvedTypeReferenceDirective.resolvedFileName!, + /*isDefaultLib*/ false, + /*ignoreNoDefaultLib*/ false, + resolvedTypeReferenceDirective.packageId, + reason, + ); } } if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--; } else { - addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_find_type_definition_file_for_0, [typeReferenceDirective]); + addFilePreprocessingFileExplainingDiagnostic( + /*file*/ undefined, + reason, + Diagnostics.Cannot_find_type_definition_file_for_0, + [typeReferenceDirective], + ); } if (saveResolution) { @@ -3929,16 +4832,20 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (oldResolution.resolution && isTraceEnabled(options, host)) { const libraryName = getLibraryNameFromLibFileName(libFileName); const resolveFrom = getInferredLibraryNameResolveFrom(options, currentDirectory, libFileName); - trace(host, - oldResolution.resolution.resolvedModule ? - oldResolution.resolution.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 : - Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved, + trace( + host, + oldResolution.resolution.resolvedModule + ? oldResolution.resolution.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 + : Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved, libraryName, getNormalizedAbsolutePath(resolveFrom, currentDirectory), oldResolution.resolution.resolvedModule?.resolvedFileName, - oldResolution.resolution.resolvedModule?.packageId && packageIdToString(oldResolution.resolution.resolvedModule.packageId) + oldResolution.resolution.resolvedModule?.packageId + && packageIdToString(oldResolution.resolution.resolvedModule.packageId), ); } (resolvedLibProcessing ??= new Map()).set(libFileName, oldResolution); @@ -3956,9 +4863,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg tracing?.pop(); const result: LibResolution = { resolution, - actual: resolution.resolvedModule ? - resolution.resolvedModule.resolvedFileName : - combinePaths(defaultLibraryPath, libFileName) + actual: resolution.resolvedModule + ? resolution.resolvedModule.resolvedFileName + : combinePaths(defaultLibraryPath, libFileName), }; (resolvedLibProcessing ??= new Map()).set(libFileName, result); return result; @@ -3969,16 +4876,21 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const { libName, libFileName } = getLibFileNameFromLibReference(libReference); if (libFileName) { // we ignore any 'no-default-lib' reference set on this file. - processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, }); + processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { + kind: FileIncludeKind.LibReferenceDirective, + file: file.path, + index, + }); } else { const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts"); const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity); - const diagnostic = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0; + const diagnostic = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 + : Diagnostics.Cannot_find_lib_definition_for_0; const args = suggestion ? [libName, suggestion] : [libName]; (fileProcessingDiagnostics ||= []).push({ kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic, - reason: { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, }, + reason: { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index }, diagnostic, args, }); @@ -3997,7 +4909,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const moduleNames = getModuleNames(file); const resolutions = resolveModuleNamesReusingOldState(moduleNames, file); Debug.assert(resolutions.length === moduleNames.length); - const optionsForFile = (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options : undefined) || options; + const optionsForFile = + (useSourceOfProjectReferenceRedirect ? getRedirectReferenceForResolution(file)?.commandLine.options + : undefined) || options; for (let index = 0; index < moduleNames.length; index++) { const resolution = resolutions[index].resolvedModule; const moduleName = moduleNames[index].text; @@ -4042,7 +4956,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg resolvedFileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, - { kind: FileIncludeKind.Import, file: file.path, index, }, + { kind: FileIncludeKind.Import, file: file.path, index }, resolution.packageId, ); } @@ -4060,15 +4974,19 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function checkSourceFilesBelongToPath(sourceFiles: readonly SourceFile[], rootDirectory: string): boolean { let allFilesBelongToPath = true; - const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory)); + const absoluteRootDirectoryPath = host.getCanonicalFileName( + getNormalizedAbsolutePath(rootDirectory, currentDirectory), + ); for (const sourceFile of sourceFiles) { if (!sourceFile.isDeclarationFile) { - const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory)); + const absoluteSourceFilePath = host.getCanonicalFileName( + getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory), + ); if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) { addProgramDiagnosticExplainingFile( sourceFile, Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, - [sourceFile.fileName, rootDirectory] + [sourceFile.fileName, rootDirectory], ); allFilesBelongToPath = false; } @@ -4113,7 +5031,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg projectReferenceRedirects.set(sourceFilePath, false); return undefined; } - commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath); + commandLine = parseJsonSourceFileConfigFileContent( + sourceFile, + configParsingHost, + basePath, + /*existingOptions*/ undefined, + refPath, + ); } sourceFile.fileName = refPath; sourceFile.path = sourceFilePath; @@ -4130,48 +5054,88 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function verifyCompilerOptions() { if (options.strictPropertyInitialization && !getStrictOptionValue(options, "strictNullChecks")) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "strictPropertyInitialization", "strictNullChecks"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "strictPropertyInitialization", + "strictNullChecks", + ); } if (options.exactOptionalPropertyTypes && !getStrictOptionValue(options, "strictNullChecks")) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "exactOptionalPropertyTypes", "strictNullChecks"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "exactOptionalPropertyTypes", + "strictNullChecks", + ); } if (options.isolatedModules || options.verbatimModuleSyntax) { if (options.out) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", options.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "out", + options.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules", + ); } if (options.outFile) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "outFile", options.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "outFile", + options.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules", + ); } } if (options.inlineSourceMap) { if (options.sourceMap) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "sourceMap", + "inlineSourceMap", + ); } if (options.mapRoot) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "mapRoot", + "inlineSourceMap", + ); } } if (options.composite) { if (options.declaration === false) { - createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_declaration_emit, "declaration"); + createDiagnosticForOptionName( + Diagnostics.Composite_projects_may_not_disable_declaration_emit, + "declaration", + ); } if (options.incremental === false) { - createDiagnosticForOptionName(Diagnostics.Composite_projects_may_not_disable_incremental_compilation, "declaration"); + createDiagnosticForOptionName( + Diagnostics.Composite_projects_may_not_disable_incremental_compilation, + "declaration", + ); } } const outputFile = outFile(options); if (options.tsBuildInfoFile) { if (!isIncrementalCompilation(options)) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "tsBuildInfoFile", "incremental", "composite"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "tsBuildInfoFile", + "incremental", + "composite", + ); } } else if (options.incremental && !outputFile && !options.configFilePath) { - programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified)); + programDiagnostics.add( + createCompilerDiagnostic( + Diagnostics + .Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified, + ), + ); } verifyDeprecatedCompilerOptions(); @@ -4185,8 +5149,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (sourceFileMayBeEmitted(file, program) && !rootPaths.has(file.path)) { addProgramDiagnosticExplainingFile( file, - Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, - [file.fileName, options.configFilePath || ""] + Diagnostics + .File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, + [file.fileName, options.configFilePath || ""], ); } } @@ -4198,41 +5163,82 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg continue; } if (!hasZeroOrOneAsteriskCharacter(key)) { - createDiagnosticForOptionPaths(/*onKey*/ true, key, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key); + createDiagnosticForOptionPaths( + /*onKey*/ true, + key, + Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, + key, + ); } if (isArray(options.paths[key])) { const len = options.paths[key].length; if (len === 0) { - createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key); + createDiagnosticForOptionPaths( + /*onKey*/ false, + key, + Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, + key, + ); } for (let i = 0; i < len; i++) { const subst = options.paths[key][i]; const typeOfSubst = typeof subst; if (typeOfSubst === "string") { if (!hasZeroOrOneAsteriskCharacter(subst)) { - createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_in_pattern_1_can_have_at_most_one_Asterisk_character, subst, key); + createDiagnosticForOptionPathKeyValue( + key, + i, + Diagnostics.Substitution_0_in_pattern_1_can_have_at_most_one_Asterisk_character, + subst, + key, + ); } if (!options.baseUrl && !pathIsRelative(subst) && !pathIsAbsolute(subst)) { - createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Non_relative_paths_are_not_allowed_when_baseUrl_is_not_set_Did_you_forget_a_leading_Slash); + createDiagnosticForOptionPathKeyValue( + key, + i, + Diagnostics + .Non_relative_paths_are_not_allowed_when_baseUrl_is_not_set_Did_you_forget_a_leading_Slash, + ); } } else { - createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst); + createDiagnosticForOptionPathKeyValue( + key, + i, + Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, + subst, + key, + typeOfSubst, + ); } } } else { - createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key); + createDiagnosticForOptionPaths( + /*onKey*/ false, + key, + Diagnostics.Substitutions_for_pattern_0_should_be_an_array, + key, + ); } } } if (!options.sourceMap && !options.inlineSourceMap) { if (options.inlineSources) { - createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources"); + createDiagnosticForOptionName( + Diagnostics + .Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, + "inlineSources", + ); } if (options.sourceRoot) { - createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot"); + createDiagnosticForOptionName( + Diagnostics + .Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, + "sourceRoot", + ); } } @@ -4242,20 +5248,39 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (options.mapRoot && !(options.sourceMap || options.declarationMap)) { // Error to specify --mapRoot without --sourcemap - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "mapRoot", "sourceMap", "declarationMap"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "mapRoot", + "sourceMap", + "declarationMap", + ); } if (options.declarationDir) { if (!getEmitDeclarations(options)) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationDir", "declaration", "composite"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "declarationDir", + "declaration", + "composite", + ); } if (outputFile) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "declarationDir", + options.out ? "out" : "outFile", + ); } } if (options.declarationMap && !getEmitDeclarations(options)) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationMap", "declaration", "composite"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, + "declarationMap", + "declaration", + "composite", + ); } if (options.lib && options.noLib) { @@ -4263,134 +5288,259 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } if (options.noImplicitUseStrict && getStrictOptionValue(options, "alwaysStrict")) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "noImplicitUseStrict", + "alwaysStrict", + ); } const languageVersion = getEmitScriptTarget(options); const firstNonAmbientExternalModuleSourceFile = find(files, f => isExternalModule(f) && !f.isDeclarationFile); if (options.isolatedModules || options.verbatimModuleSyntax) { - if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015 && options.isolatedModules) { - createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target"); + if ( + options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015 && options.isolatedModules + ) { + createDiagnosticForOptionName( + Diagnostics + .Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, + "isolatedModules", + "target", + ); } if (options.preserveConstEnums === false) { - createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_0_is_enabled, options.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules", "preserveConstEnums"); + createDiagnosticForOptionName( + Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_0_is_enabled, + options.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules", + "preserveConstEnums", + ); } } - else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 && options.module === ModuleKind.None) { + else if ( + firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 + && options.module === ModuleKind.None + ) { // We cannot use createDiagnosticFromNode because nodes do not have parents yet - const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!); - programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none)); + const span = getErrorSpanForNode( + firstNonAmbientExternalModuleSourceFile, + typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" + ? firstNonAmbientExternalModuleSourceFile + : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!, + ); + programDiagnostics.add( + createFileDiagnostic( + firstNonAmbientExternalModuleSourceFile, + span.start, + span.length, + Diagnostics.Cannot_use_imports_exports_or_module_augmentations_when_module_is_none, + ), + ); } // Cannot specify module gen that isn't amd or system with --out if (outputFile && !options.emitDeclarationOnly) { if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) { - createDiagnosticForOptionName(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile", "module"); + createDiagnosticForOptionName( + Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, + options.out ? "out" : "outFile", + "module", + ); } else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) { - const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" ? firstNonAmbientExternalModuleSourceFile : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!); - programDiagnostics.add(createFileDiagnostic(firstNonAmbientExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, options.out ? "out" : "outFile")); + const span = getErrorSpanForNode( + firstNonAmbientExternalModuleSourceFile, + typeof firstNonAmbientExternalModuleSourceFile.externalModuleIndicator === "boolean" + ? firstNonAmbientExternalModuleSourceFile + : firstNonAmbientExternalModuleSourceFile.externalModuleIndicator!, + ); + programDiagnostics.add( + createFileDiagnostic( + firstNonAmbientExternalModuleSourceFile, + span.start, + span.length, + Diagnostics.Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system, + options.out ? "out" : "outFile", + ), + ); } } if (getResolveJsonModule(options)) { if (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Classic) { - createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_cannot_be_specified_when_moduleResolution_is_set_to_classic, "resolveJsonModule"); + createDiagnosticForOptionName( + Diagnostics.Option_resolveJsonModule_cannot_be_specified_when_moduleResolution_is_set_to_classic, + "resolveJsonModule", + ); } // Any emit other than common js, amd, es2015 or esnext is error else if (!hasJsonModuleEmitEnabled(options)) { - createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_amd_es2015_or_esNext, "resolveJsonModule", "module"); + createDiagnosticForOptionName( + Diagnostics + .Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_amd_es2015_or_esNext, + "resolveJsonModule", + "module", + ); } } // there has to be common source directory if user specified --outdir || --rootDir || --sourceRoot // if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted - if (options.outDir || // there is --outDir specified - options.rootDir || // there is --rootDir specified - options.sourceRoot || // there is --sourceRoot specified - options.mapRoot) { // there is --mapRoot specified - + if ( + options.outDir // there is --outDir specified + || options.rootDir // there is --rootDir specified + || options.sourceRoot // there is --sourceRoot specified + || options.mapRoot // there is --mapRoot specified + ) { // Precalculate and cache the common source directory const dir = getCommonSourceDirectory(); // If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure if (options.outDir && dir === "" && files.some(file => getRootLength(file.fileName) > 1)) { - createDiagnosticForOptionName(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, "outDir"); + createDiagnosticForOptionName( + Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, + "outDir", + ); } } if (options.useDefineForClassFields && languageVersion === ScriptTarget.ES3) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_target_is_ES3, "useDefineForClassFields"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_target_is_ES3, + "useDefineForClassFields", + ); } if (options.checkJs && !getAllowJSCompilerOption(options)) { - programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "checkJs", "allowJs")); + programDiagnostics.add( + createCompilerDiagnostic( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "checkJs", + "allowJs", + ), + ); } if (options.emitDeclarationOnly) { if (!getEmitDeclarations(options)) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "emitDeclarationOnly", "declaration", "composite"); + 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"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "emitDeclarationOnly", + "noEmit", + ); } } - if (options.emitDecoratorMetadata && - !options.experimentalDecorators) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators"); + if ( + options.emitDecoratorMetadata + && !options.experimentalDecorators + ) { + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "emitDecoratorMetadata", + "experimentalDecorators", + ); } if (options.jsxFactory) { if (options.reactNamespace) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_with_option_1, + "reactNamespace", + "jsxFactory", + ); } if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFactory", inverseJsxOptionMap.get("" + options.jsx)); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, + "jsxFactory", + inverseJsxOptionMap.get("" + options.jsx), + ); } if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) { - createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory); + createOptionValueDiagnostic( + "jsxFactory", + Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, + options.jsxFactory, + ); } } else if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) { - createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace); + createOptionValueDiagnostic( + "reactNamespace", + Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, + options.reactNamespace, + ); } if (options.jsxFragmentFactory) { if (!options.jsxFactory) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "jsxFragmentFactory", "jsxFactory"); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, + "jsxFragmentFactory", + "jsxFactory", + ); } if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxFragmentFactory", inverseJsxOptionMap.get("" + options.jsx)); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, + "jsxFragmentFactory", + inverseJsxOptionMap.get("" + options.jsx), + ); } if (!parseIsolatedEntityName(options.jsxFragmentFactory, languageVersion)) { - createOptionValueDiagnostic("jsxFragmentFactory", Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFragmentFactory); + createOptionValueDiagnostic( + "jsxFragmentFactory", + Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, + options.jsxFragmentFactory, + ); } } if (options.reactNamespace) { if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "reactNamespace", inverseJsxOptionMap.get("" + options.jsx)); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, + "reactNamespace", + inverseJsxOptionMap.get("" + options.jsx), + ); } } if (options.jsxImportSource) { if (options.jsx === JsxEmit.React) { - createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, "jsxImportSource", inverseJsxOptionMap.get("" + options.jsx)); + createDiagnosticForOptionName( + Diagnostics.Option_0_cannot_be_specified_when_option_jsx_is_1, + "jsxImportSource", + inverseJsxOptionMap.get("" + options.jsx), + ); } } if (options.preserveValueImports && getEmitModuleKind(options) < ModuleKind.ES2015) { - createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_module_is_set_to_es2015_or_later, "preserveValueImports"); + createDiagnosticForOptionName( + Diagnostics.Option_0_can_only_be_used_when_module_is_set_to_es2015_or_later, + "preserveValueImports", + ); } const moduleKind = getEmitModuleKind(options); if (options.verbatimModuleSyntax) { if (moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.UMD || moduleKind === ModuleKind.System) { - createDiagnosticForOptionName(Diagnostics.Option_verbatimModuleSyntax_cannot_be_used_when_module_is_set_to_UMD_AMD_or_System, "verbatimModuleSyntax"); + createDiagnosticForOptionName( + Diagnostics.Option_verbatimModuleSyntax_cannot_be_used_when_module_is_set_to_UMD_AMD_or_System, + "verbatimModuleSyntax", + ); } if (options.preserveValueImports) { createRedundantOptionDiagnostic("preserveValueImports", "verbatimModuleSyntax"); @@ -4401,47 +5551,77 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } if (options.allowImportingTsExtensions && !(options.noEmit || options.emitDeclarationOnly)) { - createOptionValueDiagnostic("allowImportingTsExtensions", Diagnostics.Option_allowImportingTsExtensions_can_only_be_used_when_either_noEmit_or_emitDeclarationOnly_is_set); + createOptionValueDiagnostic( + "allowImportingTsExtensions", + Diagnostics + .Option_allowImportingTsExtensions_can_only_be_used_when_either_noEmit_or_emitDeclarationOnly_is_set, + ); } const moduleResolution = getEmitModuleResolutionKind(options); - if (options.resolvePackageJsonExports && !moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution)) { - createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, "resolvePackageJsonExports"); + if ( + options.resolvePackageJsonExports && !moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution) + ) { + createDiagnosticForOptionName( + Diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, + "resolvePackageJsonExports", + ); } - if (options.resolvePackageJsonImports && !moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution)) { - createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, "resolvePackageJsonImports"); + if ( + options.resolvePackageJsonImports && !moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution) + ) { + createDiagnosticForOptionName( + Diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, + "resolvePackageJsonImports", + ); } if (options.customConditions && !moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution)) { - createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, "customConditions"); + createDiagnosticForOptionName( + Diagnostics.Option_0_can_only_be_used_when_moduleResolution_is_set_to_node16_nodenext_or_bundler, + "customConditions", + ); } if (moduleResolution === ModuleResolutionKind.Bundler && !emitModuleKindIsNonNodeESM(moduleKind)) { - createOptionValueDiagnostic("moduleResolution", Diagnostics.Option_0_can_only_be_used_when_module_is_set_to_es2015_or_later, "bundler"); + createOptionValueDiagnostic( + "moduleResolution", + Diagnostics.Option_0_can_only_be_used_when_module_is_set_to_es2015_or_later, + "bundler", + ); } if ( - ModuleKind[moduleKind] && - (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) && - !(ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext) + ModuleKind[moduleKind] + && (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) + && !(ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext) ) { const moduleKindName = ModuleKind[moduleKind]; - createOptionValueDiagnostic("moduleResolution", Diagnostics.Option_moduleResolution_must_be_set_to_0_or_left_unspecified_when_option_module_is_set_to_1, moduleKindName, moduleKindName); + createOptionValueDiagnostic( + "moduleResolution", + Diagnostics.Option_moduleResolution_must_be_set_to_0_or_left_unspecified_when_option_module_is_set_to_1, + moduleKindName, + moduleKindName, + ); } else if ( - ModuleResolutionKind[moduleResolution] && - (ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext) && - !(ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) + ModuleResolutionKind[moduleResolution] + && (ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext) + && !(ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) ) { const moduleResolutionName = ModuleResolutionKind[moduleResolution]; - createOptionValueDiagnostic("module", Diagnostics.Option_module_must_be_set_to_0_when_option_moduleResolution_is_set_to_1, moduleResolutionName, moduleResolutionName); + createOptionValueDiagnostic( + "module", + Diagnostics.Option_module_must_be_set_to_0_when_option_moduleResolution_is_set_to_1, + moduleResolutionName, + moduleResolutionName, + ); } - // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files if (!options.noEmit && !options.suppressOutputPathCheck) { const emitHost = getEmitHost(); const emitFilesSeen = new Set(); - forEachEmittedFile(emitHost, (emitFileNames) => { + forEachEmittedFile(emitHost, emitFileNames => { if (!options.emitDeclarationOnly) { verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen); } @@ -4458,17 +5638,32 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg let chain: DiagnosticMessageChain | undefined; if (!options.configFilePath) { // The program is from either an inferred project or an external project - chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript_files_Learn_more_at_https_Colon_Slash_Slashaka_ms_Slashtsconfig); + chain = chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics + .Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript_files_Learn_more_at_https_Colon_Slash_Slashaka_ms_Slashtsconfig, + ); } - chain = chainDiagnosticMessages(chain, Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, emitFileName); + chain = chainDiagnosticMessages( + chain, + Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, + emitFileName, + ); blockEmittingOfFile(emitFileName, createCompilerDiagnosticFromMessageChain(chain)); } - const emitFileKey = !host.useCaseSensitiveFileNames() ? toFileNameLowerCase(emitFilePath) : emitFilePath; + const emitFileKey = !host.useCaseSensitiveFileNames() ? toFileNameLowerCase(emitFilePath) + : emitFilePath; // Report error if multiple files write into same file if (emitFilesSeen.has(emitFileKey)) { // Already seen the same emit file - report error - blockEmittingOfFile(emitFileName, createCompilerDiagnostic(Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName)); + blockEmittingOfFile( + emitFileName, + createCompilerDiagnostic( + Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, + emitFileName, + ), + ); } else { emitFilesSeen.add(emitFileKey); @@ -4494,7 +5689,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function checkDeprecations( deprecatedIn: string, removedIn: string, - createDiagnostic: (name: string, value: string | undefined, useInstead: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) => void, + createDiagnostic: ( + name: string, + value: string | undefined, + useInstead: string | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ) => void, fn: (createDeprecatedDiagnostic: (name: string, value?: string, useInstead?: string) => void) => void, ) { const deprecatedInVersion = new Version(deprecatedIn); @@ -4503,24 +5704,57 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const ignoreDeprecationsVersion = getIgnoreDeprecationsVersion(); const mustBeRemoved = !(removedInVersion.compareTo(typescriptVersion) === Comparison.GreaterThan); - const canBeSilenced = !mustBeRemoved && ignoreDeprecationsVersion.compareTo(deprecatedInVersion) === Comparison.LessThan; + const canBeSilenced = !mustBeRemoved + && ignoreDeprecationsVersion.compareTo(deprecatedInVersion) === Comparison.LessThan; if (mustBeRemoved || canBeSilenced) { fn((name, value, useInstead) => { if (mustBeRemoved) { if (value === undefined) { - createDiagnostic(name, value, useInstead, Diagnostics.Option_0_has_been_removed_Please_remove_it_from_your_configuration, name); + createDiagnostic( + name, + value, + useInstead, + Diagnostics.Option_0_has_been_removed_Please_remove_it_from_your_configuration, + name, + ); } else { - createDiagnostic(name, value, useInstead, Diagnostics.Option_0_1_has_been_removed_Please_remove_it_from_your_configuration, name, value); + createDiagnostic( + name, + value, + useInstead, + Diagnostics.Option_0_1_has_been_removed_Please_remove_it_from_your_configuration, + name, + value, + ); } } else { if (value === undefined) { - createDiagnostic(name, value, useInstead, Diagnostics.Option_0_is_deprecated_and_will_stop_functioning_in_TypeScript_1_Specify_compilerOption_ignoreDeprecations_Colon_2_to_silence_this_error, name, removedIn, deprecatedIn); + createDiagnostic( + name, + value, + useInstead, + Diagnostics + .Option_0_is_deprecated_and_will_stop_functioning_in_TypeScript_1_Specify_compilerOption_ignoreDeprecations_Colon_2_to_silence_this_error, + name, + removedIn, + deprecatedIn, + ); } else { - createDiagnostic(name, value, useInstead, Diagnostics.Option_0_1_is_deprecated_and_will_stop_functioning_in_TypeScript_2_Specify_compilerOption_ignoreDeprecations_Colon_3_to_silence_this_error, name, value, removedIn, deprecatedIn); + createDiagnostic( + name, + value, + useInstead, + Diagnostics + .Option_0_1_is_deprecated_and_will_stop_functioning_in_TypeScript_2_Specify_compilerOption_ignoreDeprecations_Colon_3_to_silence_this_error, + name, + value, + removedIn, + deprecatedIn, + ); } } }); @@ -4528,7 +5762,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function verifyDeprecatedCompilerOptions() { - function createDiagnostic(name: string, value: string | undefined, useInstead: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) { + function createDiagnostic( + name: string, + value: string | undefined, + useInstead: string | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ) { if (useInstead) { const details = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Use_0_instead, useInstead); const chain = chainDiagnosticMessages(details, message, ...args); @@ -4573,8 +5813,18 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg }); } - function verifyDeprecatedProjectReference(ref: ProjectReference, parentFile: JsonSourceFile | undefined, index: number) { - function createDiagnostic(_name: string, _value: string | undefined, _useInstead: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) { + function verifyDeprecatedProjectReference( + ref: ProjectReference, + parentFile: JsonSourceFile | undefined, + index: number, + ) { + function createDiagnostic( + _name: string, + _value: string | undefined, + _useInstead: string | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ) { createDiagnosticForReference(parentFile, index, message, ...args); } @@ -4585,7 +5835,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg }); } - function createDiagnosticExplainingFile(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: DiagnosticArguments | undefined): Diagnostic { + function createDiagnosticExplainingFile( + file: SourceFile | undefined, + fileProcessingReason: FileIncludeReason | undefined, + diagnostic: DiagnosticMessage, + args: DiagnosticArguments | undefined, + ): Diagnostic { let fileIncludeReasons: DiagnosticMessageChain[] | undefined; let relatedInfo: Diagnostic[] | undefined; let locationReason = isReferencedFile(fileProcessingReason) ? fileProcessingReason : undefined; @@ -4594,12 +5849,24 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // If we have location and there is only one reason file is in which is the location, dont add details for file include if (locationReason && fileIncludeReasons?.length === 1) fileIncludeReasons = undefined; const location = locationReason && getReferencedFileLocation(getSourceFileByPath, locationReason); - const fileIncludeReasonDetails = fileIncludeReasons && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon); + const fileIncludeReasonDetails = fileIncludeReasons + && chainDiagnosticMessages(fileIncludeReasons, Diagnostics.The_file_is_in_the_program_because_Colon); const redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file); - const chain = chainDiagnosticMessages(redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo : fileIncludeReasonDetails, diagnostic, ...args || emptyArray); - return location && isReferenceFileLocation(location) ? - createFileDiagnosticFromMessageChain(location.file, location.pos, location.end - location.pos, chain, relatedInfo) : - createCompilerDiagnosticFromMessageChain(chain, relatedInfo); + const chain = chainDiagnosticMessages( + redirectInfo ? fileIncludeReasonDetails ? [fileIncludeReasonDetails, ...redirectInfo] : redirectInfo + : fileIncludeReasonDetails, + diagnostic, + ...args || emptyArray, + ); + return location && isReferenceFileLocation(location) + ? createFileDiagnosticFromMessageChain( + location.file, + location.pos, + location.end - location.pos, + chain, + relatedInfo, + ) + : createCompilerDiagnosticFromMessageChain(chain, relatedInfo); function processReason(reason: FileIncludeReason) { (fileIncludeReasons ||= []).push(fileIncludeReasonToDiagnostics(program, reason)); @@ -4615,18 +5882,29 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function addFilePreprocessingFileExplainingDiagnostic(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason, diagnostic: DiagnosticMessage, args?: DiagnosticArguments) { + function addFilePreprocessingFileExplainingDiagnostic( + file: SourceFile | undefined, + fileProcessingReason: FileIncludeReason, + diagnostic: DiagnosticMessage, + args?: DiagnosticArguments, + ) { (fileProcessingDiagnostics ||= []).push({ kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic, file: file && file.path, fileProcessingReason, diagnostic, - args + args, }); } - function addProgramDiagnosticExplainingFile(file: SourceFile, diagnostic: DiagnosticMessage, args?: DiagnosticArguments) { - programDiagnostics.add(createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args)); + function addProgramDiagnosticExplainingFile( + file: SourceFile, + diagnostic: DiagnosticMessage, + args?: DiagnosticArguments, + ) { + programDiagnostics.add( + createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args), + ); } function fileIncludeReasonToRelatedInformation(reason: FileIncludeReason): DiagnosticWithLocation | undefined { @@ -4679,22 +5957,29 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg case FileIncludeKind.SourceFromProjectReference: case FileIncludeKind.OutputFromProjectReference: const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]); - const referenceInfo = forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => - resolvedRef === referencedResolvedRef ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined + const referenceInfo = forEachProjectReference( + projectReferences, + resolvedProjectReferences, + (resolvedRef, parent, index) => + resolvedRef === referencedResolvedRef + ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined, ); if (!referenceInfo) return undefined; const { sourceFile, index } = referenceInfo; - const referencesSyntax = forEachTsConfigPropArray(sourceFile as TsConfigSourceFile, "references", - property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined); - return referencesSyntax && referencesSyntax.elements.length > index ? - createDiagnosticForNodeInSourceFile( + const referencesSyntax = forEachTsConfigPropArray( + sourceFile as TsConfigSourceFile, + "references", + property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined, + ); + return referencesSyntax && referencesSyntax.elements.length > index + ? createDiagnosticForNodeInSourceFile( sourceFile, referencesSyntax.elements[index], - reason.kind === FileIncludeKind.OutputFromProjectReference ? - Diagnostics.File_is_output_from_referenced_project_specified_here : - Diagnostics.File_is_source_from_referenced_project_specified_here, - ) : - undefined; + reason.kind === FileIncludeKind.OutputFromProjectReference + ? Diagnostics.File_is_output_from_referenced_project_specified_here + : Diagnostics.File_is_source_from_referenced_project_specified_here, + ) + : undefined; case FileIncludeKind.AutomaticTypeDirectiveFile: if (!options.types) return undefined; configFileNode = getOptionsSyntaxByArrayElementValue("types", reason.typeReference); @@ -4706,7 +5991,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg message = Diagnostics.File_is_library_specified_here; break; } - const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === getEmitScriptTarget(options) ? key : undefined); + const target = forEachEntry( + targetOptionDeclaration.type, + (value, key) => value === getEmitScriptTarget(options) ? key : undefined, + ); configFileNode = target ? getOptionsSyntaxByValue("target", target) : undefined; message = Diagnostics.File_is_default_library_for_target_specified_here; break; @@ -4735,36 +6023,80 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg // ok to not have composite if the current program is container only const inputs = parent ? parent.commandLine.fileNames : rootNames; if (inputs.length) { - if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path); - if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path); + if (!options.composite) { + createDiagnosticForReference( + parentFile, + index, + Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, + ref.path, + ); + } + if (options.noEmit) { + createDiagnosticForReference( + parentFile, + index, + Diagnostics.Referenced_project_0_may_not_disable_emit, + ref.path, + ); + } } } if (ref.prepend) { const out = outFile(options); if (out) { if (!host.fileExists(out)) { - createDiagnosticForReference(parentFile, index, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path); + createDiagnosticForReference( + parentFile, + index, + Diagnostics.Output_file_0_from_project_1_does_not_exist, + out, + ref.path, + ); } } else { - createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, ref.path); + createDiagnosticForReference( + parentFile, + index, + Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, + ref.path, + ); } } if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) { - createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path); + createDiagnosticForReference( + parentFile, + index, + Diagnostics + .Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, + buildInfoPath, + ref.path, + ); hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true); } }); } - function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, ...args: DiagnosticArguments) { + function createDiagnosticForOptionPathKeyValue( + key: string, + valueIndex: number, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ) { let needCompilerDiagnostic = true; forEachOptionPathsSyntax(pathProp => { if (isObjectLiteralExpression(pathProp.initializer)) { forEachPropertyAssignment(pathProp.initializer, key, keyProps => { const initializer = keyProps.initializer; if (isArrayLiteralExpression(initializer) && initializer.elements.length > valueIndex) { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, ...args)); + programDiagnostics.add( + createDiagnosticForNodeInSourceFile( + options.configFile!, + initializer.elements[valueIndex], + message, + ...args, + ), + ); needCompilerDiagnostic = false; } }); @@ -4775,13 +6107,25 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, ...args: DiagnosticArguments) { + function createDiagnosticForOptionPaths( + onKey: boolean, + key: string, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ) { let needCompilerDiagnostic = true; forEachOptionPathsSyntax(pathProp => { - if (isObjectLiteralExpression(pathProp.initializer) && - createOptionDiagnosticInObjectLiteralSyntax( - pathProp.initializer, onKey, key, /*key2*/ undefined, - message, ...args)) { + if ( + isObjectLiteralExpression(pathProp.initializer) + && createOptionDiagnosticInObjectLiteralSyntax( + pathProp.initializer, + onKey, + key, + /*key2*/ undefined, + message, + ...args, + ) + ) { needCompilerDiagnostic = false; } }); @@ -4790,7 +6134,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function forEachOptionsSyntaxByName(name: string, callback: (prop: PropertyAssignment) => T | undefined): T | undefined { + function forEachOptionsSyntaxByName( + name: string, + callback: (prop: PropertyAssignment) => T | undefined, + ): T | undefined { return forEachPropertyAssignment(getCompilerOptionsObjectLiteralSyntax(), name, callback); } @@ -4799,15 +6146,26 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function getOptionsSyntaxByValue(name: string, value: string) { - return forEachOptionsSyntaxByName(name, property => isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer : undefined); + return forEachOptionsSyntaxByName( + name, + property => + isStringLiteral(property.initializer) && property.initializer.text === value ? property.initializer + : undefined, + ); } function getOptionsSyntaxByArrayElementValue(name: string, value: string) { const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); - return compilerOptionsObjectLiteralSyntax && getPropertyArrayElementValue(compilerOptionsObjectLiteralSyntax, name, value); + return compilerOptionsObjectLiteralSyntax + && getPropertyArrayElementValue(compilerOptionsObjectLiteralSyntax, name, value); } - function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string, option3?: string) { + function createDiagnosticForOptionName( + message: DiagnosticMessage, + option1: string, + option2?: string, + option3?: string, + ) { // TODO(jakebailey): this code makes assumptions about the format of the diagnostic messages. createDiagnosticForOption(/*onKey*/ true, option1, option2, message, option1, option2!, option3!); } @@ -4816,23 +6174,62 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, ...args); } - function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, ...args: DiagnosticArguments) { - const referencesSyntax = forEachTsConfigPropArray(sourceFile || options.configFile, "references", - property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined); + function createDiagnosticForReference( + sourceFile: JsonSourceFile | undefined, + index: number, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ) { + const referencesSyntax = forEachTsConfigPropArray( + sourceFile || options.configFile, + "references", + property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined, + ); if (referencesSyntax && referencesSyntax.elements.length > index) { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, ...args)); + programDiagnostics.add( + createDiagnosticForNodeInSourceFile( + sourceFile || options.configFile!, + referencesSyntax.elements[index], + message, + ...args, + ), + ); } else { programDiagnostics.add(createCompilerDiagnostic(message, ...args)); } } - function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessageChain): void; - function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): void; - function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): void { + function createDiagnosticForOption( + onKey: boolean, + option1: string, + option2: string | undefined, + message: DiagnosticMessageChain, + ): void; + function createDiagnosticForOption( + onKey: boolean, + option1: string, + option2: string | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): void; + function createDiagnosticForOption( + onKey: boolean, + option1: string, + option2: string | undefined, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: DiagnosticArguments + ): void { const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); - const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax || - !createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, ...args); + const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax + || !createOptionDiagnosticInObjectLiteralSyntax( + compilerOptionsObjectLiteralSyntax, + onKey, + option1, + option2, + message, + ...args, + ); if (needCompilerDiagnostic) { // eslint-disable-next-line local/no-in-operator @@ -4850,24 +6247,64 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg _compilerOptionsObjectLiteralSyntax = forEachPropertyAssignment( getTsConfigObjectLiteralExpression(options.configFile), "compilerOptions", - prop => isObjectLiteralExpression(prop.initializer) ? prop.initializer : undefined + prop => isObjectLiteralExpression(prop.initializer) ? prop.initializer : undefined, ) || false; } return _compilerOptionsObjectLiteralSyntax || undefined; } - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, messageChain: DiagnosticMessageChain): boolean; - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean; - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): boolean; - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): boolean { + function createOptionDiagnosticInObjectLiteralSyntax( + objectLiteral: ObjectLiteralExpression, + onKey: boolean, + key1: string, + key2: string | undefined, + messageChain: DiagnosticMessageChain, + ): boolean; + function createOptionDiagnosticInObjectLiteralSyntax( + objectLiteral: ObjectLiteralExpression, + onKey: boolean, + key1: string, + key2: string | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments + ): boolean; + function createOptionDiagnosticInObjectLiteralSyntax( + objectLiteral: ObjectLiteralExpression, + onKey: boolean, + key1: string, + key2: string | undefined, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: DiagnosticArguments + ): boolean; + function createOptionDiagnosticInObjectLiteralSyntax( + objectLiteral: ObjectLiteralExpression, + onKey: boolean, + key1: string, + key2: string | undefined, + message: DiagnosticMessage | DiagnosticMessageChain, + ...args: DiagnosticArguments + ): boolean { let needsCompilerDiagnostic = false; forEachPropertyAssignment(objectLiteral, key1, prop => { // eslint-disable-next-line local/no-in-operator if ("messageText" in message) { - programDiagnostics.add(createDiagnosticForNodeFromMessageChain(options.configFile!, onKey ? prop.name : prop.initializer, message)); + programDiagnostics.add( + createDiagnosticForNodeFromMessageChain( + options.configFile!, + onKey ? prop.name : prop.initializer, + message, + ), + ); } else { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, ...args)); + programDiagnostics.add( + createDiagnosticForNodeInSourceFile( + options.configFile!, + onKey ? prop.name : prop.initializer, + message, + ...args, + ), + ); } needsCompilerDiagnostic = true; }, key2); @@ -4886,11 +6323,23 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); if (compilerOptionsObjectLiteralSyntax) { // This is a no-op if `errorOnOption` isn't present in the leaf config file. - createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, /*onKey*/ true, errorOnOption, /*key2*/ undefined, Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, errorOnOption, redundantWithOption); + createOptionDiagnosticInObjectLiteralSyntax( + compilerOptionsObjectLiteralSyntax, + /*onKey*/ true, + errorOnOption, + /*key2*/ undefined, + Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, + errorOnOption, + redundantWithOption, + ); } else { // There was no config file, so both options were specified on the command line. - createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, errorOnOption, redundantWithOption); + createDiagnosticForOptionName( + Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, + errorOnOption, + redundantWithOption, + ); } } @@ -4917,7 +6366,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } // If declarationDir is specified, return if its a file in that directory - if (options.declarationDir && containsPath(options.declarationDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames())) { + if ( + options.declarationDir + && containsPath(options.declarationDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames()) + ) { return true; } @@ -4929,8 +6381,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (fileExtensionIsOneOf(filePath, supportedJSExtensionsFlat) || isDeclarationFileName(filePath)) { // Otherwise just check if sourceFile with the name exists const filePathWithoutExtension = removeFileExtension(filePath); - return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) || - !!getSourceFileByPath((filePathWithoutExtension + Extension.Tsx) as Path); + return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) + || !!getSourceFileByPath((filePathWithoutExtension + Extension.Tsx) as Path); } return false; } @@ -4960,7 +6412,9 @@ interface HostForUseSourceOfProjectReferenceRedirect { toPath(fileName: string): Path; getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined; getSourceOfProjectReferenceRedirect(path: Path): SourceOfProjectReferenceRedirect | undefined; - forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined; + forEachResolvedProjectReference( + cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, + ): T | undefined; } function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSourceOfProjectReferenceRedirect) { @@ -5012,16 +6466,17 @@ function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSource // Call getDirectories only if directory actually present on the host // This is needed to ensure that we arent getting directories that we fake about presence for host.compilerHost.getDirectories = path => - !host.getResolvedProjectReferences() || (originalDirectoryExists && originalDirectoryExists.call(host.compilerHost, path)) ? - originalGetDirectories.call(host.compilerHost, path) : - []; + !host.getResolvedProjectReferences() + || (originalDirectoryExists && originalDirectoryExists.call(host.compilerHost, path)) + ? originalGetDirectories.call(host.compilerHost, path) + : []; } // This is something we keep for life time of the host if (originalRealpath) { host.compilerHost.realpath = s => - host.getSymlinkCache().getSymlinkedFiles()?.get(host.toPath(s)) || - originalRealpath.call(host.compilerHost, s); + host.getSymlinkCache().getSymlinkedFiles()?.get(host.toPath(s)) + || originalRealpath.call(host.compilerHost, s); } return { onProgramCreateComplete, fileExists, directoryExists }; @@ -5047,9 +6502,9 @@ function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSource function fileExistsIfProjectReferenceDts(file: string) { const source = host.getSourceOfProjectReferenceRedirect(host.toPath(file)); - return source !== undefined ? - isString(source) ? originalFileExists.call(host.compilerHost, source) as boolean : true : - undefined; + return source !== undefined + ? isString(source) ? originalFileExists.call(host.compilerHost, source) as boolean : true + : undefined; } function directoryExistsIfProjectReferenceDeclDir(dir: string) { @@ -5057,11 +6512,12 @@ function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSource const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`; return forEachKey( setOfDeclarationDirectories!, - declDirPath => dirPath === declDirPath || + declDirPath => + dirPath === declDirPath // Any parent directory of declaration dir - startsWith(declDirPath, dirPathWithTrailingDirectorySeparator) || + || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator) // Any directory inside declaration dir - startsWith(dirPath, `${declDirPath}/`) + || startsWith(dirPath, `${declDirPath}/`), ); } @@ -5076,8 +6532,10 @@ function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSource const real = normalizePath(originalRealpath.call(host.compilerHost, directory)); let realPath: Path; - if (real === directory || - (realPath = ensureTrailingDirectorySeparator(host.toPath(real))) === directoryPath) { + if ( + real === directory + || (realPath = ensureTrailingDirectorySeparator(host.toPath(real))) === directoryPath + ) { // not symlinked symlinkCache.setSymlinkedDirectory(directoryPath, false); return; @@ -5085,14 +6543,14 @@ function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSource symlinkCache.setSymlinkedDirectory(directory, { real: ensureTrailingDirectorySeparator(real), - realPath + realPath, }); } function fileOrDirectoryExistsUsingSource(fileOrDirectory: string, isFile: boolean): boolean { - const fileOrDirectoryExistsUsingSource = isFile ? - (file: string) => fileExistsIfProjectReferenceDts(file) : - (dir: string) => directoryExistsIfProjectReferenceDeclDir(dir); + const fileOrDirectoryExistsUsingSource = isFile + ? (file: string) => fileExistsIfProjectReferenceDts(file) + : (dir: string) => directoryExistsIfProjectReferenceDeclDir(dir); // Check current directory or file const result = fileOrDirectoryExistsUsingSource(fileOrDirectory); if (result !== undefined) return result; @@ -5109,38 +6567,48 @@ function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSource symlinkedDirectories.entries(), ([directoryPath, symlinkedDirectory]) => { if (!symlinkedDirectory || !startsWith(fileOrDirectoryPath, directoryPath)) return undefined; - const result = fileOrDirectoryExistsUsingSource(fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath)); + const result = fileOrDirectoryExistsUsingSource( + fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath), + ); if (isFile && result) { // Store the real path for the file' - const absolutePath = getNormalizedAbsolutePath(fileOrDirectory, host.compilerHost.getCurrentDirectory()); + const absolutePath = getNormalizedAbsolutePath( + fileOrDirectory, + host.compilerHost.getCurrentDirectory(), + ); symlinkCache.setSymlinkedFile( fileOrDirectoryPath, - `${symlinkedDirectory.real}${absolutePath.replace(new RegExp(directoryPath, "i"), "")}` + `${symlinkedDirectory.real}${absolutePath.replace(new RegExp(directoryPath, "i"), "")}`, ); } return result; - } + }, ) || false; } } /** @internal */ -export const emitSkippedWithNoDiagnostics: EmitResult = { diagnostics: emptyArray, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true }; +export const emitSkippedWithNoDiagnostics: EmitResult = { + diagnostics: emptyArray, + sourceMaps: undefined, + emittedFiles: undefined, + emitSkipped: true, +}; /** @internal */ export function handleNoEmitOptions( program: Program | T, sourceFile: SourceFile | undefined, writeFile: WriteFileCallback | undefined, - cancellationToken: CancellationToken | undefined + cancellationToken: CancellationToken | undefined, ): EmitResult | undefined { const options = program.getCompilerOptions(); if (options.noEmit) { // Cache the semantic diagnostics program.getSemanticDiagnostics(sourceFile, cancellationToken); - return sourceFile || outFile(options) ? - emitSkippedWithNoDiagnostics : - program.emitBuildInfo(writeFile, cancellationToken); + return sourceFile || outFile(options) + ? emitSkippedWithNoDiagnostics + : program.emitBuildInfo(writeFile, cancellationToken); } // If the noEmitOnError flag is set, then check if we have any errors so far. If so, @@ -5151,7 +6619,7 @@ export function handleNoEmitOptions( ...program.getOptionsDiagnostics(cancellationToken), ...program.getSyntacticDiagnostics(sourceFile, cancellationToken), ...program.getGlobalDiagnostics(cancellationToken), - ...program.getSemanticDiagnostics(sourceFile, cancellationToken) + ...program.getSemanticDiagnostics(sourceFile, cancellationToken), ]; if (diagnostics.length === 0 && getEmitDeclarations(program.getCompilerOptions())) { @@ -5169,19 +6637,25 @@ export function handleNoEmitOptions( } /** @internal */ -export function filterSemanticDiagnostics(diagnostic: readonly Diagnostic[], option: CompilerOptions): readonly Diagnostic[] { +export function filterSemanticDiagnostics( + diagnostic: readonly Diagnostic[], + option: CompilerOptions, +): readonly Diagnostic[] { return filter(diagnostic, d => !d.skippedOn || !option[d.skippedOn]); } /** @internal */ export function parseConfigHostFromCompilerHostLike( - host: (CompilerHost | ProgramHost) & { onUnRecoverableConfigFileDiagnostic?: DiagnosticReporter }, + host: (CompilerHost | ProgramHost) & { onUnRecoverableConfigFileDiagnostic?: DiagnosticReporter; }, directoryStructureHost: DirectoryStructureHost = host, ): ParseConfigFileHost { return { fileExists: f => directoryStructureHost.fileExists(f), readDirectory(root, extensions, excludes, includes, depth) { - Debug.assertIsDefined(directoryStructureHost.readDirectory, "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'"); + Debug.assertIsDefined( + directoryStructureHost.readDirectory, + "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'", + ); return directoryStructureHost.readDirectory(root, extensions, excludes, includes, depth); }, readFile: f => directoryStructureHost.readFile(f), @@ -5191,7 +6665,7 @@ export function parseConfigHostFromCompilerHostLike( useCaseSensitiveFileNames: host.useCaseSensitiveFileNames(), getCurrentDirectory: () => host.getCurrentDirectory(), onUnRecoverableConfigFileDiagnostic: host.onUnRecoverableConfigFileDiagnostic || returnUndefined, - trace: host.trace ? (s) => host.trace!(s) : undefined, + trace: host.trace ? s => host.trace!(s) : undefined, }; } @@ -5212,8 +6686,18 @@ export function createPrependNodes( // Upstream project didn't have outFile set -- skip (error will have been issued earlier) if (!out) continue; - const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = getOutputPathsForBundle(resolvedRefOpts.options, /*forceDtsPaths*/ true); - const node = createInputFilesWithFilePaths(readFile, jsFilePath!, sourceMapFilePath, declarationFilePath!, declarationMapPath, buildInfoPath, host, resolvedRefOpts.options); + const { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath } = + getOutputPathsForBundle(resolvedRefOpts.options, /*forceDtsPaths*/ true); + const node = createInputFilesWithFilePaths( + readFile, + jsFilePath!, + sourceMapFilePath, + declarationFilePath!, + declarationMapPath, + buildInfoPath, + host, + resolvedRefOpts.options, + ); (nodes || (nodes = [])).push(node); } } @@ -5234,7 +6718,11 @@ export function resolveProjectReferencePath(ref: ProjectReference): ResolvedConf * * @internal */ -export function getResolutionDiagnostic(options: CompilerOptions, { extension }: ResolvedModuleFull, { isDeclarationFile }: { isDeclarationFile: SourceFile["isDeclarationFile"] }): DiagnosticMessage | undefined { +export function getResolutionDiagnostic( + options: CompilerOptions, + { extension }: ResolvedModuleFull, + { isDeclarationFile }: { isDeclarationFile: SourceFile["isDeclarationFile"]; }, +): DiagnosticMessage | undefined { switch (extension) { case Extension.Ts: case Extension.Dts: @@ -5262,14 +6750,17 @@ export function getResolutionDiagnostic(options: CompilerOptions, { extension }: return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set; } function needAllowJs() { - return getAllowJSCompilerOption(options) || !getStrictOptionValue(options, "noImplicitAny") ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type; + return getAllowJSCompilerOption(options) || !getStrictOptionValue(options, "noImplicitAny") ? undefined + : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type; } function needResolveJsonModule() { - return getResolveJsonModule(options) ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_resolveJsonModule_is_not_used; + return getResolveJsonModule(options) ? undefined + : Diagnostics.Module_0_was_resolved_to_1_but_resolveJsonModule_is_not_used; } function needAllowArbitraryExtensions() { // But don't report the allowArbitraryExtensions error from declaration files (no reason to report it, since the import doesn't have a runtime component) - return isDeclarationFile || options.allowArbitraryExtensions ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_allowArbitraryExtensions_is_not_set; + return isDeclarationFile || options.allowArbitraryExtensions ? undefined + : Diagnostics.Module_0_was_resolved_to_1_but_allowArbitraryExtensions_is_not_set; } } @@ -5285,7 +6776,10 @@ function getModuleNames({ imports, moduleAugmentations }: SourceFile): StringLit } /** @internal */ -export function getModuleNameStringLiteralAt({ imports, moduleAugmentations }: SourceFileImportsList, index: number): StringLiteralLike { +export function getModuleNameStringLiteralAt( + { imports, moduleAugmentations }: SourceFileImportsList, + index: number, +): StringLiteralLike { if (index < imports.length) return imports[index]; let augIndex = imports.length; for (const aug of moduleAugmentations) { diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 7d6ac150c05e8..d500f54b415ed 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -107,7 +107,7 @@ export interface ResolutionCache { redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile | undefined, - reusedNames: readonly T[] | undefined + reusedNames: readonly T[] | undefined, ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; resolveLibrary( libraryName: string, @@ -132,7 +132,6 @@ export interface ResolutionCache { hasChangedAutomaticTypeDirectiveNames(): boolean; isFileWithInvalidatedNonRelativeUnresolvedImports(path: Path): boolean; - startCachingPerDirectoryResolution(): void; finishCachingPerDirectoryResolution(newProgram: Program | undefined, oldProgram: Program | undefined): void; @@ -162,10 +161,14 @@ interface ResolutionWithResolvedFileName { } /** @internal */ -export interface CachedResolvedModuleWithFailedLookupLocations extends ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations { +export interface CachedResolvedModuleWithFailedLookupLocations + extends ResolvedModuleWithFailedLookupLocations, ResolutionWithFailedLookupLocations +{ } -interface CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations extends ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations { +interface CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations + extends ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolutionWithFailedLookupLocations +{ } /** @internal */ @@ -173,7 +176,11 @@ export interface ResolutionCacheHost extends MinimalResolutionCacheHost { toPath(fileName: string): Path; getCanonicalFileName: GetCanonicalFileName; getCompilationSettings(): CompilerOptions; - watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher; + watchDirectoryOfFailedLookupLocation( + directory: string, + cb: DirectoryWatcherCallback, + flags: WatchDirectoryFlags, + ): FileWatcher; watchAffectingFileLocation(file: string, cb: FileWatcherCallback): FileWatcher; onInvalidatedResolution(): void; watchTypeRootsDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher; @@ -220,9 +227,9 @@ export function removeIgnoredPath(path: Path): Path | undefined { return removeSuffix(path, "/.staging") as Path; } - return some(ignoredPaths, searchPath => stringContains(path, searchPath)) ? - undefined : - path; + return some(ignoredPaths, searchPath => stringContains(path, searchPath)) + ? undefined + : path; } function perceivedOsRootLengthForWatching(pathComponents: Readonly, length: number) { @@ -230,17 +237,21 @@ function perceivedOsRootLengthForWatching(pathComponents: Readonly, fileOrDirComponents: Readonly) { +function isInDirectoryPath( + dirComponents: Readonly, + fileOrDirComponents: Readonly, +) { if (fileOrDirComponents.length < fileOrDirComponents.length) return false; for (let i = 0; i < dirComponents.length; i++) { if (fileOrDirComponents[i] !== dirComponents[i]) return false; @@ -300,9 +314,13 @@ export function getDirectoryToWatchFailedLookupLocation( ): DirectoryOfFailedLookupWatch | undefined { const failedLookupPathComponents: Readonly = getPathComponents(failedLookupLocationPath); // Ensure failed look up is normalized path - failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? normalizePath(failedLookupLocation) : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory()); + failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? normalizePath(failedLookupLocation) + : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory()); const failedLookupComponents: readonly string[] = getPathComponents(failedLookupLocation); - const perceivedOsRootLength = perceivedOsRootLengthForWatching(failedLookupPathComponents, failedLookupPathComponents.length); + const perceivedOsRootLength = perceivedOsRootLengthForWatching( + failedLookupPathComponents, + failedLookupPathComponents.length, + ); if (failedLookupPathComponents.length <= perceivedOsRootLength + 1) return undefined; // If directory path contains node module, get the most parent node_modules directory for watching const nodeModulesIndex = failedLookupPathComponents.indexOf("node_modules" as Path); @@ -310,7 +328,11 @@ export function getDirectoryToWatchFailedLookupLocation( if (isInDirectoryPath(rootPathComponents, failedLookupPathComponents)) { if (failedLookupPathComponents.length > rootPathComponents.length + 1) { // Instead of watching root, watch directory in root to avoid watching excluded directories not needed for module resolution - return getDirectoryOfFailedLookupWatch(failedLookupComponents, failedLookupPathComponents, Math.max(rootPathComponents.length + 1, perceivedOsRootLength + 1)); + return getDirectoryOfFailedLookupWatch( + failedLookupComponents, + failedLookupPathComponents, + Math.max(rootPathComponents.length + 1, perceivedOsRootLength + 1), + ); } else { // Always watch root directory non recursively @@ -362,7 +384,7 @@ function getDirectoryOfFailedLookupWatch( dirComponents: readonly string[], dirPathComponents: Readonly, length: number, - nonRecursive?: boolean + nonRecursive?: boolean, ): DirectoryOfFailedLookupWatch { return { dir: getPathFromPathComponents(dirComponents, length), @@ -385,7 +407,8 @@ export function getDirectoryToWatchFailedLookupLocationFromTypeRoot( // Because this is called when we are watching typeRoot, we dont need additional check whether typeRoot is not say c:/users/node_modules/@types when root is c:/ return rootPath; } - typeRoot = isRootedDiskPath(typeRoot) ? normalizePath(typeRoot) : getNormalizedAbsolutePath(typeRoot, getCurrentDirectory()); + typeRoot = isRootedDiskPath(typeRoot) ? normalizePath(typeRoot) + : getNormalizedAbsolutePath(typeRoot, getCurrentDirectory()); const toWatch = getDirectoryToWatchFromFailedLookupLocationDirectory( getPathComponents(typeRoot), typeRootPathComponents, @@ -398,11 +421,14 @@ export function getDirectoryToWatchFailedLookupLocationFromTypeRoot( } /** @internal */ -export function getRootDirectoryOfResolutionCache(rootDirForResolution: string, getCurrentDirectory: () => string | undefined) { +export function getRootDirectoryOfResolutionCache( + rootDirForResolution: string, + getCurrentDirectory: () => string | undefined, +) { const normalized = getNormalizedAbsolutePath(rootDirForResolution, getCurrentDirectory()); - return !isDiskPathRoot(normalized) ? - removeTrailingDirectorySeparator(normalized) : - normalized; + return !isDiskPathRoot(normalized) + ? removeTrailingDirectorySeparator(normalized) + : normalized; } /** @internal */ @@ -410,11 +436,17 @@ export function getRootPathSplitLength(rootPath: Path) { return rootPath.split(directorySeparator).length - (hasTrailingDirectorySeparator(rootPath) ? 1 : 0); } -type GetResolutionWithResolvedFileName = - (resolution: T) => R | undefined; +type GetResolutionWithResolvedFileName< + T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName, +> = (resolution: T) => R | undefined; /** @internal */ -export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string, logChangesWhenResolvingModule: boolean): ResolutionCache { +export function createResolutionCache( + resolutionHost: ResolutionCacheHost, + rootDirForResolution: string, + logChangesWhenResolvingModule: boolean, +): ResolutionCache { let filesWithChangedSetOfUnresolvedImports: Path[] | undefined; let filesWithInvalidatedResolutions: Set | undefined; let filesWithInvalidatedNonRelativeUnresolvedImports: ReadonlyMap | undefined; @@ -446,7 +478,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD resolutionHost.getCompilationSettings(), ); - const resolvedTypeReferenceDirectives = new Map>(); + const resolvedTypeReferenceDirectives = new Map< + Path, + ModeAwareCache + >(); const typeReferenceDirectiveResolutionCache = createTypeReferenceDirectiveResolutionCache( getCurrentDirectory(), resolutionHost.getCanonicalFileName, @@ -502,7 +537,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD return resolution.resolvedModule; } - function getResolvedTypeReferenceDirective(resolution: CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations) { + function getResolvedTypeReferenceDirective( + resolution: CachedResolvedTypeReferenceDirectiveWithFailedLookupLocations, + ) { return resolution.resolvedTypeReferenceDirective; } @@ -569,12 +606,14 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD const collected = filesWithInvalidatedResolutions; filesWithInvalidatedResolutions = undefined; return { - hasInvalidatedResolutions: path => customHasInvalidatedResolutions(path) || - allModuleAndTypeResolutionsAreInvalidated || - !!collected?.has(path) || - isFileWithInvalidatedNonRelativeUnresolvedImports(path), - hasInvalidatedLibResolutions: libFileName => customHasInvalidatedLibResolutions(libFileName) || - !!resolvedLibraries?.get(libFileName)?.isInvalidated, + hasInvalidatedResolutions: path => + customHasInvalidatedResolutions(path) + || allModuleAndTypeResolutionsAreInvalidated + || !!collected?.has(path) + || isFileWithInvalidatedNonRelativeUnresolvedImports(path), + hasInvalidatedLibResolutions: libFileName => + customHasInvalidatedLibResolutions(libFileName) + || !!resolvedLibraries?.get(libFileName)?.isInvalidated, }; } @@ -593,7 +632,13 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD if (!newProgram?.resolvedLibReferences?.has(libFileName)) { stopWatchFailedLookupLocationOfResolution( resolution, - resolutionHost.toPath(getInferredLibraryNameResolveFrom(newProgram!.getCompilerOptions(), getCurrentDirectory(), libFileName)), + resolutionHost.toPath( + getInferredLibraryNameResolveFrom( + newProgram!.getCompilerOptions(), + getCurrentDirectory(), + libFileName, + ), + ), getResolvedModule, ); resolvedLibraries.delete(libFileName); @@ -646,9 +691,23 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD hasChangedAutomaticTypeDirectiveNames = false; } - function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, redirectedReference?: ResolvedProjectReference, mode?: ResolutionMode): CachedResolvedModuleWithFailedLookupLocations { + function resolveModuleName( + moduleName: string, + containingFile: string, + compilerOptions: CompilerOptions, + redirectedReference?: ResolvedProjectReference, + mode?: ResolutionMode, + ): CachedResolvedModuleWithFailedLookupLocations { const host = resolutionHost.getCompilerHost?.() || resolutionHost; - const primaryResult = ts_resolveModuleName(moduleName, containingFile, compilerOptions, host, moduleResolutionCache, redirectedReference, mode); + const primaryResult = ts_resolveModuleName( + moduleName, + containingFile, + compilerOptions, + host, + moduleResolutionCache, + redirectedReference, + mode, + ); // return result immediately only if global cache support is not enabled or if it is .ts, .tsx or .d.ts if (!resolutionHost.getGlobalCache) { return primaryResult; @@ -656,23 +715,36 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD // otherwise try to load typings from @types const globalCache = resolutionHost.getGlobalCache(); - if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) { + if ( + globalCache !== undefined && !isExternalModuleNameRelative(moduleName) + && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension)) + ) { // create different collection of failed lookup locations for second pass // if it will fail and we've already found something during the first pass - we don't want to pollute its results - const { resolvedModule, failedLookupLocations, affectingLocations, resolutionDiagnostics } = loadModuleFromGlobalCache( - Debug.checkDefined(resolutionHost.globalCacheResolutionModuleName)(moduleName), - resolutionHost.projectName, - compilerOptions, - host, - globalCache, - moduleResolutionCache, - ); + const { resolvedModule, failedLookupLocations, affectingLocations, resolutionDiagnostics } = + loadModuleFromGlobalCache( + Debug.checkDefined(resolutionHost.globalCacheResolutionModuleName)(moduleName), + resolutionHost.projectName, + compilerOptions, + host, + globalCache, + moduleResolutionCache, + ); if (resolvedModule) { // Modify existing resolution so its saved in the directory cache as well (primaryResult.resolvedModule as any) = resolvedModule; - primaryResult.failedLookupLocations = updateResolutionField(primaryResult.failedLookupLocations, failedLookupLocations); - primaryResult.affectingLocations = updateResolutionField(primaryResult.affectingLocations, affectingLocations); - primaryResult.resolutionDiagnostics = updateResolutionField(primaryResult.resolutionDiagnostics, resolutionDiagnostics); + primaryResult.failedLookupLocations = updateResolutionField( + primaryResult.failedLookupLocations, + failedLookupLocations, + ); + primaryResult.affectingLocations = updateResolutionField( + primaryResult.affectingLocations, + affectingLocations, + ); + primaryResult.resolutionDiagnostics = updateResolutionField( + primaryResult.resolutionDiagnostics, + resolutionDiagnostics, + ); return primaryResult; } } @@ -688,17 +760,23 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD ): ResolutionLoader { return { nameAndMode: moduleResolutionNameAndModeGetter, - resolve: (moduleName, resoluionMode) => resolveModuleName( - moduleName, - containingFile, - options, - redirectedReference, - resoluionMode, - ), + resolve: (moduleName, resoluionMode) => + resolveModuleName( + moduleName, + containingFile, + options, + redirectedReference, + resoluionMode, + ), }; } - interface ResolveNamesWithLocalCacheInput { + interface ResolveNamesWithLocalCacheInput< + Entry, + SourceFile, + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + > { entries: readonly Entry[]; containingFile: string; containingSourceFile: SourceFile; @@ -712,23 +790,37 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD logChanges?: boolean; deferWatchingNonRelativeResolution: boolean; } - function resolveNamesWithLocalCache({ - entries, containingFile, containingSourceFile, redirectedReference, options, - perFileCache, reusedNames, - loader, getResolutionWithResolvedFileName, deferWatchingNonRelativeResolution, - shouldRetryResolution, logChanges, + function resolveNamesWithLocalCache< + Entry, + SourceFile, + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + >({ + entries, + containingFile, + containingSourceFile, + redirectedReference, + options, + perFileCache, + reusedNames, + loader, + getResolutionWithResolvedFileName, + deferWatchingNonRelativeResolution, + shouldRetryResolution, + logChanges, }: ResolveNamesWithLocalCacheInput): readonly T[] { const path = resolutionHost.toPath(containingFile); const resolutionsInFile = perFileCache.get(path) || perFileCache.set(path, createModeAwareCache()).get(path)!; const resolvedModules: T[] = []; - const hasInvalidatedNonRelativeUnresolvedImport = logChanges && isFileWithInvalidatedNonRelativeUnresolvedImports(path); + const hasInvalidatedNonRelativeUnresolvedImport = logChanges + && isFileWithInvalidatedNonRelativeUnresolvedImports(path); // All the resolutions in this file are invalidated if this file wasn't resolved using same redirect const program = resolutionHost.getCurrentProgram(); const oldRedirect = program && program.getResolvedProjectReferenceToRedirect(containingFile); - const unmatchedRedirects = oldRedirect ? - !redirectedReference || redirectedReference.sourceFile.path !== oldRedirect.sourceFile.path : - !!redirectedReference; + const unmatchedRedirects = oldRedirect + ? !redirectedReference || redirectedReference.sourceFile.path !== oldRedirect.sourceFile.path + : !!redirectedReference; const seenNamesInFile = createModeAwareCache(); for (const entry of entries) { @@ -736,22 +828,39 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD const mode = loader.nameAndMode.getMode(entry, containingSourceFile); let resolution = resolutionsInFile.get(name, mode); // Resolution is valid if it is present and not invalidated - if (!seenNamesInFile.has(name, mode) && - (allModuleAndTypeResolutionsAreInvalidated || unmatchedRedirects || !resolution || resolution.isInvalidated || + if ( + !seenNamesInFile.has(name, mode) + && (allModuleAndTypeResolutionsAreInvalidated || unmatchedRedirects || !resolution + || resolution.isInvalidated // If the name is unresolved import that was invalidated, recalculate - (hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) && shouldRetryResolution(resolution)))) { + || (hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) + && shouldRetryResolution(resolution))) + ) { const existingResolution = resolution; resolution = loader.resolve(name, mode); if (resolutionHost.onDiscoveredSymlink && resolutionIsSymlink(resolution)) { resolutionHost.onDiscoveredSymlink(); } resolutionsInFile.set(name, mode, resolution); - watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution, path, getResolutionWithResolvedFileName, deferWatchingNonRelativeResolution); + watchFailedLookupLocationsOfExternalModuleResolutions( + name, + resolution, + path, + getResolutionWithResolvedFileName, + deferWatchingNonRelativeResolution, + ); if (existingResolution) { - stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolutionWithResolvedFileName); + stopWatchFailedLookupLocationOfResolution( + existingResolution, + path, + getResolutionWithResolvedFileName, + ); } - if (logChanges && filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) { + if ( + logChanges && filesWithChangedSetOfUnresolvedImports + && !resolutionIsEqualTo(existingResolution, resolution) + ) { filesWithChangedSetOfUnresolvedImports.push(path); // reset log changes to avoid recording the same file multiple times logChanges = false; @@ -763,21 +872,26 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD const resolved = getResolutionWithResolvedFileName(resolution!); trace( host, - perFileCache === resolvedModuleNames as unknown ? - resolved?.resolvedFileName ? - resolved.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 : - Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved : - resolved?.resolvedFileName ? - resolved.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 : - Diagnostics.Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_not_resolved, + perFileCache === resolvedModuleNames as unknown + ? resolved?.resolvedFileName + ? resolved.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 + : Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved + : resolved?.resolvedFileName + ? resolved.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 + : Diagnostics + .Reusing_resolution_of_type_reference_directive_0_from_1_of_old_program_it_was_not_resolved, name, containingFile, resolved?.resolvedFileName, - resolved?.packageId && packageIdToString(resolved.packageId) + resolved?.packageId && packageIdToString(resolved.packageId), ); } } @@ -785,11 +899,13 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD seenNamesInFile.set(name, mode, true); resolvedModules.push(resolution); } - reusedNames?.forEach(entry => seenNamesInFile.set( - loader.nameAndMode.getName(entry), - loader.nameAndMode.getMode(entry, containingSourceFile), - true, - )); + reusedNames?.forEach(entry => + seenNamesInFile.set( + loader.nameAndMode.getName(entry), + loader.nameAndMode.getMode(entry, containingSourceFile), + true, + ) + ); if (resolutionsInFile.size() !== seenNamesInFile.size()) { // Stop watching and remove the unused name resolutionsInFile.forEach((resolution, name, mode) => { @@ -826,8 +942,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile | undefined, - reusedNames: readonly T[] | undefined - ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]{ + reusedNames: readonly T[] | undefined, + ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { return resolveNamesWithLocalCache({ entries: typeDirectiveReferences, containingFile, @@ -841,7 +957,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD redirectedReference, options, resolutionHost.getCompilerHost?.() || resolutionHost, - typeReferenceDirectiveResolutionCache + typeReferenceDirectiveResolutionCache, ), getResolutionWithResolvedFileName: getResolvedTypeReferenceDirective, shouldRetryResolution: resolution => resolution.resolvedTypeReferenceDirective === undefined, @@ -871,7 +987,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD options, ), getResolutionWithResolvedFileName: getResolvedModule, - shouldRetryResolution: resolution => !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension), + shouldRetryResolution: resolution => + !resolution.resolvedModule || !resolutionExtensionIsTSOrJson(resolution.resolvedModule.extension), logChanges: logChangesWhenResolvingModule, deferWatchingNonRelativeResolution: true, // Defer non relative resolution watch because we could be using ambient modules }); @@ -889,7 +1006,13 @@ 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, + getResolvedModule, + /*deferWatchingNonRelativeResolution*/ false, + ); resolvedLibraries.set(libFileName, resolution); if (existingResolution) { stopWatchFailedLookupLocationOfResolution(existingResolution, path, getResolvedModule); @@ -900,15 +1023,17 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD const resolved = getResolvedModule(resolution); trace( host, - resolved?.resolvedFileName ? - resolved.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 : - Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved, + resolved?.resolvedFileName + ? resolved.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 + : Diagnostics.Reusing_resolution_of_module_0_from_1_of_old_program_it_was_not_resolved, libraryName, resolveFrom, resolved?.resolvedFileName, - resolved?.packageId && packageIdToString(resolved.packageId) + resolved?.packageId && packageIdToString(resolved.packageId), ); } } @@ -927,7 +1052,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD return endsWith(dirPath, "/node_modules/@types"); } - function watchFailedLookupLocationsOfExternalModuleResolutions( + function watchFailedLookupLocationsOfExternalModuleResolutions< + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + >( name: string, resolution: T, filePath: Path, @@ -1002,7 +1130,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD watchAffectingLocationsOfResolution(resolution, !failedLookupLocations?.length && !node10Result); } - function watchAffectingLocationsOfResolution(resolution: ResolutionWithFailedLookupLocations, addToResolutionsWithOnlyAffectingLocations: boolean) { + function watchAffectingLocationsOfResolution( + resolution: ResolutionWithFailedLookupLocations, + addToResolutionsWithOnlyAffectingLocations: boolean, + ) { Debug.assert(!!resolution.refCount); const { affectingLocations } = resolution; if (!affectingLocations?.length) return; @@ -1036,9 +1167,13 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD } const paths = new Set(); paths.add(locationToWatch); - let actualWatcher = canWatchAffectingLocation(resolutionHost.toPath(locationToWatch)) ? - resolutionHost.watchAffectingFileLocation(locationToWatch, (fileName, eventKind) => { - cachedDirectoryStructureHost?.addOrDeleteFile(fileName, resolutionHost.toPath(locationToWatch), eventKind); + let actualWatcher = canWatchAffectingLocation(resolutionHost.toPath(locationToWatch)) + ? resolutionHost.watchAffectingFileLocation(locationToWatch, (fileName, eventKind) => { + cachedDirectoryStructureHost?.addOrDeleteFile( + fileName, + resolutionHost.toPath(locationToWatch), + eventKind, + ); const packageJsonMap = moduleResolutionCache.getPackageJsonInfoCache().getInternalMap(); paths.forEach(path => { if (watcher.resolutions) (affectingPathChecks ??= new Set()).add(path); @@ -1053,7 +1188,7 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD actualWatcher.close(); // Ensure when watching symlinked package.json, we can close the actual file watcher only once actualWatcher = noopFileWatcher; - } + }, } : actualWatcher, resolutions: forResolution ? 1 : 0, files: forResolution ? 0 : 1, @@ -1066,13 +1201,18 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD } } - function watchFailedLookupLocationOfNonRelativeModuleResolutions(resolutions: ResolutionWithFailedLookupLocations[], name: string) { + function watchFailedLookupLocationOfNonRelativeModuleResolutions( + resolutions: ResolutionWithFailedLookupLocations[], + name: string, + ) { const program = resolutionHost.getCurrentProgram(); if (!program || !program.getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name)) { resolutions.forEach(watchFailedLookupLocationOfResolution); } else { - resolutions.forEach(resolution => watchAffectingLocationsOfResolution(resolution, /*addToResolutionsWithOnlyAffectingLocations*/ true)); + resolutions.forEach(resolution => + watchAffectingLocationsOfResolution(resolution, /*addToResolutionsWithOnlyAffectingLocations*/ true) + ); } } @@ -1083,7 +1223,11 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD dirWatcher.refCount++; } else { - directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath, nonRecursive), refCount: 1, nonRecursive }); + directoryWatchesOfFailedLookups.set(dirPath, { + watcher: createDirectoryWatcher(dir, dirPath, nonRecursive), + refCount: 1, + nonRecursive, + }); } } @@ -1109,7 +1253,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD return removeAtRoot; } - function stopWatchFailedLookupLocationOfResolution( + function stopWatchFailedLookupLocationOfResolution< + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + >( resolution: T, filePath: Path, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName, @@ -1167,7 +1314,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD }, nonRecursive ? WatchDirectoryFlags.None : WatchDirectoryFlags.Recursive); } - function removeResolutionsOfFileFromCache( + function removeResolutionsOfFileFromCache< + T extends ResolutionWithFailedLookupLocations, + R extends ResolutionWithResolvedFileName, + >( cache: Map>, filePath: Path, getResolutionWithResolvedFileName: GetResolutionWithResolvedFileName, @@ -1175,7 +1325,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD // Deleted file, stop watching failed lookups for all the resolutions in the file const resolutions = cache.get(filePath); if (resolutions) { - resolutions.forEach(resolution => stopWatchFailedLookupLocationOfResolution(resolution, filePath, getResolutionWithResolvedFileName)); + resolutions.forEach(resolution => + stopWatchFailedLookupLocationOfResolution(resolution, filePath, getResolutionWithResolvedFileName) + ); cache.delete(filePath); } } @@ -1199,7 +1351,13 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath, getResolvedTypeReferenceDirective); } - function invalidateResolutions(resolutions: Set | Map | undefined, canInvalidate: (resolution: ResolutionWithFailedLookupLocations) => boolean | undefined) { + function invalidateResolutions( + resolutions: + | Set + | Map + | undefined, + canInvalidate: (resolution: ResolutionWithFailedLookupLocations) => boolean | undefined, + ) { if (!resolutions) return false; let invalidated = false; resolutions.forEach(resolution => { @@ -1208,7 +1366,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD for (const containingFilePath of Debug.checkDefined(resolution.files)) { (filesWithInvalidatedResolutions ??= new Set()).add(containingFilePath); // When its a file with inferred types resolution, invalidate type reference directive resolution - hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames || endsWith(containingFilePath, inferredTypesContainingFile); + hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames + || endsWith(containingFilePath, inferredTypesContainingFile); } }); return invalidated; @@ -1218,19 +1377,27 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD removeResolutionsOfFile(filePath); // Resolution is invalidated if the resulting file name is same as the deleted file path const prevHasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames; - if (invalidateResolutions(resolvedFileToResolution.get(filePath), returnTrue) && - hasChangedAutomaticTypeDirectiveNames && - !prevHasChangedAutomaticTypeDirectiveNames) { + if ( + invalidateResolutions(resolvedFileToResolution.get(filePath), returnTrue) + && hasChangedAutomaticTypeDirectiveNames + && !prevHasChangedAutomaticTypeDirectiveNames + ) { resolutionHost.onChangedAutomaticTypeDirectiveNames(); } } function setFilesWithInvalidatedNonRelativeUnresolvedImports(filesMap: ReadonlyMap) { - Debug.assert(filesWithInvalidatedNonRelativeUnresolvedImports === filesMap || filesWithInvalidatedNonRelativeUnresolvedImports === undefined); + Debug.assert( + filesWithInvalidatedNonRelativeUnresolvedImports === filesMap + || filesWithInvalidatedNonRelativeUnresolvedImports === undefined, + ); filesWithInvalidatedNonRelativeUnresolvedImports = filesMap; } - function scheduleInvalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath: Path, isCreatingWatchedDirectory: boolean) { + function scheduleInvalidateResolutionOfFailedLookupLocation( + fileOrDirectoryPath: Path, + isCreatingWatchedDirectory: boolean, + ) { if (isCreatingWatchedDirectory) { // Watching directory is created // Invalidate any resolution has failed lookup in this directory @@ -1250,8 +1417,10 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD // Some file or directory in the watching directory is created // Return early if it does not have any of the watching extension or not the custom failed lookup path const dirOfFileOrDirectory = getDirectoryPath(fileOrDirectoryPath); - if (isNodeModulesAtTypesDirectory(fileOrDirectoryPath) || isNodeModulesDirectory(fileOrDirectoryPath) || - isNodeModulesAtTypesDirectory(dirOfFileOrDirectory) || isNodeModulesDirectory(dirOfFileOrDirectory)) { + if ( + isNodeModulesAtTypesDirectory(fileOrDirectoryPath) || isNodeModulesDirectory(fileOrDirectoryPath) + || isNodeModulesAtTypesDirectory(dirOfFileOrDirectory) || isNodeModulesDirectory(dirOfFileOrDirectory) + ) { // Invalidate any resolution from this directory (failedLookupChecks ||= new Set()).add(fileOrDirectoryPath); (startsWithPathChecks ||= new Set()).add(fileOrDirectoryPath); @@ -1281,7 +1450,9 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD function invalidatePackageJsonMap() { const packageJsonMap = moduleResolutionCache.getPackageJsonInfoCache().getInternalMap(); if (packageJsonMap && (failedLookupChecks || startsWithPathChecks || isInDirectoryChecks)) { - packageJsonMap.forEach((_value, path) => isInvalidatedFailedLookup(path) ? packageJsonMap.delete(path) : undefined); + packageJsonMap.forEach((_value, path) => + isInvalidatedFailedLookup(path) ? packageJsonMap.delete(path) : undefined + ); } } @@ -1313,12 +1484,16 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD return invalidated; } - invalidated = invalidateResolutions(resolutionsWithFailedLookups, canInvalidateFailedLookupResolution) || invalidated; + invalidated = invalidateResolutions(resolutionsWithFailedLookups, canInvalidateFailedLookupResolution) + || invalidated; invalidatePackageJsonMap(); failedLookupChecks = undefined; startsWithPathChecks = undefined; isInDirectoryChecks = undefined; - invalidated = invalidateResolutions(resolutionsWithOnlyAffectingLocations, canInvalidatedFailedLookupResolutionWithAffectingLocation) || invalidated; + invalidated = invalidateResolutions( + resolutionsWithOnlyAffectingLocations, + canInvalidatedFailedLookupResolutionWithAffectingLocation, + ) || invalidated; affectingPathChecks = undefined; return invalidated; } @@ -1326,19 +1501,30 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD function canInvalidateFailedLookupResolution(resolution: ResolutionWithFailedLookupLocations) { if (canInvalidatedFailedLookupResolutionWithAffectingLocation(resolution)) return true; if (!failedLookupChecks && !startsWithPathChecks && !isInDirectoryChecks) return false; - return resolution.failedLookupLocations?.some(location => isInvalidatedFailedLookup(resolutionHost.toPath(location))) || - (!!resolution.node10Result && isInvalidatedFailedLookup(resolutionHost.toPath(resolution.node10Result))); + return resolution.failedLookupLocations?.some(location => + isInvalidatedFailedLookup(resolutionHost.toPath(location)) + ) + || (!!resolution.node10Result && isInvalidatedFailedLookup(resolutionHost.toPath(resolution.node10Result))); } function isInvalidatedFailedLookup(locationPath: Path) { - return failedLookupChecks?.has(locationPath) || - firstDefinedIterator(startsWithPathChecks?.keys() || [], fileOrDirectoryPath => startsWith(locationPath, fileOrDirectoryPath) ? true : undefined) || - firstDefinedIterator(isInDirectoryChecks?.keys() || [], dirPath => locationPath.length > dirPath.length && - startsWith(locationPath, dirPath) && (isDiskPathRoot(dirPath) || locationPath[dirPath.length] === directorySeparator) ? true : undefined); + return failedLookupChecks?.has(locationPath) + || firstDefinedIterator( + startsWithPathChecks?.keys() || [], + fileOrDirectoryPath => startsWith(locationPath, fileOrDirectoryPath) ? true : undefined, + ) + || firstDefinedIterator(isInDirectoryChecks?.keys() || [], dirPath => + locationPath.length > dirPath.length + && startsWith(locationPath, dirPath) + && (isDiskPathRoot(dirPath) || locationPath[dirPath.length] === directorySeparator) ? true + : undefined); } - function canInvalidatedFailedLookupResolutionWithAffectingLocation(resolution: ResolutionWithFailedLookupLocations) { - return !!affectingPathChecks && resolution.affectingLocations?.some(location => affectingPathChecks!.has(location)); + function canInvalidatedFailedLookupResolutionWithAffectingLocation( + resolution: ResolutionWithFailedLookupLocations, + ) { + return !!affectingPathChecks + && resolution.affectingLocations?.some(location => affectingPathChecks!.has(location)); } function closeTypeRootsWatch() { @@ -1347,8 +1533,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD function createTypeRootsWatch(typeRootPath: Path, typeRoot: string): FileWatcher { // Create new watch and recursive info - return canWatchTypeRootPath(typeRootPath) ? - resolutionHost.watchTypeRootsDirectory(typeRoot, fileOrDirectory => { + return canWatchTypeRootPath(typeRootPath) + ? resolutionHost.watchTypeRootsDirectory(typeRoot, fileOrDirectory => { const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory); if (cachedDirectoryStructureHost) { // Since the file existence changed, update the sourceFiles cache @@ -1369,13 +1555,16 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD rootPath, rootPathComponents, getCurrentDirectory, - dirPath => directoryWatchesOfFailedLookups.has(dirPath) + dirPath => directoryWatchesOfFailedLookups.has(dirPath), ); if (dirPath) { - scheduleInvalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath); + scheduleInvalidateResolutionOfFailedLookupLocation( + fileOrDirectoryPath, + dirPath === fileOrDirectoryPath, + ); } - }, WatchDirectoryFlags.Recursive) : - noopFileWatcher; + }, WatchDirectoryFlags.Recursive) + : noopFileWatcher; } /** @@ -1400,8 +1589,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD arrayToMap(typeRoots, tr => resolutionHost.toPath(tr)), { createNewValue: createTypeRootsWatch, - onDeleteValue: closeFileWatcher - } + onDeleteValue: closeFileWatcher, + }, ); } else { @@ -1420,7 +1609,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD function resolutionIsSymlink(resolution: ResolutionWithFailedLookupLocations) { return !!( - (resolution as ResolvedModuleWithFailedLookupLocations).resolvedModule?.originalPath || - (resolution as ResolvedTypeReferenceDirectiveWithFailedLookupLocations).resolvedTypeReferenceDirective?.originalPath + (resolution as ResolvedModuleWithFailedLookupLocations).resolvedModule?.originalPath + || (resolution as ResolvedTypeReferenceDirectiveWithFailedLookupLocations).resolvedTypeReferenceDirective + ?.originalPath ); -} \ No newline at end of file +} diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index ccba86326b1cf..c104894ad8412 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -292,8 +292,10 @@ const textToToken = new Map(Object.entries({ Codepoint ranges for ES3 Identifiers are extracted from the Unicode 3.0.0 specification at: http://www.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.txt */ -const unicodeES3IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1610, 1649, 1747, 1749, 1749, 1765, 1766, 1786, 1788, 1808, 1808, 1810, 1836, 1920, 1957, 2309, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2784, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3294, 3294, 3296, 3297, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3424, 3425, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, 3840, 3840, 3904, 3911, 3913, 3946, 3976, 3979, 4096, 4129, 4131, 4135, 4137, 4138, 4176, 4181, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6067, 6176, 6263, 6272, 6312, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8319, 8319, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12346, 12353, 12436, 12445, 12446, 12449, 12538, 12540, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65138, 65140, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; -const unicodeES3IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 768, 846, 864, 866, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1155, 1158, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1441, 1443, 1465, 1467, 1469, 1471, 1471, 1473, 1474, 1476, 1476, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1621, 1632, 1641, 1648, 1747, 1749, 1756, 1759, 1768, 1770, 1773, 1776, 1788, 1808, 1836, 1840, 1866, 1920, 1968, 2305, 2307, 2309, 2361, 2364, 2381, 2384, 2388, 2392, 2403, 2406, 2415, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2492, 2494, 2500, 2503, 2504, 2507, 2509, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2562, 2562, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2649, 2652, 2654, 2654, 2662, 2676, 2689, 2691, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2784, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2876, 2883, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2913, 2918, 2927, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3031, 3031, 3047, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3134, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3168, 3169, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3262, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3297, 3302, 3311, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3390, 3395, 3398, 3400, 3402, 3405, 3415, 3415, 3424, 3425, 3430, 3439, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3805, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3946, 3953, 3972, 3974, 3979, 3984, 3991, 3993, 4028, 4038, 4038, 4096, 4129, 4131, 4135, 4137, 4138, 4140, 4146, 4150, 4153, 4160, 4169, 4176, 4185, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 4969, 4977, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6099, 6112, 6121, 6160, 6169, 6176, 6263, 6272, 6313, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8319, 8319, 8400, 8412, 8417, 8417, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12346, 12353, 12436, 12441, 12442, 12445, 12446, 12449, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65056, 65059, 65075, 65076, 65101, 65103, 65136, 65138, 65140, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; +// dprint-ignore +const unicodeES3IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1610, 1649, 1747, 1749, 1749, 1765, 1766, 1786, 1788, 1808, 1808, 1810, 1836, 1920, 1957, 2309, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2784, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3294, 3294, 3296, 3297, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3424, 3425, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, 3840, 3840, 3904, 3911, 3913, 3946, 3976, 3979, 4096, 4129, 4131, 4135, 4137, 4138, 4176, 4181, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6067, 6176, 6263, 6272, 6312, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8319, 8319, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12346, 12353, 12436, 12445, 12446, 12449, 12538, 12540, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65138, 65140, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500 ]; +// dprint-ignore +const unicodeES3IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 543, 546, 563, 592, 685, 688, 696, 699, 705, 720, 721, 736, 740, 750, 750, 768, 846, 864, 866, 890, 890, 902, 902, 904, 906, 908, 908, 910, 929, 931, 974, 976, 983, 986, 1011, 1024, 1153, 1155, 1158, 1164, 1220, 1223, 1224, 1227, 1228, 1232, 1269, 1272, 1273, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1441, 1443, 1465, 1467, 1469, 1471, 1471, 1473, 1474, 1476, 1476, 1488, 1514, 1520, 1522, 1569, 1594, 1600, 1621, 1632, 1641, 1648, 1747, 1749, 1756, 1759, 1768, 1770, 1773, 1776, 1788, 1808, 1836, 1840, 1866, 1920, 1968, 2305, 2307, 2309, 2361, 2364, 2381, 2384, 2388, 2392, 2403, 2406, 2415, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2492, 2494, 2500, 2503, 2504, 2507, 2509, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2562, 2562, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2649, 2652, 2654, 2654, 2662, 2676, 2689, 2691, 2693, 2699, 2701, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2784, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2870, 2873, 2876, 2883, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2913, 2918, 2927, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 2997, 2999, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3031, 3031, 3047, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3134, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3168, 3169, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3262, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3297, 3302, 3311, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3368, 3370, 3385, 3390, 3395, 3398, 3400, 3402, 3405, 3415, 3415, 3424, 3425, 3430, 3439, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3805, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3946, 3953, 3972, 3974, 3979, 3984, 3991, 3993, 4028, 4038, 4038, 4096, 4129, 4131, 4135, 4137, 4138, 4140, 4146, 4150, 4153, 4160, 4169, 4176, 4185, 4256, 4293, 4304, 4342, 4352, 4441, 4447, 4514, 4520, 4601, 4608, 4614, 4616, 4678, 4680, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4742, 4744, 4744, 4746, 4749, 4752, 4782, 4784, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4814, 4816, 4822, 4824, 4846, 4848, 4878, 4880, 4880, 4882, 4885, 4888, 4894, 4896, 4934, 4936, 4954, 4969, 4977, 5024, 5108, 5121, 5740, 5743, 5750, 5761, 5786, 5792, 5866, 6016, 6099, 6112, 6121, 6160, 6169, 6176, 6263, 6272, 6313, 7680, 7835, 7840, 7929, 7936, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8319, 8319, 8400, 8412, 8417, 8417, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8497, 8499, 8505, 8544, 8579, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12346, 12353, 12436, 12441, 12442, 12445, 12446, 12449, 12542, 12549, 12588, 12593, 12686, 12704, 12727, 13312, 19893, 19968, 40869, 40960, 42124, 44032, 55203, 63744, 64045, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65056, 65059, 65075, 65076, 65101, 65103, 65136, 65138, 65140, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65381, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500 ]; /* As per ECMAScript Language Specification 5th Edition, Section 7.6: ISyntaxToken Names and Identifiers @@ -317,8 +319,10 @@ const unicodeES3IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 2 Codepoint ranges for ES5 Identifiers are extracted from the Unicode 6.2 specification at: http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt */ -const unicodeES5IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2208, 2208, 2210, 2220, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, 7413, 7414, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; -const unicodeES5IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1520, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2048, 2093, 2112, 2139, 2208, 2208, 2210, 2220, 2276, 2302, 2304, 2403, 2406, 2415, 2417, 2423, 2425, 2431, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3161, 3168, 3171, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3396, 3398, 3400, 3402, 3406, 3415, 3415, 3424, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6263, 6272, 6314, 6320, 6389, 6400, 6428, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6617, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7376, 7378, 7380, 7414, 7424, 7654, 7676, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 11823, 11823, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12442, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42647, 42655, 42737, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43047, 43072, 43123, 43136, 43204, 43216, 43225, 43232, 43255, 43259, 43259, 43264, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43643, 43648, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65062, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, ]; +// dprint-ignore +const unicodeES5IdentifierStart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2208, 2208, 2210, 2220, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, 7413, 7414, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500 ]; +// dprint-ignore +const unicodeES5IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1319, 1329, 1366, 1369, 1369, 1377, 1415, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1520, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2048, 2093, 2112, 2139, 2208, 2208, 2210, 2220, 2276, 2302, 2304, 2403, 2406, 2415, 2417, 2423, 2425, 2431, 2433, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3073, 3075, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, 3125, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3161, 3168, 3171, 3174, 3183, 3202, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3330, 3331, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3396, 3398, 3400, 3402, 3406, 3415, 3415, 3424, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3769, 3771, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4992, 5007, 5024, 5108, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6263, 6272, 6314, 6320, 6389, 6400, 6428, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6617, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7376, 7378, 7380, 7414, 7424, 7654, 7676, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8204, 8205, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 11823, 11823, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12442, 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40908, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42647, 42655, 42737, 42775, 42783, 42786, 42888, 42891, 42894, 42896, 42899, 42912, 42922, 43000, 43047, 43072, 43123, 43136, 43204, 43216, 43225, 43232, 43255, 43259, 43259, 43264, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43643, 43648, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43968, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65062, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500 ]; /** * Generated by scripts/regenerate-unicode-identifier-parts.js on node v12.4.0 with unicode 12.1 @@ -326,7 +330,9 @@ const unicodeES5IdentifierPart = [170, 170, 181, 181, 186, 186, 192, 214, 216, 2 * unicodeESNextIdentifierStart corresponds to the ID_Start and Other_ID_Start property, and * unicodeESNextIdentifierPart corresponds to ID_Continue, Other_ID_Continue, plus ID_Start and Other_ID_Start */ +// dprint-ignore const unicodeESNextIdentifierStart = [65, 90, 97, 122, 170, 170, 181, 181, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 880, 884, 886, 887, 890, 893, 895, 895, 902, 902, 904, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1488, 1514, 1519, 1522, 1568, 1610, 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2144, 2154, 2208, 2228, 2230, 2237, 2308, 2361, 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2432, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, 2544, 2545, 2556, 2556, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, 2809, 2809, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3133, 3133, 3160, 3162, 3168, 3169, 3200, 3200, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, 3346, 3386, 3389, 3389, 3406, 3406, 3412, 3414, 3423, 3425, 3450, 3455, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3760, 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3807, 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5900, 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6264, 6272, 6312, 6314, 6314, 6320, 6389, 6400, 6430, 6480, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6656, 6678, 6688, 6740, 6823, 6823, 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7098, 7141, 7168, 7203, 7245, 7247, 7258, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7401, 7404, 7406, 7411, 7413, 7414, 7418, 7418, 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11502, 11506, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 12293, 12295, 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, 12443, 12447, 12449, 12538, 12540, 12543, 12549, 12591, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40943, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, 42560, 42606, 42623, 42653, 42656, 42735, 42775, 42783, 42786, 42888, 42891, 42943, 42946, 42950, 42999, 43009, 43011, 43013, 43015, 43018, 43020, 43042, 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, 43261, 43262, 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, 43471, 43471, 43488, 43492, 43494, 43503, 43514, 43518, 43520, 43560, 43584, 43586, 43588, 43595, 43616, 43638, 43642, 43642, 43646, 43695, 43697, 43697, 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, 43739, 43741, 43744, 43754, 43762, 43764, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43879, 43888, 44002, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66335, 66349, 66378, 66384, 66421, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 67072, 67382, 67392, 67413, 67424, 67431, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68096, 68112, 68115, 68117, 68119, 68121, 68149, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68324, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68899, 69376, 69404, 69415, 69415, 69424, 69445, 69600, 69622, 69635, 69687, 69763, 69807, 69840, 69864, 69891, 69926, 69956, 69956, 69968, 70002, 70006, 70006, 70019, 70066, 70081, 70084, 70106, 70106, 70108, 70108, 70144, 70161, 70163, 70187, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70366, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70461, 70461, 70480, 70480, 70493, 70497, 70656, 70708, 70727, 70730, 70751, 70751, 70784, 70831, 70852, 70853, 70855, 70855, 71040, 71086, 71128, 71131, 71168, 71215, 71236, 71236, 71296, 71338, 71352, 71352, 71424, 71450, 71680, 71723, 71840, 71903, 71935, 71935, 72096, 72103, 72106, 72144, 72161, 72161, 72163, 72163, 72192, 72192, 72203, 72242, 72250, 72250, 72272, 72272, 72284, 72329, 72349, 72349, 72384, 72440, 72704, 72712, 72714, 72750, 72768, 72768, 72818, 72847, 72960, 72966, 72968, 72969, 72971, 73008, 73030, 73030, 73056, 73061, 73063, 73064, 73066, 73097, 73112, 73112, 73440, 73458, 73728, 74649, 74752, 74862, 74880, 75075, 77824, 78894, 82944, 83526, 92160, 92728, 92736, 92766, 92880, 92909, 92928, 92975, 92992, 92995, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94032, 94032, 94099, 94111, 94176, 94177, 94179, 94179, 94208, 100343, 100352, 101106, 110592, 110878, 110928, 110930, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 123136, 123180, 123191, 123197, 123214, 123214, 123584, 123627, 124928, 125124, 125184, 125251, 125259, 125259, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 131072, 173782, 173824, 177972, 177984, 178205, 178208, 183969, 183984, 191456, 194560, 195101]; +// dprint-ignore const unicodeESNextIdentifierPart = [48, 57, 65, 90, 95, 95, 97, 122, 170, 170, 181, 181, 183, 183, 186, 186, 192, 214, 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, 768, 884, 886, 887, 890, 893, 895, 895, 902, 906, 908, 908, 910, 929, 931, 1013, 1015, 1153, 1155, 1159, 1162, 1327, 1329, 1366, 1369, 1369, 1376, 1416, 1425, 1469, 1471, 1471, 1473, 1474, 1476, 1477, 1479, 1479, 1488, 1514, 1519, 1522, 1552, 1562, 1568, 1641, 1646, 1747, 1749, 1756, 1759, 1768, 1770, 1788, 1791, 1791, 1808, 1866, 1869, 1969, 1984, 2037, 2042, 2042, 2045, 2045, 2048, 2093, 2112, 2139, 2144, 2154, 2208, 2228, 2230, 2237, 2259, 2273, 2275, 2403, 2406, 2415, 2417, 2435, 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, 2486, 2489, 2492, 2500, 2503, 2504, 2507, 2510, 2519, 2519, 2524, 2525, 2527, 2531, 2534, 2545, 2556, 2556, 2558, 2558, 2561, 2563, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, 2610, 2611, 2613, 2614, 2616, 2617, 2620, 2620, 2622, 2626, 2631, 2632, 2635, 2637, 2641, 2641, 2649, 2652, 2654, 2654, 2662, 2677, 2689, 2691, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, 2738, 2739, 2741, 2745, 2748, 2757, 2759, 2761, 2763, 2765, 2768, 2768, 2784, 2787, 2790, 2799, 2809, 2815, 2817, 2819, 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, 2869, 2873, 2876, 2884, 2887, 2888, 2891, 2893, 2902, 2903, 2908, 2909, 2911, 2915, 2918, 2927, 2929, 2929, 2946, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, 3006, 3010, 3014, 3016, 3018, 3021, 3024, 3024, 3031, 3031, 3046, 3055, 3072, 3084, 3086, 3088, 3090, 3112, 3114, 3129, 3133, 3140, 3142, 3144, 3146, 3149, 3157, 3158, 3160, 3162, 3168, 3171, 3174, 3183, 3200, 3203, 3205, 3212, 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3260, 3268, 3270, 3272, 3274, 3277, 3285, 3286, 3294, 3294, 3296, 3299, 3302, 3311, 3313, 3314, 3328, 3331, 3333, 3340, 3342, 3344, 3346, 3396, 3398, 3400, 3402, 3406, 3412, 3415, 3423, 3427, 3430, 3439, 3450, 3455, 3458, 3459, 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, 3530, 3530, 3535, 3540, 3542, 3542, 3544, 3551, 3558, 3567, 3570, 3571, 3585, 3642, 3648, 3662, 3664, 3673, 3713, 3714, 3716, 3716, 3718, 3722, 3724, 3747, 3749, 3749, 3751, 3773, 3776, 3780, 3782, 3782, 3784, 3789, 3792, 3801, 3804, 3807, 3840, 3840, 3864, 3865, 3872, 3881, 3893, 3893, 3895, 3895, 3897, 3897, 3902, 3911, 3913, 3948, 3953, 3972, 3974, 3991, 3993, 4028, 4038, 4038, 4096, 4169, 4176, 4253, 4256, 4293, 4295, 4295, 4301, 4301, 4304, 4346, 4348, 4680, 4682, 4685, 4688, 4694, 4696, 4696, 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, 4882, 4885, 4888, 4954, 4957, 4959, 4969, 4977, 4992, 5007, 5024, 5109, 5112, 5117, 5121, 5740, 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5880, 5888, 5900, 5902, 5908, 5920, 5940, 5952, 5971, 5984, 5996, 5998, 6000, 6002, 6003, 6016, 6099, 6103, 6103, 6108, 6109, 6112, 6121, 6155, 6157, 6160, 6169, 6176, 6264, 6272, 6314, 6320, 6389, 6400, 6430, 6432, 6443, 6448, 6459, 6470, 6509, 6512, 6516, 6528, 6571, 6576, 6601, 6608, 6618, 6656, 6683, 6688, 6750, 6752, 6780, 6783, 6793, 6800, 6809, 6823, 6823, 6832, 6845, 6912, 6987, 6992, 7001, 7019, 7027, 7040, 7155, 7168, 7223, 7232, 7241, 7245, 7293, 7296, 7304, 7312, 7354, 7357, 7359, 7376, 7378, 7380, 7418, 7424, 7673, 7675, 7957, 7960, 7965, 7968, 8005, 8008, 8013, 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, 8255, 8256, 8276, 8276, 8305, 8305, 8319, 8319, 8336, 8348, 8400, 8412, 8417, 8417, 8421, 8432, 8450, 8450, 8455, 8455, 8458, 8467, 8469, 8469, 8472, 8477, 8484, 8484, 8486, 8486, 8488, 8488, 8490, 8505, 8508, 8511, 8517, 8521, 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, 11360, 11492, 11499, 11507, 11520, 11557, 11559, 11559, 11565, 11565, 11568, 11623, 11631, 11631, 11647, 11670, 11680, 11686, 11688, 11694, 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, 11728, 11734, 11736, 11742, 11744, 11775, 12293, 12295, 12321, 12335, 12337, 12341, 12344, 12348, 12353, 12438, 12441, 12447, 12449, 12538, 12540, 12543, 12549, 12591, 12593, 12686, 12704, 12730, 12784, 12799, 13312, 19893, 19968, 40943, 40960, 42124, 42192, 42237, 42240, 42508, 42512, 42539, 42560, 42607, 42612, 42621, 42623, 42737, 42775, 42783, 42786, 42888, 42891, 42943, 42946, 42950, 42999, 43047, 43072, 43123, 43136, 43205, 43216, 43225, 43232, 43255, 43259, 43259, 43261, 43309, 43312, 43347, 43360, 43388, 43392, 43456, 43471, 43481, 43488, 43518, 43520, 43574, 43584, 43597, 43600, 43609, 43616, 43638, 43642, 43714, 43739, 43741, 43744, 43759, 43762, 43766, 43777, 43782, 43785, 43790, 43793, 43798, 43808, 43814, 43816, 43822, 43824, 43866, 43868, 43879, 43888, 44010, 44012, 44013, 44016, 44025, 44032, 55203, 55216, 55238, 55243, 55291, 63744, 64109, 64112, 64217, 64256, 64262, 64275, 64279, 64285, 64296, 64298, 64310, 64312, 64316, 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, 65024, 65039, 65056, 65071, 65075, 65076, 65101, 65103, 65136, 65140, 65142, 65276, 65296, 65305, 65313, 65338, 65343, 65343, 65345, 65370, 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, 65856, 65908, 66045, 66045, 66176, 66204, 66208, 66256, 66272, 66272, 66304, 66335, 66349, 66378, 66384, 66426, 66432, 66461, 66464, 66499, 66504, 66511, 66513, 66517, 66560, 66717, 66720, 66729, 66736, 66771, 66776, 66811, 66816, 66855, 66864, 66915, 67072, 67382, 67392, 67413, 67424, 67431, 67584, 67589, 67592, 67592, 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, 67680, 67702, 67712, 67742, 67808, 67826, 67828, 67829, 67840, 67861, 67872, 67897, 67968, 68023, 68030, 68031, 68096, 68099, 68101, 68102, 68108, 68115, 68117, 68119, 68121, 68149, 68152, 68154, 68159, 68159, 68192, 68220, 68224, 68252, 68288, 68295, 68297, 68326, 68352, 68405, 68416, 68437, 68448, 68466, 68480, 68497, 68608, 68680, 68736, 68786, 68800, 68850, 68864, 68903, 68912, 68921, 69376, 69404, 69415, 69415, 69424, 69456, 69600, 69622, 69632, 69702, 69734, 69743, 69759, 69818, 69840, 69864, 69872, 69881, 69888, 69940, 69942, 69951, 69956, 69958, 69968, 70003, 70006, 70006, 70016, 70084, 70089, 70092, 70096, 70106, 70108, 70108, 70144, 70161, 70163, 70199, 70206, 70206, 70272, 70278, 70280, 70280, 70282, 70285, 70287, 70301, 70303, 70312, 70320, 70378, 70384, 70393, 70400, 70403, 70405, 70412, 70415, 70416, 70419, 70440, 70442, 70448, 70450, 70451, 70453, 70457, 70459, 70468, 70471, 70472, 70475, 70477, 70480, 70480, 70487, 70487, 70493, 70499, 70502, 70508, 70512, 70516, 70656, 70730, 70736, 70745, 70750, 70751, 70784, 70853, 70855, 70855, 70864, 70873, 71040, 71093, 71096, 71104, 71128, 71133, 71168, 71232, 71236, 71236, 71248, 71257, 71296, 71352, 71360, 71369, 71424, 71450, 71453, 71467, 71472, 71481, 71680, 71738, 71840, 71913, 71935, 71935, 72096, 72103, 72106, 72151, 72154, 72161, 72163, 72164, 72192, 72254, 72263, 72263, 72272, 72345, 72349, 72349, 72384, 72440, 72704, 72712, 72714, 72758, 72760, 72768, 72784, 72793, 72818, 72847, 72850, 72871, 72873, 72886, 72960, 72966, 72968, 72969, 72971, 73014, 73018, 73018, 73020, 73021, 73023, 73031, 73040, 73049, 73056, 73061, 73063, 73064, 73066, 73102, 73104, 73105, 73107, 73112, 73120, 73129, 73440, 73462, 73728, 74649, 74752, 74862, 74880, 75075, 77824, 78894, 82944, 83526, 92160, 92728, 92736, 92766, 92768, 92777, 92880, 92909, 92912, 92916, 92928, 92982, 92992, 92995, 93008, 93017, 93027, 93047, 93053, 93071, 93760, 93823, 93952, 94026, 94031, 94087, 94095, 94111, 94176, 94177, 94179, 94179, 94208, 100343, 100352, 101106, 110592, 110878, 110928, 110930, 110948, 110951, 110960, 111355, 113664, 113770, 113776, 113788, 113792, 113800, 113808, 113817, 113821, 113822, 119141, 119145, 119149, 119154, 119163, 119170, 119173, 119179, 119210, 119213, 119362, 119364, 119808, 119892, 119894, 119964, 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, 120782, 120831, 121344, 121398, 121403, 121452, 121461, 121461, 121476, 121476, 121499, 121503, 121505, 121519, 122880, 122886, 122888, 122904, 122907, 122913, 122915, 122916, 122918, 122922, 123136, 123180, 123184, 123197, 123200, 123209, 123214, 123214, 123584, 123641, 124928, 125124, 125136, 125142, 125184, 125259, 125264, 125273, 126464, 126467, 126469, 126495, 126497, 126498, 126500, 126500, 126503, 126503, 126505, 126514, 126516, 126519, 126521, 126521, 126523, 126523, 126530, 126530, 126535, 126535, 126537, 126537, 126539, 126539, 126541, 126543, 126545, 126546, 126548, 126548, 126551, 126551, 126553, 126553, 126555, 126555, 126557, 126557, 126559, 126559, 126561, 126562, 126564, 126564, 126567, 126570, 126572, 126578, 126580, 126583, 126585, 126588, 126590, 126590, 126592, 126601, 126603, 126619, 126625, 126627, 126629, 126633, 126635, 126651, 131072, 173782, 173824, 177972, 177984, 178205, 178208, 183969, 183984, 191456, 194560, 195101, 917760, 917999]; /** @@ -370,17 +376,17 @@ function lookupInUnicodeMap(code: number, map: readonly number[]): boolean { } /** @internal */ export function isUnicodeIdentifierStart(code: number, languageVersion: ScriptTarget | undefined) { - return languageVersion! >= ScriptTarget.ES2015 ? - lookupInUnicodeMap(code, unicodeESNextIdentifierStart) : - languageVersion === ScriptTarget.ES5 ? lookupInUnicodeMap(code, unicodeES5IdentifierStart) : - lookupInUnicodeMap(code, unicodeES3IdentifierStart); + return languageVersion! >= ScriptTarget.ES2015 + ? lookupInUnicodeMap(code, unicodeESNextIdentifierStart) + : languageVersion === ScriptTarget.ES5 ? lookupInUnicodeMap(code, unicodeES5IdentifierStart) + : lookupInUnicodeMap(code, unicodeES3IdentifierStart); } function isUnicodeIdentifierPart(code: number, languageVersion: ScriptTarget | undefined) { - return languageVersion! >= ScriptTarget.ES2015 ? - lookupInUnicodeMap(code, unicodeESNextIdentifierPart) : - languageVersion === ScriptTarget.ES5 ? lookupInUnicodeMap(code, unicodeES5IdentifierPart) : - lookupInUnicodeMap(code, unicodeES3IdentifierPart); + return languageVersion! >= ScriptTarget.ES2015 + ? lookupInUnicodeMap(code, unicodeESNextIdentifierPart) + : languageVersion === ScriptTarget.ES5 ? lookupInUnicodeMap(code, unicodeES5IdentifierPart) + : lookupInUnicodeMap(code, unicodeES3IdentifierPart); } function makeReverseMap(source: Map): string[] { @@ -437,22 +443,42 @@ export function computeLineStarts(text: string): number[] { export function getPositionOfLineAndCharacter(sourceFile: SourceFileLike, line: number, character: number): number; /** @internal */ -export function getPositionOfLineAndCharacter(sourceFile: SourceFileLike, line: number, character: number, allowEdits?: true): number; // eslint-disable-line @typescript-eslint/unified-signatures -export function getPositionOfLineAndCharacter(sourceFile: SourceFileLike, line: number, character: number, allowEdits?: true): number { - return sourceFile.getPositionOfLineAndCharacter ? - sourceFile.getPositionOfLineAndCharacter(line, character, allowEdits) : - computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text, allowEdits); +export function getPositionOfLineAndCharacter( + sourceFile: SourceFileLike, + line: number, + character: number, + allowEdits?: true, +): number; // eslint-disable-line @typescript-eslint/unified-signatures +export function getPositionOfLineAndCharacter( + sourceFile: SourceFileLike, + line: number, + character: number, + allowEdits?: true, +): number { + return sourceFile.getPositionOfLineAndCharacter + ? sourceFile.getPositionOfLineAndCharacter(line, character, allowEdits) + : computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text, allowEdits); } /** @internal */ -export function computePositionOfLineAndCharacter(lineStarts: readonly number[], line: number, character: number, debugText?: string, allowEdits?: true): number { +export function computePositionOfLineAndCharacter( + lineStarts: readonly number[], + line: number, + character: number, + debugText?: string, + allowEdits?: true, +): number { if (line < 0 || line >= lineStarts.length) { if (allowEdits) { // Clamp line to nearest allowable value line = line < 0 ? 0 : line >= lineStarts.length ? lineStarts.length - 1 : line; } else { - Debug.fail(`Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${debugText !== undefined ? arraysEqual(lineStarts, computeLineStarts(debugText)) : "unknown"}`); + Debug.fail( + `Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${ + debugText !== undefined ? arraysEqual(lineStarts, computeLineStarts(debugText)) : "unknown" + }`, + ); } } @@ -461,7 +487,8 @@ export function computePositionOfLineAndCharacter(lineStarts: readonly number[], // Clamp to nearest allowable values to allow the underlying to be edited without crashing (accuracy is lost, instead) // TODO: Somehow track edits between file as it was during the creation of sourcemap we have and the current file and // apply them to the computed position to improve accuracy - return res > lineStarts[line + 1] ? lineStarts[line + 1] : typeof debugText === "string" && res > debugText.length ? debugText.length : res; + return res > lineStarts[line + 1] ? lineStarts[line + 1] + : typeof debugText === "string" && res > debugText.length ? debugText.length : res; } if (line < lineStarts.length - 1) { Debug.assert(res < lineStarts[line + 1]); @@ -482,7 +509,7 @@ export function computeLineAndCharacterOfPosition(lineStarts: readonly number[], const lineNumber = computeLineOfPosition(lineStarts, position); return { line: lineNumber, - character: position - lineStarts[lineNumber] + character: position - lineStarts[lineNumber], }; } @@ -530,18 +557,18 @@ export function isWhiteSpaceLike(ch: number): boolean { export function isWhiteSpaceSingleLine(ch: number): boolean { // Note: nextLine is in the Zs space, and should be considered to be a whitespace. // It is explicitly not a line-break as it isn't in the exact set specified by EcmaScript. - return ch === CharacterCodes.space || - ch === CharacterCodes.tab || - ch === CharacterCodes.verticalTab || - ch === CharacterCodes.formFeed || - ch === CharacterCodes.nonBreakingSpace || - ch === CharacterCodes.nextLine || - ch === CharacterCodes.ogham || - ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace || - ch === CharacterCodes.narrowNoBreakSpace || - ch === CharacterCodes.mathematicalSpace || - ch === CharacterCodes.ideographicSpace || - ch === CharacterCodes.byteOrderMark; + return ch === CharacterCodes.space + || ch === CharacterCodes.tab + || ch === CharacterCodes.verticalTab + || ch === CharacterCodes.formFeed + || ch === CharacterCodes.nonBreakingSpace + || ch === CharacterCodes.nextLine + || ch === CharacterCodes.ogham + || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace + || ch === CharacterCodes.narrowNoBreakSpace + || ch === CharacterCodes.mathematicalSpace + || ch === CharacterCodes.ideographicSpace + || ch === CharacterCodes.byteOrderMark; } export function isLineBreak(ch: number): boolean { @@ -556,10 +583,10 @@ export function isLineBreak(ch: number): boolean { // Only the characters in Table 3 are treated as line terminators. Other new line or line // breaking characters are treated as white space but not as line terminators. - return ch === CharacterCodes.lineFeed || - ch === CharacterCodes.carriageReturn || - ch === CharacterCodes.lineSeparator || - ch === CharacterCodes.paragraphSeparator; + return ch === CharacterCodes.lineFeed + || ch === CharacterCodes.carriageReturn + || ch === CharacterCodes.lineSeparator + || ch === CharacterCodes.paragraphSeparator; } function isDigit(ch: number): boolean { @@ -567,7 +594,8 @@ function isDigit(ch: number): boolean { } function isHexDigit(ch: number): boolean { - return isDigit(ch) || ch >= CharacterCodes.A && ch <= CharacterCodes.F || ch >= CharacterCodes.a && ch <= CharacterCodes.f; + return isDigit(ch) || ch >= CharacterCodes.A && ch <= CharacterCodes.F + || ch >= CharacterCodes.a && ch <= CharacterCodes.f; } function isCodePoint(code: number): boolean { @@ -607,7 +635,13 @@ export function couldStartTrivia(text: string, pos: number): boolean { } /** @internal */ -export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean, stopAtComments?: boolean, inJSDoc?: boolean): number { +export function skipTrivia( + text: string, + pos: number, + stopAfterLineBreak?: boolean, + stopAtComments?: boolean, + inJSDoc?: boolean, +): number { if (positionIsSynthesized(pos)) { return pos; } @@ -653,7 +687,10 @@ export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boole if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { pos += 2; while (pos < text.length) { - if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + if ( + text.charCodeAt(pos) === CharacterCodes.asterisk + && text.charCodeAt(pos + 1) === CharacterCodes.slash + ) { pos += 2; break; } @@ -720,15 +757,19 @@ function isConflictMarkerTrivia(text: string, pos: number) { } } - return ch === CharacterCodes.equals || - text.charCodeAt(pos + mergeConflictMarkerLength) === CharacterCodes.space; + return ch === CharacterCodes.equals + || text.charCodeAt(pos + mergeConflictMarkerLength) === CharacterCodes.space; } } return false; } -function scanConflictMarkerTrivia(text: string, pos: number, error?: (diag: DiagnosticMessage, pos?: number, len?: number) => void) { +function scanConflictMarkerTrivia( + text: string, + pos: number, + error?: (diag: DiagnosticMessage, pos?: number, len?: number) => void, +) { if (error) { error(Diagnostics.Merge_conflict_marker_encountered, pos, mergeConflictMarkerLength); } @@ -747,7 +788,10 @@ function scanConflictMarkerTrivia(text: string, pos: number, error?: (diag: Diag // of the next ======= or >>>>>>> marker. while (pos < len) { const currentChar = text.charCodeAt(pos); - if ((currentChar === CharacterCodes.equals || currentChar === CharacterCodes.greaterThan) && currentChar !== ch && isConflictMarkerTrivia(text, pos)) { + if ( + (currentChar === CharacterCodes.equals || currentChar === CharacterCodes.greaterThan) + && currentChar !== ch && isConflictMarkerTrivia(text, pos) + ) { break; } @@ -794,7 +838,15 @@ export function scanShebangTrivia(text: string, pos: number) { * @returns If "reduce" is true, the accumulated value. If "reduce" is false, the first truthy * return value of the callback. */ -function iterateCommentRanges(reduce: boolean, text: string, pos: number, trailing: boolean, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U | undefined) => U, state: T, initial?: U): U | undefined { +function iterateCommentRanges( + reduce: boolean, + text: string, + pos: number, + trailing: boolean, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U | undefined) => U, + state: T, + initial?: U, +): U | undefined { let pendingPos!: number; let pendingEnd!: number; let pendingKind!: CommentKind; @@ -809,7 +861,8 @@ function iterateCommentRanges(reduce: boolean, text: string, pos: number, pos = shebang.length; } } - scan: while (pos >= 0 && pos < text.length) { + scan: + while (pos >= 0 && pos < text.length) { const ch = text.charCodeAt(pos); switch (ch) { case CharacterCodes.carriageReturn: @@ -839,7 +892,8 @@ function iterateCommentRanges(reduce: boolean, text: string, pos: number, const nextChar = text.charCodeAt(pos + 1); let hasTrailingNewLine = false; if (nextChar === CharacterCodes.slash || nextChar === CharacterCodes.asterisk) { - const kind = nextChar === CharacterCodes.slash ? SyntaxKind.SingleLineCommentTrivia : SyntaxKind.MultiLineCommentTrivia; + const kind = nextChar === CharacterCodes.slash ? SyntaxKind.SingleLineCommentTrivia + : SyntaxKind.MultiLineCommentTrivia; const startPos = pos; pos += 2; if (nextChar === CharacterCodes.slash) { @@ -853,7 +907,10 @@ function iterateCommentRanges(reduce: boolean, text: string, pos: number, } else { while (pos < text.length) { - if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) { + if ( + text.charCodeAt(pos) === CharacterCodes.asterisk + && text.charCodeAt(pos + 1) === CharacterCodes.slash + ) { pos += 2; break; } @@ -863,7 +920,14 @@ function iterateCommentRanges(reduce: boolean, text: string, pos: number, if (collecting) { if (hasPendingCommentRange) { - accumulator = cb(pendingPos, pendingEnd, pendingKind, pendingHasTrailingNewLine, state, accumulator); + accumulator = cb( + pendingPos, + pendingEnd, + pendingKind, + pendingHasTrailingNewLine, + state, + accumulator, + ); if (!reduce && accumulator) { // If we are not reducing and we have a truthy result, return it. return accumulator; @@ -899,27 +963,74 @@ function iterateCommentRanges(reduce: boolean, text: string, pos: number, return accumulator; } -export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U): U | undefined; -export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; -export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined { +export function forEachLeadingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U, +): U | undefined; +export function forEachLeadingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state: T, +): U | undefined; +export function forEachLeadingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state?: T, +): U | undefined { return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ false, cb, state!); } -export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U): U | undefined; -export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; -export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined { +export function forEachTrailingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U, +): U | undefined; +export function forEachTrailingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state: T, +): U | undefined; +export function forEachTrailingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state?: T, +): U | undefined { return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ true, cb, state!); } -export function reduceEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T, initial: U) { +export function reduceEachLeadingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state: T, + initial: U, +) { return iterateCommentRanges(/*reduce*/ true, text, pos, /*trailing*/ false, cb, state, initial); } -export function reduceEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T, initial: U) { +export function reduceEachTrailingCommentRange( + text: string, + pos: number, + cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, + state: T, + initial: U, +) { return iterateCommentRanges(/*reduce*/ true, text, pos, /*trailing*/ true, cb, state, initial); } -function appendCommentRange(pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, _state: any, comments: CommentRange[] = []) { +function appendCommentRange( + pos: number, + end: number, + kind: CommentKind, + hasTrailingNewLine: boolean, + _state: any, + comments: CommentRange[] = [], +) { comments.push({ kind, pos, end, hasTrailingNewLine }); return comments; } @@ -941,21 +1052,30 @@ export function getShebang(text: string): string | undefined { } export function isIdentifierStart(ch: number, languageVersion: ScriptTarget | undefined): boolean { - return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || - ch === CharacterCodes.$ || ch === CharacterCodes._ || - ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierStart(ch, languageVersion); + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z + || ch === CharacterCodes.$ || ch === CharacterCodes._ + || ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierStart(ch, languageVersion); } -export function isIdentifierPart(ch: number, languageVersion: ScriptTarget | undefined, identifierVariant?: LanguageVariant): boolean { - return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z || - ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || ch === CharacterCodes.$ || ch === CharacterCodes._ || +export function isIdentifierPart( + ch: number, + languageVersion: ScriptTarget | undefined, + identifierVariant?: LanguageVariant, +): boolean { + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z || ch >= CharacterCodes.a && ch <= CharacterCodes.z + || ch >= CharacterCodes._0 && ch <= CharacterCodes._9 || ch === CharacterCodes.$ || ch === CharacterCodes._ // "-" and ":" are valid in JSX Identifiers - (identifierVariant === LanguageVariant.JSX ? (ch === CharacterCodes.minus || ch === CharacterCodes.colon) : false) || - ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion); + || (identifierVariant === LanguageVariant.JSX ? (ch === CharacterCodes.minus || ch === CharacterCodes.colon) + : false) + || ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion); } /** @internal */ -export function isIdentifierText(name: string, languageVersion: ScriptTarget | undefined, identifierVariant?: LanguageVariant): boolean { +export function isIdentifierText( + name: string, + languageVersion: ScriptTarget | undefined, + identifierVariant?: LanguageVariant, +): boolean { let ch = codePointAt(name, 0); if (!isIdentifierStart(ch, languageVersion)) { return false; @@ -971,14 +1091,15 @@ export function isIdentifierText(name: string, languageVersion: ScriptTarget | u } // Creates a scanner over a (possibly unspecified) range of a piece of text. -export function createScanner(languageVersion: ScriptTarget, +export function createScanner( + languageVersion: ScriptTarget, skipTrivia: boolean, languageVariant = LanguageVariant.Standard, textInitial?: string, onError?: ErrorCallback, start?: number, - length?: number): Scanner { - + length?: number, +): Scanner { // Why var? It avoids TDZ checks in the runtime which can be costly. // See: https://github.com/microsoft/TypeScript/issues/52924 /* eslint-disable no-var */ @@ -987,7 +1108,6 @@ export function createScanner(languageVersion: ScriptTarget, // Current position (end position of text of current token) var pos: number; - // end of text var end: number; @@ -1222,7 +1342,10 @@ export function createScanner(languageVersion: ScriptTarget, } if (decimalFragment !== undefined || tokenFlags & TokenFlags.Scientific) { - checkForIdentifierStartAfterNumericLiteral(start, decimalFragment === undefined && !!(tokenFlags & TokenFlags.Scientific)); + checkForIdentifierStartAfterNumericLiteral( + start, + decimalFragment === undefined && !!(tokenFlags & TokenFlags.Scientific), + ); // if value is not an integer, it can be safely coerced to a number tokenValue = "" + +result; return SyntaxKind.NumericLiteral; @@ -1245,14 +1368,26 @@ export function createScanner(languageVersion: ScriptTarget, if (length === 1 && text[identifierStart] === "n") { if (isScientific) { - error(Diagnostics.A_bigint_literal_cannot_use_exponential_notation, numericStart, identifierStart - numericStart + 1); + error( + Diagnostics.A_bigint_literal_cannot_use_exponential_notation, + numericStart, + identifierStart - numericStart + 1, + ); } else { - error(Diagnostics.A_bigint_literal_must_be_an_integer, numericStart, identifierStart - numericStart + 1); + error( + Diagnostics.A_bigint_literal_must_be_an_integer, + numericStart, + identifierStart - numericStart + 1, + ); } } else { - error(Diagnostics.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal, identifierStart, length); + error( + Diagnostics.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal, + identifierStart, + length, + ); pos = identifierStart; } } @@ -1312,9 +1447,10 @@ export function createScanner(languageVersion: ScriptTarget, if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) { ch += CharacterCodes.a - CharacterCodes.A; // standardize hex literals to lowercase } - else if (!((ch >= CharacterCodes._0 && ch <= CharacterCodes._9) || - (ch >= CharacterCodes.a && ch <= CharacterCodes.f) - )) { + else if ( + !((ch >= CharacterCodes._0 && ch <= CharacterCodes._9) + || (ch >= CharacterCodes.a && ch <= CharacterCodes.f)) + ) { break; } valueChars.push(ch); @@ -1382,7 +1518,8 @@ export function createScanner(languageVersion: ScriptTarget, contents += text.substring(start, pos); tokenFlags |= TokenFlags.Unterminated; error(Diagnostics.Unterminated_template_literal); - resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail; + resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral + : SyntaxKind.TemplateTail; break; } @@ -1392,12 +1529,15 @@ export function createScanner(languageVersion: ScriptTarget, if (currChar === CharacterCodes.backtick) { contents += text.substring(start, pos); pos++; - resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail; + resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral + : SyntaxKind.TemplateTail; break; } // '${' - if (currChar === CharacterCodes.$ && pos + 1 < end && text.charCodeAt(pos + 1) === CharacterCodes.openBrace) { + if ( + currChar === CharacterCodes.$ && pos + 1 < end && text.charCodeAt(pos + 1) === CharacterCodes.openBrace + ) { contents += text.substring(start, pos); pos += 2; resultingToken = startedWithBacktick ? SyntaxKind.TemplateHead : SyntaxKind.TemplateMiddle; @@ -1490,7 +1630,12 @@ export function createScanner(languageVersion: ScriptTarget, tokenFlags |= TokenFlags.ContainsInvalidEscape; if (shouldEmitInvalidEscapeError) { const code = parseInt(text.substring(start + 1, pos), 8); - error(Diagnostics.Octal_escape_sequences_are_not_allowed_Use_the_syntax_0, start, pos - start, "\\x" + padLeft(code.toString(16), 2, "0")); + error( + Diagnostics.Octal_escape_sequences_are_not_allowed_Use_the_syntax_0, + start, + pos - start, + "\\x" + padLeft(code.toString(16), 2, "0"), + ); return String.fromCharCode(code); } return text.substring(start, pos); @@ -1518,7 +1663,7 @@ export function createScanner(languageVersion: ScriptTarget, case CharacterCodes.singleQuote: return "'"; case CharacterCodes.doubleQuote: - return "\""; + return '"'; case CharacterCodes.u: if (pos < end && text.charCodeAt(pos) === CharacterCodes.openBrace) { // '\u{DDDDDDDD}' @@ -1536,7 +1681,9 @@ export function createScanner(languageVersion: ScriptTarget, if (!isCodePoint(escapedValue)) { tokenFlags |= TokenFlags.ContainsInvalidEscape; if (shouldEmitInvalidEscapeError) { - error(Diagnostics.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive); + error( + Diagnostics.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive, + ); } return text.substring(start, pos); } @@ -1649,9 +1796,10 @@ export function createScanner(languageVersion: ScriptTarget, return -1; } - function peekExtendedUnicodeEscape(): number { - if (codePointAt(text, pos + 1) === CharacterCodes.u && codePointAt(text, pos + 2) === CharacterCodes.openBrace) { + if ( + codePointAt(text, pos + 1) === CharacterCodes.u && codePointAt(text, pos + 2) === CharacterCodes.openBrace + ) { const start = pos; pos += 3; const escapedValueString = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ false); @@ -1767,8 +1915,8 @@ export function createScanner(languageVersion: ScriptTarget, const numericValue = tokenFlags & TokenFlags.BinarySpecifier ? parseInt(tokenValue.slice(2), 2) // skip "0b" : tokenFlags & TokenFlags.OctalSpecifier - ? parseInt(tokenValue.slice(2), 8) // skip "0o" - : +tokenValue; + ? parseInt(tokenValue.slice(2), 8) // skip "0o" + : +tokenValue; tokenValue = "" + numericValue; return SyntaxKind.NumericLiteral; } @@ -1817,7 +1965,10 @@ export function createScanner(languageVersion: ScriptTarget, continue; } else { - if (ch === CharacterCodes.carriageReturn && pos + 1 < end && text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) { + if ( + ch === CharacterCodes.carriageReturn && pos + 1 < end + && text.charCodeAt(pos + 1) === CharacterCodes.lineFeed + ) { // consume both CR and LF pos += 2; } @@ -1940,7 +2091,10 @@ export function createScanner(languageVersion: ScriptTarget, scanNumber(); return token = SyntaxKind.NumericLiteral; } - if (text.charCodeAt(pos + 1) === CharacterCodes.dot && text.charCodeAt(pos + 2) === CharacterCodes.dot) { + if ( + text.charCodeAt(pos + 1) === CharacterCodes.dot + && text.charCodeAt(pos + 2) === CharacterCodes.dot + ) { return pos += 3, token = SyntaxKind.DotDotDotToken; } pos++; @@ -1974,7 +2128,10 @@ export function createScanner(languageVersion: ScriptTarget, // Multi-line comment if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) { pos += 2; - if (text.charCodeAt(pos) === CharacterCodes.asterisk && text.charCodeAt(pos + 1) !== CharacterCodes.slash) { + if ( + text.charCodeAt(pos) === CharacterCodes.asterisk + && text.charCodeAt(pos + 1) !== CharacterCodes.slash + ) { tokenFlags |= TokenFlags.PrecedingJSDocComment; } @@ -1997,7 +2154,12 @@ export function createScanner(languageVersion: ScriptTarget, } } - commentDirectives = appendIfCommentDirective(commentDirectives, text.slice(lastLineStart, pos), commentDirectiveRegExMultiLine, lastLineStart); + commentDirectives = appendIfCommentDirective( + commentDirectives, + text.slice(lastLineStart, pos), + commentDirectiveRegExMultiLine, + lastLineStart, + ); if (!commentClosed) { error(Diagnostics.Asterisk_Slash_expected); @@ -2022,7 +2184,11 @@ export function createScanner(languageVersion: ScriptTarget, return token = SyntaxKind.SlashToken; case CharacterCodes._0: - if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.X || text.charCodeAt(pos + 1) === CharacterCodes.x)) { + if ( + pos + 2 < end + && (text.charCodeAt(pos + 1) === CharacterCodes.X + || text.charCodeAt(pos + 1) === CharacterCodes.x) + ) { pos += 2; tokenValue = scanMinimumNumberOfHexDigits(1, /*canHaveSeparators*/ true); if (!tokenValue) { @@ -2033,7 +2199,11 @@ export function createScanner(languageVersion: ScriptTarget, tokenFlags |= TokenFlags.HexSpecifier; return token = checkBigIntSuffix(); } - else if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.B || text.charCodeAt(pos + 1) === CharacterCodes.b)) { + else if ( + pos + 2 < end + && (text.charCodeAt(pos + 1) === CharacterCodes.B + || text.charCodeAt(pos + 1) === CharacterCodes.b) + ) { pos += 2; tokenValue = scanBinaryOrOctalDigits(/* base */ 2); if (!tokenValue) { @@ -2044,7 +2214,11 @@ export function createScanner(languageVersion: ScriptTarget, tokenFlags |= TokenFlags.BinarySpecifier; return token = checkBigIntSuffix(); } - else if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.O || text.charCodeAt(pos + 1) === CharacterCodes.o)) { + else if ( + pos + 2 < end + && (text.charCodeAt(pos + 1) === CharacterCodes.O + || text.charCodeAt(pos + 1) === CharacterCodes.o) + ) { pos += 2; tokenValue = scanBinaryOrOctalDigits(/* base */ 8); if (!tokenValue) { @@ -2092,9 +2266,11 @@ export function createScanner(languageVersion: ScriptTarget, if (text.charCodeAt(pos + 1) === CharacterCodes.equals) { return pos += 2, token = SyntaxKind.LessThanEqualsToken; } - if (languageVariant === LanguageVariant.JSX && - text.charCodeAt(pos + 1) === CharacterCodes.slash && - text.charCodeAt(pos + 2) !== CharacterCodes.asterisk) { + if ( + languageVariant === LanguageVariant.JSX + && text.charCodeAt(pos + 1) === CharacterCodes.slash + && text.charCodeAt(pos + 2) !== CharacterCodes.asterisk + ) { return pos += 2, token = SyntaxKind.LessThanSlashToken; } pos++; @@ -2277,7 +2453,10 @@ export function createScanner(languageVersion: ScriptTarget, } function reScanInvalidIdentifier(): SyntaxKind { - Debug.assert(token === SyntaxKind.Unknown, "'reScanInvalidIdentifier' should only be called when the current token is 'SyntaxKind.Unknown'."); + Debug.assert( + token === SyntaxKind.Unknown, + "'reScanInvalidIdentifier' should only be called when the current token is 'SyntaxKind.Unknown'.", + ); pos = tokenStart = fullStartPos; tokenFlags = 0; const ch = codePointAt(text, pos); @@ -2326,7 +2505,10 @@ export function createScanner(languageVersion: ScriptTarget, } function reScanAsteriskEqualsToken(): SyntaxKind { - Debug.assert(token === SyntaxKind.AsteriskEqualsToken, "'reScanAsteriskEqualsToken' should only be called on a '*='"); + Debug.assert( + token === SyntaxKind.AsteriskEqualsToken, + "'reScanAsteriskEqualsToken' should only be called on a '*='", + ); pos = tokenStart + 1; return token = SyntaxKind.EqualsToken; } @@ -2457,7 +2639,10 @@ export function createScanner(languageVersion: ScriptTarget, } function reScanQuestionToken(): SyntaxKind { - Debug.assert(token === SyntaxKind.QuestionQuestionToken, "'reScanQuestionToken' should only be called on a '??'"); + Debug.assert( + token === SyntaxKind.QuestionQuestionToken, + "'reScanQuestionToken' should only be called on a '??'", + ); pos = tokenStart + 1; return token = SyntaxKind.QuestionToken; } @@ -2586,16 +2771,20 @@ export function createScanner(languageVersion: ScriptTarget, if (pos >= end) { return token = SyntaxKind.EndOfFileToken; } - for (let ch = text.charCodeAt(pos); - pos < end && (!isLineBreak(ch) && ch !== CharacterCodes.backtick); - ch = codePointAt(text, ++pos)) { + for ( + let ch = text.charCodeAt(pos); + pos < end && (!isLineBreak(ch) && ch !== CharacterCodes.backtick); + ch = codePointAt(text, ++pos) + ) { if (!inBackticks) { if (ch === CharacterCodes.openBrace) { break; } - else if (ch === CharacterCodes.at + else if ( + ch === CharacterCodes.at && pos - 1 >= 0 && isWhiteSpaceSingleLine(text.charCodeAt(pos - 1)) - && !(pos + 1 < end && isWhiteSpaceLike(text.charCodeAt(pos + 1)))) { + && !(pos + 1 < end && isWhiteSpaceLike(text.charCodeAt(pos + 1))) + ) { // @ doesn't start a new tag inside ``, and elsewhere, only after whitespace and before non-whitespace break; } @@ -2683,7 +2872,10 @@ export function createScanner(languageVersion: ScriptTarget, if (isIdentifierStart(ch, languageVersion)) { let char = ch; - while (pos < end && isIdentifierPart(char = codePointAt(text, pos), languageVersion) || text.charCodeAt(pos) === CharacterCodes.minus) pos += charSize(char); + while ( + pos < end && isIdentifierPart(char = codePointAt(text, pos), languageVersion) + || text.charCodeAt(pos) === CharacterCodes.minus + ) pos += charSize(char); tokenValue = text.substring(tokenStart, pos); if (char === CharacterCodes.backslash) { tokenValue += scanIdentifierParts(); @@ -2792,25 +2984,26 @@ export function createScanner(languageVersion: ScriptTarget, } /** @internal */ -const codePointAt: (s: string, i: number) => number = (String.prototype as any).codePointAt ? (s, i) => (s as any).codePointAt(i) : function codePointAt(str, i): number { - // from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt - const size = str.length; - // Account for out-of-bounds indices: - if (i < 0 || i >= size) { - return undefined!; // String.codePointAt returns `undefined` for OOB indexes - } - // Get the first code unit - const first = str.charCodeAt(i); - // check if it's the start of a surrogate pair - if (first >= 0xD800 && first <= 0xDBFF && size > i + 1) { // high surrogate and there is a next code unit - const second = str.charCodeAt(i + 1); - if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate - // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae - return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; - } - } - return first; -}; +const codePointAt: (s: string, i: number) => number = (String.prototype as any).codePointAt + ? (s, i) => (s as any).codePointAt(i) : function codePointAt(str, i): number { + // from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt + const size = str.length; + // Account for out-of-bounds indices: + if (i < 0 || i >= size) { + return undefined!; // String.codePointAt returns `undefined` for OOB indexes + } + // Get the first code unit + const first = str.charCodeAt(i); + // check if it's the start of a surrogate pair + if (first >= 0xD800 && first <= 0xDBFF && size > i + 1) { // high surrogate and there is a next code unit + const second = str.charCodeAt(i + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; + }; /** @internal */ function charSize(ch: number) { @@ -2834,7 +3027,8 @@ function utf16EncodeAsStringFallback(codePoint: number) { return String.fromCharCode(codeUnit1, codeUnit2); } -const utf16EncodeAsStringWorker: (codePoint: number) => string = (String as any).fromCodePoint ? codePoint => (String as any).fromCodePoint(codePoint) : utf16EncodeAsStringFallback; +const utf16EncodeAsStringWorker: (codePoint: number) => string = (String as any).fromCodePoint + ? codePoint => (String as any).fromCodePoint(codePoint) : utf16EncodeAsStringFallback; /** @internal */ export function utf16EncodeAsString(codePoint: number) { diff --git a/src/compiler/semver.ts b/src/compiler/semver.ts index d17e8c55c1cd6..84f10fb86939d 100644 --- a/src/compiler/semver.ts +++ b/src/compiler/semver.ts @@ -54,8 +54,20 @@ export class Version { readonly build: readonly string[]; constructor(text: string); - constructor(major: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[]); - constructor(major: number | string, minor = 0, patch = 0, prerelease: string | readonly string[] = "", build: string | readonly string[] = "") { + constructor( + major: number, + minor?: number, + patch?: number, + prerelease?: string | readonly string[], + build?: string | readonly string[], + ); + constructor( + major: number | string, + minor = 0, + patch = 0, + prerelease: string | readonly string[] = "", + build: string | readonly string[] = "", + ) { if (typeof major === "string") { const result = Debug.checkDefined(tryParseComponents(major), "Invalid version"); ({ major, minor, patch, prerelease, build } = result); @@ -109,20 +121,32 @@ export class Version { increment(field: "major" | "minor" | "patch") { switch (field) { - case "major": return new Version(this.major + 1, 0, 0); - case "minor": return new Version(this.major, this.minor + 1, 0); - case "patch": return new Version(this.major, this.minor, this.patch + 1); - default: return Debug.assertNever(field); + case "major": + return new Version(this.major + 1, 0, 0); + case "minor": + return new Version(this.major, this.minor + 1, 0); + case "patch": + return new Version(this.major, this.minor, this.patch + 1); + default: + return Debug.assertNever(field); } } - with(fields: { major?: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[] }) { + with( + fields: { + major?: number; + minor?: number; + patch?: number; + prerelease?: string | readonly string[]; + build?: string | readonly string[]; + }, + ) { const { major = this.major, minor = this.minor, patch = this.patch, prerelease = this.prerelease, - build = this.build + build = this.build, } = fields; return new Version(major, minor, patch, prerelease, build); } @@ -147,7 +171,7 @@ function tryParseComponents(text: string) { minor: parseInt(minor, 10), patch: parseInt(patch, 10), prerelease, - build + build, }; } @@ -254,7 +278,8 @@ const whitespaceRegExp = /\s+/g; // build ::= parts // parts ::= part ( '.' part ) * // part ::= nr | [-0-9A-Za-z]+ -const partialRegExp = /^([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i; +const partialRegExp = + /^([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i; // https://github.com/npm/node-semver#range-grammar // @@ -300,7 +325,8 @@ function parsePartial(text: string) { isWildcard(major) || isWildcard(minor) ? 0 : parseInt(minor, 10), isWildcard(major) || isWildcard(minor) || isWildcard(patch) ? 0 : parseInt(patch, 10), prerelease, - build); + build, + ); return { version, major, minor, patch }; } @@ -318,9 +344,10 @@ function parseHyphen(left: string, right: string, comparators: Comparator[]) { if (!isWildcard(rightResult.major)) { comparators.push( - isWildcard(rightResult.minor) ? createComparator("<", rightResult.version.increment("major")) : - isWildcard(rightResult.patch) ? createComparator("<", rightResult.version.increment("minor")) : - createComparator("<=", rightResult.version)); + isWildcard(rightResult.minor) ? createComparator("<", rightResult.version.increment("major")) + : isWildcard(rightResult.patch) ? createComparator("<", rightResult.version.increment("minor")) + : createComparator("<=", rightResult.version), + ); } return true; @@ -335,35 +362,59 @@ function parseComparator(operator: string, text: string, comparators: Comparator switch (operator) { case "~": comparators.push(createComparator(">=", version)); - comparators.push(createComparator("<", version.increment( - isWildcard(minor) ? "major" : - "minor"))); + comparators.push(createComparator( + "<", + version.increment( + isWildcard(minor) ? "major" + : "minor", + ), + )); break; case "^": comparators.push(createComparator(">=", version)); - comparators.push(createComparator("<", version.increment( - version.major > 0 || isWildcard(minor) ? "major" : - version.minor > 0 || isWildcard(patch) ? "minor" : - "patch"))); + comparators.push(createComparator( + "<", + version.increment( + version.major > 0 || isWildcard(minor) ? "major" + : version.minor > 0 || isWildcard(patch) ? "minor" + : "patch", + ), + )); break; case "<": case ">=": comparators.push( - isWildcard(minor) || isWildcard(patch) ? createComparator(operator, version.with({ prerelease: "0" })) : - createComparator(operator, version)); + isWildcard(minor) || isWildcard(patch) + ? createComparator(operator, version.with({ prerelease: "0" })) + : createComparator(operator, version), + ); break; case "<=": case ">": comparators.push( - isWildcard(minor) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("major").with({ prerelease: "0" })) : - isWildcard(patch) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("minor").with({ prerelease: "0" })) : - createComparator(operator, version)); + isWildcard(minor) + ? createComparator( + operator === "<=" ? "<" : ">=", + version.increment("major").with({ prerelease: "0" }), + ) + : isWildcard(patch) + ? createComparator( + operator === "<=" ? "<" : ">=", + version.increment("minor").with({ prerelease: "0" }), + ) + : createComparator(operator, version), + ); break; case "=": case undefined: if (isWildcard(minor) || isWildcard(patch)) { comparators.push(createComparator(">=", version.with({ prerelease: "0" }))); - comparators.push(createComparator("<", version.increment(isWildcard(minor) ? "major" : "minor").with({ prerelease: "0" }))); + comparators.push( + createComparator( + "<", + version.increment(isWildcard(minor) ? "major" : "minor").with({ prerelease: "0" }), + ), + ); } else { comparators.push(createComparator("=", version)); @@ -408,12 +459,18 @@ function testAlternative(version: Version, comparators: readonly Comparator[]) { function testComparator(version: Version, operator: Comparator["operator"], operand: Version) { const cmp = version.compareTo(operand); switch (operator) { - case "<": return cmp < 0; - case "<=": return cmp <= 0; - case ">": return cmp > 0; - case ">=": return cmp >= 0; - case "=": return cmp === 0; - default: return Debug.assertNever(operator); + case "<": + return cmp < 0; + case "<=": + return cmp <= 0; + case ">": + return cmp > 0; + case ">=": + return cmp >= 0; + case "=": + return cmp === 0; + default: + return Debug.assertNever(operator); } } diff --git a/src/compiler/sourcemap.ts b/src/compiler/sourcemap.ts index 78ebf13ba0878..6be26771c586c 100644 --- a/src/compiler/sourcemap.ts +++ b/src/compiler/sourcemap.ts @@ -34,7 +34,13 @@ export interface SourceMapGeneratorOptions { } /** @internal */ -export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoot: string, sourcesDirectoryPath: string, generatorOptions: SourceMapGeneratorOptions): SourceMapGenerator { +export function createSourceMapGenerator( + host: EmitHost, + file: string, + sourceRoot: string, + sourcesDirectoryPath: string, + generatorOptions: SourceMapGeneratorOptions, +): SourceMapGenerator { // Why var? It avoids TDZ checks in the runtime which can be costly. // See: https://github.com/microsoft/TypeScript/issues/52924 /* eslint-disable no-var */ @@ -81,16 +87,18 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo addMapping, appendSourceMap, toJSON, - toString: () => JSON.stringify(toJSON()) + toString: () => JSON.stringify(toJSON()), }; function addSource(fileName: string) { enter(); - const source = getRelativePathToDirectoryOrUrl(sourcesDirectoryPath, + const source = getRelativePathToDirectoryOrUrl( + sourcesDirectoryPath, fileName, host.getCurrentDirectory(), host.getCanonicalFileName, - /*isAbsolutePathAnUrl*/ true); + /*isAbsolutePathAnUrl*/ true, + ); let sourceIndex = sourceToSourceIndexMap.get(source); if (sourceIndex === undefined) { @@ -136,7 +144,11 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo || pendingGeneratedCharacter !== generatedCharacter; } - function isBacktrackingSourcePosition(sourceIndex: number | undefined, sourceLine: number | undefined, sourceCharacter: number | undefined) { + function isBacktrackingSourcePosition( + sourceIndex: number | undefined, + sourceLine: number | undefined, + sourceCharacter: number | undefined, + ) { return sourceIndex !== undefined && sourceLine !== undefined && sourceCharacter !== undefined @@ -145,7 +157,14 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo || pendingSourceLine === sourceLine && pendingSourceCharacter > sourceCharacter); } - function addMapping(generatedLine: number, generatedCharacter: number, sourceIndex?: number, sourceLine?: number, sourceCharacter?: number, nameIndex?: number) { + function addMapping( + generatedLine: number, + generatedCharacter: number, + sourceIndex?: number, + sourceLine?: number, + sourceCharacter?: number, + nameIndex?: number, + ) { Debug.assert(generatedLine >= pendingGeneratedLine, "generatedLine cannot backtrack"); Debug.assert(generatedCharacter >= 0, "generatedCharacter cannot be negative"); Debug.assert(sourceIndex === undefined || sourceIndex >= 0, "sourceIndex cannot be negative"); @@ -153,8 +172,10 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo Debug.assert(sourceCharacter === undefined || sourceCharacter >= 0, "sourceCharacter cannot be negative"); enter(); // If this location wasn't recorded or the location in source is going backwards, record the mapping - if (isNewGeneratedPosition(generatedLine, generatedCharacter) || - isBacktrackingSourcePosition(sourceIndex, sourceLine, sourceCharacter)) { + if ( + isNewGeneratedPosition(generatedLine, generatedCharacter) + || isBacktrackingSourcePosition(sourceIndex, sourceLine, sourceCharacter) + ) { commitPendingMapping(); pendingGeneratedLine = generatedLine; pendingGeneratedCharacter = generatedCharacter; @@ -176,7 +197,14 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo exit(); } - function appendSourceMap(generatedLine: number, generatedCharacter: number, map: RawSourceMap, sourceMapPath: string, start?: LineAndCharacter, end?: LineAndCharacter) { + function appendSourceMap( + generatedLine: number, + generatedCharacter: number, + map: RawSourceMap, + sourceMapPath: string, + start?: LineAndCharacter, + end?: LineAndCharacter, + ) { Debug.assert(generatedLine >= pendingGeneratedLine, "generatedLine cannot backtrack"); Debug.assert(generatedCharacter >= 0, "generatedCharacter cannot be negative"); enter(); @@ -185,15 +213,21 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo let nameIndexToNewNameIndexMap: number[] | undefined; const mappingIterator = decodeMappings(map.mappings); for (const raw of mappingIterator) { - if (end && ( - raw.generatedLine > end.line || - (raw.generatedLine === end.line && raw.generatedCharacter > end.character))) { + if ( + end && ( + raw.generatedLine > end.line + || (raw.generatedLine === end.line && raw.generatedCharacter > end.character) + ) + ) { break; } - if (start && ( - raw.generatedLine < start.line || - (start.line === raw.generatedLine && raw.generatedCharacter < start.character))) { + if ( + start && ( + raw.generatedLine < start.line + || (start.line === raw.generatedLine && raw.generatedCharacter < start.character) + ) + ) { continue; } // Then reencode all the updated mappings into the overall map @@ -227,9 +261,18 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo const rawGeneratedLine = raw.generatedLine - (start ? start.line : 0); const newGeneratedLine = rawGeneratedLine + generatedLine; - const rawGeneratedCharacter = start && start.line === raw.generatedLine ? raw.generatedCharacter - start.character : raw.generatedCharacter; - const newGeneratedCharacter = rawGeneratedLine === 0 ? rawGeneratedCharacter + generatedCharacter : rawGeneratedCharacter; - addMapping(newGeneratedLine, newGeneratedCharacter, newSourceIndex, newSourceLine, newSourceCharacter, newNameIndex); + const rawGeneratedCharacter = start && start.line === raw.generatedLine + ? raw.generatedCharacter - start.character : raw.generatedCharacter; + const newGeneratedCharacter = rawGeneratedLine === 0 ? rawGeneratedCharacter + generatedCharacter + : rawGeneratedCharacter; + addMapping( + newGeneratedLine, + newGeneratedCharacter, + newSourceIndex, + newSourceLine, + newSourceCharacter, + newNameIndex, + ); } exit(); } @@ -350,7 +393,8 @@ export function createSourceMapGenerator(host: EmitHost, file: string, sourceRoo currentDigit = currentDigit | 32; } appendMappingCharCode(base64FormatEncode(currentDigit)); - } while (inValue > 0); + } + while (inValue > 0); } } @@ -373,7 +417,7 @@ export interface LineInfo { export function getLineInfo(text: string, lineStarts: readonly number[]): LineInfo { return { getLineCount: () => lineStarts.length, - getLineText: line => text.substring(lineStarts[line], lineStarts[line + 1]) + getLineText: line => text.substring(lineStarts[line], lineStarts[line + 1]), }; } @@ -410,7 +454,8 @@ export function isRawSourceMap(x: any): x is RawSourceMap { && typeof x.mappings === "string" && isArray(x.sources) && every(x.sources, isString) && (x.sourceRoot === undefined || x.sourceRoot === null || typeof x.sourceRoot === "string") - && (x.sourcesContent === undefined || x.sourcesContent === null || isArray(x.sourcesContent) && every(x.sourcesContent, isStringOrNull)) + && (x.sourcesContent === undefined || x.sourcesContent === null + || isArray(x.sourcesContent) && every(x.sourcesContent, isStringOrNull)) && (x.names === undefined || x.names === null || isArray(x.names) && every(x.names, isString)); } /* eslint-enable no-null/no-null */ @@ -468,9 +513,15 @@ export function decodeMappings(mappings: string): MappingsDecoder { // TODO(jakebailey): can we implement this without writing next ourselves? return { - get pos() { return pos; }, - get error() { return error; }, - get state() { return captureMapping(/*hasSource*/ true, /*hasName*/ true); }, + get pos() { + return pos; + }, + get error() { + return error; + }, + get state() { + return captureMapping(/*hasSource*/ true, /*hasName*/ true); + }, next() { while (!done && pos < mappings.length) { const ch = mappings.charCodeAt(pos); @@ -501,12 +552,16 @@ export function decodeMappings(mappings: string): MappingsDecoder { sourceIndex += base64VLQFormatDecode(); if (hasReportedError()) return stopIterating(); if (sourceIndex < 0) return setErrorAndStopIterating("Invalid sourceIndex found"); - if (isSourceMappingSegmentEnd()) return setErrorAndStopIterating("Unsupported Format: No entries after sourceIndex"); + if (isSourceMappingSegmentEnd()) { + return setErrorAndStopIterating("Unsupported Format: No entries after sourceIndex"); + } sourceLine += base64VLQFormatDecode(); if (hasReportedError()) return stopIterating(); if (sourceLine < 0) return setErrorAndStopIterating("Invalid sourceLine found"); - if (isSourceMappingSegmentEnd()) return setErrorAndStopIterating("Unsupported Format: No entries after sourceLine"); + if (isSourceMappingSegmentEnd()) { + return setErrorAndStopIterating("Unsupported Format: No entries after sourceLine"); + } sourceCharacter += base64VLQFormatDecode(); if (hasReportedError()) return stopIterating(); @@ -518,7 +573,9 @@ export function decodeMappings(mappings: string): MappingsDecoder { if (hasReportedError()) return stopIterating(); if (nameIndex < 0) return setErrorAndStopIterating("Invalid nameIndex found"); - if (!isSourceMappingSegmentEnd()) return setErrorAndStopIterating("Unsupported Error Format: Entries after nameIndex"); + if (!isSourceMappingSegmentEnd()) { + return setErrorAndStopIterating("Unsupported Error Format: Entries after nameIndex"); + } } } @@ -529,7 +586,7 @@ export function decodeMappings(mappings: string): MappingsDecoder { }, [Symbol.iterator]() { return this; - } + }, }; function captureMapping(hasSource: true, hasName: true): Required; @@ -541,11 +598,11 @@ export function decodeMappings(mappings: string): MappingsDecoder { sourceIndex: hasSource ? sourceIndex : undefined, sourceLine: hasSource ? sourceLine : undefined, sourceCharacter: hasSource ? sourceCharacter : undefined, - nameIndex: hasName ? nameIndex : undefined + nameIndex: hasName ? nameIndex : undefined, }; } - function stopIterating(): { value: never, done: true } { + function stopIterating(): { value: never; done: true; } { done = true; return { value: undefined!, done: true }; } @@ -566,9 +623,9 @@ export function decodeMappings(mappings: string): MappingsDecoder { } function isSourceMappingSegmentEnd() { - return (pos === mappings.length || - mappings.charCodeAt(pos) === CharacterCodes.comma || - mappings.charCodeAt(pos) === CharacterCodes.semicolon); + return (pos === mappings.length + || mappings.charCodeAt(pos) === CharacterCodes.comma + || mappings.charCodeAt(pos) === CharacterCodes.semicolon); } function base64VLQFormatDecode(): number { @@ -577,7 +634,9 @@ export function decodeMappings(mappings: string): MappingsDecoder { let value = 0; for (; moreDigits; pos++) { - if (pos >= mappings.length) return setError("Error in decoding base64VLQFormatDecode, past the mapping string"), -1; + if (pos >= mappings.length) { + return setError("Error in decoding base64VLQFormatDecode, past the mapping string"), -1; + } // 6 digit number const currentByte = base64FormatDecode(mappings.charCodeAt(pos)); @@ -610,11 +669,11 @@ export function decodeMappings(mappings: string): MappingsDecoder { export function sameMapping(left: T, right: T) { return left === right || left.generatedLine === right.generatedLine - && left.generatedCharacter === right.generatedCharacter - && left.sourceIndex === right.sourceIndex - && left.sourceLine === right.sourceLine - && left.sourceCharacter === right.sourceCharacter - && left.nameIndex === right.nameIndex; + && left.generatedCharacter === right.generatedCharacter + && left.sourceIndex === right.sourceIndex + && left.sourceLine === right.sourceLine + && left.sourceCharacter === right.sourceCharacter + && left.nameIndex === right.nameIndex; } /** @internal */ @@ -625,21 +684,21 @@ export function isSourceMapping(mapping: Mapping): mapping is SourceMapping { } function base64FormatEncode(value: number) { - return value >= 0 && value < 26 ? CharacterCodes.A + value : - value >= 26 && value < 52 ? CharacterCodes.a + value - 26 : - value >= 52 && value < 62 ? CharacterCodes._0 + value - 52 : - value === 62 ? CharacterCodes.plus : - value === 63 ? CharacterCodes.slash : - Debug.fail(`${value}: not a base64 value`); + return value >= 0 && value < 26 ? CharacterCodes.A + value + : value >= 26 && value < 52 ? CharacterCodes.a + value - 26 + : value >= 52 && value < 62 ? CharacterCodes._0 + value - 52 + : value === 62 ? CharacterCodes.plus + : value === 63 ? CharacterCodes.slash + : Debug.fail(`${value}: not a base64 value`); } function base64FormatDecode(ch: number) { - return ch >= CharacterCodes.A && ch <= CharacterCodes.Z ? ch - CharacterCodes.A : - ch >= CharacterCodes.a && ch <= CharacterCodes.z ? ch - CharacterCodes.a + 26 : - ch >= CharacterCodes._0 && ch <= CharacterCodes._9 ? ch - CharacterCodes._0 + 52 : - ch === CharacterCodes.plus ? 62 : - ch === CharacterCodes.slash ? 63 : - -1; + return ch >= CharacterCodes.A && ch <= CharacterCodes.Z ? ch - CharacterCodes.A + : ch >= CharacterCodes.a && ch <= CharacterCodes.z ? ch - CharacterCodes.a + 26 + : ch >= CharacterCodes._0 && ch <= CharacterCodes._9 ? ch - CharacterCodes._0 + 52 + : ch === CharacterCodes.plus ? 62 + : ch === CharacterCodes.slash ? 63 + : -1; } interface MappedPosition { @@ -687,25 +746,36 @@ function getGeneratedPositionOfMapping(value: MappedPosition) { } /** @internal */ -export function createDocumentPositionMapper(host: DocumentPositionMapperHost, map: RawSourceMap, mapPath: string): DocumentPositionMapper { +export function createDocumentPositionMapper( + host: DocumentPositionMapperHost, + map: RawSourceMap, + mapPath: string, +): DocumentPositionMapper { const mapDirectory = getDirectoryPath(mapPath); const sourceRoot = map.sourceRoot ? getNormalizedAbsolutePath(map.sourceRoot, mapDirectory) : mapDirectory; const generatedAbsoluteFilePath = getNormalizedAbsolutePath(map.file, mapDirectory); const generatedFile = host.getSourceFileLike(generatedAbsoluteFilePath); const sourceFileAbsolutePaths = map.sources.map(source => getNormalizedAbsolutePath(source, sourceRoot)); - const sourceToSourceIndexMap = new Map(sourceFileAbsolutePaths.map((source, i) => [host.getCanonicalFileName(source), i])); + const sourceToSourceIndexMap = new Map( + sourceFileAbsolutePaths.map((source, i) => [host.getCanonicalFileName(source), i]), + ); let decodedMappings: readonly MappedPosition[] | undefined; let generatedMappings: SortedReadonlyArray | undefined; let sourceMappings: readonly SortedReadonlyArray[] | undefined; return { getSourcePosition, - getGeneratedPosition + getGeneratedPosition, }; function processMapping(mapping: Mapping): MappedPosition { const generatedPosition = generatedFile !== undefined - ? getPositionOfLineAndCharacter(generatedFile, mapping.generatedLine, mapping.generatedCharacter, /*allowEdits*/ true) + ? getPositionOfLineAndCharacter( + generatedFile, + mapping.generatedLine, + mapping.generatedCharacter, + /*allowEdits*/ true, + ) : -1; let source: string | undefined; let sourcePosition: number | undefined; @@ -713,7 +783,12 @@ export function createDocumentPositionMapper(host: DocumentPositionMapperHost, m const sourceFile = host.getSourceFileLike(sourceFileAbsolutePaths[mapping.sourceIndex]); source = map.sources[mapping.sourceIndex]; sourcePosition = sourceFile !== undefined - ? getPositionOfLineAndCharacter(sourceFile, mapping.sourceLine, mapping.sourceCharacter, /*allowEdits*/ true) + ? getPositionOfLineAndCharacter( + sourceFile, + mapping.sourceLine, + mapping.sourceCharacter, + /*allowEdits*/ true, + ) : -1; } return { @@ -721,7 +796,7 @@ export function createDocumentPositionMapper(host: DocumentPositionMapperHost, m source, sourceIndex: mapping.sourceIndex, sourcePosition, - nameIndex: mapping.nameIndex + nameIndex: mapping.nameIndex, }; } @@ -751,7 +826,9 @@ export function createDocumentPositionMapper(host: DocumentPositionMapperHost, m if (!list) lists[mapping.sourceIndex] = list = []; list.push(mapping); } - sourceMappings = lists.map(list => sortAndDeduplicate(list, compareSourcePositions, sameMappedPosition)); + sourceMappings = lists.map(list => + sortAndDeduplicate(list, compareSourcePositions, sameMappedPosition) + ); } return sourceMappings[sourceIndex]; } @@ -810,5 +887,5 @@ export function createDocumentPositionMapper(host: DocumentPositionMapperHost, m /** @internal */ export const identitySourceMapConsumer: DocumentPositionMapper = { getSourcePosition: identity, - getGeneratedPosition: identity + getGeneratedPosition: identity, }; diff --git a/src/compiler/symbolWalker.ts b/src/compiler/symbolWalker.ts index 09853623cc5db..3adeee07406e4 100644 --- a/src/compiler/symbolWalker.ts +++ b/src/compiler/symbolWalker.ts @@ -37,8 +37,8 @@ export function createGetSymbolWalker( getResolvedSymbol: (node: Identifier) => Symbol, getConstraintOfTypeParameter: (typeParameter: TypeParameter) => Type | undefined, getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier, - getTypeArguments: (type: TypeReference) => readonly Type[]) { - + getTypeArguments: (type: TypeReference) => readonly Type[], +) { return getSymbolWalker; function getSymbolWalker(accept: (symbol: Symbol) => boolean = () => true): SymbolWalker { @@ -214,4 +214,3 @@ export function createGetSymbolWalker( } } } - diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index db12d3a6dd96e..7ed73946a6e38 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -81,7 +81,7 @@ export function setStackTraceLimit() { export enum FileWatcherEventKind { Created, Changed, - Deleted + Deleted, } export type FileWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, modifiedTime?: Date) => void; @@ -96,13 +96,23 @@ interface WatchedFile { export enum PollingInterval { High = 2000, Medium = 500, - Low = 250 + Low = 250, } /** @internal */ -export type HostWatchFile = (fileName: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined) => FileWatcher; +export type HostWatchFile = ( + fileName: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, +) => FileWatcher; /** @internal */ -export type HostWatchDirectory = (fileName: string, callback: DirectoryWatcherCallback, recursive: boolean, options: WatchOptions | undefined) => FileWatcher; +export type HostWatchDirectory = ( + fileName: string, + callback: DirectoryWatcherCallback, + recursive: boolean, + options: WatchOptions | undefined, +) => FileWatcher; /** @internal */ export const missingFileModifiedTime = new Date(0); // Any subsequent modification will occur after this time @@ -122,7 +132,7 @@ function createPollingIntervalBasedLevels(levels: Levels) { return { [PollingInterval.Low]: levels.Low, [PollingInterval.Medium]: levels.Medium, - [PollingInterval.High]: levels.High + [PollingInterval.High]: levels.High, }; } @@ -136,8 +146,10 @@ function setCustomPollingValues(system: System) { return; } const pollingIntervalChanged = setCustomLevels("TSC_WATCH_POLLINGINTERVAL", PollingInterval); - pollingChunkSize = getCustomPollingBasedLevels("TSC_WATCH_POLLINGCHUNKSIZE", defaultChunkLevels) || pollingChunkSize; - unchangedPollThresholds = getCustomPollingBasedLevels("TSC_WATCH_UNCHANGEDPOLLTHRESHOLDS", defaultChunkLevels) || unchangedPollThresholds; + pollingChunkSize = getCustomPollingBasedLevels("TSC_WATCH_POLLINGCHUNKSIZE", defaultChunkLevels) + || pollingChunkSize; + unchangedPollThresholds = getCustomPollingBasedLevels("TSC_WATCH_UNCHANGEDPOLLTHRESHOLDS", defaultChunkLevels) + || unchangedPollThresholds; function getLevel(envVar: string, level: keyof Levels) { return system.getEnvironmentVariable(`${envVar}_${level.toUpperCase()}`); @@ -175,8 +187,8 @@ function setCustomPollingValues(system: System) { function getCustomPollingBasedLevels(baseVariable: string, defaultLevels: Levels) { const customLevels = getCustomLevels(baseVariable); - return (pollingIntervalChanged || customLevels) && - createPollingIntervalBasedLevels(customLevels ? { ...defaultLevels, ...customLevels } : defaultLevels); + return (pollingIntervalChanged || customLevels) + && createPollingIntervalBasedLevels(customLevels ? { ...defaultLevels, ...customLevels } : defaultLevels); } } @@ -186,8 +198,9 @@ interface WatchedFileWithIsClosed extends WatchedFile { function pollWatchedFileQueue( host: { getModifiedTime: NonNullable; }, queue: (T | undefined)[], - pollIndex: number, chunkSize: number, - callbackOnWatchFileStat?: (watchedFile: T, pollIndex: number, fileChanged: boolean) => void + pollIndex: number, + chunkSize: number, + callbackOnWatchFileStat?: (watchedFile: T, pollIndex: number, fileChanged: boolean) => void, ) { let definedValueCopyToIndex = pollIndex; // Max visit would be all elements of the queue @@ -258,12 +271,16 @@ function createDynamicPriorityPollingWatchFile(host: { const highPollingIntervalQueue = createPollingIntervalQueue(PollingInterval.High); return watchFile; - function watchFile(fileName: string, callback: FileWatcherCallback, defaultPollingInterval: PollingInterval): FileWatcher { + function watchFile( + fileName: string, + callback: FileWatcherCallback, + defaultPollingInterval: PollingInterval, + ): FileWatcher { const file: WatchedFileWithUnchangedPolls = { fileName, callback, unchangedPolls: 0, - mtime: getModifiedTime(host, fileName) + mtime: getModifiedTime(host, fileName), }; watchedFiles.push(file); @@ -274,7 +291,7 @@ function createDynamicPriorityPollingWatchFile(host: { // Remove from watchedFiles unorderedRemoveItem(watchedFiles, file); // Do not update polling interval queue since that will happen as part of polling - } + }, }; } @@ -287,7 +304,12 @@ function createDynamicPriorityPollingWatchFile(host: { } function pollPollingIntervalQueue(_timeoutType: string, queue: PollingIntervalQueue) { - queue.pollIndex = pollQueue(queue, queue.pollingInterval, queue.pollIndex, pollingChunkSize[queue.pollingInterval]); + queue.pollIndex = pollQueue( + queue, + queue.pollingInterval, + queue.pollIndex, + pollingChunkSize[queue.pollingInterval], + ); // Set the next polling index and timeout if (queue.length) { scheduleNextPoll(queue.pollingInterval); @@ -311,13 +333,18 @@ function createDynamicPriorityPollingWatchFile(host: { } } - function pollQueue(queue: (WatchedFileWithUnchangedPolls | undefined)[], pollingInterval: PollingInterval, pollIndex: number, chunkSize: number) { + function pollQueue( + queue: (WatchedFileWithUnchangedPolls | undefined)[], + pollingInterval: PollingInterval, + pollIndex: number, + chunkSize: number, + ) { return pollWatchedFileQueue( host, queue, pollIndex, chunkSize, - onWatchFileStat + onWatchFileStat, ); function onWatchFileStat(watchedFile: WatchedFileWithUnchangedPolls, pollIndex: number, fileChanged: boolean) { @@ -341,7 +368,10 @@ function createDynamicPriorityPollingWatchFile(host: { else if (pollingInterval !== PollingInterval.High) { watchedFile.unchangedPolls++; queue[pollIndex] = undefined; - addToPollingIntervalQueue(watchedFile, pollingInterval === PollingInterval.Low ? PollingInterval.Medium : PollingInterval.High); + addToPollingIntervalQueue( + watchedFile, + pollingInterval === PollingInterval.Low ? PollingInterval.Medium : PollingInterval.High, + ); } } } @@ -374,23 +404,36 @@ function createDynamicPriorityPollingWatchFile(host: { } function scheduleNextPoll(pollingInterval: PollingInterval) { - pollingIntervalQueue(pollingInterval).pollScheduled = host.setTimeout(pollingInterval === PollingInterval.Low ? pollLowPollingIntervalQueue : pollPollingIntervalQueue, pollingInterval, pollingInterval === PollingInterval.Low ? "pollLowPollingIntervalQueue" : "pollPollingIntervalQueue", pollingIntervalQueue(pollingInterval)); + pollingIntervalQueue(pollingInterval).pollScheduled = host.setTimeout( + pollingInterval === PollingInterval.Low ? pollLowPollingIntervalQueue : pollPollingIntervalQueue, + pollingInterval, + pollingInterval === PollingInterval.Low ? "pollLowPollingIntervalQueue" : "pollPollingIntervalQueue", + pollingIntervalQueue(pollingInterval), + ); } } -function createUseFsEventsOnParentDirectoryWatchFile(fsWatch: FsWatch, useCaseSensitiveFileNames: boolean): HostWatchFile { +function createUseFsEventsOnParentDirectoryWatchFile( + fsWatch: FsWatch, + useCaseSensitiveFileNames: boolean, +): HostWatchFile { // One file can have multiple watchers const fileWatcherCallbacks = createMultiMap(); const dirWatchers = new Map(); const toCanonicalName = createGetCanonicalFileName(useCaseSensitiveFileNames); return nonPollingWatchFile; - function nonPollingWatchFile(fileName: string, callback: FileWatcherCallback, _pollingInterval: PollingInterval, fallbackOptions: WatchOptions | undefined): FileWatcher { + function nonPollingWatchFile( + fileName: string, + callback: FileWatcherCallback, + _pollingInterval: PollingInterval, + fallbackOptions: WatchOptions | undefined, + ): FileWatcher { const filePath = toCanonicalName(fileName); fileWatcherCallbacks.add(filePath, callback); const dirPath = getDirectoryPath(filePath) || "."; - const watcher = dirWatchers.get(dirPath) || - createDirectoryWatcher(getDirectoryPath(fileName) || ".", dirPath, fallbackOptions); + const watcher = dirWatchers.get(dirPath) + || createDirectoryWatcher(getDirectoryPath(fileName) || ".", dirPath, fallbackOptions); watcher.referenceCount++; return { close: () => { @@ -402,7 +445,7 @@ function createUseFsEventsOnParentDirectoryWatchFile(fsWatch: FsWatch, useCaseSe watcher.referenceCount--; } fileWatcherCallbacks.remove(filePath, callback); - } + }, }; } @@ -424,7 +467,7 @@ function createUseFsEventsOnParentDirectoryWatchFile(fsWatch: FsWatch, useCaseSe }, /*recursive*/ false, PollingInterval.Medium, - fallbackOptions + fallbackOptions, ) as DirectoryWatcher; watcher.referenceCount = 0; dirWatchers.set(dirPath, watcher); @@ -445,7 +488,7 @@ function createFixedChunkSizePollingWatchFile(host: { const file: WatchedFileWithIsClosed = { fileName, callback, - mtime: getModifiedTime(host, fileName) + mtime: getModifiedTime(host, fileName), }; watchedFiles.push(file); scheduleNextPoll(); @@ -453,7 +496,7 @@ function createFixedChunkSizePollingWatchFile(host: { close: () => { file.isClosed = true; unorderedRemoveItem(watchedFiles, file); - } + }, }; } @@ -469,7 +512,7 @@ function createFixedChunkSizePollingWatchFile(host: { } } -interface SingleFileWatcher{ +interface SingleFileWatcher { watcher: FileWatcher; callbacks: T[]; } @@ -488,11 +531,14 @@ function createSingleWatcherPerName cache.get(path)?.callbacks.slice().forEach(cb => cb(param1, param2, param3)) - ) as T), - callbacks: [callback] + watcher: createWatcher( + ( + // Cant infer types correctly so lets satisfy checker + (param1: any, param2: never, param3: any) => + cache.get(path)?.callbacks.slice().forEach(cb => cb(param1, param2, param3)) + ) as T, + ), + callbacks: [callback], }); } @@ -505,7 +551,7 @@ function createSingleWatcherPerName(); const callbackCache = createMultiMap(); - const cacheToUpdateChildWatches = new Map(); + const cacheToUpdateChildWatches = new Map< + Path, + { dirName: string; options: WatchOptions | undefined; fileNames: string[]; } + >(); let timerToUpdateChildWatches: any; const filePathComparer = getStringComparer(!useCaseSensitiveFileNames); const toCanonicalFilePath = createGetCanonicalFileName(useCaseSensitiveFileNames); - return (dirName, callback, recursive, options) => recursive ? - createDirectoryWatcher(dirName, options, callback) : - watchDirectory(dirName, callback, recursive, options); + return (dirName, callback, recursive, options) => + recursive + ? createDirectoryWatcher(dirName, options, callback) + : watchDirectory(dirName, callback, recursive, options); /** * Create the directory watcher for the dirPath. */ - function createDirectoryWatcher(dirName: string, options: WatchOptions | undefined, callback?: DirectoryWatcherCallback): ChildDirectoryWatcher { + function createDirectoryWatcher( + dirName: string, + options: WatchOptions | undefined, + callback?: DirectoryWatcherCallback, + ): ChildDirectoryWatcher { const dirPath = toCanonicalFilePath(dirName) as Path; let directoryWatcher = cache.get(dirPath); if (directoryWatcher) { @@ -608,22 +662,27 @@ function createDirectoryWatcherSupportingRecursive({ } else { directoryWatcher = { - watcher: watchDirectory(dirName, fileName => { - if (isIgnoredPath(fileName, options)) return; + watcher: watchDirectory( + dirName, + fileName => { + if (isIgnoredPath(fileName, options)) return; - if (options?.synchronousWatchDirectory) { - // Call the actual callback - invokeCallbacks(dirPath, fileName); + if (options?.synchronousWatchDirectory) { + // Call the actual callback + invokeCallbacks(dirPath, fileName); - // Iterate through existing children and update the watches if needed - updateChildWatches(dirName, dirPath, options); - } - else { - nonSyncUpdateChildWatches(dirName, dirPath, fileName, options); - } - }, /*recursive*/ false, options), + // Iterate through existing children and update the watches if needed + updateChildWatches(dirName, dirPath, options); + } + else { + nonSyncUpdateChildWatches(dirName, dirPath, fileName, options); + } + }, + /*recursive*/ false, + options, + ), refCount: 1, - childWatches: emptyArray + childWatches: emptyArray, }; cache.set(dirPath, directoryWatcher); updateChildWatches(dirName, dirPath, options); @@ -646,7 +705,7 @@ function createDirectoryWatcherSupportingRecursive({ cache.delete(dirPath); closeFileWatcherOf(directoryWatcher); directoryWatcher.childWatches.forEach(closeFileWatcher); - } + }, }; } @@ -665,7 +724,10 @@ function createDirectoryWatcherSupportingRecursive({ // Call the actual callback callbackCache.forEach((callbacks, rootDirName) => { if (invokeMap && invokeMap.get(rootDirName) === true) return; - if (rootDirName === dirPath || (startsWith(dirPath, rootDirName) && dirPath[rootDirName.length] === directorySeparator)) { + if ( + rootDirName === dirPath + || (startsWith(dirPath, rootDirName) && dirPath[rootDirName.length] === directorySeparator) + ) { if (invokeMap) { if (fileNames) { const existing = invokeMap.get(rootDirName); @@ -687,7 +749,12 @@ function createDirectoryWatcherSupportingRecursive({ }); } - function nonSyncUpdateChildWatches(dirName: string, dirPath: Path, fileName: string, options: WatchOptions | undefined) { + function nonSyncUpdateChildWatches( + dirName: string, + dirPath: Path, + fileName: string, + options: WatchOptions | undefined, + ) { // Iterate through existing children and update the watches if needed const parentWatcher = cache.get(dirPath); if (parentWatcher && fileSystemEntryExists(dirName, FileSystemEntryKind.Directory)) { @@ -701,7 +768,12 @@ function createDirectoryWatcherSupportingRecursive({ removeChildWatches(parentWatcher); } - function scheduleUpdateChildWatches(dirName: string, dirPath: Path, fileName: string, options: WatchOptions | undefined) { + function scheduleUpdateChildWatches( + dirName: string, + dirPath: Path, + fileName: string, + options: WatchOptions | undefined, + ) { const existing = cacheToUpdateChildWatches.get(dirPath); if (existing) { existing.fileNames.push(fileName); @@ -749,7 +821,9 @@ function createDirectoryWatcherSupportingRecursive({ }); const elapsed = timestamp() - start; - sysLog(`sysLog:: Elapsed:: ${elapsed}ms:: onTimerToUpdateChildWatches:: ${cacheToUpdateChildWatches.size} ${timerToUpdateChildWatches}`); + sysLog( + `sysLog:: Elapsed:: ${elapsed}ms:: onTimerToUpdateChildWatches:: ${cacheToUpdateChildWatches.size} ${timerToUpdateChildWatches}`, + ); } function removeChildWatches(parentWatcher: HostDirectoryWatcher | undefined) { @@ -768,17 +842,20 @@ function createDirectoryWatcherSupportingRecursive({ if (!parentWatcher) return false; let newChildWatches: ChildDirectoryWatcher[] | undefined; const hasChanges = enumerateInsertsAndDeletes( - fileSystemEntryExists(parentDir, FileSystemEntryKind.Directory) ? mapDefined(getAccessibleSortedChildDirectories(parentDir), child => { - const childFullName = getNormalizedAbsolutePath(child, parentDir); - // Filter our the symbolic link directories since those arent included in recursive watch - // which is same behaviour when recursive: true is passed to fs.watch - return !isIgnoredPath(childFullName, options) && filePathComparer(childFullName, normalizePath(realpath(childFullName))) === Comparison.EqualTo ? childFullName : undefined; - }) : emptyArray, + fileSystemEntryExists(parentDir, FileSystemEntryKind.Directory) + ? mapDefined(getAccessibleSortedChildDirectories(parentDir), child => { + const childFullName = getNormalizedAbsolutePath(child, parentDir); + // Filter our the symbolic link directories since those arent included in recursive watch + // which is same behaviour when recursive: true is passed to fs.watch + return !isIgnoredPath(childFullName, options) + && filePathComparer(childFullName, normalizePath(realpath(childFullName))) + === Comparison.EqualTo ? childFullName : undefined; + }) : emptyArray, parentWatcher.childWatches, (child, childWatcher) => filePathComparer(child, childWatcher.dirName), createAndAddChildDirectoryWatcher, closeFileWatcher, - addChildDirectoryWatcher + addChildDirectoryWatcher, ); parentWatcher.childWatches = newChildWatches || emptyArray; return hasChanges; @@ -800,8 +877,8 @@ function createDirectoryWatcherSupportingRecursive({ } function isIgnoredPath(path: string, options: WatchOptions | undefined) { - return some(ignoredPaths, searchPath => isInPath(path, searchPath)) || - isIgnoredByWatchOptions(path, options, useCaseSensitiveFileNames, getCurrentDirectory); + return some(ignoredPaths, searchPath => isInPath(path, searchPath)) + || isIgnoredByWatchOptions(path, options, useCaseSensitiveFileNames, getCurrentDirectory); } function isInPath(path: string, searchPath: string) { @@ -812,15 +889,30 @@ function createDirectoryWatcherSupportingRecursive({ } /** @internal */ -export type FsWatchCallback = (eventName: "rename" | "change", relativeFileName: string | undefined | null, modifiedTime?: Date) => void; +export type FsWatchCallback = ( + eventName: "rename" | "change", + relativeFileName: string | undefined | null, + modifiedTime?: Date, +) => void; /** @internal */ -export type FsWatch = (fileOrDirectory: string, entryKind: FileSystemEntryKind, callback: FsWatchCallback, recursive: boolean, fallbackPollingInterval: PollingInterval, fallbackOptions: WatchOptions | undefined) => FileWatcher; +export type FsWatch = ( + fileOrDirectory: string, + entryKind: FileSystemEntryKind, + callback: FsWatchCallback, + recursive: boolean, + fallbackPollingInterval: PollingInterval, + fallbackOptions: WatchOptions | undefined, +) => FileWatcher; /** @internal */ export interface FsWatchWorkerWatcher extends FileWatcher { on(eventName: string, listener: () => void): void; } /** @internal */ -export type FsWatchWorker = (fileOrDirectory: string, recursive: boolean, callback: FsWatchCallback) => FsWatchWorkerWatcher; +export type FsWatchWorker = ( + fileOrDirectory: string, + recursive: boolean, + callback: FsWatchCallback, +) => FsWatchWorkerWatcher; /** @internal */ export const enum FileSystemEntryKind { File, @@ -828,19 +920,24 @@ export const enum FileSystemEntryKind { } function createFileWatcherCallback(callback: FsWatchCallback): FileWatcherCallback { - return (_fileName, eventKind, modifiedTime) => callback(eventKind === FileWatcherEventKind.Changed ? "change" : "rename", "", modifiedTime); + return (_fileName, eventKind, modifiedTime) => + callback(eventKind === FileWatcherEventKind.Changed ? "change" : "rename", "", modifiedTime); } function createFsWatchCallbackForFileWatcherCallback( fileName: string, callback: FileWatcherCallback, - getModifiedTime: NonNullable + getModifiedTime: NonNullable, ): FsWatchCallback { return (eventName, _relativeFileName, modifiedTime) => { if (eventName === "rename") { // Check time stamps rather than file system entry checks modifiedTime ||= getModifiedTime(fileName) || missingFileModifiedTime; - callback(fileName, modifiedTime !== missingFileModifiedTime ? FileWatcherEventKind.Created : FileWatcherEventKind.Deleted, modifiedTime); + callback( + fileName, + modifiedTime !== missingFileModifiedTime ? FileWatcherEventKind.Created : FileWatcherEventKind.Deleted, + modifiedTime, + ); } else { // Change @@ -856,8 +953,8 @@ function isIgnoredByWatchOptions( getCurrentDirectory: System["getCurrentDirectory"], ) { return (options?.excludeDirectories || options?.excludeFiles) && ( - matchesExclude(pathToCheck, options?.excludeFiles, useCaseSensitiveFileNames, getCurrentDirectory()) || - matchesExclude(pathToCheck, options?.excludeDirectories, useCaseSensitiveFileNames, getCurrentDirectory()) + matchesExclude(pathToCheck, options?.excludeFiles, useCaseSensitiveFileNames, getCurrentDirectory()) + || matchesExclude(pathToCheck, options?.excludeDirectories, useCaseSensitiveFileNames, getCurrentDirectory()) ); } @@ -874,8 +971,12 @@ function createFsWatchCallbackForDirectoryWatcherCallback( // event name is "change") if (eventName === "rename") { // When deleting a file, the passed baseFileName is null - const fileName = !relativeFileName ? directoryName : normalizePath(combinePaths(directoryName, relativeFileName)); - if (!relativeFileName || !isIgnoredByWatchOptions(fileName, options, useCaseSensitiveFileNames, getCurrentDirectory)) { + const fileName = !relativeFileName ? directoryName + : normalizePath(combinePaths(directoryName, relativeFileName)); + if ( + !relativeFileName + || !isIgnoredByWatchOptions(fileName, options, useCaseSensitiveFileNames, getCurrentDirectory) + ) { callback(fileName); } } @@ -938,10 +1039,15 @@ export function createSystemWatchFunctions({ let hitSystemWatcherLimit = false; return { watchFile, - watchDirectory + watchDirectory, }; - function watchFile(fileName: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined): FileWatcher { + function watchFile( + fileName: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + ): FileWatcher { options = updateOptionsForWatchFile(options, useNonPollingWatchers); const watchFileKind = Debug.checkDefined(options.watchFile); switch (watchFileKind) { @@ -952,7 +1058,12 @@ export function createSystemWatchFunctions({ case WatchFileKind.DynamicPriorityPolling: return ensureDynamicPollingWatchFile()(fileName, callback, pollingInterval, /*options*/ undefined); case WatchFileKind.FixedChunkSizePolling: - return ensureFixedChunkSizePollingWatchFile()(fileName, callback, /* pollingInterval */ undefined!, /*options*/ undefined); + return ensureFixedChunkSizePollingWatchFile()( + fileName, + callback, + /* pollingInterval */ undefined!, + /*options*/ undefined, + ); case WatchFileKind.UseFsEvents: return fsWatch( fileName, @@ -960,11 +1071,14 @@ export function createSystemWatchFunctions({ createFsWatchCallbackForFileWatcherCallback(fileName, callback, getModifiedTime), /*recursive*/ false, pollingInterval, - getFallbackOptions(options) + getFallbackOptions(options), ); case WatchFileKind.UseFsEventsOnParentDirectory: if (!nonPollingWatchFile) { - nonPollingWatchFile = createUseFsEventsOnParentDirectoryWatchFile(fsWatch, useCaseSensitiveFileNames); + nonPollingWatchFile = createUseFsEventsOnParentDirectoryWatchFile( + fsWatch, + useCaseSensitiveFileNames, + ); } return nonPollingWatchFile(fileName, callback, pollingInterval, getFallbackOptions(options)); default: @@ -980,7 +1094,10 @@ export function createSystemWatchFunctions({ return fixedChunkSizePollingWatchFile ||= createFixedChunkSizePollingWatchFile({ getModifiedTime, setTimeout }); } - function updateOptionsForWatchFile(options: WatchOptions | undefined, useNonPollingWatchers?: boolean): WatchOptions { + function updateOptionsForWatchFile( + options: WatchOptions | undefined, + useNonPollingWatchers?: boolean, + ): WatchOptions { if (options && options.watchFile !== undefined) return options; switch (tscWatchFile) { case "PriorityPollingInterval": @@ -999,37 +1116,52 @@ export function createSystemWatchFunctions({ useNonPollingWatchers = true; // fall through default: - return useNonPollingWatchers ? + return useNonPollingWatchers // Use notifications from FS to watch with falling back to fs.watchFile - generateWatchFileOptions(WatchFileKind.UseFsEventsOnParentDirectory, PollingWatchKind.PriorityInterval, options) : + ? generateWatchFileOptions( + WatchFileKind.UseFsEventsOnParentDirectory, + PollingWatchKind.PriorityInterval, + options, + ) // Default to using fs events - { watchFile: WatchFileKind.UseFsEvents }; + : { watchFile: WatchFileKind.UseFsEvents }; } } function generateWatchFileOptions( watchFile: WatchFileKind, fallbackPolling: PollingWatchKind, - options: WatchOptions | undefined + options: WatchOptions | undefined, ): WatchOptions { const defaultFallbackPolling = options?.fallbackPolling; return { watchFile, - fallbackPolling: defaultFallbackPolling === undefined ? - fallbackPolling : - defaultFallbackPolling + fallbackPolling: defaultFallbackPolling === undefined + ? fallbackPolling + : defaultFallbackPolling, }; } - function watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean, options: WatchOptions | undefined): FileWatcher { + function watchDirectory( + directoryName: string, + callback: DirectoryWatcherCallback, + recursive: boolean, + options: WatchOptions | undefined, + ): FileWatcher { if (fsSupportsRecursiveFsWatch) { return fsWatch( directoryName, FileSystemEntryKind.Directory, - createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback, options, useCaseSensitiveFileNames, getCurrentDirectory), + createFsWatchCallbackForDirectoryWatcherCallback( + directoryName, + callback, + options, + useCaseSensitiveFileNames, + getCurrentDirectory, + ), recursive, PollingInterval.Medium, - getFallbackOptions(options) + getFallbackOptions(options), ); } @@ -1042,13 +1174,18 @@ export function createSystemWatchFunctions({ watchDirectory: nonRecursiveWatchDirectory, realpath, setTimeout, - clearTimeout + clearTimeout, }); } return hostRecursiveDirectoryWatcher(directoryName, callback, recursive, options); } - function nonRecursiveWatchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean, options: WatchOptions | undefined): FileWatcher { + function nonRecursiveWatchDirectory( + directoryName: string, + callback: DirectoryWatcherCallback, + recursive: boolean, + options: WatchOptions | undefined, + ): FileWatcher { Debug.assert(!recursive); const watchDirectoryOptions = updateOptionsForWatchDirectory(options); const watchDirectoryKind = Debug.checkDefined(watchDirectoryOptions.watchDirectory); @@ -1058,30 +1195,36 @@ export function createSystemWatchFunctions({ directoryName, () => callback(directoryName), PollingInterval.Medium, - /*options*/ undefined + /*options*/ undefined, ); case WatchDirectoryKind.DynamicPriorityPolling: return ensureDynamicPollingWatchFile()( directoryName, () => callback(directoryName), PollingInterval.Medium, - /*options*/ undefined + /*options*/ undefined, ); case WatchDirectoryKind.FixedChunkSizePolling: return ensureFixedChunkSizePollingWatchFile()( directoryName, () => callback(directoryName), /* pollingInterval */ undefined!, - /*options*/ undefined + /*options*/ undefined, ); case WatchDirectoryKind.UseFsEvents: return fsWatch( directoryName, FileSystemEntryKind.Directory, - createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback, options, useCaseSensitiveFileNames, getCurrentDirectory), + createFsWatchCallbackForDirectoryWatcherCallback( + directoryName, + callback, + options, + useCaseSensitiveFileNames, + getCurrentDirectory, + ), recursive, PollingInterval.Medium, - getFallbackOptions(watchDirectoryOptions) + getFallbackOptions(watchDirectoryOptions), ); default: Debug.assertNever(watchDirectoryKind); @@ -1101,14 +1244,19 @@ export function createSystemWatchFunctions({ const defaultFallbackPolling = options?.fallbackPolling; return { watchDirectory: WatchDirectoryKind.UseFsEvents, - fallbackPolling: defaultFallbackPolling !== undefined ? - defaultFallbackPolling : - undefined + fallbackPolling: defaultFallbackPolling !== undefined + ? defaultFallbackPolling + : undefined, }; } } - function pollingWatchFile(fileName: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined) { + function pollingWatchFile( + fileName: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + ) { return createSingleWatcherPerName( pollingWatches, useCaseSensitiveFileNames, @@ -1123,14 +1271,22 @@ export function createSystemWatchFunctions({ callback: FsWatchCallback, recursive: boolean, fallbackPollingInterval: PollingInterval, - fallbackOptions: WatchOptions | undefined + fallbackOptions: WatchOptions | undefined, ): FileWatcher { return createSingleWatcherPerName( recursive ? fsWatchesRecursive : fsWatches, useCaseSensitiveFileNames, fileOrDirectory, callback, - cb => fsWatchHandlingExistenceOnHost(fileOrDirectory, entryKind, cb, recursive, fallbackPollingInterval, fallbackOptions), + cb => + fsWatchHandlingExistenceOnHost( + fileOrDirectory, + entryKind, + cb, + recursive, + fallbackPollingInterval, + fallbackOptions, + ), ); } @@ -1140,18 +1296,20 @@ export function createSystemWatchFunctions({ callback: FsWatchCallback, recursive: boolean, fallbackPollingInterval: PollingInterval, - fallbackOptions: WatchOptions | undefined + fallbackOptions: WatchOptions | undefined, ): FileWatcher { let lastDirectoryPartWithDirectorySeparator: string | undefined; let lastDirectoryPart: string | undefined; if (inodeWatching) { - lastDirectoryPartWithDirectorySeparator = fileOrDirectory.substring(fileOrDirectory.lastIndexOf(directorySeparator)); + lastDirectoryPartWithDirectorySeparator = fileOrDirectory.substring( + fileOrDirectory.lastIndexOf(directorySeparator), + ); lastDirectoryPart = lastDirectoryPartWithDirectorySeparator.slice(directorySeparator.length); } /** Watcher for the file system entry depending on whether it is missing or present */ - let watcher: FileWatcher | undefined = !fileSystemEntryExists(fileOrDirectory, entryKind) ? - watchMissingFileSystemEntry() : - watchPresentFileSystemEntry(); + let watcher: FileWatcher | undefined = !fileSystemEntryExists(fileOrDirectory, entryKind) + ? watchMissingFileSystemEntry() + : watchPresentFileSystemEntry(); return { close: () => { // Close the watcher (either existing file system entry watcher or missing file system entry watcher) @@ -1159,13 +1317,17 @@ export function createSystemWatchFunctions({ watcher.close(); watcher = undefined; } - } + }, }; function updateWatcher(createWatcher: () => FileWatcher) { // If watcher is not closed, update it if (watcher) { - sysLog(`sysLog:: ${fileOrDirectory}:: Changing watcher to ${createWatcher === watchPresentFileSystemEntry ? "Present" : "Missing"}FileSystemEntryWatcher`); + sysLog( + `sysLog:: ${fileOrDirectory}:: Changing watcher to ${ + createWatcher === watchPresentFileSystemEntry ? "Present" : "Missing" + }FileSystemEntryWatcher`, + ); watcher.close(); watcher = createWatcher(); } @@ -1184,9 +1346,9 @@ export function createSystemWatchFunctions({ const presentWatcher = fsWatchWorker( fileOrDirectory, recursive, - inodeWatching ? - callbackChangingToMissingFileSystemEntry : - callback + inodeWatching + ? callbackChangingToMissingFileSystemEntry + : callback, ); // Watch the missing file or directory or error presentWatcher.on("error", () => { @@ -1205,7 +1367,10 @@ export function createSystemWatchFunctions({ } } - function callbackChangingToMissingFileSystemEntry(event: "rename" | "change", relativeName: string | undefined | null) { + function callbackChangingToMissingFileSystemEntry( + event: "rename" | "change", + relativeName: string | undefined | null, + ) { // In some scenarios, file save operation fires event with fileName.ext~ instead of fileName.ext // To ensure we see the file going missing and coming back up (file delete and then recreated) // and watches being updated correctly we are calling back with fileName.ext as well as fileName.ext~ @@ -1218,16 +1383,21 @@ export function createSystemWatchFunctions({ } // because relativeName is not guaranteed to be correct we need to check on each rename with few combinations // Eg on ubuntu while watching app/node_modules the relativeName is "node_modules" which is neither relative nor full path - if (event === "rename" && - (!relativeName || - relativeName === lastDirectoryPart || - endsWith(relativeName, lastDirectoryPartWithDirectorySeparator!))) { + if ( + event === "rename" + && (!relativeName + || relativeName === lastDirectoryPart + || endsWith(relativeName, lastDirectoryPartWithDirectorySeparator!)) + ) { const modifiedTime = getModifiedTime(fileOrDirectory) || missingFileModifiedTime; if (originalRelativeName) callback(event, originalRelativeName, modifiedTime); callback(event, relativeName, modifiedTime); if (inodeWatching) { // If this was rename event, inode has changed means we need to update watcher - updateWatcher(modifiedTime === missingFileModifiedTime ? watchMissingFileSystemEntry : watchPresentFileSystemEntry); + updateWatcher( + modifiedTime === missingFileModifiedTime ? watchMissingFileSystemEntry + : watchPresentFileSystemEntry, + ); } else if (modifiedTime === missingFileModifiedTime) { updateWatcher(watchMissingFileSystemEntry); @@ -1248,7 +1418,7 @@ export function createSystemWatchFunctions({ fileOrDirectory, createFileWatcherCallback(callback), fallbackPollingInterval, - fallbackOptions + fallbackOptions, ); } @@ -1272,7 +1442,7 @@ export function createSystemWatchFunctions({ } }, fallbackPollingInterval, - fallbackOptions + fallbackOptions, ); } } @@ -1293,10 +1463,21 @@ export function patchWriteFileEnsuringDirectory(sys: System) { !!writeBom, (path, data, writeByteOrderMark) => originalWriteFile.call(sys, path, data, writeByteOrderMark), path => sys.createDirectory(path), - path => sys.directoryExists(path)); + path => sys.directoryExists(path), + ); } -export type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex"; +export type BufferEncoding = + | "ascii" + | "utf8" + | "utf-8" + | "utf16le" + | "ucs2" + | "ucs-2" + | "base64" + | "latin1" + | "binary" + | "hex"; /** @internal */ export interface NodeBuffer extends Uint8Array { @@ -1305,14 +1486,14 @@ export interface NodeBuffer extends Uint8Array { write(str: string, offset: number, encoding?: BufferEncoding): number; write(str: string, offset: number, length: number, encoding?: BufferEncoding): number; toString(encoding?: string, start?: number, end?: number): string; - toJSON(): { type: "Buffer"; data: number[] }; + toJSON(): { type: "Buffer"; data: number[]; }; equals(otherBuffer: Uint8Array): boolean; compare( otherBuffer: Uint8Array, targetStart?: number, targetEnd?: number, sourceStart?: number, - sourceEnd?: number + sourceEnd?: number, ): number; copy(targetBuffer: Uint8Array, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; slice(begin?: number, end?: number): Buffer; @@ -1375,7 +1556,7 @@ export interface NodeBuffer extends Uint8Array { } /** @internal */ -export interface Buffer extends NodeBuffer { } +export interface Buffer extends NodeBuffer {} // TODO: GH#18217 Methods on System are often used as if they are certainly defined export interface System { @@ -1393,8 +1574,18 @@ export interface System { * @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that * use native OS file watching */ - watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; - watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; + watchFile?( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; + watchDirectory?( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; resolvePath(path: string): string; fileExists(path: string): boolean; directoryExists(path: string): boolean; @@ -1402,7 +1593,13 @@ export interface System { getExecutingFilePath(): string; getCurrentDirectory(): string; getDirectories(path: string): string[]; - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; getModifiedTime?(path: string): Date | undefined; setModifiedTime?(path: string, time: Date): void; deleteFile?(path: string): void; @@ -1475,14 +1672,16 @@ export let sys: System = (() => { const platform: string = _os.platform(); const useCaseSensitiveFileNames = isFileSystemCaseSensitive(); - const fsRealpath = !!_fs.realpathSync.native ? process.platform === "win32" ? fsRealPathHandlingLongPath : _fs.realpathSync.native : _fs.realpathSync; + const fsRealpath = !!_fs.realpathSync.native + ? process.platform === "win32" ? fsRealPathHandlingLongPath : _fs.realpathSync.native : _fs.realpathSync; // If our filename is "sys.js", then we are executing unbundled on the raw tsc output. // In that case, simulate a faked path in the directory where a bundle would normally // appear (e.g. the directory containing lib.*.d.ts files). // // Note that if we ever emit as files like cjs/mjs, this check will be wrong. - const executingFilePath = __filename.endsWith("sys.js") ? _path.join(_path.dirname(__dirname), "__fake__.js") : __filename; + const executingFilePath = __filename.endsWith("sys.js") ? _path.join(_path.dirname(__dirname), "__fake__.js") + : __filename; const fsSupportsRecursiveFsWatch = process.platform === "win32" || process.platform === "darwin"; const getCurrentDirectory = memoize(() => process.cwd()); @@ -1513,7 +1712,7 @@ export let sys: System = (() => { write(s: string): void { process.stdout.write(s); }, - getWidthOfTerminal(){ + getWidthOfTerminal() { return process.stdout.columns; }, writeOutputIsTTY() { @@ -1576,9 +1775,12 @@ export let sys: System = (() => { }, enableCPUProfiler, disableCPUProfiler, - cpuProfilingEnabled: () => !!activeSession || contains(process.execArgv, "--cpu-prof") || contains(process.execArgv, "--prof"), + cpuProfilingEnabled: () => + !!activeSession || contains(process.execArgv, "--cpu-prof") || contains(process.execArgv, "--prof"), realpath, - debugMode: !!process.env.NODE_INSPECTOR_IPC || !!process.env.VSCODE_INSPECTOR_OPTIONS || some(process.execArgv, arg => /^--(inspect|debug)(-brk)?(=\d+)?$/i.test(arg)) || !!(process as any).recordreplay, + debugMode: !!process.env.NODE_INSPECTOR_IPC || !!process.env.VSCODE_INSPECTOR_OPTIONS + || some(process.execArgv, arg => /^--(inspect|debug)(-brk)?(=\d+)?$/i.test(arg)) + || !!(process as any).recordreplay, tryEnableSourceMapsForHost() { try { (require("source-map-support") as typeof import("source-map-support")).install(); @@ -1593,7 +1795,7 @@ export let sys: System = (() => { process.stdout.write("\x1Bc"); }, setBlocking: () => { - const handle = (process.stdout as any)?._handle as { setBlocking?: (value: boolean) => void }; + const handle = (process.stdout as any)?._handle as { setBlocking?: (value: boolean) => void; }; if (handle && handle.setBlocking) { handle.setBlocking(true); } @@ -1609,7 +1811,7 @@ export let sys: System = (() => { catch (error) { return { module: undefined, modulePath: undefined, error }; } - } + }, }; return nodeSystem; @@ -1664,10 +1866,17 @@ export let sys: System = (() => { if (node.callFrame.url) { const url = normalizeSlashes(node.callFrame.url); if (containsPath(fileUrlRoot, url, useCaseSensitiveFileNames)) { - node.callFrame.url = getRelativePathToDirectoryOrUrl(fileUrlRoot, url, fileUrlRoot, createGetCanonicalFileName(useCaseSensitiveFileNames), /*isAbsolutePathAnUrl*/ true); + node.callFrame.url = getRelativePathToDirectoryOrUrl( + fileUrlRoot, + url, + fileUrlRoot, + createGetCanonicalFileName(useCaseSensitiveFileNames), + /*isAbsolutePathAnUrl*/ true, + ); } else if (!nativePattern.test(url)) { - node.callFrame.url = (remappedPaths.has(url) ? remappedPaths : remappedPaths.set(url, `external${externalFileCounter}.js`)).get(url)!; + node.callFrame.url = (remappedPaths.has(url) ? remappedPaths + : remappedPaths.set(url, `external${externalFileCounter}.js`)).get(url)!; externalFileCounter++; } } @@ -1682,7 +1891,10 @@ export let sys: System = (() => { if (!err) { try { if (statSync(profilePath)?.isDirectory()) { - profilePath = _path.join(profilePath, `${(new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`); + profilePath = _path.join( + profilePath, + `${(new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`, + ); } } catch { @@ -1727,17 +1939,21 @@ export let sys: System = (() => { /** Convert all lowercase chars to uppercase, and vice-versa */ function swapCase(s: string): string { - return s.replace(/\w/g, (ch) => { + return s.replace(/\w/g, ch => { const up = ch.toUpperCase(); return ch === up ? ch.toLowerCase() : up; }); } - function fsWatchFileWorker(fileName: string, callback: FileWatcherCallback, pollingInterval: number): FileWatcher { + function fsWatchFileWorker( + fileName: string, + callback: FileWatcherCallback, + pollingInterval: number, + ): FileWatcher { _fs.watchFile(fileName, { persistent: true, interval: pollingInterval }, fileChanged); let eventKind: FileWatcherEventKind; return { - close: () => _fs.unwatchFile(fileName, fileChanged) + close: () => _fs.unwatchFile(fileName, fileChanged), }; function fileChanged(curr: import("fs").Stats, prev: import("fs").Stats) { @@ -1775,9 +1991,9 @@ export let sys: System = (() => { // (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643) return _fs.watch( fileOrDirectory, - fsSupportsRecursiveFsWatch ? - { persistent: true, recursive: !!recursive } : { persistent: true }, - callback + fsSupportsRecursiveFsWatch + ? { persistent: true, recursive: !!recursive } : { persistent: true }, + callback, ); } @@ -1890,8 +2106,24 @@ export let sys: System = (() => { } } - function readDirectory(path: string, extensions?: readonly string[], excludes?: readonly string[], includes?: readonly string[], depth?: number): string[] { - return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), depth, getAccessibleFileSystemEntries, realpath); + function readDirectory( + path: string, + extensions?: readonly string[], + excludes?: readonly string[], + includes?: readonly string[], + depth?: number, + ): string[] { + return matchFiles( + path, + extensions, + excludes, + includes, + useCaseSensitiveFileNames, + process.cwd(), + depth, + getAccessibleFileSystemEntries, + realpath, + ); } function fileSystemEntryExists(path: string, entryKind: FileSystemEntryKind): boolean { @@ -1906,9 +2138,12 @@ export let sys: System = (() => { return false; } switch (entryKind) { - case FileSystemEntryKind.File: return stat.isFile(); - case FileSystemEntryKind.Directory: return stat.isDirectory(); - default: return false; + case FileSystemEntryKind.File: + return stat.isFile(); + case FileSystemEntryKind.Directory: + return stat.isDirectory(); + default: + return false; } } catch (e) { @@ -2003,9 +2238,11 @@ export function setSys(s: System) { if (sys && sys.getEnvironmentVariable) { setCustomPollingValues(sys); - Debug.setAssertionLevel(/^development$/i.test(sys.getEnvironmentVariable("NODE_ENV")) - ? AssertionLevel.Normal - : AssertionLevel.None); + Debug.setAssertionLevel( + /^development$/i.test(sys.getEnvironmentVariable("NODE_ENV")) + ? AssertionLevel.Normal + : AssertionLevel.None, + ); } if (sys && sys.debugMode) { Debug.isDebugging = true; diff --git a/src/compiler/tracing.ts b/src/compiler/tracing.ts index 4f091195827a8..af53078fc7b28 100644 --- a/src/compiler/tracing.ts +++ b/src/compiler/tracing.ts @@ -51,7 +51,14 @@ export namespace tracingEnabled { // The actual constraint is that JSON.stringify be able to serialize it without throwing. interface Args { - [key: string]: string | number | boolean | null | undefined | Args | readonly (string | number | boolean | null | undefined | Args)[]; + [key: string]: + | string + | number + | boolean + | null + | undefined + | Args + | readonly (string | number | boolean | null | undefined | Args)[]; } /** Starts tracing for the given project. */ @@ -79,8 +86,7 @@ export namespace tracingEnabled { fs.mkdirSync(traceDir, { recursive: true }); } - const countPart = - mode === "build" ? `.${process.pid}-${++traceCount}` + const countPart = mode === "build" ? `.${process.pid}-${++traceCount}` : mode === "server" ? `.${process.pid}` : ``; const tracePath = combinePaths(traceDir, `trace${countPart}.json`); @@ -97,12 +103,16 @@ export namespace tracingEnabled { // Start with a prefix that contains some metadata that the devtools profiler expects (also avoids a warning on import) const meta = { cat: "__metadata", ph: "M", ts: 1000 * timestamp(), pid: 1, tid: 1 }; - fs.writeSync(traceFd, + fs.writeSync( + traceFd, "[\n" - + [{ name: "process_name", args: { name: "tsc" }, ...meta }, - { name: "thread_name", args: { name: "Main" }, ...meta }, - { name: "TracingStartedInBrowser", ...meta, cat: "disabled-by-default-devtools.timeline" }] - .map(v => JSON.stringify(v)).join(",\n")); + + [{ name: "process_name", args: { name: "tsc" }, ...meta }, { + name: "thread_name", + args: { name: "Main" }, + ...meta, + }, { name: "TracingStartedInBrowser", ...meta, cat: "disabled-by-default-devtools.timeline" }] + .map(v => JSON.stringify(v)).join(",\n"), + ); } /** Stops tracing for the in-progress project and dumps the type catalog. */ @@ -144,7 +154,7 @@ export namespace tracingEnabled { writeEvent("I", phase, name, args, `"s":"g"`); } - const eventStack: { phase: Phase, name: string, args?: Args, time: number, separateBeginAndEnd: boolean }[] = []; + const eventStack: { phase: Phase; name: string; args?: Args; time: number; separateBeginAndEnd: boolean; }[] = []; /** * @param separateBeginAndEnd - used for special cases where we need the trace point even if the event @@ -184,9 +194,14 @@ export namespace tracingEnabled { } } - function writeEvent(eventType: string, phase: Phase, name: string, args: Args | undefined, extras?: string, - time: number = 1000 * timestamp()) { - + function writeEvent( + eventType: string, + phase: Phase, + name: string, + args: Args | undefined, + extras?: string, + time: number = 1000 * timestamp(), + ) { // In server mode, there's no easy way to dump type information, so we drop events that would require it. if (mode === "server" && phase === Phase.CheckTypes) return; @@ -322,7 +337,9 @@ export namespace tracingEnabled { recursionId: recursionToken, isTuple: objectFlags & ObjectFlags.Tuple ? true : undefined, unionTypes: (type.flags & TypeFlags.Union) ? (type as UnionType).types?.map(t => t.id) : undefined, - intersectionTypes: (type.flags & TypeFlags.Intersection) ? (type as IntersectionType).types.map(t => t.id) : undefined, + intersectionTypes: (type.flags & TypeFlags.Intersection) ? (type as IntersectionType).types.map(t => + t.id + ) : undefined, aliasTypeArguments: type.aliasTypeArguments?.map(t => t.id), keyofType: (type.flags & TypeFlags.Index) ? (type as IndexType).type?.id : undefined, ...indexedAccessProperties, diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index f8c1ee5d5eeca..7272a6b4805ef 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -72,7 +72,7 @@ import { transformNodeModule, transformSystemModule, transformTypeScript, - VariableDeclaration + VariableDeclaration, } from "./_namespaces/ts"; import * as performance from "./_namespaces/ts.performance"; @@ -97,7 +97,7 @@ const enum TransformationState { Uninitialized, Initialized, Completed, - Disposed + Disposed, } const enum SyntaxKindFeatureFlags { @@ -109,14 +109,22 @@ const enum SyntaxKindFeatureFlags { export const noTransformers: EmitTransformers = { scriptTransformers: emptyArray, declarationTransformers: emptyArray }; /** @internal */ -export function getTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnly?: boolean | EmitOnly): EmitTransformers { +export function getTransformers( + compilerOptions: CompilerOptions, + customTransformers?: CustomTransformers, + emitOnly?: boolean | EmitOnly, +): EmitTransformers { return { scriptTransformers: getScriptTransformers(compilerOptions, customTransformers, emitOnly), declarationTransformers: getDeclarationTransformers(customTransformers), }; } -function getScriptTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnly?: boolean | EmitOnly) { +function getScriptTransformers( + compilerOptions: CompilerOptions, + customTransformers?: CustomTransformers, + emitOnly?: boolean | EmitOnly, +) { if (emitOnly) return emptyArray; const languageVersion = getEmitScriptTarget(compilerOptions); @@ -140,7 +148,9 @@ function getScriptTransformers(compilerOptions: CompilerOptions, customTransform transformers.push(transformESNext); } - if (!compilerOptions.experimentalDecorators && (languageVersion < ScriptTarget.ESNext || !useDefineForClassFields)) { + if ( + !compilerOptions.experimentalDecorators && (languageVersion < ScriptTarget.ESNext || !useDefineForClassFields) + ) { transformers.push(transformESDecorators); } @@ -190,7 +200,10 @@ function getScriptTransformers(compilerOptions: CompilerOptions, customTransform function getDeclarationTransformers(customTransformers?: CustomTransformers) { const transformers: TransformerFactory[] = []; transformers.push(transformDeclarations); - addRange(transformers, customTransformers && map(customTransformers.afterDeclarations, wrapDeclarationTransformerFactory)); + addRange( + transformers, + customTransformers && map(customTransformers.afterDeclarations, wrapDeclarationTransformerFactory), + ); return transformers; } @@ -204,7 +217,10 @@ function wrapCustomTransformer(transformer: CustomTransformer): Transformer(transformer: TransformerFactory | CustomTransformerFactory, handleDefault: (context: TransformationContext, tx: Transformer) => Transformer): TransformerFactory { +function wrapCustomTransformerFactory( + transformer: TransformerFactory | CustomTransformerFactory, + handleDefault: (context: TransformationContext, tx: Transformer) => Transformer, +): TransformerFactory { return context => { const customTransformer = transformer(context); return typeof customTransformer === "function" @@ -213,11 +229,15 @@ function wrapCustomTransformerFactory(transformer }; } -function wrapScriptTransformerFactory(transformer: TransformerFactory | CustomTransformerFactory): TransformerFactory { +function wrapScriptTransformerFactory( + transformer: TransformerFactory | CustomTransformerFactory, +): TransformerFactory { return wrapCustomTransformerFactory(transformer, chainBundle); } -function wrapDeclarationTransformerFactory(transformer: TransformerFactory | CustomTransformerFactory): TransformerFactory { +function wrapDeclarationTransformerFactory( + transformer: TransformerFactory | CustomTransformerFactory, +): TransformerFactory { return wrapCustomTransformerFactory(transformer, (_, node) => node); } @@ -243,7 +263,15 @@ export function noEmitNotification(hint: EmitHint, node: Node, callback: (hint: * * @internal */ -export function transformNodes(resolver: EmitResolver | undefined, host: EmitHost | undefined, factory: NodeFactory, options: CompilerOptions, nodes: readonly T[], transformers: readonly TransformerFactory[], allowDtsFiles: boolean): TransformationResult { +export function transformNodes( + resolver: EmitResolver | undefined, + host: EmitHost | undefined, + factory: NodeFactory, + options: CompilerOptions, + nodes: readonly T[], + transformers: readonly TransformerFactory[], + allowDtsFiles: boolean, +): TransformationResult { const enabledSyntaxKindFeatures = new Array(SyntaxKind.Count); let lexicalEnvironmentVariableDeclarations: VariableDeclaration[]; let lexicalEnvironmentFunctionDeclarations: FunctionDeclaration[]; @@ -290,21 +318,31 @@ export function transformNodes(resolver: EmitResolver | undefine enableEmitNotification, isSubstitutionEnabled, isEmitNotificationEnabled, - get onSubstituteNode() { return onSubstituteNode; }, + get onSubstituteNode() { + return onSubstituteNode; + }, set onSubstituteNode(value) { - Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed."); + Debug.assert( + state < TransformationState.Initialized, + "Cannot modify transformation hooks after initialization has completed.", + ); Debug.assert(value !== undefined, "Value must not be 'undefined'"); onSubstituteNode = value; }, - get onEmitNode() { return onEmitNode; }, + get onEmitNode() { + return onEmitNode; + }, set onEmitNode(value) { - Debug.assert(state < TransformationState.Initialized, "Cannot modify transformation hooks after initialization has completed."); + Debug.assert( + state < TransformationState.Initialized, + "Cannot modify transformation hooks after initialization has completed.", + ); Debug.assert(value !== undefined, "Value must not be 'undefined'"); onEmitNode = value; }, addDiagnostic(diag) { diagnostics.push(diag); - } + }, }; // Ensure the parse tree is clean before applying transformations @@ -329,7 +367,12 @@ export function transformNodes(resolver: EmitResolver | undefine // Transform each node. const transformed: T[] = []; for (const node of nodes) { - tracing?.push(tracing.Phase.Emit, "transformNodes", node.kind === SyntaxKind.SourceFile ? { path: (node as any as SourceFile).path } : { kind: node.kind, pos: node.pos, end: node.end }); + tracing?.push( + tracing.Phase.Emit, + "transformNodes", + node.kind === SyntaxKind.SourceFile ? { path: (node as any as SourceFile).path } + : { kind: node.kind, pos: node.pos, end: node.end }, + ); transformed.push((allowDtsFiles ? transformation : transformRoot)(node)); tracing?.pop(); } @@ -346,7 +389,7 @@ export function transformNodes(resolver: EmitResolver | undefine emitNodeWithNotification, isEmitNotificationEnabled, dispose, - diagnostics + diagnostics, }; function transformRoot(node: T) { @@ -357,7 +400,10 @@ export function transformNodes(resolver: EmitResolver | undefine * Enables expression substitutions in the pretty printer for the provided SyntaxKind. */ function enableSubstitution(kind: SyntaxKind) { - Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the transformation context after transformation has completed.", + ); enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.Substitution; } @@ -385,7 +431,10 @@ export function transformNodes(resolver: EmitResolver | undefine * Enables before/after emit notifications in the pretty printer for the provided SyntaxKind. */ function enableEmitNotification(kind: SyntaxKind) { - Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the transformation context after transformation has completed.", + ); enabledSyntaxKindFeatures[kind] |= SyntaxKindFeatureFlags.EmitNotifications; } @@ -406,7 +455,10 @@ export function transformNodes(resolver: EmitResolver | undefine * @param emitCallback The callback used to emit the node. */ function emitNodeWithNotification(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) { - Debug.assert(state < TransformationState.Disposed, "Cannot invoke TransformationResult callbacks after the result is disposed."); + Debug.assert( + state < TransformationState.Disposed, + "Cannot invoke TransformationResult callbacks after the result is disposed.", + ); if (node) { // TODO: Remove check and unconditionally use onEmitNode when API is breakingly changed // (see https://github.com/microsoft/TypeScript/pull/36248/files/5062623f39120171b98870c71344b3242eb03d23#r369766739) @@ -423,8 +475,14 @@ export function transformNodes(resolver: EmitResolver | undefine * Records a hoisted variable declaration for the provided name within a lexical environment. */ function hoistVariableDeclaration(name: Identifier): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); const decl = setEmitFlags(factory.createVariableDeclaration(name), EmitFlags.NoNestedSourceMaps); if (!lexicalEnvironmentVariableDeclarations) { lexicalEnvironmentVariableDeclarations = [decl]; @@ -441,8 +499,14 @@ export function transformNodes(resolver: EmitResolver | undefine * Records a hoisted function declaration within a lexical environment. */ function hoistFunctionDeclaration(func: FunctionDeclaration): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); setEmitFlags(func, EmitFlags.CustomPrologue); if (!lexicalEnvironmentFunctionDeclarations) { lexicalEnvironmentFunctionDeclarations = [func]; @@ -456,8 +520,14 @@ export function transformNodes(resolver: EmitResolver | undefine * Adds an initialization statement to the top of the lexical environment. */ function addInitializationStatement(node: Statement): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); setEmitFlags(node, EmitFlags.CustomPrologue); if (!lexicalEnvironmentStatements) { lexicalEnvironmentStatements = [node]; @@ -472,16 +542,24 @@ export function transformNodes(resolver: EmitResolver | undefine * are pushed onto a stack, and the related storage variables are reset. */ function startLexicalEnvironment(): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended."); // Save the current lexical environment. Rather than resizing the array we adjust the // stack size variable. This allows us to reuse existing array slots we've // already allocated between transformations to avoid allocation and GC overhead during // transformation. - lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentVariableDeclarations; - lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFunctionDeclarations; + lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset] = + lexicalEnvironmentVariableDeclarations; + lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset] = + lexicalEnvironmentFunctionDeclarations; lexicalEnvironmentStatementsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentStatements; lexicalEnvironmentFlagsStack[lexicalEnvironmentStackOffset] = lexicalEnvironmentFlags; lexicalEnvironmentStackOffset++; @@ -493,16 +571,28 @@ export function transformNodes(resolver: EmitResolver | undefine /** Suspends the current lexical environment, usually after visiting a parameter list. */ function suspendLexicalEnvironment(): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is already suspended."); lexicalEnvironmentSuspended = true; } /** Resumes a suspended lexical environment, usually before visiting a function body. */ function resumeLexicalEnvironment(): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); Debug.assert(lexicalEnvironmentSuspended, "Lexical environment is not suspended."); lexicalEnvironmentSuspended = false; } @@ -512,14 +602,22 @@ export function transformNodes(resolver: EmitResolver | undefine * any hoisted declarations added in this environment are returned. */ function endLexicalEnvironment(): Statement[] | undefined { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the lexical environment during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the lexical environment after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the lexical environment during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the lexical environment after transformation has completed.", + ); Debug.assert(!lexicalEnvironmentSuspended, "Lexical environment is suspended."); let statements: Statement[] | undefined; - if (lexicalEnvironmentVariableDeclarations || - lexicalEnvironmentFunctionDeclarations || - lexicalEnvironmentStatements) { + if ( + lexicalEnvironmentVariableDeclarations + || lexicalEnvironmentFunctionDeclarations + || lexicalEnvironmentStatements + ) { if (lexicalEnvironmentFunctionDeclarations) { statements = [...lexicalEnvironmentFunctionDeclarations]; } @@ -527,7 +625,7 @@ export function transformNodes(resolver: EmitResolver | undefine if (lexicalEnvironmentVariableDeclarations) { const statement = factory.createVariableStatement( /*modifiers*/ undefined, - factory.createVariableDeclarationList(lexicalEnvironmentVariableDeclarations) + factory.createVariableDeclarationList(lexicalEnvironmentVariableDeclarations), ); setEmitFlags(statement, EmitFlags.CustomPrologue); @@ -552,8 +650,10 @@ export function transformNodes(resolver: EmitResolver | undefine // Restore the previous lexical environment. lexicalEnvironmentStackOffset--; - lexicalEnvironmentVariableDeclarations = lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset]; - lexicalEnvironmentFunctionDeclarations = lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset]; + lexicalEnvironmentVariableDeclarations = + lexicalEnvironmentVariableDeclarationsStack[lexicalEnvironmentStackOffset]; + lexicalEnvironmentFunctionDeclarations = + lexicalEnvironmentFunctionDeclarationsStack[lexicalEnvironmentStackOffset]; lexicalEnvironmentStatements = lexicalEnvironmentStatementsStack[lexicalEnvironmentStackOffset]; lexicalEnvironmentFlags = lexicalEnvironmentFlagsStack[lexicalEnvironmentStackOffset]; if (lexicalEnvironmentStackOffset === 0) { @@ -566,9 +666,9 @@ export function transformNodes(resolver: EmitResolver | undefine } function setLexicalEnvironmentFlags(flags: LexicalEnvironmentFlags, value: boolean): void { - lexicalEnvironmentFlags = value ? - lexicalEnvironmentFlags | flags : - lexicalEnvironmentFlags & ~flags; + lexicalEnvironmentFlags = value + ? lexicalEnvironmentFlags | flags + : lexicalEnvironmentFlags & ~flags; } function getLexicalEnvironmentFlags(): LexicalEnvironmentFlags { @@ -580,7 +680,10 @@ export function transformNodes(resolver: EmitResolver | undefine */ function startBlockScope() { Debug.assert(state > TransformationState.Uninitialized, "Cannot start a block scope during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot start a block scope after transformation has completed."); + Debug.assert( + state < TransformationState.Completed, + "Cannot start a block scope after transformation has completed.", + ); blockScopedVariableDeclarationsStack[blockScopeStackOffset] = blockScopedVariableDeclarations; blockScopeStackOffset++; blockScopedVariableDeclarations = undefined!; @@ -591,16 +694,21 @@ export function transformNodes(resolver: EmitResolver | undefine */ function endBlockScope() { Debug.assert(state > TransformationState.Uninitialized, "Cannot end a block scope during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot end a block scope after transformation has completed."); - const statements: Statement[] | undefined = some(blockScopedVariableDeclarations) ? - [ + Debug.assert( + state < TransformationState.Completed, + "Cannot end a block scope after transformation has completed.", + ); + const statements: Statement[] | undefined = some(blockScopedVariableDeclarations) + ? [ factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - blockScopedVariableDeclarations.map(identifier => factory.createVariableDeclaration(identifier)), - NodeFlags.Let - ) - ) + blockScopedVariableDeclarations.map(identifier => + factory.createVariableDeclaration(identifier) + ), + NodeFlags.Let, + ), + ), ] : undefined; blockScopeStackOffset--; blockScopedVariableDeclarations = blockScopedVariableDeclarationsStack[blockScopeStackOffset]; @@ -616,8 +724,14 @@ export function transformNodes(resolver: EmitResolver | undefine } function requestEmitHelper(helper: EmitHelper): void { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the transformation context during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the transformation context after transformation has completed.", + ); Debug.assert(!helper.scoped, "Cannot request a scoped emit helper."); if (helper.dependencies) { for (const h of helper.dependencies) { @@ -628,8 +742,14 @@ export function transformNodes(resolver: EmitResolver | undefine } function readEmitHelpers(): EmitHelper[] | undefined { - Debug.assert(state > TransformationState.Uninitialized, "Cannot modify the transformation context during initialization."); - Debug.assert(state < TransformationState.Completed, "Cannot modify the transformation context after transformation has completed."); + Debug.assert( + state > TransformationState.Uninitialized, + "Cannot modify the transformation context during initialization.", + ); + Debug.assert( + state < TransformationState.Completed, + "Cannot modify the transformation context after transformation has completed.", + ); const helpers = emitHelpers; emitHelpers = undefined; return helpers; diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index aa4fb43ebc954..a87fdfb492505 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -224,7 +224,7 @@ import { visitNodes, Visitor, visitParameterList, - VisitResult + VisitResult, } from "../_namespaces/ts"; const enum ClassPropertySubstitutionFlags { @@ -338,7 +338,11 @@ const enum ClassFacts { WillHoistInitializersToConstructor = 1 << 4, } -type LexicalEnv = LexicalEnvironment; +type LexicalEnv = LexicalEnvironment< + ClassLexicalEnvironment | undefined, + PrivateEnvironmentData, + PrivateIdentifierInfo +>; type PrivateEnv = PrivateEnvironment; /** @@ -358,7 +362,7 @@ export function transformClassFields(context: TransformationContext): (x: Source endLexicalEnvironment, startLexicalEnvironment, resumeLexicalEnvironment, - addBlockScopedVariable + addBlockScopedVariable, } = context; const resolver = context.getEmitResolver(); const compilerOptions = context.getCompilerOptions(); @@ -378,10 +382,9 @@ export function transformClassFields(context: TransformationContext): (x: Source // We need to transform `accessor` fields when target < ESNext. // We may need to transform `accessor` fields when `useDefineForClassFields: false` - const shouldTransformAutoAccessors = - languageVersion < ScriptTarget.ESNext ? Ternary.True : - !useDefineForClassFields ? Ternary.Maybe : - Ternary.False; + const shouldTransformAutoAccessors = languageVersion < ScriptTarget.ESNext ? Ternary.True + : !useDefineForClassFields ? Ternary.Maybe + : Ternary.False; // We need to transform `this` in a static initializer into a reference to the class // when target < ES2022 since the assignment will be moved outside of the class body. @@ -389,12 +392,12 @@ export function transformClassFields(context: TransformationContext): (x: Source // We don't need to transform `super` property access when target <= ES5 because // the es2015 transformation handles those. - const shouldTransformSuperInStaticInitializers = shouldTransformThisInStaticInitializers && languageVersion >= ScriptTarget.ES2015; + const shouldTransformSuperInStaticInitializers = shouldTransformThisInStaticInitializers + && languageVersion >= ScriptTarget.ES2015; - const shouldTransformAnything = - shouldTransformInitializers || - shouldTransformPrivateElementsOrClassStaticBlocks || - shouldTransformAutoAccessors === Ternary.True; + const shouldTransformAnything = shouldTransformInitializers + || shouldTransformPrivateElementsOrClassStaticBlocks + || shouldTransformAutoAccessors === Ternary.True; const previousOnSubstituteNode = context.onSubstituteNode; context.onSubstituteNode = onSubstituteNode; @@ -438,7 +441,8 @@ export function transformClassFields(context: TransformationContext): (x: Source } lexicalEnvironment = undefined; - shouldTransformPrivateStaticElementsInFile = !!(getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements); + shouldTransformPrivateStaticElementsInFile = + !!(getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements); if (!shouldTransformAnything && !shouldTransformPrivateStaticElementsInFile) { return node; } @@ -458,8 +462,10 @@ export function transformClassFields(context: TransformationContext): (x: Source } function visitor(node: Node): VisitResult { - if (!(node.transformFlags & TransformFlags.ContainsClassFields) && - !(node.transformFlags & TransformFlags.ContainsLexicalThisOrSuper)) { + if ( + !(node.transformFlags & TransformFlags.ContainsClassFields) + && !(node.transformFlags & TransformFlags.ContainsLexicalThisOrSuper) + ) { return node; } @@ -493,7 +499,10 @@ export function transformClassFields(context: TransformationContext): (x: Source return visitElementAccessExpression(node as ElementAccessExpression); case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, /*discarded*/ false); + return visitPreOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + /*discarded*/ false, + ); case SyntaxKind.BinaryExpression: return visitBinaryExpression(node as BinaryExpression, /*discarded*/ false); case SyntaxKind.ParenthesizedExpression: @@ -514,7 +523,7 @@ export function transformClassFields(context: TransformationContext): (x: Source return setCurrentClassElementAnd( /*classElement*/ undefined, fallbackVisitor, - node + node, ); case SyntaxKind.Constructor: case SyntaxKind.MethodDeclaration: @@ -522,9 +531,13 @@ export function transformClassFields(context: TransformationContext): (x: Source case SyntaxKind.SetAccessor: { // If we are descending into a class element, set the class element return setCurrentClassElementAnd( - node as ConstructorDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, + node as + | ConstructorDeclaration + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration, fallbackVisitor, - node + node, ); } default: @@ -543,7 +556,10 @@ export function transformClassFields(context: TransformationContext): (x: Source switch (node.kind) { case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, /*discarded*/ true); + return visitPreOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + /*discarded*/ true, + ); case SyntaxKind.BinaryExpression: return visitBinaryExpression(node as BinaryExpression, /*discarded*/ true); case SyntaxKind.CommaListExpression: @@ -591,24 +607,28 @@ export function transformClassFields(context: TransformationContext): (x: Source return setCurrentClassElementAnd( node as ConstructorDeclaration, visitConstructorDeclaration, - node as ConstructorDeclaration); + node as ConstructorDeclaration, + ); case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.MethodDeclaration: return setCurrentClassElementAnd( node as MethodDeclaration | AccessorDeclaration, visitMethodOrAccessorDeclaration, - node as MethodDeclaration | AccessorDeclaration); + node as MethodDeclaration | AccessorDeclaration, + ); case SyntaxKind.PropertyDeclaration: return setCurrentClassElementAnd( node as PropertyDeclaration, visitPropertyDeclaration, - node as PropertyDeclaration); + node as PropertyDeclaration, + ); case SyntaxKind.ClassStaticBlockDeclaration: return setCurrentClassElementAnd( node as ClassStaticBlockDeclaration, visitClassStaticBlockDeclaration, - node as ClassStaticBlockDeclaration); + node as ClassStaticBlockDeclaration, + ); case SyntaxKind.ComputedPropertyName: return visitComputedPropertyName(node as ComputedPropertyName); case SyntaxKind.SemicolonClassElement: @@ -641,7 +661,10 @@ export function transformClassFields(context: TransformationContext): (x: Source case SyntaxKind.SetAccessor: return classElementVisitor(node); default: - Debug.assertMissingNode(node, "Expected node to either be a PropertyDeclaration, GetAccessorDeclaration, or SetAccessorDeclaration"); + Debug.assertMissingNode( + node, + "Expected node to either be a PropertyDeclaration, GetAccessorDeclaration, or SetAccessorDeclaration", + ); break; } } @@ -671,7 +694,7 @@ export function transformClassFields(context: TransformationContext): (x: Source const receiver = visitNode(node.right, visitor, isExpression); return setOriginalNode( emitHelpers().createClassPrivateFieldInHelper(info.brandCheckIdentifier, receiver), - node + node, ); } @@ -699,9 +722,9 @@ export function transformClassFields(context: TransformationContext): (x: Source pendingStatements = []; const visitedNode = visitEachChild(node, visitor, context); - const statement = some(pendingStatements) ? - [visitedNode, ...pendingStatements] : - visitedNode; + const statement = some(pendingStatements) + ? [visitedNode, ...pendingStatements] + : visitedNode; pendingStatements = savedPendingStatements; return statement; @@ -788,7 +811,12 @@ export function transformClassFields(context: TransformationContext): (x: Source // is `""`. if (isNamedEvaluation(node, isAnonymousClassNeedingAssignedName)) { - node = transformNamedEvaluation(context, node, /*ignoreEmptyStringLiteral*/ true, node.isExportEquals ? "" : "default"); + node = transformNamedEvaluation( + context, + node, + /*ignoreEmptyStringLiteral*/ true, + node.isExportEquals ? "" : "default", + ); } return visitEachChild(node, visitor, context); @@ -798,7 +826,10 @@ export function transformClassFields(context: TransformationContext): (x: Source if (some(pendingExpressions)) { if (isParenthesizedExpression(expression)) { pendingExpressions.push(expression.expression); - expression = factory.updateParenthesizedExpression(expression, factory.inlineExpressions(pendingExpressions)); + expression = factory.updateParenthesizedExpression( + expression, + factory.inlineExpressions(pendingExpressions), + ); } else { pendingExpressions.push(expression); @@ -821,9 +852,16 @@ export function transformClassFields(context: TransformationContext): (x: Source return fallbackVisitor(node); } - function shouldTransformClassElementToWeakMap(node: PrivateIdentifierMethodDeclaration | PrivateIdentifierAccessorDeclaration | PrivateIdentifierPropertyDeclaration) { + function shouldTransformClassElementToWeakMap( + node: + | PrivateIdentifierMethodDeclaration + | PrivateIdentifierAccessorDeclaration + | PrivateIdentifierPropertyDeclaration, + ) { if (shouldTransformPrivateElementsOrClassStaticBlocks) return true; - if (hasStaticModifier(node) && getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements) return true; + if (hasStaticModifier(node) && getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements) { + return true; + } return false; } @@ -847,15 +885,18 @@ export function transformClassFields(context: TransformationContext): (x: Source factory.createAssignment( functionName, factory.createFunctionExpression( - filter(node.modifiers, (m): m is Modifier => isModifier(m) && !isStaticModifier(m) && !isAccessorModifier(m)), + filter( + node.modifiers, + (m): m is Modifier => isModifier(m) && !isStaticModifier(m) && !isAccessorModifier(m), + ), node.asteriskToken, functionName, /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - visitFunctionBody(node.body!, visitor, context) - ) - ) + visitFunctionBody(node.body!, visitor, context), + ), + ), ); } @@ -922,7 +963,10 @@ export function transformClassFields(context: TransformationContext): (x: Source if (isComputedPropertyName(name) && !isSimpleInlineableExpression(name.expression)) { const cacheAssignment = findComputedPropertyNameCacheAssignment(name); if (cacheAssignment) { - getterName = factory.updateComputedPropertyName(name, visitNode(name.expression, visitor, isExpression)); + getterName = factory.updateComputedPropertyName( + name, + visitNode(name.expression, visitor, isExpression), + ); setterName = factory.updateComputedPropertyName(name, cacheAssignment.left); } else { @@ -975,14 +1019,19 @@ export function transformClassFields(context: TransformationContext): (x: Source // TODO: fix const statement = transformPropertyOrClassStaticBlock(node, factory.createThis()); if (statement) { - return factory.createClassStaticBlockDeclaration(factory.createBlock([statement], /*multiLine*/ true)); + return factory.createClassStaticBlockDeclaration( + factory.createBlock([statement], /*multiLine*/ true), + ); } } return undefined; } - if (shouldTransformInitializersUsingSet && !isStatic(node) && lexicalEnvironment?.data && lexicalEnvironment.data.facts & ClassFacts.WillHoistInitializersToConstructor) { + if ( + shouldTransformInitializersUsingSet && !isStatic(node) && lexicalEnvironment?.data + && lexicalEnvironment.data.facts & ClassFacts.WillHoistInitializersToConstructor + ) { // If we are transforming initializers using Set semantics we will elide the initializer as it will // be moved to the constructor to preserve evaluation order next to public instance fields. We don't // need to do this transformation for private static fields since public static fields can be @@ -993,7 +1042,7 @@ export function transformClassFields(context: TransformationContext): (x: Source node.name, /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined + /*initializer*/ undefined, ); } @@ -1007,7 +1056,7 @@ export function transformClassFields(context: TransformationContext): (x: Source visitNode(node.name, propertyNameVisitor, isPropertyName), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression) + visitNode(node.initializer, visitor, isExpression), ); } @@ -1019,7 +1068,8 @@ export function transformClassFields(context: TransformationContext): (x: Source const expr = getPropertyNameExpressionIfNeeded( node.name, - /*shouldHoist*/ !!node.initializer || useDefineForClassFields); + /*shouldHoist*/ !!node.initializer || useDefineForClassFields, + ); if (expr) { getPendingExpressions().push(...flattenCommaList(expr)); } @@ -1028,7 +1078,7 @@ export function transformClassFields(context: TransformationContext): (x: Source const initializerStatement = transformPropertyOrClassStaticBlock(node, factory.createThis()); if (initializerStatement) { const staticBlock = factory.createClassStaticBlockDeclaration( - factory.createBlock([initializerStatement]) + factory.createBlock([initializerStatement]), ); setOriginalNode(staticBlock, node); @@ -1052,28 +1102,32 @@ export function transformClassFields(context: TransformationContext): (x: Source visitNode(node.name, propertyNameVisitor, isPropertyName), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression) + visitNode(node.initializer, visitor, isExpression), ); } function transformFieldInitializer(node: PropertyDeclaration) { Debug.assert(!hasDecorators(node), "Decorators should already have been transformed and elided."); - return isPrivateIdentifierClassElementDeclaration(node) ? - transformPrivateFieldInitializer(node) : - transformPublicFieldInitializer(node); + return isPrivateIdentifierClassElementDeclaration(node) + ? transformPrivateFieldInitializer(node) + : transformPublicFieldInitializer(node); } function shouldTransformAutoAccessorsInCurrentClass() { - return shouldTransformAutoAccessors === Ternary.True || - shouldTransformAutoAccessors === Ternary.Maybe && - !!lexicalEnvironment?.data && !!(lexicalEnvironment.data.facts & ClassFacts.WillHoistInitializersToConstructor); + return shouldTransformAutoAccessors === Ternary.True + || shouldTransformAutoAccessors === Ternary.Maybe + && !!lexicalEnvironment?.data + && !!(lexicalEnvironment.data.facts & ClassFacts.WillHoistInitializersToConstructor); } function visitPropertyDeclaration(node: PropertyDeclaration) { // If this is an auto-accessor, we defer to `transformAutoAccessor`. That function // will in turn call `transformFieldInitializer` as needed. - if (isAutoAccessorPropertyDeclaration(node) && (shouldTransformAutoAccessorsInCurrentClass() || - hasStaticModifier(node) && getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements)) { + if ( + isAutoAccessorPropertyDeclaration(node) && (shouldTransformAutoAccessorsInCurrentClass() + || hasStaticModifier(node) + && getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements) + ) { return transformAutoAccessor(node); } @@ -1081,10 +1135,10 @@ export function transformClassFields(context: TransformationContext): (x: Source } function shouldForceDynamicThis() { - return !!currentClassElement && - hasStaticModifier(currentClassElement) && - isAccessor(currentClassElement) && - isAutoAccessorPropertyDeclaration(getOriginalNode(currentClassElement)); + return !!currentClassElement + && hasStaticModifier(currentClassElement) + && isAccessor(currentClassElement) + && isAutoAccessorPropertyDeclaration(getOriginalNode(currentClassElement)); } /** @@ -1116,21 +1170,21 @@ export function transformClassFields(context: TransformationContext): (x: Source receiver, info.brandCheckIdentifier, info.kind, - info.getterName + info.getterName, ); case PrivateIdentifierKind.Method: return emitHelpers().createClassPrivateFieldGetHelper( receiver, info.brandCheckIdentifier, info.kind, - info.methodName + info.methodName, ); case PrivateIdentifierKind.Field: return emitHelpers().createClassPrivateFieldGetHelper( receiver, info.brandCheckIdentifier, info.kind, - info.isStatic ? info.variableName : undefined + info.isStatic ? info.variableName : undefined, ); case "untransformed": return Debug.fail("Access helpers should not be created for untransformed private elements"); @@ -1147,18 +1201,20 @@ export function transformClassFields(context: TransformationContext): (x: Source return setTextRange( setOriginalNode( createPrivateIdentifierAccess(privateIdentifierInfo, node.expression), - node + node, ), - node + node, ); } } - if (shouldTransformSuperInStaticInitializers && - currentClassElement && - isSuperProperty(node) && - isIdentifier(node.name) && - isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) && - lexicalEnvironment?.data) { + if ( + shouldTransformSuperInStaticInitializers + && currentClassElement + && isSuperProperty(node) + && isIdentifier(node.name) + && isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) + && lexicalEnvironment?.data + ) { const { classConstructor, superClassReference, facts } = lexicalEnvironment.data; if (facts & ClassFacts.ClassWasDecorated) { return visitInvalidSuperProperty(node); @@ -1168,7 +1224,7 @@ export function transformClassFields(context: TransformationContext): (x: Source const superProperty = factory.createReflectGetCall( superClassReference, factory.createStringLiteralFromNode(node.name), - classConstructor + classConstructor, ); setOriginalNode(superProperty, node.expression); setTextRange(superProperty, node.expression); @@ -1179,11 +1235,13 @@ export function transformClassFields(context: TransformationContext): (x: Source } function visitElementAccessExpression(node: ElementAccessExpression) { - if (shouldTransformSuperInStaticInitializers && - currentClassElement && - isSuperProperty(node) && - isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) && - lexicalEnvironment?.data) { + if ( + shouldTransformSuperInStaticInitializers + && currentClassElement + && isSuperProperty(node) + && isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) + && lexicalEnvironment?.data + ) { const { classConstructor, superClassReference, facts } = lexicalEnvironment.data; if (facts & ClassFacts.ClassWasDecorated) { return visitInvalidSuperProperty(node); @@ -1194,7 +1252,7 @@ export function transformClassFields(context: TransformationContext): (x: Source const superProperty = factory.createReflectGetCall( superClassReference, visitNode(node.argumentExpression, visitor, isExpression), - classConstructor + classConstructor, ); setOriginalNode(superProperty, node.expression); setTextRange(superProperty, node.expression); @@ -1204,9 +1262,14 @@ export function transformClassFields(context: TransformationContext): (x: Source return visitEachChild(node, visitor, context); } - function visitPreOrPostfixUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression, discarded: boolean) { - if (node.operator === SyntaxKind.PlusPlusToken || - node.operator === SyntaxKind.MinusMinusToken) { + function visitPreOrPostfixUnaryExpression( + node: PrefixUnaryExpression | PostfixUnaryExpression, + discarded: boolean, + ) { + if ( + node.operator === SyntaxKind.PlusPlusToken + || node.operator === SyntaxKind.MinusMinusToken + ) { const operand = skipParentheses(node.operand); if (isPrivateIdentifierPropertyAccessExpression(operand)) { @@ -1217,13 +1280,20 @@ export function transformClassFields(context: TransformationContext): (x: Source const { readExpression, initializeExpression } = createCopiableReceiverExpr(receiver); let expression: Expression = createPrivateIdentifierAccess(info, readExpression); - const temp = isPrefixUnaryExpression(node) || discarded ? undefined : factory.createTempVariable(hoistVariableDeclaration); - expression = expandPreOrPostfixIncrementOrDecrementExpression(factory, node, expression, hoistVariableDeclaration, temp); + const temp = isPrefixUnaryExpression(node) || discarded ? undefined + : factory.createTempVariable(hoistVariableDeclaration); + expression = expandPreOrPostfixIncrementOrDecrementExpression( + factory, + node, + expression, + hoistVariableDeclaration, + temp, + ); expression = createPrivateIdentifierAssignment( info, initializeExpression || readExpression, expression, - SyntaxKind.EqualsToken + SyntaxKind.EqualsToken, ); setOriginalNode(expression, node); setTextRange(expression, node); @@ -1234,11 +1304,13 @@ export function transformClassFields(context: TransformationContext): (x: Source return expression; } } - else if (shouldTransformSuperInStaticInitializers && - currentClassElement && - isSuperProperty(operand) && - isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) && - lexicalEnvironment?.data) { + else if ( + shouldTransformSuperInStaticInitializers + && currentClassElement + && isSuperProperty(operand) + && isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) + && lexicalEnvironment?.data + ) { // converts `++super.a` into `(Reflect.set(_baseTemp, "a", (_a = Reflect.get(_baseTemp, "a", _classTemp), _b = ++_a), _classTemp), _b)` // converts `++super[f()]` into `(Reflect.set(_baseTemp, _a = f(), (_b = Reflect.get(_baseTemp, _a, _classTemp), _c = ++_b), _classTemp), _c)` // converts `--super.a` into `(Reflect.set(_baseTemp, "a", (_a = Reflect.get(_baseTemp, "a", _classTemp), _b = --_a), _classTemp), _b)` @@ -1250,9 +1322,9 @@ export function transformClassFields(context: TransformationContext): (x: Source const { classConstructor, superClassReference, facts } = lexicalEnvironment.data; if (facts & ClassFacts.ClassWasDecorated) { const expression = visitInvalidSuperProperty(operand); - return isPrefixUnaryExpression(node) ? - factory.updatePrefixUnaryExpression(node, expression) : - factory.updatePostfixUnaryExpression(node, expression); + return isPrefixUnaryExpression(node) + ? factory.updatePrefixUnaryExpression(node, expression) + : factory.updatePostfixUnaryExpression(node, expression); } if (classConstructor && superClassReference) { let setterName: Expression | undefined; @@ -1268,16 +1340,34 @@ export function transformClassFields(context: TransformationContext): (x: Source } else { getterName = factory.createTempVariable(hoistVariableDeclaration); - setterName = factory.createAssignment(getterName, visitNode(operand.argumentExpression, visitor, isExpression)); + setterName = factory.createAssignment( + getterName, + visitNode(operand.argumentExpression, visitor, isExpression), + ); } } if (setterName && getterName) { - let expression: Expression = factory.createReflectGetCall(superClassReference, getterName, classConstructor); + let expression: Expression = factory.createReflectGetCall( + superClassReference, + getterName, + classConstructor, + ); setTextRange(expression, operand); const temp = discarded ? undefined : factory.createTempVariable(hoistVariableDeclaration); - expression = expandPreOrPostfixIncrementOrDecrementExpression(factory, node, expression, hoistVariableDeclaration, temp); - expression = factory.createReflectSetCall(superClassReference, setterName, expression, classConstructor); + expression = expandPreOrPostfixIncrementOrDecrementExpression( + factory, + node, + expression, + hoistVariableDeclaration, + temp, + ); + expression = factory.createReflectSetCall( + superClassReference, + setterName, + expression, + classConstructor, + ); setOriginalNode(expression, node); setTextRange(expression, node); if (temp) { @@ -1298,18 +1388,20 @@ export function transformClassFields(context: TransformationContext): (x: Source visitNode(node.initializer, discardedValueVisitor, isForInitializer), visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, discardedValueVisitor, isExpression), - visitIterationBody(node.statement, visitor, context) + visitIterationBody(node.statement, visitor, context), ); } function visitExpressionStatement(node: ExpressionStatement) { return factory.updateExpressionStatement( node, - visitNode(node.expression, discardedValueVisitor, isExpression) + visitNode(node.expression, discardedValueVisitor, isExpression), ); } - function createCopiableReceiverExpr(receiver: Expression): { readExpression: Expression; initializeExpression: Expression | undefined } { + function createCopiableReceiverExpr( + receiver: Expression, + ): { readExpression: Expression; initializeExpression: Expression | undefined; } { const clone = nodeIsSynthesized(receiver) ? receiver : factory.cloneNode(receiver); if (receiver.kind === SyntaxKind.ThisKeyword && noSubstitution.has(receiver)) { noSubstitution.add(clone); @@ -1323,34 +1415,46 @@ export function transformClassFields(context: TransformationContext): (x: Source } function visitCallExpression(node: CallExpression) { - if (isPrivateIdentifierPropertyAccessExpression(node.expression) && - accessPrivateIdentifier(node.expression.name)) { + if ( + isPrivateIdentifierPropertyAccessExpression(node.expression) + && accessPrivateIdentifier(node.expression.name) + ) { // obj.#x() // Transform call expressions of private names to properly bind the `this` parameter. - const { thisArg, target } = factory.createCallBinding(node.expression, hoistVariableDeclaration, languageVersion); + const { thisArg, target } = factory.createCallBinding( + node.expression, + hoistVariableDeclaration, + languageVersion, + ); if (isCallChain(node)) { return factory.updateCallChain( node, - factory.createPropertyAccessChain(visitNode(target, visitor, isExpression), node.questionDotToken, "call"), + factory.createPropertyAccessChain( + visitNode(target, visitor, isExpression), + node.questionDotToken, + "call", + ), /*questionDotToken*/ undefined, /*typeArguments*/ undefined, - [visitNode(thisArg, visitor, isExpression), ...visitNodes(node.arguments, visitor, isExpression)] + [visitNode(thisArg, visitor, isExpression), ...visitNodes(node.arguments, visitor, isExpression)], ); } return factory.updateCallExpression( node, factory.createPropertyAccessExpression(visitNode(target, visitor, isExpression), "call"), /*typeArguments*/ undefined, - [visitNode(thisArg, visitor, isExpression), ...visitNodes(node.arguments, visitor, isExpression)] + [visitNode(thisArg, visitor, isExpression), ...visitNodes(node.arguments, visitor, isExpression)], ); } - if (shouldTransformSuperInStaticInitializers && - currentClassElement && - isSuperProperty(node.expression) && - isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) && - lexicalEnvironment?.data?.classConstructor) { + if ( + shouldTransformSuperInStaticInitializers + && currentClassElement + && isSuperProperty(node.expression) + && isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) + && lexicalEnvironment?.data?.classConstructor + ) { // super.x() // super[x]() @@ -1358,7 +1462,7 @@ export function transformClassFields(context: TransformationContext): (x: Source const invocation = factory.createFunctionCallCall( visitNode(node.expression, visitor, isExpression), lexicalEnvironment.data.classConstructor, - visitNodes(node.arguments, visitor, isExpression) + visitNodes(node.arguments, visitor, isExpression), ); setOriginalNode(invocation, node); setTextRange(invocation, node); @@ -1369,8 +1473,10 @@ export function transformClassFields(context: TransformationContext): (x: Source } function visitTaggedTemplateExpression(node: TaggedTemplateExpression) { - if (isPrivateIdentifierPropertyAccessExpression(node.tag) && - accessPrivateIdentifier(node.tag.name)) { + if ( + isPrivateIdentifierPropertyAccessExpression(node.tag) + && accessPrivateIdentifier(node.tag.name) + ) { // Bind the `this` correctly for tagged template literals when the tag is a private identifier property access. const { thisArg, target } = factory.createCallBinding(node.tag, hoistVariableDeclaration, languageVersion); return factory.updateTaggedTemplateExpression( @@ -1378,23 +1484,24 @@ export function transformClassFields(context: TransformationContext): (x: Source factory.createCallExpression( factory.createPropertyAccessExpression(visitNode(target, visitor, isExpression), "bind"), /*typeArguments*/ undefined, - [visitNode(thisArg, visitor, isExpression)] + [visitNode(thisArg, visitor, isExpression)], ), /*typeArguments*/ undefined, - visitNode(node.template, visitor, isTemplateLiteral) + visitNode(node.template, visitor, isTemplateLiteral), ); } - if (shouldTransformSuperInStaticInitializers && - currentClassElement && - isSuperProperty(node.tag) && - isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) && - lexicalEnvironment?.data?.classConstructor) { - + if ( + shouldTransformSuperInStaticInitializers + && currentClassElement + && isSuperProperty(node.tag) + && isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) + && lexicalEnvironment?.data?.classConstructor + ) { // converts `` super.f`x` `` into `` Reflect.get(_baseTemp, "f", _classTemp).bind(_classTemp)`x` `` const invocation = factory.createFunctionBindCall( visitNode(node.tag, visitor, isExpression), lexicalEnvironment.data.classConstructor, - [] + [], ); setOriginalNode(invocation, node); setTextRange(invocation, node); @@ -1402,7 +1509,7 @@ export function transformClassFields(context: TransformationContext): (x: Source node, invocation, /*typeArguments*/ undefined, - visitNode(node.template, visitor, isTemplateLiteral) + visitNode(node.template, visitor, isTemplateLiteral), ); } return visitEachChild(node, visitor, context); @@ -1418,8 +1525,10 @@ export function transformClassFields(context: TransformationContext): (x: Source const result = visitNode(node.body.statements[0].expression, visitor, isExpression); // If the generated `_classThis` assignment is a noop (i.e., `_classThis = _classThis`), we can // eliminate the expression - if (isAssignmentExpression(result, /*excludeCompoundAssignment*/ true) && - result.left === result.right) { + if ( + isAssignmentExpression(result, /*excludeCompoundAssignment*/ true) + && result.left === result.right + ) { return undefined; } return result; @@ -1433,7 +1542,7 @@ export function transformClassFields(context: TransformationContext): (x: Source let statements = setCurrentClassElementAnd( node, statements => visitNodes(statements, visitor, isStatement), - node.body.statements + node.body.statements, ); statements = factory.mergeLexicalEnvironment(statements, endLexicalEnvironment()); @@ -1453,13 +1562,12 @@ export function transformClassFields(context: TransformationContext): (x: Source return false; } - const hasTransformableStatics = - (shouldTransformPrivateElementsOrClassStaticBlocks || - !!(getInternalEmitFlags(node) && InternalEmitFlags.TransformPrivateStaticElements)) && - some(staticPropertiesOrClassStaticBlocks, node => - isClassStaticBlockDeclaration(node) || - isPrivateIdentifierClassElementDeclaration(node) || - shouldTransformInitializers && isInitializedProperty(node)); + const hasTransformableStatics = (shouldTransformPrivateElementsOrClassStaticBlocks + || !!(getInternalEmitFlags(node) && InternalEmitFlags.TransformPrivateStaticElements)) + && some(staticPropertiesOrClassStaticBlocks, node => + isClassStaticBlockDeclaration(node) + || isPrivateIdentifierClassElementDeclaration(node) + || shouldTransformInitializers && isInitializedProperty(node)); return hasTransformableStatics; } return false; @@ -1476,11 +1584,11 @@ export function transformClassFields(context: TransformationContext): (x: Source node, visitNode(node.left, assignmentTargetVisitor, isExpression), node.operatorToken, - visitNode(node.right, visitor, isExpression) + visitNode(node.right, visitor, isExpression), ); - const expr = some(pendingExpressions) ? - factory.inlineExpressions(compact([...pendingExpressions, node])) : - node; + const expr = some(pendingExpressions) + ? factory.inlineExpressions(compact([...pendingExpressions, node])) + : node; pendingExpressions = savedPendingExpressions; return expr; } @@ -1516,25 +1624,35 @@ export function transformClassFields(context: TransformationContext): (x: Source Debug.assertNode(node, isAssignmentExpression); } - const left = skipOuterExpressions(node.left, OuterExpressionKinds.PartiallyEmittedExpressions | OuterExpressionKinds.Parentheses); + const left = skipOuterExpressions( + node.left, + OuterExpressionKinds.PartiallyEmittedExpressions | OuterExpressionKinds.Parentheses, + ); if (isPrivateIdentifierPropertyAccessExpression(left)) { // obj.#x = ... const info = accessPrivateIdentifier(left.name); if (info) { return setTextRange( setOriginalNode( - createPrivateIdentifierAssignment(info, left.expression, node.right, node.operatorToken.kind), - node + createPrivateIdentifierAssignment( + info, + left.expression, + node.right, + node.operatorToken.kind, + ), + node, ), - node + node, ); } } - else if (shouldTransformSuperInStaticInitializers && - currentClassElement && - isSuperProperty(node.left) && - isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) && - lexicalEnvironment?.data) { + else if ( + shouldTransformSuperInStaticInitializers + && currentClassElement + && isSuperProperty(node.left) + && isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) + && lexicalEnvironment?.data + ) { // super.x = ... // super[x] = ... // super.x += ... @@ -1545,13 +1663,14 @@ export function transformClassFields(context: TransformationContext): (x: Source node, visitInvalidSuperProperty(node.left), node.operatorToken, - visitNode(node.right, visitor, isExpression)); + visitNode(node.right, visitor, isExpression), + ); } if (classConstructor && superClassReference) { - let setterName = - isElementAccessExpression(node.left) ? visitNode(node.left.argumentExpression, visitor, isExpression) : - isIdentifier(node.left.name) ? factory.createStringLiteralFromNode(node.left.name) : - undefined; + let setterName = isElementAccessExpression(node.left) + ? visitNode(node.left.argumentExpression, visitor, isExpression) + : isIdentifier(node.left.name) ? factory.createStringLiteralFromNode(node.left.name) + : undefined; if (setterName) { // converts `super.x = 1` into `(Reflect.set(_baseTemp, "x", _a = 1, _classTemp), _a)` // converts `super[f()] = 1` into `(Reflect.set(_baseTemp, f(), _a = 1, _classTemp), _a)` @@ -1568,14 +1687,14 @@ export function transformClassFields(context: TransformationContext): (x: Source const superPropertyGet = factory.createReflectGetCall( superClassReference, getterName, - classConstructor + classConstructor, ); setOriginalNode(superPropertyGet, node.left); setTextRange(superPropertyGet, node.left); expression = factory.createBinaryExpression( superPropertyGet, getNonAssignmentOperatorForCompoundAssignment(node.operatorToken.kind), - expression + expression, ); setTextRange(expression, node); } @@ -1590,7 +1709,7 @@ export function transformClassFields(context: TransformationContext): (x: Source superClassReference, setterName, expression, - classConstructor + classConstructor, ); setOriginalNode(expression, node); setTextRange(expression, node); @@ -1613,9 +1732,9 @@ export function transformClassFields(context: TransformationContext): (x: Source } function visitCommaListExpression(node: CommaListExpression, discarded: boolean) { - const elements = discarded ? - visitCommaListElements(node.elements, discardedValueVisitor) : - visitCommaListElements(node.elements, visitor, discardedValueVisitor); + const elements = discarded + ? visitCommaListElements(node.elements, discardedValueVisitor) + : visitCommaListElements(node.elements, visitor, discardedValueVisitor); return factory.updateCommaListExpression(node, elements); } @@ -1625,15 +1744,18 @@ export function transformClassFields(context: TransformationContext): (x: Source // ... // 2. Return ? NamedEvaluation of |Expression| with argument _name_. - const visitorFunc: Visitor = - discarded ? discardedValueVisitor : - visitor; + const visitorFunc: Visitor = discarded ? discardedValueVisitor + : visitor; const expression = visitNode(node.expression, visitorFunc, isExpression); return factory.updateParenthesizedExpression(node, expression); } - - function createPrivateIdentifierAssignment(info: PrivateIdentifierInfo, receiver: Expression, right: Expression, operator: AssignmentOperator): Expression { + function createPrivateIdentifierAssignment( + info: PrivateIdentifierInfo, + receiver: Expression, + right: Expression, + operator: AssignmentOperator, + ): Expression { receiver = visitNode(receiver, visitor, isExpression); right = visitNode(right, visitor, isExpression); ensureDynamicThisIfNeeded(receiver); @@ -1644,20 +1766,20 @@ export function transformClassFields(context: TransformationContext): (x: Source right = factory.createBinaryExpression( createPrivateIdentifierAccessHelper(info, readExpression), getNonAssignmentOperatorForCompoundAssignment(operator), - right + right, ); } setCommentRange(receiver, moveRangePos(receiver, -1)); - switch(info.kind) { + switch (info.kind) { case PrivateIdentifierKind.Accessor: return emitHelpers().createClassPrivateFieldSetHelper( receiver, info.brandCheckIdentifier, right, info.kind, - info.setterName + info.setterName, ); case PrivateIdentifierKind.Method: return emitHelpers().createClassPrivateFieldSetHelper( @@ -1665,7 +1787,7 @@ export function transformClassFields(context: TransformationContext): (x: Source info.brandCheckIdentifier, right, info.kind, - /*f*/ undefined + /*f*/ undefined, ); case PrivateIdentifierKind.Field: return emitHelpers().createClassPrivateFieldSetHelper( @@ -1673,7 +1795,7 @@ export function transformClassFields(context: TransformationContext): (x: Source info.brandCheckIdentifier, right, info.kind, - info.isStatic ? info.variableName : undefined + info.isStatic ? info.variableName : undefined, ); case "untransformed": return Debug.fail("Access helpers should not be created for untransformed private elements"); @@ -1693,7 +1815,10 @@ export function transformClassFields(context: TransformationContext): (x: Source if (isClassDeclaration(original) && classOrConstructorParameterIsDecorated(legacyDecorators, original)) { facts |= ClassFacts.ClassWasDecorated; } - if (shouldTransformPrivateElementsOrClassStaticBlocks && (classHasClassThisAssignment(node) || classHasExplicitlyAssignedName(node))) { + if ( + shouldTransformPrivateElementsOrClassStaticBlocks + && (classHasClassThisAssignment(node) || classHasExplicitlyAssignedName(node)) + ) { facts |= ClassFacts.NeedsClassConstructorReference; } let containsPublicInstanceFields = false; @@ -1702,21 +1827,32 @@ export function transformClassFields(context: TransformationContext): (x: Source let containsInstanceAutoAccessors = false; for (const member of node.members) { if (isStatic(member)) { - if (member.name && (isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) && - shouldTransformPrivateElementsOrClassStaticBlocks) { + if ( + member.name && (isPrivateIdentifier(member.name) || isAutoAccessorPropertyDeclaration(member)) + && shouldTransformPrivateElementsOrClassStaticBlocks + ) { facts |= ClassFacts.NeedsClassConstructorReference; } - else if (isAutoAccessorPropertyDeclaration(member) && shouldTransformAutoAccessors === Ternary.True && !node.name && !node.emitNode?.classThis) { + else if ( + isAutoAccessorPropertyDeclaration(member) && shouldTransformAutoAccessors === Ternary.True + && !node.name && !node.emitNode?.classThis + ) { facts |= ClassFacts.NeedsClassConstructorReference; } if (isPropertyDeclaration(member) || isClassStaticBlockDeclaration(member)) { - if (shouldTransformThisInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalThis) { + if ( + shouldTransformThisInStaticInitializers + && member.transformFlags & TransformFlags.ContainsLexicalThis + ) { facts |= ClassFacts.NeedsSubstitutionForThisInClassStaticField; if (!(facts & ClassFacts.ClassWasDecorated)) { facts |= ClassFacts.NeedsClassConstructorReference; } } - if (shouldTransformSuperInStaticInitializers && member.transformFlags & TransformFlags.ContainsLexicalSuper) { + if ( + shouldTransformSuperInStaticInitializers + && member.transformFlags & TransformFlags.ContainsLexicalSuper + ) { if (!(facts & ClassFacts.ClassWasDecorated)) { facts |= ClassFacts.NeedsClassConstructorReference | ClassFacts.NeedsClassSuperReference; } @@ -1742,10 +1878,11 @@ export function transformClassFields(context: TransformationContext): (x: Source } const willHoistInitializersToConstructor = - shouldTransformInitializersUsingDefine && containsPublicInstanceFields || - shouldTransformInitializersUsingSet && containsInitializedPublicInstanceFields || - shouldTransformPrivateElementsOrClassStaticBlocks && containsInstancePrivateElements || - shouldTransformPrivateElementsOrClassStaticBlocks && containsInstanceAutoAccessors && shouldTransformAutoAccessors === Ternary.True; + shouldTransformInitializersUsingDefine && containsPublicInstanceFields + || shouldTransformInitializersUsingSet && containsInitializedPublicInstanceFields + || shouldTransformPrivateElementsOrClassStaticBlocks && containsInstancePrivateElements + || shouldTransformPrivateElementsOrClassStaticBlocks && containsInstanceAutoAccessors + && shouldTransformAutoAccessors === Ternary.True; if (willHoistInitializersToConstructor) { facts |= ClassFacts.WillHoistInitializersToConstructor; @@ -1763,15 +1900,18 @@ export function transformClassFields(context: TransformationContext): (x: Source node, factory.createAssignment( temp, - visitNode(node.expression, visitor, isExpression) + visitNode(node.expression, visitor, isExpression), ), - /*typeArguments*/ undefined + /*typeArguments*/ undefined, ); } return visitEachChild(node, visitor, context); } - function visitInNewClassLexicalEnvironment(node: T, visitor: (node: T, facts: ClassFacts) => U) { + function visitInNewClassLexicalEnvironment( + node: T, + visitor: (node: T, facts: ClassFacts) => U, + ) { const savedCurrentClassContainer = currentClassContainer; const savedPendingExpressions = pendingExpressions; const savedLexicalEnvironment = lexicalEnvironment; @@ -1779,7 +1919,8 @@ export function transformClassFields(context: TransformationContext): (x: Source pendingExpressions = undefined; startClassLexicalEnvironment(); - const shouldAlwaysTransformPrivateStaticElements = getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements; + const shouldAlwaysTransformPrivateStaticElements = getInternalEmitFlags(node) + & InternalEmitFlags.TransformPrivateStaticElements; if (shouldTransformPrivateElementsOrClassStaticBlocks || shouldAlwaysTransformPrivateStaticElements) { const name = getNameOfDeclaration(node); if (name && isIdentifier(name)) { @@ -1789,8 +1930,10 @@ export function transformClassFields(context: TransformationContext): (x: Source if (isStringLiteral(node.emitNode.assignedName)) { // If the class name was assigned from a string literal based on an Identifier, use the Identifier // as the prefix. - if (node.emitNode.assignedName.textSourceNode && - isIdentifier(node.emitNode.assignedName.textSourceNode)) { + if ( + node.emitNode.assignedName.textSourceNode + && isIdentifier(node.emitNode.assignedName.textSourceNode) + ) { getPrivateIdentifierEnvironment().data.className = node.emitNode.assignedName.textSourceNode; } // If the class name was assigned from a string literal that is a valid identifier, create an @@ -1808,7 +1951,7 @@ export function transformClassFields(context: TransformationContext): (x: Source if (some(privateInstanceMethodsAndAccessors)) { getPrivateIdentifierEnvironment().data.weakSetName = createHoistedVariableForClass( "instances", - privateInstanceMethodsAndAccessors[0].name + privateInstanceMethodsAndAccessors[0].name, ); } } @@ -1828,7 +1971,6 @@ export function transformClassFields(context: TransformationContext): (x: Source currentClassContainer = savedCurrentClassContainer; pendingExpressions = savedPendingExpressions; return result; - } function visitClassDeclaration(node: ClassDeclaration) { @@ -1851,7 +1993,10 @@ export function transformClassFields(context: TransformationContext): (x: Source if (shouldTransformPrivateElementsOrClassStaticBlocks && node.emitNode?.classThis) { getClassLexicalEnvironment().classConstructor = node.emitNode.classThis; - pendingClassReferenceAssignment = factory.createAssignment(node.emitNode.classThis, factory.getInternalName(node)); + pendingClassReferenceAssignment = factory.createAssignment( + node.emitNode.classThis, + factory.getInternalName(node), + ); } else { const temp = factory.createTempVariable(hoistVariableDeclaration, /*reservedInNestedScopes*/ true); @@ -1864,7 +2009,8 @@ export function transformClassFields(context: TransformationContext): (x: Source getClassLexicalEnvironment().classThis = node.emitNode.classThis; } - const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsConstructorReference; + const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) + & NodeCheckFlags.ContainsConstructorReference; const isExport = hasSyntacticModifier(node, ModifierFlags.Export); const isDefault = hasSyntacticModifier(node, ModifierFlags.Default); let modifiers = visitNodes(node.modifiers, modifierVisitor, isModifier); @@ -1881,7 +2027,10 @@ export function transformClassFields(context: TransformationContext): (x: Source statements.push(factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))); } - if (shouldTransformInitializersUsingSet || shouldTransformPrivateElementsOrClassStaticBlocks || getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements) { + if ( + shouldTransformInitializersUsingSet || shouldTransformPrivateElementsOrClassStaticBlocks + || getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements + ) { // Emit static property assignment. Because classDeclaration is lexically evaluated, // it is safe to emit static property assignment after classDeclaration // From ES6 specification: @@ -1899,7 +2048,7 @@ export function transformClassFields(context: TransformationContext): (x: Source statements.push(factory.createExportAssignment( /*modifiers*/ undefined, /*isExportEquals*/ false, - factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) + factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true), )); } @@ -1915,7 +2064,7 @@ export function transformClassFields(context: TransformationContext): (x: Source node.name, /*typeParameters*/ undefined, heritageClauses, - members + members, ); statements.unshift(classDecl); @@ -1959,7 +2108,10 @@ export function transformClassFields(context: TransformationContext): (x: Source } const requiresBlockScopedVar = classCheckFlags & NodeCheckFlags.BlockScopedBindingInLoop; - const temp = factory.createTempVariable(requiresBlockScopedVar ? addBlockScopedVariable : hoistVariableDeclaration, /*reservedInNestedScopes*/ true); + const temp = factory.createTempVariable( + requiresBlockScopedVar ? addBlockScopedVariable : hoistVariableDeclaration, + /*reservedInNestedScopes*/ true, + ); getClassLexicalEnvironment().classConstructor = factory.cloneNode(temp); return temp; } @@ -1981,7 +2133,7 @@ export function transformClassFields(context: TransformationContext): (x: Source node.name, /*typeParameters*/ undefined, heritageClauses, - members + members, ); const expressions: Expression[] = []; @@ -1991,16 +2143,19 @@ export function transformClassFields(context: TransformationContext): (x: Source // Static initializers are transformed to `static {}` blocks when `useDefineForClassFields: false` // and not also transforming static blocks. - const hasTransformableStatics = - (shouldTransformPrivateElementsOrClassStaticBlocks || getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements) && - some(staticPropertiesOrClassStaticBlocks, node => - isClassStaticBlockDeclaration(node) || - isPrivateIdentifierClassElementDeclaration(node) || - shouldTransformInitializers && isInitializedProperty(node)); + const hasTransformableStatics = (shouldTransformPrivateElementsOrClassStaticBlocks + || getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements) + && some(staticPropertiesOrClassStaticBlocks, node => + isClassStaticBlockDeclaration(node) + || isPrivateIdentifierClassElementDeclaration(node) + || shouldTransformInitializers && isInitializedProperty(node)); if (hasTransformableStatics || some(pendingExpressions)) { if (isDecoratedClassDeclaration) { - Debug.assertIsDefined(pendingStatements, "Decorated classes transformed by TypeScript are expected to be within a variable declaration."); + Debug.assertIsDefined( + pendingStatements, + "Decorated classes transformed by TypeScript are expected to be within a variable declaration.", + ); // Write any pending expressions from elided or moved computed property names if (some(pendingExpressions)) { @@ -2008,7 +2163,11 @@ export function transformClassFields(context: TransformationContext): (x: Source } if (some(staticPropertiesOrClassStaticBlocks)) { - addPropertyOrClassStaticBlockStatements(pendingStatements, staticPropertiesOrClassStaticBlocks, node.emitNode?.classThis ?? factory.getInternalName(node)); + addPropertyOrClassStaticBlockStatements( + pendingStatements, + staticPropertiesOrClassStaticBlocks, + node.emitNode?.classThis ?? factory.getInternalName(node), + ); } if (temp) { @@ -2035,7 +2194,10 @@ export function transformClassFields(context: TransformationContext): (x: Source // Add any pending expressions leftover from elided or relocated computed property names addRange(expressions, pendingExpressions); - addRange(expressions, generateInitializedPropertyExpressionsOrClassStaticBlock(staticPropertiesOrClassStaticBlocks, temp)); + addRange( + expressions, + generateInitializedPropertyExpressionsOrClassStaticBlock(staticPropertiesOrClassStaticBlocks, temp), + ); expressions.push(factory.cloneNode(temp)); } } @@ -2062,9 +2224,11 @@ export function transformClassFields(context: TransformationContext): (x: Source } function visitThisExpression(node: ThisExpression) { - if (shouldTransformThisInStaticInitializers && currentClassElement && - isClassStaticBlockDeclaration(currentClassElement) && - lexicalEnvironment?.data) { + if ( + shouldTransformThisInStaticInitializers && currentClassElement + && isClassStaticBlockDeclaration(currentClassElement) + && lexicalEnvironment?.data + ) { const { classThis, classConstructor } = lexicalEnvironment.data; return classThis ?? classConstructor ?? node; } @@ -2073,14 +2237,19 @@ export function transformClassFields(context: TransformationContext): (x: Source } function transformClassMembers(node: ClassDeclaration | ClassExpression) { - const shouldTransformPrivateStaticElementsInClass = !!(getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements); + const shouldTransformPrivateStaticElementsInClass = + !!(getInternalEmitFlags(node) & InternalEmitFlags.TransformPrivateStaticElements); // Declare private names if (shouldTransformPrivateElementsOrClassStaticBlocks || shouldTransformPrivateStaticElementsInFile) { for (const member of node.members) { if (isPrivateIdentifierClassElementDeclaration(member)) { if (shouldTransformClassElementToWeakMap(member)) { - addPrivateIdentifierToEnvironment(member, member.name, addPrivateIdentifierClassElementToEnvironment); + addPrivateIdentifierToEnvironment( + member, + member.name, + addPrivateIdentifierClassElementToEnvironment, + ); } else { const privateEnv = getPrivateIdentifierEnvironment(); @@ -2098,10 +2267,20 @@ export function transformClassFields(context: TransformationContext): (x: Source if (shouldTransformAutoAccessorsInCurrentClass()) { for (const member of node.members) { if (isAutoAccessorPropertyDeclaration(member)) { - const storageName = factory.getGeneratedPrivateNameForNode(member.name, /*prefix*/ undefined, "_accessor_storage"); - if (shouldTransformPrivateElementsOrClassStaticBlocks || - shouldTransformPrivateStaticElementsInClass && hasStaticModifier(member)) { - addPrivateIdentifierToEnvironment(member, storageName, addPrivateIdentifierPropertyDeclarationToEnvironment); + const storageName = factory.getGeneratedPrivateNameForNode( + member.name, + /*prefix*/ undefined, + "_accessor_storage", + ); + if ( + shouldTransformPrivateElementsOrClassStaticBlocks + || shouldTransformPrivateStaticElementsInClass && hasStaticModifier(member) + ) { + addPrivateIdentifierToEnvironment( + member, + storageName, + addPrivateIdentifierPropertyDeclarationToEnvironment, + ); } else { const privateEnv = getPrivateIdentifierEnvironment(); @@ -2140,9 +2319,12 @@ export function transformClassFields(context: TransformationContext): (x: Source /*parameters*/ [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, - factory.createBlock([statement])); + factory.createBlock([statement]), + ); prologue = factory.createAssignment(temp, arrow); - statement = factory.createExpressionStatement(factory.createCallExpression(temp, /*typeArguments*/ undefined, [])); + statement = factory.createExpressionStatement( + factory.createCallExpression(temp, /*typeArguments*/ undefined, []), + ); } const block = factory.createBlock([statement]); @@ -2160,9 +2342,12 @@ export function transformClassFields(context: TransformationContext): (x: Source membersArray = append(membersArray, classNamedEvaluationHelperBlock); membersArray = append(membersArray, syntheticConstructor); membersArray = append(membersArray, syntheticStaticBlock); - const remainingMembers = classThisAssignmentBlock || classNamedEvaluationHelperBlock ? - filter(members, member => member !== classThisAssignmentBlock && member !== classNamedEvaluationHelperBlock) : - members; + const remainingMembers = classThisAssignmentBlock || classNamedEvaluationHelperBlock + ? filter( + members, + member => member !== classThisAssignmentBlock && member !== classNamedEvaluationHelperBlock, + ) + : members; membersArray = addRange(membersArray, remainingMembers); members = setTextRange(factory.createNodeArray(membersArray), /*location*/ node.members); } @@ -2180,20 +2365,27 @@ export function transformClassFields(context: TransformationContext): (x: Source factory.createNewExpression( factory.createIdentifier("WeakSet"), /*typeArguments*/ undefined, - [] - ) - ) + [], + ), + ), ); } - function transformConstructor(constructor: ConstructorDeclaration | undefined, container: ClassDeclaration | ClassExpression) { + function transformConstructor( + constructor: ConstructorDeclaration | undefined, + container: ClassDeclaration | ClassExpression, + ) { constructor = visitNode(constructor, visitor, isConstructorDeclaration); - if (!lexicalEnvironment?.data || !(lexicalEnvironment.data.facts & ClassFacts.WillHoistInitializersToConstructor)) { + if ( + !lexicalEnvironment?.data + || !(lexicalEnvironment.data.facts & ClassFacts.WillHoistInitializersToConstructor) + ) { return constructor; } const extendsClauseElement = getEffectiveBaseTypeNode(container); - const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); + const isDerivedClass = !!(extendsClauseElement + && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); const parameters = visitParameterList(constructor ? constructor.parameters : undefined, visitor, context); const body = transformConstructorBody(container, constructor, isDerivedClass); if (!body) { @@ -2211,19 +2403,30 @@ export function transformClassFields(context: TransformationContext): (x: Source factory.createConstructorDeclaration( /*modifiers*/ undefined, parameters ?? [], - body + body, ), - constructor || container + constructor || container, ), - constructor - ) + constructor, + ), ); } - function transformConstructorBodyWorker(statementsOut: Statement[], statementsIn: NodeArray, statementOffset: number, superPath: readonly number[], superPathDepth: number, initializerStatements: readonly Statement[], constructor: ConstructorDeclaration) { + function transformConstructorBodyWorker( + statementsOut: Statement[], + statementsIn: NodeArray, + statementOffset: number, + superPath: readonly number[], + superPathDepth: number, + initializerStatements: readonly Statement[], + constructor: ConstructorDeclaration, + ) { const superStatementIndex = superPath[superPathDepth]; const superStatement = statementsIn[superStatementIndex]; - addRange(statementsOut, visitNodes(statementsIn, visitor, isStatement, statementOffset, superStatementIndex - statementOffset)); + addRange( + statementsOut, + visitNodes(statementsIn, visitor, isStatement, statementOffset, superStatementIndex - statementOffset), + ); statementOffset = superStatementIndex + 1; if (isTryStatement(superStatement)) { const tryBlockStatements: Statement[] = []; @@ -2235,7 +2438,8 @@ export function transformClassFields(context: TransformationContext): (x: Source superPath, superPathDepth + 1, initializerStatements, - constructor); + constructor, + ); const tryBlockStatementsArray = factory.createNodeArray(tryBlockStatements); setTextRange(tryBlockStatementsArray, superStatement.tryBlock.statements); @@ -2244,7 +2448,8 @@ export function transformClassFields(context: TransformationContext): (x: Source superStatement, factory.updateBlock(superStatement.tryBlock, tryBlockStatements), visitNode(superStatement.catchClause, visitor, isCatchClause), - visitNode(superStatement.finallyBlock, visitor, isBlock))); + visitNode(superStatement.finallyBlock, visitor, isBlock), + )); } else { addRange(statementsOut, visitNodes(statementsIn, visitor, isStatement, superStatementIndex, 1)); @@ -2280,11 +2485,19 @@ export function transformClassFields(context: TransformationContext): (x: Source addRange(statementsOut, visitNodes(statementsIn, visitor, isStatement, statementOffset)); } - function transformConstructorBody(node: ClassDeclaration | ClassExpression, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) { + function transformConstructorBody( + node: ClassDeclaration | ClassExpression, + constructor: ConstructorDeclaration | undefined, + isDerivedClass: boolean, + ) { const instanceProperties = getProperties(node, /*requireInitializer*/ false, /*isStatic*/ false); let properties = instanceProperties; if (!useDefineForClassFields) { - properties = filter(properties, property => !!property.initializer || isPrivateIdentifier(property.name) || hasAccessorModifier(property)); + properties = filter( + properties, + property => + !!property.initializer || isPrivateIdentifier(property.name) || hasAccessorModifier(property), + ); } const privateMethodsAndAccessors = getPrivateInstanceMethodsAndAccessors(node); @@ -2317,8 +2530,14 @@ export function transformClassFields(context: TransformationContext): (x: Source // private methods can be called in property initializers, they should execute first. addInstanceMethodStatements(initializerStatements, privateMethodsAndAccessors, receiver); if (constructor) { - const parameterProperties = filter(instanceProperties, prop => isParameterPropertyDeclaration(getOriginalNode(prop), constructor)); - const nonParameterProperties = filter(properties, prop => !isParameterPropertyDeclaration(getOriginalNode(prop), constructor)); + const parameterProperties = filter( + instanceProperties, + prop => isParameterPropertyDeclaration(getOriginalNode(prop), constructor), + ); + const nonParameterProperties = filter( + properties, + prop => !isParameterPropertyDeclaration(getOriginalNode(prop), constructor), + ); addPropertyOrClassStaticBlockStatements(initializerStatements, parameterProperties, receiver); addPropertyOrClassStaticBlockStatements(initializerStatements, nonParameterProperties, receiver); } @@ -2327,7 +2546,12 @@ export function transformClassFields(context: TransformationContext): (x: Source } if (constructor?.body) { - statementOffset = factory.copyPrologue(constructor.body.statements, statements, /*ensureUseStrict*/ false, visitor); + statementOffset = factory.copyPrologue( + constructor.body.statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); const superStatementIndices = findSuperStatementIndexPath(constructor.body.statements, statementOffset); if (superStatementIndices.length) { transformConstructorBodyWorker( @@ -2337,7 +2561,7 @@ export function transformClassFields(context: TransformationContext): (x: Source superStatementIndices, /*superPathDepth*/ 0, initializerStatements, - constructor + constructor, ); } else { @@ -2367,9 +2591,9 @@ export function transformClassFields(context: TransformationContext): (x: Source factory.createCallExpression( factory.createSuper(), /*typeArguments*/ undefined, - [factory.createSpreadElement(factory.createIdentifier("arguments"))] - ) - ) + [factory.createSpreadElement(factory.createIdentifier("arguments"))], + ), + ), ); } addRange(statements, initializerStatements); @@ -2381,19 +2605,19 @@ export function transformClassFields(context: TransformationContext): (x: Source return undefined; } - const multiLine = constructor?.body && constructor.body.statements.length >= statements.length ? - constructor.body.multiLine ?? statements.length > 0 : - statements.length > 0; + const multiLine = constructor?.body && constructor.body.statements.length >= statements.length + ? constructor.body.multiLine ?? statements.length > 0 + : statements.length > 0; return setTextRange( factory.createBlock( setTextRange( factory.createNodeArray(statements), - /*location*/ constructor ? constructor.body!.statements : node.members + /*location*/ constructor ? constructor.body!.statements : node.members, ), - multiLine + multiLine, ), - /*location*/ constructor ? constructor.body : undefined + /*location*/ constructor ? constructor.body : undefined, ); } @@ -2403,7 +2627,11 @@ export function transformClassFields(context: TransformationContext): (x: Source * @param properties An array of property declarations to transform. * @param receiver The receiver on which each property should be assigned. */ - function addPropertyOrClassStaticBlockStatements(statements: Statement[], properties: readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[], receiver: LeftHandSideExpression) { + function addPropertyOrClassStaticBlockStatements( + statements: Statement[], + properties: readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[], + receiver: LeftHandSideExpression, + ) { for (const property of properties) { if (isStatic(property) && !shouldTransformPrivateElementsOrClassStaticBlocks) { continue; @@ -2418,10 +2646,13 @@ export function transformClassFields(context: TransformationContext): (x: Source } } - function transformPropertyOrClassStaticBlock(property: PropertyDeclaration | ClassStaticBlockDeclaration, receiver: LeftHandSideExpression) { - const expression = isClassStaticBlockDeclaration(property) ? - setCurrentClassElementAnd(property, transformClassStaticBlockDeclaration, property) : - transformProperty(property, receiver); + function transformPropertyOrClassStaticBlock( + property: PropertyDeclaration | ClassStaticBlockDeclaration, + receiver: LeftHandSideExpression, + ) { + const expression = isClassStaticBlockDeclaration(property) + ? setCurrentClassElementAnd(property, transformClassStaticBlockDeclaration, property) + : transformProperty(property, receiver); if (!expression) { return undefined; } @@ -2462,12 +2693,15 @@ export function transformClassFields(context: TransformationContext): (x: Source * @param propertiesOrClassStaticBlocks An array of property declarations to transform. * @param receiver The receiver on which each property should be assigned. */ - function generateInitializedPropertyExpressionsOrClassStaticBlock(propertiesOrClassStaticBlocks: readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[], receiver: LeftHandSideExpression) { + function generateInitializedPropertyExpressionsOrClassStaticBlock( + propertiesOrClassStaticBlocks: readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[], + receiver: LeftHandSideExpression, + ) { const expressions: Expression[] = []; for (const property of propertiesOrClassStaticBlocks) { - const expression = isClassStaticBlockDeclaration(property) ? - setCurrentClassElementAnd(property, transformClassStaticBlockDeclaration, property) : - setCurrentClassElementAnd(property, () => transformProperty(property, receiver), /*arg*/ undefined); + const expression = isClassStaticBlockDeclaration(property) + ? setCurrentClassElementAnd(property, transformClassStaticBlockDeclaration, property) + : setCurrentClassElementAnd(property, () => transformProperty(property, receiver), /*arg*/ undefined); if (!expression) { continue; } @@ -2510,18 +2744,20 @@ export function transformClassFields(context: TransformationContext): (x: Source property = transformNamedEvaluation(context, property); } - const propertyName = - hasAccessorModifier(property) ? - factory.getGeneratedPrivateNameForNode(property.name) : - isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) ? - factory.updateComputedPropertyName(property.name, factory.getGeneratedNameForNode(property.name)) : - property.name; + const propertyName = hasAccessorModifier(property) + ? factory.getGeneratedPrivateNameForNode(property.name) + : isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) + ? factory.updateComputedPropertyName(property.name, factory.getGeneratedNameForNode(property.name)) + : property.name; if (hasStaticModifier(property)) { currentClassElement = property; } - if (isPrivateIdentifier(propertyName) && shouldTransformClassElementToWeakMap(property as PrivateIdentifierPropertyDeclaration)) { + if ( + isPrivateIdentifier(propertyName) + && shouldTransformClassElementToWeakMap(property as PrivateIdentifierPropertyDeclaration) + ) { const privateIdentifierInfo = accessPrivateIdentifier(propertyName); if (privateIdentifierInfo) { if (privateIdentifierInfo.kind === PrivateIdentifierKind.Field) { @@ -2530,14 +2766,14 @@ export function transformClassFields(context: TransformationContext): (x: Source factory, receiver, visitNode(property.initializer, visitor, isExpression), - privateIdentifierInfo.brandCheckIdentifier + privateIdentifierInfo.brandCheckIdentifier, ); } else { return createPrivateStaticFieldInitializer( factory, privateIdentifierInfo.variableName, - visitNode(property.initializer, visitor, isExpression) + visitNode(property.initializer, visitor, isExpression), ); } } @@ -2559,18 +2795,23 @@ export function transformClassFields(context: TransformationContext): (x: Source } let initializer = visitNode(property.initializer, visitor, isExpression); - if (isParameterPropertyDeclaration(propertyOriginalNode, propertyOriginalNode.parent) && isIdentifier(propertyName)) { + if ( + isParameterPropertyDeclaration(propertyOriginalNode, propertyOriginalNode.parent) + && isIdentifier(propertyName) + ) { // A parameter-property declaration always overrides the initializer. The only time a parameter-property // declaration *should* have an initializer is when decorators have added initializers that need to run before // any other initializer const localName = factory.cloneNode(propertyName); if (initializer) { // unwrap `(__runInitializers(this, _instanceExtraInitializers), void 0)` - if (isParenthesizedExpression(initializer) && - isCommaExpression(initializer.expression) && - isCallToHelper(initializer.expression.left, "___runInitializers" as __String) && - isVoidExpression(initializer.expression.right) && - isNumericLiteral(initializer.expression.right.expression)) { + if ( + isParenthesizedExpression(initializer) + && isCommaExpression(initializer.expression) + && isCallToHelper(initializer.expression.left, "___runInitializers" as __String) + && isVoidExpression(initializer.expression.right) + && isNumericLiteral(initializer.expression.right.expression) + ) { initializer = initializer.expression.left; } initializer = factory.inlineExpressions([initializer, localName]); @@ -2587,16 +2828,27 @@ export function transformClassFields(context: TransformationContext): (x: Source } if (emitAssignment || isPrivateIdentifier(propertyName)) { - const memberAccess = createMemberAccessForPropertyName(factory, receiver, propertyName, /*location*/ propertyName); + const memberAccess = createMemberAccessForPropertyName( + factory, + receiver, + propertyName, + /*location*/ propertyName, + ); addEmitFlags(memberAccess, EmitFlags.NoLeadingComments); const expression = factory.createAssignment(memberAccess, initializer); return expression; } else { const name = isComputedPropertyName(propertyName) ? propertyName.expression - : isIdentifier(propertyName) ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText)) + : isIdentifier(propertyName) + ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText)) : propertyName; - const descriptor = factory.createPropertyDescriptor({ value: initializer, configurable: true, writable: true, enumerable: true }); + const descriptor = factory.createPropertyDescriptor({ + value: initializer, + configurable: true, + writable: true, + enumerable: true, + }); return factory.createObjectDefinePropertyCall(receiver, name, descriptor); } } @@ -2638,7 +2890,11 @@ export function transformClassFields(context: TransformationContext): (x: Source * @param methods An array of method declarations. * @param receiver The receiver on which each method should be assigned. */ - function addInstanceMethodStatements(statements: Statement[], methods: readonly (MethodDeclaration | AccessorDeclaration | AutoAccessorPropertyDeclaration)[], receiver: LeftHandSideExpression) { + function addInstanceMethodStatements( + statements: Statement[], + methods: readonly (MethodDeclaration | AccessorDeclaration | AutoAccessorPropertyDeclaration)[], + receiver: LeftHandSideExpression, + ) { if (!shouldTransformPrivateElementsOrClassStaticBlocks || !some(methods)) { return; } @@ -2647,21 +2903,23 @@ export function transformClassFields(context: TransformationContext): (x: Source Debug.assert(weakSetName, "weakSetName should be set in private identifier environment"); statements.push( factory.createExpressionStatement( - createPrivateInstanceMethodInitializer(factory, receiver, weakSetName) - ) + createPrivateInstanceMethodInitializer(factory, receiver, weakSetName), + ), ); } function visitInvalidSuperProperty(node: SuperProperty) { - return isPropertyAccessExpression(node) ? - factory.updatePropertyAccessExpression( + return isPropertyAccessExpression(node) + ? factory.updatePropertyAccessExpression( node, factory.createVoidZero(), - node.name) : - factory.updateElementAccessExpression( + node.name, + ) + : factory.updateElementAccessExpression( node, factory.createVoidZero(), - visitNode(node.argumentExpression, visitor, isExpression)); + visitNode(node.argumentExpression, visitor, isExpression), + ); } /** @@ -2675,7 +2933,8 @@ export function transformClassFields(context: TransformationContext): (x: Source const expression = visitNode(name.expression, visitor, isExpression); const innerExpression = skipPartiallyEmittedExpressions(expression); const inlinable = isSimpleInlineableExpression(innerExpression); - const alreadyTransformed = !!cacheAssignment || isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left); + const alreadyTransformed = !!cacheAssignment + || isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left); if (!alreadyTransformed && !inlinable && shouldHoist) { const generatedName = factory.getGeneratedNameForNode(name); if (resolver.getNodeCheckFlags(name) & NodeCheckFlags.BlockScopedBindingInLoop) { @@ -2728,22 +2987,62 @@ export function transformClassFields(context: TransformationContext): (x: Source privateEnv: PrivateEnv, isStatic: boolean, isValid: boolean, - previousInfo: PrivateIdentifierInfo | undefined + previousInfo: PrivateIdentifierInfo | undefined, ) { if (isAutoAccessorPropertyDeclaration(node)) { - addPrivateIdentifierAutoAccessorPropertyDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierAutoAccessorPropertyDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } else if (isPropertyDeclaration(node)) { - addPrivateIdentifierPropertyDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierPropertyDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } else if (isMethodDeclaration(node)) { - addPrivateIdentifierMethodDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierMethodDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } else if (isGetAccessorDeclaration(node)) { - addPrivateIdentifierGetAccessorDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierGetAccessorDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } else if (isSetAccessorDeclaration(node)) { - addPrivateIdentifierSetAccessorDeclarationToEnvironment(node, name, lex, privateEnv, isStatic, isValid, previousInfo); + addPrivateIdentifierSetAccessorDeclarationToEnvironment( + node, + name, + lex, + privateEnv, + isStatic, + isValid, + previousInfo, + ); } } @@ -2754,11 +3053,13 @@ export function transformClassFields(context: TransformationContext): (x: Source privateEnv: PrivateEnv, isStatic: boolean, isValid: boolean, - _previousInfo: PrivateIdentifierInfo | undefined + _previousInfo: PrivateIdentifierInfo | undefined, ) { if (isStatic) { - const brandCheckIdentifier = - Debug.checkDefined(lex.classThis ?? lex.classConstructor, "classConstructor should be set in private identifier environment"); + const brandCheckIdentifier = Debug.checkDefined( + lex.classThis ?? lex.classConstructor, + "classConstructor should be set in private identifier environment", + ); const variableName = createHoistedVariableForPrivateName(name); setPrivateIdentifier(privateEnv, name, { @@ -2784,8 +3085,8 @@ export function transformClassFields(context: TransformationContext): (x: Source factory.createNewExpression( factory.createIdentifier("WeakMap"), /*typeArguments*/ undefined, - [] - ) + [], + ), )); } } @@ -2797,12 +3098,18 @@ export function transformClassFields(context: TransformationContext): (x: Source privateEnv: PrivateEnv, isStatic: boolean, isValid: boolean, - _previousInfo: PrivateIdentifierInfo | undefined + _previousInfo: PrivateIdentifierInfo | undefined, ) { const methodName = createHoistedVariableForPrivateName(name); - const brandCheckIdentifier = isStatic ? - Debug.checkDefined(lex.classThis ?? lex.classConstructor, "classConstructor should be set in private identifier environment") : - Debug.checkDefined(privateEnv.data.weakSetName, "weakSetName should be set in private identifier environment"); + const brandCheckIdentifier = isStatic + ? Debug.checkDefined( + lex.classThis ?? lex.classConstructor, + "classConstructor should be set in private identifier environment", + ) + : Debug.checkDefined( + privateEnv.data.weakSetName, + "weakSetName should be set in private identifier environment", + ); setPrivateIdentifier(privateEnv, name, { kind: PrivateIdentifierKind.Method, @@ -2820,14 +3127,23 @@ export function transformClassFields(context: TransformationContext): (x: Source privateEnv: PrivateEnv, isStatic: boolean, isValid: boolean, - previousInfo: PrivateIdentifierInfo | undefined + previousInfo: PrivateIdentifierInfo | undefined, ) { const getterName = createHoistedVariableForPrivateName(name, "_get"); - const brandCheckIdentifier = isStatic ? - Debug.checkDefined(lex.classThis ?? lex.classConstructor, "classConstructor should be set in private identifier environment") : - Debug.checkDefined(privateEnv.data.weakSetName, "weakSetName should be set in private identifier environment"); + const brandCheckIdentifier = isStatic + ? Debug.checkDefined( + lex.classThis ?? lex.classConstructor, + "classConstructor should be set in private identifier environment", + ) + : Debug.checkDefined( + privateEnv.data.weakSetName, + "weakSetName should be set in private identifier environment", + ); - if (previousInfo?.kind === PrivateIdentifierKind.Accessor && previousInfo.isStatic === isStatic && !previousInfo.getterName) { + if ( + previousInfo?.kind === PrivateIdentifierKind.Accessor && previousInfo.isStatic === isStatic + && !previousInfo.getterName + ) { previousInfo.getterName = getterName; } else { @@ -2849,15 +3165,23 @@ export function transformClassFields(context: TransformationContext): (x: Source privateEnv: PrivateEnv, isStatic: boolean, isValid: boolean, - previousInfo: PrivateIdentifierInfo | undefined + previousInfo: PrivateIdentifierInfo | undefined, ) { const setterName = createHoistedVariableForPrivateName(name, "_set"); - const brandCheckIdentifier = isStatic ? - Debug.checkDefined(lex.classThis ?? lex.classConstructor, "classConstructor should be set in private identifier environment") : - Debug.checkDefined(privateEnv.data.weakSetName, "weakSetName should be set in private identifier environment"); + const brandCheckIdentifier = isStatic + ? Debug.checkDefined( + lex.classThis ?? lex.classConstructor, + "classConstructor should be set in private identifier environment", + ) + : Debug.checkDefined( + privateEnv.data.weakSetName, + "weakSetName should be set in private identifier environment", + ); - if (previousInfo?.kind === PrivateIdentifierKind.Accessor && - previousInfo.isStatic === isStatic && !previousInfo.setterName) { + if ( + previousInfo?.kind === PrivateIdentifierKind.Accessor + && previousInfo.isStatic === isStatic && !previousInfo.setterName + ) { previousInfo.setterName = setterName; } else { @@ -2879,13 +3203,19 @@ export function transformClassFields(context: TransformationContext): (x: Source privateEnv: PrivateEnv, isStatic: boolean, isValid: boolean, - _previousInfo: PrivateIdentifierInfo | undefined + _previousInfo: PrivateIdentifierInfo | undefined, ) { const getterName = createHoistedVariableForPrivateName(name, "_get"); const setterName = createHoistedVariableForPrivateName(name, "_set"); - const brandCheckIdentifier = isStatic ? - Debug.checkDefined(lex.classThis ?? lex.classConstructor, "classConstructor should be set in private identifier environment") : - Debug.checkDefined(privateEnv.data.weakSetName, "weakSetName should be set in private identifier environment"); + const brandCheckIdentifier = isStatic + ? Debug.checkDefined( + lex.classThis ?? lex.classConstructor, + "classConstructor should be set in private identifier environment", + ) + : Debug.checkDefined( + privateEnv.data.weakSetName, + "weakSetName should be set in private identifier environment", + ); setPrivateIdentifier(privateEnv, name, { kind: PrivateIdentifierKind.Accessor, @@ -2897,7 +3227,9 @@ export function transformClassFields(context: TransformationContext): (x: Source }); } - function addPrivateIdentifierToEnvironment( + function addPrivateIdentifierToEnvironment< + T extends PropertyDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, + >( node: T, name: PrivateIdentifier, addDeclaration: ( @@ -2907,8 +3239,8 @@ export function transformClassFields(context: TransformationContext): (x: Source privateEnv: PrivateEnv, isStatic: boolean, isValid: boolean, - previousInfo: PrivateIdentifierInfo | undefined - ) => void + previousInfo: PrivateIdentifierInfo | undefined, + ) => void, ) { const lex = getClassLexicalEnvironment(); const privateEnv = getPrivateIdentifierEnvironment(); @@ -2918,13 +3250,28 @@ export function transformClassFields(context: TransformationContext): (x: Source addDeclaration(node, name, lex, privateEnv, isStatic, isValid, previousInfo); } - function createHoistedVariableForClass(name: string | PrivateIdentifier | undefined, node: PrivateIdentifier | ClassStaticBlockDeclaration, suffix?: string): Identifier { + function createHoistedVariableForClass( + name: string | PrivateIdentifier | undefined, + node: PrivateIdentifier | ClassStaticBlockDeclaration, + suffix?: string, + ): Identifier { const { className } = getPrivateIdentifierEnvironment().data; const prefix: GeneratedNamePart | string = className ? { prefix: "_", node: className, suffix: "_" } : "_"; - const identifier = - typeof name === "object" ? factory.getGeneratedNameForNode(name, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes, prefix, suffix) : - typeof name === "string" ? factory.createUniqueName(name, GeneratedIdentifierFlags.Optimistic, prefix, suffix) : - factory.createTempVariable(/*recordTempVariable*/ undefined, /*reservedInNestedScopes*/ true, prefix, suffix); + const identifier = typeof name === "object" + ? factory.getGeneratedNameForNode( + name, + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes, + prefix, + suffix, + ) + : typeof name === "string" + ? factory.createUniqueName(name, GeneratedIdentifierFlags.Optimistic, prefix, suffix) + : factory.createTempVariable( + /*recordTempVariable*/ undefined, + /*reservedInNestedScopes*/ true, + prefix, + suffix, + ); if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.BlockScopedBindingInLoop) { addBlockScopedVariable(identifier); @@ -2962,7 +3309,13 @@ export function transformClassFields(context: TransformationContext): (x: Source // differently inside the function. if (isThisProperty(node) || isSuperProperty(node) || !isSimpleCopiableExpression(node.expression)) { receiver = factory.createTempVariable(hoistVariableDeclaration, /*reservedInNestedScopes*/ true); - getPendingExpressions().push(factory.createBinaryExpression(receiver, SyntaxKind.EqualsToken, visitNode(node.expression, visitor, isExpression))); + getPendingExpressions().push( + factory.createBinaryExpression( + receiver, + SyntaxKind.EqualsToken, + visitNode(node.expression, visitor, isExpression), + ), + ); } return factory.createAssignmentTargetWrapper( parameter, @@ -2970,8 +3323,8 @@ export function transformClassFields(context: TransformationContext): (x: Source info, receiver, parameter, - SyntaxKind.EqualsToken - ) + SyntaxKind.EqualsToken, + ), ); } @@ -2983,20 +3336,21 @@ export function transformClassFields(context: TransformationContext): (x: Source if (isPrivateIdentifierPropertyAccessExpression(node)) { return wrapPrivateIdentifierForDestructuringTarget(node); } - else if (shouldTransformSuperInStaticInitializers && - currentClassElement && - isSuperProperty(node) && - isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) && - lexicalEnvironment?.data) { + else if ( + shouldTransformSuperInStaticInitializers + && currentClassElement + && isSuperProperty(node) + && isStaticPropertyDeclarationOrClassStaticBlock(currentClassElement) + && lexicalEnvironment?.data + ) { const { classConstructor, superClassReference, facts } = lexicalEnvironment.data; if (facts & ClassFacts.ClassWasDecorated) { return visitInvalidSuperProperty(node); } else if (classConstructor && superClassReference) { - const name = - isElementAccessExpression(node) ? visitNode(node.argumentExpression, visitor, isExpression) : - isIdentifier(node.name) ? factory.createStringLiteralFromNode(node.name) : - undefined; + const name = isElementAccessExpression(node) ? visitNode(node.argumentExpression, visitor, isExpression) + : isIdentifier(node.name) ? factory.createStringLiteralFromNode(node.name) + : undefined; if (name) { const temp = factory.createTempVariable(/*recordTempVariable*/ undefined); return factory.createAssignmentTargetWrapper( @@ -3006,7 +3360,7 @@ export function transformClassFields(context: TransformationContext): (x: Source name, temp, classConstructor, - ) + ), ); } } @@ -3014,7 +3368,9 @@ export function transformClassFields(context: TransformationContext): (x: Source return visitEachChild(node, visitor, context); } - function visitAssignmentElement(node: Exclude): ArrayAssignmentElement { + function visitAssignmentElement( + node: Exclude, + ): ArrayAssignmentElement { // 13.15.5.5 RS: IteratorDestructuringAssignmentEvaluation // AssignmentElement : DestructuringAssignmentTarget Initializer? // ... @@ -3029,7 +3385,9 @@ export function transformClassFields(context: TransformationContext): (x: Source if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true)) { const left = visitDestructuringAssignmentTarget(node.left); const right = visitNode(node.right, visitor, isExpression); - return factory.updateBinaryExpression(node, left, node.operatorToken, right) as AssignmentExpression; + return factory.updateBinaryExpression(node, left, node.operatorToken, right) as AssignmentExpression< + EqualsToken + >; } return visitDestructuringAssignmentTarget(node) as ArrayAssignmentElement; } @@ -3124,7 +3482,7 @@ export function transformClassFields(context: TransformationContext): (x: Source // [ { set value(x) { this.#myProp = x; } }.value ] = [ "hello" ]; return factory.updateArrayLiteralExpression( node, - visitNodes(node.elements, visitArrayAssignmentElement, isExpression) + visitNodes(node.elements, visitArrayAssignmentElement, isExpression), ); } else { @@ -3138,7 +3496,7 @@ export function transformClassFields(context: TransformationContext): (x: Source // ({ stringProperty: { set value(x) { this.#myProp = x; } }.value }) = { stringProperty: "hello" }; return factory.updateObjectLiteralExpression( node, - visitNodes(node.properties, visitObjectAssignmentElement, isObjectLiteralElementLike) + visitNodes(node.properties, visitObjectAssignmentElement, isObjectLiteralElementLike), ); } } @@ -3152,7 +3510,8 @@ export function transformClassFields(context: TransformationContext): (x: Source const savedPreviousShouldSubstituteThisWithClassThis = previousShouldSubstituteThisWithClassThis; lexicalEnvironment = lex; previousShouldSubstituteThisWithClassThis = shouldSubstituteThisWithClassThis; - shouldSubstituteThisWithClassThis = !isClassStaticBlockDeclaration(original) || !(getInternalEmitFlags(original) & InternalEmitFlags.TransformPrivateStaticElements); + shouldSubstituteThisWithClassThis = !isClassStaticBlockDeclaration(original) + || !(getInternalEmitFlags(original) & InternalEmitFlags.TransformPrivateStaticElements); previousOnEmitNode(hint, node, emitCallback); shouldSubstituteThisWithClassThis = previousShouldSubstituteThisWithClassThis; previousShouldSubstituteThisWithClassThis = savedPreviousShouldSubstituteThisWithClassThis; @@ -3231,9 +3590,11 @@ export function transformClassFields(context: TransformationContext): (x: Source } function substituteThisExpression(node: ThisExpression) { - if (enabledSubstitutions & ClassPropertySubstitutionFlags.ClassStaticThisOrSuperReference && - lexicalEnvironment?.data && - !noSubstitution.has(node)) { + if ( + enabledSubstitutions & ClassPropertySubstitutionFlags.ClassStaticThisOrSuperReference + && lexicalEnvironment?.data + && !noSubstitution.has(node) + ) { const { facts, classConstructor, classThis } = lexicalEnvironment.data; const substituteThis = shouldSubstituteThisWithClassThis ? classThis ?? classConstructor : classConstructor; if (substituteThis) { @@ -3242,7 +3603,7 @@ export function transformClassFields(context: TransformationContext): (x: Source factory.cloneNode(substituteThis), node, ), - node + node, ); } if (facts & ClassFacts.ClassWasDecorated && legacyDecorators) { @@ -3281,28 +3642,41 @@ export function transformClassFields(context: TransformationContext): (x: Source } } -function createPrivateStaticFieldInitializer(factory: NodeFactory, variableName: Identifier, initializer: Expression | undefined) { +function createPrivateStaticFieldInitializer( + factory: NodeFactory, + variableName: Identifier, + initializer: Expression | undefined, +) { return factory.createAssignment( variableName, factory.createObjectLiteralExpression([ - factory.createPropertyAssignment("value", initializer || factory.createVoidZero()) - ]) + factory.createPropertyAssignment("value", initializer || factory.createVoidZero()), + ]), ); } -function createPrivateInstanceFieldInitializer(factory: NodeFactory, receiver: LeftHandSideExpression, initializer: Expression | undefined, weakMapName: Identifier) { +function createPrivateInstanceFieldInitializer( + factory: NodeFactory, + receiver: LeftHandSideExpression, + initializer: Expression | undefined, + weakMapName: Identifier, +) { return factory.createCallExpression( factory.createPropertyAccessExpression(weakMapName, "set"), /*typeArguments*/ undefined, - [receiver, initializer || factory.createVoidZero()] + [receiver, initializer || factory.createVoidZero()], ); } -function createPrivateInstanceMethodInitializer(factory: NodeFactory, receiver: LeftHandSideExpression, weakSetName: Identifier) { +function createPrivateInstanceMethodInitializer( + factory: NodeFactory, + receiver: LeftHandSideExpression, + weakSetName: Identifier, +) { return factory.createCallExpression( factory.createPropertyAccessExpression(weakSetName, "add"), /*typeArguments*/ undefined, - [receiver] + [receiver], ); } @@ -3310,7 +3684,10 @@ function isReservedPrivateName(node: PrivateIdentifier) { return !isGeneratedPrivateIdentifier(node) && node.escapedText === "#constructor"; } -type PrivateIdentifierInExpression = BinaryExpression & { readonly left: PrivateIdentifier, readonly token: InKeyword }; +type PrivateIdentifierInExpression = BinaryExpression & { + readonly left: PrivateIdentifier; + readonly token: InKeyword; +}; function isPrivateIdentifierInExpression(node: BinaryExpression): node is PrivateIdentifierInExpression { return isPrivateIdentifier(node.left) @@ -3321,6 +3698,8 @@ function isStaticPropertyDeclaration(node: Node): node is PropertyDeclaration { return isPropertyDeclaration(node) && hasStaticModifier(node); } -function isStaticPropertyDeclarationOrClassStaticBlock(node: Node): node is ClassStaticBlockDeclaration | PropertyDeclaration { +function isStaticPropertyDeclarationOrClassStaticBlock( + node: Node, +): node is ClassStaticBlockDeclaration | PropertyDeclaration { return isClassStaticBlockDeclaration(node) || isStaticPropertyDeclaration(node); -} \ No newline at end of file +} diff --git a/src/compiler/transformers/classThis.ts b/src/compiler/transformers/classThis.ts index b03cd68144b09..59a5082795630 100644 --- a/src/compiler/transformers/classThis.ts +++ b/src/compiler/transformers/classThis.ts @@ -20,7 +20,7 @@ import { some, Statement, SyntaxKind, - ThisExpression + ThisExpression, } from "../_namespaces/ts"; /** @@ -31,7 +31,11 @@ import { * 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 { +export function createClassThisAssignmentBlock( + factory: NodeFactory, + classThis: Identifier, + thisExpression = factory.createThis(), +): ClassThisAssignmentBlock { // produces: // // static { _classThis = this; } @@ -52,14 +56,16 @@ export function createClassThisAssignmentBlock(factory: NodeFactory, classThis: /** @internal */ export type ClassThisAssignmentBlock = ClassStaticBlockDeclaration & { readonly body: Block & { - readonly statements: NodeArray & readonly [ - ExpressionStatement & { - readonly expression: AssignmentExpression & { - readonly left: Identifier; - readonly right: ThisExpression; - }; - } - ]; + readonly statements: + & NodeArray + & readonly [ + ExpressionStatement & { + readonly expression: AssignmentExpression & { + readonly left: Identifier; + readonly right: ThisExpression; + }; + }, + ]; }; }; @@ -74,11 +80,11 @@ export function isClassThisAssignmentBlock(node: Node): node is ClassThisAssignm } const statement = node.body.statements[0]; - return isExpressionStatement(statement) && - isAssignmentExpression(statement.expression, /*excludeCompoundAssignment*/ true) && - isIdentifier(statement.expression.left) && - node.emitNode?.classThis === statement.expression.left && - statement.expression.right.kind === SyntaxKind.ThisKeyword; + return isExpressionStatement(statement) + && isAssignmentExpression(statement.expression, /*excludeCompoundAssignment*/ true) + && isIdentifier(statement.expression.left) + && node.emitNode?.classThis === statement.expression.left + && statement.expression.right.kind === SyntaxKind.ThisKeyword; } /** @@ -99,11 +105,18 @@ export function classHasClassThisAssignment(node: ClassLikeDeclaration) { * expression that has already had its `EmitFlags` set or may have been tracked to prevent substitution. * @internal */ -export function injectClassThisAssignmentIfMissing(factory: NodeFactory, node: T, - classThis: Identifier, thisExpression?: ThisExpression): Extract>; -export function injectClassThisAssignmentIfMissing(factory: NodeFactory, node: T, - classThis: Identifier, thisExpression?: ThisExpression) { - +export function injectClassThisAssignmentIfMissing( + factory: NodeFactory, + node: T, + classThis: Identifier, + thisExpression?: ThisExpression, +): Extract>; +export function injectClassThisAssignmentIfMissing( + factory: NodeFactory, + node: T, + classThis: Identifier, + thisExpression?: ThisExpression, +) { // given: // // class C { @@ -127,21 +140,23 @@ export function injectClassThisAssignmentIfMissing 0 ? (parseTreeNode.parent as SignatureDeclaration).parameters[paramIdx - 1] : undefined; + const paramIdx = (parseTreeNode.parent as SignatureDeclaration).parameters.indexOf( + parseTreeNode as ParameterDeclaration, + ); + const previousSibling = paramIdx > 0 ? (parseTreeNode.parent as SignatureDeclaration).parameters[paramIdx - 1] + : undefined; const text = currentSourceFile.text; const commentRanges = previousSibling ? concatenate( // to handle // ... parameters, /** @internal */ // public param: string - getTrailingCommentRanges(text, skipTrivia(text, previousSibling.end + 1, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true)), - getLeadingCommentRanges(text, node.pos) + getTrailingCommentRanges( + text, + skipTrivia(text, previousSibling.end + 1, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true), + ), + getLeadingCommentRanges(text, node.pos), ) - : getTrailingCommentRanges(text, skipTrivia(text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true)); + : getTrailingCommentRanges( + text, + skipTrivia(text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true), + ); return commentRanges && commentRanges.length && hasInternalAnnotation(last(commentRanges), currentSourceFile); } const leadingCommentRanges = parseTreeNode && getLeadingCommentRangesOfNode(parseTreeNode, currentSourceFile); @@ -268,14 +289,13 @@ export function isInternalDeclaration(node: Node, currentSourceFile: SourceFile) }); } -const declarationEmitNodeBuilderFlags = - NodeBuilderFlags.MultilineObjectLiterals | - NodeBuilderFlags.WriteClassExpressionAsTypeLiteral | - NodeBuilderFlags.UseTypeOfFunction | - NodeBuilderFlags.UseStructuralFallback | - NodeBuilderFlags.AllowEmptyTuple | - NodeBuilderFlags.GenerateNamesForShadowedTypeParams | - NodeBuilderFlags.NoTruncation; +const declarationEmitNodeBuilderFlags = NodeBuilderFlags.MultilineObjectLiterals + | NodeBuilderFlags.WriteClassExpressionAsTypeLiteral + | NodeBuilderFlags.UseTypeOfFunction + | NodeBuilderFlags.UseStructuralFallback + | NodeBuilderFlags.AllowEmptyTuple + | NodeBuilderFlags.GenerateNamesForShadowedTypeParams + | NodeBuilderFlags.NoTruncation; /** * Transforms a ts file into a .d.ts file @@ -296,7 +316,10 @@ export function transformDeclarations(context: TransformationContext) { let enclosingDeclaration: Node; let necessaryTypeReferences: Set<[specifier: string, mode: ResolutionMode]> | undefined; let lateMarkedStatements: LateVisibilityPaintedStatement[] | undefined; - let lateStatementReplacementMap: Map>; + let lateStatementReplacementMap: Map< + NodeId, + VisitResult + >; let suppressNewDiagnosticContexts: boolean; let exportedModulesFromDeclarationEmit: Symbol[] | undefined; @@ -329,7 +352,9 @@ export function transformDeclarations(context: TransformationContext) { const { noResolve, stripInternal } = options; return transformRoot; - function recordTypeReferenceDirectivesIfNecessary(typeReferenceDirectives: readonly [specifier: string, mode: ResolutionMode][] | undefined): void { + function recordTypeReferenceDirectivesIfNecessary( + typeReferenceDirectives: readonly [specifier: string, mode: ResolutionMode][] | undefined, + ): void { if (!typeReferenceDirectives) { return; } @@ -371,17 +396,25 @@ export function transformDeclarations(context: TransformationContext) { const errorInfo = getSymbolAccessibilityDiagnostic(symbolAccessibilityResult); if (errorInfo) { if (errorInfo.typeName) { - context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode, - errorInfo.diagnosticMessage, - getTextOfNode(errorInfo.typeName), - symbolAccessibilityResult.errorSymbolName!, - symbolAccessibilityResult.errorModuleName!)); + context.addDiagnostic( + createDiagnosticForNode( + symbolAccessibilityResult.errorNode || errorInfo.errorNode, + errorInfo.diagnosticMessage, + getTextOfNode(errorInfo.typeName), + symbolAccessibilityResult.errorSymbolName!, + symbolAccessibilityResult.errorModuleName!, + ), + ); } else { - context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode, - errorInfo.diagnosticMessage, - symbolAccessibilityResult.errorSymbolName!, - symbolAccessibilityResult.errorModuleName!)); + context.addDiagnostic( + createDiagnosticForNode( + symbolAccessibilityResult.errorNode || errorInfo.errorNode, + errorInfo.diagnosticMessage, + symbolAccessibilityResult.errorSymbolName!, + symbolAccessibilityResult.errorModuleName!, + ), + ); } return true; } @@ -397,7 +430,14 @@ export function transformDeclarations(context: TransformationContext) { function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { if (symbol.flags & SymbolFlags.TypeParameter) return false; - const issuedDiagnostic = handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasToMarkVisible*/ true)); + const issuedDiagnostic = handleSymbolAccessibilityError( + resolver.isSymbolAccessible( + symbol, + enclosingDeclaration, + meaning, + /*shouldComputeAliasToMarkVisible*/ true, + ), + ); recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning)); return issuedDiagnostic; } @@ -405,51 +445,86 @@ export function transformDeclarations(context: TransformationContext) { function reportPrivateInBaseOfClassExpression(propertyName: string) { if (errorNameNode || errorFallbackNode) { context.addDiagnostic( - createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.Property_0_of_exported_class_expression_may_not_be_private_or_protected, propertyName)); + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics.Property_0_of_exported_class_expression_may_not_be_private_or_protected, + propertyName, + ), + ); } } function errorDeclarationNameWithFallback() { - return errorNameNode ? declarationNameToString(errorNameNode) : - errorFallbackNode && getNameOfDeclaration(errorFallbackNode) ? declarationNameToString(getNameOfDeclaration(errorFallbackNode)) : - errorFallbackNode && isExportAssignment(errorFallbackNode) ? errorFallbackNode.isExportEquals ? "export=" : "default" : - "(Missing)"; // same fallback declarationNameToString uses when node is zero-width (ie, nameless) + return errorNameNode ? declarationNameToString(errorNameNode) + : errorFallbackNode && getNameOfDeclaration(errorFallbackNode) + ? declarationNameToString(getNameOfDeclaration(errorFallbackNode)) + : errorFallbackNode && isExportAssignment(errorFallbackNode) + ? errorFallbackNode.isExportEquals ? "export=" : "default" + : "(Missing)"; // same fallback declarationNameToString uses when node is zero-width (ie, nameless) } function reportInaccessibleUniqueSymbolError() { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, - errorDeclarationNameWithFallback(), - "unique symbol")); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, + errorDeclarationNameWithFallback(), + "unique symbol", + ), + ); } } function reportCyclicStructureError() { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_a_type_with_a_cyclic_structure_which_cannot_be_trivially_serialized_A_type_annotation_is_necessary, - errorDeclarationNameWithFallback())); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_inferred_type_of_0_references_a_type_with_a_cyclic_structure_which_cannot_be_trivially_serialized_A_type_annotation_is_necessary, + errorDeclarationNameWithFallback(), + ), + ); } } function reportInaccessibleThisError() { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, - errorDeclarationNameWithFallback(), - "this")); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, + errorDeclarationNameWithFallback(), + "this", + ), + ); } } function reportLikelyUnsafeImportRequiredError(specifier: string) { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_cannot_be_named_without_a_reference_to_1_This_is_likely_not_portable_A_type_annotation_is_necessary, - errorDeclarationNameWithFallback(), - specifier)); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_inferred_type_of_0_cannot_be_named_without_a_reference_to_1_This_is_likely_not_portable_A_type_annotation_is_necessary, + errorDeclarationNameWithFallback(), + specifier, + ), + ); } } function reportTruncationError() { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_this_node_exceeds_the_maximum_length_the_compiler_will_serialize_An_explicit_type_annotation_is_needed)); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_inferred_type_of_this_node_exceeds_the_maximum_length_the_compiler_will_serialize_An_explicit_type_annotation_is_needed, + ), + ); } } @@ -459,8 +534,15 @@ export function transformDeclarations(context: TransformationContext) { if (primaryDeclaration && augmentingDeclarations) { for (const augmentations of augmentingDeclarations) { context.addDiagnostic(addRelatedInfo( - createDiagnosticForNode(augmentations, Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized), - createDiagnosticForNode(primaryDeclaration, Diagnostics.This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file) + createDiagnosticForNode( + augmentations, + Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized, + ), + createDiagnosticForNode( + primaryDeclaration, + Diagnostics + .This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file, + ), )); } } @@ -468,25 +550,45 @@ export function transformDeclarations(context: TransformationContext) { function reportNonSerializableProperty(propertyName: string) { if (errorNameNode || errorFallbackNode) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_type_of_this_node_cannot_be_serialized_because_its_property_0_cannot_be_serialized, propertyName)); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics.The_type_of_this_node_cannot_be_serialized_because_its_property_0_cannot_be_serialized, + propertyName, + ), + ); } } function reportImportTypeNodeResolutionModeOverride() { if (!isNightly() && (errorNameNode || errorFallbackNode)) { - context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_type_of_this_expression_cannot_be_named_without_a_resolution_mode_assertion_which_is_an_unstable_feature_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next)); + context.addDiagnostic( + createDiagnosticForNode( + (errorNameNode || errorFallbackNode)!, + Diagnostics + .The_type_of_this_expression_cannot_be_named_without_a_resolution_mode_assertion_which_is_an_unstable_feature_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next, + ), + ); } } function transformDeclarationsForJS(sourceFile: SourceFile, bundled?: boolean) { const oldDiag = getSymbolAccessibilityDiagnostic; - getSymbolAccessibilityDiagnostic = (s) => (s.errorNode && canProduceDiagnostics(s.errorNode) ? createGetSymbolAccessibilityDiagnosticForNode(s.errorNode)(s) : ({ - diagnosticMessage: s.errorModuleName - ? Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit - : Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit, - errorNode: s.errorNode || sourceFile - })); - const result = resolver.getDeclarationStatementsForSourceFile(sourceFile, declarationEmitNodeBuilderFlags, symbolTracker, bundled); + getSymbolAccessibilityDiagnostic = s => (s.errorNode && canProduceDiagnostics(s.errorNode) + ? createGetSymbolAccessibilityDiagnosticForNode(s.errorNode)(s) : ({ + diagnosticMessage: s.errorModuleName + ? Diagnostics + .Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit + : Diagnostics + .Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit, + errorNode: s.errorNode || sourceFile, + })); + const result = resolver.getDeclarationStatementsForSourceFile( + sourceFile, + declarationEmitNodeBuilderFlags, + symbolTracker, + bundled, + ); getSymbolAccessibilityDiagnostic = oldDiag; return result; } @@ -504,8 +606,8 @@ export function transformDeclarations(context: TransformationContext) { refs = new Map(); libs = new Map(); let hasNoDefaultLib = false; - const bundle = factory.createBundle(map(node.sourceFiles, - sourceFile => { + const bundle = factory.createBundle( + map(node.sourceFiles, sourceFile => { if (sourceFile.isDeclarationFile) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217 hasNoDefaultLib = hasNoDefaultLib || sourceFile.hasNoDefaultLib; currentSourceFile = sourceFile; @@ -521,35 +623,70 @@ export function transformDeclarations(context: TransformationContext) { if (isExternalOrCommonJsModule(sourceFile) || isJsonSourceFile(sourceFile)) { resultHasExternalModuleIndicator = false; // unused in external module bundle emit (all external modules are within module blocks, therefore are known to be modules) needsDeclare = false; - const statements = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) : visitNodes(sourceFile.statements, visitDeclarationStatements, isStatement); - const newFile = factory.updateSourceFile(sourceFile, [factory.createModuleDeclaration( - [factory.createModifier(SyntaxKind.DeclareKeyword)], - factory.createStringLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)), - factory.createModuleBlock(setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), sourceFile.statements)) - )], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []); + const statements = isSourceFileJS(sourceFile) + ? factory.createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) + : visitNodes(sourceFile.statements, visitDeclarationStatements, isStatement); + const newFile = factory.updateSourceFile( + sourceFile, + [factory.createModuleDeclaration( + [factory.createModifier(SyntaxKind.DeclareKeyword)], + factory.createStringLiteral( + getResolvedExternalModuleName(context.getEmitHost(), sourceFile), + ), + factory.createModuleBlock( + setTextRange( + factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), + sourceFile.statements, + ), + ), + )], + /*isDeclarationFile*/ true, + /*referencedFiles*/ [], + /*typeReferences*/ [], + /*hasNoDefaultLib*/ false, + /*libReferences*/ [], + ); return newFile; } needsDeclare = true; - const updated = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) : visitNodes(sourceFile.statements, visitDeclarationStatements, isStatement); - return factory.updateSourceFile(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []); - } - ), mapDefined(node.prepends, prepend => { - if (prepend.kind === SyntaxKind.InputFiles) { - const sourceFile = createUnparsedSourceFile(prepend, "dts", stripInternal); - hasNoDefaultLib = hasNoDefaultLib || !!sourceFile.hasNoDefaultLib; - collectReferences(sourceFile, refs); - recordTypeReferenceDirectivesIfNecessary(map(sourceFile.typeReferenceDirectives, ref => [ref.fileName, ref.resolutionMode])); - collectLibs(sourceFile, libs); - return sourceFile; - } - return prepend; - })); + const updated = isSourceFileJS(sourceFile) + ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) + : visitNodes(sourceFile.statements, visitDeclarationStatements, isStatement); + return factory.updateSourceFile( + sourceFile, + transformAndReplaceLatePaintedStatements(updated), + /*isDeclarationFile*/ true, + /*referencedFiles*/ [], + /*typeReferences*/ [], + /*hasNoDefaultLib*/ false, + /*libReferences*/ [], + ); + }), + mapDefined(node.prepends, prepend => { + if (prepend.kind === SyntaxKind.InputFiles) { + const sourceFile = createUnparsedSourceFile(prepend, "dts", stripInternal); + hasNoDefaultLib = hasNoDefaultLib || !!sourceFile.hasNoDefaultLib; + collectReferences(sourceFile, refs); + recordTypeReferenceDirectivesIfNecessary( + map(sourceFile.typeReferenceDirectives, ref => [ref.fileName, ref.resolutionMode]), + ); + collectLibs(sourceFile, libs); + return sourceFile; + } + return prepend; + }), + ); bundle.syntheticFileReferences = []; bundle.syntheticTypeReferences = getFileReferencesForUsedTypeReferences(); bundle.syntheticLibReferences = getLibReferences(); bundle.hasNoDefaultLib = hasNoDefaultLib; - const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!)); - const referenceVisitor = mapReferencesIntoArray(bundle.syntheticFileReferences as FileReference[], outputFilePath); + const outputFilePath = getDirectoryPath( + normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!), + ); + const referenceVisitor = mapReferencesIntoArray( + bundle.syntheticFileReferences as FileReference[], + outputFilePath, + ); refs.forEach(referenceVisitor); return bundle; } @@ -570,7 +707,9 @@ export function transformDeclarations(context: TransformationContext) { refs = collectReferences(currentSourceFile, new Map()); libs = collectLibs(currentSourceFile, new Map()); const references: FileReference[] = []; - const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!)); + const outputFilePath = getDirectoryPath( + normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!), + ); const referenceVisitor = mapReferencesIntoArray(references, outputFilePath); let combinedStatements: NodeArray; if (isSourceFileJS(currentSourceFile)) { @@ -580,14 +719,31 @@ export function transformDeclarations(context: TransformationContext) { } else { const statements = visitNodes(node.statements, visitDeclarationStatements, isStatement); - combinedStatements = setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), node.statements); + combinedStatements = setTextRange( + factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), + node.statements, + ); refs.forEach(referenceVisitor); emittedImports = filter(combinedStatements, isAnyImportSyntax); - if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) { - combinedStatements = setTextRange(factory.createNodeArray([...combinedStatements, createEmptyExports(factory)]), combinedStatements); + if ( + isExternalModule(node) + && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker)) + ) { + combinedStatements = setTextRange( + factory.createNodeArray([...combinedStatements, createEmptyExports(factory)]), + combinedStatements, + ); } } - const updated = factory.updateSourceFile(node, combinedStatements, /*isDeclarationFile*/ true, references, getFileReferencesForUsedTypeReferences(), node.hasNoDefaultLib, getLibReferences()); + const updated = factory.updateSourceFile( + node, + combinedStatements, + /*isDeclarationFile*/ true, + references, + getFileReferencesForUsedTypeReferences(), + node.hasNoDefaultLib, + getLibReferences(), + ); updated.exportedModulesFromDeclarationEmit = exportedModulesFromDeclarationEmit; return updated; @@ -596,20 +752,29 @@ export function transformDeclarations(context: TransformationContext) { } function getFileReferencesForUsedTypeReferences() { - return necessaryTypeReferences ? mapDefined(arrayFrom(necessaryTypeReferences.keys()), getFileReferenceForSpecifierModeTuple) : []; + return necessaryTypeReferences + ? mapDefined(arrayFrom(necessaryTypeReferences.keys()), getFileReferenceForSpecifierModeTuple) : []; } - function getFileReferenceForSpecifierModeTuple([typeName, mode]: [specifier: string, mode: ResolutionMode]): FileReference | undefined { + function getFileReferenceForSpecifierModeTuple( + [typeName, mode]: [specifier: string, mode: ResolutionMode], + ): FileReference | undefined { // Elide type references for which we have imports if (emittedImports) { for (const importStatement of emittedImports) { - if (isImportEqualsDeclaration(importStatement) && isExternalModuleReference(importStatement.moduleReference)) { + if ( + isImportEqualsDeclaration(importStatement) + && isExternalModuleReference(importStatement.moduleReference) + ) { const expr = importStatement.moduleReference.expression; if (isStringLiteralLike(expr) && expr.text === typeName) { return undefined; } } - else if (isImportDeclaration(importStatement) && isStringLiteral(importStatement.moduleSpecifier) && importStatement.moduleSpecifier.text === typeName) { + else if ( + isImportDeclaration(importStatement) && isStringLiteral(importStatement.moduleSpecifier) + && importStatement.moduleSpecifier.text === typeName + ) { return undefined; } } @@ -617,7 +782,10 @@ export function transformDeclarations(context: TransformationContext) { return { fileName: typeName, pos: -1, end: -1, ...(mode ? { resolutionMode: mode } : undefined) }; } - function mapReferencesIntoArray(references: FileReference[], outputFilePath: string): (file: SourceFile) => void { + function mapReferencesIntoArray( + references: FileReference[], + outputFilePath: string, + ): (file: SourceFile) => void { return file => { let declFileName: string; if (file.isDeclarationFile) { // Neither decl files or js should have their refs changed @@ -650,7 +818,7 @@ export function transformDeclarations(context: TransformationContext) { declFileName, host.getCurrentDirectory(), host.getCanonicalFileName, - /*isAbsolutePathAnUrl*/ false + /*isAbsolutePathAnUrl*/ false, ); if (startsWith(fileName, "./") && hasExtension(fileName)) { fileName = fileName.substring(2); @@ -695,10 +863,16 @@ export function transformDeclarations(context: TransformationContext) { } else { if (name.kind === SyntaxKind.ArrayBindingPattern) { - return factory.updateArrayBindingPattern(name, visitNodes(name.elements, visitBindingElement, isArrayBindingElement)); + return factory.updateArrayBindingPattern( + name, + visitNodes(name.elements, visitBindingElement, isArrayBindingElement), + ); } else { - return factory.updateObjectBindingPattern(name, visitNodes(name.elements, visitBindingElement, isBindingElement)); + return factory.updateObjectBindingPattern( + name, + visitNodes(name.elements, visitBindingElement, isBindingElement), + ); } } @@ -707,14 +881,17 @@ export function transformDeclarations(context: TransformationContext) { if (elem.kind === SyntaxKind.OmittedExpression) { return elem; } - if (elem.propertyName && isIdentifier(elem.propertyName) && isIdentifier(elem.name) && !elem.symbol.isReferenced && !isIdentifierANonContextualKeyword(elem.propertyName)) { - // Unnecessary property renaming is forbidden in types, so remove renaming + if ( + elem.propertyName && isIdentifier(elem.propertyName) && isIdentifier(elem.name) + && !elem.symbol.isReferenced && !isIdentifierANonContextualKeyword(elem.propertyName) + ) { + // Unnecessary property renaming is forbidden in types, so remove renaming return factory.updateBindingElement( elem, elem.dotDotDotToken, /*propertyName*/ undefined, elem.propertyName, - shouldPrintWithInitializer(elem) ? elem.initializer : undefined + shouldPrintWithInitializer(elem) ? elem.initializer : undefined, ); } return factory.updateBindingElement( @@ -722,12 +899,16 @@ export function transformDeclarations(context: TransformationContext) { elem.dotDotDotToken, elem.propertyName, filterBindingPatternInitializersAndRenamings(elem.name), - shouldPrintWithInitializer(elem) ? elem.initializer : undefined + shouldPrintWithInitializer(elem) ? elem.initializer : undefined, ); } } - function ensureParameter(p: ParameterDeclaration, modifierMask?: ModifierFlags, type?: TypeNode): ParameterDeclaration { + function ensureParameter( + p: ParameterDeclaration, + modifierMask?: ModifierFlags, + type?: TypeNode, + ): ParameterDeclaration { let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined; if (!suppressNewDiagnosticContexts) { oldDiag = getSymbolAccessibilityDiagnostic; @@ -738,9 +919,10 @@ export function transformDeclarations(context: TransformationContext) { maskModifiers(factory, p, modifierMask), p.dotDotDotToken, filterBindingPatternInitializersAndRenamings(p.name), - resolver.isOptionalParameter(p) ? (p.questionToken || factory.createToken(SyntaxKind.QuestionToken)) : undefined, + resolver.isOptionalParameter(p) ? (p.questionToken || factory.createToken(SyntaxKind.QuestionToken)) + : undefined, ensureType(p, type || p.type, /*ignorePrivate*/ true), // Ignore private param props, since this type is going straight back into a param - ensureNoInitializer(p) + ensureNoInitializer(p), ); if (!suppressNewDiagnosticContexts) { getSymbolAccessibilityDiagnostic = oldDiag!; @@ -749,7 +931,8 @@ export function transformDeclarations(context: TransformationContext) { } function shouldPrintWithInitializer(node: Node) { - return canHaveLiteralInitializer(node) && resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safe + return canHaveLiteralInitializer(node) + && resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safe } function ensureNoInitializer(node: CanHaveLiteralInitializer) { @@ -773,7 +956,11 @@ export function transformDeclarations(context: TransformationContext) { | PropertyDeclaration | PropertySignature; - function ensureType(node: HasInferredType, type: TypeNode | undefined, ignorePrivate?: boolean): TypeNode | undefined { + function ensureType( + node: HasInferredType, + type: TypeNode | undefined, + ignorePrivate?: boolean, + ): TypeNode | undefined { if (!ignorePrivate && hasEffectiveModifier(node, ModifierFlags.Private)) { // Private nodes emit no types (except private parameter properties, whose parameter types are actually visible) return; @@ -782,14 +969,15 @@ export function transformDeclarations(context: TransformationContext) { // Literal const declarations will have an initializer ensured rather than a type return; } - const shouldUseResolverType = node.kind === SyntaxKind.Parameter && - (resolver.isRequiredInitializedParameter(node) || - resolver.isOptionalUninitializedParameterProperty(node)); + const shouldUseResolverType = node.kind === SyntaxKind.Parameter + && (resolver.isRequiredInitializedParameter(node) + || resolver.isOptionalUninitializedParameterProperty(node)); if (type && !shouldUseResolverType) { return visitNode(type, visitDeclarationSubtree, isTypeNode); } if (!getParseTreeNode(node)) { - return type ? visitNode(type, visitDeclarationSubtree, isTypeNode) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + return type ? visitNode(type, visitDeclarationSubtree, isTypeNode) + : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); } if (node.kind === SyntaxKind.SetAccessor) { // Set accessors with no associated type node (from it's param or get accessor return) are `any` since they are never contextually typed right now @@ -803,15 +991,55 @@ export function transformDeclarations(context: TransformationContext) { getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node); } if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { - return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); + return cleanup( + resolver.createTypeOfDeclaration( + node, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + ); } - if (node.kind === SyntaxKind.Parameter + if ( + node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.PropertyDeclaration - || node.kind === SyntaxKind.PropertySignature) { - if (isPropertySignature(node) || !node.initializer) return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType)); - return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType) || resolver.createTypeOfExpression(node.initializer, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); + || node.kind === SyntaxKind.PropertySignature + ) { + if (isPropertySignature(node) || !node.initializer) { + return cleanup( + resolver.createTypeOfDeclaration( + node, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + shouldUseResolverType, + ), + ); + } + return cleanup( + resolver.createTypeOfDeclaration( + node, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + shouldUseResolverType, + ) + || resolver.createTypeOfExpression( + node.initializer, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + ); } - return cleanup(resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); + return cleanup( + resolver.createReturnTypeOfSignatureDeclaration( + node, + enclosingDeclaration, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + ); function cleanup(returnValue: TypeNode | undefined) { errorNameNode = undefined; @@ -869,7 +1097,11 @@ export function transformDeclarations(context: TransformationContext) { } } - function updateParamsList(node: Node, params: NodeArray, modifierMask?: ModifierFlags): NodeArray { + function updateParamsList( + node: Node, + params: NodeArray, + modifierMask?: ModifierFlags, + ): NodeArray { if (hasEffectiveModifier(node, ModifierFlags.Private)) { return factory.createNodeArray(); } @@ -893,7 +1125,10 @@ export function transformDeclarations(context: TransformationContext) { if (!isPrivate) { const valueParameter = getSetAccessorValueParameter(input); if (valueParameter) { - const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input)); + const accessorType = getTypeAnnotationFromAllAccessorDeclarations( + input, + resolver.getAllAccessorDeclarations(input), + ); newValueParameter = ensureParameter(valueParameter, /*modifierMask*/ undefined, accessorType); } } @@ -901,7 +1136,7 @@ export function transformDeclarations(context: TransformationContext) { newValueParameter = factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, - "value" + "value", ); } newParams = append(newParams, newValueParameter); @@ -910,7 +1145,8 @@ export function transformDeclarations(context: TransformationContext) { } function ensureTypeParams(node: Node, params: NodeArray | undefined) { - return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined : visitNodes(params, visitDeclarationSubtree, isTypeParameterDeclaration); + return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined + : visitNodes(params, visitDeclarationSubtree, isTypeParameterDeclaration); } function isEnclosingDeclaration(node: Node) { @@ -937,9 +1173,13 @@ export function transformDeclarations(context: TransformationContext) { return setCommentRange(updated, getCommentRange(original)); } - function rewriteModuleSpecifier(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode, input: T | undefined): T | StringLiteral { + function rewriteModuleSpecifier( + parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode, + input: T | undefined, + ): T | StringLiteral { if (!input) return undefined!; // TODO: GH#18217 - resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || (parent.kind !== SyntaxKind.ModuleDeclaration && parent.kind !== SyntaxKind.ImportType); + resultHasExternalModuleIndicator = resultHasExternalModuleIndicator + || (parent.kind !== SyntaxKind.ModuleDeclaration && parent.kind !== SyntaxKind.ImportType); if (isStringLiteralLike(input)) { if (isBundledEmit) { const newName = getExternalModuleNameFromDeclaration(context.getEmitHost(), resolver, parent); @@ -967,7 +1207,7 @@ export function transformDeclarations(context: TransformationContext) { decl.modifiers, decl.isTypeOnly, decl.name, - factory.updateExternalModuleReference(decl.moduleReference, rewriteModuleSpecifier(decl, specifier)) + factory.updateExternalModuleReference(decl.moduleReference, rewriteModuleSpecifier(decl, specifier)), ); } else { @@ -987,32 +1227,50 @@ export function transformDeclarations(context: TransformationContext) { decl.modifiers, decl.importClause, rewriteModuleSpecifier(decl, decl.moduleSpecifier), - getResolutionModeOverrideForClauseInNightly(decl.assertClause) + getResolutionModeOverrideForClauseInNightly(decl.assertClause), ); } // The `importClause` visibility corresponds to the default's visibility. - const visibleDefaultBinding = decl.importClause && decl.importClause.name && resolver.isDeclarationVisible(decl.importClause) ? decl.importClause.name : undefined; + const visibleDefaultBinding = + decl.importClause && decl.importClause.name && resolver.isDeclarationVisible(decl.importClause) + ? decl.importClause.name : undefined; if (!decl.importClause.namedBindings) { // No named bindings (either namespace or list), meaning the import is just default or should be elided - return visibleDefaultBinding && factory.updateImportDeclaration(decl, decl.modifiers, factory.updateImportClause( - decl.importClause, - decl.importClause.isTypeOnly, - visibleDefaultBinding, - /*namedBindings*/ undefined, - ), rewriteModuleSpecifier(decl, decl.moduleSpecifier), getResolutionModeOverrideForClauseInNightly(decl.assertClause)); + return visibleDefaultBinding && factory.updateImportDeclaration( + decl, + decl.modifiers, + factory.updateImportClause( + decl.importClause, + decl.importClause.isTypeOnly, + visibleDefaultBinding, + /*namedBindings*/ undefined, + ), + rewriteModuleSpecifier(decl, decl.moduleSpecifier), + getResolutionModeOverrideForClauseInNightly(decl.assertClause), + ); } if (decl.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { // Namespace import (optionally with visible default) - const namedBindings = resolver.isDeclarationVisible(decl.importClause.namedBindings) ? decl.importClause.namedBindings : /*namedBindings*/ undefined; - return visibleDefaultBinding || namedBindings ? factory.updateImportDeclaration(decl, decl.modifiers, factory.updateImportClause( - decl.importClause, - decl.importClause.isTypeOnly, - visibleDefaultBinding, - namedBindings, - ), rewriteModuleSpecifier(decl, decl.moduleSpecifier), getResolutionModeOverrideForClauseInNightly(decl.assertClause)) : undefined; + const namedBindings = resolver.isDeclarationVisible(decl.importClause.namedBindings) + ? decl.importClause.namedBindings : /*namedBindings*/ undefined; + return visibleDefaultBinding || namedBindings ? factory.updateImportDeclaration( + decl, + decl.modifiers, + factory.updateImportClause( + decl.importClause, + decl.importClause.isTypeOnly, + visibleDefaultBinding, + namedBindings, + ), + rewriteModuleSpecifier(decl, decl.moduleSpecifier), + getResolutionModeOverrideForClauseInNightly(decl.assertClause), + ) : undefined; } // Named imports (optionally with visible default) - const bindingList = mapDefined(decl.importClause.namedBindings.elements, b => resolver.isDeclarationVisible(b) ? b : undefined); + const bindingList = mapDefined( + decl.importClause.namedBindings.elements, + b => resolver.isDeclarationVisible(b) ? b : undefined, + ); if ((bindingList && bindingList.length) || visibleDefaultBinding) { return factory.updateImportDeclaration( decl, @@ -1021,10 +1279,11 @@ export function transformDeclarations(context: TransformationContext) { decl.importClause, decl.importClause.isTypeOnly, visibleDefaultBinding, - bindingList && bindingList.length ? factory.updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined, + bindingList && bindingList.length + ? factory.updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined, ), rewriteModuleSpecifier(decl, decl.moduleSpecifier), - getResolutionModeOverrideForClauseInNightly(decl.assertClause) + getResolutionModeOverrideForClauseInNightly(decl.assertClause), ); } // Augmentation of export depends on import @@ -1034,7 +1293,7 @@ export function transformDeclarations(context: TransformationContext) { decl.modifiers, /*importClause*/ undefined, rewriteModuleSpecifier(decl, decl.moduleSpecifier), - getResolutionModeOverrideForClauseInNightly(decl.assertClause) + getResolutionModeOverrideForClauseInNightly(decl.assertClause), ); } // Nothing visible @@ -1044,7 +1303,13 @@ export function transformDeclarations(context: TransformationContext) { const mode = getResolutionModeOverrideForClause(assertClause); if (mode !== undefined) { if (!isNightly()) { - context.addDiagnostic(createDiagnosticForNode(assertClause!, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next)); + context.addDiagnostic( + createDiagnosticForNode( + assertClause!, + Diagnostics + .resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next, + ), + ); } return assertClause; } @@ -1069,7 +1334,11 @@ export function transformDeclarations(context: TransformationContext) { while (length(lateMarkedStatements)) { const i = lateMarkedStatements!.shift()!; if (!isLateVisibilityPaintedStatement(i)) { - return Debug.fail(`Late replaced statement was found which is not handled by the declaration transformer!: ${Debug.formatSyntaxKind((i as Node).kind)}`); + return Debug.fail( + `Late replaced statement was found which is not handled by the declaration transformer!: ${ + Debug.formatSyntaxKind((i as Node).kind) + }`, + ); } const priorNeedsDeclare = needsDeclare; needsDeclare = i.parent && isSourceFile(i.parent) && !(isExternalModule(i.parent) && isBundledEmit); @@ -1093,7 +1362,11 @@ export function transformDeclarations(context: TransformationContext) { // Top-level declarations in .d.ts files are always considered exported even without a modifier unless there's an export assignment or specifier needsScopeFixMarker = true; } - if (isSourceFile(statement.parent) && (isArray(result) ? some(result, isExternalModuleIndicator) : isExternalModuleIndicator(result))) { + if ( + isSourceFile(statement.parent) + && (isArray(result) ? some(result, isExternalModuleIndicator) + : isExternalModuleIndicator(result)) + ) { resultHasExternalModuleIndicator = true; } } @@ -1130,13 +1403,23 @@ export function transformDeclarations(context: TransformationContext) { // We'd see a TDZ violation at runtime const canProduceDiagnostic = canProduceDiagnostics(input); const oldWithinObjectLiteralType = suppressNewDiagnosticContexts; - let shouldEnterSuppressNewDiagnosticsContextContext = ((input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) && input.parent.kind !== SyntaxKind.TypeAliasDeclaration); + let shouldEnterSuppressNewDiagnosticsContextContext = + (input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) + && input.parent.kind !== SyntaxKind.TypeAliasDeclaration; // Emit methods which are private as properties with no type information if (isMethodDeclaration(input) || isMethodSignature(input)) { if (hasEffectiveModifier(input, ModifierFlags.Private)) { if (input.symbol && input.symbol.declarations && input.symbol.declarations[0] !== input) return; // Elide all but the first overload - return cleanup(factory.createPropertyDeclaration(ensureModifiers(input), input.name, /*questionOrExclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)); + return cleanup( + factory.createPropertyDeclaration( + ensureModifiers(input), + input.name, + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined, + ), + ); } } @@ -1160,7 +1443,9 @@ export function transformDeclarations(context: TransformationContext) { checkEntityNameVisibility(input.expression, enclosingDeclaration); } const node = visitEachChild(input, visitDeclarationSubtree, context); - return cleanup(factory.updateExpressionWithTypeArguments(node, node.expression, node.typeArguments)); + return cleanup( + factory.updateExpressionWithTypeArguments(node, node.expression, node.typeArguments), + ); } case SyntaxKind.TypeReference: { checkEntityNameVisibility(input.typeName, enclosingDeclaration); @@ -1172,14 +1457,14 @@ export function transformDeclarations(context: TransformationContext) { input, ensureTypeParams(input, input.typeParameters), updateParamsList(input, input.parameters), - ensureType(input, input.type) + ensureType(input, input.type), )); case SyntaxKind.Constructor: { // A constructor declaration may not have a type annotation const ctor = factory.createConstructorDeclaration( /*modifiers*/ ensureModifiers(input), updateParamsList(input, input.parameters, ModifierFlags.None), - /*body*/ undefined + /*body*/ undefined, ); return cleanup(ctor); } @@ -1195,7 +1480,7 @@ export function transformDeclarations(context: TransformationContext) { ensureTypeParams(input, input.typeParameters), updateParamsList(input, input.parameters), ensureType(input, input.type), - /*body*/ undefined + /*body*/ undefined, ); return cleanup(sig); } @@ -1203,14 +1488,18 @@ export function transformDeclarations(context: TransformationContext) { if (isPrivateIdentifier(input.name)) { return cleanup(/*returnValue*/ undefined); } - const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input)); + const accessorType = getTypeAnnotationFromAllAccessorDeclarations( + input, + resolver.getAllAccessorDeclarations(input), + ); return cleanup(factory.updateGetAccessorDeclaration( input, ensureModifiers(input), input.name, updateAccessorParamsList(input, hasEffectiveModifier(input, ModifierFlags.Private)), ensureType(input, accessorType), - /*body*/ undefined)); + /*body*/ undefined, + )); } case SyntaxKind.SetAccessor: { if (isPrivateIdentifier(input.name)) { @@ -1221,7 +1510,8 @@ export function transformDeclarations(context: TransformationContext) { ensureModifiers(input), input.name, updateAccessorParamsList(input, hasEffectiveModifier(input, ModifierFlags.Private)), - /*body*/ undefined)); + /*body*/ undefined, + )); } case SyntaxKind.PropertyDeclaration: if (isPrivateIdentifier(input.name)) { @@ -1233,7 +1523,7 @@ export function transformDeclarations(context: TransformationContext) { input.name, input.questionToken, ensureType(input, input.type), - ensureNoInitializer(input) + ensureNoInitializer(input), )); case SyntaxKind.PropertySignature: if (isPrivateIdentifier(input.name)) { @@ -1244,7 +1534,7 @@ export function transformDeclarations(context: TransformationContext) { ensureModifiers(input), input.name, input.questionToken, - ensureType(input, input.type) + ensureType(input, input.type), )); case SyntaxKind.MethodSignature: { if (isPrivateIdentifier(input.name)) { @@ -1257,7 +1547,7 @@ export function transformDeclarations(context: TransformationContext) { input.questionToken, ensureTypeParams(input, input.typeParameters), updateParamsList(input, input.parameters), - ensureType(input, input.type) + ensureType(input, input.type), )); } case SyntaxKind.CallSignature: { @@ -1265,7 +1555,7 @@ export function transformDeclarations(context: TransformationContext) { input, ensureTypeParams(input, input.typeParameters), updateParamsList(input, input.parameters), - ensureType(input, input.type) + ensureType(input, input.type), )); } case SyntaxKind.IndexSignature: { @@ -1273,7 +1563,8 @@ export function transformDeclarations(context: TransformationContext) { input, ensureModifiers(input), updateParamsList(input, input.parameters), - visitNode(input.type, visitDeclarationSubtree, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + visitNode(input.type, visitDeclarationSubtree, isTypeNode) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), )); } case SyntaxKind.VariableDeclaration: { @@ -1282,11 +1573,27 @@ export function transformDeclarations(context: TransformationContext) { } shouldEnterSuppressNewDiagnosticsContextContext = true; suppressNewDiagnosticContexts = true; // Variable declaration types also suppress new diagnostic contexts, provided the contexts wouldn't be made for binding pattern types - return cleanup(factory.updateVariableDeclaration(input, input.name, /*exclamationToken*/ undefined, ensureType(input, input.type), ensureNoInitializer(input))); + return cleanup( + factory.updateVariableDeclaration( + input, + input.name, + /*exclamationToken*/ undefined, + ensureType(input, input.type), + ensureNoInitializer(input), + ), + ); } case SyntaxKind.TypeParameter: { if (isPrivateMethodTypeParameter(input) && (input.default || input.constraint)) { - return cleanup(factory.updateTypeParameterDeclaration(input, input.modifiers, input.name, /*constraint*/ undefined, /*defaultType*/ undefined)); + return cleanup( + factory.updateTypeParameterDeclaration( + input, + input.modifiers, + input.name, + /*constraint*/ undefined, + /*defaultType*/ undefined, + ), + ); } return cleanup(visitEachChild(input, visitDeclarationSubtree, context)); } @@ -1304,30 +1611,58 @@ export function transformDeclarations(context: TransformationContext) { Debug.assert(extendsType); Debug.assert(trueType); Debug.assert(falseType); - return cleanup(factory.updateConditionalTypeNode(input, checkType, extendsType, trueType, falseType)); + return cleanup( + factory.updateConditionalTypeNode(input, checkType, extendsType, trueType, falseType), + ); } case SyntaxKind.FunctionType: { - return cleanup(factory.updateFunctionTypeNode(input, visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), updateParamsList(input, input.parameters), Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)))); + return cleanup( + factory.updateFunctionTypeNode( + input, + visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), + updateParamsList(input, input.parameters), + Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)), + ), + ); } case SyntaxKind.ConstructorType: { - return cleanup(factory.updateConstructorTypeNode(input, ensureModifiers(input), visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), updateParamsList(input, input.parameters), Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)))); + return cleanup( + factory.updateConstructorTypeNode( + input, + ensureModifiers(input), + visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), + updateParamsList(input, input.parameters), + Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)), + ), + ); } case SyntaxKind.ImportType: { if (!isLiteralImportTypeNode(input)) return cleanup(input); return cleanup(factory.updateImportTypeNode( input, - factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)), + factory.updateLiteralTypeNode( + input.argument, + rewriteModuleSpecifier(input, input.argument.literal), + ), input.assertions, input.qualifier, visitNodes(input.typeArguments, visitDeclarationSubtree, isTypeNode), - input.isTypeOf + input.isTypeOf, )); } - default: Debug.assertNever(input, `Attempted to process unhandled node kind: ${Debug.formatSyntaxKind((input as Node).kind)}`); + default: + Debug.assertNever( + input, + `Attempted to process unhandled node kind: ${Debug.formatSyntaxKind((input as Node).kind)}`, + ); } } - if (isTupleTypeNode(input) && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line === getLineAndCharacterOfPosition(currentSourceFile, input.end).line)) { + if ( + isTupleTypeNode(input) + && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line + === getLineAndCharacterOfPosition(currentSourceFile, input.end).line) + ) { setEmitFlags(input, EmitFlags.SingleLine); } @@ -1354,7 +1689,8 @@ export function transformDeclarations(context: TransformationContext) { } function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) { - return node.parent.kind === SyntaxKind.MethodDeclaration && hasEffectiveModifier(node.parent, ModifierFlags.Private); + return node.parent.kind === SyntaxKind.MethodDeclaration + && hasEffectiveModifier(node.parent, ModifierFlags.Private); } function visitDeclarationStatements(input: Node): VisitResult { @@ -1378,7 +1714,7 @@ export function transformDeclarations(context: TransformationContext) { input.isTypeOnly, input.exportClause, rewriteModuleSpecifier(input, input.moduleSpecifier), - getResolutionModeOverrideForClause(input.assertClause) ? input.assertClause : undefined + getResolutionModeOverrideForClause(input.assertClause) ? input.assertClause : undefined, ); } case SyntaxKind.ExportAssignment: { @@ -1394,12 +1730,25 @@ export function transformDeclarations(context: TransformationContext) { const newId = factory.createUniqueName("_default", GeneratedIdentifierFlags.Optimistic); getSymbolAccessibilityDiagnostic = () => ({ diagnosticMessage: Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0, - errorNode: input + errorNode: input, }); errorFallbackNode = input; - const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(input.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined); + const varDecl = factory.createVariableDeclaration( + newId, + /*exclamationToken*/ undefined, + resolver.createTypeOfExpression( + input.expression, + input, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + /*initializer*/ undefined, + ); errorFallbackNode = undefined; - const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const)); + const statement = factory.createVariableStatement( + needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], + factory.createVariableDeclarationList([varDecl], NodeFlags.Const), + ); preserveJsDoc(statement, input); removeAllComments(input); @@ -1415,13 +1764,18 @@ export function transformDeclarations(context: TransformationContext) { } function stripExportModifiers(statement: Statement): Statement { - if (isImportEqualsDeclaration(statement) || hasEffectiveModifier(statement, ModifierFlags.Default) || !canHaveModifiers(statement)) { + if ( + isImportEqualsDeclaration(statement) || hasEffectiveModifier(statement, ModifierFlags.Default) + || !canHaveModifiers(statement) + ) { // `export import` statements should remain as-is, as imports are _not_ implicitly exported in an ambient namespace // Likewise, `export default` classes and the like and just be `default`, so we preserve their `export` modifiers, too return statement; } - const modifiers = factory.createModifiersFromModifierFlags(getEffectiveModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export)); + const modifiers = factory.createModifiersFromModifierFlags( + getEffectiveModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export), + ); return factory.updateModifiers(statement, modifiers); } @@ -1429,7 +1783,7 @@ export function transformDeclarations(context: TransformationContext) { node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, - body: ModuleBody | undefined + body: ModuleBody | undefined, ) { const updated = factory.updateModuleDeclaration(node, modifiers, name, body); @@ -1441,7 +1795,7 @@ export function transformDeclarations(context: TransformationContext) { updated.modifiers, updated.name, updated.body, - updated.flags | NodeFlags.Namespace + updated.flags | NodeFlags.Namespace, ); setOriginalNode(fixed, updated); @@ -1477,7 +1831,9 @@ export function transformDeclarations(context: TransformationContext) { const canProdiceDiagnostic = canProduceDiagnostics(input); const oldDiag = getSymbolAccessibilityDiagnostic; if (canProdiceDiagnostic) { - getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input as DeclarationDiagnosticProducing); + getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode( + input as DeclarationDiagnosticProducing, + ); } const previousNeedsDeclare = needsDeclare; @@ -1489,7 +1845,7 @@ export function transformDeclarations(context: TransformationContext) { ensureModifiers(input), input.name, visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), - Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)) + Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)), )); needsDeclare = previousNeedsDeclare; return clean; @@ -1501,7 +1857,7 @@ export function transformDeclarations(context: TransformationContext) { input.name, ensureTypeParams(input, input.typeParameters), transformHeritageClauses(input.heritageClauses), - visitNodes(input.members, visitDeclarationSubtree, isTypeElement) + visitNodes(input.members, visitDeclarationSubtree, isTypeElement), )); } case SyntaxKind.FunctionDeclaration: { @@ -1514,37 +1870,66 @@ export function transformDeclarations(context: TransformationContext) { ensureTypeParams(input, input.typeParameters), updateParamsList(input, input.parameters), ensureType(input, input.type), - /*body*/ undefined + /*body*/ undefined, )); if (clean && resolver.isExpandoFunctionDeclaration(input) && shouldEmitFunctionProperties(input)) { const props = resolver.getPropertiesOfContainerFunction(input); // Use parseNodeFactory so it is usable as an enclosing declaration - const fakespace = parseNodeFactory.createModuleDeclaration(/*modifiers*/ undefined, clean.name || factory.createIdentifier("_default"), factory.createModuleBlock([]), NodeFlags.Namespace); + const fakespace = parseNodeFactory.createModuleDeclaration( + /*modifiers*/ undefined, + clean.name || factory.createIdentifier("_default"), + factory.createModuleBlock([]), + NodeFlags.Namespace, + ); setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration); fakespace.locals = createSymbolTable(props); fakespace.symbol = props[0].parent!; const exportMappings: [Identifier, string][] = []; let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => { - if (!p.valueDeclaration || !(isPropertyAccessExpression(p.valueDeclaration) || isElementAccessExpression(p.valueDeclaration) || isBinaryExpression(p.valueDeclaration))) { + if ( + !p.valueDeclaration + || !(isPropertyAccessExpression(p.valueDeclaration) + || isElementAccessExpression(p.valueDeclaration) + || isBinaryExpression(p.valueDeclaration)) + ) { return undefined; } const nameStr = unescapeLeadingUnderscores(p.escapedName); if (!isIdentifierText(nameStr, ScriptTarget.ESNext)) { return undefined; // unique symbol or non-identifier name - omit, since there's no syntax that can preserve it } - getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration); - const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker); + getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode( + p.valueDeclaration, + ); + const type = resolver.createTypeOfDeclaration( + p.valueDeclaration, + fakespace, + declarationEmitNodeBuilderFlags, + symbolTracker, + ); getSymbolAccessibilityDiagnostic = oldDiag; const isNonContextualKeywordName = isStringANonContextualKeyword(nameStr); - const name = isNonContextualKeywordName ? factory.getGeneratedNameForNode(p.valueDeclaration) : factory.createIdentifier(nameStr); + const name = isNonContextualKeywordName ? factory.getGeneratedNameForNode(p.valueDeclaration) + : factory.createIdentifier(nameStr); if (isNonContextualKeywordName) { exportMappings.push([name, nameStr]); } - const varDecl = factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, /*initializer*/ undefined); - return factory.createVariableStatement(isNonContextualKeywordName ? undefined : [factory.createToken(SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([varDecl])); + const varDecl = factory.createVariableDeclaration( + name, + /*exclamationToken*/ undefined, + type, + /*initializer*/ undefined, + ); + return factory.createVariableStatement( + isNonContextualKeywordName ? undefined : [factory.createToken(SyntaxKind.ExportKeyword)], + factory.createVariableDeclarationList([varDecl]), + ); }); if (!exportMappings.length) { - declarations = mapDefined(declarations, declaration => factory.updateModifiers(declaration, ModifierFlags.None)); + declarations = mapDefined( + declarations, + declaration => factory.updateModifiers(declaration, ModifierFlags.None), + ); } else { declarations.push(factory.createExportDeclaration( @@ -1552,15 +1937,22 @@ export function transformDeclarations(context: TransformationContext) { /*isTypeOnly*/ false, factory.createNamedExports(map(exportMappings, ([gen, exp]) => { return factory.createExportSpecifier(/*isTypeOnly*/ false, gen, exp); - })) + })), )); } - const namespaceDecl = factory.createModuleDeclaration(ensureModifiers(input), input.name!, factory.createModuleBlock(declarations), NodeFlags.Namespace); + const namespaceDecl = factory.createModuleDeclaration( + ensureModifiers(input), + input.name!, + factory.createModuleBlock(declarations), + NodeFlags.Namespace, + ); if (!hasEffectiveModifier(clean, ModifierFlags.Default)) { return [clean, namespaceDecl]; } - const modifiers = factory.createModifiersFromModifierFlags((getEffectiveModifierFlags(clean) & ~ModifierFlags.ExportDefault) | ModifierFlags.Ambient); + const modifiers = factory.createModifiersFromModifierFlags( + (getEffectiveModifierFlags(clean) & ~ModifierFlags.ExportDefault) | ModifierFlags.Ambient, + ); const cleanDeclaration = factory.updateFunctionDeclaration( clean, modifiers, @@ -1569,20 +1961,20 @@ export function transformDeclarations(context: TransformationContext) { clean.typeParameters, clean.parameters, clean.type, - /*body*/ undefined + /*body*/ undefined, ); const namespaceDeclaration = factory.updateModuleDeclaration( namespaceDecl, modifiers, namespaceDecl.name, - namespaceDecl.body + namespaceDecl.body, ); const exportDefaultDeclaration = factory.createExportAssignment( /*modifiers*/ undefined, /*isExportEquals*/ false, - namespaceDecl.name + namespaceDecl.name, ); if (isSourceFile(input.parent)) { @@ -1631,7 +2023,7 @@ export function transformDeclarations(context: TransformationContext) { input, mods, isExternalModuleAugmentation(input) ? rewriteModuleSpecifier(input, input.name) : input.name, - body + body, )); } else { @@ -1647,7 +2039,7 @@ export function transformDeclarations(context: TransformationContext) { input, mods, input.name, - body as ModuleBody + body as ModuleBody, )); } } @@ -1660,16 +2052,23 @@ export function transformDeclarations(context: TransformationContext) { let parameterProperties: readonly PropertyDeclaration[] | undefined; if (ctor) { const oldDiag = getSymbolAccessibilityDiagnostic; - parameterProperties = compact(flatMap(ctor.parameters, (param) => { - if (!hasSyntacticModifier(param, ModifierFlags.ParameterPropertyModifier) || shouldStripInternal(param)) return; + parameterProperties = compact(flatMap(ctor.parameters, param => { + if ( + !hasSyntacticModifier(param, ModifierFlags.ParameterPropertyModifier) + || shouldStripInternal(param) + ) return; getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(param); if (param.name.kind === SyntaxKind.Identifier) { - return preserveJsDoc(factory.createPropertyDeclaration( - ensureModifiers(param), - param.name, - param.questionToken, - ensureType(param, param.type), - ensureNoInitializer(param)), param); + return preserveJsDoc( + factory.createPropertyDeclaration( + ensureModifiers(param), + param.name, + param.questionToken, + ensureType(param, param.type), + ensureNoInitializer(param), + ), + param, + ); } else { // Pattern - this is currently an error, but we emit declarations for it somewhat correctly @@ -1689,7 +2088,7 @@ export function transformDeclarations(context: TransformationContext) { elem.name as Identifier, /*questionOrExclamationToken*/ undefined, ensureType(elem, /*type*/ undefined), - /*initializer*/ undefined + /*initializer*/ undefined, )); } return elems; @@ -1698,7 +2097,10 @@ export function transformDeclarations(context: TransformationContext) { getSymbolAccessibilityDiagnostic = oldDiag; } - const hasPrivateIdentifier = some(input.members, member => !!member.name && isPrivateIdentifier(member.name)); + const hasPrivateIdentifier = some( + input.members, + member => !!member.name && isPrivateIdentifier(member.name), + ); // When the class has at least one private identifier, create a unique constant identifier to retain the nominal typing behavior // Prevents other classes with the same public members from being used in place of the current class const privateIdentifier = hasPrivateIdentifier ? [ @@ -1707,43 +2109,87 @@ export function transformDeclarations(context: TransformationContext) { factory.createPrivateIdentifier("#private"), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined - ) + /*initializer*/ undefined, + ), ] : undefined; - const memberNodes = concatenate(concatenate(privateIdentifier, parameterProperties), visitNodes(input.members, visitDeclarationSubtree, isClassElement)); + const memberNodes = concatenate( + concatenate(privateIdentifier, parameterProperties), + visitNodes(input.members, visitDeclarationSubtree, isClassElement), + ); const members = factory.createNodeArray(memberNodes); const extendsClause = getEffectiveBaseTypeNode(input); - if (extendsClause && !isEntityNameExpression(extendsClause.expression) && extendsClause.expression.kind !== SyntaxKind.NullKeyword) { + if ( + extendsClause && !isEntityNameExpression(extendsClause.expression) + && extendsClause.expression.kind !== SyntaxKind.NullKeyword + ) { // We must add a temporary declaration for the extends clause expression const oldId = input.name ? unescapeLeadingUnderscores(input.name.escapedText) : "default"; const newId = factory.createUniqueName(`${oldId}_base`, GeneratedIdentifierFlags.Optimistic); getSymbolAccessibilityDiagnostic = () => ({ - diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1, + diagnosticMessage: + Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1, errorNode: extendsClause, - typeName: input.name + typeName: input.name, }); - const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(extendsClause.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined); - const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const)); + const varDecl = factory.createVariableDeclaration( + newId, + /*exclamationToken*/ undefined, + resolver.createTypeOfExpression( + extendsClause.expression, + input, + declarationEmitNodeBuilderFlags, + symbolTracker, + ), + /*initializer*/ undefined, + ); + const statement = factory.createVariableStatement( + needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], + factory.createVariableDeclarationList([varDecl], NodeFlags.Const), + ); const heritageClauses = factory.createNodeArray(map(input.heritageClauses, clause => { if (clause.token === SyntaxKind.ExtendsKeyword) { const oldDiag = getSymbolAccessibilityDiagnostic; - getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(clause.types[0]); - const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, newId, visitNodes(t.typeArguments, visitDeclarationSubtree, isTypeNode)))); + getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode( + clause.types[0], + ); + const newClause = factory.updateHeritageClause( + clause, + map(clause.types, t => + factory.updateExpressionWithTypeArguments( + t, + newId, + visitNodes(t.typeArguments, visitDeclarationSubtree, isTypeNode), + )), + ); getSymbolAccessibilityDiagnostic = oldDiag; return newClause; } - return factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => isEntityNameExpression(t.expression) || t.expression.kind === SyntaxKind.NullKeyword)), visitDeclarationSubtree, isExpressionWithTypeArguments)); + return factory.updateHeritageClause( + clause, + visitNodes( + factory.createNodeArray( + filter(clause.types, t => + isEntityNameExpression(t.expression) + || t.expression.kind === SyntaxKind.NullKeyword), + ), + visitDeclarationSubtree, + isExpressionWithTypeArguments, + ), + ); })); - return [statement, cleanup(factory.updateClassDeclaration( - input, - modifiers, - input.name, - typeParameters, - heritageClauses, - members - ))!]; // TODO: GH#18217 + return [ + statement, + cleanup(factory.updateClassDeclaration( + input, + modifiers, + input.name, + typeParameters, + heritageClauses, + members, + ))!, + ]; // TODO: GH#18217 } else { const heritageClauses = transformHeritageClauses(input.heritageClauses); @@ -1753,7 +2199,7 @@ export function transformDeclarations(context: TransformationContext) { input.name, typeParameters, heritageClauses, - members + members, )); } } @@ -1761,23 +2207,34 @@ export function transformDeclarations(context: TransformationContext) { return cleanup(transformVariableStatement(input)); } case SyntaxKind.EnumDeclaration: { - return cleanup(factory.updateEnumDeclaration(input, factory.createNodeArray(ensureModifiers(input)), input.name, factory.createNodeArray(mapDefined(input.members, m => { - if (shouldStripInternal(m)) return; - // Rewrite enum values to their constants, if available - const constValue = resolver.getConstantValue(m); - const newInitializer = constValue === undefined - ? undefined - : typeof constValue === "string" - ? factory.createStringLiteral(constValue) - : constValue < 0 - ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(constValue))) - : factory.createNumericLiteral(constValue); - return preserveJsDoc(factory.updateEnumMember(m, m.name, newInitializer), m); - })))); + return cleanup(factory.updateEnumDeclaration( + input, + factory.createNodeArray(ensureModifiers(input)), + input.name, + factory.createNodeArray(mapDefined(input.members, m => { + if (shouldStripInternal(m)) return; + // Rewrite enum values to their constants, if available + const constValue = resolver.getConstantValue(m); + const newInitializer = constValue === undefined + ? undefined + : typeof constValue === "string" + ? factory.createStringLiteral(constValue) + : constValue < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(Math.abs(constValue)), + ) + : factory.createNumericLiteral(constValue); + return preserveJsDoc(factory.updateEnumMember(m, m.name, newInitializer), m); + })), + )); } } // Anything left unhandled is an error, so this should be unreachable - return Debug.assertNever(input, `Unhandled top-level node in declaration emit: ${Debug.formatSyntaxKind((input as Node).kind)}`); + return Debug.assertNever( + input, + `Unhandled top-level node in declaration emit: ${Debug.formatSyntaxKind((input as Node).kind)}`, + ); function cleanup(node: T | undefined): T | undefined { if (isEnclosingDeclaration(input)) { @@ -1831,7 +2288,12 @@ export function transformDeclarations(context: TransformationContext) { return recreateBindingPattern(e.name); } else { - return factory.createVariableDeclaration(e.name, /*exclamationToken*/ undefined, ensureType(e, /*type*/ undefined), /*initializer*/ undefined); + return factory.createVariableDeclaration( + e.name, + /*exclamationToken*/ undefined, + ensureType(e, /*type*/ undefined), + /*initializer*/ undefined, + ); } } } @@ -1885,7 +2347,10 @@ export function transformDeclarations(context: TransformationContext) { return maskModifierFlags(node, mask, additions); } - function getTypeAnnotationFromAllAccessorDeclarations(node: AccessorDeclaration, accessors: AllAccessorDeclarations) { + function getTypeAnnotationFromAllAccessorDeclarations( + node: AccessorDeclaration, + accessors: AllAccessorDeclarations, + ) { let accessorType = getTypeAnnotationFromAccessor(node); if (!accessorType && node !== accessors.firstAccessor) { accessorType = getTypeAnnotationFromAccessor(accessors.firstAccessor); @@ -1901,9 +2366,22 @@ export function transformDeclarations(context: TransformationContext) { } function transformHeritageClauses(nodes: NodeArray | undefined) { - return factory.createNodeArray(filter(map(nodes, clause => factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => { - return isEntityNameExpression(t.expression) || (clause.token === SyntaxKind.ExtendsKeyword && t.expression.kind === SyntaxKind.NullKeyword); - })), visitDeclarationSubtree, isExpressionWithTypeArguments))), clause => clause.types && !!clause.types.length)); + return factory.createNodeArray(filter( + map(nodes, clause => + factory.updateHeritageClause( + clause, + visitNodes( + factory.createNodeArray(filter(clause.types, t => { + return isEntityNameExpression(t.expression) + || (clause.token === SyntaxKind.ExtendsKeyword + && t.expression.kind === SyntaxKind.NullKeyword); + })), + visitDeclarationSubtree, + isExpressionWithTypeArguments, + ), + )), + clause => clause.types && !!clause.types.length, + )); } } @@ -1915,11 +2393,20 @@ function isAlwaysType(node: Node) { } // Elide "public" modifier, as it is the default -function maskModifiers(factory: NodeFactory, node: Node, modifierMask?: ModifierFlags, modifierAdditions?: ModifierFlags): Modifier[] | undefined { +function maskModifiers( + factory: NodeFactory, + node: Node, + modifierMask?: ModifierFlags, + modifierAdditions?: ModifierFlags, +): Modifier[] | undefined { return factory.createModifiersFromModifierFlags(maskModifierFlags(node, modifierMask, modifierAdditions)); } -function maskModifierFlags(node: Node, modifierMask: ModifierFlags = ModifierFlags.All ^ ModifierFlags.Public, modifierAdditions: ModifierFlags = ModifierFlags.None): ModifierFlags { +function maskModifierFlags( + node: Node, + modifierMask: ModifierFlags = ModifierFlags.All ^ ModifierFlags.Public, + modifierAdditions: ModifierFlags = ModifierFlags.None, +): ModifierFlags { let flags = (getEffectiveModifierFlags(node) & modifierMask) | modifierAdditions; if (flags & ModifierFlags.Default && !(flags & ModifierFlags.Export)) { // A non-exported default is a nonsequitor - we usually try to remove all export modifiers @@ -1937,8 +2424,8 @@ function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode return accessor.kind === SyntaxKind.GetAccessor ? accessor.type // Getter - return type : accessor.parameters.length > 0 - ? accessor.parameters[0].type // Setter parameter type - : undefined; + ? accessor.parameters[0].type // Setter parameter type + : undefined; } } diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index 2e3154aa7f710..771c40ba031cb 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -66,7 +66,9 @@ import { } from "../../_namespaces/ts"; /** @internal */ -export type GetSymbolAccessibilityDiagnostic = (symbolAccessibilityResult: SymbolAccessibilityResult) => (SymbolAccessibilityDiagnostic | undefined); +export type GetSymbolAccessibilityDiagnostic = ( + symbolAccessibilityResult: SymbolAccessibilityResult, +) => SymbolAccessibilityDiagnostic | undefined; /** @internal */ export interface SymbolAccessibilityDiagnostic { @@ -104,28 +106,28 @@ export type DeclarationDiagnosticProducing = /** @internal */ export function canProduceDiagnostics(node: Node): node is DeclarationDiagnosticProducing { - return isVariableDeclaration(node) || - isPropertyDeclaration(node) || - isPropertySignature(node) || - isBindingElement(node) || - isSetAccessor(node) || - isGetAccessor(node) || - isConstructSignatureDeclaration(node) || - isCallSignatureDeclaration(node) || - isMethodDeclaration(node) || - isMethodSignature(node) || - isFunctionDeclaration(node) || - isParameter(node) || - isTypeParameterDeclaration(node) || - isExpressionWithTypeArguments(node) || - isImportEqualsDeclaration(node) || - isTypeAliasDeclaration(node) || - isConstructorDeclaration(node) || - isIndexSignatureDeclaration(node) || - isPropertyAccessExpression(node) || - isElementAccessExpression(node) || - isBinaryExpression(node) || - isJSDocTypeAlias(node); + return isVariableDeclaration(node) + || isPropertyDeclaration(node) + || isPropertySignature(node) + || isBindingElement(node) + || isSetAccessor(node) + || isGetAccessor(node) + || isConstructSignatureDeclaration(node) + || isCallSignatureDeclaration(node) + || isMethodDeclaration(node) + || isMethodSignature(node) + || isFunctionDeclaration(node) + || isParameter(node) + || isTypeParameterDeclaration(node) + || isExpressionWithTypeArguments(node) + || isImportEqualsDeclaration(node) + || isTypeAliasDeclaration(node) + || isConstructorDeclaration(node) + || isIndexSignatureDeclaration(node) + || isPropertyAccessExpression(node) + || isElementAccessExpression(node) + || isBinaryExpression(node) + || isJSDocTypeAlias(node); } /** @internal */ @@ -144,77 +146,96 @@ export function createGetSymbolAccessibilityDiagnosticForNodeName(node: Declarat return diagnosticMessage !== undefined ? { diagnosticMessage, errorNode: node, - typeName: (node as NamedDeclaration).name + typeName: (node as NamedDeclaration).name, } : undefined; } function getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) { if (isStatic(node)) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; } else { - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; } } - function getMethodNameVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined { + function getMethodNameVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic | undefined { const diagnosticMessage = getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult); return diagnosticMessage !== undefined ? { diagnosticMessage, errorNode: node, - typeName: (node as NamedDeclaration).name + typeName: (node as NamedDeclaration).name, } : undefined; } function getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) { if (isStatic(node)) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_method_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_method_0_of_exported_class_has_or_is_using_private_name_1; } else { - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Method_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Method_0_of_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics.Method_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Method_0_of_exported_interface_has_or_is_using_private_name_1; } } } /** @internal */ -export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationDiagnosticProducing): GetSymbolAccessibilityDiagnostic { - if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isElementAccessExpression(node) || isBinaryExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) { +export function createGetSymbolAccessibilityDiagnosticForNode( + node: DeclarationDiagnosticProducing, +): GetSymbolAccessibilityDiagnostic { + if ( + isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) + || isPropertyAccessExpression(node) || isElementAccessExpression(node) || isBinaryExpression(node) + || isBindingElement(node) || isConstructorDeclaration(node) + ) { return getVariableDeclarationTypeVisibilityError; } else if (isSetAccessor(node) || isGetAccessor(node)) { return getAccessorDeclarationTypeVisibilityError; } - else if (isConstructSignatureDeclaration(node) || isCallSignatureDeclaration(node) || isMethodDeclaration(node) || isMethodSignature(node) || isFunctionDeclaration(node) || isIndexSignatureDeclaration(node)) { + else if ( + isConstructSignatureDeclaration(node) || isCallSignatureDeclaration(node) || isMethodDeclaration(node) + || isMethodSignature(node) || isFunctionDeclaration(node) || isIndexSignatureDeclaration(node) + ) { return getReturnTypeVisibilityError; } else if (isParameter(node)) { - if (isParameterPropertyDeclaration(node, node.parent) && hasSyntacticModifier(node.parent, ModifierFlags.Private)) { + if ( + isParameterPropertyDeclaration(node, node.parent) + && hasSyntacticModifier(node.parent, ModifierFlags.Private) + ) { return getVariableDeclarationTypeVisibilityError; } return getParameterDeclarationTypeVisibilityError; @@ -232,147 +253,186 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD return getTypeAliasDeclarationVisibilityError; } else { - return Debug.assertNever(node, `Attempted to set a declaration diagnostic context for unhandled node kind: ${Debug.formatSyntaxKind((node as Node).kind)}`); + return Debug.assertNever( + node, + `Attempted to set a declaration diagnostic context for unhandled node kind: ${ + Debug.formatSyntaxKind((node as Node).kind) + }`, + ); } - function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) { + function getVariableDeclarationTypeVisibilityDiagnosticMessage( + symbolAccessibilityResult: SymbolAccessibilityResult, + ) { if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Exported_variable_0_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Exported_variable_0_has_or_is_using_private_name_1; } // This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit // The only exception here is if the constructor was marked as private. we are not emitting the constructor parameters at all. - else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.ElementAccessExpression || node.kind === SyntaxKind.BinaryExpression || node.kind === SyntaxKind.PropertySignature || - (node.kind === SyntaxKind.Parameter && hasSyntacticModifier(node.parent, ModifierFlags.Private))) { + else if ( + node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression + || node.kind === SyntaxKind.ElementAccessExpression || node.kind === SyntaxKind.BinaryExpression + || node.kind === SyntaxKind.PropertySignature + || (node.kind === SyntaxKind.Parameter && hasSyntacticModifier(node.parent, ModifierFlags.Private)) + ) { // TODO(jfreeman): Deal with computed properties in error reporting. if (isStatic(node)) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1; } else if (node.parent.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.Parameter) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1; } else { // Interfaces cannot have types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1; } } } - function getVariableDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined { + function getVariableDeclarationTypeVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic | undefined { const diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult); return diagnosticMessage !== undefined ? { diagnosticMessage, errorNode: node, - typeName: (node as NamedDeclaration).name + typeName: (node as NamedDeclaration).name, } : undefined; } - function getAccessorDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { + function getAccessorDeclarationTypeVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic { let diagnosticMessage: DiagnosticMessage; if (node.kind === SyntaxKind.SetAccessor) { // Getters can infer the return type from the returned expression, but setters cannot, so the // "_from_external_module_1_but_cannot_be_named" case cannot occur. if (isStatic(node)) { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1; } else { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_private_name_1; } } else { if (isStatic(node)) { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_private_name_1; } else { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_private_name_1; } } return { diagnosticMessage, errorNode: (node as NamedDeclaration).name!, - typeName: (node as NamedDeclaration).name + typeName: (node as NamedDeclaration).name, }; } - function getReturnTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { + function getReturnTypeVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic { let diagnosticMessage: DiagnosticMessage; switch (node.kind) { case SyntaxKind.ConstructSignature: // Interfaces cannot have return types that cannot be named - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 + : Diagnostics + .Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0; break; case SyntaxKind.CallSignature: // Interfaces cannot have return types that cannot be named - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 + : Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0; break; case SyntaxKind.IndexSignature: // Interfaces cannot have return types that cannot be named - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 + : Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0; break; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: if (isStatic(node)) { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : - Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named + : Diagnostics + .Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 + : Diagnostics + .Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0; } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : - Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named + : Diagnostics + .Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 + : Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0; } else { // Interfaces cannot have return types that cannot be named - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 + : Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0; } break; case SyntaxKind.FunctionDeclaration: - diagnosticMessage = symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : - Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 : - Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0; + diagnosticMessage = symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named + : Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 + : Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0; break; default: @@ -381,84 +441,104 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD return { diagnosticMessage, - errorNode: (node as NamedDeclaration).name || node + errorNode: (node as NamedDeclaration).name || node, }; } - function getParameterDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined { - const diagnosticMessage: DiagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult); + function getParameterDeclarationTypeVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic | undefined { + const diagnosticMessage: DiagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage( + symbolAccessibilityResult, + ); return diagnosticMessage !== undefined ? { diagnosticMessage, errorNode: node, - typeName: (node as NamedDeclaration).name + typeName: (node as NamedDeclaration).name, } : undefined; } - function getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult): DiagnosticMessage { + function getParameterDeclarationTypeVisibilityDiagnosticMessage( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): DiagnosticMessage { switch (node.parent.kind) { case SyntaxKind.Constructor: - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1; case SyntaxKind.ConstructSignature: case SyntaxKind.ConstructorType: // Interfaces cannot have parameter types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; case SyntaxKind.CallSignature: // Interfaces cannot have parameter types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; case SyntaxKind.IndexSignature: // Interfaces cannot have parameter types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_private_name_1; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: if (isStatic(node.parent)) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics + .Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; } else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics + .Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; } else { // Interfaces cannot have parameter types that cannot be named - return symbolAccessibilityResult.errorModuleName ? - Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? Diagnostics + .Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; } case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionType: - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1; case SyntaxKind.SetAccessor: case SyntaxKind.GetAccessor: - return symbolAccessibilityResult.errorModuleName ? - symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? - Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : - Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_private_module_2 : - Diagnostics.Parameter_0_of_accessor_has_or_is_using_private_name_1; + return symbolAccessibilityResult.errorModuleName + ? symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed + ? Diagnostics + .Parameter_0_of_accessor_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named + : Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_private_module_2 + : Diagnostics.Parameter_0_of_accessor_has_or_is_using_private_name_1; default: return Debug.fail(`Unknown parent for parameter: ${Debug.formatSyntaxKind(node.parent.kind)}`); @@ -483,23 +563,28 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD case SyntaxKind.ConstructorType: case SyntaxKind.ConstructSignature: - diagnosticMessage = Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1; break; case SyntaxKind.CallSignature: - diagnosticMessage = Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1; break; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: if (isStatic(node.parent)) { - diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; } else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { - diagnosticMessage = Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; + diagnosticMessage = Diagnostics + .Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1; } else { - diagnosticMessage = Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; + diagnosticMessage = + Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1; } break; @@ -523,7 +608,7 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD return { diagnosticMessage, errorNode: node, - typeName: (node as NamedDeclaration).name + typeName: (node as NamedDeclaration).name, }; } @@ -532,10 +617,11 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD // Heritage clause is written by user so it can always be named if (isClassDeclaration(node.parent.parent)) { // Class or Interface implemented/extended is inaccessible - diagnosticMessage = isHeritageClause(node.parent) && node.parent.token === SyntaxKind.ImplementsKeyword ? - Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 : - node.parent.parent.name ? Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1 : - Diagnostics.extends_clause_of_exported_class_has_or_is_using_private_name_0; + diagnosticMessage = isHeritageClause(node.parent) && node.parent.token === SyntaxKind.ImplementsKeyword + ? Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 + : node.parent.parent.name + ? Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1 + : Diagnostics.extends_clause_of_exported_class_has_or_is_using_private_name_0; } else { // interface is inaccessible @@ -545,7 +631,7 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD return { diagnosticMessage, errorNode: node, - typeName: getNameOfDeclaration(node.parent.parent as Declaration) + typeName: getNameOfDeclaration(node.parent.parent as Declaration), }; } @@ -553,16 +639,19 @@ export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationD return { diagnosticMessage: Diagnostics.Import_declaration_0_is_using_private_name_1, errorNode: node, - typeName: (node as NamedDeclaration).name + typeName: (node as NamedDeclaration).name, }; } - function getTypeAliasDeclarationVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { + function getTypeAliasDeclarationVisibilityError( + symbolAccessibilityResult: SymbolAccessibilityResult, + ): SymbolAccessibilityDiagnostic { return { diagnosticMessage: symbolAccessibilityResult.errorModuleName ? Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1_from_module_2 : Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1, - errorNode: isJSDocTypeAlias(node) ? Debug.checkDefined(node.typeExpression) : (node as TypeAliasDeclaration).type, + errorNode: isJSDocTypeAlias(node) ? Debug.checkDefined(node.typeExpression) + : (node as TypeAliasDeclaration).type, typeName: isJSDocTypeAlias(node) ? getNameOfDeclaration(node) : (node as TypeAliasDeclaration).name, }; } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 27a991d0f3402..d095fcb158797 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -69,9 +69,16 @@ interface FlattenContext { hoistTempVariables: boolean; hasTransformedPriorElement?: boolean; // indicates whether we've transformed a prior declaration emitExpression: (value: Expression) => void; - emitBindingOrAssignment: (target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node | undefined) => void; + emitBindingOrAssignment: ( + target: BindingOrAssignmentElementTarget, + value: Expression, + location: TextRange, + original: Node | undefined, + ) => void; createArrayBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ArrayBindingOrAssignmentPattern; - createObjectBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ObjectBindingOrAssignmentPattern; + createObjectBindingOrAssignmentPattern: ( + elements: BindingOrAssignmentElement[], + ) => ObjectBindingOrAssignmentPattern; createArrayBindingOrAssignmentElement: (node: Identifier) => BindingOrAssignmentElement; visitor: (node: Node) => VisitResult; } @@ -97,11 +104,12 @@ export const enum FlattenLevel { */ export function flattenDestructuringAssignment( node: VariableDeclaration | DestructuringAssignment, - visitor: ((node: Node) => VisitResult), + visitor: (node: Node) => VisitResult, context: TransformationContext, level: FlattenLevel, needsValue?: boolean, - createAssignmentCallback?: (name: Identifier, value: Expression, location?: TextRange) => Expression): Expression { + createAssignmentCallback?: (name: Identifier, value: Expression, location?: TextRange) => Expression, +): Expression { let location: TextRange = node; let value: Expression | undefined; if (isDestructuringAssignment(node)) { @@ -128,15 +136,17 @@ export function flattenDestructuringAssignment( createArrayBindingOrAssignmentPattern: elements => makeArrayAssignmentPattern(context.factory, elements), createObjectBindingOrAssignmentPattern: elements => makeObjectAssignmentPattern(context.factory, elements), createArrayBindingOrAssignmentElement: makeAssignmentElement, - visitor + visitor, }; if (value) { value = visitNode(value, visitor, isExpression); Debug.assert(value); - if (isIdentifier(value) && bindingOrAssignmentElementAssignsToName(node, value.escapedText) || - bindingOrAssignmentElementContainsNonLiteralComputedName(node)) { + if ( + isIdentifier(value) && bindingOrAssignmentElementAssignsToName(node, value.escapedText) + || bindingOrAssignmentElementContainsNonLiteralComputedName(node) + ) { // If the right-hand value of the assignment is also an assignment target then // we need to cache the right-hand value. value = ensureIdentifier(flattenContext, value, /*reuseIdentifierExpressions*/ false, location); @@ -161,7 +171,13 @@ export function flattenDestructuringAssignment( } } - flattenBindingOrAssignmentElement(flattenContext, node, value, location, /*skipInitializer*/ isDestructuringAssignment(node)); + flattenBindingOrAssignmentElement( + flattenContext, + node, + value, + location, + /*skipInitializer*/ isDestructuringAssignment(node), + ); if (value && needsValue) { if (!some(expressions)) { @@ -177,13 +193,21 @@ export function flattenDestructuringAssignment( expressions = append(expressions, expression); } - function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node | undefined) { + function emitBindingOrAssignment( + target: BindingOrAssignmentElementTarget, + value: Expression, + location: TextRange, + original: Node | undefined, + ) { Debug.assertNode(target, createAssignmentCallback ? isIdentifier : isExpression); const expression = createAssignmentCallback ? createAssignmentCallback(target as Identifier, value, location) : setTextRange( - context.factory.createAssignment(Debug.checkDefined(visitNode(target as Expression, visitor, isExpression)), value), - location + context.factory.createAssignment( + Debug.checkDefined(visitNode(target as Expression, visitor, isExpression)), + value, + ), + location, ); expression.original = original; emitExpression(expression); @@ -217,11 +241,15 @@ function bindingOrAssignmentElementContainsNonLiteralComputedName(element: Bindi return true; } const target = getTargetOfBindingOrAssignmentElement(element); - return !!target && isBindingOrAssignmentPattern(target) && bindingOrAssignmentPatternContainsNonLiteralComputedName(target); + return !!target && isBindingOrAssignmentPattern(target) + && bindingOrAssignmentPatternContainsNonLiteralComputedName(target); } function bindingOrAssignmentPatternContainsNonLiteralComputedName(pattern: BindingOrAssignmentPattern): boolean { - return !!forEach(getElementsOfBindingOrAssignmentPattern(pattern), bindingOrAssignmentElementContainsNonLiteralComputedName); + return !!forEach( + getElementsOfBindingOrAssignmentPattern(pattern), + bindingOrAssignmentElementContainsNonLiteralComputedName, + ); } /** @@ -244,9 +272,16 @@ export function flattenDestructuringBinding( level: FlattenLevel, rval?: Expression, hoistTempVariables = false, - skipInitializer?: boolean): VariableDeclaration[] { + skipInitializer?: boolean, +): VariableDeclaration[] { let pendingExpressions: Expression[] | undefined; - const pendingDeclarations: { pendingExpressions?: Expression[], name: BindingName, value: Expression, location?: TextRange, original?: Node; }[] = []; + const pendingDeclarations: { + pendingExpressions?: Expression[]; + name: BindingName; + value: Expression; + location?: TextRange; + original?: Node; + }[] = []; const declarations: VariableDeclaration[] = []; const flattenContext: FlattenContext = { context, @@ -258,17 +293,31 @@ export function flattenDestructuringBinding( createArrayBindingOrAssignmentPattern: elements => makeArrayBindingPattern(context.factory, elements), createObjectBindingOrAssignmentPattern: elements => makeObjectBindingPattern(context.factory, elements), createArrayBindingOrAssignmentElement: name => makeBindingElement(context.factory, name), - visitor + visitor, }; if (isVariableDeclaration(node)) { let initializer = getInitializerOfBindingOrAssignmentElement(node); - if (initializer && (isIdentifier(initializer) && bindingOrAssignmentElementAssignsToName(node, initializer.escapedText) || - bindingOrAssignmentElementContainsNonLiteralComputedName(node))) { + if ( + initializer + && (isIdentifier(initializer) && bindingOrAssignmentElementAssignsToName(node, initializer.escapedText) + || bindingOrAssignmentElementContainsNonLiteralComputedName(node)) + ) { // If the right-hand value of the assignment is also an assignment target then // we need to cache the right-hand value. - initializer = ensureIdentifier(flattenContext, Debug.checkDefined(visitNode(initializer, flattenContext.visitor, isExpression)), /*reuseIdentifierExpressions*/ false, initializer); - node = context.factory.updateVariableDeclaration(node, node.name, /*exclamationToken*/ undefined, /*type*/ undefined, initializer); + initializer = ensureIdentifier( + flattenContext, + Debug.checkDefined(visitNode(initializer, flattenContext.visitor, isExpression)), + /*reuseIdentifierExpressions*/ false, + initializer, + ); + node = context.factory.updateVariableDeclaration( + node, + node.name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + initializer, + ); } } @@ -285,7 +334,7 @@ export function flattenDestructuringBinding( const pendingDeclaration = last(pendingDeclarations); pendingDeclaration.pendingExpressions = append( pendingDeclaration.pendingExpressions, - context.factory.createAssignment(temp, pendingDeclaration.value) + context.factory.createAssignment(temp, pendingDeclaration.value), ); addRange(pendingDeclaration.pendingExpressions, pendingExpressions); pendingDeclaration.value = temp; @@ -296,7 +345,7 @@ export function flattenDestructuringBinding( name, /*exclamationToken*/ undefined, /*type*/ undefined, - pendingExpressions ? context.factory.inlineExpressions(append(pendingExpressions, value)) : value + pendingExpressions ? context.factory.inlineExpressions(append(pendingExpressions, value)) : value, ); variable.original = original; setTextRange(variable, location); @@ -308,7 +357,12 @@ export function flattenDestructuringBinding( pendingExpressions = append(pendingExpressions, value); } - function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange | undefined, original: Node | undefined) { + function emitBindingOrAssignment( + target: BindingOrAssignmentElementTarget, + value: Expression, + location: TextRange | undefined, + original: Node | undefined, + ) { Debug.assertNode(target, isBindingName); if (pendingExpressions) { value = context.factory.inlineExpressions(append(pendingExpressions, value)); @@ -333,10 +387,15 @@ function flattenBindingOrAssignmentElement( element: BindingOrAssignmentElement, value: Expression | undefined, location: TextRange, - skipInitializer?: boolean) { + skipInitializer?: boolean, +) { const bindingTarget = getTargetOfBindingOrAssignmentElement(element)!; // TODO: GH#18217 if (!skipInitializer) { - const initializer = visitNode(getInitializerOfBindingOrAssignmentElement(element), flattenContext.visitor, isExpression); + const initializer = visitNode( + getInitializerOfBindingOrAssignmentElement(element), + flattenContext.visitor, + isExpression, + ); if (initializer) { // Combine value and initializer if (value) { @@ -375,7 +434,13 @@ function flattenBindingOrAssignmentElement( * @param value The current RHS value to assign to the element. * @param location The location to use for source maps and comments. */ -function flattenObjectBindingOrAssignmentPattern(flattenContext: FlattenContext, parent: BindingOrAssignmentElement, pattern: ObjectBindingOrAssignmentPattern, value: Expression, location: TextRange) { +function flattenObjectBindingOrAssignmentPattern( + flattenContext: FlattenContext, + parent: BindingOrAssignmentElement, + pattern: ObjectBindingOrAssignmentPattern, + value: Expression, + location: TextRange, +) { const elements = getElementsOfBindingOrAssignmentPattern(pattern); const numElements = elements.length; if (numElements !== 1) { @@ -392,35 +457,65 @@ function flattenObjectBindingOrAssignmentPattern(flattenContext: FlattenContext, const element = elements[i]; if (!getRestIndicatorOfBindingOrAssignmentElement(element)) { const propertyName = getPropertyNameOfBindingOrAssignmentElement(element)!; - if (flattenContext.level >= FlattenLevel.ObjectRest - && !(element.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) - && !(getTargetOfBindingOrAssignmentElement(element)!.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) - && !isComputedPropertyName(propertyName)) { - bindingElements = append(bindingElements, visitNode(element, flattenContext.visitor, isBindingOrAssignmentElement)); + if ( + flattenContext.level >= FlattenLevel.ObjectRest + && !(element.transformFlags + & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) + && !(getTargetOfBindingOrAssignmentElement(element)!.transformFlags + & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) + && !isComputedPropertyName(propertyName) + ) { + bindingElements = append( + bindingElements, + visitNode(element, flattenContext.visitor, isBindingOrAssignmentElement), + ); } else { if (bindingElements) { - flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); + flattenContext.emitBindingOrAssignment( + flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), + value, + location, + pattern, + ); bindingElements = undefined; } const rhsValue = createDestructuringPropertyAccess(flattenContext, value, propertyName); if (isComputedPropertyName(propertyName)) { - computedTempVariables = append(computedTempVariables, (rhsValue as ElementAccessExpression).argumentExpression); + computedTempVariables = append( + computedTempVariables, + (rhsValue as ElementAccessExpression).argumentExpression, + ); } flattenBindingOrAssignmentElement(flattenContext, element, rhsValue, /*location*/ element); } } else if (i === numElements - 1) { if (bindingElements) { - flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); + flattenContext.emitBindingOrAssignment( + flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), + value, + location, + pattern, + ); bindingElements = undefined; } - const rhsValue = flattenContext.context.getEmitHelperFactory().createRestHelper(value, elements, computedTempVariables, pattern); + const rhsValue = flattenContext.context.getEmitHelperFactory().createRestHelper( + value, + elements, + computedTempVariables, + pattern, + ); flattenBindingOrAssignmentElement(flattenContext, element, rhsValue, element); } } if (bindingElements) { - flattenContext.emitBindingOrAssignment(flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), value, location, pattern); + flattenContext.emitBindingOrAssignment( + flattenContext.createObjectBindingOrAssignmentPattern(bindingElements), + value, + location, + pattern, + ); } } @@ -433,7 +528,13 @@ function flattenObjectBindingOrAssignmentPattern(flattenContext: FlattenContext, * @param value The current RHS value to assign to the element. * @param location The location to use for source maps and comments. */ -function flattenArrayBindingOrAssignmentPattern(flattenContext: FlattenContext, parent: BindingOrAssignmentElement, pattern: ArrayBindingOrAssignmentPattern, value: Expression, location: TextRange) { +function flattenArrayBindingOrAssignmentPattern( + flattenContext: FlattenContext, + parent: BindingOrAssignmentElement, + pattern: ArrayBindingOrAssignmentPattern, + value: Expression, + location: TextRange, +) { const elements = getElementsOfBindingOrAssignmentPattern(pattern); const numElements = elements.length; if (flattenContext.level < FlattenLevel.ObjectRest && flattenContext.downlevelIteration) { @@ -445,16 +546,18 @@ function flattenArrayBindingOrAssignmentPattern(flattenContext: FlattenContext, value, numElements > 0 && getRestIndicatorOfBindingOrAssignmentElement(elements[numElements - 1]) ? undefined - : numElements + : numElements, ), - location + location, ), /*reuseIdentifierExpressions*/ false, - location + location, ); } - else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0) - || every(elements, isOmittedExpression)) { + else if ( + numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0) + || every(elements, isOmittedExpression) + ) { // For anything other than a single-element destructuring we need to generate a temporary // to ensure value is evaluated exactly once. Additionally, if we have zero elements // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, @@ -471,14 +574,20 @@ function flattenArrayBindingOrAssignmentPattern(flattenContext: FlattenContext, if (flattenContext.level >= FlattenLevel.ObjectRest) { // If an array pattern contains an ObjectRest, we must cache the result so that we // can perform the ObjectRest destructuring in a different declaration - if (element.transformFlags & TransformFlags.ContainsObjectRestOrSpread || flattenContext.hasTransformedPriorElement && !isSimpleBindingOrAssignmentElement(element)) { + if ( + element.transformFlags & TransformFlags.ContainsObjectRestOrSpread + || flattenContext.hasTransformedPriorElement && !isSimpleBindingOrAssignmentElement(element) + ) { flattenContext.hasTransformedPriorElement = true; const temp = flattenContext.context.factory.createTempVariable(/*recordTempVariable*/ undefined); if (flattenContext.hoistTempVariables) { flattenContext.context.hoistVariableDeclaration(temp); } - restContainingElements = append(restContainingElements, [temp, element] as [Identifier, BindingOrAssignmentElement]); + restContainingElements = append( + restContainingElements, + [temp, element] as [Identifier, BindingOrAssignmentElement], + ); bindingElements = append(bindingElements, flattenContext.createArrayBindingOrAssignmentElement(temp)); } else { @@ -498,7 +607,12 @@ function flattenArrayBindingOrAssignmentPattern(flattenContext: FlattenContext, } } if (bindingElements) { - flattenContext.emitBindingOrAssignment(flattenContext.createArrayBindingOrAssignmentPattern(bindingElements), value, location, pattern); + flattenContext.emitBindingOrAssignment( + flattenContext.createArrayBindingOrAssignmentPattern(bindingElements), + value, + location, + pattern, + ); } if (restContainingElements) { for (const [id, element] of restContainingElements) { @@ -514,7 +628,9 @@ function isSimpleBindingOrAssignmentElement(element: BindingOrAssignmentElement) if (propertyName && !isPropertyNameLiteral(propertyName)) return false; const initializer = getInitializerOfBindingOrAssignmentElement(element); if (initializer && !isSimpleInlineableExpression(initializer)) return false; - if (isBindingOrAssignmentPattern(target)) return every(getElementsOfBindingOrAssignmentPattern(target), isSimpleBindingOrAssignmentElement); + if (isBindingOrAssignmentPattern(target)) { + return every(getElementsOfBindingOrAssignmentPattern(target), isSimpleBindingOrAssignmentElement); + } return isIdentifier(target); } @@ -526,9 +642,20 @@ function isSimpleBindingOrAssignmentElement(element: BindingOrAssignmentElement) * @param defaultValue The default value to use if `value` is `undefined` at runtime. * @param location The location to use for source maps and comments. */ -function createDefaultValueCheck(flattenContext: FlattenContext, value: Expression, defaultValue: Expression, location: TextRange): Expression { +function createDefaultValueCheck( + flattenContext: FlattenContext, + value: Expression, + defaultValue: Expression, + location: TextRange, +): Expression { value = ensureIdentifier(flattenContext, value, /*reuseIdentifierExpressions*/ true, location); - return flattenContext.context.factory.createConditionalExpression(flattenContext.context.factory.createTypeCheck(value, "undefined"), /*questionToken*/ undefined, defaultValue, /*colonToken*/ undefined, value); + return flattenContext.context.factory.createConditionalExpression( + flattenContext.context.factory.createTypeCheck(value, "undefined"), + /*questionToken*/ undefined, + defaultValue, + /*colonToken*/ undefined, + value, + ); } /** @@ -541,10 +668,19 @@ function createDefaultValueCheck(flattenContext: FlattenContext, value: Expressi * @param value The RHS value that is the source of the property. * @param propertyName The destructuring property name. */ -function createDestructuringPropertyAccess(flattenContext: FlattenContext, value: Expression, propertyName: PropertyName): LeftHandSideExpression { +function createDestructuringPropertyAccess( + flattenContext: FlattenContext, + value: Expression, + propertyName: PropertyName, +): LeftHandSideExpression { const { factory } = flattenContext.context; if (isComputedPropertyName(propertyName)) { - const argumentExpression = ensureIdentifier(flattenContext, Debug.checkDefined(visitNode(propertyName.expression, flattenContext.visitor, isExpression)), /*reuseIdentifierExpressions*/ false, /*location*/ propertyName); + const argumentExpression = ensureIdentifier( + flattenContext, + Debug.checkDefined(visitNode(propertyName.expression, flattenContext.visitor, isExpression)), + /*reuseIdentifierExpressions*/ false, + /*location*/ propertyName, + ); return flattenContext.context.factory.createElementAccessExpression(value, argumentExpression); } else if (isStringOrNumericLiteralLike(propertyName)) { @@ -568,7 +704,12 @@ function createDestructuringPropertyAccess(flattenContext: FlattenContext, value * false if it is necessary to always emit an identifier. * @param location The location to use for source maps and comments. */ -function ensureIdentifier(flattenContext: FlattenContext, value: Expression, reuseIdentifierExpressions: boolean, location: TextRange) { +function ensureIdentifier( + flattenContext: FlattenContext, + value: Expression, + reuseIdentifierExpressions: boolean, + location: TextRange, +) { if (isIdentifier(value) && reuseIdentifierExpressions) { return value; } @@ -576,7 +717,9 @@ function ensureIdentifier(flattenContext: FlattenContext, value: Expression, reu const temp = flattenContext.context.factory.createTempVariable(/*recordTempVariable*/ undefined); if (flattenContext.hoistTempVariables) { flattenContext.context.hoistVariableDeclaration(temp); - flattenContext.emitExpression(setTextRange(flattenContext.context.factory.createAssignment(temp, value), location)); + flattenContext.emitExpression( + setTextRange(flattenContext.context.factory.createAssignment(temp, value), location), + ); } else { flattenContext.emitBindingOrAssignment(temp, value, location, /*original*/ undefined); diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 5e2b895a23498..210225b1b4c67 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -208,7 +208,7 @@ import { VisitResult, VoidExpression, WhileStatement, - YieldExpression + YieldExpression, } from "../_namespaces/ts"; const enum ES2015SubstitutionFlags { @@ -264,19 +264,19 @@ interface LoopOutParameter { const enum LoopOutParameterFlags { None = 0, - Body = 1 << 0, // Modified in the body of the iteration statement - Initializer = 1 << 1, // Set in the initializer of a ForStatement + Body = 1 << 0, // Modified in the body of the iteration statement + Initializer = 1 << 1, // Set in the initializer of a ForStatement } const enum CopyDirection { ToOriginal, - ToOutParameter + ToOutParameter, } const enum Jump { - Break = 1 << 1, - Continue = 1 << 2, - Return = 1 << 3 + Break = 1 << 1, + Continue = 1 << 2, + Return = 1 << 3, } interface ConvertedLoopState { @@ -357,9 +357,15 @@ interface ConvertedLoopState { loopOutParameters: LoopOutParameter[]; } -type LoopConverter = (node: T, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement; +type LoopConverter = ( + node: T, + outermostLabeledStatement: LabeledStatement | undefined, + convertedLoopBodyStatements: Statement[] | undefined, + ancestorFacts: HierarchyFacts, +) => Statement; // Facts we track as we traverse the tree +// dprint-ignore const enum HierarchyFacts { None = 0, @@ -459,6 +465,7 @@ const enum HierarchyFacts { FunctionSubtreeExcludes = NewTarget | CapturedLexicalThis, } +// dprint-ignore const enum SpreadSegmentKind { None, // Not a spread segment UnpackedSpread, // A spread segment that must be packed (i.e., converting `[...[1, , 2]]` into `[1, undefined, 2]`) @@ -500,7 +507,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile function recordTaggedTemplateString(temp: Identifier) { taggedTemplateStringDeclarations = append( taggedTemplateStringDeclarations, - factory.createVariableDeclaration(temp)); + factory.createVariableDeclaration(temp), + ); } /** @@ -554,7 +562,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param includeFacts The new `HierarchyFacts` of the subtree that should be propagated. */ function exitSubtree(ancestorFacts: HierarchyFacts, excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) { - hierarchyFacts = (hierarchyFacts & ~excludeFacts | includeFacts) & HierarchyFacts.SubtreeFactsMask | ancestorFacts; + hierarchyFacts = (hierarchyFacts & ~excludeFacts | includeFacts) & HierarchyFacts.SubtreeFactsMask + | ancestorFacts; } function isReturnVoidStatementInConstructorWithCapturedSuper(node: Node): boolean { @@ -601,7 +610,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile if (isPropertyDeclaration(original) && hasStaticModifier(original)) { const ancestorFacts = enterSubtree( HierarchyFacts.StaticInitializerExcludes, - HierarchyFacts.StaticInitializerIncludes + HierarchyFacts.StaticInitializerIncludes, ); const result = visitorWorker(node, /*expressionResultIsUnused*/ false); exitSubtree(ancestorFacts, HierarchyFacts.FunctionSubtreeExcludes, HierarchyFacts.None); @@ -669,7 +678,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile case SyntaxKind.DoStatement: case SyntaxKind.WhileStatement: - return visitDoOrWhileStatement(node as DoStatement | WhileStatement, /*outermostLabeledStatement*/ undefined); + return visitDoOrWhileStatement( + node as DoStatement | WhileStatement, + /*outermostLabeledStatement*/ undefined, + ); case SyntaxKind.ForStatement: return visitForStatement(node as ForStatement, /*outermostLabeledStatement*/ undefined); @@ -776,15 +788,18 @@ export function transformES2015(context: TransformationContext): (x: SourceFile addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset)); if (taggedTemplateStringDeclarations) { statements.push( - factory.createVariableStatement(/*modifiers*/ undefined, - factory.createVariableDeclarationList(taggedTemplateStringDeclarations))); + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList(taggedTemplateStringDeclarations), + ), + ); } factory.mergeLexicalEnvironment(prologue, endLexicalEnvironment()); insertCaptureThisForNodeIfNeeded(prologue, node); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); return factory.updateSourceFile( node, - setTextRange(factory.createNodeArray(concatenate(prologue, statements)), node.statements) + setTextRange(factory.createNodeArray(concatenate(prologue, statements)), node.statements), ); } @@ -808,7 +823,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } function returnCapturedThis(node: Node): ReturnStatement { - return setOriginalNode(factory.createReturnStatement(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)), node); + return setOriginalNode( + factory.createReturnStatement( + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + ), + node, + ); } function visitReturnStatement(node: ReturnStatement): Statement { @@ -824,10 +847,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createIdentifier("value"), node.expression ? Debug.checkDefined(visitNode(node.expression, visitor, isExpression)) - : factory.createVoidZero() - ) - ] - ) + : factory.createVoidZero(), + ), + ], + ), ); } else if (isReturnVoidStatementInConstructorWithCapturedSuper(node)) { @@ -858,14 +881,18 @@ export function transformES2015(context: TransformationContext): (x: SourceFile function visitIdentifier(node: Identifier): Identifier { if (convertedLoopState) { if (resolver.isArgumentsLocalBinding(node)) { - return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = factory.createUniqueName("arguments")); + return convertedLoopState.argumentsName + || (convertedLoopState.argumentsName = factory.createUniqueName("arguments")); } } if (node.flags & NodeFlags.IdentifierHasExtendedUnicodeEscape) { - return setOriginalNode(setTextRange( - factory.createIdentifier(unescapeLeadingUnderscores(node.escapedText)), - node - ), node); + return setOriginalNode( + setTextRange( + factory.createIdentifier(unescapeLeadingUnderscores(node.escapedText)), + node, + ), + node, + ); } return node; } @@ -878,8 +905,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // - break/continue is non-labeled and located in non-converted loop/switch statement const jump = node.kind === SyntaxKind.BreakStatement ? Jump.Break : Jump.Continue; const canUseBreakOrContinue = - (node.label && convertedLoopState.labels && convertedLoopState.labels.get(idText(node.label))) || - (!node.label && (convertedLoopState.allowedNonLabeledJumps! & jump)); + (node.label && convertedLoopState.labels && convertedLoopState.labels.get(idText(node.label))) + || (!node.label && (convertedLoopState.allowedNonLabeledJumps! & jump)); if (!canUseBreakOrContinue) { let labelMarker: string; @@ -946,13 +973,16 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.getLocalName(node, /*allowComments*/ true), /*exclamationToken*/ undefined, /*type*/ undefined, - transformClassLikeDeclarationToExpression(node) + transformClassLikeDeclarationToExpression(node), ); setOriginalNode(variable, node); const statements: Statement[] = []; - const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([variable])); + const statement = factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([variable]), + ); setOriginalNode(statement, node); setTextRange(statement, node); @@ -1030,9 +1060,17 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - extendsClauseElement ? [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel))] : [], + extendsClauseElement + ? [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + )] : [], /*type*/ undefined, - transformClassBody(node, extendsClauseElement) + transformClassBody(node, extendsClauseElement), ); // To preserve the behavior of the old emitter, we explicitly indent @@ -1056,8 +1094,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*typeArguments*/ undefined, extendsClauseElement ? [Debug.checkDefined(visitNode(extendsClauseElement.expression, visitor, isExpression))] - : [] - ) + : [], + ), ); addSyntheticLeadingComment(result, SyntaxKind.MultiLineCommentTrivia, "* @class "); return result; @@ -1069,17 +1107,24 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param node A ClassExpression or ClassDeclaration node. * @param extendsClauseElement The expression for the class `extends` clause. */ - function transformClassBody(node: ClassExpression | ClassDeclaration, extendsClauseElement: ExpressionWithTypeArguments | undefined): Block { + function transformClassBody( + node: ClassExpression | ClassDeclaration, + extendsClauseElement: ExpressionWithTypeArguments | undefined, + ): Block { const statements: Statement[] = []; const name = factory.getInternalName(node); - const constructorLikeName = isIdentifierANonContextualKeyword(name) ? factory.getGeneratedNameForNode(name) : name; + const constructorLikeName = isIdentifierANonContextualKeyword(name) ? factory.getGeneratedNameForNode(name) + : name; startLexicalEnvironment(); addExtendsHelperIfNeeded(statements, node, extendsClauseElement); addConstructor(statements, node, constructorLikeName, extendsClauseElement); addClassMembers(statements, node); // Create a synthetic text range for the return statement. - const closingBraceLocation = createTokenRange(skipTrivia(currentText, node.members.end), SyntaxKind.CloseBraceToken); + const closingBraceLocation = createTokenRange( + skipTrivia(currentText, node.members.end), + SyntaxKind.CloseBraceToken, + ); // The following partially-emitted expression exists purely to align our sourcemap // emit with the original emitter. @@ -1094,7 +1139,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); - const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), /*location*/ node.members), /*multiLine*/ true); + const block = factory.createBlock( + setTextRange(factory.createNodeArray(statements), /*location*/ node.members), + /*multiLine*/ true, + ); setEmitFlags(block, EmitFlags.NoComments); return block; } @@ -1106,15 +1154,19 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param node The ClassExpression or ClassDeclaration node. * @param extendsClauseElement The expression for the class `extends` clause. */ - function addExtendsHelperIfNeeded(statements: Statement[], node: ClassExpression | ClassDeclaration, extendsClauseElement: ExpressionWithTypeArguments | undefined): void { + function addExtendsHelperIfNeeded( + statements: Statement[], + node: ClassExpression | ClassDeclaration, + extendsClauseElement: ExpressionWithTypeArguments | undefined, + ): void { if (extendsClauseElement) { statements.push( setTextRange( factory.createExpressionStatement( - emitHelpers().createExtendsHelper(factory.getInternalName(node)) + emitHelpers().createExtendsHelper(factory.getInternalName(node)), ), - /*location*/ extendsClauseElement - ) + /*location*/ extendsClauseElement, + ), ); } } @@ -1126,7 +1178,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param node The ClassExpression or ClassDeclaration node. * @param extendsClauseElement The expression for the class `extends` clause. */ - function addConstructor(statements: Statement[], node: ClassExpression | ClassDeclaration, name: Identifier, extendsClauseElement: ExpressionWithTypeArguments | undefined): void { + function addConstructor( + statements: Statement[], + node: ClassExpression | ClassDeclaration, + name: Identifier, + extendsClauseElement: ExpressionWithTypeArguments | undefined, + ): void { const savedConvertedLoopState = convertedLoopState; convertedLoopState = undefined; const ancestorFacts = enterSubtree(HierarchyFacts.ConstructorExcludes, HierarchyFacts.ConstructorIncludes); @@ -1139,7 +1196,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, transformConstructorParameters(constructor, hasSynthesizedSuper), /*type*/ undefined, - transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper) + transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper), ); setTextRange(constructorFunction, constructor || node); @@ -1159,13 +1216,20 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param hasSynthesizedSuper A value indicating whether the constructor starts with a * synthesized `super` call. */ - function transformConstructorParameters(constructor: ConstructorDeclaration | undefined, hasSynthesizedSuper: boolean) { + function transformConstructorParameters( + constructor: ConstructorDeclaration | undefined, + hasSynthesizedSuper: boolean, + ) { // If the TypeScript transformer needed to synthesize a constructor for property // initializers, it would have also added a synthetic `...args` parameter and // `super` call. // If this is the case, we do not include the synthetic `...args` parameter and // will instead use the `arguments` object in ES5/3. - return visitParameterList(constructor && !hasSynthesizedSuper ? constructor.parameters : undefined, visitor, context) + return visitParameterList( + constructor && !hasSynthesizedSuper ? constructor.parameters : undefined, + visitor, + context, + ) || [] as ParameterDeclaration[]; } @@ -1198,7 +1262,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile statementOffset: number, superPath: readonly number[], superPathDepth: number, - constructor: ConstructorDeclaration & { body: FunctionBody }, + constructor: ConstructorDeclaration & { body: FunctionBody; }, isDerivedClass: boolean, hasSynthesizedSuper: boolean, isFirstStatement: boolean, @@ -1213,7 +1277,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile let firstMaterialIndex = statementOffset; while (isFirstStatement && firstMaterialIndex < superStatementIndex) { const statement = constructor.body.statements[firstMaterialIndex]; - if (!isUninitializedVariableStatement(statement) && !isUsingDeclarationStateVariableStatement(statement)) break; + if ( + !isUninitializedVariableStatement(statement) && !isUsingDeclarationStateVariableStatement(statement) + ) break; firstMaterialIndex++; } @@ -1221,7 +1287,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } // visit everything prior to the statement containing `super()`. - addRange(statementsOut, visitNodes(statementsIn, visitor, isStatement, statementOffset, leadingStatementsEnd - statementOffset)); + addRange( + statementsOut, + visitNodes(statementsIn, visitor, isStatement, statementOffset, leadingStatementsEnd - statementOffset), + ); const superStatement = superStatementIndex >= 0 ? statementsIn[superStatementIndex] : undefined; if (superStatement && isTryStatement(superStatement)) { @@ -1237,7 +1306,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile constructor, isDerivedClass, hasSynthesizedSuper, - isFirstStatement); + isFirstStatement, + ); const tryBlockStatementsArray = factory.createNodeArray(tryBlockStatements); setTextRange(tryBlockStatementsArray, superStatement.tryBlock.statements); @@ -1246,7 +1316,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile superStatement, factory.updateBlock(superStatement.tryBlock, tryBlockStatements), visitNode(superStatement.catchClause, visitor, isCatchClause), - visitNode(superStatement.finallyBlock, visitor, isBlock))); + visitNode(superStatement.finallyBlock, visitor, isBlock), + )); } else { const superCall = superStatement && getSuperCallFromStatement(superStatement); @@ -1261,9 +1332,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } if (isDerivedClass || superCallExpression) { - if (superCallExpression && - superStatementIndex === statementsIn.length - 1 && - !(constructor.body.transformFlags & TransformFlags.ContainsLexicalThis)) { + if ( + superCallExpression + && superStatementIndex === statementsIn.length - 1 + && !(constructor.body.transformFlags & TransformFlags.ContainsLexicalThis) + ) { // If the subclass constructor does *not* contain `this` and *ends* with a `super()` call, we will use the // following representation: // @@ -1359,7 +1432,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } function isUninitializedVariableStatement(node: Statement) { - return isVariableStatement(node) && every(node.declarationList.declarations, decl => isIdentifier(decl.name) && !decl.initializer); + return isVariableStatement(node) + && every(node.declarationList.declarations, decl => isIdentifier(decl.name) && !decl.initializer); } function isUsingDeclarationStateVariableStatement(node: Statement) { @@ -1369,9 +1443,18 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const initializer = varDecl.initializer; if (!isObjectLiteralExpression(initializer) || initializer.properties.length !== 3) return false; const [stackProp, errorProp, hasErrorProp] = initializer.properties; - if (!isPropertyAssignment(stackProp) || !isIdentifier(stackProp.name) || idText(stackProp.name) !== "stack" || !isArrayLiteralExpression(stackProp.initializer)) return false; - if (!isPropertyAssignment(errorProp) || !isIdentifier(errorProp.name) || idText(errorProp.name) !== "error" || !isVoidExpression(errorProp.initializer) || !isNumericLiteral(errorProp.initializer.expression)) return false; - if (!isPropertyAssignment(hasErrorProp) || !isIdentifier(hasErrorProp.name) || idText(hasErrorProp.name) !== "hasError" || hasErrorProp.initializer.kind !== SyntaxKind.FalseKeyword) return false; + if ( + !isPropertyAssignment(stackProp) || !isIdentifier(stackProp.name) || idText(stackProp.name) !== "stack" + || !isArrayLiteralExpression(stackProp.initializer) + ) return false; + if ( + !isPropertyAssignment(errorProp) || !isIdentifier(errorProp.name) || idText(errorProp.name) !== "error" + || !isVoidExpression(errorProp.initializer) || !isNumericLiteral(errorProp.initializer.expression) + ) return false; + if ( + !isPropertyAssignment(hasErrorProp) || !isIdentifier(hasErrorProp.name) + || idText(hasErrorProp.name) !== "hasError" || hasErrorProp.initializer.kind !== SyntaxKind.FalseKeyword + ) return false; return true; } @@ -1384,10 +1467,16 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param hasSynthesizedSuper A value indicating whether the constructor starts with a * synthesized `super` call. */ - function transformConstructorBody(constructor: ConstructorDeclaration & { body: FunctionBody } | undefined, node: ClassDeclaration | ClassExpression, extendsClauseElement: ExpressionWithTypeArguments | undefined, hasSynthesizedSuper: boolean) { + function transformConstructorBody( + constructor: ConstructorDeclaration & { body: FunctionBody; } | undefined, + node: ClassDeclaration | ClassExpression, + extendsClauseElement: ExpressionWithTypeArguments | undefined, + hasSynthesizedSuper: boolean, + ) { // determine whether the class is known syntactically to be a derived class (e.g. a // class that extends a value that is not syntactically known to be `null`). - const isDerivedClass = !!extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword; + const isDerivedClass = !!extendsClauseElement + && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword; // When the subclass does not have a constructor, we synthesize a *default* constructor using the following // representation: @@ -1413,7 +1502,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // In derived classes, there may be code before the necessary super() call // We'll remove pre-super statements to be tacked on after the rest of the body - const standardPrologueEnd = factory.copyStandardPrologue(constructor.body.statements, prologue, /*statementOffset*/ 0); + const standardPrologueEnd = factory.copyStandardPrologue( + constructor.body.statements, + prologue, + /*statementOffset*/ 0, + ); const superStatementIndices = findSuperStatementIndexPath(constructor.body.statements, standardPrologueEnd); if (hasSynthesizedSuper || superStatementIndices.length > 0) { hierarchyFacts |= HierarchyFacts.ConstructorWithCapturedSuper; @@ -1429,7 +1522,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile constructor, isDerivedClass, hasSynthesizedSuper, - /*isFirstStatement*/ true // NOTE: this will be recalculated inside of transformConstructorBodyWorker + /*isFirstStatement*/ true, // NOTE: this will be recalculated inside of transformConstructorBodyWorker ); // Add parameter defaults at the beginning of the output, with prologue statements @@ -1439,7 +1532,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.mergeLexicalEnvironment(prologue, endLexicalEnvironment()); if (mayReplaceThis && !isSufficientlyCoveredByReturnStatements(constructor.body)) { - statements.push(factory.createReturnStatement(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel))); + statements.push( + factory.createReturnStatement( + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + ), + ); } const body = factory.createBlock( @@ -1447,12 +1547,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createNodeArray( [ ...prologue, - ...statements - ] + ...statements, + ], ), - /*location*/ constructor.body.statements + /*location*/ constructor.body.statements, ), - /*multiLine*/ true + /*multiLine*/ true, ); setTextRange(body, constructor.body); @@ -1473,8 +1573,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile else if (statement.kind === SyntaxKind.IfStatement) { const ifStatement = statement as IfStatement; if (ifStatement.elseStatement) { - return isSufficientlyCoveredByReturnStatements(ifStatement.thenStatement) && - isSufficientlyCoveredByReturnStatements(ifStatement.elseStatement); + return isSufficientlyCoveredByReturnStatements(ifStatement.thenStatement) + && isSufficientlyCoveredByReturnStatements(ifStatement.elseStatement); } } // A block is covered if it has a last statement which is covered. @@ -1496,16 +1596,22 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return factory.createLogicalOr( factory.createLogicalAnd( factory.createStrictInequality( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), - factory.createNull() + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + factory.createNull(), ), factory.createFunctionApplyCall( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), createActualThis(), factory.createIdentifier("arguments"), - ) + ), ), - createActualThis() + createActualThis(), ); } @@ -1530,11 +1636,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.getGeneratedNameForNode(node), /*questionToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined + /*initializer*/ undefined, ), - /*location*/ node + /*location*/ node, ), - /*original*/ node + /*original*/ node, ); } else if (node.initializer) { @@ -1547,11 +1653,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile node.name, /*questionToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined + /*initializer*/ undefined, ), - /*location*/ node + /*location*/ node, ), - /*original*/ node + /*original*/ node, ); } else { @@ -1587,7 +1693,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } if (isBindingPattern(name)) { - added = insertDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer) || added; + added = insertDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer) + || added; } else if (initializer) { insertDefaultValueAssignmentForInitializer(statements, parameter, name, initializer); @@ -1605,7 +1712,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param name The name of the parameter. * @param initializer The initializer for the parameter. */ - function insertDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression | undefined): boolean { + function insertDefaultValueAssignmentForBindingPattern( + statements: Statement[], + parameter: ParameterDeclaration, + name: BindingPattern, + initializer: Expression | undefined, + ): boolean { // In cases where a binding pattern is simply '[]' or '{}', // we usually don't want to emit a var declaration; however, in the presence // of an initializer, we must emit that expression to preserve side effects. @@ -1621,12 +1733,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile visitor, context, FlattenLevel.All, - factory.getGeneratedNameForNode(parameter) - ) - ) + factory.getGeneratedNameForNode(parameter), + ), + ), ), - EmitFlags.CustomPrologue - ) + EmitFlags.CustomPrologue, + ), ); return true; } @@ -1637,11 +1749,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createExpressionStatement( factory.createAssignment( factory.getGeneratedNameForNode(parameter), - Debug.checkDefined(visitNode(initializer, visitor, isExpression)) - ) + Debug.checkDefined(visitNode(initializer, visitor, isExpression)), + ), ), - EmitFlags.CustomPrologue - ) + EmitFlags.CustomPrologue, + ), ); return true; } @@ -1656,7 +1768,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param name The name of the parameter. * @param initializer The initializer for the parameter. */ - function insertDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void { + function insertDefaultValueAssignmentForInitializer( + statements: Statement[], + parameter: ParameterDeclaration, + name: Identifier, + initializer: Expression, + ): void { initializer = Debug.checkDefined(visitNode(initializer, visitor, isExpression)); const statement = factory.createIfStatement( factory.createTypeCheck(factory.cloneNode(name), "undefined"), @@ -1668,24 +1785,35 @@ export function transformES2015(context: TransformationContext): (x: SourceFile setTextRange( factory.createAssignment( // TODO(rbuckton): Does this need to be parented? - setEmitFlags(setParent(setTextRange(factory.cloneNode(name), name), name.parent), EmitFlags.NoSourceMap), - setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer) | EmitFlags.NoComments) + setEmitFlags( + setParent(setTextRange(factory.cloneNode(name), name), name.parent), + EmitFlags.NoSourceMap, + ), + setEmitFlags( + initializer, + EmitFlags.NoSourceMap | getEmitFlags(initializer) | EmitFlags.NoComments, + ), ), - parameter + parameter, ), - EmitFlags.NoComments - ) - ) + EmitFlags.NoComments, + ), + ), ]), - parameter + parameter, ), - EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments - ) + EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps + | EmitFlags.NoComments, + ), ); startOnNewLine(statement); setTextRange(statement, parameter); - setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue | EmitFlags.NoComments); + setEmitFlags( + statement, + EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue + | EmitFlags.NoComments, + ); insertStatementAfterCustomPrologue(statements, statement); } @@ -1697,7 +1825,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * part of a constructor declaration with a * synthesized call to `super` */ - function shouldAddRestParameter(node: ParameterDeclaration | undefined, inConstructorWithSynthesizedSuper: boolean): node is ParameterDeclaration { + function shouldAddRestParameter( + node: ParameterDeclaration | undefined, + inConstructorWithSynthesizedSuper: boolean, + ): node is ParameterDeclaration { return !!(node && node.dotDotDotToken && !inConstructorWithSynthesizedSuper); } @@ -1710,7 +1841,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * part of a constructor declaration with a * synthesized call to `super` */ - function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): boolean { + function addRestParameterIfNeeded( + statements: Statement[], + node: FunctionLikeDeclaration, + inConstructorWithSynthesizedSuper: boolean, + ): boolean { const prologueStatements: Statement[] = []; const parameter = lastOrUndefined(node.parameters); if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) { @@ -1719,11 +1854,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // `declarationName` is the name of the local declaration for the parameter. // TODO(rbuckton): Does this need to be parented? - const declarationName = parameter.name.kind === SyntaxKind.Identifier ? setParent(setTextRange(factory.cloneNode(parameter.name), parameter.name), parameter.name.parent) : factory.createTempVariable(/*recordTempVariable*/ undefined); + const declarationName = parameter.name.kind === SyntaxKind.Identifier + ? setParent(setTextRange(factory.cloneNode(parameter.name), parameter.name), parameter.name.parent) + : factory.createTempVariable(/*recordTempVariable*/ undefined); setEmitFlags(declarationName, EmitFlags.NoSourceMap); // `expressionName` is the name of the parameter used in expressions. - const expressionName = parameter.name.kind === SyntaxKind.Identifier ? factory.cloneNode(parameter.name) : declarationName; + const expressionName = parameter.name.kind === SyntaxKind.Identifier ? factory.cloneNode(parameter.name) + : declarationName; const restIndex = node.parameters.length - 1; const temp = factory.createLoopVariable(); @@ -1738,14 +1876,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile declarationName, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createArrayLiteralExpression([]) - ) - ]) + factory.createArrayLiteralExpression([]), + ), + ]), ), - /*location*/ parameter + /*location*/ parameter, ), - EmitFlags.CustomPrologue - ) + EmitFlags.CustomPrologue, + ), ); // for (var _i = restIndex; _i < arguments.length; _i++) { @@ -1754,16 +1892,21 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const forStatement = factory.createForStatement( setTextRange( factory.createVariableDeclarationList([ - factory.createVariableDeclaration(temp, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(restIndex)) + factory.createVariableDeclaration( + temp, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(restIndex), + ), ]), - parameter + parameter, ), setTextRange( factory.createLessThan( temp, - factory.createPropertyAccessExpression(factory.createIdentifier("arguments"), "length") + factory.createPropertyAccessExpression(factory.createIdentifier("arguments"), "length"), ), - parameter + parameter, ), setTextRange(factory.createPostfixIncrement(temp), parameter), factory.createBlock([ @@ -1775,15 +1918,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile expressionName, restIndex === 0 ? temp - : factory.createSubtract(temp, factory.createNumericLiteral(restIndex)) + : factory.createSubtract(temp, factory.createNumericLiteral(restIndex)), ), - factory.createElementAccessExpression(factory.createIdentifier("arguments"), temp) - ) + factory.createElementAccessExpression(factory.createIdentifier("arguments"), temp), + ), ), - /*location*/ parameter - ) - ) - ]) + /*location*/ parameter, + ), + ), + ]), ); setEmitFlags(forStatement, EmitFlags.CustomPrologue); @@ -1798,13 +1941,19 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - flattenDestructuringBinding(parameter, visitor, context, FlattenLevel.All, expressionName), - ) + flattenDestructuringBinding( + parameter, + visitor, + context, + FlattenLevel.All, + expressionName, + ), + ), ), - parameter + parameter, ), - EmitFlags.CustomPrologue - ) + EmitFlags.CustomPrologue, + ), ); } @@ -1839,8 +1988,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createBinaryExpression( factory.createThis(), SyntaxKind.EqualsToken, - superExpression - ) + superExpression, + ), ); statements.push(assignSuperExpression); setCommentRange(assignSuperExpression, getOriginalNode(superExpression).parent); @@ -1852,12 +2001,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*modifiers*/ undefined, factory.createVariableDeclarationList([ factory.createVariableDeclaration( - factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*exclamationToken*/ undefined, /*type*/ undefined, - initializer - ) - ]) + initializer, + ), + ]), ); setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue); setSourceMapRange(captureThisStatement, node); @@ -1884,7 +2036,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // should be relatively safe to use. newTarget = factory.createPropertyAccessExpression( setEmitFlags(factory.createThis(), EmitFlags.NoSubstitution), - "constructor" + "constructor", ); break; @@ -1898,16 +2050,16 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createBinaryExpression( setEmitFlags(factory.createThis(), EmitFlags.NoSubstitution), SyntaxKind.InstanceOfKeyword, - factory.getLocalName(node) - ) + factory.getLocalName(node), + ), ), /*questionToken*/ undefined, factory.createPropertyAccessExpression( setEmitFlags(factory.createThis(), EmitFlags.NoSubstitution), - "constructor" + "constructor", ), /*colonToken*/ undefined, - factory.createVoidZero() + factory.createVoidZero(), ); break; @@ -1919,12 +2071,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*modifiers*/ undefined, factory.createVariableDeclarationList([ factory.createVariableDeclaration( - factory.createUniqueName("_newTarget", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_newTarget", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*exclamationToken*/ undefined, /*type*/ undefined, - newTarget - ) - ]) + newTarget, + ), + ]), ); setEmitFlags(captureNewTargetStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue); @@ -1949,14 +2104,22 @@ export function transformES2015(context: TransformationContext): (x: SourceFile break; case SyntaxKind.MethodDeclaration: - statements.push(transformClassMethodDeclarationToStatement(getClassMemberPrefix(node, member), member as MethodDeclaration, node)); + statements.push( + transformClassMethodDeclarationToStatement( + getClassMemberPrefix(node, member), + member as MethodDeclaration, + node, + ), + ); break; case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: const accessors = getAllAccessorDeclarations(node.members, member as AccessorDeclaration); if (member === accessors.firstAccessor) { - statements.push(transformAccessorsToStatement(getClassMemberPrefix(node, member), accessors, node)); + statements.push( + transformAccessorsToStatement(getClassMemberPrefix(node, member), accessors, node), + ); } break; @@ -1988,21 +2151,45 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param receiver The receiver for the member. * @param member The MethodDeclaration node. */ - function transformClassMethodDeclarationToStatement(receiver: LeftHandSideExpression, member: MethodDeclaration, container: Node) { + function transformClassMethodDeclarationToStatement( + receiver: LeftHandSideExpression, + member: MethodDeclaration, + container: Node, + ) { const commentRange = getCommentRange(member); const sourceMapRange = getSourceMapRange(member); - const memberFunction = transformFunctionLikeToExpression(member, /*location*/ member, /*name*/ undefined, container); + const memberFunction = transformFunctionLikeToExpression( + member, + /*location*/ member, + /*name*/ undefined, + container, + ); const propertyName = visitNode(member.name, visitor, isPropertyName); Debug.assert(propertyName); let e: Expression; if (!isPrivateIdentifier(propertyName) && getUseDefineForClassFields(context.getCompilerOptions())) { const name = isComputedPropertyName(propertyName) ? propertyName.expression - : isIdentifier(propertyName) ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText)) + : isIdentifier(propertyName) + ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText)) : propertyName; - e = factory.createObjectDefinePropertyCall(receiver, name, factory.createPropertyDescriptor({ value: memberFunction, enumerable: false, writable: true, configurable: true })); + e = factory.createObjectDefinePropertyCall( + receiver, + name, + factory.createPropertyDescriptor({ + value: memberFunction, + enumerable: false, + writable: true, + configurable: true, + }), + ); } else { - const memberName = createMemberAccessForPropertyName(factory, receiver, propertyName, /*location*/ member.name); + const memberName = createMemberAccessForPropertyName( + factory, + receiver, + propertyName, + /*location*/ member.name, + ); e = factory.createAssignment(memberName, memberFunction); } setEmitFlags(memberFunction, EmitFlags.NoComments); @@ -2025,8 +2212,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param receiver The receiver for the member. * @param accessors The set of related get/set accessors. */ - function transformAccessorsToStatement(receiver: LeftHandSideExpression, accessors: AllAccessorDeclarations, container: Node): Statement { - const statement = factory.createExpressionStatement(transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false)); + function transformAccessorsToStatement( + receiver: LeftHandSideExpression, + accessors: AllAccessorDeclarations, + container: Node, + ): Statement { + const statement = factory.createExpressionStatement( + transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false), + ); // The location for the statement is used to emit source maps only. // No comments should be emitted for this statement to align with the // old emitter. @@ -2041,7 +2234,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * * @param receiver The receiver for the member. */ - function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations, container: Node, startsOnNewLine: boolean): Expression { + function transformAccessorsToExpression( + receiver: LeftHandSideExpression, + { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations, + container: Node, + startsOnNewLine: boolean, + ): Expression { // To align with source maps in the old emitter, the receiver and property name // arguments are both mapped contiguously to the accessor name. // TODO(rbuckton): Does this need to be parented? @@ -2052,7 +2250,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const visitedAccessorName = visitNode(firstAccessor.name, visitor, isPropertyName); Debug.assert(visitedAccessorName); if (isPrivateIdentifier(visitedAccessorName)) { - return Debug.failBadSyntaxKind(visitedAccessorName, "Encountered unhandled private identifier while transforming ES2015."); + return Debug.failBadSyntaxKind( + visitedAccessorName, + "Encountered unhandled private identifier while transforming ES2015.", + ); } const propertyName = createExpressionForPropertyName(factory, visitedAccessorName); setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoLeadingSourceMap); @@ -2060,7 +2261,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const properties: ObjectLiteralElementLike[] = []; if (getAccessor) { - const getterFunction = transformFunctionLikeToExpression(getAccessor, /*location*/ undefined, /*name*/ undefined, container); + const getterFunction = transformFunctionLikeToExpression( + getAccessor, + /*location*/ undefined, + /*name*/ undefined, + container, + ); setSourceMapRange(getterFunction, getSourceMapRange(getAccessor)); setEmitFlags(getterFunction, EmitFlags.NoLeadingComments); const getter = factory.createPropertyAssignment("get", getterFunction); @@ -2069,7 +2275,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } if (setAccessor) { - const setterFunction = transformFunctionLikeToExpression(setAccessor, /*location*/ undefined, /*name*/ undefined, container); + const setterFunction = transformFunctionLikeToExpression( + setAccessor, + /*location*/ undefined, + /*name*/ undefined, + container, + ); setSourceMapRange(setterFunction, getSourceMapRange(setAccessor)); setEmitFlags(setterFunction, EmitFlags.NoLeadingComments); const setter = factory.createPropertyAssignment("set", setterFunction); @@ -2078,8 +2289,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } properties.push( - factory.createPropertyAssignment("enumerable", getAccessor || setAccessor ? factory.createFalse() : factory.createTrue()), - factory.createPropertyAssignment("configurable", factory.createTrue()) + factory.createPropertyAssignment( + "enumerable", + getAccessor || setAccessor ? factory.createFalse() : factory.createTrue(), + ), + factory.createPropertyAssignment("configurable", factory.createTrue()), ); const call = factory.createCallExpression( @@ -2088,8 +2302,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile [ target, propertyName, - factory.createObjectLiteralExpression(properties, /*multiLine*/ true) - ] + factory.createObjectLiteralExpression(properties, /*multiLine*/ true), + ], ); if (startsOnNewLine) { startOnNewLine(call); @@ -2104,7 +2318,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param node An ArrowFunction node. */ function visitArrowFunction(node: ArrowFunction) { - if (node.transformFlags & TransformFlags.ContainsLexicalThis && !(hierarchyFacts & HierarchyFacts.StaticInitializer)) { + if ( + node.transformFlags & TransformFlags.ContainsLexicalThis + && !(hierarchyFacts & HierarchyFacts.StaticInitializer) + ) { hierarchyFacts |= HierarchyFacts.CapturedLexicalThis; } @@ -2118,7 +2335,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - transformFunctionBody(node) + transformFunctionBody(node), ); setTextRange(func, node); setOriginalNode(func, node); @@ -2159,7 +2376,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, parameters, /*type*/ undefined, - body + body, ); } @@ -2188,7 +2405,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, parameters, /*type*/ undefined, - body + body, ); } @@ -2199,15 +2416,26 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param location The source-map location for the new FunctionExpression. * @param name The name of the new FunctionExpression. */ - function transformFunctionLikeToExpression(node: FunctionLikeDeclaration, location: TextRange | undefined, name: Identifier | undefined, container: Node | undefined): FunctionExpression { + function transformFunctionLikeToExpression( + node: FunctionLikeDeclaration, + location: TextRange | undefined, + name: Identifier | undefined, + container: Node | undefined, + ): FunctionExpression { const savedConvertedLoopState = convertedLoopState; convertedLoopState = undefined; const ancestorFacts = container && isClassLike(container) && !isStatic(node) - ? enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes | HierarchyFacts.NonStaticClassElement) + ? enterSubtree( + HierarchyFacts.FunctionExcludes, + HierarchyFacts.FunctionIncludes | HierarchyFacts.NonStaticClassElement, + ) : enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes); const parameters = visitParameterList(node.parameters, visitor, context); const body = transformFunctionBody(node); - if (hierarchyFacts & HierarchyFacts.NewTarget && !name && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) { + if ( + hierarchyFacts & HierarchyFacts.NewTarget && !name + && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression) + ) { name = factory.getGeneratedNameForNode(node); } @@ -2222,11 +2450,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, parameters, /*type*/ undefined, - body + body, ), - location + location, ), - /*original*/ node + /*original*/ node, ); } @@ -2251,12 +2479,25 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // ensureUseStrict is false because no new prologue-directive should be added. // addStandardPrologue will put already-existing directives at the beginning of the target statement-array statementOffset = factory.copyStandardPrologue(body.statements, prologue, 0, /*ensureUseStrict*/ false); - statementOffset = factory.copyCustomPrologue(body.statements, statements, statementOffset, visitor, isHoistedFunction); - statementOffset = factory.copyCustomPrologue(body.statements, statements, statementOffset, visitor, isHoistedVariableStatement); + statementOffset = factory.copyCustomPrologue( + body.statements, + statements, + statementOffset, + visitor, + isHoistedFunction, + ); + statementOffset = factory.copyCustomPrologue( + body.statements, + statements, + statementOffset, + visitor, + isHoistedVariableStatement, + ); } multiLine = addDefaultValueAssignmentsIfNeeded(statements, node) || multiLine; - multiLine = addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false) || multiLine; + multiLine = addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false) + || multiLine; if (isBlock(body)) { // addCustomPrologue puts already-existing directives at the beginning of the target statement-array @@ -2293,7 +2534,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const returnStatement = factory.createReturnStatement(expression); setTextRange(returnStatement, body); moveSyntheticComments(returnStatement, body); - setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments); + setEmitFlags( + returnStatement, + EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments, + ); statements.push(returnStatement); // To align with the source map emit for the old emitter, we set a custom @@ -2316,7 +2560,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return body; } - const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), statementsLocation), multiLine); + const block = factory.createBlock( + setTextRange(factory.createNodeArray(statements), statementsLocation), + multiLine, + ); setTextRange(block, node.body); if (!multiLine && singleLine) { setEmitFlags(block, EmitFlags.SingleLine); @@ -2336,7 +2583,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return visitEachChild(node, visitor, context); } const ancestorFacts = hierarchyFacts & HierarchyFacts.IterationStatement - ? enterSubtree(HierarchyFacts.IterationStatementBlockExcludes, HierarchyFacts.IterationStatementBlockIncludes) + ? enterSubtree( + HierarchyFacts.IterationStatementBlockExcludes, + HierarchyFacts.IterationStatementBlockIncludes, + ) : enterSubtree(HierarchyFacts.BlockExcludes, HierarchyFacts.BlockIncludes); const updated = visitEachChild(node, visitor, context); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); @@ -2359,7 +2609,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the * expression of an `ExpressionStatement`). */ - function visitParenthesizedExpression(node: ParenthesizedExpression, expressionResultIsUnused: boolean): ParenthesizedExpression { + function visitParenthesizedExpression( + node: ParenthesizedExpression, + expressionResultIsUnused: boolean, + ): ParenthesizedExpression { return visitEachChild(node, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, context); } @@ -2378,14 +2631,21 @@ export function transformES2015(context: TransformationContext): (x: SourceFile visitor, context, FlattenLevel.All, - !expressionResultIsUnused); + !expressionResultIsUnused, + ); } if (node.operatorToken.kind === SyntaxKind.CommaToken) { return factory.updateBinaryExpression( node, Debug.checkDefined(visitNode(node.left, visitorWithUnusedExpressionResult, isExpression)), node.operatorToken, - Debug.checkDefined(visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression)) + Debug.checkDefined( + visitNode( + node.right, + expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, + isExpression, + ), + ), ); } return visitEachChild(node, visitor, context); @@ -2402,7 +2662,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile let result: Expression[] | undefined; for (let i = 0; i < node.elements.length; i++) { const element = node.elements[i]; - const visited = visitNode(element, i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, isExpression); + const visited = visitNode( + element, + i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, + isExpression, + ); if (result || visited !== element) { result ||= node.elements.slice(0, i); Debug.assert(visited); @@ -2416,13 +2680,21 @@ export function transformES2015(context: TransformationContext): (x: SourceFile function isVariableStatementOfTypeScriptClassWrapper(node: VariableStatement) { return node.declarationList.declarations.length === 1 && !!node.declarationList.declarations[0].initializer - && !!(getInternalEmitFlags(node.declarationList.declarations[0].initializer) & InternalEmitFlags.TypeScriptClassWrapper); + && !!(getInternalEmitFlags(node.declarationList.declarations[0].initializer) + & InternalEmitFlags.TypeScriptClassWrapper); } function visitVariableStatement(node: VariableStatement): Statement | undefined { - const ancestorFacts = enterSubtree(HierarchyFacts.None, hasSyntacticModifier(node, ModifierFlags.Export) ? HierarchyFacts.ExportedVariableStatement : HierarchyFacts.None); + const ancestorFacts = enterSubtree( + HierarchyFacts.None, + hasSyntacticModifier(node, ModifierFlags.Export) ? HierarchyFacts.ExportedVariableStatement + : HierarchyFacts.None, + ); let updated: Statement | undefined; - if (convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0 && !isVariableStatementOfTypeScriptClassWrapper(node)) { + if ( + convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0 + && !isVariableStatementOfTypeScriptClassWrapper(node) + ) { // we are inside a converted loop - hoist variable declarations let assignments: Expression[] | undefined; for (const decl of node.declarationList.declarations) { @@ -2434,11 +2706,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile decl, visitor, context, - FlattenLevel.All + FlattenLevel.All, ); } else { - assignment = factory.createBinaryExpression(decl.name, SyntaxKind.EqualsToken, Debug.checkDefined(visitNode(decl.initializer, visitor, isExpression))); + assignment = factory.createBinaryExpression( + decl.name, + SyntaxKind.EqualsToken, + Debug.checkDefined(visitNode(decl.initializer, visitor, isExpression)), + ); setTextRange(assignment, decl); } @@ -2472,9 +2748,13 @@ export function transformES2015(context: TransformationContext): (x: SourceFile enableSubstitutionsForBlockScopedBindings(); } - const declarations = visitNodes(node.declarations, node.flags & NodeFlags.Let - ? visitVariableDeclarationInLetDeclarationList - : visitVariableDeclaration, isVariableDeclaration); + const declarations = visitNodes( + node.declarations, + node.flags & NodeFlags.Let + ? visitVariableDeclarationInLetDeclarationList + : visitVariableDeclaration, + isVariableDeclaration, + ); const declarationList = factory.createVariableDeclarationList(declarations); setOriginalNode(declarationList, node); @@ -2483,8 +2763,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // If the first or last declaration is a binding pattern, we need to modify // the source map range for the declaration list. - if (node.transformFlags & TransformFlags.ContainsBindingPattern - && (isBindingPattern(node.declarations[0].name) || isBindingPattern(last(node.declarations).name))) { + if ( + node.transformFlags & TransformFlags.ContainsBindingPattern + && (isBindingPattern(node.declarations[0].name) || isBindingPattern(last(node.declarations).name)) + ) { setSourceMapRange(declarationList, getRangeUnion(declarations)); } @@ -2554,14 +2836,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const flags = resolver.getNodeCheckFlags(node); const isCapturedInFunction = flags & NodeCheckFlags.CapturedBlockScopedBinding; const isDeclaredInLoop = flags & NodeCheckFlags.BlockScopedBindingInLoop; - const emittedAsTopLevel = - (hierarchyFacts & HierarchyFacts.TopLevel) !== 0 + const emittedAsTopLevel = (hierarchyFacts & HierarchyFacts.TopLevel) !== 0 || (isCapturedInFunction && isDeclaredInLoop && (hierarchyFacts & HierarchyFacts.IterationStatementBlock) !== 0); - const emitExplicitInitializer = - !emittedAsTopLevel + const emitExplicitInitializer = !emittedAsTopLevel && (hierarchyFacts & HierarchyFacts.ForInOrForOfStatement) === 0 && (!resolver.isDeclarationWithCollidingName(node) || (isDeclaredInLoop @@ -2586,7 +2866,13 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } if (!node.initializer && shouldEmitExplicitInitializerForLetDeclaration(node)) { - return factory.updateVariableDeclaration(node, node.name, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createVoidZero()); + return factory.updateVariableDeclaration( + node, + node.name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createVoidZero(), + ); } return visitEachChild(node, visitor, context); @@ -2607,7 +2893,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile context, FlattenLevel.All, /*rval*/ undefined, - (ancestorFacts & HierarchyFacts.ExportedVariableStatement) !== 0 + (ancestorFacts & HierarchyFacts.ExportedVariableStatement) !== 0, ); } else { @@ -2633,7 +2919,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const statement = unwrapInnermostStatementOfLabel(node, convertedLoopState && recordLabel); return isIterationStatement(statement, /*lookInLabeledStatements*/ false) ? visitIterationStatement(statement, /*outermostLabeledStatement*/ node) - : factory.restoreEnclosingLabel(Debug.checkDefined(visitNode(statement, visitor, isStatement, factory.liftToBlock)), node, convertedLoopState && resetLabel); + : factory.restoreEnclosingLabel( + Debug.checkDefined(visitNode(statement, visitor, isStatement, factory.liftToBlock)), + node, + convertedLoopState && resetLabel, + ); } function visitIterationStatement(node: IterationStatement, outermostLabeledStatement: LabeledStatement) { @@ -2650,19 +2940,34 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } } - function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: T, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter) { + function visitIterationStatementWithFacts( + excludeFacts: HierarchyFacts, + includeFacts: HierarchyFacts, + node: T, + outermostLabeledStatement: LabeledStatement | undefined, + convert?: LoopConverter, + ) { const ancestorFacts = enterSubtree(excludeFacts, includeFacts); - const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, ancestorFacts, convert); + const updated = convertIterationStatementBodyIfNecessary( + node, + outermostLabeledStatement, + ancestorFacts, + convert, + ); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); return updated; } - function visitDoOrWhileStatement(node: DoStatement | WhileStatement, outermostLabeledStatement: LabeledStatement | undefined) { + function visitDoOrWhileStatement( + node: DoStatement | WhileStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ) { return visitIterationStatementWithFacts( HierarchyFacts.DoOrWhileStatementExcludes, HierarchyFacts.DoOrWhileStatementIncludes, node, - outermostLabeledStatement); + outermostLabeledStatement, + ); } function visitForStatement(node: ForStatement, outermostLabeledStatement: LabeledStatement | undefined) { @@ -2670,7 +2975,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile HierarchyFacts.ForStatementExcludes, HierarchyFacts.ForStatementIncludes, node, - outermostLabeledStatement); + outermostLabeledStatement, + ); } function visitEachChildOfForStatement(node: ForStatement) { @@ -2679,7 +2985,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile visitNode(node.initializer, visitorWithUnusedExpressionResult, isForInitializer), visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, visitorWithUnusedExpressionResult, isExpression), - Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock)) + Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock)), ); } @@ -2688,19 +2994,28 @@ export function transformES2015(context: TransformationContext): (x: SourceFile HierarchyFacts.ForInOrForOfStatementExcludes, HierarchyFacts.ForInOrForOfStatementIncludes, node, - outermostLabeledStatement); + outermostLabeledStatement, + ); } - function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult { + function visitForOfStatement( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ): VisitResult { return visitIterationStatementWithFacts( HierarchyFacts.ForInOrForOfStatementExcludes, HierarchyFacts.ForInOrForOfStatementIncludes, node, outermostLabeledStatement, - compilerOptions.downlevelIteration ? convertForOfStatementForIterable : convertForOfStatementForArray); + compilerOptions.downlevelIteration ? convertForOfStatementForIterable : convertForOfStatementForArray, + ); } - function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[] | undefined) { + function convertForOfStatementHead( + node: ForOfStatement, + boundValue: Expression, + convertedLoopBodyStatements: Statement[] | undefined, + ) { const statements: Statement[] = []; const initializer = node.initializer; if (isVariableDeclarationList(initializer)) { @@ -2717,10 +3032,13 @@ export function transformES2015(context: TransformationContext): (x: SourceFile visitor, context, FlattenLevel.All, - boundValue + boundValue, ); - const declarationList = setTextRange(factory.createVariableDeclarationList(declarations), node.initializer); + const declarationList = setTextRange( + factory.createVariableDeclarationList(declarations), + node.initializer, + ); setOriginalNode(declarationList, node.initializer); // Adjust the source map range for the first declaration to align with the old @@ -2730,8 +3048,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile statements.push( factory.createVariableStatement( /*modifiers*/ undefined, - declarationList - ) + declarationList, + ), ); } else { @@ -2745,19 +3063,20 @@ export function transformES2015(context: TransformationContext): (x: SourceFile setTextRange( factory.createVariableDeclarationList([ factory.createVariableDeclaration( - firstOriginalDeclaration ? firstOriginalDeclaration.name : factory.createTempVariable(/*recordTempVariable*/ undefined), + firstOriginalDeclaration ? firstOriginalDeclaration.name + : factory.createTempVariable(/*recordTempVariable*/ undefined), /*exclamationToken*/ undefined, /*type*/ undefined, - boundValue - ) + boundValue, + ), ]), - moveRangePos(initializer, -1) + moveRangePos(initializer, -1), ), - initializer - ) + initializer, + ), ), - moveRangeEnd(initializer, -1) - ) + moveRangeEnd(initializer, -1), + ), ); } } @@ -2766,11 +3085,22 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // evaluated on every iteration. const assignment = factory.createAssignment(initializer, boundValue); if (isDestructuringAssignment(assignment)) { - statements.push(factory.createExpressionStatement(visitBinaryExpression(assignment, /*expressionResultIsUnused*/ true))); + statements.push( + factory.createExpressionStatement( + visitBinaryExpression(assignment, /*expressionResultIsUnused*/ true), + ), + ); } else { setTextRangeEnd(assignment, initializer.end); - statements.push(setTextRange(factory.createExpressionStatement(Debug.checkDefined(visitNode(assignment, visitor, isExpression))), moveRangeEnd(initializer, -1))); + statements.push( + setTextRange( + factory.createExpressionStatement( + Debug.checkDefined(visitNode(assignment, visitor, isExpression)), + ), + moveRangeEnd(initializer, -1), + ), + ); } } @@ -2781,7 +3111,13 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const statement = visitNode(node.statement, visitor, isStatement, factory.liftToBlock); Debug.assert(statement); if (isBlock(statement)) { - return factory.updateBlock(statement, setTextRange(factory.createNodeArray(concatenate(statements, statement.statements)), statement.statements)); + return factory.updateBlock( + statement, + setTextRange( + factory.createNodeArray(concatenate(statements, statement.statements)), + statement.statements, + ), + ); } else { statements.push(statement); @@ -2794,13 +3130,17 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return setEmitFlags( factory.createBlock( factory.createNodeArray(statements), - /*multiLine*/ true + /*multiLine*/ true, ), - EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps + EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps, ); } - function convertForOfStatementForArray(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined): Statement { + function convertForOfStatementForArray( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement | undefined, + convertedLoopBodyStatements: Statement[] | undefined, + ): Statement { // The following ES6 code: // // for (let v of expr) { } @@ -2831,7 +3171,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // // we don't want to emit a temporary variable for the RHS, just use it directly. const counter = factory.createLoopVariable(); - const rhsReference = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined); + const rhsReference = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) + : factory.createTempVariable(/*recordTempVariable*/ undefined); // The old emitter does not emit source maps for the expression setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression)); @@ -2841,28 +3182,44 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*initializer*/ setEmitFlags( setTextRange( factory.createVariableDeclarationList([ - setTextRange(factory.createVariableDeclaration(counter, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(0)), moveRangePos(node.expression, -1)), - setTextRange(factory.createVariableDeclaration(rhsReference, /*exclamationToken*/ undefined, /*type*/ undefined, expression), node.expression) + setTextRange( + factory.createVariableDeclaration( + counter, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createNumericLiteral(0), + ), + moveRangePos(node.expression, -1), + ), + setTextRange( + factory.createVariableDeclaration( + rhsReference, + /*exclamationToken*/ undefined, + /*type*/ undefined, + expression, + ), + node.expression, + ), ]), - node.expression + node.expression, ), - EmitFlags.NoHoisting + EmitFlags.NoHoisting, ), /*condition*/ setTextRange( factory.createLessThan( counter, - factory.createPropertyAccessExpression(rhsReference, "length") + factory.createPropertyAccessExpression(rhsReference, "length"), ), - node.expression + node.expression, ), /*incrementor*/ setTextRange(factory.createPostfixIncrement(counter), node.expression), /*statement*/ convertForOfStatementHead( node, factory.createElementAccessExpression(rhsReference, counter), - convertedLoopBodyStatements - ) + convertedLoopBodyStatements, + ), ), - /*location*/ node + /*location*/ node, ); // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. @@ -2871,16 +3228,27 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return factory.restoreEnclosingLabel(forStatement, outermostLabeledStatement, convertedLoopState && resetLabel); } - function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts): Statement { + function convertForOfStatementForIterable( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement | undefined, + convertedLoopBodyStatements: Statement[] | undefined, + ancestorFacts: HierarchyFacts, + ): Statement { const expression = visitNode(node.expression, visitor, isExpression); Debug.assert(expression); - const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined); - const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) : factory.createTempVariable(/*recordTempVariable*/ undefined); + const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) + : factory.createTempVariable(/*recordTempVariable*/ undefined); + const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) + : factory.createTempVariable(/*recordTempVariable*/ undefined); const errorRecord = factory.createUniqueName("e"); const catchVariable = factory.getGeneratedNameForNode(errorRecord); const returnMethod = factory.createTempVariable(/*recordTempVariable*/ undefined); const values = setTextRange(emitHelpers().createValuesHelper(expression), node.expression); - const next = factory.createCallExpression(factory.createPropertyAccessExpression(iterator, "next"), /*typeArguments*/ undefined, []); + const next = factory.createCallExpression( + factory.createPropertyAccessExpression(iterator, "next"), + /*typeArguments*/ undefined, + [], + ); hoistVariableDeclaration(errorRecord); hoistVariableDeclaration(returnMethod); @@ -2896,24 +3264,37 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*initializer*/ setEmitFlags( setTextRange( factory.createVariableDeclarationList([ - setTextRange(factory.createVariableDeclaration(iterator, /*exclamationToken*/ undefined, /*type*/ undefined, initializer), node.expression), - factory.createVariableDeclaration(result, /*exclamationToken*/ undefined, /*type*/ undefined, next) + setTextRange( + factory.createVariableDeclaration( + iterator, + /*exclamationToken*/ undefined, + /*type*/ undefined, + initializer, + ), + node.expression, + ), + factory.createVariableDeclaration( + result, + /*exclamationToken*/ undefined, + /*type*/ undefined, + next, + ), ]), - node.expression + node.expression, ), - EmitFlags.NoHoisting + EmitFlags.NoHoisting, ), /*condition*/ factory.createLogicalNot(factory.createPropertyAccessExpression(result, "done")), /*incrementor*/ factory.createAssignment(result, next), /*statement*/ convertForOfStatementHead( node, factory.createPropertyAccessExpression(result, "value"), - convertedLoopBodyStatements - ) + convertedLoopBodyStatements, + ), ), - /*location*/ node + /*location*/ node, ), - EmitFlags.NoTokenTrailingSourceMaps + EmitFlags.NoTokenTrailingSourceMaps, ); return factory.createTryStatement( @@ -2921,23 +3302,24 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.restoreEnclosingLabel( forStatement, outermostLabeledStatement, - convertedLoopState && resetLabel - ) + convertedLoopState && resetLabel, + ), ]), - factory.createCatchClause(factory.createVariableDeclaration(catchVariable), + factory.createCatchClause( + factory.createVariableDeclaration(catchVariable), setEmitFlags( factory.createBlock([ factory.createExpressionStatement( factory.createAssignment( errorRecord, factory.createObjectLiteralExpression([ - factory.createPropertyAssignment("error", catchVariable) - ]) - ) - ) + factory.createPropertyAssignment("error", catchVariable), + ]), + ), + ), ]), - EmitFlags.SingleLine - ) + EmitFlags.SingleLine, + ), ), factory.createBlock([ factory.createTryStatement( @@ -2948,19 +3330,19 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createLogicalAnd( result, factory.createLogicalNot( - factory.createPropertyAccessExpression(result, "done") - ) + factory.createPropertyAccessExpression(result, "done"), + ), ), factory.createAssignment( returnMethod, - factory.createPropertyAccessExpression(iterator, "return") - ) + factory.createPropertyAccessExpression(iterator, "return"), + ), ), factory.createExpressionStatement( - factory.createFunctionCallCall(returnMethod, iterator, []) - ) + factory.createFunctionCallCall(returnMethod, iterator, []), + ), ), - EmitFlags.SingleLine + EmitFlags.SingleLine, ), ]), /*catchClause*/ undefined, @@ -2970,16 +3352,16 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createIfStatement( errorRecord, factory.createThrowStatement( - factory.createPropertyAccessExpression(errorRecord, "error") - ) + factory.createPropertyAccessExpression(errorRecord, "error"), + ), ), - EmitFlags.SingleLine - ) + EmitFlags.SingleLine, + ), ]), - EmitFlags.SingleLine - ) - ) - ]) + EmitFlags.SingleLine, + ), + ), + ]), ); } @@ -2996,9 +3378,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile let numInitialProperties = -1, hasComputed = false; for (let i = 0; i < properties.length; i++) { const property = properties[i]; - if ((property.transformFlags & TransformFlags.ContainsYield && - hierarchyFacts & HierarchyFacts.AsyncFunctionBody) - || (hasComputed = Debug.checkDefined(property.name).kind === SyntaxKind.ComputedPropertyName)) { + if ( + (property.transformFlags & TransformFlags.ContainsYield + && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) + || (hasComputed = Debug.checkDefined(property.name).kind === SyntaxKind.ComputedPropertyName) + ) { numInitialProperties = i; break; } @@ -3019,10 +3403,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile setEmitFlags( factory.createObjectLiteralExpression( visitNodes(properties, visitor, isObjectLiteralElementLike, 0, numInitialProperties), - node.multiLine + node.multiLine, ), - hasComputed ? EmitFlags.Indented : 0 - ) + hasComputed ? EmitFlags.Indented : 0, + ), ); if (node.multiLine) { @@ -3035,7 +3419,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // We need to clone the temporary identifier so that we can write it on a // new line - expressions.push(node.multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp); + expressions.push( + node.multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp, + ); return factory.inlineExpressions(expressions); } @@ -3055,15 +3441,21 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsCapturedBlockScopeBinding) !== 0; } - function shouldConvertInitializerOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleInitializer { + function shouldConvertInitializerOfForStatement( + node: IterationStatement, + ): node is ForStatementWithConvertibleInitializer { return isForStatement(node) && !!node.initializer && shouldConvertPartOfIterationStatement(node.initializer); } - function shouldConvertConditionOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleCondition { + function shouldConvertConditionOfForStatement( + node: IterationStatement, + ): node is ForStatementWithConvertibleCondition { return isForStatement(node) && !!node.condition && shouldConvertPartOfIterationStatement(node.condition); } - function shouldConvertIncrementorOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleIncrementor { + function shouldConvertIncrementorOfForStatement( + node: IterationStatement, + ): node is ForStatementWithConvertibleIncrementor { return isForStatement(node) && !!node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor); } @@ -3079,7 +3471,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /** * Records constituents of name for the given variable to be hoisted in the outer scope. */ - function hoistVariableDeclarationDeclaredInConvertedLoop(state: ConvertedLoopState, node: VariableDeclaration): void { + function hoistVariableDeclarationDeclaredInConvertedLoop( + state: ConvertedLoopState, + node: VariableDeclaration, + ): void { if (!state.hoistedLocalVariables) { state.hoistedLocalVariables = []; } @@ -3100,7 +3495,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } } - function convertIterationStatementBodyIfNecessary(node: T, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convert?: LoopConverter): VisitResult { + function convertIterationStatementBodyIfNecessary( + node: T, + outermostLabeledStatement: LabeledStatement | undefined, + ancestorFacts: HierarchyFacts, + convert?: LoopConverter, + ): VisitResult { if (!shouldConvertIterationStatement(node)) { let saveAllowedNonLabeledJumps: Jump | undefined; if (convertedLoopState) { @@ -3115,7 +3515,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile : factory.restoreEnclosingLabel( isForStatement(node) ? visitEachChildOfForStatement(node) : visitEachChild(node, visitor, context), outermostLabeledStatement, - convertedLoopState && resetLabel); + convertedLoopState && resetLabel, + ); if (convertedLoopState) { convertedLoopState.allowedNonLabeledJumps = saveAllowedNonLabeledJumps; @@ -3129,8 +3530,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const outerConvertedLoopState = convertedLoopState; convertedLoopState = currentState; - const initializerFunction = shouldConvertInitializerOfForStatement(node) ? createFunctionForInitializerOfForStatement(node, currentState) : undefined; - const bodyFunction = shouldConvertBodyOfIterationStatement(node) ? createFunctionForBodyOfIterationStatement(node, currentState, outerConvertedLoopState) : undefined; + const initializerFunction = shouldConvertInitializerOfForStatement(node) + ? createFunctionForInitializerOfForStatement(node, currentState) : undefined; + const bodyFunction = shouldConvertBodyOfIterationStatement(node) + ? createFunctionForBodyOfIterationStatement(node, currentState, outerConvertedLoopState) : undefined; convertedLoopState = outerConvertedLoopState; @@ -3140,7 +3543,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile addExtraDeclarationsForConvertedLoop(statements, currentState, outerConvertedLoopState); if (initializerFunction) { - statements.push(generateCallToConvertedLoopInitializer(initializerFunction.functionName, initializerFunction.containsYield)); + statements.push( + generateCallToConvertedLoopInitializer( + initializerFunction.functionName, + initializerFunction.containsYield, + ), + ); } let loop: Statement; @@ -3149,12 +3557,24 @@ export function transformES2015(context: TransformationContext): (x: SourceFile loop = convert(node, outermostLabeledStatement, bodyFunction.part, ancestorFacts); } else { - const clone = convertIterationStatementCore(node, initializerFunction, factory.createBlock(bodyFunction.part, /*multiLine*/ true)); - loop = factory.restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel); + const clone = convertIterationStatementCore( + node, + initializerFunction, + factory.createBlock(bodyFunction.part, /*multiLine*/ true), + ); + loop = factory.restoreEnclosingLabel( + clone, + outermostLabeledStatement, + convertedLoopState && resetLabel, + ); } } else { - const clone = convertIterationStatementCore(node, initializerFunction, Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock))); + const clone = convertIterationStatementCore( + node, + initializerFunction, + Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock)), + ); loop = factory.restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel); } @@ -3162,26 +3582,49 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return statements; } - function convertIterationStatementCore(node: IterationStatement, initializerFunction: IterationStatementPartFunction | undefined, convertedLoopBody: Statement) { + function convertIterationStatementCore( + node: IterationStatement, + initializerFunction: IterationStatementPartFunction | undefined, + convertedLoopBody: Statement, + ) { switch (node.kind) { - case SyntaxKind.ForStatement: return convertForStatement(node as ForStatement, initializerFunction, convertedLoopBody); - case SyntaxKind.ForInStatement: return convertForInStatement(node as ForInStatement, convertedLoopBody); - case SyntaxKind.ForOfStatement: return convertForOfStatement(node as ForOfStatement, convertedLoopBody); - case SyntaxKind.DoStatement: return convertDoStatement(node as DoStatement, convertedLoopBody); - case SyntaxKind.WhileStatement: return convertWhileStatement(node as WhileStatement, convertedLoopBody); - default: return Debug.failBadSyntaxKind(node, "IterationStatement expected"); + case SyntaxKind.ForStatement: + return convertForStatement(node as ForStatement, initializerFunction, convertedLoopBody); + case SyntaxKind.ForInStatement: + return convertForInStatement(node as ForInStatement, convertedLoopBody); + case SyntaxKind.ForOfStatement: + return convertForOfStatement(node as ForOfStatement, convertedLoopBody); + case SyntaxKind.DoStatement: + return convertDoStatement(node as DoStatement, convertedLoopBody); + case SyntaxKind.WhileStatement: + return convertWhileStatement(node as WhileStatement, convertedLoopBody); + default: + return Debug.failBadSyntaxKind(node, "IterationStatement expected"); } } - function convertForStatement(node: ForStatement, initializerFunction: IterationStatementPartFunction | undefined, convertedLoopBody: Statement) { + function convertForStatement( + node: ForStatement, + initializerFunction: IterationStatementPartFunction | undefined, + convertedLoopBody: Statement, + ) { const shouldConvertCondition = node.condition && shouldConvertPartOfIterationStatement(node.condition); - const shouldConvertIncrementor = shouldConvertCondition || node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor); + const shouldConvertIncrementor = shouldConvertCondition + || node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor); return factory.updateForStatement( node, - visitNode(initializerFunction ? initializerFunction.part : node.initializer, visitorWithUnusedExpressionResult, isForInitializer), + visitNode( + initializerFunction ? initializerFunction.part : node.initializer, + visitorWithUnusedExpressionResult, + isForInitializer, + ), visitNode(shouldConvertCondition ? undefined : node.condition, visitor, isExpression), - visitNode(shouldConvertIncrementor ? undefined : node.incrementor, visitorWithUnusedExpressionResult, isExpression), - convertedLoopBody + visitNode( + shouldConvertIncrementor ? undefined : node.incrementor, + visitorWithUnusedExpressionResult, + isExpression, + ), + convertedLoopBody, ); } @@ -3191,7 +3634,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*awaitModifier*/ undefined, Debug.checkDefined(visitNode(node.initializer, visitor, isForInitializer)), Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), - convertedLoopBody); + convertedLoopBody, + ); } function convertForInStatement(node: ForInStatement, convertedLoopBody: Statement) { @@ -3199,21 +3643,24 @@ export function transformES2015(context: TransformationContext): (x: SourceFile node, Debug.checkDefined(visitNode(node.initializer, visitor, isForInitializer)), Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), - convertedLoopBody); + convertedLoopBody, + ); } function convertDoStatement(node: DoStatement, convertedLoopBody: Statement) { return factory.updateDoStatement( node, convertedLoopBody, - Debug.checkDefined(visitNode(node.expression, visitor, isExpression))); + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), + ); } function convertWhileStatement(node: WhileStatement, convertedLoopBody: Statement) { return factory.updateWhileStatement( node, Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), - convertedLoopBody); + convertedLoopBody, + ); } function createConvertedLoopState(node: IterationStatement) { @@ -3234,11 +3681,17 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // variables declared in the loop initializer that will be changed inside the loop const loopOutParameters: LoopOutParameter[] = []; if (loopInitializer && (getCombinedNodeFlags(loopInitializer) & NodeFlags.BlockScoped)) { - const hasCapturedBindingsInForHead = shouldConvertInitializerOfForStatement(node) || - shouldConvertConditionOfForStatement(node) || - shouldConvertIncrementorOfForStatement(node); + const hasCapturedBindingsInForHead = shouldConvertInitializerOfForStatement(node) + || shouldConvertConditionOfForStatement(node) + || shouldConvertIncrementorOfForStatement(node); for (const decl of loopInitializer.declarations) { - processLoopVariableDeclaration(node, decl, loopParameters, loopOutParameters, hasCapturedBindingsInForHead); + processLoopVariableDeclaration( + node, + decl, + loopParameters, + loopOutParameters, + hasCapturedBindingsInForHead, + ); } } @@ -3265,7 +3718,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return currentState; } - function addExtraDeclarationsForConvertedLoop(statements: Statement[], state: ConvertedLoopState, outerState: ConvertedLoopState | undefined) { + function addExtraDeclarationsForConvertedLoop( + statements: Statement[], + state: ConvertedLoopState, + outerState: ConvertedLoopState | undefined, + ) { let extraVariableDeclarations: VariableDeclaration[] | undefined; // propagate state from the inner loop to the outer loop if necessary if (state.argumentsName) { @@ -3281,8 +3738,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile state.argumentsName, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createIdentifier("arguments") - ) + factory.createIdentifier("arguments"), + ), ); } } @@ -3303,8 +3760,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile state.thisName, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createIdentifier("this") - ) + factory.createIdentifier("this"), + ), ); } } @@ -3340,14 +3797,21 @@ export function transformES2015(context: TransformationContext): (x: SourceFile if (!extraVariableDeclarations) { extraVariableDeclarations = []; } - extraVariableDeclarations.push(factory.createVariableDeclaration(state.conditionVariable, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createFalse())); + extraVariableDeclarations.push( + factory.createVariableDeclaration( + state.conditionVariable, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createFalse(), + ), + ); } // create variable statement to hold all introduced variable declarations if (extraVariableDeclarations) { statements.push(factory.createVariableStatement( /*modifiers*/ undefined, - factory.createVariableDeclarationList(extraVariableDeclarations) + factory.createVariableDeclarationList(extraVariableDeclarations), )); } } @@ -3360,7 +3824,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } function createOutVariable(p: LoopOutParameter) { - return factory.createVariableDeclaration(p.originalName, /*exclamationToken*/ undefined, /*type*/ undefined, p.outParamName); + return factory.createVariableDeclaration( + p.originalName, + /*exclamationToken*/ undefined, + /*type*/ undefined, + p.outParamName, + ); } /** @@ -3369,17 +3838,27 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * used to preserve the per-iteration environment semantics of * [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation). */ - function createFunctionForInitializerOfForStatement(node: ForStatementWithConvertibleInitializer, currentState: ConvertedLoopState): IterationStatementPartFunction { + function createFunctionForInitializerOfForStatement( + node: ForStatementWithConvertibleInitializer, + currentState: ConvertedLoopState, + ): IterationStatementPartFunction { const functionName = factory.createUniqueName("_loop_init"); const containsYield = (node.initializer.transformFlags & TransformFlags.ContainsYield) !== 0; let emitFlags = EmitFlags.None; if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis; - if (containsYield && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) emitFlags |= EmitFlags.AsyncFunctionBody; + if (containsYield && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) { + emitFlags |= EmitFlags.AsyncFunctionBody; + } const statements: Statement[] = []; statements.push(factory.createVariableStatement(/*modifiers*/ undefined, node.initializer)); - copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Initializer, CopyDirection.ToOutParameter, statements); + copyOutParameters( + currentState.loopOutParameters, + LoopOutParameterFlags.Initializer, + CopyDirection.ToOutParameter, + statements, + ); // This transforms the following ES2015 syntax: // @@ -3421,15 +3900,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile Debug.checkDefined(visitNode( factory.createBlock(statements, /*multiLine*/ true), visitor, - isBlock - )) + isBlock, + )), ), - emitFlags - ) - ) + emitFlags, + ), + ), ]), - EmitFlags.NoHoisting - ) + EmitFlags.NoHoisting, + ), ); const part = factory.createVariableDeclarationList(map(currentState.loopOutParameters, createOutVariable)); @@ -3442,7 +3921,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * preserve the per-iteration environment semantics of * [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation). */ - function createFunctionForBodyOfIterationStatement(node: IterationStatement, currentState: ConvertedLoopState, outerState: ConvertedLoopState | undefined): IterationStatementPartFunction { + function createFunctionForBodyOfIterationStatement( + node: IterationStatement, + currentState: ConvertedLoopState, + outerState: ConvertedLoopState | undefined, + ): IterationStatementPartFunction { const functionName = factory.createUniqueName("_loop"); startLexicalEnvironment(); const statement = visitNode(node.statement, visitor, isStatement, factory.liftToBlock); @@ -3492,21 +3975,30 @@ export function transformES2015(context: TransformationContext): (x: SourceFile if (node.incrementor) { statements.push(factory.createIfStatement( currentState.conditionVariable, - factory.createExpressionStatement(Debug.checkDefined(visitNode(node.incrementor, visitor, isExpression))), - factory.createExpressionStatement(factory.createAssignment(currentState.conditionVariable, factory.createTrue())) + factory.createExpressionStatement( + Debug.checkDefined(visitNode(node.incrementor, visitor, isExpression)), + ), + factory.createExpressionStatement( + factory.createAssignment(currentState.conditionVariable, factory.createTrue()), + ), )); } else { statements.push(factory.createIfStatement( factory.createLogicalNot(currentState.conditionVariable), - factory.createExpressionStatement(factory.createAssignment(currentState.conditionVariable, factory.createTrue())) + factory.createExpressionStatement( + factory.createAssignment(currentState.conditionVariable, factory.createTrue()), + ), )); } if (shouldConvertConditionOfForStatement(node)) { statements.push(factory.createIfStatement( - factory.createPrefixUnaryExpression(SyntaxKind.ExclamationToken, Debug.checkDefined(visitNode(node.condition, visitor, isExpression))), - Debug.checkDefined(visitNode(factory.createBreakStatement(), visitor, isStatement)) + factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + Debug.checkDefined(visitNode(node.condition, visitor, isExpression)), + ), + Debug.checkDefined(visitNode(factory.createBreakStatement(), visitor, isStatement)), )); } } @@ -3519,7 +4011,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile statements.push(statement); } - copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOutParameter, statements); + copyOutParameters( + currentState.loopOutParameters, + LoopOutParameterFlags.Body, + CopyDirection.ToOutParameter, + statements, + ); insertStatementsAfterStandardPrologue(statements, lexicalEnvironment); const loopBody = factory.createBlock(statements, /*multiLine*/ true); @@ -3529,7 +4026,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile let emitFlags: EmitFlags = EmitFlags.ReuseTempVariableScope; if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis; - if (containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0) emitFlags |= EmitFlags.AsyncFunctionBody; + if (containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0) { + emitFlags |= EmitFlags.AsyncFunctionBody; + } // This transforms the following ES2015 syntax (in addition to other variations): // @@ -3546,34 +4045,33 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // _loop_1(i); // } - const functionDeclaration = - factory.createVariableStatement( - /*modifiers*/ undefined, - setEmitFlags( - factory.createVariableDeclarationList( - [ - factory.createVariableDeclaration( - functionName, - /*exclamationToken*/ undefined, - /*type*/ undefined, - setEmitFlags( - factory.createFunctionExpression( - /*modifiers*/ undefined, - containsYield ? factory.createToken(SyntaxKind.AsteriskToken) : undefined, - /*name*/ undefined, - /*typeParameters*/ undefined, - currentState.loopParameters, - /*type*/ undefined, - loopBody - ), - emitFlags - ) - ) - ] - ), - EmitFlags.NoHoisting - ) - ); + const functionDeclaration = factory.createVariableStatement( + /*modifiers*/ undefined, + setEmitFlags( + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + functionName, + /*exclamationToken*/ undefined, + /*type*/ undefined, + setEmitFlags( + factory.createFunctionExpression( + /*modifiers*/ undefined, + containsYield ? factory.createToken(SyntaxKind.AsteriskToken) : undefined, + /*name*/ undefined, + /*typeParameters*/ undefined, + currentState.loopParameters, + /*type*/ undefined, + loopBody, + ), + emitFlags, + ), + ), + ], + ), + EmitFlags.NoHoisting, + ), + ); const part = generateCallToConvertedLoop(functionName, currentState, outerState, containsYield); return { functionName, containsYield, functionDeclaration, part }; @@ -3585,7 +4083,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return factory.createBinaryExpression(target, SyntaxKind.EqualsToken, source); } - function copyOutParameters(outParams: LoopOutParameter[], partFlags: LoopOutParameterFlags, copyDirection: CopyDirection, statements: Statement[]): void { + function copyOutParameters( + outParams: LoopOutParameter[], + partFlags: LoopOutParameterFlags, + copyDirection: CopyDirection, + statements: Statement[], + ): void { for (const outParam of outParams) { if (outParam.flags & partFlags) { statements.push(factory.createExpressionStatement(copyOutParameter(outParam, copyDirection))); @@ -3593,49 +4096,74 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } } - function generateCallToConvertedLoopInitializer(initFunctionExpressionName: Identifier, containsYield: boolean): Statement { + function generateCallToConvertedLoopInitializer( + initFunctionExpressionName: Identifier, + containsYield: boolean, + ): Statement { const call = factory.createCallExpression(initFunctionExpressionName, /*typeArguments*/ undefined, []); const callResult = containsYield ? factory.createYieldExpression( factory.createToken(SyntaxKind.AsteriskToken), - setEmitFlags(call, EmitFlags.Iterator) + setEmitFlags(call, EmitFlags.Iterator), ) : call; return factory.createExpressionStatement(callResult); } - function generateCallToConvertedLoop(loopFunctionExpressionName: Identifier, state: ConvertedLoopState, outerState: ConvertedLoopState | undefined, containsYield: boolean): Statement[] { - + function generateCallToConvertedLoop( + loopFunctionExpressionName: Identifier, + state: ConvertedLoopState, + outerState: ConvertedLoopState | undefined, + containsYield: boolean, + ): Statement[] { const statements: Statement[] = []; // loop is considered simple if it does not have any return statements or break\continue that transfer control outside of the loop // simple loops are emitted as just 'loop()'; // NOTE: if loop uses only 'continue' it still will be emitted as simple loop - const isSimpleLoop = - !(state.nonLocalJumps! & ~Jump.Continue) && - !state.labeledNonLocalBreaks && - !state.labeledNonLocalContinues; + const isSimpleLoop = !(state.nonLocalJumps! & ~Jump.Continue) + && !state.labeledNonLocalBreaks + && !state.labeledNonLocalContinues; - const call = factory.createCallExpression(loopFunctionExpressionName, /*typeArguments*/ undefined, map(state.loopParameters, p => p.name as Identifier)); + const call = factory.createCallExpression( + loopFunctionExpressionName, + /*typeArguments*/ undefined, + map(state.loopParameters, p => p.name as Identifier), + ); const callResult = containsYield ? factory.createYieldExpression( factory.createToken(SyntaxKind.AsteriskToken), - setEmitFlags(call, EmitFlags.Iterator) + setEmitFlags(call, EmitFlags.Iterator), ) : call; if (isSimpleLoop) { statements.push(factory.createExpressionStatement(callResult)); - copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements); + copyOutParameters( + state.loopOutParameters, + LoopOutParameterFlags.Body, + CopyDirection.ToOriginal, + statements, + ); } else { const loopResultName = factory.createUniqueName("state"); const stateVariable = factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration(loopResultName, /*exclamationToken*/ undefined, /*type*/ undefined, callResult)] - ) + [factory.createVariableDeclaration( + loopResultName, + /*exclamationToken*/ undefined, + /*type*/ undefined, + callResult, + )], + ), ); statements.push(stateVariable); - copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements); + copyOutParameters( + state.loopOutParameters, + LoopOutParameterFlags.Body, + CopyDirection.ToOriginal, + statements, + ); if (state.nonLocalJumps! & Jump.Return) { let returnStatement: ReturnStatement; @@ -3644,13 +4172,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile returnStatement = factory.createReturnStatement(loopResultName); } else { - returnStatement = factory.createReturnStatement(factory.createPropertyAccessExpression(loopResultName, "value")); + returnStatement = factory.createReturnStatement( + factory.createPropertyAccessExpression(loopResultName, "value"), + ); } statements.push( factory.createIfStatement( factory.createTypeCheck(loopResultName, "object"), - returnStatement - ) + returnStatement, + ), ); } @@ -3659,22 +4189,34 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createIfStatement( factory.createStrictEquality( loopResultName, - factory.createStringLiteral("break") + factory.createStringLiteral("break"), ), - factory.createBreakStatement() - ) + factory.createBreakStatement(), + ), ); } if (state.labeledNonLocalBreaks || state.labeledNonLocalContinues) { const caseClauses: CaseClause[] = []; - processLabeledJumps(state.labeledNonLocalBreaks!, /*isBreak*/ true, loopResultName, outerState, caseClauses); - processLabeledJumps(state.labeledNonLocalContinues!, /*isBreak*/ false, loopResultName, outerState, caseClauses); + processLabeledJumps( + state.labeledNonLocalBreaks!, + /*isBreak*/ true, + loopResultName, + outerState, + caseClauses, + ); + processLabeledJumps( + state.labeledNonLocalContinues!, + /*isBreak*/ false, + loopResultName, + outerState, + caseClauses, + ); statements.push( factory.createSwitchStatement( loopResultName, - factory.createCaseBlock(caseClauses) - ) + factory.createCaseBlock(caseClauses), + ), ); } } @@ -3696,7 +4238,13 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } } - function processLabeledJumps(table: Map, isBreak: boolean, loopResultName: Identifier, outerLoop: ConvertedLoopState | undefined, caseClauses: CaseClause[]): void { + function processLabeledJumps( + table: Map, + isBreak: boolean, + loopResultName: Identifier, + outerLoop: ConvertedLoopState | undefined, + caseClauses: CaseClause[], + ): void { if (!table) { return; } @@ -3717,17 +4265,31 @@ export function transformES2015(context: TransformationContext): (x: SourceFile }); } - function processLoopVariableDeclaration(container: IterationStatement, decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[], hasCapturedBindingsInForHead: boolean) { + function processLoopVariableDeclaration( + container: IterationStatement, + decl: VariableDeclaration | BindingElement, + loopParameters: ParameterDeclaration[], + loopOutParameters: LoopOutParameter[], + hasCapturedBindingsInForHead: boolean, + ) { const name = decl.name; if (isBindingPattern(name)) { for (const element of name.elements) { if (!isOmittedExpression(element)) { - processLoopVariableDeclaration(container, element, loopParameters, loopOutParameters, hasCapturedBindingsInForHead); + processLoopVariableDeclaration( + container, + element, + loopParameters, + loopOutParameters, + hasCapturedBindingsInForHead, + ); } } } else { - loopParameters.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name)); + loopParameters.push( + factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name), + ); const checkFlags = resolver.getNodeCheckFlags(decl); if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForHead) { const outParamName = factory.createUniqueName("out_" + idText(name)); @@ -3739,8 +4301,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile if (container.initializer && resolver.isBindingCapturedByNode(container.initializer, decl)) { flags |= LoopOutParameterFlags.Initializer; } - if (container.condition && resolver.isBindingCapturedByNode(container.condition, decl) || - container.incrementor && resolver.isBindingCapturedByNode(container.incrementor, decl)) { + if ( + container.condition && resolver.isBindingCapturedByNode(container.condition, decl) + || container.incrementor && resolver.isBindingCapturedByNode(container.incrementor, decl) + ) { flags |= LoopOutParameterFlags.Body; } } @@ -3758,7 +4322,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param numInitialNonComputedProperties The number of initial properties without * computed property names. */ - function addObjectLiteralMembers(expressions: Expression[], node: ObjectLiteralExpression, receiver: Identifier, start: number) { + function addObjectLiteralMembers( + expressions: Expression[], + node: ObjectLiteralExpression, + receiver: Identifier, + start: number, + ) { const properties = node.properties; const numProperties = properties.length; for (let i = start; i < numProperties; i++) { @@ -3774,7 +4343,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile break; case SyntaxKind.MethodDeclaration: - expressions.push(transformObjectLiteralMethodDeclarationToExpression(property, receiver, node, node.multiLine!)); + expressions.push( + transformObjectLiteralMethodDeclarationToExpression(property, receiver, node, node.multiLine!), + ); break; case SyntaxKind.PropertyAssignment: @@ -3782,7 +4353,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile break; case SyntaxKind.ShorthandPropertyAssignment: - expressions.push(transformShorthandPropertyAssignmentToExpression(property, receiver, node.multiLine!)); + expressions.push( + transformShorthandPropertyAssignmentToExpression(property, receiver, node.multiLine!), + ); break; default: @@ -3799,14 +4372,18 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param property The PropertyAssignment node. * @param receiver The receiver for the assignment. */ - function transformPropertyAssignmentToExpression(property: PropertyAssignment, receiver: Expression, startsOnNewLine: boolean) { + function transformPropertyAssignmentToExpression( + property: PropertyAssignment, + receiver: Expression, + startsOnNewLine: boolean, + ) { const expression = factory.createAssignment( createMemberAccessForPropertyName( factory, receiver, - Debug.checkDefined(visitNode(property.name, visitor, isPropertyName)) + Debug.checkDefined(visitNode(property.name, visitor, isPropertyName)), ), - Debug.checkDefined(visitNode(property.initializer, visitor, isExpression)) + Debug.checkDefined(visitNode(property.initializer, visitor, isExpression)), ); setTextRange(expression, property); if (startsOnNewLine) { @@ -3822,14 +4399,18 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param property The ShorthandPropertyAssignment node. * @param receiver The receiver for the assignment. */ - function transformShorthandPropertyAssignmentToExpression(property: ShorthandPropertyAssignment, receiver: Expression, startsOnNewLine: boolean) { + function transformShorthandPropertyAssignmentToExpression( + property: ShorthandPropertyAssignment, + receiver: Expression, + startsOnNewLine: boolean, + ) { const expression = factory.createAssignment( createMemberAccessForPropertyName( factory, receiver, - Debug.checkDefined(visitNode(property.name, visitor, isPropertyName)) + Debug.checkDefined(visitNode(property.name, visitor, isPropertyName)), ), - factory.cloneNode(property.name) + factory.cloneNode(property.name), ); setTextRange(expression, property); if (startsOnNewLine) { @@ -3845,14 +4426,19 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param method The MethodDeclaration node. * @param receiver The receiver for the assignment. */ - function transformObjectLiteralMethodDeclarationToExpression(method: MethodDeclaration, receiver: Expression, container: Node, startsOnNewLine: boolean) { + function transformObjectLiteralMethodDeclarationToExpression( + method: MethodDeclaration, + receiver: Expression, + container: Node, + startsOnNewLine: boolean, + ) { const expression = factory.createAssignment( createMemberAccessForPropertyName( factory, receiver, - Debug.checkDefined(visitNode(method.name, visitor, isPropertyName)) + Debug.checkDefined(visitNode(method.name, visitor, isPropertyName)), ), - transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined, container) + transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined, container), ); setTextRange(expression, method); if (startsOnNewLine) { @@ -3864,7 +4450,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile function visitCatchClause(node: CatchClause): CatchClause { const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes); let updated: CatchClause; - Debug.assert(!!node.variableDeclaration, "Catch clause variable should always be present when downleveling ES2015."); + Debug.assert( + !!node.variableDeclaration, + "Catch clause variable should always be present when downleveling ES2015.", + ); if (isBindingPattern(node.variableDeclaration.name)) { const temp = factory.createTempVariable(/*recordTempVariable*/ undefined); const newVariableDeclaration = factory.createVariableDeclaration(temp); @@ -3874,12 +4463,16 @@ export function transformES2015(context: TransformationContext): (x: SourceFile visitor, context, FlattenLevel.All, - temp + temp, ); const list = factory.createVariableDeclarationList(vars); setTextRange(list, node.variableDeclaration); const destructure = factory.createVariableStatement(/*modifiers*/ undefined, list); - updated = factory.updateCatchClause(node, newVariableDeclaration, addStatementToStartOfBlock(node.block, destructure)); + updated = factory.updateCatchClause( + node, + newVariableDeclaration, + addStatementToStartOfBlock(node.block, destructure), + ); } else { updated = visitEachChild(node, visitor, context); @@ -3905,14 +4498,19 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // Methods on classes are handled in visitClassDeclaration/visitClassExpression. // Methods with computed property names are handled in visitObjectLiteralExpression. Debug.assert(!isComputedPropertyName(node.name)); - const functionExpression = transformFunctionLikeToExpression(node, /*location*/ moveRangePos(node, -1), /*name*/ undefined, /*container*/ undefined); + const functionExpression = transformFunctionLikeToExpression( + node, + /*location*/ moveRangePos(node, -1), + /*name*/ undefined, + /*container*/ undefined, + ); setEmitFlags(functionExpression, EmitFlags.NoLeadingComments | getEmitFlags(functionExpression)); return setTextRange( factory.createPropertyAssignment( node.name, - functionExpression + functionExpression, ), - /*location*/ node + /*location*/ node, ); } @@ -3930,7 +4528,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const parameters = visitParameterList(node.parameters, visitor, context); const body = transformFunctionBody(node); if (node.kind === SyntaxKind.GetAccessor) { - updated = factory.updateGetAccessorDeclaration(node, node.modifiers, node.name, parameters, node.type, body); + updated = factory.updateGetAccessorDeclaration( + node, + node.modifiers, + node.name, + parameters, + node.type, + body, + ); } else { updated = factory.updateSetAccessorDeclaration(node, node.modifiers, node.name, parameters, body); @@ -3949,9 +4554,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return setTextRange( factory.createPropertyAssignment( node.name, - visitIdentifier(factory.cloneNode(node.name)) + visitIdentifier(factory.cloneNode(node.name)), ), - /*location*/ node + /*location*/ node, ); } @@ -3977,7 +4582,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile function visitArrayLiteralExpression(node: ArrayLiteralExpression): Expression { if (some(node.elements, isSpreadElement)) { // We are here because we contain a SpreadElementExpression. - return transformAndSpreadElements(node.elements, /*isArgumentList*/ false, !!node.multiLine, /*hasTrailingComma*/ !!node.elements.hasTrailingComma); + return transformAndSpreadElements( + node.elements, + /*isArgumentList*/ false, + !!node.multiLine, + /*hasTrailingComma*/ !!node.elements.hasTrailingComma, + ); } return visitEachChild(node, visitor, context); } @@ -3993,9 +4603,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } const expression = skipOuterExpressions(node.expression); - if (expression.kind === SyntaxKind.SuperKeyword || - isSuperProperty(expression) || - some(node.arguments, isSpreadElement)) { + if ( + expression.kind === SyntaxKind.SuperKeyword + || isSuperProperty(expression) + || some(node.arguments, isSpreadElement) + ) { return visitCallExpressionWithPotentialCapturedThisAssignment(node, /*assignToCapturedThis*/ true); } @@ -4003,7 +4615,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile node, Debug.checkDefined(visitNode(node.expression, callExpressionVisitor, isExpression)), /*typeArguments*/ undefined, - visitNodes(node.arguments, visitor, isExpression) + visitNodes(node.arguments, visitor, isExpression), ); } @@ -4045,7 +4657,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // The class statements are the statements generated by visiting the first statement with initializer of the // body (1), while all other statements are added to remainingStatements (2) - const isVariableStatementWithInitializer = (stmt: Statement) => isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer; + const isVariableStatementWithInitializer = (stmt: Statement) => + isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer; // visit the class body statements outside of any converted loop body. const savedConvertedLoopState = convertedLoopState; @@ -4078,12 +4691,18 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // }()) // let aliasAssignment = tryCast(initializer, isAssignmentExpression); - if (!aliasAssignment && isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.CommaToken) { + if ( + !aliasAssignment && isBinaryExpression(initializer) + && initializer.operatorToken.kind === SyntaxKind.CommaToken + ) { aliasAssignment = tryCast(initializer.left, isAssignmentExpression); } // The underlying call (3) is another IIFE that may contain a '_super' argument. - const call = cast(aliasAssignment ? skipOuterExpressions(aliasAssignment.right) : initializer, isCallExpression); + const call = cast( + aliasAssignment ? skipOuterExpressions(aliasAssignment.right) : initializer, + isCallExpression, + ); const func = cast(skipOuterExpressions(call.expression), isFunctionExpression); const funcStatements = func.body.statements; @@ -4109,9 +4728,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createExpressionStatement( factory.createAssignment( aliasAssignment.left, - cast(variable.name, isIdentifier) - ) - ) + cast(variable.name, isIdentifier), + ), + ), ); } @@ -4137,8 +4756,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // of the inner wrapper if its expression is not trivially an Identifier. const returnStatement = tryCast(elementAt(funcStatements, classBodyEnd), isReturnStatement); for (const statement of remainingStatements) { - if (isReturnStatement(statement) && returnStatement?.expression && - !isIdentifier(returnStatement.expression)) { + if ( + isReturnStatement(statement) && returnStatement?.expression + && !isIdentifier(returnStatement.expression) + ) { statements.push(returnStatement); } else { @@ -4152,11 +4773,16 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // Recreate any outer parentheses or partially-emitted expressions to preserve source map // and comment locations. - return factory.restoreOuterExpressions(node.expression, - factory.restoreOuterExpressions(variable.initializer, - factory.restoreOuterExpressions(aliasAssignment && aliasAssignment.right, - factory.updateCallExpression(call, - factory.restoreOuterExpressions(call.expression, + return factory.restoreOuterExpressions( + node.expression, + factory.restoreOuterExpressions( + variable.initializer, + factory.restoreOuterExpressions( + aliasAssignment && aliasAssignment.right, + factory.updateCallExpression( + call, + factory.restoreOuterExpressions( + call.expression, factory.updateFunctionExpression( func, /*modifiers*/ undefined, @@ -4167,15 +4793,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*type*/ undefined, factory.updateBlock( func.body, - statements - ) - ) + statements, + ), + ), ), /*typeArguments*/ undefined, - call.arguments - ) - ) - ) + call.arguments, + ), + ), + ), ); } @@ -4183,13 +4809,17 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return visitCallExpressionWithPotentialCapturedThisAssignment(node, /*assignToCapturedThis*/ false); } - function visitCallExpressionWithPotentialCapturedThisAssignment(node: CallExpression, assignToCapturedThis: boolean): CallExpression | BinaryExpression { + function visitCallExpressionWithPotentialCapturedThisAssignment( + node: CallExpression, + assignToCapturedThis: boolean, + ): CallExpression | BinaryExpression { // We are here either because SuperKeyword was used somewhere in the expression, or // because we contain a SpreadElementExpression. - if (node.transformFlags & TransformFlags.ContainsRestOrSpread || - node.expression.kind === SyntaxKind.SuperKeyword || - isSuperProperty(skipOuterExpressions(node.expression))) { - + if ( + node.transformFlags & TransformFlags.ContainsRestOrSpread + || node.expression.kind === SyntaxKind.SuperKeyword + || isSuperProperty(skipOuterExpressions(node.expression)) + ) { const { target, thisArg } = factory.createCallBinding(node.expression, hoistVariableDeclaration); if (node.expression.kind === SyntaxKind.SuperKeyword) { setEmitFlags(thisArg, EmitFlags.NoSubstitution); @@ -4213,8 +4843,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile resultingCall = factory.createFunctionApplyCall( Debug.checkDefined(visitNode(target, callExpressionVisitor, isExpression)), - node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : Debug.checkDefined(visitNode(thisArg, visitor, isExpression)), - transformAndSpreadElements(node.arguments, /*isArgumentList*/ true, /*multiLine*/ false, /*hasTrailingComma*/ false) + node.expression.kind === SyntaxKind.SuperKeyword ? thisArg + : Debug.checkDefined(visitNode(thisArg, visitor, isExpression)), + transformAndSpreadElements( + node.arguments, + /*isArgumentList*/ true, + /*multiLine*/ false, + /*hasTrailingComma*/ false, + ), ); } else { @@ -4230,21 +4866,27 @@ export function transformES2015(context: TransformationContext): (x: SourceFile resultingCall = setTextRange( factory.createFunctionCallCall( Debug.checkDefined(visitNode(target, callExpressionVisitor, isExpression)), - node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : Debug.checkDefined(visitNode(thisArg, visitor, isExpression)), - visitNodes(node.arguments, visitor, isExpression) + node.expression.kind === SyntaxKind.SuperKeyword ? thisArg + : Debug.checkDefined(visitNode(thisArg, visitor, isExpression)), + visitNodes(node.arguments, visitor, isExpression), ), - node + node, ); } if (node.expression.kind === SyntaxKind.SuperKeyword) { - const initializer = - factory.createLogicalOr( - resultingCall, - createActualThis() - ); + const initializer = factory.createLogicalOr( + resultingCall, + createActualThis(), + ); resultingCall = assignToCapturedThis - ? factory.createAssignment(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), initializer) + ? factory.createAssignment( + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + initializer, + ) : initializer; } return setOriginalNode(resultingCall, node); @@ -4267,15 +4909,23 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // [output] // new ((_a = C).bind.apply(_a, [void 0].concat(a)))() - const { target, thisArg } = factory.createCallBinding(factory.createPropertyAccessExpression(node.expression, "bind"), hoistVariableDeclaration); + const { target, thisArg } = factory.createCallBinding( + factory.createPropertyAccessExpression(node.expression, "bind"), + hoistVariableDeclaration, + ); return factory.createNewExpression( factory.createFunctionApplyCall( Debug.checkDefined(visitNode(target, visitor, isExpression)), thisArg, - transformAndSpreadElements(factory.createNodeArray([factory.createVoidZero(), ...node.arguments!]), /*isArgumentList*/ true, /*multiLine*/ false, /*hasTrailingComma*/ false) + transformAndSpreadElements( + factory.createNodeArray([factory.createVoidZero(), ...node.arguments!]), + /*isArgumentList*/ true, + /*multiLine*/ false, + /*hasTrailingComma*/ false, + ), ), /*typeArguments*/ undefined, - [] + [], ); } return visitEachChild(node, visitor, context); @@ -4290,7 +4940,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * argument list. * @param multiLine A value indicating whether the result should be emitted on multiple lines. */ - function transformAndSpreadElements(elements: NodeArray, isArgumentList: boolean, multiLine: boolean, hasTrailingComma: boolean): Expression { + function transformAndSpreadElements( + elements: NodeArray, + isArgumentList: boolean, + multiLine: boolean, + hasTrailingComma: boolean, + ): Expression { // When there is no leading SpreadElement: // // [source] @@ -4329,9 +4984,12 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // As we visit each element, we return one of two functions to use as the "key": // - `visitSpanOfSpreads` for one or more contiguous `...` spread expressions, i.e. `...a, ...b` in `[1, 2, ...a, ...b]` // - `visitSpanOfNonSpreads` for one or more contiguous non-spread elements, i.e. `1, 2`, in `[1, 2, ...a, ...b]` - spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) => - visitPartition(partition, multiLine, hasTrailingComma && end === numElements) - ) + spanMap( + elements, + partitionSpread, + (partition, visitPartition, _start, end) => + visitPartition(partition, multiLine, hasTrailingComma && end === numElements), + ), ); if (segments.length === 1) { @@ -4340,25 +4998,27 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // a CallExpression or NewExpression. When using `--downlevelIteration`, we need // to coerce this into an array for use with `apply`, so we will use the code path // that follows instead. - if (isArgumentList && !compilerOptions.downlevelIteration + if ( + isArgumentList && !compilerOptions.downlevelIteration || isPackedArrayLiteral(firstSegment.expression) // see NOTE (above) - || isCallToHelper(firstSegment.expression, "___spreadArray" as __String)) { + || isCallToHelper(firstSegment.expression, "___spreadArray" as __String) + ) { return firstSegment.expression; } } const helpers = emitHelpers(); const startsWithSpread = segments[0].kind !== SpreadSegmentKind.None; - let expression: Expression = - startsWithSpread ? factory.createArrayLiteralExpression() : - segments[0].expression; + let expression: Expression = startsWithSpread ? factory.createArrayLiteralExpression() + : segments[0].expression; for (let i = startsWithSpread ? 0 : 1; i < segments.length; i++) { const segment = segments[i]; // If this is for an argument list, it doesn't matter if the array is packed or sparse expression = helpers.createSpreadArrayHelper( expression, segment.expression, - segment.kind === SpreadSegmentKind.UnpackedSpread && !isArgumentList); + segment.kind === SpreadSegmentKind.UnpackedSpread && !isArgumentList, + ); } return expression; } @@ -4380,10 +5040,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // We don't need to pack already packed array literals, or existing calls to the `__read` helper. const isCallToReadHelper = isCallToHelper(expression, "___read" as __String); - let kind = isCallToReadHelper || isPackedArrayLiteral(expression) ? SpreadSegmentKind.PackedSpread : SpreadSegmentKind.UnpackedSpread; + let kind = isCallToReadHelper || isPackedArrayLiteral(expression) ? SpreadSegmentKind.PackedSpread + : SpreadSegmentKind.UnpackedSpread; // We don't need the `__read` helper for array literals. Array packing will be performed by `__spreadArray`. - if (compilerOptions.downlevelIteration && kind === SpreadSegmentKind.UnpackedSpread && !isArrayLiteralExpression(expression) && !isCallToReadHelper) { + if ( + compilerOptions.downlevelIteration && kind === SpreadSegmentKind.UnpackedSpread + && !isArrayLiteralExpression(expression) && !isCallToReadHelper + ) { expression = emitHelpers().createReadHelper(expression, /*count*/ undefined); // the `__read` helper returns a packed array, so we don't need to ensure a packed array kind = SpreadSegmentKind.PackedSpread; @@ -4395,7 +5059,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile function visitSpanOfNonSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): SpreadSegment { const expression = factory.createArrayLiteralExpression( visitNodes(factory.createNodeArray(chunk, hasTrailingComma), visitor, isExpression), - multiLine); + multiLine, + ); // We do not pack non-spread segments, this is so that `[1, , ...[2, , 3], , 4]` is properly downleveled to // `[1, , 2, undefined, 3, , 4]`. See the NOTE in `transformAndSpreadElements` @@ -4451,7 +5116,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile visitor, currentSourceFile, recordTaggedTemplateString, - ProcessLevel.All + ProcessLevel.All, ); } @@ -4484,15 +5149,27 @@ export function transformES2015(context: TransformationContext): (x: SourceFile */ function visitSuperKeyword(isExpressionOfCall: boolean): LeftHandSideExpression { return hierarchyFacts & HierarchyFacts.NonStaticClassElement - && !isExpressionOfCall - ? factory.createPropertyAccessExpression(factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), "prototype") - : factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + && !isExpressionOfCall + ? factory.createPropertyAccessExpression( + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + "prototype", + ) + : factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); } function visitMetaProperty(node: MetaProperty) { if (node.keywordToken === SyntaxKind.NewKeyword && node.name.escapedText === "target") { hierarchyFacts |= HierarchyFacts.NewTarget; - return factory.createUniqueName("_newTarget", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + return factory.createUniqueName( + "_newTarget", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); } return node; } @@ -4511,7 +5188,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile HierarchyFacts.FunctionExcludes, getEmitFlags(node) & EmitFlags.CapturesThis ? HierarchyFacts.FunctionIncludes | HierarchyFacts.CapturesThis - : HierarchyFacts.FunctionIncludes); + : HierarchyFacts.FunctionIncludes, + ); previousOnEmitNode(hint, node, emitCallback); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); return; @@ -4638,7 +5316,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile function isPartOfClassBody(declaration: ClassLikeDeclaration, node: Identifier) { let currentNode: Node | undefined = getParseTreeNode(node); - if (!currentNode || currentNode === declaration || currentNode.end <= declaration.pos || currentNode.pos >= declaration.end) { + if ( + !currentNode || currentNode === declaration || currentNode.end <= declaration.pos + || currentNode.pos >= declaration.end + ) { // if the node has no correlation to a parse tree node, its definitely not // part of the body. // if the node is outside of the document range of the declaration, its @@ -4666,9 +5347,17 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param node The ThisKeyword node. */ function substituteThisKeyword(node: PrimaryExpression): PrimaryExpression { - if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis - && hierarchyFacts & HierarchyFacts.CapturesThis) { - return setTextRange(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), node); + if ( + enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis + && hierarchyFacts & HierarchyFacts.CapturesThis + ) { + return setTextRange( + factory.createUniqueName( + "_this", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + node, + ); } return node; } @@ -4679,7 +5368,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile : factory.createPropertyAccessExpression(factory.getInternalName(node), "prototype"); } - function hasSynthesizedDefaultSuperCall(constructor: ConstructorDeclaration | undefined, hasExtendsClause: boolean) { + function hasSynthesizedDefaultSuperCall( + constructor: ConstructorDeclaration | undefined, + hasExtendsClause: boolean, + ) { if (!constructor || !hasExtendsClause) { return false; } diff --git a/src/compiler/transformers/es2016.ts b/src/compiler/transformers/es2016.ts index 33df5b94f0d0b..7a2d623d15a90 100644 --- a/src/compiler/transformers/es2016.ts +++ b/src/compiler/transformers/es2016.ts @@ -21,7 +21,7 @@ import { export function transformES2016(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle { const { factory, - hoistVariableDeclaration + hoistVariableDeclaration, } = context; return chainBundle(context, transformSourceFile); @@ -69,16 +69,19 @@ export function transformES2016(context: TransformationContext): (x: SourceFile target = setTextRange( factory.createElementAccessExpression( setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression), - setTextRange(factory.createAssignment(argumentExpressionTemp, left.argumentExpression), left.argumentExpression) + setTextRange( + factory.createAssignment(argumentExpressionTemp, left.argumentExpression), + left.argumentExpression, + ), ), - left + left, ); value = setTextRange( factory.createElementAccessExpression( expressionTemp, - argumentExpressionTemp + argumentExpressionTemp, ), - left + left, ); } else if (isPropertyAccessExpression(left)) { @@ -87,16 +90,16 @@ export function transformES2016(context: TransformationContext): (x: SourceFile target = setTextRange( factory.createPropertyAccessExpression( setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression), - left.name + left.name, ), - left + left, ); value = setTextRange( factory.createPropertyAccessExpression( expressionTemp, - left.name + left.name, ), - left + left, ); } else { @@ -107,9 +110,9 @@ export function transformES2016(context: TransformationContext): (x: SourceFile return setTextRange( factory.createAssignment( target, - setTextRange(factory.createGlobalMethodCall("Math", "pow", [value, right]), node) + setTextRange(factory.createGlobalMethodCall("Math", "pow", [value, right]), node), ), - node + node, ); } diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 1c1a2e9f45f23..a42b0b2afe11e 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -98,17 +98,22 @@ import { VisitResult, } from "../_namespaces/ts"; -type SuperContainer = ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration; +type SuperContainer = + | ClassDeclaration + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration + | ConstructorDeclaration; const enum ES2017SubstitutionFlags { /** Enables substitutions for async methods with `super` calls. */ - AsyncMethodsWithSuper = 1 << 0 + AsyncMethodsWithSuper = 1 << 0, } const enum ContextFlags { None = 0, NonTopLevel = 1 << 0, - HasLexicalThis = 1 << 1 + HasLexicalThis = 1 << 1, } /** @internal */ @@ -118,7 +123,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile getEmitHelperFactory: emitHelpers, resumeLexicalEnvironment, endLexicalEnvironment, - hoistVariableDeclaration + hoistVariableDeclaration, } = context; const resolver = context.getEmitResolver(); @@ -216,35 +221,65 @@ export function transformES2017(context: TransformationContext): (x: SourceFile return visitAwaitExpression(node as AwaitExpression); case SyntaxKind.MethodDeclaration: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitMethodDeclaration, node as MethodDeclaration); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitMethodDeclaration, + node as MethodDeclaration, + ); case SyntaxKind.FunctionDeclaration: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitFunctionDeclaration, node as FunctionDeclaration); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitFunctionDeclaration, + node as FunctionDeclaration, + ); case SyntaxKind.FunctionExpression: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitFunctionExpression, node as FunctionExpression); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitFunctionExpression, + node as FunctionExpression, + ); case SyntaxKind.ArrowFunction: return doWithContext(ContextFlags.NonTopLevel, visitArrowFunction, node as ArrowFunction); case SyntaxKind.PropertyAccessExpression: - if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) { + if ( + capturedSuperProperties && isPropertyAccessExpression(node) + && node.expression.kind === SyntaxKind.SuperKeyword + ) { capturedSuperProperties.add(node.name.escapedText); } return visitEachChild(node, visitor, context); case SyntaxKind.ElementAccessExpression: - if (capturedSuperProperties && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword) { + if ( + capturedSuperProperties + && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword + ) { hasSuperElementAccess = true; } return visitEachChild(node, visitor, context); case SyntaxKind.GetAccessor: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitGetAccessorDeclaration, node as GetAccessorDeclaration); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitGetAccessorDeclaration, + node as GetAccessorDeclaration, + ); case SyntaxKind.SetAccessor: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitSetAccessorDeclaration, node as SetAccessorDeclaration); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitSetAccessorDeclaration, + node as SetAccessorDeclaration, + ); case SyntaxKind.Constructor: - return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitConstructorDeclaration, node as ConstructorDeclaration); + return doWithContext( + ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, + visitConstructorDeclaration, + node as ConstructorDeclaration, + ); case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: return doWithContext(ContextFlags.NonTopLevel | ContextFlags.HasLexicalThis, visitDefault, node); @@ -315,7 +350,10 @@ export function transformES2017(context: TransformationContext): (x: SourceFile function visitVariableStatementInAsyncBody(node: VariableStatement) { if (isVariableDeclarationListWithCollidingName(node.declarationList)) { - const expression = visitVariableDeclarationListWithCollidingNames(node.declarationList, /*hasReceiver*/ false); + const expression = visitVariableDeclarationListWithCollidingNames( + node.declarationList, + /*hasReceiver*/ false, + ); return expression ? factory.createExpressionStatement(expression) : undefined; } return visitEachChild(node, visitor, context); @@ -327,8 +365,8 @@ export function transformES2017(context: TransformationContext): (x: SourceFile isVariableDeclarationListWithCollidingName(node.initializer) ? visitVariableDeclarationListWithCollidingNames(node.initializer, /*hasReceiver*/ true)! : Debug.checkDefined(visitNode(node.initializer, visitor, isForInitializer)), - Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), - visitIterationBody(node.statement, asyncBodyVisitor, context) + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), + visitIterationBody(node.statement, asyncBodyVisitor, context), ); } @@ -340,7 +378,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile ? visitVariableDeclarationListWithCollidingNames(node.initializer, /*hasReceiver*/ true)! : Debug.checkDefined(visitNode(node.initializer, visitor, isForInitializer)), Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), - visitIterationBody(node.statement, asyncBodyVisitor, context) + visitIterationBody(node.statement, asyncBodyVisitor, context), ); } @@ -353,7 +391,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile : visitNode(node.initializer, visitor, isForInitializer), visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, visitor, isExpression), - visitIterationBody(node.statement, asyncBodyVisitor, context) + visitIterationBody(node.statement, asyncBodyVisitor, context), ); } @@ -373,11 +411,11 @@ export function transformES2017(context: TransformationContext): (x: SourceFile setTextRange( factory.createYieldExpression( /*asteriskToken*/ undefined, - visitNode(node.expression, visitor, isExpression) + visitNode(node.expression, visitor, isExpression), ), - node + node, ), - node + node, ); } @@ -386,7 +424,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile node, visitNodes(node.modifiers, visitor, isModifier), visitParameterList(node.parameters, visitor, context), - transformMethodBody(node) + transformMethodBody(node), ); } @@ -410,7 +448,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile /*type*/ undefined, getFunctionFlags(node) & FunctionFlags.Async ? transformAsyncFunctionBody(node) - : transformMethodBody(node) + : transformMethodBody(node), ); } @@ -421,7 +459,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile node.name, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - transformMethodBody(node) + transformMethodBody(node), ); } @@ -431,7 +469,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile visitNodes(node.modifiers, visitor, isModifierLike), node.name, visitParameterList(node.parameters, visitor, context), - transformMethodBody(node) + transformMethodBody(node), ); } @@ -454,7 +492,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile /*type*/ undefined, getFunctionFlags(node) & FunctionFlags.Async ? transformAsyncFunctionBody(node) - : visitFunctionBody(node.body, visitor, context) + : visitFunctionBody(node.body, visitor, context), ); } @@ -477,7 +515,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile /*type*/ undefined, getFunctionFlags(node) & FunctionFlags.Async ? transformAsyncFunctionBody(node) - : visitFunctionBody(node.body, visitor, context) + : visitFunctionBody(node.body, visitor, context), ); } @@ -503,7 +541,10 @@ export function transformES2017(context: TransformationContext): (x: SourceFile ); } - function recordDeclarationName({ name }: ParameterDeclaration | VariableDeclaration | BindingElement, names: Set<__String>) { + function recordDeclarationName( + { name }: ParameterDeclaration | VariableDeclaration | BindingElement, + names: Set<__String>, + ) { if (isIdentifier(name)) { names.add(name.escapedText); } @@ -529,7 +570,11 @@ export function transformES2017(context: TransformationContext): (x: SourceFile const variables = getInitializedVariables(node); if (variables.length === 0) { if (hasReceiver) { - return visitNode(factory.converters.convertToAssignmentElementTarget(node.declarations[0].name), visitor, isExpression); + return visitNode( + factory.converters.convertToAssignmentElementTarget(node.declarations[0].name), + visitor, + isExpression, + ); } return undefined; } @@ -558,9 +603,9 @@ export function transformES2017(context: TransformationContext): (x: SourceFile const converted = setSourceMapRange( factory.createAssignment( factory.converters.convertToAssignmentElementTarget(node.name), - node.initializer! + node.initializer!, ), - node + node, ); return Debug.checkDefined(visitNode(converted, visitor, isExpression)); } @@ -579,7 +624,9 @@ export function transformES2017(context: TransformationContext): (x: SourceFile return false; } - function transformMethodBody(node: MethodDeclaration | AccessorDeclaration | ConstructorDeclaration): FunctionBody | undefined { + function transformMethodBody( + node: MethodDeclaration | AccessorDeclaration | ConstructorDeclaration, + ): FunctionBody | undefined { Debug.assertIsDefined(node.body); const savedCapturedSuperProperties = capturedSuperProperties; @@ -592,14 +639,21 @@ export function transformES2017(context: TransformationContext): (x: SourceFile // Minor optimization, emit `_super` helper to capture `super` access in an arrow. // This step isn't needed if we eventually transform this to ES5. const originalMethod = getOriginalNode(node, isFunctionLikeDeclaration); - const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && - resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync) && - (getFunctionFlags(originalMethod) & FunctionFlags.AsyncGenerator) !== FunctionFlags.AsyncGenerator; + const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 + && resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync + | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync) + && (getFunctionFlags(originalMethod) & FunctionFlags.AsyncGenerator) !== FunctionFlags.AsyncGenerator; if (emitSuperHelpers) { enableSubstitutionForAsyncMethodsWithSuper(); if (capturedSuperProperties.size) { - const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties); + const variableStatement = createSuperAccessVariableStatement( + factory, + resolver, + node, + capturedSuperProperties, + ); substitutedSuperAccessors[getNodeId(variableStatement)] = true; const statements = updated.statements.slice(); @@ -623,7 +677,9 @@ export function transformES2017(context: TransformationContext): (x: SourceFile return updated; } - function transformAsyncFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody; + function transformAsyncFunctionBody( + node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression, + ): FunctionBody; function transformAsyncFunctionBody(node: ArrowFunction): ConciseBody; function transformAsyncFunctionBody(node: FunctionLikeDeclaration): ConciseBody { resumeLexicalEnvironment(); @@ -656,28 +712,41 @@ export function transformES2017(context: TransformationContext): (x: SourceFile let result: ConciseBody; if (!isArrowFunction) { const statements: Statement[] = []; - const statementOffset = factory.copyPrologue((node.body as Block).statements, statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = factory.copyPrologue( + (node.body as Block).statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); statements.push( factory.createReturnStatement( emitHelpers().createAwaiterHelper( inHasLexicalThisContext(), hasLexicalArguments, promiseConstructor, - transformAsyncFunctionBodyWorker(node.body as Block, statementOffset) - ) - ) + transformAsyncFunctionBodyWorker(node.body as Block, statementOffset), + ), + ), ); insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); // Minor optimization, emit `_super` helper to capture `super` access in an arrow. // This step isn't needed if we eventually transform this to ES5. - const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync); + const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 + && resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync + | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync); if (emitSuperHelpers) { enableSubstitutionForAsyncMethodsWithSuper(); if (capturedSuperProperties.size) { - const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties); + const variableStatement = createSuperAccessVariableStatement( + factory, + resolver, + node, + capturedSuperProperties, + ); substitutedSuperAccessors[getNodeId(variableStatement)] = true; insertStatementsAfterStandardPrologue(statements, [variableStatement]); } @@ -703,13 +772,19 @@ export function transformES2017(context: TransformationContext): (x: SourceFile inHasLexicalThisContext(), hasLexicalArguments, promiseConstructor, - transformAsyncFunctionBodyWorker(node.body) + transformAsyncFunctionBodyWorker(node.body), ); const declarations = endLexicalEnvironment(); if (some(declarations)) { const block = factory.converters.convertToFunctionBlock(expression); - result = factory.updateBlock(block, setTextRange(factory.createNodeArray(concatenate(declarations, block.statements)), block.statements)); + result = factory.updateBlock( + block, + setTextRange( + factory.createNodeArray(concatenate(declarations, block.statements)), + block.statements, + ), + ); } else { result = expression; @@ -729,7 +804,9 @@ export function transformES2017(context: TransformationContext): (x: SourceFile return factory.updateBlock(body, visitNodes(body.statements, asyncBodyVisitor, isStatement, start)); } else { - return factory.converters.convertToFunctionBlock(Debug.checkDefined(visitNode(body, asyncBodyVisitor, isConciseBody))); + return factory.converters.convertToFunctionBlock( + Debug.checkDefined(visitNode(body, asyncBodyVisitor, isConciseBody)), + ); } } @@ -737,8 +814,10 @@ export function transformES2017(context: TransformationContext): (x: SourceFile const typeName = type && getEntityNameFromTypeNode(type); if (typeName && isEntityName(typeName)) { const serializationKind = resolver.getTypeReferenceSerializationKind(typeName); - if (serializationKind === TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue - || serializationKind === TypeReferenceSerializationKind.Unknown) { + if ( + serializationKind === TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue + || serializationKind === TypeReferenceSerializationKind.Unknown + ) { return typeName; } } @@ -778,7 +857,9 @@ export function transformES2017(context: TransformationContext): (x: SourceFile // If we need to support substitutions for `super` in an async method, // we should track it here. if (enabledSubstitutions & ES2017SubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) { - const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAccessInAsync | NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync); + const superContainerFlags = resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.MethodWithSuperPropertyAccessInAsync + | NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync); if (superContainerFlags !== enclosingSuperContainerFlags) { const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags; enclosingSuperContainerFlags = superContainerFlags; @@ -829,9 +910,13 @@ export function transformES2017(context: TransformationContext): (x: SourceFile if (node.expression.kind === SyntaxKind.SuperKeyword) { return setTextRange( factory.createPropertyAccessExpression( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), - node.name), - node + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + node.name, + ), + node, ); } return node; @@ -841,7 +926,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile if (node.expression.kind === SyntaxKind.SuperKeyword) { return createSuperElementAccessInAsyncMethod( node.argumentExpression, - node + node, ); } return node; @@ -858,8 +943,8 @@ export function transformES2017(context: TransformationContext): (x: SourceFile /*typeArguments*/ undefined, [ factory.createThis(), - ...node.arguments - ] + ...node.arguments, + ], ); } return node; @@ -874,28 +959,37 @@ export function transformES2017(context: TransformationContext): (x: SourceFile || kind === SyntaxKind.SetAccessor; } - function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression { + function createSuperElementAccessInAsyncMethod( + argumentExpression: Expression, + location: TextRange, + ): LeftHandSideExpression { if (enclosingSuperContainerFlags & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) { return setTextRange( factory.createPropertyAccessExpression( factory.createCallExpression( - factory.createUniqueName("_superIndex", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_superIndex", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*typeArguments*/ undefined, - [argumentExpression] + [argumentExpression], ), - "value" + "value", ), - location + location, ); } else { return setTextRange( factory.createCallExpression( - factory.createUniqueName("_superIndex", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_superIndex", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*typeArguments*/ undefined, - [argumentExpression] + [argumentExpression], ), - location + location, ); } } @@ -906,10 +1000,16 @@ export function transformES2017(context: TransformationContext): (x: SourceFile * * @internal */ -export function createSuperAccessVariableStatement(factory: NodeFactory, resolver: EmitResolver, node: FunctionLikeDeclaration, names: Set<__String>) { +export function createSuperAccessVariableStatement( + factory: NodeFactory, + resolver: EmitResolver, + node: FunctionLikeDeclaration, + names: Set<__String>, +) { // Create a variable declaration with a getter/setter (if binding) definition for each name: // const _super = Object.create(null, { x: { get: () => super.x, set: (v) => super.x = v }, ... }); - const hasBinding = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) !== 0; + const hasBinding = + (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) !== 0; const accessors: PropertyAssignment[] = []; names.forEach((_, key) => { const name = unescapeLeadingUnderscores(key); @@ -919,20 +1019,20 @@ export function createSuperAccessVariableStatement(factory: NodeFactory, resolve factory.createArrowFunction( /*modifiers*/ undefined, /*typeParameters*/ undefined, - /* parameters */[], + /* parameters */ [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, setEmitFlags( factory.createPropertyAccessExpression( setEmitFlags( factory.createSuper(), - EmitFlags.NoSubstitution + EmitFlags.NoSubstitution, ), - name + name, ), - EmitFlags.NoSubstitution - ) - ) + EmitFlags.NoSubstitution, + ), + ), )); if (hasBinding) { getterAndSetter.push( @@ -941,15 +1041,15 @@ export function createSuperAccessVariableStatement(factory: NodeFactory, resolve factory.createArrowFunction( /*modifiers*/ undefined, /*typeParameters*/ undefined, - /* parameters */[ + /* parameters */ [ factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "v", /*questionToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined - ) + /*initializer*/ undefined, + ), ], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, @@ -958,23 +1058,23 @@ export function createSuperAccessVariableStatement(factory: NodeFactory, resolve factory.createPropertyAccessExpression( setEmitFlags( factory.createSuper(), - EmitFlags.NoSubstitution + EmitFlags.NoSubstitution, ), - name + name, ), - EmitFlags.NoSubstitution + EmitFlags.NoSubstitution, ), - factory.createIdentifier("v") - ) - ) - ) + factory.createIdentifier("v"), + ), + ), + ), ); } accessors.push( factory.createPropertyAssignment( name, factory.createObjectLiteralExpression(getterAndSetter), - ) + ), ); }); return factory.createVariableStatement( @@ -982,21 +1082,26 @@ export function createSuperAccessVariableStatement(factory: NodeFactory, resolve factory.createVariableDeclarationList( [ factory.createVariableDeclaration( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), /*exclamationToken*/ undefined, /*type*/ undefined, factory.createCallExpression( factory.createPropertyAccessExpression( factory.createIdentifier("Object"), - "create" + "create", ), /*typeArguments*/ undefined, [ factory.createNull(), - factory.createObjectLiteralExpression(accessors, /*multiLine*/ true) - ] - ) - ) + factory.createObjectLiteralExpression(accessors, /*multiLine*/ true), + ], + ), + ), ], - NodeFlags.Const)); + NodeFlags.Const, + ), + ); } diff --git a/src/compiler/transformers/es2018.ts b/src/compiler/transformers/es2018.ts index 00ca8babafec4..b08ad043a12ec 100644 --- a/src/compiler/transformers/es2018.ts +++ b/src/compiler/transformers/es2018.ts @@ -114,7 +114,7 @@ import { const enum ESNextSubstitutionFlags { /** Enables substitutions for async methods with `super` calls. */ - AsyncMethodsWithSuper = 1 << 0 + AsyncMethodsWithSuper = 1 << 0, } // Facts we track as we traverse the tree @@ -156,7 +156,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile getEmitHelperFactory: emitHelpers, resumeLexicalEnvironment, endLexicalEnvironment, - hoistVariableDeclaration + hoistVariableDeclaration, } = context; const resolver = context.getEmitResolver(); @@ -215,7 +215,8 @@ export function transformES2018(context: TransformationContext): (x: SourceFile function recordTaggedTemplateString(temp: Identifier) { taggedTemplateStringDeclarations = append( taggedTemplateStringDeclarations, - factory.createVariableDeclaration(temp)); + factory.createVariableDeclaration(temp), + ); } function transformSourceFile(node: SourceFile) { @@ -247,7 +248,12 @@ export function transformES2018(context: TransformationContext): (x: SourceFile return node; } - function doWithHierarchyFacts(cb: (value: T) => U, value: T, excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) { + function doWithHierarchyFacts( + cb: (value: T) => U, + value: T, + excludeFacts: HierarchyFacts, + includeFacts: HierarchyFacts, + ) { if (affectsSubtree(excludeFacts, includeFacts)) { const ancestorFacts = enterSubtree(excludeFacts, includeFacts); const result = cb(value); @@ -297,7 +303,8 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitDefault, node, HierarchyFacts.IterationStatementExcludes, - HierarchyFacts.IterationStatementIncludes); + HierarchyFacts.IterationStatementIncludes, + ); case SyntaxKind.ForOfStatement: return visitForOfStatement(node as ForOfStatement, /*outermostLabeledStatement*/ undefined); case SyntaxKind.ForStatement: @@ -305,7 +312,8 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitForStatement, node as ForStatement, HierarchyFacts.IterationStatementExcludes, - HierarchyFacts.IterationStatementIncludes); + HierarchyFacts.IterationStatementIncludes, + ); case SyntaxKind.VoidExpression: return visitVoidExpression(node as VoidExpression); case SyntaxKind.Constructor: @@ -313,43 +321,50 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitConstructorDeclaration, node as ConstructorDeclaration, HierarchyFacts.ClassOrFunctionExcludes, - HierarchyFacts.ClassOrFunctionIncludes); + HierarchyFacts.ClassOrFunctionIncludes, + ); case SyntaxKind.MethodDeclaration: return doWithHierarchyFacts( visitMethodDeclaration, node as MethodDeclaration, HierarchyFacts.ClassOrFunctionExcludes, - HierarchyFacts.ClassOrFunctionIncludes); + HierarchyFacts.ClassOrFunctionIncludes, + ); case SyntaxKind.GetAccessor: return doWithHierarchyFacts( visitGetAccessorDeclaration, node as GetAccessorDeclaration, HierarchyFacts.ClassOrFunctionExcludes, - HierarchyFacts.ClassOrFunctionIncludes); + HierarchyFacts.ClassOrFunctionIncludes, + ); case SyntaxKind.SetAccessor: return doWithHierarchyFacts( visitSetAccessorDeclaration, node as SetAccessorDeclaration, HierarchyFacts.ClassOrFunctionExcludes, - HierarchyFacts.ClassOrFunctionIncludes); + HierarchyFacts.ClassOrFunctionIncludes, + ); case SyntaxKind.FunctionDeclaration: return doWithHierarchyFacts( visitFunctionDeclaration, node as FunctionDeclaration, HierarchyFacts.ClassOrFunctionExcludes, - HierarchyFacts.ClassOrFunctionIncludes); + HierarchyFacts.ClassOrFunctionIncludes, + ); case SyntaxKind.FunctionExpression: return doWithHierarchyFacts( visitFunctionExpression, node as FunctionExpression, HierarchyFacts.ClassOrFunctionExcludes, - HierarchyFacts.ClassOrFunctionIncludes); + HierarchyFacts.ClassOrFunctionIncludes, + ); case SyntaxKind.ArrowFunction: return doWithHierarchyFacts( visitArrowFunction, node as ArrowFunction, HierarchyFacts.ArrowFunctionExcludes, - HierarchyFacts.ArrowFunctionIncludes); + HierarchyFacts.ArrowFunctionIncludes, + ); case SyntaxKind.Parameter: return visitParameter(node as ParameterDeclaration); case SyntaxKind.ExpressionStatement: @@ -359,12 +374,18 @@ export function transformES2018(context: TransformationContext): (x: SourceFile case SyntaxKind.TaggedTemplateExpression: return visitTaggedTemplateExpression(node as TaggedTemplateExpression); case SyntaxKind.PropertyAccessExpression: - if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) { + if ( + capturedSuperProperties && isPropertyAccessExpression(node) + && node.expression.kind === SyntaxKind.SuperKeyword + ) { capturedSuperProperties.add(node.name.escapedText); } return visitEachChild(node, visitor, context); case SyntaxKind.ElementAccessExpression: - if (capturedSuperProperties && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword) { + if ( + capturedSuperProperties + && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword + ) { hasSuperElementAccess = true; } return visitEachChild(node, visitor, context); @@ -374,7 +395,8 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitDefault, node, HierarchyFacts.ClassOrFunctionExcludes, - HierarchyFacts.ClassOrFunctionIncludes); + HierarchyFacts.ClassOrFunctionIncludes, + ); default: return visitEachChild(node, visitor, context); } @@ -384,10 +406,13 @@ export function transformES2018(context: TransformationContext): (x: SourceFile if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { return setOriginalNode( setTextRange( - factory.createYieldExpression(/*asteriskToken*/ undefined, emitHelpers().createAwaitHelper(visitNode(node.expression, visitor, isExpression))), - /*location*/ node + factory.createYieldExpression( + /*asteriskToken*/ undefined, + emitHelpers().createAwaitHelper(visitNode(node.expression, visitor, isExpression)), + ), + /*location*/ node, ), - node + node, ); } return visitEachChild(node, visitor, context); @@ -410,17 +435,17 @@ export function transformES2018(context: TransformationContext): (x: SourceFile emitHelpers().createAsyncDelegatorHelper( setTextRange( emitHelpers().createAsyncValuesHelper(expression), - expression - ) + expression, + ), ), - expression - ) - ) - ) + expression, + ), + ), + ), ), - node + node, ), - node + node, ); } @@ -431,12 +456,12 @@ export function transformES2018(context: TransformationContext): (x: SourceFile createDownlevelAwait( node.expression ? visitNode(node.expression, visitor, isExpression) - : factory.createVoidZero() - ) + : factory.createVoidZero(), + ), ), - node + node, ), - node + node, ); } @@ -445,9 +470,12 @@ export function transformES2018(context: TransformationContext): (x: SourceFile function visitReturnStatement(node: ReturnStatement) { if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { - return factory.updateReturnStatement(node, createDownlevelAwait( - node.expression ? visitNode(node.expression, visitor, isExpression) : factory.createVoidZero() - )); + return factory.updateReturnStatement( + node, + createDownlevelAwait( + node.expression ? visitNode(node.expression, visitor, isExpression) : factory.createVoidZero(), + ), + ); } return visitEachChild(node, visitor, context); @@ -477,9 +505,12 @@ export function transformES2018(context: TransformationContext): (x: SourceFile objects.push(visitNode(target, visitor, isExpression)); } else { - chunkObject = append(chunkObject, e.kind === SyntaxKind.PropertyAssignment - ? factory.createPropertyAssignment(e.name, visitNode(e.initializer, visitor, isExpression)) - : visitNode(e, visitor, isObjectLiteralElementLike)); + chunkObject = append( + chunkObject, + e.kind === SyntaxKind.PropertyAssignment + ? factory.createPropertyAssignment(e.name, visitNode(e.initializer, visitor, isExpression)) + : visitNode(e, visitor, isObjectLiteralElementLike), + ); } } if (chunkObject) { @@ -538,23 +569,35 @@ export function transformES2018(context: TransformationContext): (x: SourceFile * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the * expression of an `ExpressionStatement`). */ - function visitParenthesizedExpression(node: ParenthesizedExpression, expressionResultIsUnused: boolean): ParenthesizedExpression { + function visitParenthesizedExpression( + node: ParenthesizedExpression, + expressionResultIsUnused: boolean, + ): ParenthesizedExpression { return visitEachChild(node, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, context); } function visitSourceFile(node: SourceFile): SourceFile { const ancestorFacts = enterSubtree( HierarchyFacts.SourceFileExcludes, - isEffectiveStrictModeSourceFile(node, compilerOptions) ? - HierarchyFacts.StrictModeSourceFileIncludes : - HierarchyFacts.SourceFileIncludes); + isEffectiveStrictModeSourceFile(node, compilerOptions) + ? HierarchyFacts.StrictModeSourceFileIncludes + : HierarchyFacts.SourceFileIncludes, + ); exportedVariableStatement = false; const visited = visitEachChild(node, visitor, context); - const statement = concatenate(visited.statements, taggedTemplateStringDeclarations && [ - factory.createVariableStatement(/*modifiers*/ undefined, - factory.createVariableDeclarationList(taggedTemplateStringDeclarations)) - ]); - const result = factory.updateSourceFile(visited, setTextRange(factory.createNodeArray(statement), node.statements)); + const statement = concatenate( + visited.statements, + taggedTemplateStringDeclarations && [ + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList(taggedTemplateStringDeclarations), + ), + ], + ); + const result = factory.updateSourceFile( + visited, + setTextRange(factory.createNodeArray(statement), node.statements), + ); exitSubtree(ancestorFacts); return result; } @@ -566,7 +609,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitor, currentSourceFile, recordTaggedTemplateString, - ProcessLevel.LiftRestriction + ProcessLevel.LiftRestriction, ); } @@ -584,7 +627,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitor, context, FlattenLevel.ObjectRest, - !expressionResultIsUnused + !expressionResultIsUnused, ); } if (node.operatorToken.kind === SyntaxKind.CommaToken) { @@ -592,7 +635,11 @@ export function transformES2018(context: TransformationContext): (x: SourceFile node, visitNode(node.left, visitorWithUnusedExpressionResult, isExpression), node.operatorToken, - visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression) + visitNode( + node.right, + expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, + isExpression, + ), ); } return visitEachChild(node, visitor, context); @@ -609,7 +656,11 @@ export function transformES2018(context: TransformationContext): (x: SourceFile let result: Expression[] | undefined; for (let i = 0; i < node.elements.length; i++) { const element = node.elements[i]; - const visited = visitNode(element, i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, isExpression); + const visited = visitNode( + element, + i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, + isExpression, + ); if (result || visited !== element) { result ||= node.elements.slice(0, i); result.push(visited); @@ -620,11 +671,19 @@ export function transformES2018(context: TransformationContext): (x: SourceFile } function visitCatchClause(node: CatchClause) { - if (node.variableDeclaration && - isBindingPattern(node.variableDeclaration.name) && - node.variableDeclaration.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { + if ( + node.variableDeclaration + && isBindingPattern(node.variableDeclaration.name) + && node.variableDeclaration.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread + ) { const name = factory.getGeneratedNameForNode(node.variableDeclaration.name); - const updatedDecl = factory.updateVariableDeclaration(node.variableDeclaration, node.variableDeclaration.name, /*exclamationToken*/ undefined, /*type*/ undefined, name); + const updatedDecl = factory.updateVariableDeclaration( + node.variableDeclaration, + node.variableDeclaration.name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + name, + ); const visitedBindings = flattenDestructuringBinding(updatedDecl, visitor, context, FlattenLevel.ObjectRest); let block = visitNode(node.block, visitor, isBlock); if (some(visitedBindings)) { @@ -635,8 +694,15 @@ export function transformES2018(context: TransformationContext): (x: SourceFile } return factory.updateCatchClause( node, - factory.updateVariableDeclaration(node.variableDeclaration, name, /*exclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined), - block); + factory.updateVariableDeclaration( + node.variableDeclaration, + name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined, + ), + block, + ); } return visitEachChild(node, visitor, context); } @@ -668,7 +734,10 @@ export function transformES2018(context: TransformationContext): (x: SourceFile return visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ false); } - function visitVariableDeclarationWorker(node: VariableDeclaration, exportedVariableStatement: boolean): VisitResult { + function visitVariableDeclarationWorker( + node: VariableDeclaration, + exportedVariableStatement: boolean, + ): VisitResult { // If we are here it is because the name contains a binding pattern with a rest somewhere in it. if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { return flattenDestructuringBinding( @@ -677,7 +746,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile context, FlattenLevel.ObjectRest, /*rval*/ undefined, - exportedVariableStatement + exportedVariableStatement, ); } return visitEachChild(node, visitor, context); @@ -689,7 +758,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitNode(node.initializer, visitorWithUnusedExpressionResult, isForInitializer), visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, visitorWithUnusedExpressionResult, isExpression), - visitIterationBody(node.statement, visitor, context) + visitIterationBody(node.statement, visitor, context), ); } @@ -702,15 +771,23 @@ export function transformES2018(context: TransformationContext): (x: SourceFile * * @param node A ForOfStatement. */ - function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult { - const ancestorFacts = enterSubtree(HierarchyFacts.IterationStatementExcludes, HierarchyFacts.IterationStatementIncludes); - if (node.initializer.transformFlags & TransformFlags.ContainsObjectRestOrSpread || - isAssignmentPattern(node.initializer) && containsObjectRestOrSpread(node.initializer)) { + function visitForOfStatement( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ): VisitResult { + const ancestorFacts = enterSubtree( + HierarchyFacts.IterationStatementExcludes, + HierarchyFacts.IterationStatementIncludes, + ); + if ( + node.initializer.transformFlags & TransformFlags.ContainsObjectRestOrSpread + || isAssignmentPattern(node.initializer) && containsObjectRestOrSpread(node.initializer) + ) { node = transformForOfStatementWithObjectRest(node); } - const result = node.awaitModifier ? - transformForAwaitOfStatement(node, outermostLabeledStatement, ancestorFacts) : - factory.restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement); + const result = node.awaitModifier + ? transformForAwaitOfStatement(node, outermostLabeledStatement, ancestorFacts) + : factory.restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement); exitSubtree(ancestorFacts); return result; } @@ -738,20 +815,20 @@ export function transformES2018(context: TransformationContext): (x: SourceFile setTextRange( factory.createVariableDeclarationList( [ - setTextRange(factory.createVariableDeclaration(temp), node.initializer) + setTextRange(factory.createVariableDeclaration(temp), node.initializer), ], - NodeFlags.Let + NodeFlags.Let, ), - node.initializer + node.initializer, ), node.expression, setTextRange( factory.createBlock( setTextRange(factory.createNodeArray(statements), statementsLocation), - /*multiLine*/ true + /*multiLine*/ true, ), - bodyLocation - ) + bodyLocation, + ), ); } return node; @@ -786,9 +863,9 @@ export function transformES2018(context: TransformationContext): (x: SourceFile return setTextRange( factory.createBlock( setTextRange(factory.createNodeArray(statements), statementsLocation), - /*multiLine*/ true + /*multiLine*/ true, ), - bodyLocation + bodyLocation, ); } @@ -798,17 +875,27 @@ export function transformES2018(context: TransformationContext): (x: SourceFile : factory.createAwaitExpression(expression); } - function transformForAwaitOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts) { + function transformForAwaitOfStatement( + node: ForOfStatement, + outermostLabeledStatement: LabeledStatement | undefined, + ancestorFacts: HierarchyFacts, + ) { const expression = visitNode(node.expression, visitor, isExpression); - const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined); - const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) : factory.createTempVariable(/*recordTempVariable*/ undefined); + const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) + : factory.createTempVariable(/*recordTempVariable*/ undefined); + const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) + : factory.createTempVariable(/*recordTempVariable*/ undefined); const nonUserCode = factory.createTempVariable(/*recordTempVariable*/ undefined); const done = factory.createTempVariable(hoistVariableDeclaration); const errorRecord = factory.createUniqueName("e"); const catchVariable = factory.getGeneratedNameForNode(errorRecord); const returnMethod = factory.createTempVariable(/*recordTempVariable*/ undefined); const callValues = setTextRange(emitHelpers().createAsyncValuesHelper(expression), node.expression); - const callNext = factory.createCallExpression(factory.createPropertyAccessExpression(iterator, "next"), /*typeArguments*/ undefined, []); + const callNext = factory.createCallExpression( + factory.createPropertyAccessExpression(iterator, "next"), + /*typeArguments*/ undefined, + [], + ); const getDone = factory.createPropertyAccessExpression(result, "done"); const getValue = factory.createPropertyAccessExpression(result, "value"); const callReturn = factory.createFunctionCallCall(returnMethod, iterator, []); @@ -817,9 +904,9 @@ export function transformES2018(context: TransformationContext): (x: SourceFile hoistVariableDeclaration(returnMethod); // if we are enclosed in an outer loop ensure we reset 'errorRecord' per each iteration - const initializer = ancestorFacts & HierarchyFacts.IterationContainer ? - factory.inlineExpressions([factory.createAssignment(errorRecord, factory.createVoidZero()), callValues]) : - callValues; + const initializer = ancestorFacts & HierarchyFacts.IterationContainer + ? factory.inlineExpressions([factory.createAssignment(errorRecord, factory.createVoidZero()), callValues]) + : callValues; const forStatement = setEmitFlags( setTextRange( @@ -827,25 +914,38 @@ export function transformES2018(context: TransformationContext): (x: SourceFile /*initializer*/ setEmitFlags( setTextRange( factory.createVariableDeclarationList([ - factory.createVariableDeclaration(nonUserCode, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createTrue()), - setTextRange(factory.createVariableDeclaration(iterator, /*exclamationToken*/ undefined, /*type*/ undefined, initializer), node.expression), - factory.createVariableDeclaration(result) + factory.createVariableDeclaration( + nonUserCode, + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createTrue(), + ), + setTextRange( + factory.createVariableDeclaration( + iterator, + /*exclamationToken*/ undefined, + /*type*/ undefined, + initializer, + ), + node.expression, + ), + factory.createVariableDeclaration(result), ]), - node.expression + node.expression, ), - EmitFlags.NoHoisting + EmitFlags.NoHoisting, ), /*condition*/ factory.inlineExpressions([ factory.createAssignment(result, createDownlevelAwait(callNext)), factory.createAssignment(done, getDone), - factory.createLogicalNot(done) + factory.createLogicalNot(done), ]), /*incrementor*/ factory.createAssignment(nonUserCode, factory.createTrue()), - /*statement*/ convertForOfStatementHead(node, getValue, nonUserCode) + /*statement*/ convertForOfStatementHead(node, getValue, nonUserCode), ), - /*location*/ node + /*location*/ node, ), - EmitFlags.NoTokenTrailingSourceMaps + EmitFlags.NoTokenTrailingSourceMaps, ); setOriginalNode(forStatement, node); @@ -853,8 +953,8 @@ export function transformES2018(context: TransformationContext): (x: SourceFile factory.createBlock([ factory.restoreEnclosingLabel( forStatement, - outermostLabeledStatement - ) + outermostLabeledStatement, + ), ]), factory.createCatchClause( factory.createVariableDeclaration(catchVariable), @@ -864,13 +964,13 @@ export function transformES2018(context: TransformationContext): (x: SourceFile factory.createAssignment( errorRecord, factory.createObjectLiteralExpression([ - factory.createPropertyAssignment("error", catchVariable) - ]) - ) - ) + factory.createPropertyAssignment("error", catchVariable), + ]), + ), + ), ]), - EmitFlags.SingleLine - ) + EmitFlags.SingleLine, + ), ), factory.createBlock([ factory.createTryStatement( @@ -884,13 +984,13 @@ export function transformES2018(context: TransformationContext): (x: SourceFile ), factory.createAssignment( returnMethod, - factory.createPropertyAccessExpression(iterator, "return") - ) + factory.createPropertyAccessExpression(iterator, "return"), + ), ), - factory.createExpressionStatement(createDownlevelAwait(callReturn)) + factory.createExpressionStatement(createDownlevelAwait(callReturn)), ), - EmitFlags.SingleLine - ) + EmitFlags.SingleLine, + ), ]), /*catchClause*/ undefined, /*finallyBlock*/ setEmitFlags( @@ -899,16 +999,16 @@ export function transformES2018(context: TransformationContext): (x: SourceFile factory.createIfStatement( errorRecord, factory.createThrowStatement( - factory.createPropertyAccessExpression(errorRecord, "error") - ) + factory.createPropertyAccessExpression(errorRecord, "error"), + ), ), - EmitFlags.SingleLine - ) + EmitFlags.SingleLine, + ), ]), - EmitFlags.SingleLine - ) - ) - ]) + EmitFlags.SingleLine, + ), + ), + ]), ); } @@ -926,7 +1026,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile isBindingPattern(node.name) ? factory.getGeneratedNameForNode(node) : node.name, /*questionToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined + /*initializer*/ undefined, ); } if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { @@ -939,7 +1039,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile factory.getGeneratedNameForNode(node), /*questionToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression) + visitNode(node.initializer, visitor, isExpression), ); } return visitEachChild(node, visitor, context); @@ -967,7 +1067,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile node, node.modifiers, visitParameterList(node.parameters, parameterVisitor, context), - transformFunctionBody(node) + transformFunctionBody(node), ); enclosingFunctionFlags = savedEnclosingFunctionFlags; parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; @@ -985,7 +1085,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitNode(node.name, visitor, isPropertyName), visitParameterList(node.parameters, parameterVisitor, context), /*type*/ undefined, - transformFunctionBody(node) + transformFunctionBody(node), ); enclosingFunctionFlags = savedEnclosingFunctionFlags; parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; @@ -1002,7 +1102,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile node.modifiers, visitNode(node.name, visitor, isPropertyName), visitParameterList(node.parameters, parameterVisitor, context), - transformFunctionBody(node) + transformFunctionBody(node), ); enclosingFunctionFlags = savedEnclosingFunctionFlags; parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; @@ -1029,7 +1129,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile /*type*/ undefined, enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ? transformAsyncGeneratorFunctionBody(node) - : transformFunctionBody(node) + : transformFunctionBody(node), ); enclosingFunctionFlags = savedEnclosingFunctionFlags; parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; @@ -1055,7 +1155,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile /*type*/ undefined, enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ? transformAsyncGeneratorFunctionBody(node) - : transformFunctionBody(node) + : transformFunctionBody(node), ); enclosingFunctionFlags = savedEnclosingFunctionFlags; parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; @@ -1100,17 +1200,24 @@ export function transformES2018(context: TransformationContext): (x: SourceFile /*type*/ undefined, enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator ? transformAsyncGeneratorFunctionBody(node) - : transformFunctionBody(node) + : transformFunctionBody(node), ); enclosingFunctionFlags = savedEnclosingFunctionFlags; parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; return updated; } - function transformAsyncGeneratorFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody { + function transformAsyncGeneratorFunctionBody( + node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression, + ): FunctionBody { resumeLexicalEnvironment(); const statements: Statement[] = []; - const statementOffset = factory.copyPrologue(node.body!.statements, statements, /*ensureUseStrict*/ false, visitor); + const statementOffset = factory.copyPrologue( + node.body!.statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); appendObjectRestAssignmentsIfNeeded(statements, node); const savedCapturedSuperProperties = capturedSuperProperties; @@ -1129,20 +1236,28 @@ export function transformES2018(context: TransformationContext): (x: SourceFile /*type*/ undefined, factory.updateBlock( node.body!, - visitLexicalEnvironment(node.body!.statements, visitor, context, statementOffset) - ) + visitLexicalEnvironment(node.body!.statements, visitor, context, statementOffset), + ), ), - !!(hierarchyFacts & HierarchyFacts.HasLexicalThis) - ) + !!(hierarchyFacts & HierarchyFacts.HasLexicalThis), + ), ); // Minor optimization, emit `_super` helper to capture `super` access in an arrow. // This step isn't needed if we eventually transform this to ES5. - const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync); + const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 + && resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync + | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync); if (emitSuperHelpers) { enableSubstitutionForAsyncMethodsWithSuper(); - const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties); + const variableStatement = createSuperAccessVariableStatement( + factory, + resolver, + node, + capturedSuperProperties, + ); substitutedSuperAccessors[getNodeId(variableStatement)] = true; insertStatementsAfterStandardPrologue(statements, [variableStatement]); } @@ -1167,7 +1282,14 @@ export function transformES2018(context: TransformationContext): (x: SourceFile return block; } - function transformFunctionBody(node: FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | AccessorDeclaration): FunctionBody; + function transformFunctionBody( + node: + | FunctionDeclaration + | FunctionExpression + | ConstructorDeclaration + | MethodDeclaration + | AccessorDeclaration, + ): FunctionBody; function transformFunctionBody(node: ArrowFunction): ConciseBody; function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody { resumeLexicalEnvironment(); @@ -1189,7 +1311,10 @@ export function transformES2018(context: TransformationContext): (x: SourceFile return body; } - function appendObjectRestAssignmentsIfNeeded(statements: Statement[] | undefined, node: FunctionLikeDeclaration): Statement[] | undefined { + function appendObjectRestAssignmentsIfNeeded( + statements: Statement[] | undefined, + node: FunctionLikeDeclaration, + ): Statement[] | undefined { let containsPrecedingObjectRestOrSpread = false; for (const parameter of node.parameters) { if (containsPrecedingObjectRestOrSpread) { @@ -1205,7 +1330,8 @@ export function transformES2018(context: TransformationContext): (x: SourceFile visitor, context, FlattenLevel.All, - factory.getGeneratedNameForNode(parameter)); + factory.getGeneratedNameForNode(parameter), + ); if (some(declarations)) { const declarationList = factory.createVariableDeclarationList(declarations); const statement = factory.createVariableStatement(/*modifiers*/ undefined, declarationList); @@ -1246,13 +1372,21 @@ export function transformES2018(context: TransformationContext): (x: SourceFile const block = factory.createBlock([factory.createExpressionStatement(assignment)]); setTextRange(block, parameter); - setEmitFlags(block, EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments); + setEmitFlags( + block, + EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps + | EmitFlags.NoComments, + ); const typeCheck = factory.createTypeCheck(factory.cloneNode(parameter.name), "undefined"); const statement = factory.createIfStatement(typeCheck, block); startOnNewLine(statement); setTextRange(statement, parameter); - setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue | EmitFlags.NoComments); + setEmitFlags( + statement, + EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue + | EmitFlags.NoComments, + ); statements = append(statements, statement); } } @@ -1310,7 +1444,9 @@ export function transformES2018(context: TransformationContext): (x: SourceFile // If we need to support substitutions for `super` in an async method, // we should track it here. if (enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) { - const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAccessInAsync | NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync); + const superContainerFlags = resolver.getNodeCheckFlags(node) + & (NodeCheckFlags.MethodWithSuperPropertyAccessInAsync + | NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync); if (superContainerFlags !== enclosingSuperContainerFlags) { const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags; enclosingSuperContainerFlags = superContainerFlags; @@ -1361,9 +1497,13 @@ export function transformES2018(context: TransformationContext): (x: SourceFile if (node.expression.kind === SyntaxKind.SuperKeyword) { return setTextRange( factory.createPropertyAccessExpression( - factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), - node.name), - node + factory.createUniqueName( + "_super", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + node.name, + ), + node, ); } return node; @@ -1373,7 +1513,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile if (node.expression.kind === SyntaxKind.SuperKeyword) { return createSuperElementAccessInAsyncMethod( node.argumentExpression, - node + node, ); } return node; @@ -1390,8 +1530,8 @@ export function transformES2018(context: TransformationContext): (x: SourceFile /*typeArguments*/ undefined, [ factory.createThis(), - ...node.arguments - ] + ...node.arguments, + ], ); } return node; @@ -1406,18 +1546,21 @@ export function transformES2018(context: TransformationContext): (x: SourceFile || kind === SyntaxKind.SetAccessor; } - function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression { + function createSuperElementAccessInAsyncMethod( + argumentExpression: Expression, + location: TextRange, + ): LeftHandSideExpression { if (enclosingSuperContainerFlags & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) { return setTextRange( factory.createPropertyAccessExpression( factory.createCallExpression( factory.createIdentifier("_superIndex"), /*typeArguments*/ undefined, - [argumentExpression] + [argumentExpression], ), - "value" + "value", ), - location + location, ); } else { @@ -1425,9 +1568,9 @@ export function transformES2018(context: TransformationContext): (x: SourceFile factory.createCallExpression( factory.createIdentifier("_superIndex"), /*typeArguments*/ undefined, - [argumentExpression] + [argumentExpression], ), - location + location, ); } } diff --git a/src/compiler/transformers/es2019.ts b/src/compiler/transformers/es2019.ts index 0bd2be45422a4..0435e4c352707 100644 --- a/src/compiler/transformers/es2019.ts +++ b/src/compiler/transformers/es2019.ts @@ -43,7 +43,7 @@ export function transformES2019(context: TransformationContext): (x: SourceFile return factory.updateCatchClause( node, factory.createVariableDeclaration(factory.createTempVariable(/*recordTempVariable*/ undefined)), - visitNode(node.block, visitor, isBlock) + visitNode(node.block, visitor, isBlock), ); } return visitEachChild(node, visitor, context); diff --git a/src/compiler/transformers/es2020.ts b/src/compiler/transformers/es2020.ts index b030dca03ce5c..985fccde13555 100644 --- a/src/compiler/transformers/es2020.ts +++ b/src/compiler/transformers/es2020.ts @@ -96,17 +96,28 @@ export function transformES2020(context: TransformationContext): (x: SourceFile return { expression: chain.expression, chain: links }; } - function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean, isDelete: boolean): Expression { + function visitNonOptionalParenthesizedExpression( + node: ParenthesizedExpression, + captureThisArg: boolean, + isDelete: boolean, + ): Expression { const expression = visitNonOptionalExpression(node.expression, captureThisArg, isDelete); if (isSyntheticReference(expression)) { // `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` } // `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` } - return factory.createSyntheticReferenceExpression(factory.updateParenthesizedExpression(node, expression.expression), expression.thisArg); + return factory.createSyntheticReferenceExpression( + factory.updateParenthesizedExpression(node, expression.expression), + expression.thisArg, + ); } return factory.updateParenthesizedExpression(node, expression); } - function visitNonOptionalPropertyOrElementAccessExpression(node: AccessExpression, captureThisArg: boolean, isDelete: boolean): Expression { + function visitNonOptionalPropertyOrElementAccessExpression( + node: AccessExpression, + captureThisArg: boolean, + isDelete: boolean, + ): Expression { if (isOptionalChain(node)) { // If `node` is an optional chain, then it is the outermost chain of an optional expression. return visitOptionalExpression(node, captureThisArg, isDelete); @@ -128,7 +139,11 @@ export function transformES2020(context: TransformationContext): (x: SourceFile expression = node.kind === SyntaxKind.PropertyAccessExpression ? factory.updatePropertyAccessExpression(node, expression, visitNode(node.name, visitor, isIdentifier)) - : factory.updateElementAccessExpression(node, expression, visitNode(node.argumentExpression, visitor, isExpression)); + : factory.updateElementAccessExpression( + node, + expression, + visitNode(node.argumentExpression, visitor, isExpression), + ); return thisArg ? factory.createSyntheticReferenceExpression(expression, thisArg) : expression; } @@ -139,10 +154,17 @@ export function transformES2020(context: TransformationContext): (x: SourceFile } if (isParenthesizedExpression(node.expression) && isOptionalChain(skipParentheses(node.expression))) { // capture thisArg for calls of parenthesized optional chains like `(foo?.bar)()` - const expression = visitNonOptionalParenthesizedExpression(node.expression, /*captureThisArg*/ true, /*isDelete*/ false); + const expression = visitNonOptionalParenthesizedExpression( + node.expression, + /*captureThisArg*/ true, + /*isDelete*/ false, + ); const args = visitNodes(node.arguments, visitor, isExpression); if (isSyntheticReference(expression)) { - return setTextRange(factory.createFunctionCallCall(expression.expression, expression.thisArg, args), node); + return setTextRange( + factory.createFunctionCallCall(expression.expression, expression.thisArg, args), + node, + ); } return factory.updateCallExpression(node, expression, /*typeArguments*/ undefined, args); } @@ -151,20 +173,40 @@ export function transformES2020(context: TransformationContext): (x: SourceFile function visitNonOptionalExpression(node: Expression, captureThisArg: boolean, isDelete: boolean): Expression { switch (node.kind) { - case SyntaxKind.ParenthesizedExpression: return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg, isDelete); + case SyntaxKind.ParenthesizedExpression: + return visitNonOptionalParenthesizedExpression( + node as ParenthesizedExpression, + captureThisArg, + isDelete, + ); case SyntaxKind.PropertyAccessExpression: - case SyntaxKind.ElementAccessExpression: return visitNonOptionalPropertyOrElementAccessExpression(node as AccessExpression, captureThisArg, isDelete); - case SyntaxKind.CallExpression: return visitNonOptionalCallExpression(node as CallExpression, captureThisArg); - default: return visitNode(node, visitor, isExpression); + case SyntaxKind.ElementAccessExpression: + return visitNonOptionalPropertyOrElementAccessExpression( + node as AccessExpression, + captureThisArg, + isDelete, + ); + case SyntaxKind.CallExpression: + return visitNonOptionalCallExpression(node as CallExpression, captureThisArg); + default: + return visitNode(node, visitor, isExpression); } } function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean, isDelete: boolean): Expression { const { expression, chain } = flattenChain(node); - const left = visitNonOptionalExpression(skipPartiallyEmittedExpressions(expression), isCallChain(chain[0]), /*isDelete*/ false); + const left = visitNonOptionalExpression( + skipPartiallyEmittedExpressions(expression), + isCallChain(chain[0]), + /*isDelete*/ false, + ); let leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined; let capturedLeft = isSyntheticReference(left) ? left.expression : left; - let leftExpression = factory.restoreOuterExpressions(expression, capturedLeft, OuterExpressionKinds.PartiallyEmittedExpressions); + let leftExpression = factory.restoreOuterExpressions( + expression, + capturedLeft, + OuterExpressionKinds.PartiallyEmittedExpressions, + ); if (!isSimpleCopiableExpression(capturedLeft)) { capturedLeft = factory.createTempVariable(hoistVariableDeclaration); leftExpression = factory.createAssignment(capturedLeft, leftExpression); @@ -186,8 +228,14 @@ export function transformES2020(context: TransformationContext): (x: SourceFile } } rightExpression = segment.kind === SyntaxKind.PropertyAccessExpression - ? factory.createPropertyAccessExpression(rightExpression, visitNode(segment.name, visitor, isIdentifier)) - : factory.createElementAccessExpression(rightExpression, visitNode(segment.argumentExpression, visitor, isExpression)); + ? factory.createPropertyAccessExpression( + rightExpression, + visitNode(segment.name, visitor, isIdentifier), + ) + : factory.createElementAccessExpression( + rightExpression, + visitNode(segment.argumentExpression, visitor, isExpression), + ); break; case SyntaxKind.CallExpression: if (i === 0 && leftThisArg) { @@ -198,14 +246,14 @@ export function transformES2020(context: TransformationContext): (x: SourceFile rightExpression = factory.createFunctionCallCall( rightExpression, leftThisArg.kind === SyntaxKind.SuperKeyword ? factory.createThis() : leftThisArg, - visitNodes(segment.arguments, visitor, isExpression) + visitNodes(segment.arguments, visitor, isExpression), ); } else { rightExpression = factory.createCallExpression( rightExpression, /*typeArguments*/ undefined, - visitNodes(segment.arguments, visitor, isExpression) + visitNodes(segment.arguments, visitor, isExpression), ); } break; @@ -214,8 +262,20 @@ export function transformES2020(context: TransformationContext): (x: SourceFile } const target = isDelete - ? factory.createConditionalExpression(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), /*questionToken*/ undefined, factory.createTrue(), /*colonToken*/ undefined, factory.createDeleteExpression(rightExpression)) - : factory.createConditionalExpression(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), /*questionToken*/ undefined, factory.createVoidZero(), /*colonToken*/ undefined, rightExpression); + ? factory.createConditionalExpression( + createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), + /*questionToken*/ undefined, + factory.createTrue(), + /*colonToken*/ undefined, + factory.createDeleteExpression(rightExpression), + ) + : factory.createConditionalExpression( + createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), + /*questionToken*/ undefined, + factory.createVoidZero(), + /*colonToken*/ undefined, + rightExpression, + ); setTextRange(target, node); return thisArg ? factory.createSyntheticReferenceExpression(target, thisArg) : target; } @@ -224,15 +284,19 @@ export function transformES2020(context: TransformationContext): (x: SourceFile return factory.createBinaryExpression( factory.createBinaryExpression( left, - factory.createToken(invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken), - factory.createNull() + factory.createToken( + invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken, + ), + factory.createNull(), ), factory.createToken(invert ? SyntaxKind.BarBarToken : SyntaxKind.AmpersandAmpersandToken), factory.createBinaryExpression( right, - factory.createToken(invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken), - factory.createVoidZero() - ) + factory.createToken( + invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken, + ), + factory.createVoidZero(), + ), ); } @@ -243,18 +307,24 @@ export function transformES2020(context: TransformationContext): (x: SourceFile right = factory.createTempVariable(hoistVariableDeclaration); left = factory.createAssignment(right, left); } - return setTextRange(factory.createConditionalExpression( - createNotNullCondition(left, right), - /*questionToken*/ undefined, - right, - /*colonToken*/ undefined, - visitNode(node.right, visitor, isExpression), - ), node); + return setTextRange( + factory.createConditionalExpression( + createNotNullCondition(left, right), + /*questionToken*/ undefined, + right, + /*colonToken*/ undefined, + visitNode(node.right, visitor, isExpression), + ), + node, + ); } function visitDeleteExpression(node: DeleteExpression) { return isOptionalChain(skipParentheses(node.expression)) - ? setOriginalNode(visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), node) + ? setOriginalNode( + visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), + node, + ) : factory.updateDeleteExpression(node, visitNode(node.expression, visitor, isExpression)); } } diff --git a/src/compiler/transformers/es2021.ts b/src/compiler/transformers/es2021.ts index b2fbd0fbe71b2..13fc315f6d70e 100644 --- a/src/compiler/transformers/es2021.ts +++ b/src/compiler/transformers/es2021.ts @@ -25,7 +25,7 @@ import { export function transformES2021(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle { const { hoistVariableDeclaration, - factory + factory, } = context; return chainBundle(context, transformSourceFile); @@ -47,7 +47,9 @@ export function transformES2021(context: TransformationContext): (x: SourceFile return visitEachChild(node, visitor, context); } - function transformLogicalAssignment(binaryExpression: AssignmentExpression>): VisitResult { + function transformLogicalAssignment( + binaryExpression: AssignmentExpression>, + ): VisitResult { const operator = binaryExpression.operatorToken; const nonAssignmentOperator = getNonAssignmentOperatorForCompoundAssignment(operator.kind); let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression)); @@ -56,38 +58,39 @@ export function transformES2021(context: TransformationContext): (x: SourceFile if (isAccessExpression(left)) { const propertyAccessTargetSimpleCopiable = isSimpleCopiableExpression(left.expression); - const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression : - factory.createTempVariable(hoistVariableDeclaration); - const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression : factory.createAssignment( - propertyAccessTarget, - left.expression - ); + const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression + : factory.createTempVariable(hoistVariableDeclaration); + const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression + : factory.createAssignment( + propertyAccessTarget, + left.expression, + ); if (isPropertyAccessExpression(left)) { assignmentTarget = factory.createPropertyAccessExpression( propertyAccessTarget, - left.name + left.name, ); left = factory.createPropertyAccessExpression( propertyAccessTargetAssignment, - left.name + left.name, ); } else { const elementAccessArgumentSimpleCopiable = isSimpleCopiableExpression(left.argumentExpression); - const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression : - factory.createTempVariable(hoistVariableDeclaration); + const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression + : factory.createTempVariable(hoistVariableDeclaration); assignmentTarget = factory.createElementAccessExpression( propertyAccessTarget, - elementAccessArgument + elementAccessArgument, ); left = factory.createElementAccessExpression( propertyAccessTargetAssignment, elementAccessArgumentSimpleCopiable ? left.argumentExpression : factory.createAssignment( elementAccessArgument, - left.argumentExpression - ) + left.argumentExpression, + ), ); } } @@ -98,9 +101,9 @@ export function transformES2021(context: TransformationContext): (x: SourceFile factory.createParenthesizedExpression( factory.createAssignment( assignmentTarget, - right - ) - ) + right, + ), + ), ); } } diff --git a/src/compiler/transformers/esDecorators.ts b/src/compiler/transformers/esDecorators.ts index 3ed8995d32d17..ad12a937a5085 100644 --- a/src/compiler/transformers/esDecorators.ts +++ b/src/compiler/transformers/esDecorators.ts @@ -186,7 +186,7 @@ import { visitNodes, Visitor, VisitResult, - WrappedExpression + WrappedExpression, } from "../_namespaces/ts"; // Class/Decorator evaluation order, as it pertains to this transformer: @@ -278,8 +278,7 @@ type LexicalEnvironmentStackEntry = | ClassLexicalEnvironmentStackEntry | ClassElementLexicalEnvironmentStackEntry | OtherLexicalEnvironmentStackEntry - | PropertyNameLexicalEnvironmentStackEntry - ; + | PropertyNameLexicalEnvironmentStackEntry; /** @internal */ export function transformESDecorators(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle { @@ -344,14 +343,22 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } function exitClass() { - Debug.assert(top?.kind === "class", "Incorrect value for top.kind.", () => `Expected top.kind to be 'class' but got '${top?.kind}' instead.`); + Debug.assert( + top?.kind === "class", + "Incorrect value for top.kind.", + () => `Expected top.kind to be 'class' but got '${top?.kind}' instead.`, + ); pendingExpressions = top.savedPendingExpressions; top = top.next; updateState(); } function enterClassElement(node: ClassElement) { - Debug.assert(top?.kind === "class", "Incorrect value for top.kind.", () => `Expected top.kind to be 'class' but got '${top?.kind}' instead.`); + Debug.assert( + top?.kind === "class", + "Incorrect value for top.kind.", + () => `Expected top.kind to be 'class' but got '${top?.kind}' instead.`, + ); top = { kind: "class-element", next: top }; if (isClassStaticBlockDeclaration(node) || isPropertyDeclaration(node) && hasStaticModifier(node)) { top.classThis = top.next.classInfo?.classThis; @@ -361,20 +368,36 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } function exitClassElement() { - Debug.assert(top?.kind === "class-element", "Incorrect value for top.kind.", () => `Expected top.kind to be 'class-element' but got '${top?.kind}' instead.`); - Debug.assert(top.next?.kind === "class", "Incorrect value for top.next.kind.", () => `Expected top.next.kind to be 'class' but got '${top!.next?.kind}' instead.`); + Debug.assert( + top?.kind === "class-element", + "Incorrect value for top.kind.", + () => `Expected top.kind to be 'class-element' but got '${top?.kind}' instead.`, + ); + Debug.assert( + top.next?.kind === "class", + "Incorrect value for top.next.kind.", + () => `Expected top.next.kind to be 'class' but got '${top!.next?.kind}' instead.`, + ); top = top.next; updateState(); } function enterName() { - Debug.assert(top?.kind === "class-element", "Incorrect value for top.kind.", () => `Expected top.kind to be 'class-element' but got '${top?.kind}' instead.`); + Debug.assert( + top?.kind === "class-element", + "Incorrect value for top.kind.", + () => `Expected top.kind to be 'class-element' but got '${top?.kind}' instead.`, + ); top = { kind: "name", next: top }; updateState(); } function exitName() { - Debug.assert(top?.kind === "name", "Incorrect value for top.kind.", () => `Expected top.kind to be 'name' but got '${top?.kind}' instead.`); + Debug.assert( + top?.kind === "name", + "Incorrect value for top.kind.", + () => `Expected top.kind to be 'name' but got '${top?.kind}' instead.`, + ); top = top.next; updateState(); } @@ -392,7 +415,11 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } function exitOther() { - Debug.assert(top?.kind === "other", "Incorrect value for top.kind.", () => `Expected top.kind to be 'other' but got '${top?.kind}' instead.`); + Debug.assert( + top?.kind === "other", + "Incorrect value for top.kind.", + () => `Expected top.kind to be 'other' but got '${top?.kind}' instead.`, + ); if (top.depth > 0) { Debug.assert(!pendingExpressions); top.depth--; @@ -458,7 +485,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc return visitTaggedTemplateExpression(node as TaggedTemplateExpression); case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, /*discarded*/ false); + return visitPreOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + /*discarded*/ false, + ); case SyntaxKind.PropertyAccessExpression: return visitPropertyAccessExpression(node as PropertyAccessExpression); case SyntaxKind.ElementAccessExpression: @@ -523,7 +553,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc switch (node.kind) { case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, /*discarded*/ true); + return visitPreOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + /*discarded*/ true, + ); case SyntaxKind.BinaryExpression: return visitBinaryExpression(node as BinaryExpression, /*discarded*/ true); case SyntaxKind.CommaListExpression: @@ -536,11 +569,13 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } function getHelperVariableName(node: ClassLikeDeclaration | ClassElement) { - let declarationName = - node.name && isIdentifier(node.name) && !isGeneratedIdentifier(node.name) ? idText(node.name) : - node.name && isPrivateIdentifier(node.name) && !isGeneratedIdentifier(node.name) ? idText(node.name).slice(1) : - node.name && isStringLiteral(node.name) && isIdentifierText(node.name.text, ScriptTarget.ESNext) ? node.name.text : - isClassLike(node) ? "class" : "member"; + let declarationName = node.name && isIdentifier(node.name) && !isGeneratedIdentifier(node.name) + ? idText(node.name) + : node.name && isPrivateIdentifier(node.name) && !isGeneratedIdentifier(node.name) + ? idText(node.name).slice(1) + : node.name && isStringLiteral(node.name) && isIdentifierText(node.name.text, ScriptTarget.ESNext) + ? node.name.text + : isClassLike(node) ? "class" : "member"; if (isGetAccessor(node)) declarationName = `get_${declarationName}`; if (isSetAccessor(node)) declarationName = `set_${declarationName}`; if (node.name && isPrivateIdentifier(node.name)) declarationName = `private_${declarationName}`; @@ -549,7 +584,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } function createHelperVariable(node: ClassLikeDeclaration | ClassElement, suffix: string) { - return factory.createUniqueName(`${getHelperVariableName(node)}_${suffix}`, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes); + return factory.createUniqueName( + `${getHelperVariableName(node)}_${suffix}`, + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes, + ); } function createLet(name: Identifier, initializer?: Expression) { @@ -560,14 +598,17 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc name, /*exclamationToken*/ undefined, /*type*/ undefined, - initializer + initializer, ), - ], NodeFlags.Let) + ], NodeFlags.Let), ); } function createClassInfo(node: ClassLikeDeclaration): ClassInfo { - const metadataReference = factory.createUniqueName("_metadata", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + const metadataReference = factory.createUniqueName( + "_metadata", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); let instanceExtraInitializersName: Identifier | undefined; let staticExtraInitializersName: Identifier | undefined; let hasStaticInitializers = false; @@ -580,10 +621,16 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc for (const member of node.members) { if (isNamedClassElement(member) && nodeOrChildIsDecorated(/*useLegacyDecorators*/ false, member, node)) { if (hasStaticModifier(member)) { - staticExtraInitializersName ??= factory.createUniqueName("_staticExtraInitializers", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + staticExtraInitializersName ??= factory.createUniqueName( + "_staticExtraInitializers", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); } else { - instanceExtraInitializersName ??= factory.createUniqueName("_instanceExtraInitializers", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + instanceExtraInitializersName ??= factory.createUniqueName( + "_instanceExtraInitializers", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); } } if (isClassStaticBlockDeclaration(member)) { @@ -593,23 +640,28 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } else if (isPropertyDeclaration(member)) { if (hasStaticModifier(member)) { - hasStaticInitializers ||= (!!member.initializer || hasDecorators(member)); + hasStaticInitializers ||= !!member.initializer || hasDecorators(member); } else { hasNonAmbientInstanceFields ||= !isAmbientPropertyDeclaration(member); } } - if ((isPrivateIdentifierClassElementDeclaration(member) || isAutoAccessorPropertyDeclaration(member)) && hasStaticModifier(member)) { + if ( + (isPrivateIdentifierClassElementDeclaration(member) || isAutoAccessorPropertyDeclaration(member)) + && hasStaticModifier(member) + ) { hasStaticPrivateClassElements = true; } // exit early if possible - if (staticExtraInitializersName && - instanceExtraInitializersName && - hasStaticInitializers && - hasNonAmbientInstanceFields && - hasStaticPrivateClassElements) { + if ( + staticExtraInitializersName + && instanceExtraInitializersName + && hasStaticInitializers + && hasNonAmbientInstanceFields + && hasStaticPrivateClassElements + ) { break; } } @@ -630,11 +682,19 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // When a class has class decorators we end up transforming it into a statement that would otherwise give it an // assigned name. If the class doesn't have an assigned name, we'll give it an assigned name of `""`) - if (!classHasDeclaredOrExplicitlyAssignedName(node) && classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node)) { + if ( + !classHasDeclaredOrExplicitlyAssignedName(node) + && classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node) + ) { node = injectClassNamedEvaluationHelperBlockIfMissing(context, node, factory.createStringLiteral("")); } - const classReference = factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ false, /*ignoreAssignedName*/ true); + const classReference = factory.getLocalName( + node, + /*allowComments*/ false, + /*allowSourceMaps*/ false, + /*ignoreAssignedName*/ true, + ); const classInfo = createClassInfo(node); const classDefinitionStatements: Statement[] = []; let leadingBlockStatements: Statement[] | undefined; @@ -652,15 +712,32 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // of the mutated class. // - Since a class decorator can add extra initializers, we must define a variable to keep track of // extra initializers. - classInfo.classDecoratorsName = factory.createUniqueName("_classDecorators", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); - classInfo.classDescriptorName = factory.createUniqueName("_classDescriptor", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); - classInfo.classExtraInitializersName = factory.createUniqueName("_classExtraInitializers", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + classInfo.classDecoratorsName = factory.createUniqueName( + "_classDecorators", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); + classInfo.classDescriptorName = factory.createUniqueName( + "_classDescriptor", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); + classInfo.classExtraInitializersName = factory.createUniqueName( + "_classExtraInitializers", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); // We do not mark _classThis as FileLevel if it may be reused by class private fields, which requires the // ability access the captured `_classThis` of outer scopes. - const needsUniqueClassThis = some(node.members, member => (isPrivateIdentifierClassElementDeclaration(member) || isAutoAccessorPropertyDeclaration(member)) && hasStaticModifier(member)); - classInfo.classThis = factory.createUniqueName("_classThis", needsUniqueClassThis ? - GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes : - GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + const needsUniqueClassThis = some( + node.members, + member => + (isPrivateIdentifierClassElementDeclaration(member) || isAutoAccessorPropertyDeclaration(member)) + && hasStaticModifier(member), + ); + classInfo.classThis = factory.createUniqueName( + "_classThis", + needsUniqueClassThis + ? GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.ReservedInNestedScopes + : GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); classDefinitionStatements.push( createLet(classInfo.classDecoratorsName, factory.createArrayLiteralExpression(classDecorators)), createLet(classInfo.classDescriptorName), @@ -679,19 +756,25 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc const extendsElement = extendsClause && firstOrUndefined(extendsClause.types); const extendsExpression = extendsElement && visitNode(extendsElement.expression, visitor, isExpression); if (extendsExpression) { - classInfo.classSuper = factory.createUniqueName("_classSuper", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + classInfo.classSuper = factory.createUniqueName( + "_classSuper", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); - // Ensure we do not give the class or function an assigned name due to the variable by prefixing it - // with `0, `. + // Ensure we do not give the class or function an assigned name due to the variable by prefixing it + // with `0, `. const unwrapped = skipOuterExpressions(extendsExpression); - const safeExtendsExpression = - isClassExpression(unwrapped) && !unwrapped.name || - isFunctionExpression(unwrapped) && !unwrapped.name || - isArrowFunction(unwrapped) ? - factory.createComma(factory.createNumericLiteral(0), extendsExpression) : - extendsExpression; + const safeExtendsExpression = isClassExpression(unwrapped) && !unwrapped.name + || isFunctionExpression(unwrapped) && !unwrapped.name + || isArrowFunction(unwrapped) + ? factory.createComma(factory.createNumericLiteral(0), extendsExpression) + : extendsExpression; classDefinitionStatements.push(createLet(classInfo.classSuper, safeExtendsExpression)); - const updatedExtendsElement = factory.updateExpressionWithTypeArguments(extendsElement, classInfo.classSuper, /*typeArguments*/ undefined); + const updatedExtendsElement = factory.updateExpressionWithTypeArguments( + extendsElement, + classInfo.classSuper, + /*typeArguments*/ undefined, + ); const updatedExtendsClause = factory.updateHeritageClause(extendsClause, [updatedExtendsElement]); heritageClauses = factory.createNodeArray([updatedExtendsClause]); } @@ -714,7 +797,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // NOTE: If there are no constructors, but there are instance initializers, a synthetic constructor is added. enterClass(classInfo); - leadingBlockStatements = append(leadingBlockStatements, createMetadata(classInfo.metadataReference, classInfo.classSuper)); + leadingBlockStatements = append( + leadingBlockStatements, + createMetadata(classInfo.metadataReference, classInfo.classSuper), + ); let members = visitNodes(node.members, classElementVisitor, isClassElement); if (pendingExpressions) { @@ -753,32 +839,39 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc const initializerStatements = prepareConstructor(node, classInfo); if (initializerStatements) { const extendsClauseElement = getEffectiveBaseTypeNode(node); - const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); + const isDerivedClass = !!(extendsClauseElement + && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); const constructorStatements: Statement[] = []; if (isDerivedClass) { const spreadArguments = factory.createSpreadElement(factory.createIdentifier("arguments")); - const superCall = factory.createCallExpression(factory.createSuper(), /*typeArguments*/ undefined, [spreadArguments]); + const superCall = factory.createCallExpression(factory.createSuper(), /*typeArguments*/ undefined, [ + spreadArguments, + ]); constructorStatements.push(factory.createExpressionStatement(superCall)); } addRange(constructorStatements, initializerStatements); const constructorBody = factory.createBlock(constructorStatements, /*multiLine*/ true); - syntheticConstructor = factory.createConstructorDeclaration(/*modifiers*/ undefined, [], constructorBody); + syntheticConstructor = factory.createConstructorDeclaration( + /*modifiers*/ undefined, + [], + constructorBody, + ); } } // Used in steps 5, 7, and 11 if (classInfo.staticExtraInitializersName) { classDefinitionStatements.push( - createLet(classInfo.staticExtraInitializersName, factory.createArrayLiteralExpression()) + createLet(classInfo.staticExtraInitializersName, factory.createArrayLiteralExpression()), ); } // Used in steps 6, 8, and during construction if (classInfo.instanceExtraInitializersName) { classDefinitionStatements.push( - createLet(classInfo.instanceExtraInitializersName, factory.createArrayLiteralExpression()) + createLet(classInfo.instanceExtraInitializersName, factory.createArrayLiteralExpression()), ); } @@ -788,7 +881,9 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc if (isStatic(member)) { classDefinitionStatements.push(createLet(memberInfo.memberDecoratorsName)); if (memberInfo.memberInitializersName) { - classDefinitionStatements.push(createLet(memberInfo.memberInitializersName, factory.createArrayLiteralExpression())); + classDefinitionStatements.push( + createLet(memberInfo.memberInitializersName, factory.createArrayLiteralExpression()), + ); } if (memberInfo.memberDescriptorName) { classDefinitionStatements.push(createLet(memberInfo.memberDescriptorName)); @@ -803,7 +898,9 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc if (!isStatic(member)) { classDefinitionStatements.push(createLet(memberInfo.memberDecoratorsName)); if (memberInfo.memberInitializersName) { - classDefinitionStatements.push(createLet(memberInfo.memberInitializersName, factory.createArrayLiteralExpression())); + classDefinitionStatements.push( + createLet(memberInfo.memberInitializersName, factory.createArrayLiteralExpression()), + ); } if (memberInfo.memberDescriptorName) { classDefinitionStatements.push(createLet(memberInfo.memberDescriptorName)); @@ -826,7 +923,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // 9. Class decorators are applied // 10. Class binding is initialized - if (classInfo.classDescriptorName && classInfo.classDecoratorsName && classInfo.classExtraInitializersName && classInfo.classThis) { + if ( + classInfo.classDescriptorName && classInfo.classDecoratorsName && classInfo.classExtraInitializersName + && classInfo.classThis + ) { leadingBlockStatements ??= []; // produces: @@ -841,7 +941,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc classInfo.classDecoratorsName, { kind: "class", name: classNameReference, metadata: classInfo.metadataReference }, factory.createNull(), - classInfo.classExtraInitializersName + classInfo.classExtraInitializersName, ); const esDecorateStatement = factory.createExpressionStatement(esDecorateHelper); setSourceMapRange(esDecorateStatement, moveRangePastDecorators(node)); @@ -849,7 +949,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // produces: // C = _classThis = _classDescriptor.value; - const classDescriptorValueReference = factory.createPropertyAccessExpression(classInfo.classDescriptorName, "value"); + const classDescriptorValueReference = factory.createPropertyAccessExpression( + classInfo.classDescriptorName, + "value", + ); const classThisAssignment = factory.createAssignment(classInfo.classThis, classDescriptorValueReference); const classReferenceAssignment = factory.createAssignment(classReference, classThisAssignment); leadingBlockStatements.push(factory.createExpressionStatement(classReferenceAssignment)); @@ -860,7 +963,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // 11. Static extra initializers are evaluated if (classInfo.staticExtraInitializersName) { - const runStaticInitializersHelper = emitHelpers().createRunInitializersHelper(renamedClassThis, classInfo.staticExtraInitializersName); + const runStaticInitializersHelper = emitHelpers().createRunInitializersHelper( + renamedClassThis, + classInfo.staticExtraInitializersName, + ); const runStaticInitializersStatement = factory.createExpressionStatement(runStaticInitializersHelper); setSourceMapRange(runStaticInitializersStatement, node.name ?? moveRangePastDecorators(node)); leadingBlockStatements = append(leadingBlockStatements, runStaticInitializersStatement); @@ -870,7 +976,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // 13. Class extra initializers are evaluated if (classInfo.classExtraInitializersName) { - const runClassInitializersHelper = emitHelpers().createRunInitializersHelper(renamedClassThis, classInfo.classExtraInitializersName); + const runClassInitializersHelper = emitHelpers().createRunInitializersHelper( + renamedClassThis, + classInfo.classExtraInitializersName, + ); const runClassInitializersStatement = factory.createExpressionStatement(runClassInitializersHelper); setSourceMapRange(runClassInitializersStatement, node.name ?? moveRangePastDecorators(node)); trailingBlockStatements = append(trailingBlockStatements, runClassInitializersStatement); @@ -889,8 +998,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // static { ... } // ... // } - const leadingStaticBlock = leadingBlockStatements && - factory.createClassStaticBlockDeclaration(factory.createBlock(leadingBlockStatements, /*multiLine*/ true)); + const leadingStaticBlock = leadingBlockStatements + && factory.createClassStaticBlockDeclaration( + factory.createBlock(leadingBlockStatements, /*multiLine*/ true), + ); if (leadingStaticBlock && shouldTransformPrivateStaticElementsInClass) { // We use `InternalEmitFlags.TransformPrivateStaticElements` as a marker on a class static block @@ -906,8 +1017,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // ... // static { ... } // } - const trailingStaticBlock = trailingBlockStatements && - factory.createClassStaticBlockDeclaration(factory.createBlock(trailingBlockStatements, /*multiLine*/ true)); + const trailingStaticBlock = trailingBlockStatements + && factory.createClassStaticBlockDeclaration( + factory.createBlock(trailingBlockStatements, /*multiLine*/ true), + ); if (leadingStaticBlock || syntheticConstructor || trailingStaticBlock) { const newMembers: ClassElement[] = []; @@ -965,14 +1078,26 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // return C; // })(); - classExpression = factory.createClassExpression(/*modifiers*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, heritageClauses, members); + classExpression = factory.createClassExpression( + /*modifiers*/ undefined, + /*name*/ undefined, + /*typeParameters*/ undefined, + heritageClauses, + members, + ); if (classInfo.classThis) { classExpression = injectClassThisAssignmentIfMissing(factory, classExpression, classInfo.classThis); } - const classReferenceDeclaration = factory.createVariableDeclaration(classReference, /*exclamationToken*/ undefined, /*type*/ undefined, classExpression); + const classReferenceDeclaration = factory.createVariableDeclaration( + classReference, + /*exclamationToken*/ undefined, + /*type*/ undefined, + classExpression, + ); const classReferenceVarDeclList = factory.createVariableDeclarationList([classReferenceDeclaration]); - const returnExpr = classInfo.classThis ? factory.createAssignment(classReference, classInfo.classThis) : classReference; + const returnExpr = classInfo.classThis ? factory.createAssignment(classReference, classInfo.classThis) + : classReference; classDefinitionStatements.push( factory.createVariableStatement(/*modifiers*/ undefined, classReferenceVarDeclList), factory.createReturnStatement(returnExpr), @@ -981,33 +1106,45 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc else { // produces: // return ; - classExpression = factory.createClassExpression(/*modifiers*/ undefined, node.name, /*typeParameters*/ undefined, heritageClauses, members); + classExpression = factory.createClassExpression( + /*modifiers*/ undefined, + node.name, + /*typeParameters*/ undefined, + heritageClauses, + members, + ); classDefinitionStatements.push(factory.createReturnStatement(classExpression)); } if (shouldTransformPrivateStaticElementsInClass) { addInternalEmitFlags(classExpression, InternalEmitFlags.TransformPrivateStaticElements); for (const member of classExpression.members) { - if ((isPrivateIdentifierClassElementDeclaration(member) || isAutoAccessorPropertyDeclaration(member)) && hasStaticModifier(member)) { + if ( + (isPrivateIdentifierClassElementDeclaration(member) || isAutoAccessorPropertyDeclaration(member)) + && hasStaticModifier(member) + ) { addInternalEmitFlags(member, InternalEmitFlags.TransformPrivateStaticElements); } } } setOriginalNode(classExpression, node); - return factory.createImmediatelyInvokedArrowFunction(factory.mergeLexicalEnvironment(classDefinitionStatements, lexicalEnvironment)); + return factory.createImmediatelyInvokedArrowFunction( + factory.mergeLexicalEnvironment(classDefinitionStatements, lexicalEnvironment), + ); } function isDecoratedClassLike(node: ClassLikeDeclaration) { - return classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node) || - childIsDecorated(/*useLegacyDecorators*/ false, node); + return classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, node) + || childIsDecorated(/*useLegacyDecorators*/ false, node); } function visitClassDeclaration(node: ClassDeclaration): VisitResult { if (isDecoratedClassLike(node)) { const statements: Statement[] = []; const originalClass = getOriginalNode(node, isClassLike) ?? node; - const className = originalClass.name ? factory.createStringLiteralFromNode(originalClass.name) : factory.createStringLiteral("default"); + const className = originalClass.name ? factory.createStringLiteralFromNode(originalClass.name) + : factory.createStringLiteral("default"); const isExport = hasSyntacticModifier(node, ModifierFlags.Export); const isDefault = hasSyntacticModifier(node, ModifierFlags.Default); if (!node.name) { @@ -1018,7 +1155,12 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc if (node.name) { // let C = (() => { ... })(); // export default C; - const varDecl = factory.createVariableDeclaration(factory.getLocalName(node), /*exclamationToken*/ undefined, /*type*/ undefined, iife); + const varDecl = factory.createVariableDeclaration( + factory.getLocalName(node), + /*exclamationToken*/ undefined, + /*type*/ undefined, + iife, + ); setOriginalNode(varDecl, node); const varDecls = factory.createVariableDeclarationList([varDecl], NodeFlags.Let); @@ -1044,10 +1186,16 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // let C = (() => { ... })(); Debug.assertIsDefined(node.name, "A class declaration that is not a default export must have a name."); const iife = transformClassLike(node); - const modifierVisitorNoExport = isExport ? ((node: ModifierLike) => isExportModifier(node) ? undefined : modifierVisitor(node)) : modifierVisitor; + const modifierVisitorNoExport = isExport ? ((node: ModifierLike) => + isExportModifier(node) ? undefined : modifierVisitor(node)) : modifierVisitor; const modifiers = visitNodes(node.modifiers, modifierVisitorNoExport, isModifier); const declName = factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); - const varDecl = factory.createVariableDeclaration(declName, /*exclamationToken*/ undefined, /*type*/ undefined, iife); + const varDecl = factory.createVariableDeclaration( + declName, + /*exclamationToken*/ undefined, + /*type*/ undefined, + iife, + ); setOriginalNode(varDecl, node); const varDecls = factory.createVariableDeclarationList([varDecl], NodeFlags.Let); @@ -1070,7 +1218,14 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc enterClass(/*classInfo*/ undefined); const members = visitNodes(node.members, classElementVisitor, isClassElement); exitClass(); - return factory.updateClassDeclaration(node, modifiers, node.name, /*typeParameters*/ undefined, heritageClauses, members); + return factory.updateClassDeclaration( + node, + modifiers, + node.name, + /*typeParameters*/ undefined, + heritageClauses, + members, + ); } } @@ -1086,7 +1241,14 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc enterClass(/*classInfo*/ undefined); const members = visitNodes(node.members, classElementVisitor, isClassElement); exitClass(); - return factory.updateClassExpression(node, modifiers, node.name, /*typeParameters*/ undefined, heritageClauses, members); + return factory.updateClassExpression( + node, + modifiers, + node.name, + /*typeParameters*/ undefined, + heritageClauses, + members, + ); } } @@ -1104,19 +1266,29 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc factory.createExpressionStatement( emitHelpers().createRunInitializersHelper( factory.createThis(), - classInfo.instanceExtraInitializersName - ) - ) + classInfo.instanceExtraInitializersName, + ), + ), ); return statements; } } - function transformConstructorBodyWorker(statementsOut: Statement[], statementsIn: NodeArray, statementOffset: number, superPath: readonly number[], superPathDepth: number, initializerStatements: readonly Statement[]) { + function transformConstructorBodyWorker( + statementsOut: Statement[], + statementsIn: NodeArray, + statementOffset: number, + superPath: readonly number[], + superPathDepth: number, + initializerStatements: readonly Statement[], + ) { const superStatementIndex = superPath[superPathDepth]; const superStatement = statementsIn[superStatementIndex]; - addRange(statementsOut, visitNodes(statementsIn, visitor, isStatement, statementOffset, superStatementIndex - statementOffset)); + addRange( + statementsOut, + visitNodes(statementsIn, visitor, isStatement, statementOffset, superStatementIndex - statementOffset), + ); if (isTryStatement(superStatement)) { const tryBlockStatements: Statement[] = []; @@ -1126,7 +1298,8 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc /*statementOffset*/ 0, superPath, superPathDepth + 1, - initializerStatements); + initializerStatements, + ); const tryBlockStatementsArray = factory.createNodeArray(tryBlockStatements); setTextRange(tryBlockStatementsArray, superStatement.tryBlock.statements); @@ -1135,7 +1308,8 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc superStatement, factory.updateBlock(superStatement.tryBlock, tryBlockStatements), visitNode(superStatement.catchClause, visitor, isCatchClause), - visitNode(superStatement.finallyBlock, visitor, isBlock))); + visitNode(superStatement.finallyBlock, visitor, isBlock), + )); } else { addRange(statementsOut, visitNodes(statementsIn, visitor, isStatement, superStatementIndex, 1)); @@ -1155,10 +1329,22 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc const initializerStatements = prepareConstructor(classInfo.class, classInfo); if (initializerStatements) { const statements: Statement[] = []; - const nonPrologueStart = factory.copyPrologue(node.body.statements, statements, /*ensureUseStrict*/ false, visitor); + const nonPrologueStart = factory.copyPrologue( + node.body.statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); const superStatementIndices = findSuperStatementIndexPath(node.body.statements, nonPrologueStart); if (superStatementIndices.length > 0) { - transformConstructorBodyWorker(statements, node.body.statements, nonPrologueStart, superStatementIndices, 0, initializerStatements); + transformConstructorBodyWorker( + statements, + node.body.statements, + nonPrologueStart, + superStatementIndices, + 0, + initializerStatements, + ); } else { addRange(statements, initializerStatements); @@ -1190,7 +1376,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc >( member: TNode, classInfo: ClassInfo | undefined, - createDescriptor?: (node: TNode & { readonly name: PrivateIdentifier }, modifiers: ModifiersArray | undefined) => Expression + createDescriptor?: ( + node: TNode & { readonly name: PrivateIdentifier; }, + modifiers: ModifiersArray | undefined, + ) => Expression, ) { let referencedName: Expression | undefined; let name: PropertyName | undefined; @@ -1208,7 +1397,9 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // Member decorators require privileged access to private names. However, computed property // evaluation occurs interspersed with decorator evaluation. This means that if we encounter // a computed property name we must inline decorator evaluation. - const memberDecorators = transformAllDecoratorsOfDeclaration(getAllDecoratorsOfClassElement(member, classInfo.class, /*useLegacyDecorators*/ false)); + const memberDecorators = transformAllDecoratorsOfDeclaration( + getAllDecoratorsOfClassElement(member, classInfo.class, /*useLegacyDecorators*/ false), + ); const modifiers = visitNodes(member.modifiers, modifierVisitor, isModifier); if (memberDecorators) { @@ -1225,24 +1416,22 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // 6. Non-static non-field (method/getter/setter/auto-accessor) element decorators are applied // 7. Static field (excl. auto-accessor) element decorators are applied // 8. Non-static field (excl. auto-accessor) element decorators are applied - const statements = - isMethodOrAccessor(member) || isAutoAccessorPropertyDeclaration(member) ? - isStatic(member) ? - classInfo.staticNonFieldDecorationStatements ??= [] : - classInfo.nonStaticNonFieldDecorationStatements ??= [] : - isPropertyDeclaration(member) && !isAutoAccessorPropertyDeclaration(member) ? - isStatic(member) ? - classInfo.staticFieldDecorationStatements ??= [] : - classInfo.nonStaticFieldDecorationStatements ??= [] : - Debug.fail(); - - const kind = - isGetAccessorDeclaration(member) ? "getter" : - isSetAccessorDeclaration(member) ? "setter" : - isMethodDeclaration(member) ? "method" : - isAutoAccessorPropertyDeclaration(member) ? "accessor" : - isPropertyDeclaration(member) ? "field" : - Debug.fail(); + const statements = isMethodOrAccessor(member) || isAutoAccessorPropertyDeclaration(member) + ? isStatic(member) + ? classInfo.staticNonFieldDecorationStatements ??= [] + : classInfo.nonStaticNonFieldDecorationStatements ??= [] + : isPropertyDeclaration(member) && !isAutoAccessorPropertyDeclaration(member) + ? isStatic(member) + ? classInfo.staticFieldDecorationStatements ??= [] + : classInfo.nonStaticFieldDecorationStatements ??= [] + : Debug.fail(); + + const kind = isGetAccessorDeclaration(member) ? "getter" + : isSetAccessorDeclaration(member) ? "setter" + : isMethodDeclaration(member) ? "method" + : isAutoAccessorPropertyDeclaration(member) ? "accessor" + : isPropertyDeclaration(member) ? "field" + : Debug.fail(); let propertyName: ESDecorateName; if (isIdentifier(member.name) || isPrivateIdentifier(member.name)) { @@ -1272,16 +1461,23 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc access: { // 15.7.3 CreateDecoratorAccessObject (kind, name) // 2. If _kind_ is ~field~, ~method~, ~accessor~, or ~getter~, then ... - get: isPropertyDeclaration(member) || isGetAccessorDeclaration(member) || isMethodDeclaration(member), + get: isPropertyDeclaration(member) || isGetAccessorDeclaration(member) + || isMethodDeclaration(member), // 3. If _kind_ is ~field~, ~accessor~, or ~setter~, then ... - set: isPropertyDeclaration(member) || isSetAccessorDeclaration(member) + set: isPropertyDeclaration(member) || isSetAccessorDeclaration(member), }, metadata: classInfo.metadataReference, }; - const extraInitializers = isStatic(member) ? - classInfo.staticExtraInitializersName ??= factory.createUniqueName("_staticExtraInitializers", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel) : - classInfo.instanceExtraInitializersName ??= factory.createUniqueName("_instanceExtraInitializers", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + const extraInitializers = isStatic(member) + ? classInfo.staticExtraInitializersName ??= factory.createUniqueName( + "_staticExtraInitializers", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ) + : classInfo.instanceExtraInitializersName ??= factory.createUniqueName( + "_instanceExtraInitializers", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); if (isMethodOrAccessor(member)) { // __esDecorate(this, null, _static_member_decorators, { kind: "method", name: "...", static: true, private: false, access: { ... } }, _staticExtraInitializers); @@ -1300,12 +1496,22 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc let descriptor: Expression | undefined; if (isPrivateIdentifierClassElementDeclaration(member) && createDescriptor) { - descriptor = createDescriptor(member, visitNodes(modifiers, node => tryCast(node, isAsyncModifier), isModifier)); + descriptor = createDescriptor( + member, + visitNodes(modifiers, node => tryCast(node, isAsyncModifier), isModifier), + ); memberInfo.memberDescriptorName = descriptorName = createHelperVariable(member, "descriptor"); descriptor = factory.createAssignment(descriptorName, descriptor); } - const esDecorateExpression = emitHelpers().createESDecorateHelper(factory.createThis(), descriptor ?? factory.createNull(), memberDecoratorsName, context, factory.createNull(), extraInitializers); + const esDecorateExpression = emitHelpers().createESDecorateHelper( + factory.createThis(), + descriptor ?? factory.createNull(), + memberDecoratorsName, + context, + factory.createNull(), + extraInitializers, + ); const esDecorateStatement = factory.createExpressionStatement(esDecorateExpression); setSourceMapRange(esDecorateStatement, moveRangePastDecorators(member)); statements.push(esDecorateStatement); @@ -1318,7 +1524,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } let descriptor: Expression | undefined; - if (isPrivateIdentifierClassElementDeclaration(member) && hasAccessorModifier(member) && createDescriptor) { + if ( + isPrivateIdentifierClassElementDeclaration(member) && hasAccessorModifier(member) + && createDescriptor + ) { descriptor = createDescriptor(member, /*modifiers*/ undefined); memberInfo.memberDescriptorName = descriptorName = createHelperVariable(member, "descriptor"); descriptor = factory.createAssignment(descriptorName, descriptor); @@ -1327,14 +1536,15 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // _static_field_initializers = __esDecorate(null, null, _static_member_decorators, { kind: "field", name: "...", static: true, private: ..., access: { ... } }, _staticExtraInitializers); // _field_initializers = __esDecorate(null, null, _member_decorators, { kind: "field", name: "...", static: false, private: ..., access: { ... } }, _instanceExtraInitializers); const esDecorateExpression = emitHelpers().createESDecorateHelper( - isAutoAccessorPropertyDeclaration(member) ? - factory.createThis() : - factory.createNull(), + isAutoAccessorPropertyDeclaration(member) + ? factory.createThis() + : factory.createNull(), descriptor ?? factory.createNull(), memberDecoratorsName, context, initializersName, - extraInitializers); + extraInitializers, + ); const esDecorateStatement = factory.createExpressionStatement(esDecorateExpression); setSourceMapRange(esDecorateStatement, moveRangePastDecorators(member)); statements.push(esDecorateStatement); @@ -1358,7 +1568,11 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc function visitMethodDeclaration(node: MethodDeclaration) { enterClassElement(node); - const { modifiers, name, descriptorName } = partialTransformClassElement(node, classInfo, createMethodDescriptorObject); + const { modifiers, name, descriptorName } = partialTransformClassElement( + node, + classInfo, + createMethodDescriptorObject, + ); if (descriptorName) { exitClassElement(); return finishClassElement(createMethodDescriptorForwarder(modifiers, name, descriptorName), node); @@ -1367,13 +1581,30 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc const parameters = visitNodes(node.parameters, visitor, isParameter); const body = visitNode(node.body, visitor, isBlock); exitClassElement(); - return finishClassElement(factory.updateMethodDeclaration(node, modifiers, node.asteriskToken, name, /*questionToken*/ undefined, /*typeParameters*/ undefined, parameters, /*type*/ undefined, body), node); + return finishClassElement( + factory.updateMethodDeclaration( + node, + modifiers, + node.asteriskToken, + name, + /*questionToken*/ undefined, + /*typeParameters*/ undefined, + parameters, + /*type*/ undefined, + body, + ), + node, + ); } } function visitGetAccessorDeclaration(node: GetAccessorDeclaration) { enterClassElement(node); - const { modifiers, name, descriptorName } = partialTransformClassElement(node, classInfo, createGetAccessorDescriptorObject); + const { modifiers, name, descriptorName } = partialTransformClassElement( + node, + classInfo, + createGetAccessorDescriptorObject, + ); if (descriptorName) { exitClassElement(); return finishClassElement(createGetAccessorDescriptorForwarder(modifiers, name, descriptorName), node); @@ -1382,13 +1613,20 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc const parameters = visitNodes(node.parameters, visitor, isParameter); const body = visitNode(node.body, visitor, isBlock); exitClassElement(); - return finishClassElement(factory.updateGetAccessorDeclaration(node, modifiers, name, parameters, /*type*/ undefined, body), node); + return finishClassElement( + factory.updateGetAccessorDeclaration(node, modifiers, name, parameters, /*type*/ undefined, body), + node, + ); } } function visitSetAccessorDeclaration(node: SetAccessorDeclaration) { enterClassElement(node); - const { modifiers, name, descriptorName } = partialTransformClassElement(node, classInfo, createSetAccessorDescriptorObject); + const { modifiers, name, descriptorName } = partialTransformClassElement( + node, + classInfo, + createSetAccessorDescriptorObject, + ); if (descriptorName) { exitClassElement(); return finishClassElement(createSetAccessorDescriptorForwarder(modifiers, name, descriptorName), node); @@ -1397,7 +1635,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc const parameters = visitNodes(node.parameters, visitor, isParameter); const body = visitNode(node.body, visitor, isBlock); exitClassElement(); - return finishClassElement(factory.updateSetAccessorDeclaration(node, modifiers, name, parameters, body), node); + return finishClassElement( + factory.updateSetAccessorDeclaration(node, modifiers, name, parameters, body), + node, + ); } } @@ -1442,7 +1683,11 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // a. Let _value_ be ? NamedEvaluation of |Initializer| with argument _functionObject_.[[ClassFieldInitializerName]]. // ... - const { modifiers, name, initializersName, descriptorName, thisArg } = partialTransformClassElement(node, classInfo, hasAccessorModifier(node) ? createAccessorPropertyDescriptorObject : undefined); + const { modifiers, name, initializersName, descriptorName, thisArg } = partialTransformClassElement( + node, + classInfo, + hasAccessorModifier(node) ? createAccessorPropertyDescriptorObject : undefined, + ); startLexicalEnvironment(); @@ -1451,19 +1696,22 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc initializer = emitHelpers().createRunInitializersHelper( thisArg ?? factory.createThis(), initializersName, - initializer ?? factory.createVoidZero()); + initializer ?? factory.createVoidZero(), + ); } - if (!isStatic(node) && classInfo?.instanceExtraInitializersName && !classInfo?.hasInjectedInstanceInitializers) { + if ( + !isStatic(node) && classInfo?.instanceExtraInitializersName && !classInfo?.hasInjectedInstanceInitializers + ) { // for the first non-static field initializer, inject a call to `__runInitializers`. classInfo.hasInjectedInstanceInitializers = true; initializer ??= factory.createVoidZero(); initializer = factory.createParenthesizedExpression(factory.createComma( emitHelpers().createRunInitializersHelper( factory.createThis(), - classInfo.instanceExtraInitializersName + classInfo.instanceExtraInitializersName, ), - initializer + initializer, )); } @@ -1475,7 +1723,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc if (some(declarations)) { initializer = factory.createImmediatelyInvokedArrowFunction([ ...declarations, - factory.createReturnStatement(initializer) + factory.createReturnStatement(initializer), ]); } @@ -1505,7 +1753,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc if (isComputedPropertyName(name) && !isSimpleInlineableExpression(name.expression)) { const cacheAssignment = findComputedPropertyNameCacheAssignment(name); if (cacheAssignment) { - getterName = factory.updateComputedPropertyName(name, visitNode(name.expression, visitor, isExpression)); + getterName = factory.updateComputedPropertyName( + name, + visitNode(name.expression, visitor, isExpression), + ); setterName = factory.updateComputedPropertyName(name, cacheAssignment.left); } else { @@ -1519,9 +1770,18 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } } - const modifiersWithoutAccessor = visitNodes(modifiers, node => node.kind !== SyntaxKind.AccessorKeyword ? node : undefined, isModifier); + const modifiersWithoutAccessor = visitNodes( + modifiers, + node => node.kind !== SyntaxKind.AccessorKeyword ? node : undefined, + isModifier, + ); - const backingField = createAccessorPropertyBackingField(factory, node, modifiersWithoutAccessor, initializer); + const backingField = createAccessorPropertyBackingField( + factory, + node, + modifiersWithoutAccessor, + initializer, + ); setOriginalNode(backingField, node); setEmitFlags(backingField, EmitFlags.NoComments); setSourceMapRange(backingField, sourceMapRange); @@ -1540,7 +1800,17 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc return [backingField, getter, setter]; } - return finishClassElement(factory.updatePropertyDeclaration(node, modifiers, name, /*questionOrExclamationToken*/ undefined, /*type*/ undefined, initializer), node); + return finishClassElement( + factory.updatePropertyDeclaration( + node, + modifiers, + name, + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + initializer, + ), + node, + ); } function visitThisExpression(node: ThisExpression) { @@ -1625,7 +1895,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc visitNode(node.name, visitor, isBindingName), /*questionToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression) + visitNode(node.initializer, visitor, isExpression), ); if (updated !== node) { @@ -1650,7 +1920,8 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // transforms to `return class { };`, and thus the empty string *can* be ignored. const innerExpression = skipOuterExpressions(node); - return isClassExpression(innerExpression) && !innerExpression.name && !classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, innerExpression); + return isClassExpression(innerExpression) && !innerExpression.name + && !classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ false, innerExpression); } function visitForStatement(node: ForStatement) { @@ -1659,7 +1930,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc visitNode(node.initializer, discardedValueVisitor, isForInitializer), visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, discardedValueVisitor, isExpression), - visitIterationBody(node.statement, visitor, context) + visitIterationBody(node.statement, visitor, context), ); } @@ -1707,10 +1978,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } if (isSuperProperty(node.left) && classThis && classSuper) { - let setterName = - isElementAccessExpression(node.left) ? visitNode(node.left.argumentExpression, visitor, isExpression) : - isIdentifier(node.left.name) ? factory.createStringLiteralFromNode(node.left.name) : - undefined; + let setterName = isElementAccessExpression(node.left) + ? visitNode(node.left.argumentExpression, visitor, isExpression) + : isIdentifier(node.left.name) ? factory.createStringLiteralFromNode(node.left.name) + : undefined; if (setterName) { // super.x = ... // super.x += ... @@ -1727,14 +1998,15 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc const superPropertyGet = factory.createReflectGetCall( classSuper, getterName, - classThis); + classThis, + ); setOriginalNode(superPropertyGet, node.left); setTextRange(superPropertyGet, node.left); expression = factory.createBinaryExpression( superPropertyGet, getNonAssignmentOperatorForCompoundAssignment(node.operatorToken.kind), - expression + expression, ); setTextRange(expression, node); } @@ -1749,7 +2021,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc classSuper, setterName, expression, - classThis + classThis, ); setOriginalNode(expression, node); setTextRange(expression, node); @@ -1773,15 +2045,20 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc return visitEachChild(node, visitor, context); } - function visitPreOrPostfixUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression, discarded: boolean) { - if (node.operator === SyntaxKind.PlusPlusToken || - node.operator === SyntaxKind.MinusMinusToken) { + function visitPreOrPostfixUnaryExpression( + node: PrefixUnaryExpression | PostfixUnaryExpression, + discarded: boolean, + ) { + if ( + node.operator === SyntaxKind.PlusPlusToken + || node.operator === SyntaxKind.MinusMinusToken + ) { const operand = skipParentheses(node.operand); if (isSuperProperty(operand) && classThis && classSuper) { - let setterName = - isElementAccessExpression(operand) ? visitNode(operand.argumentExpression, visitor, isExpression) : - isIdentifier(operand.name) ? factory.createStringLiteralFromNode(operand.name) : - undefined; + let setterName = isElementAccessExpression(operand) + ? visitNode(operand.argumentExpression, visitor, isExpression) + : isIdentifier(operand.name) ? factory.createStringLiteralFromNode(operand.name) + : undefined; if (setterName) { let getterName = setterName; if (!isSimpleInlineableExpression(setterName)) { @@ -1815,7 +2092,13 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // result of the operation so that we can provide it to `y` when the assignment is complete. const temp = discarded ? undefined : factory.createTempVariable(hoistVariableDeclaration); - expression = expandPreOrPostfixIncrementOrDecrementExpression(factory, node, expression, hoistVariableDeclaration, temp); + expression = expandPreOrPostfixIncrementOrDecrementExpression( + factory, + node, + expression, + hoistVariableDeclaration, + temp, + ); expression = factory.createReflectSetCall(classSuper, setterName, expression, classThis); setOriginalNode(expression, node); setTextRange(expression, node); @@ -1834,9 +2117,9 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } function visitCommaListExpression(node: CommaListExpression, discarded: boolean) { - const elements = discarded ? - visitCommaListElements(node.elements, discardedValueVisitor) : - visitCommaListElements(node.elements, visitor, discardedValueVisitor); + const elements = discarded + ? visitCommaListElements(node.elements, discardedValueVisitor) + : visitCommaListElements(node.elements, visitor, discardedValueVisitor); return factory.updateCommaListExpression(node, elements); } @@ -1944,10 +2227,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc } if (isSuperProperty(node) && classThis && classSuper) { - const propertyName = - isElementAccessExpression(node) ? visitNode(node.argumentExpression, visitor, isExpression) : - isIdentifier(node.name) ? factory.createStringLiteralFromNode(node.name) : - undefined; + const propertyName = isElementAccessExpression(node) + ? visitNode(node.argumentExpression, visitor, isExpression) + : isIdentifier(node.name) ? factory.createStringLiteralFromNode(node.name) + : undefined; if (propertyName) { const paramName = factory.createTempVariable(/*recordTempVariable*/ undefined); const expression = factory.createAssignmentTargetWrapper( @@ -1957,7 +2240,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc propertyName, paramName, classThis, - ) + ), ); setOriginalNode(expression, node); setTextRange(expression, node); @@ -1968,7 +2251,9 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc return visitEachChild(node, visitor, context); } - function visitAssignmentElement(node: Exclude): ArrayAssignmentElement { + function visitAssignmentElement( + node: Exclude, + ): ArrayAssignmentElement { // 13.15.5.5 RS: IteratorDestructuringAssignmentEvaluation // AssignmentElement : DestructuringAssignmentTarget Initializer? // ... @@ -1984,7 +2269,12 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc const assignmentTarget = visitDestructuringAssignmentTarget(node.left); const initializer = visitNode(node.right, visitor, isExpression); - return factory.updateBinaryExpression(node, assignmentTarget, node.operatorToken, initializer) as ArrayAssignmentElement; + return factory.updateBinaryExpression( + node, + assignmentTarget, + node.operatorToken, + initializer, + ) as ArrayAssignmentElement; } else { return visitDestructuringAssignmentTarget(node) as ArrayAssignmentElement; @@ -2045,7 +2335,11 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // ... if (isNamedEvaluation(node, isAnonymousClassNeedingAssignedName)) { - node = transformNamedEvaluation(context, node, canIgnoreEmptyStringLiteralInAssignedName(node.objectAssignmentInitializer)); + node = transformNamedEvaluation( + context, + node, + canIgnoreEmptyStringLiteralInAssignedName(node.objectAssignmentInitializer), + ); } return visitEachChild(node, visitor, context); @@ -2116,7 +2410,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc if (some(pendingExpressions)) { if (isParenthesizedExpression(expression)) { pendingExpressions.push(expression.expression); - expression = factory.updateParenthesizedExpression(expression, factory.inlineExpressions(pendingExpressions)); + expression = factory.updateParenthesizedExpression( + expression, + factory.inlineExpressions(pendingExpressions), + ); } else { pendingExpressions.push(expression); @@ -2154,7 +2451,12 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc // preserve the 'this' binding for an access expression const innerExpression = skipOuterExpressions(expression); if (isAccessExpression(innerExpression)) { - const { target, thisArg } = factory.createCallBinding(expression, hoistVariableDeclaration, languageVersion, /*cacheIdentifiers*/ true); + const { target, thisArg } = factory.createCallBinding( + expression, + hoistVariableDeclaration, + languageVersion, + /*cacheIdentifiers*/ true, + ); return factory.restoreOuterExpressions(expression, factory.createFunctionBindCall(target, thisArg, [])); } return expression; @@ -2163,7 +2465,15 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc /** * Creates a `value`, `get`, or `set` method for a pseudo-{@link PropertyDescriptor} object created for a private element. */ - function createDescriptorMethod(original: Node, name: PrivateIdentifier, modifiers: ModifiersArray | undefined, asteriskToken: AsteriskToken | undefined, kind: "value" | "get" | "set", parameters: readonly ParameterDeclaration[], body: Block | undefined) { + function createDescriptorMethod( + original: Node, + name: PrivateIdentifier, + modifiers: ModifiersArray | undefined, + asteriskToken: AsteriskToken | undefined, + kind: "value" | "get" | "set", + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ) { const func = factory.createFunctionExpression( modifiers, asteriskToken, @@ -2171,7 +2481,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc /*typeParameters*/ undefined, parameters, /*type*/ undefined, - body ?? factory.createBlock([]) + body ?? factory.createBlock([]), ); setOriginalNode(func, original); setSourceMapRange(func, moveRangePastDecorators(original)); @@ -2190,7 +2500,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc /** * Creates a pseudo-{@link PropertyDescriptor} object used when decorating a private {@link MethodDeclaration}. */ - function createMethodDescriptorObject(node: PrivateIdentifierMethodDeclaration, modifiers: ModifiersArray | undefined) { + function createMethodDescriptorObject( + node: PrivateIdentifierMethodDeclaration, + modifiers: ModifiersArray | undefined, + ) { return factory.createObjectLiteralExpression([ createDescriptorMethod( node, @@ -2199,14 +2512,18 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc node.asteriskToken, "value", visitNodes(node.parameters, visitor, isParameter), - visitNode(node.body, visitor, isBlock)) + visitNode(node.body, visitor, isBlock), + ), ]); } /** * Creates a pseudo-{@link PropertyDescriptor} object used when decorating a private {@link GetAccessorDeclaration}. */ - function createGetAccessorDescriptorObject(node: PrivateIdentifierGetAccessorDeclaration, modifiers: ModifiersArray | undefined) { + function createGetAccessorDescriptorObject( + node: PrivateIdentifierGetAccessorDeclaration, + modifiers: ModifiersArray | undefined, + ) { return factory.createObjectLiteralExpression([ createDescriptorMethod( node, @@ -2215,14 +2532,18 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc /*asteriskToken*/ undefined, "get", [], - visitNode(node.body, visitor, isBlock)) + visitNode(node.body, visitor, isBlock), + ), ]); } /** * Creates a pseudo-{@link PropertyDescriptor} object used when decorating a private {@link SetAccessorDeclaration}. */ - function createSetAccessorDescriptorObject(node: PrivateIdentifierSetAccessorDeclaration, modifiers: ModifiersArray | undefined) { + function createSetAccessorDescriptorObject( + node: PrivateIdentifierSetAccessorDeclaration, + modifiers: ModifiersArray | undefined, + ) { return factory.createObjectLiteralExpression([ createDescriptorMethod( node, @@ -2231,14 +2552,18 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc /*asteriskToken*/ undefined, "set", visitNodes(node.parameters, visitor, isParameter), - visitNode(node.body, visitor, isBlock)) + visitNode(node.body, visitor, isBlock), + ), ]); } /** * Creates a pseudo-{@link PropertyDescriptor} object used when decorating an `accessor` {@link PropertyDeclaration} with a private name. */ - function createAccessorPropertyDescriptorObject(node: PrivateIdentifierPropertyDeclaration, modifiers: ModifiersArray | undefined) { + function createAccessorPropertyDescriptorObject( + node: PrivateIdentifierPropertyDeclaration, + modifiers: ModifiersArray | undefined, + ) { // { // get() { return this.${privateName}; }, // set(value) { this.${privateName} = value; }, @@ -2256,10 +2581,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc factory.createReturnStatement( factory.createPropertyAccessExpression( factory.createThis(), - factory.getGeneratedPrivateNameForNode(node.name) - ) - ) - ]) + factory.getGeneratedPrivateNameForNode(node.name), + ), + ), + ]), ), createDescriptorMethod( node, @@ -2270,20 +2595,20 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc [factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, - "value" + "value", )], factory.createBlock([ factory.createExpressionStatement( factory.createAssignment( factory.createPropertyAccessExpression( factory.createThis(), - factory.getGeneratedPrivateNameForNode(node.name) + factory.getGeneratedPrivateNameForNode(node.name), ), - factory.createIdentifier("value") - ) - ) - ]) - ) + factory.createIdentifier("value"), + ), + ), + ]), + ), ]); } @@ -2293,7 +2618,11 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc * @param name The name for the resulting declaration. * @param descriptorName The name of the descriptor variable. */ - function createMethodDescriptorForwarder(modifiers: ModifiersArray | undefined, name: PropertyName, descriptorName: Identifier) { + function createMethodDescriptorForwarder( + modifiers: ModifiersArray | undefined, + name: PropertyName, + descriptorName: Identifier, + ) { // strip off all but the `static` modifier modifiers = visitNodes(modifiers, node => isStaticModifier(node) ? node : undefined, isModifier); return factory.createGetAccessorDeclaration( @@ -2305,10 +2634,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc factory.createReturnStatement( factory.createPropertyAccessExpression( descriptorName, - factory.createIdentifier("value") - ) - ) - ]) + factory.createIdentifier("value"), + ), + ), + ]), ); } @@ -2318,7 +2647,11 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc * @param name The name for the resulting declaration. * @param descriptorName The name of the descriptor variable. */ - function createGetAccessorDescriptorForwarder(modifiers: ModifiersArray | undefined, name: PropertyName, descriptorName: Identifier) { + function createGetAccessorDescriptorForwarder( + modifiers: ModifiersArray | undefined, + name: PropertyName, + descriptorName: Identifier, + ) { // strip off all but the `static` modifier modifiers = visitNodes(modifiers, node => isStaticModifier(node) ? node : undefined, isModifier); return factory.createGetAccessorDeclaration( @@ -2331,13 +2664,13 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc factory.createFunctionCallCall( factory.createPropertyAccessExpression( descriptorName, - factory.createIdentifier("get") + factory.createIdentifier("get"), ), factory.createThis(), - [] - ) - ) - ]) + [], + ), + ), + ]), ); } @@ -2347,7 +2680,11 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc * @param name The name for the resulting declaration. * @param descriptorName The name of the descriptor variable. */ - function createSetAccessorDescriptorForwarder(modifiers: ModifiersArray | undefined, name: PropertyName, descriptorName: Identifier) { + function createSetAccessorDescriptorForwarder( + modifiers: ModifiersArray | undefined, + name: PropertyName, + descriptorName: Identifier, + ) { // strip off all but the `static` modifier modifiers = visitNodes(modifiers, node => isStaticModifier(node) ? node : undefined, isModifier); return factory.createSetAccessorDeclaration( @@ -2356,20 +2693,20 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc [factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, - "value" + "value", )], factory.createBlock([ factory.createReturnStatement( factory.createFunctionCallCall( factory.createPropertyAccessExpression( descriptorName, - factory.createIdentifier("set") + factory.createIdentifier("set"), ), factory.createThis(), - [factory.createIdentifier("value")] - ) - ) - ]) + [factory.createIdentifier("value")], + ), + ), + ]), ); } function createMetadata(name: Identifier, classSuper: Identifier | undefined) { @@ -2386,20 +2723,26 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc factory.createCallExpression( factory.createPropertyAccessExpression(factory.createIdentifier("Object"), "create"), /*typeArguments*/ undefined, - [classSuper ? createSymbolMetadataReference(classSuper) : factory.createNull()] + [classSuper ? createSymbolMetadataReference(classSuper) : factory.createNull()], ), factory.createToken(SyntaxKind.ColonToken), factory.createVoidZero(), ), ); - return factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([varDecl], NodeFlags.Const)); + return factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([varDecl], NodeFlags.Const), + ); } function createSymbolMetadata(target: Identifier | ThisExpression, value: Identifier) { const defineProperty = factory.createObjectDefinePropertyCall( target, factory.createPropertyAccessExpression(factory.createIdentifier("Symbol"), "metadata"), - factory.createPropertyDescriptor({ configurable: true, writable: true, enumerable: true, value }, /*singleLine*/ true) + factory.createPropertyDescriptor( + { configurable: true, writable: true, enumerable: true, value }, + /*singleLine*/ true, + ), ); return setEmitFlags( factory.createIfStatement(value, factory.createExpressionStatement(defineProperty)), @@ -2414,7 +2757,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc factory.createPropertyAccessExpression(factory.createIdentifier("Symbol"), "metadata"), ), SyntaxKind.QuestionQuestionToken, - factory.createNull() + factory.createNull(), ); } } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index d20cdd511d9ba..0c6e56dbd0a6e 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -60,7 +60,7 @@ import { visitEachChild, visitNode, visitNodes, - VisitResult + VisitResult, } from "../_namespaces/ts"; const enum UsingKind { @@ -182,7 +182,10 @@ export function transformESNext(context: TransformationContext): (x: SourceFile const statement = node.statements[pos]; if (getUsingKind(statement) !== UsingKind.None) { if (pos > prologueCount) { - addRange(topLevelStatements, visitNodes(node.statements, visitor, isStatement, prologueCount, pos - prologueCount)); + addRange( + topLevelStatements, + visitNodes(node.statements, visitor, isStatement, prologueCount, pos - prologueCount), + ); } break; } @@ -193,15 +196,24 @@ export function transformESNext(context: TransformationContext): (x: SourceFile // transform the rest of the body const envBinding = createEnvBinding(); - const bodyStatements = transformUsingDeclarations(node.statements, pos, node.statements.length, envBinding, topLevelStatements); + const bodyStatements = transformUsingDeclarations( + node.statements, + pos, + node.statements.length, + envBinding, + topLevelStatements, + ); // add `export {}` declarations for any hoisted bindings. if (exportBindings.size) { - append(topLevelStatements, factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports(arrayFrom(exportBindings.values())) - )); + append( + topLevelStatements, + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports(arrayFrom(exportBindings.values())), + ), + ); } addRange(topLevelStatements, endLexicalEnvironment()); @@ -210,17 +222,20 @@ export function transformESNext(context: TransformationContext): (x: SourceFile factory.createModifiersFromModifierFlags(ModifierFlags.Export), factory.createVariableDeclarationList( exportVars, - NodeFlags.Let - ) + NodeFlags.Let, + ), )); } - addRange(topLevelStatements, createDownlevelUsingStatements(bodyStatements, envBinding, usingKind === UsingKind.Async)); + addRange( + topLevelStatements, + createDownlevelUsingStatements(bodyStatements, envBinding, usingKind === UsingKind.Async), + ); if (exportEqualsBinding) { topLevelStatements.push(factory.createExportAssignment( /*modifiers*/ undefined, /*isExportEquals*/ true, - exportEqualsBinding + exportEqualsBinding, )); } @@ -240,11 +255,17 @@ export function transformESNext(context: TransformationContext): (x: SourceFile [ ...visitArray(node.statements, visitor, isStatement, 0, prologueCount), ...createDownlevelUsingStatements( - transformUsingDeclarations(node.statements, prologueCount, node.statements.length, envBinding, /*topLevelStatements*/ undefined), + transformUsingDeclarations( + node.statements, + prologueCount, + node.statements.length, + envBinding, + /*topLevelStatements*/ undefined, + ), envBinding, usingKind === UsingKind.Async, - ) - ] + ), + ], ); } return visitEachChild(node, visitor, context); @@ -272,11 +293,11 @@ export function transformESNext(context: TransformationContext): (x: SourceFile /*initializer*/ undefined, node.condition, node.incrementor, - node.statement - ) + node.statement, + ), ]), visitor, - isStatement + isStatement, ); } @@ -306,29 +327,38 @@ export function transformESNext(context: TransformationContext): (x: SourceFile const isAwaitUsing = getUsingKindOfVariableDeclarationList(forInitializer) === UsingKind.Async; const temp = factory.getGeneratedNameForNode(forDecl.name); - const usingVar = factory.updateVariableDeclaration(forDecl, forDecl.name, /*exclamationToken*/ undefined, /*type*/ undefined, temp); - const usingVarList = factory.createVariableDeclarationList([usingVar], isAwaitUsing ? NodeFlags.AwaitUsing : NodeFlags.Using); + const usingVar = factory.updateVariableDeclaration( + forDecl, + forDecl.name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + temp, + ); + const usingVarList = factory.createVariableDeclarationList( + [usingVar], + isAwaitUsing ? NodeFlags.AwaitUsing : NodeFlags.Using, + ); const usingVarStatement = factory.createVariableStatement(/*modifiers*/ undefined, usingVarList); return visitNode( factory.updateForOfStatement( node, node.awaitModifier, factory.createVariableDeclarationList([ - factory.createVariableDeclaration(temp) + factory.createVariableDeclaration(temp), ], NodeFlags.Const), node.expression, - isBlock(node.statement) ? - factory.updateBlock(node.statement, [ + isBlock(node.statement) + ? factory.updateBlock(node.statement, [ usingVarStatement, - ...node.statement.statements - ]) : - factory.createBlock([ + ...node.statement.statements, + ]) + : factory.createBlock([ usingVarStatement, - node.statement - ], /*multiLine*/ true) + node.statement, + ], /*multiLine*/ true), ), visitor, - isStatement + isStatement, ); } return visitEachChild(node, visitor, context); @@ -340,13 +370,25 @@ export function transformESNext(context: TransformationContext): (x: SourceFile return factory.updateCaseClause( node, visitNode(node.expression, visitor, isExpression), - transformUsingDeclarations(node.statements, /*start*/ 0, node.statements.length, envBinding, /*topLevelStatements*/ undefined) + transformUsingDeclarations( + node.statements, + /*start*/ 0, + node.statements.length, + envBinding, + /*topLevelStatements*/ undefined, + ), ); } else { return factory.updateDefaultClause( node, - transformUsingDeclarations(node.statements, /*start*/ 0, node.statements.length, envBinding, /*topLevelStatements*/ undefined) + transformUsingDeclarations( + node.statements, + /*start*/ 0, + node.statements.length, + envBinding, + /*topLevelStatements*/ undefined, + ), ); } } @@ -388,9 +430,9 @@ export function transformESNext(context: TransformationContext): (x: SourceFile visitNode(node.expression, visitor, isExpression), factory.updateCaseBlock( node.caseBlock, - node.caseBlock.clauses.map(clause => visitCaseOrDefaultClause(clause, envBinding)) - ) - ) + node.caseBlock.clauses.map(clause => visitCaseOrDefaultClause(clause, envBinding)), + ), + ), ], envBinding, usingKind === UsingKind.Async, @@ -403,7 +445,13 @@ export function transformESNext(context: TransformationContext): (x: SourceFile /** * Transform `using` declarations in a statement list. */ - function transformUsingDeclarations(statementsIn: readonly Statement[], start: number, end: number, envBinding: Identifier, topLevelStatements: Statement[] | undefined) { + function transformUsingDeclarations( + statementsIn: readonly Statement[], + start: number, + end: number, + envBinding: Identifier, + topLevelStatements: Statement[] | undefined, + ) { const statements: Statement[] = []; for (let i = start; i < end; i++) { @@ -424,7 +472,8 @@ export function transformESNext(context: TransformationContext): (x: SourceFile declaration = transformNamedEvaluation(context, declaration); } - const initializer = visitNode(declaration.initializer, visitor, isExpression) ?? factory.createVoidZero(); + const initializer = visitNode(declaration.initializer, visitor, isExpression) + ?? factory.createVoidZero(); declarations.push(factory.updateVariableDeclaration( declaration, declaration.name, @@ -433,8 +482,8 @@ export function transformESNext(context: TransformationContext): (x: SourceFile emitHelpers().createAddDisposableResourceHelper( envBinding, initializer, - usingKind === UsingKind.Async - ) + usingKind === UsingKind.Async, + ), )); } @@ -515,14 +564,23 @@ export function transformESNext(context: TransformationContext): (x: SourceFile // // body // default_1 = expr; - defaultExportBinding = factory.createUniqueName("_default", GeneratedIdentifierFlags.ReservedInNestedScopes | GeneratedIdentifierFlags.FileLevel | GeneratedIdentifierFlags.Optimistic); + defaultExportBinding = factory.createUniqueName( + "_default", + GeneratedIdentifierFlags.ReservedInNestedScopes | GeneratedIdentifierFlags.FileLevel + | GeneratedIdentifierFlags.Optimistic, + ); hoistBindingIdentifier(defaultExportBinding, /*isExport*/ true, "default", node); // give a class or function expression an assigned name, if needed. let expression = node.expression; let innerExpression = skipOuterExpressions(expression); if (isNamedEvaluation(innerExpression)) { - innerExpression = transformNamedEvaluation(context, innerExpression, /*ignoreEmptyStringLiteral*/ false, "default"); + innerExpression = transformNamedEvaluation( + context, + innerExpression, + /*ignoreEmptyStringLiteral*/ false, + "default", + ); expression = factory.restoreOuterExpressions(expression, innerExpression); } @@ -554,7 +612,11 @@ export function transformESNext(context: TransformationContext): (x: SourceFile // // top level suffix // export = default_1; - exportEqualsBinding = factory.createUniqueName("_default", GeneratedIdentifierFlags.ReservedInNestedScopes | GeneratedIdentifierFlags.FileLevel | GeneratedIdentifierFlags.Optimistic); + exportEqualsBinding = factory.createUniqueName( + "_default", + GeneratedIdentifierFlags.ReservedInNestedScopes | GeneratedIdentifierFlags.FileLevel + | GeneratedIdentifierFlags.Optimistic, + ); hoistVariableDeclaration(exportEqualsBinding); // give a class or function expression an assigned name, if needed. @@ -598,7 +660,12 @@ export function transformESNext(context: TransformationContext): (x: SourceFile // } // // If the class is exported, we also produce an `export { C };` - hoistBindingIdentifier(factory.getLocalName(node), isExported && !isDefault, /*exportAlias*/ undefined, node); + hoistBindingIdentifier( + factory.getLocalName(node), + isExported && !isDefault, + /*exportAlias*/ undefined, + node, + ); expression = factory.createAssignment(factory.getDeclarationName(node), expression); if (isNamedEvaluation(expression)) { expression = transformNamedEvaluation(context, expression, /*ignoreEmptyStringLiteral*/ false); @@ -635,11 +702,20 @@ export function transformESNext(context: TransformationContext): (x: SourceFile // } // // Though we will never reassign `default_1`, this most closely matches the specified runtime semantics. - defaultExportBinding = factory.createUniqueName("_default", GeneratedIdentifierFlags.ReservedInNestedScopes | GeneratedIdentifierFlags.FileLevel | GeneratedIdentifierFlags.Optimistic); + defaultExportBinding = factory.createUniqueName( + "_default", + GeneratedIdentifierFlags.ReservedInNestedScopes | GeneratedIdentifierFlags.FileLevel + | GeneratedIdentifierFlags.Optimistic, + ); hoistBindingIdentifier(defaultExportBinding, /*isExport*/ true, "default", node); expression = factory.createAssignment(defaultExportBinding, expression); if (isNamedEvaluation(expression)) { - expression = transformNamedEvaluation(context, expression, /*ignoreEmptyStringLiteral*/ false, "default"); + expression = transformNamedEvaluation( + context, + expression, + /*ignoreEmptyStringLiteral*/ false, + "default", + ); } setOriginalNode(expression, node); } @@ -673,7 +749,10 @@ export function transformESNext(context: TransformationContext): (x: SourceFile let target: Expression; if (isIdentifier(node.name)) { target = factory.cloneNode(node.name); - setEmitFlags(target, getEmitFlags(target) & ~(EmitFlags.LocalName | EmitFlags.ExportName | EmitFlags.InternalName)); + setEmitFlags( + target, + getEmitFlags(target) & ~(EmitFlags.LocalName | EmitFlags.ExportName | EmitFlags.InternalName), + ); } else { target = factory.converters.convertToAssignmentPattern(node.name); @@ -686,7 +765,11 @@ export function transformESNext(context: TransformationContext): (x: SourceFile return assignment; } - function hoistBindingElement(node: VariableDeclaration | BindingElement, isExportedDeclaration: boolean, original: Node | undefined) { + function hoistBindingElement( + node: VariableDeclaration | BindingElement, + isExportedDeclaration: boolean, + original: Node | undefined, + ) { // NOTE: `node` has already been visited if (isBindingPattern(node.name)) { for (const element of node.name.elements) { @@ -700,7 +783,12 @@ export function transformESNext(context: TransformationContext): (x: SourceFile } } - function hoistBindingIdentifier(node: Identifier, isExport: boolean, exportAlias: string | Identifier | undefined, original: Node | undefined) { + function hoistBindingIdentifier( + node: Identifier, + isExport: boolean, + exportAlias: string | Identifier | undefined, + original: Node | undefined, + ) { // NOTE: `node` has already been visited const name = isGeneratedIdentifier(node) ? node : factory.cloneNode(node); if (isExport) { @@ -728,7 +816,11 @@ export function transformESNext(context: TransformationContext): (x: SourceFile return factory.createUniqueName("env"); } - function createDownlevelUsingStatements(bodyStatements: readonly Statement[], envBinding: Identifier, async: boolean) { + function createDownlevelUsingStatements( + bodyStatements: readonly Statement[], + envBinding: Identifier, + async: boolean, + ) { const statements: Statement[] = []; // produces: @@ -738,9 +830,14 @@ export function transformESNext(context: TransformationContext): (x: SourceFile const envObject = factory.createObjectLiteralExpression([ factory.createPropertyAssignment("stack", factory.createArrayLiteralExpression()), factory.createPropertyAssignment("error", factory.createVoidZero()), - factory.createPropertyAssignment("hasError", factory.createFalse()) + factory.createPropertyAssignment("hasError", factory.createFalse()), ]); - const envVar = factory.createVariableDeclaration(envBinding, /*exclamationToken*/ undefined, /*type*/ undefined, envObject); + const envVar = factory.createVariableDeclaration( + envBinding, + /*exclamationToken*/ undefined, + /*type*/ undefined, + envObject, + ); const envVarList = factory.createVariableDeclarationList([envVar], NodeFlags.Const); const envVarStatement = factory.createVariableStatement(/*modifiers*/ undefined, envVarList); statements.push(envVarStatement); @@ -784,14 +881,16 @@ export function transformESNext(context: TransformationContext): (x: SourceFile factory.createExpressionStatement( factory.createAssignment( factory.createPropertyAccessExpression(envBinding, "error"), - bodyCatchBinding) + bodyCatchBinding, + ), ), factory.createExpressionStatement( factory.createAssignment( factory.createPropertyAccessExpression(envBinding, "hasError"), - factory.createTrue()) + factory.createTrue(), + ), ), - ], /*multiLine*/ true) + ], /*multiLine*/ true), ); let finallyBlock: Block; @@ -805,18 +904,21 @@ export function transformESNext(context: TransformationContext): (x: SourceFile result, /*exclamationToken*/ undefined, /*type*/ undefined, - emitHelpers().createDisposeResourcesHelper(envBinding) - ) - ], NodeFlags.Const) + emitHelpers().createDisposeResourcesHelper(envBinding), + ), + ], NodeFlags.Const), + ), + factory.createIfStatement( + result, + factory.createExpressionStatement(factory.createAwaitExpression(result)), ), - factory.createIfStatement(result, factory.createExpressionStatement(factory.createAwaitExpression(result))) ], /*multiLine*/ true); } else { finallyBlock = factory.createBlock([ factory.createExpressionStatement( - emitHelpers().createDisposeResourcesHelper(envBinding) - ) + emitHelpers().createDisposeResourcesHelper(envBinding), + ), ], /*multiLine*/ true); } @@ -836,14 +938,14 @@ function countPrologueStatements(statements: readonly Statement[]) { return 0; } -function isUsingVariableDeclarationList(node: Node): node is VariableDeclarationList & { _usingBrand: any } { +function isUsingVariableDeclarationList(node: Node): node is VariableDeclarationList & { _usingBrand: any; } { return isVariableDeclarationList(node) && getUsingKindOfVariableDeclarationList(node) !== UsingKind.None; } function getUsingKindOfVariableDeclarationList(node: VariableDeclarationList) { - return (node.flags & NodeFlags.BlockScoped) === NodeFlags.AwaitUsing ? UsingKind.Async : - (node.flags & NodeFlags.BlockScoped) === NodeFlags.Using ? UsingKind.Sync : - UsingKind.None; + return (node.flags & NodeFlags.BlockScoped) === NodeFlags.AwaitUsing ? UsingKind.Async + : (node.flags & NodeFlags.BlockScoped) === NodeFlags.Using ? UsingKind.Sync + : UsingKind.None; } function getUsingKindOfVariableStatement(node: VariableStatement) { diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 0439defa66437..9e1b9d0ba3b96 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -218,6 +218,7 @@ import { type Label = number; +// dprint-ignore const enum OpCode { Nop, // No operation, used to force a new case in the state machine Statement, // A regular javascript statement @@ -229,10 +230,13 @@ const enum OpCode { YieldStar, // A completion instruction for the `yield*` keyword (not implemented, but reserved for future use) Return, // A completion instruction for the `return` keyword Throw, // A completion instruction for the `throw` keyword - Endfinally // Marks the end of a `finally` block + Endfinally, // Marks the end of a `finally` block } -type OperationArguments = [Label] | [Label, Expression] | [Statement] | [Expression | undefined] | [Expression, Expression]; +type OperationArguments = [Label] | [Label, Expression] | [Statement] | [Expression | undefined] | [ + Expression, + Expression, +]; // whether a generated code block is opening or closing at the current operation for a FunctionBuilder const enum BlockAction { @@ -246,7 +250,7 @@ const enum CodeBlockKind { With, Switch, Loop, - Labeled + Labeled, } // the state for a generated code exception block @@ -254,11 +258,11 @@ const enum ExceptionBlockState { Try, Catch, Finally, - Done + Done, } // A generated code block -type CodeBlock = | ExceptionBlock | LabeledBlock | SwitchBlock | LoopBlock | WithBlock; +type CodeBlock = ExceptionBlock | LabeledBlock | SwitchBlock | LoopBlock | WithBlock; // a generated exception block, used for 'try' statements interface ExceptionBlock { @@ -316,12 +320,18 @@ const enum Instruction { function getInstructionName(instruction: Instruction): string { switch (instruction) { - case Instruction.Return: return "return"; - case Instruction.Break: return "break"; - case Instruction.Yield: return "yield"; - case Instruction.YieldStar: return "yield*"; - case Instruction.Endfinally: return "endfinally"; - default: return undefined!; // TODO: GH#18217 + case Instruction.Return: + return "return"; + case Instruction.Break: + return "break"; + case Instruction.Yield: + return "yield"; + case Instruction.YieldStar: + return "yield*"; + case Instruction.Endfinally: + return "endfinally"; + default: + return undefined!; // TODO: GH#18217 } } @@ -333,7 +343,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF resumeLexicalEnvironment, endLexicalEnvironment, hoistFunctionDeclaration, - hoistVariableDeclaration + hoistVariableDeclaration, } = context; const compilerOptions = context.getCompilerOptions(); @@ -397,7 +407,6 @@ export function transformGenerators(context: TransformationContext): (x: SourceF return node; } - const visited = visitEachChild(node, visitor, context); addEmitHelpers(visited, context.readEmitHelpers()); return visited; @@ -477,7 +486,10 @@ export function transformGenerators(context: TransformationContext): (x: SourceF if (node.transformFlags & TransformFlags.ContainsYield) { return visitJavaScriptContainingYield(node); } - else if (node.transformFlags & (TransformFlags.ContainsGenerator | TransformFlags.ContainsHoistedDeclarationOrCompletion)) { + else if ( + node.transformFlags + & (TransformFlags.ContainsGenerator | TransformFlags.ContainsHoistedDeclarationOrCompletion) + ) { return visitEachChild(node, visitor, context); } else { @@ -555,11 +567,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - transformGeneratorFunctionBody(node.body!) + transformGeneratorFunctionBody(node.body!), ), - /*location*/ node + /*location*/ node, ), - node + node, ); } else { @@ -604,11 +616,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - transformGeneratorFunctionBody(node.body) + transformGeneratorFunctionBody(node.body), ), - /*location*/ node + /*location*/ node, ), - node + node, ); } else { @@ -740,10 +752,10 @@ export function transformGenerators(context: TransformationContext): (x: SourceF return setSourceMapRange( factory.createExpressionStatement( factory.inlineExpressions( - map(variables, transformInitializedVariable) - ) + map(variables, transformInitializedVariable), + ), ), - node + node, ); } } @@ -791,8 +803,16 @@ export function transformGenerators(context: TransformationContext): (x: SourceF target = factory.updatePropertyAccessExpression( left as PropertyAccessExpression, - cacheExpression(Debug.checkDefined(visitNode((left as PropertyAccessExpression).expression, visitor, isLeftHandSideExpression))), - (left as PropertyAccessExpression).name + cacheExpression( + Debug.checkDefined( + visitNode( + (left as PropertyAccessExpression).expression, + visitor, + isLeftHandSideExpression, + ), + ), + ), + (left as PropertyAccessExpression).name, ); break; @@ -808,9 +828,22 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // .mark resumeLabel // _a[_b] = %sent%; - target = factory.updateElementAccessExpression(left as ElementAccessExpression, - cacheExpression(Debug.checkDefined(visitNode((left as ElementAccessExpression).expression, visitor, isLeftHandSideExpression))), - cacheExpression(Debug.checkDefined(visitNode((left as ElementAccessExpression).argumentExpression, visitor, isExpression))) + target = factory.updateElementAccessExpression( + left as ElementAccessExpression, + cacheExpression( + Debug.checkDefined( + visitNode( + (left as ElementAccessExpression).expression, + visitor, + isLeftHandSideExpression, + ), + ), + ), + cacheExpression( + Debug.checkDefined( + visitNode((left as ElementAccessExpression).argumentExpression, visitor, isExpression), + ), + ), ); break; @@ -828,16 +861,21 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createBinaryExpression( cacheExpression(target), getNonAssignmentOperatorForCompoundAssignment(operator), - Debug.checkDefined(visitNode(right, visitor, isExpression)) + Debug.checkDefined(visitNode(right, visitor, isExpression)), ), - node - ) + node, + ), ), - node + node, ); } else { - return factory.updateBinaryExpression(node, target, node.operatorToken, Debug.checkDefined(visitNode(right, visitor, isExpression))); + return factory.updateBinaryExpression( + node, + target, + node.operatorToken, + Debug.checkDefined(visitNode(right, visitor, isExpression)), + ); } } @@ -862,10 +900,12 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // .yield resumeLabel // _a + %sent% + c() - return factory.updateBinaryExpression(node, + return factory.updateBinaryExpression( + node, cacheExpression(Debug.checkDefined(visitNode(node.left, visitor, isExpression))), node.operatorToken, - Debug.checkDefined(visitNode(node.right, visitor, isExpression))); + Debug.checkDefined(visitNode(node.right, visitor, isExpression)), + ); } return visitEachChild(node, visitor, context); @@ -898,7 +938,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF } else { if (containsYield(node) && pendingExpressions.length > 0) { - emitWorker(OpCode.Statement, [factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))]); + emitWorker(OpCode.Statement, [ + factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions)), + ]); pendingExpressions = []; } @@ -921,7 +963,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF } else { if (containsYield(elem) && pendingExpressions.length > 0) { - emitWorker(OpCode.Statement, [factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))]); + emitWorker(OpCode.Statement, [ + factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions)), + ]); pendingExpressions = []; } pendingExpressions.push(Debug.checkDefined(visitNode(elem, visitor, isExpression))); @@ -968,7 +1012,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const resultLabel = defineLabel(); const resultLocal = declareLocal(); - emitAssignment(resultLocal, Debug.checkDefined(visitNode(node.left, visitor, isExpression)), /*location*/ node.left); + emitAssignment( + resultLocal, + Debug.checkDefined(visitNode(node.left, visitor, isExpression)), + /*location*/ node.left, + ); if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { // Logical `&&` shortcuts when the left-hand operand is falsey. emitBreakWhenFalse(resultLabel, resultLocal, /*location*/ node.left); @@ -978,7 +1026,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF emitBreakWhenTrue(resultLabel, resultLocal, /*location*/ node.left); } - emitAssignment(resultLocal, Debug.checkDefined(visitNode(node.right, visitor, isExpression)), /*location*/ node.right); + emitAssignment( + resultLocal, + Debug.checkDefined(visitNode(node.right, visitor, isExpression)), + /*location*/ node.right, + ); markLabel(resultLabel); return resultLocal; } @@ -1011,11 +1063,23 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const whenFalseLabel = defineLabel(); const resultLabel = defineLabel(); const resultLocal = declareLocal(); - emitBreakWhenFalse(whenFalseLabel, Debug.checkDefined(visitNode(node.condition, visitor, isExpression)), /*location*/ node.condition); - emitAssignment(resultLocal, Debug.checkDefined(visitNode(node.whenTrue, visitor, isExpression)), /*location*/ node.whenTrue); + emitBreakWhenFalse( + whenFalseLabel, + Debug.checkDefined(visitNode(node.condition, visitor, isExpression)), + /*location*/ node.condition, + ); + emitAssignment( + resultLocal, + Debug.checkDefined(visitNode(node.whenTrue, visitor, isExpression)), + /*location*/ node.whenTrue, + ); emitBreak(resultLabel); markLabel(whenFalseLabel); - emitAssignment(resultLocal, Debug.checkDefined(visitNode(node.whenFalse, visitor, isExpression)), /*location*/ node.whenFalse); + emitAssignment( + resultLocal, + Debug.checkDefined(visitNode(node.whenFalse, visitor, isExpression)), + /*location*/ node.whenFalse, + ); markLabel(resultLabel); return resultLocal; } @@ -1070,7 +1134,12 @@ export function transformGenerators(context: TransformationContext): (x: SourceF * @param elements The elements to visit. * @param multiLine Whether array literals created should be emitted on multiple lines. */ - function visitElements(elements: NodeArray, leadingElement?: Expression, location?: TextRange, multiLine?: boolean) { + function visitElements( + elements: NodeArray, + leadingElement?: Expression, + location?: TextRange, + multiLine?: boolean, + ) { // [source] // ar = [1, yield, 2]; // @@ -1087,12 +1156,13 @@ export function transformGenerators(context: TransformationContext): (x: SourceF if (numInitialElements > 0) { temp = declareLocal(); const initialElements = visitNodes(elements, visitor, isExpression, 0, numInitialElements); - emitAssignment(temp, + emitAssignment( + temp, factory.createArrayLiteralExpression( leadingElement ? [leadingElement, ...initialElements] - : initialElements - ) + : initialElements, + ), ); leadingElement = undefined; } @@ -1101,8 +1171,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF return temp ? factory.createArrayConcatCall(temp, [factory.createArrayLiteralExpression(expressions, multiLine)]) : setTextRange( - factory.createArrayLiteralExpression(leadingElement ? [leadingElement, ...expressions] : expressions, multiLine), - location + factory.createArrayLiteralExpression( + leadingElement ? [leadingElement, ...expressions] : expressions, + multiLine, + ), + location, ); function reduceElement(expressions: Expression[], element: Expression) { @@ -1117,12 +1190,12 @@ export function transformGenerators(context: TransformationContext): (x: SourceF hasAssignedTemp ? factory.createArrayConcatCall( temp, - [factory.createArrayLiteralExpression(expressions, multiLine)] + [factory.createArrayLiteralExpression(expressions, multiLine)], ) : factory.createArrayLiteralExpression( leadingElement ? [leadingElement, ...expressions] : expressions, - multiLine - ) + multiLine, + ), ); leadingElement = undefined; expressions = []; @@ -1157,16 +1230,19 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const numInitialProperties = countInitialNodesWithoutYield(properties); const temp = declareLocal(); - emitAssignment(temp, + emitAssignment( + temp, factory.createObjectLiteralExpression( visitNodes(properties, visitor, isObjectLiteralElementLike, 0, numInitialProperties), - multiLine - ) + multiLine, + ), ); const expressions = reduceLeft(properties, reduceProperty, [] as Expression[], numInitialProperties); // TODO(rbuckton): Does this need to be parented? - expressions.push(multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp); + expressions.push( + multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp, + ); return factory.inlineExpressions(expressions); function reduceProperty(expressions: Expression[], property: ObjectLiteralElementLike) { @@ -1204,9 +1280,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // .mark resumeLabel // a = _a[%sent%] - return factory.updateElementAccessExpression(node, + return factory.updateElementAccessExpression( + node, cacheExpression(Debug.checkDefined(visitNode(node.expression, visitor, isLeftHandSideExpression))), - Debug.checkDefined(visitNode(node.argumentExpression, visitor, isExpression))); + Debug.checkDefined(visitNode(node.argumentExpression, visitor, isExpression)), + ); } return visitEachChild(node, visitor, context); @@ -1224,17 +1302,22 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // .yield resumeLabel // .mark resumeLabel // _b.apply(_a, _c.concat([%sent%, 2])); - const { target, thisArg } = factory.createCallBinding(node.expression, hoistVariableDeclaration, languageVersion, /*cacheIdentifiers*/ true); + const { target, thisArg } = factory.createCallBinding( + node.expression, + hoistVariableDeclaration, + languageVersion, + /*cacheIdentifiers*/ true, + ); return setOriginalNode( setTextRange( factory.createFunctionApplyCall( cacheExpression(Debug.checkDefined(visitNode(target, visitor, isLeftHandSideExpression))), thisArg, - visitElements(node.arguments) + visitElements(node.arguments), ), - node + node, ), - node + node, ); } @@ -1254,7 +1337,10 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // .mark resumeLabel // new (_b.apply(_a, _c.concat([%sent%, 2]))); - const { target, thisArg } = factory.createCallBinding(factory.createPropertyAccessExpression(node.expression, "bind"), hoistVariableDeclaration); + const { target, thisArg } = factory.createCallBinding( + factory.createPropertyAccessExpression(node.expression, "bind"), + hoistVariableDeclaration, + ); return setOriginalNode( setTextRange( factory.createNewExpression( @@ -1263,15 +1349,15 @@ export function transformGenerators(context: TransformationContext): (x: SourceF thisArg, visitElements( node.arguments!, - /*leadingElement*/ factory.createVoidZero() - ) + /*leadingElement*/ factory.createVoidZero(), + ), ), /*typeArguments*/ undefined, - [] + [], ), - node + node, ), - node + node, ); } return visitEachChild(node, visitor, context); @@ -1353,7 +1439,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF emitStatement(visitNode(node, visitor, isStatement)); } - function transformAndEmitVariableDeclarationList(node: VariableDeclarationList): VariableDeclarationList | undefined { + function transformAndEmitVariableDeclarationList( + node: VariableDeclarationList, + ): VariableDeclarationList | undefined { for (const variable of node.declarations) { const name = factory.cloneNode(variable.name as Identifier); setCommentRange(name, variable.name); @@ -1388,9 +1476,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF return setSourceMapRange( factory.createAssignment( setSourceMapRange(factory.cloneNode(node.name) as Identifier, node.name), - Debug.checkDefined(visitNode(node.initializer, visitor, isExpression)) + Debug.checkDefined(visitNode(node.initializer, visitor, isExpression)), ), - node + node, ); } @@ -1413,7 +1501,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF if (containsYield(node.thenStatement) || containsYield(node.elseStatement)) { const endLabel = defineLabel(); const elseLabel = node.elseStatement ? defineLabel() : undefined; - emitBreakWhenFalse(node.elseStatement ? elseLabel! : endLabel, Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), /*location*/ node.expression); + emitBreakWhenFalse( + node.elseStatement ? elseLabel! : endLabel, + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), + /*location*/ node.expression, + ); transformAndEmitEmbeddedStatement(node.thenStatement); if (node.elseStatement) { emitBreak(endLabel); @@ -1547,10 +1639,10 @@ export function transformGenerators(context: TransformationContext): (x: SourceF emitStatement( setTextRange( factory.createExpressionStatement( - Debug.checkDefined(visitNode(initializer, visitor, isExpression)) + Debug.checkDefined(visitNode(initializer, visitor, isExpression)), ), - initializer - ) + initializer, + ), ); } } @@ -1567,10 +1659,10 @@ export function transformGenerators(context: TransformationContext): (x: SourceF emitStatement( setTextRange( factory.createExpressionStatement( - Debug.checkDefined(visitNode(node.incrementor, visitor, isExpression)) + Debug.checkDefined(visitNode(node.incrementor, visitor, isExpression)), ), - node.incrementor - ) + node.incrementor, + ), ); } emitBreak(conditionLabel); @@ -1593,13 +1685,14 @@ export function transformGenerators(context: TransformationContext): (x: SourceF } const variables = getInitializedVariables(initializer); - node = factory.updateForStatement(node, + node = factory.updateForStatement( + node, variables.length > 0 ? factory.inlineExpressions(map(variables, transformInitializedVariable)) : undefined, visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, visitor, isExpression), - visitIterationBody(node.statement, visitor, context) + visitIterationBody(node.statement, visitor, context), ); } else { @@ -1656,10 +1749,10 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createCallExpression( factory.createPropertyAccessExpression(keysArray, "push"), /*typeArguments*/ undefined, - [key] - ) - ) - ) + [key], + ), + ), + ), ); emitAssignment(keysIndex, factory.createNumericLiteral(0)); @@ -1669,7 +1762,10 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const endLoopLabel = beginLoopBlock(incrementLabel); markLabel(conditionLabel); - emitBreakWhenFalse(endLoopLabel, factory.createLessThan(keysIndex, factory.createPropertyAccessExpression(keysArray, "length"))); + emitBreakWhenFalse( + endLoopLabel, + factory.createLessThan(keysIndex, factory.createPropertyAccessExpression(keysArray, "length")), + ); emitAssignment(key, factory.createElementAccessExpression(keysArray, keysIndex)); emitBreakWhenFalse(incrementLabel, factory.createBinaryExpression(key, SyntaxKind.InKeyword, obj)); @@ -1725,10 +1821,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF hoistVariableDeclaration(variable.name as Identifier); } - node = factory.updateForInStatement(node, + node = factory.updateForInStatement( + node, initializer.declarations[0].name as Identifier, Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), - Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock)) + Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock)), ); } else { @@ -1789,14 +1886,14 @@ export function transformGenerators(context: TransformationContext): (x: SourceF function transformAndEmitReturnStatement(node: ReturnStatement): void { emitReturn( visitNode(node.expression, visitor, isExpression), - /*location*/ node + /*location*/ node, ); } function visitReturnStatement(node: ReturnStatement) { return createInlineReturn( visitNode(node.expression, visitor, isExpression), - /*location*/ node + /*location*/ node, ); } @@ -1889,9 +1986,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createCaseClause( Debug.checkDefined(visitNode(clause.expression, visitor, isExpression)), [ - createInlineBreak(clauseLabels[i], /*location*/ clause.expression) - ] - ) + createInlineBreak(clauseLabels[i], /*location*/ clause.expression), + ], + ), ); } else { @@ -1982,7 +2079,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // TODO(rbuckton): `expression` should be required on `throw`. emitThrow( Debug.checkDefined(visitNode(node.expression ?? factory.createVoidZero(), visitor, isExpression)), - /*location*/ node + /*location*/ node, ); } @@ -2192,7 +2289,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF kind: CodeBlockKind.With, expression, startLabel, - endLabel + endLabel, }); } @@ -2216,7 +2313,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF kind: CodeBlockKind.Exception, state: ExceptionBlockState.Try, startLabel, - endLabel + endLabel, }); emitNop(); return endLabel; @@ -2261,7 +2358,14 @@ export function transformGenerators(context: TransformationContext): (x: SourceF exception.catchVariable = name; exception.catchLabel = catchLabel; - emitAssignment(name, factory.createCallExpression(factory.createPropertyAccessExpression(state, "sent"), /*typeArguments*/ undefined, [])); + emitAssignment( + name, + factory.createCallExpression( + factory.createPropertyAccessExpression(state, "sent"), + /*typeArguments*/ undefined, + [], + ), + ); emitNop(); } @@ -2313,7 +2417,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF kind: CodeBlockKind.Loop, isScript: true, breakLabel: -1, - continueLabel: -1 + continueLabel: -1, }); } @@ -2352,13 +2456,12 @@ export function transformGenerators(context: TransformationContext): (x: SourceF /** * Begins a code block that supports `break` statements that are defined in the source * tree and not from generated code. - * */ function beginScriptSwitchBlock(): void { beginBlock({ kind: CodeBlockKind.Switch, isScript: true, - breakLabel: -1 + breakLabel: -1, }); } @@ -2394,7 +2497,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF kind: CodeBlockKind.Labeled, isScript: true, labelText, - breakLabel: -1 + breakLabel: -1, }); } @@ -2404,7 +2507,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF kind: CodeBlockKind.Labeled, isScript: false, labelText, - breakLabel + breakLabel, }); } @@ -2563,10 +2666,10 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createReturnStatement( factory.createArrayLiteralExpression([ createInstruction(Instruction.Break), - createLabel(label) - ]) + createLabel(label), + ]), ), - location + location, ); } @@ -2579,12 +2682,13 @@ export function transformGenerators(context: TransformationContext): (x: SourceF function createInlineReturn(expression?: Expression, location?: TextRange): ReturnStatement { return setTextRange( factory.createReturnStatement( - factory.createArrayLiteralExpression(expression - ? [createInstruction(Instruction.Return), expression] - : [createInstruction(Instruction.Return)] - ) + factory.createArrayLiteralExpression( + expression + ? [createInstruction(Instruction.Return), expression] + : [createInstruction(Instruction.Return)], + ), ), - location + location, ); } @@ -2596,9 +2700,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createCallExpression( factory.createPropertyAccessExpression(state, "sent"), /*typeArguments*/ undefined, - [] + [], ), - location + location, ); } @@ -2766,11 +2870,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF /*type*/ undefined, factory.createBlock( buildResult, - /*multiLine*/ buildResult.length > 0 - ) + /*multiLine*/ buildResult.length > 0, + ), ), - EmitFlags.ReuseTempVariableScope - ) + EmitFlags.ReuseTempVariableScope, + ), ); } @@ -2892,18 +2996,21 @@ export function transformGenerators(context: TransformationContext): (x: SourceF statements.unshift( factory.createExpressionStatement( factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(state, "trys"), "push"), + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression(state, "trys"), + "push", + ), /*typeArguments*/ undefined, [ factory.createArrayLiteralExpression([ createLabel(startLabel), createLabel(catchLabel), createLabel(finallyLabel), - createLabel(endLabel) - ]) - ] - ) - ) + createLabel(endLabel), + ]), + ], + ), + ), ); currentExceptionBlock = undefined; @@ -2916,9 +3023,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createExpressionStatement( factory.createAssignment( factory.createPropertyAccessExpression(state, "label"), - factory.createNumericLiteral(labelNumber + 1) - ) - ) + factory.createNumericLiteral(labelNumber + 1), + ), + ), ); } } @@ -2926,8 +3033,8 @@ export function transformGenerators(context: TransformationContext): (x: SourceF clauses.push( factory.createCaseClause( factory.createNumericLiteral(labelNumber), - statements || [] - ) + statements || [], + ), ); statements = undefined; @@ -3016,7 +3123,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF withBlockStack!.pop(); } break; - // default: do nothing + // default: do nothing } } } @@ -3097,7 +3204,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF * @param operationLocation The source map location for the operation. */ function writeAssign(left: Expression, right: Expression, operationLocation: TextRange | undefined): void { - writeStatement(setTextRange(factory.createExpressionStatement(factory.createAssignment(left, right)), operationLocation)); + writeStatement( + setTextRange(factory.createExpressionStatement(factory.createAssignment(left, right)), operationLocation), + ); } /** @@ -3125,15 +3234,16 @@ export function transformGenerators(context: TransformationContext): (x: SourceF setEmitFlags( setTextRange( factory.createReturnStatement( - factory.createArrayLiteralExpression(expression - ? [createInstruction(Instruction.Return), expression] - : [createInstruction(Instruction.Return)] - ) + factory.createArrayLiteralExpression( + expression + ? [createInstruction(Instruction.Return), expression] + : [createInstruction(Instruction.Return)], + ), ), - operationLocation + operationLocation, ), - EmitFlags.NoTokenSourceMaps - ) + EmitFlags.NoTokenSourceMaps, + ), ); } @@ -3151,13 +3261,13 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createReturnStatement( factory.createArrayLiteralExpression([ createInstruction(Instruction.Break), - createLabel(label) - ]) + createLabel(label), + ]), ), - operationLocation + operationLocation, ), - EmitFlags.NoTokenSourceMaps - ) + EmitFlags.NoTokenSourceMaps, + ), ); } @@ -3178,16 +3288,16 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createReturnStatement( factory.createArrayLiteralExpression([ createInstruction(Instruction.Break), - createLabel(label) - ]) + createLabel(label), + ]), ), - operationLocation + operationLocation, ), - EmitFlags.NoTokenSourceMaps - ) + EmitFlags.NoTokenSourceMaps, + ), ), - EmitFlags.SingleLine - ) + EmitFlags.SingleLine, + ), ); } @@ -3208,16 +3318,16 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createReturnStatement( factory.createArrayLiteralExpression([ createInstruction(Instruction.Break), - createLabel(label) - ]) + createLabel(label), + ]), ), - operationLocation + operationLocation, ), - EmitFlags.NoTokenSourceMaps - ) + EmitFlags.NoTokenSourceMaps, + ), ), - EmitFlags.SingleLine - ) + EmitFlags.SingleLine, + ), ); } @@ -3236,13 +3346,13 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createArrayLiteralExpression( expression ? [createInstruction(Instruction.Yield), expression] - : [createInstruction(Instruction.Yield)] - ) + : [createInstruction(Instruction.Yield)], + ), ), - operationLocation + operationLocation, ), - EmitFlags.NoTokenSourceMaps - ) + EmitFlags.NoTokenSourceMaps, + ), ); } @@ -3260,13 +3370,13 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createReturnStatement( factory.createArrayLiteralExpression([ createInstruction(Instruction.YieldStar), - expression - ]) + expression, + ]), ), - operationLocation + operationLocation, ), - EmitFlags.NoTokenSourceMaps - ) + EmitFlags.NoTokenSourceMaps, + ), ); } @@ -3278,9 +3388,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF writeStatement( factory.createReturnStatement( factory.createArrayLiteralExpression([ - createInstruction(Instruction.Endfinally) - ]) - ) + createInstruction(Instruction.Endfinally), + ]), + ), ); } } diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index fe3ccc883f718..9483a81a8b61c 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -106,8 +106,16 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B if (currentFileState.filenameDeclaration) { return currentFileState.filenameDeclaration.name; } - const declaration = factory.createVariableDeclaration(factory.createUniqueName("_jsxFileName", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), /*exclamationToken*/ undefined, /*type*/ undefined, factory.createStringLiteral(currentSourceFile.fileName)); - currentFileState.filenameDeclaration = declaration as VariableDeclaration & { name: Identifier }; + const declaration = factory.createVariableDeclaration( + factory.createUniqueName( + "_jsxFileName", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createStringLiteral(currentSourceFile.fileName), + ); + currentFileState.filenameDeclaration = declaration as VariableDeclaration & { name: Identifier; }; return currentFileState.filenameDeclaration.name; } @@ -140,8 +148,16 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B specifierSourceImports = new Map(); currentFileState.utilizedImplicitRuntimeImports.set(importSource, specifierSourceImports); } - const generatedName = factory.createUniqueName(`_${name}`, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel | GeneratedIdentifierFlags.AllowNameSubstitution); - const specifier = factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier(name), generatedName); + const generatedName = factory.createUniqueName( + `_${name}`, + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel + | GeneratedIdentifierFlags.AllowNameSubstitution, + ); + const specifier = factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier(name), + generatedName, + ); setIdentifierGeneratedImportReference(generatedName, specifier); specifierSourceImports.set(name, specifier); return generatedName; @@ -164,26 +180,59 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B addEmitHelpers(visited, context.readEmitHelpers()); let statements: readonly Statement[] = visited.statements; if (currentFileState.filenameDeclaration) { - statements = insertStatementAfterCustomPrologue(statements.slice(), factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([currentFileState.filenameDeclaration], NodeFlags.Const))); + statements = insertStatementAfterCustomPrologue( + statements.slice(), + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([currentFileState.filenameDeclaration], NodeFlags.Const), + ), + ); } if (currentFileState.utilizedImplicitRuntimeImports) { - for (const [importSource, importSpecifiersMap] of arrayFrom(currentFileState.utilizedImplicitRuntimeImports.entries())) { + for ( + const [importSource, importSpecifiersMap] of arrayFrom( + currentFileState.utilizedImplicitRuntimeImports.entries(), + ) + ) { if (isExternalModule(node)) { // Add `import` statement - const importStatement = factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamedImports(arrayFrom(importSpecifiersMap.values()))), factory.createStringLiteral(importSource), /*assertClause*/ undefined); + const importStatement = factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause( + /*isTypeOnly*/ false, + /*name*/ undefined, + factory.createNamedImports(arrayFrom(importSpecifiersMap.values())), + ), + factory.createStringLiteral(importSource), + /*assertClause*/ undefined, + ); setParentRecursive(importStatement, /*incremental*/ false); statements = insertStatementAfterCustomPrologue(statements.slice(), importStatement); } else if (isExternalOrCommonJsModule(node)) { // Add `require` statement - const requireStatement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([ - factory.createVariableDeclaration( - factory.createObjectBindingPattern(arrayFrom(importSpecifiersMap.values(), s => factory.createBindingElement(/*dotDotDotToken*/ undefined, s.propertyName, s.name))), - /*exclamationToken*/ undefined, - /*type*/ undefined, - factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [factory.createStringLiteral(importSource)]) - ) - ], NodeFlags.Const)); + const requireStatement = factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration( + factory.createObjectBindingPattern( + arrayFrom(importSpecifiersMap.values(), s => + factory.createBindingElement( + /*dotDotDotToken*/ undefined, + s.propertyName, + s.name, + )), + ), + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createCallExpression( + factory.createIdentifier("require"), + /*typeArguments*/ undefined, + [factory.createStringLiteral(importSource)], + ), + ), + ], NodeFlags.Const), + ); setParentRecursive(requireStatement, /*incremental*/ false); statements = insertStatementAfterCustomPrologue(statements.slice(), requireStatement); } @@ -250,8 +299,11 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B } function hasProto(obj: ObjectLiteralExpression) { - return obj.properties.some(p => isPropertyAssignment(p) && - (isIdentifier(p.name) && idText(p.name) === "__proto__" || isStringLiteral(p.name) && p.name.text === "__proto__")); + return obj.properties.some(p => + isPropertyAssignment(p) + && (isIdentifier(p.name) && idText(p.name) === "__proto__" + || isStringLiteral(p.name) && p.name.text === "__proto__") + ); } /** @@ -260,7 +312,10 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B function hasKeyAfterPropsSpread(node: JsxOpeningLikeElement) { let spread = false; for (const elem of node.attributes.properties) { - if (isJsxSpreadAttribute(elem) && (!isObjectLiteralExpression(elem.expression) || elem.expression.properties.some(isSpreadAssignment))) { + if ( + isJsxSpreadAttribute(elem) + && (!isObjectLiteralExpression(elem.expression) || elem.expression.properties.some(isSpreadAssignment)) + ) { spread = true; } else if (spread && isJsxAttribute(elem) && isIdentifier(elem.name) && elem.name.escapedText === "key") { @@ -275,17 +330,20 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B } function visitJsxElement(node: JsxElement, isChild: boolean) { - const tagTransform = shouldUseCreateElement(node.openingElement) ? visitJsxOpeningLikeElementCreateElement : visitJsxOpeningLikeElementJSX; + const tagTransform = shouldUseCreateElement(node.openingElement) ? visitJsxOpeningLikeElementCreateElement + : visitJsxOpeningLikeElementJSX; return tagTransform(node.openingElement, node.children, isChild, /*location*/ node); } function visitJsxSelfClosingElement(node: JsxSelfClosingElement, isChild: boolean) { - const tagTransform = shouldUseCreateElement(node) ? visitJsxOpeningLikeElementCreateElement : visitJsxOpeningLikeElementJSX; + const tagTransform = shouldUseCreateElement(node) ? visitJsxOpeningLikeElementCreateElement + : visitJsxOpeningLikeElementJSX; return tagTransform(node, /*children*/ undefined, isChild, /*location*/ node); } function visitJsxFragment(node: JsxFragment, isChild: boolean) { - const tagTransform = currentFileState.importSpecifier === undefined ? visitJsxOpeningFragmentCreateElement : visitJsxOpeningFragmentJSX; + const tagTransform = currentFileState.importSpecifier === undefined ? visitJsxOpeningFragmentCreateElement + : visitJsxOpeningFragmentJSX; return tagTransform(node.openingFragment, node.children, isChild, /*location*/ node); } @@ -301,23 +359,33 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B return result && factory.createPropertyAssignment("children", result); } const result = mapDefined(children, transformJsxChildToExpression); - return length(result) ? factory.createPropertyAssignment("children", factory.createArrayLiteralExpression(result)) : undefined; + return length(result) + ? factory.createPropertyAssignment("children", factory.createArrayLiteralExpression(result)) : undefined; } - function visitJsxOpeningLikeElementJSX(node: JsxOpeningLikeElement, children: readonly JsxChild[] | undefined, isChild: boolean, location: TextRange) { + function visitJsxOpeningLikeElementJSX( + node: JsxOpeningLikeElement, + children: readonly JsxChild[] | undefined, + isChild: boolean, + location: TextRange, + ) { const tagName = getTagName(node); - const childrenProp = children && children.length ? convertJsxChildrenToChildrenPropAssignment(children) : undefined; - const keyAttr = find(node.attributes.properties, p => !!p.name && isIdentifier(p.name) && p.name.escapedText === "key") as JsxAttribute | undefined; + const childrenProp = children && children.length ? convertJsxChildrenToChildrenPropAssignment(children) + : undefined; + const keyAttr = find( + node.attributes.properties, + p => !!p.name && isIdentifier(p.name) && p.name.escapedText === "key", + ) as JsxAttribute | undefined; const attrs = keyAttr ? filter(node.attributes.properties, p => p !== keyAttr) : node.attributes.properties; - const objectProperties = length(attrs) ? transformJsxAttributesToObjectProps(attrs, childrenProp) : - factory.createObjectLiteralExpression(childrenProp ? [childrenProp] : emptyArray); // When there are no attributes, React wants {} + const objectProperties = length(attrs) ? transformJsxAttributesToObjectProps(attrs, childrenProp) + : factory.createObjectLiteralExpression(childrenProp ? [childrenProp] : emptyArray); // When there are no attributes, React wants {} return visitJsxOpeningLikeElementOrFragmentJSX( tagName, objectProperties, keyAttr, children || emptyArray, isChild, - location + location, ); } @@ -327,11 +395,11 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B keyAttr: JsxAttribute | undefined, children: readonly JsxChild[], isChild: boolean, - location: TextRange + location: TextRange, ) { const nonWhitespaceChildren = getSemanticJsxChildren(children); - const isStaticChildren = - length(nonWhitespaceChildren) > 1 || !!(nonWhitespaceChildren[0] as JsxExpression)?.dotDotDotToken; + const isStaticChildren = length(nonWhitespaceChildren) > 1 + || !!(nonWhitespaceChildren[0] as JsxExpression)?.dotDotDotToken; const args: Expression[] = [tagName, objectProperties]; // function jsx(type, config, maybeKey) {} // "maybeKey" is optional. It is acceptable to use "_jsx" without a third argument @@ -352,7 +420,10 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B args.push(factory.createObjectLiteralExpression([ factory.createPropertyAssignment("fileName", getCurrentFileNameExpression()), factory.createPropertyAssignment("lineNumber", factory.createNumericLiteral(lineCol.line + 1)), - factory.createPropertyAssignment("columnNumber", factory.createNumericLiteral(lineCol.character + 1)) + factory.createPropertyAssignment( + "columnNumber", + factory.createNumericLiteral(lineCol.character + 1), + ), ])); // __self development flag args.push(factory.createThis()); @@ -361,7 +432,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B const element = setTextRange( factory.createCallExpression(getJsxFactoryCallee(isStaticChildren), /*typeArguments*/ undefined, args), - location + location, ); if (isChild) { @@ -371,18 +442,23 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B return element; } - function visitJsxOpeningLikeElementCreateElement(node: JsxOpeningLikeElement, children: readonly JsxChild[] | undefined, isChild: boolean, location: TextRange) { + function visitJsxOpeningLikeElementCreateElement( + node: JsxOpeningLikeElement, + children: readonly JsxChild[] | undefined, + isChild: boolean, + location: TextRange, + ) { const tagName = getTagName(node); const attrs = node.attributes.properties; - const objectProperties = length(attrs) ? transformJsxAttributesToObjectProps(attrs) : - factory.createNull(); // When there are no attributes, React wants "null" + const objectProperties = length(attrs) ? transformJsxAttributesToObjectProps(attrs) + : factory.createNull(); // When there are no attributes, React wants "null" const callee = currentFileState.importSpecifier === undefined ? createJsxFactoryExpression( factory, context.getEmitResolver().getJsxFactoryEntity(currentSourceFile), compilerOptions.reactNamespace!, // TODO: GH#18217 - node + node, ) : getImplicitImportForName("createElement"); @@ -392,7 +468,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B tagName, objectProperties, mapDefined(children, transformJsxChildToExpression), - location + location, ); if (isChild) { @@ -402,7 +478,12 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B return element; } - function visitJsxOpeningFragmentJSX(_node: JsxOpeningFragment, children: readonly JsxChild[], isChild: boolean, location: TextRange) { + function visitJsxOpeningFragmentJSX( + _node: JsxOpeningFragment, + children: readonly JsxChild[], + isChild: boolean, + location: TextRange, + ) { let childrenProps: Expression | undefined; if (children && children.length) { const result = convertJsxChildrenToChildrenPropObject(children); @@ -416,11 +497,16 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B /*keyAttr*/ undefined, children, isChild, - location + location, ); } - function visitJsxOpeningFragmentCreateElement(node: JsxOpeningFragment, children: readonly JsxChild[], isChild: boolean, location: TextRange) { + function visitJsxOpeningFragmentCreateElement( + node: JsxOpeningFragment, + children: readonly JsxChild[], + isChild: boolean, + location: TextRange, + ) { const element = createExpressionForJsxFragment( factory, context.getEmitResolver().getJsxFactoryEntity(currentSourceFile), @@ -428,7 +514,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B compilerOptions.reactNamespace!, // TODO: GH#18217 mapDefined(children, transformJsxChildToExpression), node, - location + location, ); if (isChild) { @@ -445,22 +531,40 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B return factory.createSpreadAssignment(Debug.checkDefined(visitNode(node.expression, visitor, isExpression))); } - function transformJsxAttributesToObjectProps(attrs: readonly(JsxSpreadAttribute | JsxAttribute)[], children?: PropertyAssignment) { + function transformJsxAttributesToObjectProps( + attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], + children?: PropertyAssignment, + ) { const target = getEmitScriptTarget(compilerOptions); - return target && target >= ScriptTarget.ES2018 ? factory.createObjectLiteralExpression(transformJsxAttributesToProps(attrs, children)) : - transformJsxAttributesToExpression(attrs, children); + return target && target >= ScriptTarget.ES2018 + ? factory.createObjectLiteralExpression(transformJsxAttributesToProps(attrs, children)) + : transformJsxAttributesToExpression(attrs, children); } - function transformJsxAttributesToProps(attrs: readonly(JsxSpreadAttribute | JsxAttribute)[], children?: PropertyAssignment) { - const props = flatten(spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => - flatten(map(attrs, attr => isSpread ? transformJsxSpreadAttributeToProps(attr as JsxSpreadAttribute) : transformJsxAttributeToObjectLiteralElement(attr as JsxAttribute))))); + function transformJsxAttributesToProps( + attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], + children?: PropertyAssignment, + ) { + const props = flatten( + spanMap( + attrs, + isJsxSpreadAttribute, + (attrs, isSpread) => + flatten(map(attrs, attr => + isSpread ? transformJsxSpreadAttributeToProps(attr as JsxSpreadAttribute) + : transformJsxAttributeToObjectLiteralElement(attr as JsxAttribute))), + ), + ); if (children) { props.push(children); } return props; } - function transformJsxAttributesToExpression(attrs: readonly(JsxSpreadAttribute | JsxAttribute)[], children?: PropertyAssignment) { + function transformJsxAttributesToExpression( + attrs: readonly (JsxSpreadAttribute | JsxAttribute)[], + children?: PropertyAssignment, + ) { const expressions: Expression[] = []; let properties: ObjectLiteralElementLike[] = []; @@ -522,7 +626,8 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B if (node.kind === SyntaxKind.StringLiteral) { // Always recreate the literal to escape any escape sequences or newlines which may be in the original jsx string and which // Need to be escaped to be handled correctly in a normal string - const singleQuote = node.singleQuote !== undefined ? node.singleQuote : !isStringDoubleQuoted(node, currentSourceFile); + const singleQuote = node.singleQuote !== undefined ? node.singleQuote + : !isStringDoubleQuoted(node, currentSourceFile); const literal = factory.createStringLiteral(tryDecodeEntities(node.text) || node.text, singleQuote); return setTextRange(literal, node); } @@ -580,7 +685,10 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B // If we've seen any non-whitespace characters on this line, add the 'trim' of the line. // (lastNonWhitespace === -1 is a special flag to detect whether the first line is all whitespace.) if (firstNonWhitespace !== -1 && lastNonWhitespace !== -1) { - acc = addLineOfJsxText(acc, text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1)); + acc = addLineOfJsxText( + acc, + text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1), + ); } // Reset firstNonWhitespace for the next line. @@ -614,19 +722,22 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B * See https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references */ function decodeEntities(text: string): string { - return text.replace(/&((#((\d+)|x([\da-fA-F]+)))|(\w+));/g, (match, _all, _number, _digits, decimal, hex, word) => { - if (decimal) { - return utf16EncodeAsString(parseInt(decimal, 10)); - } - else if (hex) { - return utf16EncodeAsString(parseInt(hex, 16)); - } - else { - const ch = entities.get(word); - // If this is not a valid entity, then just use `match` (replace it with itself, i.e. don't replace) - return ch ? utf16EncodeAsString(ch) : match; - } - }); + return text.replace( + /&((#((\d+)|x([\da-fA-F]+)))|(\w+));/g, + (match, _all, _number, _digits, decimal, hex, word) => { + if (decimal) { + return utf16EncodeAsString(parseInt(decimal, 10)); + } + else if (hex) { + return utf16EncodeAsString(parseInt(hex, 16)); + } + else { + const ch = entities.get(word); + // If this is not a valid entity, then just use `match` (replace it with itself, i.e. don't replace) + return ch ? utf16EncodeAsString(ch) : match; + } + }, + ); } /** Like `decodeEntities` but returns `undefined` if there were no entities to decode. */ @@ -926,5 +1037,5 @@ const entities = new Map(Object.entries({ spades: 0x2660, clubs: 0x2663, hearts: 0x2665, - diams: 0x2666 + diams: 0x2666, })); diff --git a/src/compiler/transformers/legacyDecorators.ts b/src/compiler/transformers/legacyDecorators.ts index d8ff2bcf72bb4..a722c2dfa7d14 100644 --- a/src/compiler/transformers/legacyDecorators.ts +++ b/src/compiler/transformers/legacyDecorators.ts @@ -85,7 +85,9 @@ import { } from "../_namespaces/ts"; /** @internal */ -export function transformLegacyDecorators(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle { +export function transformLegacyDecorators( + context: TransformationContext, +): (x: SourceFile | Bundle) => SourceFile | Bundle { const { factory, getEmitHelperFactory: emitHelpers, @@ -151,13 +153,16 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S } function visitClassDeclaration(node: ClassDeclaration): VisitResult { - if (!(classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ true, node) || childIsDecorated(/*useLegacyDecorators*/ true, node))) { + if ( + !(classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ true, node) + || childIsDecorated(/*useLegacyDecorators*/ true, node)) + ) { return visitEachChild(node, visitor, context); } - const statements = classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ true, node) ? - transformClassDeclarationWithClassDecorators(node, node.name) : - transformClassDeclarationWithoutClassDecorators(node, node.name); + const statements = classOrConstructorParameterIsDecorated(/*useLegacyDecorators*/ true, node) + ? transformClassDeclarationWithClassDecorators(node, node.name) + : transformClassDeclarationWithoutClassDecorators(node, node.name); return singleOrMany(statements); } @@ -166,7 +171,9 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return !!(decorator.transformFlags & TransformFlags.ContainsPrivateIdentifierInExpression); } - function parameterDecoratorsContainPrivateIdentifierInExpression(parameterDecorators: readonly Decorator[] | undefined) { + function parameterDecoratorsContainPrivateIdentifierInExpression( + parameterDecorators: readonly Decorator[] | undefined, + ) { return some(parameterDecorators, decoratorContainsPrivateIdentifierInExpression); } @@ -185,12 +192,15 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S addClassElementDecorationStatements(decorationStatements, node, /*isStatic*/ false); addClassElementDecorationStatements(decorationStatements, node, /*isStatic*/ true); if (hasClassElementWithDecoratorContainingPrivateIdentifierInExpression(node)) { - members = setTextRange(factory.createNodeArray([ - ...members, - factory.createClassStaticBlockDeclaration( - factory.createBlock(decorationStatements, /*multiLine*/ true) - ) - ]), members); + members = setTextRange( + factory.createNodeArray([ + ...members, + factory.createClassStaticBlockDeclaration( + factory.createBlock(decorationStatements, /*multiLine*/ true), + ), + ]), + members, + ); decorationStatements = undefined; } return { decorationStatements, members }; @@ -220,7 +230,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S name, /*typeParameters*/ undefined, heritageClauses, - members + members, ); return addRange([updated], decorationStatements); @@ -319,16 +329,20 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S const isExport = hasSyntacticModifier(node, ModifierFlags.Export); const isDefault = hasSyntacticModifier(node, ModifierFlags.Default); - const modifiers = visitNodes(node.modifiers, node => isExportOrDefaultModifier(node) || isDecorator(node) ? undefined : node, isModifierLike); + const modifiers = visitNodes( + node.modifiers, + node => isExportOrDefaultModifier(node) || isDecorator(node) ? undefined : node, + isModifierLike, + ); const location = moveRangePastModifiers(node); const classAlias = getClassAliasIfNeeded(node); // When we transform to ES5/3 this will be moved inside an IIFE and should reference the name // without any block-scoped variable collision handling - const declName = languageVersion < ScriptTarget.ES2015 ? - factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) : - factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); + const declName = languageVersion < ScriptTarget.ES2015 + ? factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) + : factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); // ... = class ${name} ${heritageClauses} { // ${members} @@ -341,23 +355,28 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S // If we're emitting to ES2022 or later then we need to reassign the class alias before // static initializers are evaluated. - const assignClassAliasInStaticBlock = - languageVersion >= ScriptTarget.ES2022 && - !!classAlias && - some(members, member => - isPropertyDeclaration(member) && hasSyntacticModifier(member, ModifierFlags.Static) || - isClassStaticBlockDeclaration(member)); + const assignClassAliasInStaticBlock = languageVersion >= ScriptTarget.ES2022 + && !!classAlias + && some( + members, + member => + isPropertyDeclaration(member) && hasSyntacticModifier(member, ModifierFlags.Static) + || isClassStaticBlockDeclaration(member), + ); if (assignClassAliasInStaticBlock) { - members = setTextRange(factory.createNodeArray([ - factory.createClassStaticBlockDeclaration( - factory.createBlock([ - factory.createExpressionStatement( - factory.createAssignment(classAlias, factory.createThis()) - ) - ]) - ), - ...members - ]), members); + members = setTextRange( + factory.createNodeArray([ + factory.createClassStaticBlockDeclaration( + factory.createBlock([ + factory.createExpressionStatement( + factory.createAssignment(classAlias, factory.createThis()), + ), + ]), + ), + ...members, + ]), + members, + ); } const classExpression = factory.createClassExpression( @@ -365,15 +384,22 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S name && isGeneratedIdentifier(name) ? undefined : name, /*typeParameters*/ undefined, heritageClauses, - members); + members, + ); setOriginalNode(classExpression, node); setTextRange(classExpression, location); // let ${name} = ${classExpression} where name is either declaredName if the class doesn't contain self-reference // or decoratedClassAlias if the class contain self-reference. - const varInitializer = classAlias && !assignClassAliasInStaticBlock ? factory.createAssignment(classAlias, classExpression) : classExpression; - const varDecl = factory.createVariableDeclaration(declName, /*exclamationToken*/ undefined, /*type*/ undefined, varInitializer); + const varInitializer = classAlias && !assignClassAliasInStaticBlock + ? factory.createAssignment(classAlias, classExpression) : classExpression; + const varDecl = factory.createVariableDeclaration( + declName, + /*exclamationToken*/ undefined, + /*type*/ undefined, + varInitializer, + ); setOriginalNode(varDecl, node); const varDeclList = factory.createVariableDeclarationList([varDecl], NodeFlags.Let); @@ -408,7 +434,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S node.name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - visitNodes(node.members, visitor, isClassElement) + visitNodes(node.members, visitor, isClassElement), ); } @@ -417,7 +443,8 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S node, visitNodes(node.modifiers, modifierVisitor, isModifier), visitNodes(node.parameters, visitor, isParameter), - visitNode(node.body, visitor, isBlock)); + visitNode(node.body, visitor, isBlock), + ); } function finishClassElement(updated: ClassElement, original: ClassElement) { @@ -431,38 +458,47 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S } function visitMethodDeclaration(node: MethodDeclaration) { - return finishClassElement(factory.updateMethodDeclaration( + return finishClassElement( + factory.updateMethodDeclaration( + node, + visitNodes(node.modifiers, modifierVisitor, isModifier), + node.asteriskToken, + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), + /*questionToken*/ undefined, + /*typeParameters*/ undefined, + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + visitNode(node.body, visitor, isBlock), + ), node, - visitNodes(node.modifiers, modifierVisitor, isModifier), - node.asteriskToken, - Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), - /*questionToken*/ undefined, - /*typeParameters*/ undefined, - visitNodes(node.parameters, visitor, isParameter), - /*type*/ undefined, - visitNode(node.body, visitor, isBlock) - ), node); + ); } function visitGetAccessorDeclaration(node: GetAccessorDeclaration) { - return finishClassElement(factory.updateGetAccessorDeclaration( + return finishClassElement( + factory.updateGetAccessorDeclaration( + node, + visitNodes(node.modifiers, modifierVisitor, isModifier), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), + visitNodes(node.parameters, visitor, isParameter), + /*type*/ undefined, + visitNode(node.body, visitor, isBlock), + ), node, - visitNodes(node.modifiers, modifierVisitor, isModifier), - Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), - visitNodes(node.parameters, visitor, isParameter), - /*type*/ undefined, - visitNode(node.body, visitor, isBlock) - ), node); + ); } function visitSetAccessorDeclaration(node: SetAccessorDeclaration) { - return finishClassElement(factory.updateSetAccessorDeclaration( + return finishClassElement( + factory.updateSetAccessorDeclaration( + node, + visitNodes(node.modifiers, modifierVisitor, isModifier), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), + visitNodes(node.parameters, visitor, isParameter), + visitNode(node.body, visitor, isBlock), + ), node, - visitNodes(node.modifiers, modifierVisitor, isModifier), - Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), - visitNodes(node.parameters, visitor, isParameter), - visitNode(node.body, visitor, isBlock) - ), node); + ); } function visitPropertyDeclaration(node: PropertyDeclaration) { @@ -470,14 +506,17 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return undefined; } - return finishClassElement(factory.updatePropertyDeclaration( + return finishClassElement( + factory.updatePropertyDeclaration( + node, + visitNodes(node.modifiers, modifierVisitor, isModifier), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + visitNode(node.initializer, visitor, isExpression), + ), node, - visitNodes(node.modifiers, modifierVisitor, isModifier), - Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), - /*questionOrExclamationToken*/ undefined, - /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression) - ), node); + ); } function visitParameterDeclaration(node: ParameterDeclaration) { @@ -488,7 +527,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S Debug.checkDefined(visitNode(node.name, visitor, isBindingName)), /*questionToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression) + visitNode(node.initializer, visitor, isExpression), ); if (updated !== node) { // While we emit the source map for the node after skipping decorators and modifiers, @@ -533,7 +572,13 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S * instance members. */ function addClassElementDecorationStatements(statements: Statement[], node: ClassDeclaration, isStatic: boolean) { - addRange(statements, map(generateClassElementDecorationExpressions(node, isStatic), expr => factory.createExpressionStatement(expr))); + addRange( + statements, + map( + generateClassElementDecorationExpressions(node, isStatic), + expr => factory.createExpressionStatement(expr), + ), + ); } /** @@ -555,7 +600,10 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S * @param isStatic A value indicating whether to retrieve static or instance members of * the class. */ - function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): readonly ClassElement[] { + function getDecoratedClassElements( + node: ClassExpression | ClassDeclaration, + isStatic: boolean, + ): readonly ClassElement[] { return filter(node.members, m => isDecoratedClassElement(m, isStatic, node)); } @@ -621,13 +669,15 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S // const prefix = getClassMemberPrefix(node, member); - const memberName = getExpressionForPropertyName(member, /*generateNameForComputedPropertyName*/ !hasSyntacticModifier(member, ModifierFlags.Ambient)); + const memberName = getExpressionForPropertyName( + member, + /*generateNameForComputedPropertyName*/ !hasSyntacticModifier(member, ModifierFlags.Ambient), + ); const descriptor = languageVersion > ScriptTarget.ES3 ? isPropertyDeclaration(member) && !hasAccessorModifier(member) // We emit `void 0` here to indicate to `__decorate` that it can invoke `Object.defineProperty` directly, but that it // should not invoke `Object.getOwnPropertyDescriptor`. ? factory.createVoidZero() - // We emit `null` here to indicate to `__decorate` that it can invoke `Object.getOwnPropertyDescriptor` directly. // We have this extra argument here so that we can inject an explicit property descriptor at a later date. : factory.createNull() @@ -637,7 +687,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S decoratorExpressions, prefix, memberName, - descriptor + descriptor, ); setEmitFlags(helper, EmitFlags.NoComments); @@ -673,11 +723,14 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S // When we transform to ES5/3 this will be moved inside an IIFE and should reference the name // without any block-scoped variable collision handling - const localName = languageVersion < ScriptTarget.ES2015 ? - factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) : - factory.getDeclarationName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); + const localName = languageVersion < ScriptTarget.ES2015 + ? factory.getInternalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true) + : factory.getDeclarationName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); const decorate = emitHelpers().createDecorateHelper(decoratorExpressions, localName); - const expression = factory.createAssignment(localName, classAlias ? factory.createAssignment(classAlias, decorate) : decorate); + const expression = factory.createAssignment( + localName, + classAlias ? factory.createAssignment(classAlias, decorate) : decorate, + ); setEmitFlags(expression, EmitFlags.NoComments); setSourceMapRange(expression, moveRangePastModifiers(node)); return expression; @@ -705,7 +758,8 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S for (const decorator of decorators) { const helper = emitHelpers().createParamHelper( transformDecorator(decorator), - parameterOffset); + parameterOffset, + ); setTextRange(helper, decorator.expression); setEmitFlags(helper, EmitFlags.NoComments); expressions.push(helper); @@ -721,7 +775,10 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S * * @param member The member whose name should be converted into an expression. */ - function getExpressionForPropertyName(member: ClassElement | EnumMember, generateNameForComputedPropertyName: boolean): Expression { + function getExpressionForPropertyName( + member: ClassElement | EnumMember, + generateNameForComputedPropertyName: boolean, + ): Expression { const name = member.name!; if (isPrivateIdentifier(name)) { return factory.createIdentifier(""); @@ -758,7 +815,9 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S function getClassAliasIfNeeded(node: ClassDeclaration) { if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsConstructorReference) { enableSubstitutionForClassAliases(); - const classAlias = factory.createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? idText(node.name) : "default"); + const classAlias = factory.createUniqueName( + node.name && !isGeneratedIdentifier(node.name) ? idText(node.name) : "default", + ); classAliases[getOriginalNodeId(node)] = classAlias; hoistVariableDeclaration(classAlias); return classAlias; @@ -827,4 +886,3 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return undefined; } } - diff --git a/src/compiler/transformers/module/esnextAnd2015.ts b/src/compiler/transformers/module/esnextAnd2015.ts index 879544063f9f0..3d0f6f7439c33 100644 --- a/src/compiler/transformers/module/esnextAnd2015.ts +++ b/src/compiler/transformers/module/esnextAnd2015.ts @@ -51,7 +51,9 @@ import { } from "../../_namespaces/ts"; /** @internal */ -export function transformECMAScriptModule(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle { +export function transformECMAScriptModule( + context: TransformationContext, +): (x: SourceFile | Bundle) => SourceFile | Bundle { const { factory, getEmitHelperFactory: emitHelpers, @@ -85,7 +87,12 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S if (importRequireStatements) { result = factory.updateSourceFile( result, - setTextRange(factory.createNodeArray(insertStatementsAfterCustomPrologue(result.statements.slice(), importRequireStatements)), result.statements), + setTextRange( + factory.createNodeArray( + insertStatementsAfterCustomPrologue(result.statements.slice(), importRequireStatements), + ), + result.statements, + ), ); } if (!isExternalModule(node) || some(result.statements, isExternalModuleIndicator)) { @@ -93,7 +100,10 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S } return factory.updateSourceFile( result, - setTextRange(factory.createNodeArray([...result.statements, createEmptyExports(factory)]), result.statements), + setTextRange( + factory.createNodeArray([...result.statements, createEmptyExports(factory)]), + result.statements, + ), ); } @@ -101,7 +111,12 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S } function updateExternalModule(node: SourceFile) { - const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded(factory, emitHelpers(), node, compilerOptions); + const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded( + factory, + emitHelpers(), + node, + compilerOptions, + ); if (externalHelpersImportDeclaration) { const statements: Statement[] = []; const statementOffset = factory.copyPrologue(node.statements, statements); @@ -110,7 +125,8 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset)); return factory.updateSourceFile( node, - setTextRange(factory.createNodeArray(statements), node.statements)); + setTextRange(factory.createNodeArray(statements), node.statements), + ); } else { return visitEachChild(node, visitor, context); @@ -123,11 +139,12 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S // Though an error in es2020 modules, in node-flavor es2020 modules, we can helpfully transform this to a synthetic `require` call // To give easy access to a synchronous `require` in node-flavor esm. We do the transform even in scenarios where we error, but `import.meta.url` // is available, just because the output is reasonable for a node-like runtime. - return getEmitModuleKind(compilerOptions) >= ModuleKind.Node16 ? visitImportEqualsDeclaration(node as ImportEqualsDeclaration) : undefined; + return getEmitModuleKind(compilerOptions) >= ModuleKind.Node16 + ? visitImportEqualsDeclaration(node as ImportEqualsDeclaration) : undefined; case SyntaxKind.ExportAssignment: return visitExportAssignment(node as ExportAssignment); case SyntaxKind.ExportDeclaration: - const exportDecl = (node as ExportDeclaration); + const exportDecl = node as ExportDeclaration; return visitExportDeclaration(exportDecl); } @@ -139,27 +156,44 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S * * @param importNode The declaration to import. */ - function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { - const moduleName = getExternalModuleNameLiteral(factory, importNode, Debug.checkDefined(currentSourceFile), host, resolver, compilerOptions); + function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { + const moduleName = getExternalModuleNameLiteral( + factory, + importNode, + Debug.checkDefined(currentSourceFile), + host, + resolver, + compilerOptions, + ); const args: Expression[] = []; if (moduleName) { args.push(moduleName); } if (!importRequireStatements) { - const createRequireName = factory.createUniqueName("_createRequire", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); + const createRequireName = factory.createUniqueName( + "_createRequire", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ); const importStatement = factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause( /*isTypeOnly*/ false, /*name*/ undefined, factory.createNamedImports([ - factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("createRequire"), createRequireName) - ]) + factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier("createRequire"), + createRequireName, + ), + ]), ), - factory.createStringLiteral("module") + factory.createStringLiteral("module"), + ); + const requireHelperName = factory.createUniqueName( + "__require", + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, ); - const requireHelperName = factory.createUniqueName("__require", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel); const requireStatement = factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( @@ -168,16 +202,25 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S requireHelperName, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createCallExpression(factory.cloneNode(createRequireName), /*typeArguments*/ undefined, [ - factory.createPropertyAccessExpression(factory.createMetaProperty(SyntaxKind.ImportKeyword, factory.createIdentifier("meta")), factory.createIdentifier("url")) - ]) - ) + factory.createCallExpression( + factory.cloneNode(createRequireName), + /*typeArguments*/ undefined, + [ + factory.createPropertyAccessExpression( + factory.createMetaProperty( + SyntaxKind.ImportKeyword, + factory.createIdentifier("meta"), + ), + factory.createIdentifier("url"), + ), + ], + ), + ), ], - /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None - ) + /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None, + ), ); importRequireStatements = [importStatement, requireStatement]; - } const name = importRequireStatements[1].declarationList.declarations[0].name; @@ -191,10 +234,14 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S * @param node The node to visit. */ function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { - Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); + Debug.assert( + isExternalModuleImportEqualsDeclaration(node), + "import= for internal module references should be handled in an earlier transformer.", + ); let statements: Statement[] | undefined; - statements = append(statements, + statements = append( + statements, setOriginalNode( setTextRange( factory.createVariableStatement( @@ -205,15 +252,16 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S factory.cloneNode(node.name), /*exclamationToken*/ undefined, /*type*/ undefined, - createRequireCall(node) - ) + createRequireCall(node), + ), ], - /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None - ) + /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None, + ), ), - node), - node - ) + node, + ), + node, + ), ); statements = appendExportsOfImportEqualsDeclaration(statements, node); @@ -221,13 +269,25 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S return singleOrMany(statements); } - function appendExportsOfImportEqualsDeclaration(statements: Statement[] | undefined, node: ImportEqualsDeclaration) { + function appendExportsOfImportEqualsDeclaration( + statements: Statement[] | undefined, + node: ImportEqualsDeclaration, + ) { if (hasSyntacticModifier(node, ModifierFlags.Export)) { - statements = append(statements, factory.createExportDeclaration( - /*modifiers*/ undefined, - node.isTypeOnly, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, idText(node.name))]) - )); + statements = append( + statements, + factory.createExportDeclaration( + /*modifiers*/ undefined, + node.isTypeOnly, + factory.createNamedExports([ + factory.createExportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + idText(node.name), + ), + ]), + ), + ); } return statements; } @@ -256,19 +316,22 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S /*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport( - synthName - ) + synthName, + ), ), node.moduleSpecifier, - node.assertClause + node.assertClause, ); setOriginalNode(importDecl, node.exportClause); - const exportDecl = isExportNamespaceAsDefaultDeclaration(node) ? factory.createExportDefault(synthName) : factory.createExportDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, synthName, oldIdentifier)]), - ); + const exportDecl = isExportNamespaceAsDefaultDeclaration(node) ? factory.createExportDefault(synthName) + : factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([ + factory.createExportSpecifier(/*isTypeOnly*/ false, synthName, oldIdentifier), + ]), + ); setOriginalNode(exportDecl, node); return [importDecl, exportDecl]; @@ -321,7 +384,13 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S const name = idText(node); let substitution = helperNameSubstitutions!.get(name); if (!substitution) { - helperNameSubstitutions!.set(name, substitution = factory.createUniqueName(name, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)); + helperNameSubstitutions!.set( + name, + substitution = factory.createUniqueName( + name, + GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel, + ), + ); } return substitution; } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index b6339fcc15a90..86665501c1940 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -173,9 +173,12 @@ export function transformModule(context: TransformationContext): (x: SourceFile function getTransformModuleDelegate(moduleKind: ModuleKind): (node: SourceFile) => SourceFile { switch (moduleKind) { - case ModuleKind.AMD: return transformAMDModule; - case ModuleKind.UMD: return transformUMDModule; - default: return transformCommonJSModule; + case ModuleKind.AMD: + return transformAMDModule; + case ModuleKind.UMD: + return transformUMDModule; + default: + return transformCommonJSModule; } } @@ -184,7 +187,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile getEmitHelperFactory: emitHelpers, startLexicalEnvironment, endLexicalEnvironment, - hoistVariableDeclaration + hoistVariableDeclaration, } = context; const compilerOptions = context.getCompilerOptions(); @@ -218,10 +221,12 @@ export function transformModule(context: TransformationContext): (x: SourceFile * @param node The SourceFile node. */ function transformSourceFile(node: SourceFile) { - if (node.isDeclarationFile || - !(isEffectiveExternalModule(node, compilerOptions) || - node.transformFlags & TransformFlags.ContainsDynamicImport || - (isJsonSourceFile(node) && hasJsonModuleEmitEnabled(compilerOptions) && outFile(compilerOptions)))) { + if ( + node.isDeclarationFile + || !(isEffectiveExternalModule(node, compilerOptions) + || node.transformFlags & TransformFlags.ContainsDynamicImport + || (isJsonSourceFile(node) && hasJsonModuleEmitEnabled(compilerOptions) && outFile(compilerOptions))) + ) { return node; } @@ -238,7 +243,6 @@ export function transformModule(context: TransformationContext): (x: SourceFile return updated; } - function shouldEmitUnderscoreUnderscoreESModule() { if (!currentModuleInfo.exportEquals && isExternalModule(currentSourceFile)) { return true; @@ -255,24 +259,37 @@ export function transformModule(context: TransformationContext): (x: SourceFile startLexicalEnvironment(); const statements: Statement[] = []; - const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); - const statementOffset = factory.copyPrologue(node.statements, statements, ensureUseStrict && !isJsonSourceFile(node), topLevelVisitor); + const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") + || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); + const statementOffset = factory.copyPrologue( + node.statements, + statements, + ensureUseStrict && !isJsonSourceFile(node), + topLevelVisitor, + ); if (shouldEmitUnderscoreUnderscoreESModule()) { append(statements, createUnderscoreUnderscoreESModule()); } if (length(currentModuleInfo.exportedNames)) { const chunkSize = 50; - for (let i=0; i factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev), - factory.createVoidZero() as Expression - ) - ) + (prev, nextId) => + factory.createAssignment( + factory.createPropertyAccessExpression( + factory.createIdentifier("exports"), + factory.createIdentifier(idText(nextId)), + ), + prev, + ), + factory.createVoidZero() as Expression, + ), + ), ); } } @@ -282,7 +299,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false); insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); - const updated = factory.updateSourceFile(node, setTextRange(factory.createNodeArray(statements), node.statements)); + const updated = factory.updateSourceFile( + node, + setTextRange(factory.createNodeArray(statements), node.statements), + ); addEmitHelpers(updated, context.readEmitHelpers()); return updated; } @@ -318,12 +338,16 @@ export function transformModule(context: TransformationContext): (x: SourceFile // // we need to add modules without alias names to the end of the dependencies list - const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ true); + const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies( + node, + /*includeNonAmdDependencies*/ true, + ); // Create an updated SourceFile: // // define(mofactory.updateSourceFile", "module2"], function ... - const updated = factory.updateSourceFile(node, + const updated = factory.updateSourceFile( + node, setTextRange( factory.createNodeArray([ factory.createExpressionStatement( @@ -337,37 +361,48 @@ export function transformModule(context: TransformationContext): (x: SourceFile // Add the dependency array argument: // // ["require", "exports", module1", "module2", ...] - factory.createArrayLiteralExpression(jsonSourceFile ? emptyArray : [ - factory.createStringLiteral("require"), - factory.createStringLiteral("exports"), - ...aliasedModuleNames, - ...unaliasedModuleNames - ]), + factory.createArrayLiteralExpression( + jsonSourceFile ? emptyArray : [ + factory.createStringLiteral("require"), + factory.createStringLiteral("exports"), + ...aliasedModuleNames, + ...unaliasedModuleNames, + ], + ), // Add the module body function argument: // // function (require, exports, module1, module2) ... - jsonSourceFile ? - jsonSourceFile.statements.length ? jsonSourceFile.statements[0].expression : factory.createObjectLiteralExpression() : - factory.createFunctionExpression( + jsonSourceFile + ? jsonSourceFile.statements.length ? jsonSourceFile.statements[0].expression + : factory.createObjectLiteralExpression() + : factory.createFunctionExpression( /*modifiers*/ undefined, /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, [ - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"), - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"), - ...importAliasNames + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "require", + ), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "exports", + ), + ...importAliasNames, ], /*type*/ undefined, - transformAsynchronousModuleBody(node) - ) - ] - ) - ) + transformAsynchronousModuleBody(node), + ), + ], + ), + ), ]), - /*location*/ node.statements - ) + /*location*/ node.statements, + ), ); addEmitHelpers(updated, context.readEmitHelpers()); @@ -380,7 +415,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile * @param node The SourceFile node. */ function transformUMDModule(node: SourceFile) { - const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ false); + const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies( + node, + /*includeNonAmdDependencies*/ false, + ); const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions); const umdHeader = factory.createFunctionExpression( /*modifiers*/ undefined, @@ -395,7 +433,13 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.createIfStatement( factory.createLogicalAnd( factory.createTypeCheck(factory.createIdentifier("module"), "object"), - factory.createTypeCheck(factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports"), "object") + factory.createTypeCheck( + factory.createPropertyAccessExpression( + factory.createIdentifier("module"), + "exports", + ), + "object", + ), ), factory.createBlock([ factory.createVariableStatement( @@ -410,32 +454,35 @@ export function transformModule(context: TransformationContext): (x: SourceFile /*typeArguments*/ undefined, [ factory.createIdentifier("require"), - factory.createIdentifier("exports") - ] - ) - ) - ] + factory.createIdentifier("exports"), + ], + ), + ), + ], ), setEmitFlags( factory.createIfStatement( factory.createStrictInequality( factory.createIdentifier("v"), - factory.createIdentifier("undefined") + factory.createIdentifier("undefined"), ), factory.createExpressionStatement( factory.createAssignment( - factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports"), - factory.createIdentifier("v") - ) - ) + factory.createPropertyAccessExpression( + factory.createIdentifier("module"), + "exports", + ), + factory.createIdentifier("v"), + ), + ), ), - EmitFlags.SingleLine - ) + EmitFlags.SingleLine, + ), ]), factory.createIfStatement( factory.createLogicalAnd( factory.createTypeCheck(factory.createIdentifier("define"), "function"), - factory.createPropertyAccessExpression(factory.createIdentifier("define"), "amd") + factory.createPropertyAccessExpression(factory.createIdentifier("define"), "amd"), ), factory.createBlock([ factory.createExpressionStatement( @@ -449,20 +496,20 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.createStringLiteral("require"), factory.createStringLiteral("exports"), ...aliasedModuleNames, - ...unaliasedModuleNames + ...unaliasedModuleNames, ]), - factory.createIdentifier("factory") - ] - ) - ) - ]) - ) - ) + factory.createIdentifier("factory"), + ], + ), + ), + ]), + ), + ), ], - /*multiLine*/ true + /*multiLine*/ true, ), - /*location*/ undefined - ) + /*location*/ undefined, + ), ); // Create an updated SourceFile: @@ -495,19 +542,27 @@ export function transformModule(context: TransformationContext): (x: SourceFile /*name*/ undefined, /*typeParameters*/ undefined, [ - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"), - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"), - ...importAliasNames + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "require", + ), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "exports", + ), + ...importAliasNames, ], /*type*/ undefined, - transformAsynchronousModuleBody(node) - ) - ] - ) - ) + transformAsynchronousModuleBody(node), + ), + ], + ), + ), ]), - /*location*/ node.statements - ) + /*location*/ node.statements, + ), ); addEmitHelpers(updated, context.readEmitHelpers()); @@ -520,7 +575,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile * @param node The source file. * @param includeNonAmdDependencies A value indicating whether to include non-AMD dependencies. */ - function collectAsynchronousDependencies(node: SourceFile, includeNonAmdDependencies: boolean): AsynchronousDependencies { + function collectAsynchronousDependencies( + node: SourceFile, + includeNonAmdDependencies: boolean, + ): AsynchronousDependencies { // names of modules with corresponding parameter in the factory function const aliasedModuleNames: Expression[] = []; @@ -536,7 +594,13 @@ export function transformModule(context: TransformationContext): (x: SourceFile for (const amdDependency of node.amdDependencies) { if (amdDependency.name) { aliasedModuleNames.push(factory.createStringLiteral(amdDependency.path)); - importAliasNames.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, amdDependency.name)); + importAliasNames.push( + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + amdDependency.name, + ), + ); } else { unaliasedModuleNames.push(factory.createStringLiteral(amdDependency.path)); @@ -545,7 +609,14 @@ export function transformModule(context: TransformationContext): (x: SourceFile for (const importNode of currentModuleInfo.externalImports) { // Find the name of the external module - const externalModuleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions); + const externalModuleName = getExternalModuleNameLiteral( + factory, + importNode, + currentSourceFile, + host, + resolver, + compilerOptions, + ); // Find the name of the module alias, if there is one const importAliasName = getLocalNameForExternalImport(factory, importNode, currentSourceFile); @@ -558,7 +629,13 @@ export function transformModule(context: TransformationContext): (x: SourceFile // This is so that when printer will not substitute the identifier setEmitFlags(importAliasName, EmitFlags.NoSubstitution); aliasedModuleNames.push(externalModuleName); - importAliasNames.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, importAliasName)); + importAliasNames.push( + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + importAliasName, + ), + ); } else { unaliasedModuleNames.push(externalModuleName); @@ -570,7 +647,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile } function getAMDImportExpressionForImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration) { - if (isImportEqualsDeclaration(node) || isExportDeclaration(node) || !getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions)) { + if ( + isImportEqualsDeclaration(node) || isExportDeclaration(node) + || !getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions) + ) { return undefined; } const name = getLocalNameForExternalImport(factory, node, currentSourceFile)!; // TODO: GH#18217 @@ -590,13 +670,30 @@ export function transformModule(context: TransformationContext): (x: SourceFile startLexicalEnvironment(); const statements: Statement[] = []; - const statementOffset = factory.copyPrologue(node.statements, statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, topLevelVisitor); + const statementOffset = factory.copyPrologue( + node.statements, + statements, + /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, + topLevelVisitor, + ); if (shouldEmitUnderscoreUnderscoreESModule()) { append(statements, createUnderscoreUnderscoreESModule()); } if (length(currentModuleInfo.exportedNames)) { - append(statements, factory.createExpressionStatement(reduceLeft(currentModuleInfo.exportedNames, (prev, nextId) => factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev), factory.createVoidZero() as Expression))); + append( + statements, + factory.createExpressionStatement( + reduceLeft(currentModuleInfo.exportedNames, (prev, nextId) => + factory.createAssignment( + factory.createPropertyAccessExpression( + factory.createIdentifier("exports"), + factory.createIdentifier(idText(nextId)), + ), + prev, + ), factory.createVoidZero() as Expression), + ), + ); } // Visit each statement of the module body. @@ -644,10 +741,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.createAssignment( factory.createPropertyAccessExpression( factory.createIdentifier("module"), - "exports" + "exports", ), - expressionResult - ) + expressionResult, + ), ); setTextRange(statement, currentModuleInfo.exportEquals); @@ -755,7 +852,11 @@ export function transformModule(context: TransformationContext): (x: SourceFile function visitorWorker(node: Node, valueIsDiscarded: boolean): VisitResult { // This visitor does not need to descend into the tree if there is no dynamic import, destructuring assignment, or update expression // as export/import statements are only transformed at the top level of a file. - if (!(node.transformFlags & (TransformFlags.ContainsDynamicImport | TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsUpdateExpressionForIdentifier))) { + if ( + !(node.transformFlags + & (TransformFlags.ContainsDynamicImport | TransformFlags.ContainsDestructuringAssignment + | TransformFlags.ContainsUpdateExpressionForIdentifier)) + ) { return node; } @@ -780,7 +881,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile break; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded); + return visitPreOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded, + ); } return visitEachChild(node, visitor, context); @@ -817,7 +921,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: return false; - default: Debug.assertNever(elem, "Unhandled object member kind"); + default: + Debug.assertNever(elem, "Unhandled object member kind"); } } } @@ -841,16 +946,29 @@ export function transformModule(context: TransformationContext): (x: SourceFile function visitDestructuringAssignment(node: DestructuringAssignment, valueIsDiscarded: boolean): Expression { if (destructuringNeedsFlattening(node.left)) { - return flattenDestructuringAssignment(node, visitor, context, FlattenLevel.All, !valueIsDiscarded, createAllExportExpressions); + return flattenDestructuringAssignment( + node, + visitor, + context, + FlattenLevel.All, + !valueIsDiscarded, + createAllExportExpressions, + ); } return visitEachChild(node, visitor, context); } function visitForStatement(node: ForStatement, isTopLevel: boolean) { - if (isTopLevel && node.initializer && - isVariableDeclarationList(node.initializer) && - !(node.initializer.flags & NodeFlags.BlockScoped)) { - const exportStatements = appendExportsOfVariableDeclarationList(/*statements*/ undefined, node.initializer, /*isForInOrOfInitializer*/ false); + if ( + isTopLevel && node.initializer + && isVariableDeclarationList(node.initializer) + && !(node.initializer.flags & NodeFlags.BlockScoped) + ) { + const exportStatements = appendExportsOfVariableDeclarationList( + /*statements*/ undefined, + node.initializer, + /*isForInOrOfInitializer*/ false, + ); if (exportStatements) { const statements: Statement[] = []; const varDeclList = visitNode(node.initializer, discardedValueVisitor, isVariableDeclarationList); @@ -861,7 +979,9 @@ export function transformModule(context: TransformationContext): (x: SourceFile const condition = visitNode(node.condition, visitor, isExpression); const incrementor = visitNode(node.incrementor, discardedValueVisitor, isExpression); const body = visitIterationBody(node.statement, isTopLevel ? topLevelNestedVisitor : visitor, context); - statements.push(factory.updateForStatement(node, /*initializer*/ undefined, condition, incrementor, body)); + statements.push( + factory.updateForStatement(node, /*initializer*/ undefined, condition, incrementor, body), + ); return statements; } } @@ -870,7 +990,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile visitNode(node.initializer, discardedValueVisitor, isForInitializer), visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, discardedValueVisitor, isExpression), - visitIterationBody(node.statement, isTopLevel ? topLevelNestedVisitor : visitor, context) + visitIterationBody(node.statement, isTopLevel ? topLevelNestedVisitor : visitor, context), ); } @@ -881,14 +1001,18 @@ export function transformModule(context: TransformationContext): (x: SourceFile */ function visitForInStatement(node: ForInStatement): VisitResult { if (isVariableDeclarationList(node.initializer) && !(node.initializer.flags & NodeFlags.BlockScoped)) { - const exportStatements = appendExportsOfVariableDeclarationList(/*statements*/ undefined, node.initializer, /*isForInOrOfInitializer*/ true); + const exportStatements = appendExportsOfVariableDeclarationList( + /*statements*/ undefined, + node.initializer, + /*isForInOrOfInitializer*/ true, + ); if (some(exportStatements)) { const initializer = visitNode(node.initializer, discardedValueVisitor, isForInitializer); const expression = visitNode(node.expression, visitor, isExpression); const body = visitIterationBody(node.statement, topLevelNestedVisitor, context); - const mergedBody = isBlock(body) ? - factory.updateBlock(body, [...exportStatements, ...body.statements]) : - factory.createBlock([...exportStatements, body], /*multiLine*/ true); + const mergedBody = isBlock(body) + ? factory.updateBlock(body, [...exportStatements, ...body.statements]) + : factory.createBlock([...exportStatements, body], /*multiLine*/ true); return factory.updateForInStatement(node, initializer, expression, mergedBody); } } @@ -896,7 +1020,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile node, visitNode(node.initializer, discardedValueVisitor, isForInitializer), visitNode(node.expression, visitor, isExpression), - visitIterationBody(node.statement, topLevelNestedVisitor, context) + visitIterationBody(node.statement, topLevelNestedVisitor, context), ); } @@ -907,14 +1031,18 @@ export function transformModule(context: TransformationContext): (x: SourceFile */ function visitForOfStatement(node: ForOfStatement): VisitResult { if (isVariableDeclarationList(node.initializer) && !(node.initializer.flags & NodeFlags.BlockScoped)) { - const exportStatements = appendExportsOfVariableDeclarationList(/*statements*/ undefined, node.initializer, /*isForInOrOfInitializer*/ true); + const exportStatements = appendExportsOfVariableDeclarationList( + /*statements*/ undefined, + node.initializer, + /*isForInOrOfInitializer*/ true, + ); const initializer = visitNode(node.initializer, discardedValueVisitor, isForInitializer); const expression = visitNode(node.expression, visitor, isExpression); let body = visitIterationBody(node.statement, topLevelNestedVisitor, context); if (some(exportStatements)) { - body = isBlock(body) ? - factory.updateBlock(body, [...exportStatements, ...body.statements]) : - factory.createBlock([...exportStatements, body], /*multiLine*/ true); + body = isBlock(body) + ? factory.updateBlock(body, [...exportStatements, ...body.statements]) + : factory.createBlock([...exportStatements, body], /*multiLine*/ true); } return factory.updateForOfStatement(node, node.awaitModifier, initializer, expression, body); } @@ -923,7 +1051,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile node.awaitModifier, visitNode(node.initializer, discardedValueVisitor, isForInitializer), visitNode(node.expression, visitor, isExpression), - visitIterationBody(node.statement, topLevelNestedVisitor, context) + visitIterationBody(node.statement, topLevelNestedVisitor, context), ); } @@ -936,7 +1064,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile return factory.updateDoStatement( node, visitIterationBody(node.statement, topLevelNestedVisitor, context), - visitNode(node.expression, visitor, isExpression) + visitNode(node.expression, visitor, isExpression), ); } @@ -949,7 +1077,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile return factory.updateWhileStatement( node, visitNode(node.expression, visitor, isExpression), - visitIterationBody(node.statement, topLevelNestedVisitor, context) + visitIterationBody(node.statement, topLevelNestedVisitor, context), ); } @@ -962,7 +1090,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile return factory.updateLabeledStatement( node, node.label, - Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)) + Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)), ); } @@ -975,7 +1103,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile return factory.updateWithStatement( node, visitNode(node.expression, visitor, isExpression), - Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)) + Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)), ); } @@ -989,7 +1117,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile node, visitNode(node.expression, visitor, isExpression), Debug.checkDefined(visitNode(node.thenStatement, topLevelNestedVisitor, isStatement, factory.liftToBlock)), - visitNode(node.elseStatement, topLevelNestedVisitor, isStatement, factory.liftToBlock) + visitNode(node.elseStatement, topLevelNestedVisitor, isStatement, factory.liftToBlock), ); } @@ -1002,7 +1130,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile return factory.updateSwitchStatement( node, visitNode(node.expression, visitor, isExpression), - Debug.checkDefined(visitNode(node.caseBlock, topLevelNestedVisitor, isCaseBlock)) + Debug.checkDefined(visitNode(node.caseBlock, topLevelNestedVisitor, isCaseBlock)), ); } @@ -1014,7 +1142,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile function visitCaseBlock(node: CaseBlock): CaseBlock { return factory.updateCaseBlock( node, - visitNodes(node.clauses, topLevelNestedVisitor, isCaseOrDefaultClause) + visitNodes(node.clauses, topLevelNestedVisitor, isCaseOrDefaultClause), ); } @@ -1027,7 +1155,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile return factory.updateCaseClause( node, visitNode(node.expression, visitor, isExpression), - visitNodes(node.statements, topLevelNestedVisitor, isStatement) + visitNodes(node.statements, topLevelNestedVisitor, isStatement), ); } @@ -1058,7 +1186,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile return factory.updateCatchClause( node, node.variableDeclaration, - Debug.checkDefined(visitNode(node.block, topLevelNestedVisitor, isBlock)) + Debug.checkDefined(visitNode(node.block, topLevelNestedVisitor, isBlock)), ); } @@ -1075,19 +1203,28 @@ export function transformModule(context: TransformationContext): (x: SourceFile function visitExpressionStatement(node: ExpressionStatement) { return factory.updateExpressionStatement( node, - visitNode(node.expression, discardedValueVisitor, isExpression) + visitNode(node.expression, discardedValueVisitor, isExpression), ); } function visitParenthesizedExpression(node: ParenthesizedExpression, valueIsDiscarded: boolean) { - return factory.updateParenthesizedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); + return factory.updateParenthesizedExpression( + node, + visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression), + ); } function visitPartiallyEmittedExpression(node: PartiallyEmittedExpression, valueIsDiscarded: boolean) { - return factory.updatePartiallyEmittedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); + return factory.updatePartiallyEmittedExpression( + node, + visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression), + ); } - function visitPreOrPostfixUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded: boolean) { + function visitPreOrPostfixUnaryExpression( + node: PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded: boolean, + ) { // When we see a prefix or postfix increment expression whose operand is an exported // symbol, we should ensure all exports of that symbol are updated with the correct // value. @@ -1097,11 +1234,13 @@ export function transformModule(context: TransformationContext): (x: SourceFile // - We do not transform identifiers that were originally the name of an enum or // namespace due to how they are transformed in TypeScript. // - We only transform identifiers that are exported at the top level. - if ((node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) + if ( + (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) && isIdentifier(node.operand) && !isGeneratedIdentifier(node.operand) && !isLocalName(node.operand) - && !isDeclarationNameOfEnumOrNamespace(node.operand)) { + && !isDeclarationNameOfEnumOrNamespace(node.operand) + ) { const exportedNames = getExports(node.operand); if (exportedNames) { let temp: Identifier | undefined; @@ -1141,10 +1280,19 @@ export function transformModule(context: TransformationContext): (x: SourceFile if (moduleKind === ModuleKind.None && languageVersion >= ScriptTarget.ES2020) { return visitEachChild(node, visitor, context); } - const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); + const externalModuleName = getExternalModuleNameLiteral( + factory, + node, + currentSourceFile, + host, + resolver, + compilerOptions, + ); const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor, isExpression); // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. - const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; + const argument = externalModuleName + && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) + ? externalModuleName : firstArgument; const containsLexicalThis = !!(node.transformFlags & TransformFlags.ContainsLexicalThis); switch (compilerOptions.module) { case ModuleKind.AMD: @@ -1173,24 +1321,29 @@ export function transformModule(context: TransformationContext): (x: SourceFile // }); needUMDDynamicImportHelper = true; if (isSimpleCopiableExpression(arg)) { - const argClone = isGeneratedIdentifier(arg) ? arg : isStringLiteral(arg) ? factory.createStringLiteralFromNode(arg) : setEmitFlags(setTextRange(factory.cloneNode(arg), arg), EmitFlags.NoComments); + const argClone = isGeneratedIdentifier(arg) ? arg + : isStringLiteral(arg) ? factory.createStringLiteralFromNode(arg) + : setEmitFlags(setTextRange(factory.cloneNode(arg), arg), EmitFlags.NoComments); return factory.createConditionalExpression( /*condition*/ factory.createIdentifier("__syncRequire"), /*questionToken*/ undefined, /*whenTrue*/ createImportCallExpressionCommonJS(arg), /*colonToken*/ undefined, - /*whenFalse*/ createImportCallExpressionAMD(argClone, containsLexicalThis) + /*whenFalse*/ createImportCallExpressionAMD(argClone, containsLexicalThis), ); } else { const temp = factory.createTempVariable(hoistVariableDeclaration); - return factory.createComma(factory.createAssignment(temp, arg), factory.createConditionalExpression( - /*condition*/ factory.createIdentifier("__syncRequire"), - /*questionToken*/ undefined, - /*whenTrue*/ createImportCallExpressionCommonJS(temp, /*isInlineable*/ true), - /*colonToken*/ undefined, - /*whenFalse*/ createImportCallExpressionAMD(temp, containsLexicalThis) - )); + return factory.createComma( + factory.createAssignment(temp, arg), + factory.createConditionalExpression( + /*condition*/ factory.createIdentifier("__syncRequire"), + /*questionToken*/ undefined, + /*whenTrue*/ createImportCallExpressionCommonJS(temp, /*isInlineable*/ true), + /*colonToken*/ undefined, + /*whenFalse*/ createImportCallExpressionAMD(temp, containsLexicalThis), + ), + ); } } @@ -1205,16 +1358,16 @@ export function transformModule(context: TransformationContext): (x: SourceFile const reject = factory.createUniqueName("reject"); const parameters = [ factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ resolve), - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ reject) + factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ reject), ]; const body = factory.createBlock([ factory.createExpressionStatement( factory.createCallExpression( factory.createIdentifier("require"), /*typeArguments*/ undefined, - [factory.createArrayLiteralExpression([arg || factory.createOmittedExpression()]), resolve, reject] - ) - ) + [factory.createArrayLiteralExpression([arg || factory.createOmittedExpression()]), resolve, reject], + ), + ), ]); let func: FunctionExpression | ArrowFunction; @@ -1225,7 +1378,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile parameters, /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, - body); + body, + ); } else { func = factory.createFunctionExpression( @@ -1235,7 +1389,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, parameters, /*type*/ undefined, - body); + body, + ); // if there is a lexical 'this' in the import call arguments, ensure we indicate // that this new function expression indicates it captures 'this' so that the @@ -1245,9 +1400,15 @@ export function transformModule(context: TransformationContext): (x: SourceFile } } - const promise = factory.createNewExpression(factory.createIdentifier("Promise"), /*typeArguments*/ undefined, [func]); + const promise = factory.createNewExpression(factory.createIdentifier("Promise"), /*typeArguments*/ undefined, [ + func, + ]); if (getESModuleInterop(compilerOptions)) { - return factory.createCallExpression(factory.createPropertyAccessExpression(promise, factory.createIdentifier("then")), /*typeArguments*/ undefined, [emitHelpers().createImportStarCallbackHelper()]); + return factory.createCallExpression( + factory.createPropertyAccessExpression(promise, factory.createIdentifier("then")), + /*typeArguments*/ undefined, + [emitHelpers().createImportStarCallbackHelper()], + ); } return promise; } @@ -1268,18 +1429,18 @@ export function transformModule(context: TransformationContext): (x: SourceFile /*argumentsArray*/ needSyncEval ? languageVersion >= ScriptTarget.ES2015 ? [ - factory.createTemplateExpression(factory.createTemplateHead(""), [ - factory.createTemplateSpan(arg, factory.createTemplateTail("")), - ]), - ] + factory.createTemplateExpression(factory.createTemplateHead(""), [ + factory.createTemplateSpan(arg, factory.createTemplateTail("")), + ]), + ] : [ - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createStringLiteral(""), "concat"), - /*typeArguments*/ undefined, - [arg] - ), - ] - : [] + factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createStringLiteral(""), "concat"), + /*typeArguments*/ undefined, + [arg], + ), + ] + : [], ); let requireCall: Expression = factory.createCallExpression( @@ -1296,7 +1457,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.createParameterDeclaration( /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, - /*name*/ "s"), + /*name*/ "s", + ), ] : []; @@ -1308,7 +1470,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile /*parameters*/ parameters, /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, - requireCall); + requireCall, + ); } else { func = factory.createFunctionExpression( @@ -1318,16 +1481,24 @@ export function transformModule(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, /*parameters*/ parameters, /*type*/ undefined, - factory.createBlock([factory.createReturnStatement(requireCall)])); + factory.createBlock([factory.createReturnStatement(requireCall)]), + ); } - const downleveledImport = factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]); + const downleveledImport = factory.createCallExpression( + factory.createPropertyAccessExpression(promiseResolveCall, "then"), + /*typeArguments*/ undefined, + [func], + ); return downleveledImport; } function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) { - if (!getESModuleInterop(compilerOptions) || getInternalEmitFlags(node) & InternalEmitFlags.NeverApplyImportHelper) { + if ( + !getESModuleInterop(compilerOptions) + || getInternalEmitFlags(node) & InternalEmitFlags.NeverApplyImportHelper + ) { return innerExpr; } if (getExportNeedsImportStarHelper(node)) { @@ -1337,7 +1508,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile } function getHelperExpressionForImport(node: ImportDeclaration, innerExpr: Expression) { - if (!getESModuleInterop(compilerOptions) || getInternalEmitFlags(node) & InternalEmitFlags.NeverApplyImportHelper) { + if ( + !getESModuleInterop(compilerOptions) + || getInternalEmitFlags(node) & InternalEmitFlags.NeverApplyImportHelper + ) { return innerExpr; } if (getImportNeedsImportStarHelper(node)) { @@ -1360,7 +1534,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile if (moduleKind !== ModuleKind.AMD) { if (!node.importClause) { // import "mod"; - return setOriginalNode(setTextRange(factory.createExpressionStatement(createRequireCall(node)), node), node); + return setOriginalNode( + setTextRange(factory.createExpressionStatement(createRequireCall(node)), node), + node, + ); } else { const variables: VariableDeclaration[] = []; @@ -1371,8 +1548,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.cloneNode(namespaceDeclaration.name), /*exclamationToken*/ undefined, /*type*/ undefined, - getHelperExpressionForImport(node, createRequireCall(node)) - ) + getHelperExpressionForImport(node, createRequireCall(node)), + ), ); } else { @@ -1385,8 +1562,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.getGeneratedNameForNode(node), /*exclamationToken*/ undefined, /*type*/ undefined, - getHelperExpressionForImport(node, createRequireCall(node)) - ) + getHelperExpressionForImport(node, createRequireCall(node)), + ), ); if (namespaceDeclaration && isDefaultImport(node)) { @@ -1395,31 +1572,34 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.cloneNode(namespaceDeclaration.name), /*exclamationToken*/ undefined, /*type*/ undefined, - factory.getGeneratedNameForNode(node) - ) + factory.getGeneratedNameForNode(node), + ), ); } } - statements = append(statements, + statements = append( + statements, setOriginalNode( setTextRange( factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( variables, - languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None - ) + languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None, + ), ), - /*location*/ node), - /*original*/ node - ) + /*location*/ node, + ), + /*original*/ node, + ), ); } } else if (namespaceDeclaration && isDefaultImport(node)) { // import d, * as n from "mod"; - statements = append(statements, + statements = append( + statements, factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( @@ -1430,15 +1610,16 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.cloneNode(namespaceDeclaration.name), /*exclamationToken*/ undefined, /*type*/ undefined, - factory.getGeneratedNameForNode(node) + factory.getGeneratedNameForNode(node), ), - /*location*/ node), - /*original*/ node - ) + /*location*/ node, + ), + /*original*/ node, + ), ], - languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None - ) - ) + languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None, + ), + ), ); } @@ -1452,7 +1633,14 @@ export function transformModule(context: TransformationContext): (x: SourceFile * @param importNode The declararation to import. */ function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { - const moduleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions); + const moduleName = getExternalModuleNameLiteral( + factory, + importNode, + currentSourceFile, + host, + resolver, + compilerOptions, + ); const args: Expression[] = []; if (moduleName) { args.push(moduleName); @@ -1467,27 +1655,33 @@ export function transformModule(context: TransformationContext): (x: SourceFile * @param node The node to visit. */ function visitTopLevelImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { - Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); + Debug.assert( + isExternalModuleImportEqualsDeclaration(node), + "import= for internal module references should be handled in an earlier transformer.", + ); let statements: Statement[] | undefined; if (moduleKind !== ModuleKind.AMD) { if (hasSyntacticModifier(node, ModifierFlags.Export)) { - statements = append(statements, + statements = append( + statements, setOriginalNode( setTextRange( factory.createExpressionStatement( createExportExpression( node.name, - createRequireCall(node) - ) + createRequireCall(node), + ), ), - node), - node - ) + node, + ), + node, + ), ); } else { - statements = append(statements, + statements = append( + statements, setOriginalNode( setTextRange( factory.createVariableStatement( @@ -1498,29 +1692,32 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.cloneNode(node.name), /*exclamationToken*/ undefined, /*type*/ undefined, - createRequireCall(node) - ) + createRequireCall(node), + ), ], - /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None - ) + /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None, + ), ), - node), - node - ) + node, + ), + node, + ), ); } } else { if (hasSyntacticModifier(node, ModifierFlags.Export)) { - statements = append(statements, + statements = append( + statements, setOriginalNode( setTextRange( factory.createExpressionStatement( - createExportExpression(factory.getExportName(node), factory.getLocalName(node)) + createExportExpression(factory.getExportName(node), factory.getLocalName(node)), ), - node), - node - ) + node, + ), + node, + ), ); } } @@ -1557,13 +1754,14 @@ export function transformModule(context: TransformationContext): (x: SourceFile generatedName, /*exclamationToken*/ undefined, /*type*/ undefined, - createRequireCall(node) - ) - ]) + createRequireCall(node), + ), + ]), ), - /*location*/ node), - /* original */ node - ) + /*location*/ node, + ), + /* original */ node, + ), ); } for (const specifier of node.exportClause.elements) { @@ -1572,30 +1770,43 @@ export function transformModule(context: TransformationContext): (x: SourceFile setOriginalNode( setTextRange( factory.createExpressionStatement( - emitHelpers().createCreateBindingHelper(generatedName, factory.createStringLiteralFromNode(specifier.propertyName || specifier.name), specifier.propertyName ? factory.createStringLiteralFromNode(specifier.name) : undefined) + emitHelpers().createCreateBindingHelper( + generatedName, + factory.createStringLiteralFromNode(specifier.propertyName || specifier.name), + specifier.propertyName ? factory.createStringLiteralFromNode(specifier.name) + : undefined, + ), ), - specifier), - specifier - ) + specifier, + ), + specifier, + ), ); } else { - const exportNeedsImportDefault = - !!getESModuleInterop(compilerOptions) && - !(getInternalEmitFlags(node) & InternalEmitFlags.NeverApplyImportHelper) && - idText(specifier.propertyName || specifier.name) === "default"; + const exportNeedsImportDefault = !!getESModuleInterop(compilerOptions) + && !(getInternalEmitFlags(node) & InternalEmitFlags.NeverApplyImportHelper) + && idText(specifier.propertyName || specifier.name) === "default"; const exportedValue = factory.createPropertyAccessExpression( - exportNeedsImportDefault ? emitHelpers().createImportDefaultHelper(generatedName) : generatedName, - specifier.propertyName || specifier.name); + exportNeedsImportDefault ? emitHelpers().createImportDefaultHelper(generatedName) + : generatedName, + specifier.propertyName || specifier.name, + ); statements.push( setOriginalNode( setTextRange( factory.createExpressionStatement( - createExportExpression(factory.getExportName(specifier), exportedValue, /*location*/ undefined, /*liveBinding*/ true) + createExportExpression( + factory.getExportName(specifier), + exportedValue, + /*location*/ undefined, + /*liveBinding*/ true, + ), ), - specifier), - specifier - ) + specifier, + ), + specifier, + ), ); } } @@ -1612,16 +1823,19 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.createExpressionStatement( createExportExpression( factory.cloneNode(node.exportClause.name), - getHelperExpressionForExport(node, moduleKind !== ModuleKind.AMD ? - createRequireCall(node) : - isExportNamespaceAsDefaultDeclaration(node) ? generatedName : - factory.createIdentifier(idText(node.exportClause.name))) - ) + getHelperExpressionForExport( + node, + moduleKind !== ModuleKind.AMD + ? createRequireCall(node) + : isExportNamespaceAsDefaultDeclaration(node) ? generatedName + : factory.createIdentifier(idText(node.exportClause.name)), + ), + ), ), - node + node, ), - node - ) + node, + ), ); return singleOrMany(statements); @@ -1631,10 +1845,13 @@ export function transformModule(context: TransformationContext): (x: SourceFile return setOriginalNode( setTextRange( factory.createExpressionStatement( - emitHelpers().createExportStarHelper(moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName) + emitHelpers().createExportStarHelper( + moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName, + ), ), - node), - node + node, + ), + node, ); } } @@ -1649,7 +1866,12 @@ export function transformModule(context: TransformationContext): (x: SourceFile return undefined; } - return createExportStatement(factory.createIdentifier("default"), visitNode(node.expression, visitor, isExpression), /*location*/ node, /*allowComments*/ true); + return createExportStatement( + factory.createIdentifier("default"), + visitNode(node.expression, visitor, isExpression), + /*location*/ node, + /*allowComments*/ true, + ); } /** @@ -1660,7 +1882,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { let statements: Statement[] | undefined; if (hasSyntacticModifier(node, ModifierFlags.Export)) { - statements = append(statements, + statements = append( + statements, setOriginalNode( setTextRange( factory.createFunctionDeclaration( @@ -1670,12 +1893,12 @@ export function transformModule(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - visitEachChild(node.body, visitor, context) + visitEachChild(node.body, visitor, context), ), - /*location*/ node + /*location*/ node, ), - /*original*/ node - ) + /*original*/ node, + ), ); } else { @@ -1694,7 +1917,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile function visitClassDeclaration(node: ClassDeclaration): VisitResult { let statements: Statement[] | undefined; if (hasSyntacticModifier(node, ModifierFlags.Export)) { - statements = append(statements, + statements = append( + statements, setOriginalNode( setTextRange( factory.createClassDeclaration( @@ -1702,12 +1926,12 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - visitNodes(node.members, visitor, isClassElement) + visitNodes(node.members, visitor, isClassElement), ), - node + node, ), - node - ) + node, + ), ); } else { @@ -1753,7 +1977,9 @@ export function transformModule(context: TransformationContext): (x: SourceFile /*type*/ undefined, createExportExpression( variable.name, - visitNode(variable.initializer, visitor, isExpression))); + visitNode(variable.initializer, visitor, isExpression), + ), + ); variables = append(variables, updatedVariable); } else { @@ -1761,22 +1987,26 @@ export function transformModule(context: TransformationContext): (x: SourceFile } } else if (variable.initializer) { - if (!isBindingPattern(variable.name) && (isArrowFunction(variable.initializer) || isFunctionExpression(variable.initializer) || isClassExpression(variable.initializer))) { + if ( + !isBindingPattern(variable.name) + && (isArrowFunction(variable.initializer) || isFunctionExpression(variable.initializer) + || isClassExpression(variable.initializer)) + ) { const expression = factory.createAssignment( setTextRange( factory.createPropertyAccessExpression( factory.createIdentifier("exports"), - variable.name + variable.name, ), - /*location*/ variable.name + /*location*/ variable.name, ), - factory.createIdentifier(getTextOfIdentifierOrLiteral(variable.name)) + factory.createIdentifier(getTextOfIdentifierOrLiteral(variable.name)), ); const updatedVariable = factory.createVariableDeclaration( variable.name, variable.exclamationToken, variable.type, - visitNode(variable.initializer, visitor, isExpression) + visitNode(variable.initializer, visitor, isExpression), ); variables = append(variables, updatedVariable); @@ -1784,17 +2014,30 @@ export function transformModule(context: TransformationContext): (x: SourceFile removeCommentsOnExpressions = true; } else { - expressions = append(expressions, transformInitializedVariable(variable as InitializedVariableDeclaration)); + expressions = append( + expressions, + transformInitializedVariable(variable as InitializedVariableDeclaration), + ); } } } if (variables) { - statements = append(statements, factory.updateVariableStatement(node, modifiers, factory.updateVariableDeclarationList(node.declarationList, variables))); + statements = append( + statements, + factory.updateVariableStatement( + node, + modifiers, + factory.updateVariableDeclarationList(node.declarationList, variables), + ), + ); } if (expressions) { - const statement = setOriginalNode(setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node), node); + const statement = setOriginalNode( + setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node), + node, + ); if (removeCommentsOnExpressions) { removeAllComments(statement); } @@ -1838,7 +2081,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile context, FlattenLevel.All, /*needsValue*/ false, - createAllExportExpressions + createAllExportExpressions, ); } else { @@ -1846,11 +2089,11 @@ export function transformModule(context: TransformationContext): (x: SourceFile setTextRange( factory.createPropertyAccessExpression( factory.createIdentifier("exports"), - node.name + node.name, ), - /*location*/ node.name + /*location*/ node.name, ), - node.initializer ? visitNode(node.initializer, visitor, isExpression) : factory.createVoidZero() + node.initializer ? visitNode(node.initializer, visitor, isExpression) : factory.createVoidZero(), ); } } @@ -1864,7 +2107,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfImportDeclaration(statements: Statement[] | undefined, decl: ImportDeclaration): Statement[] | undefined { + function appendExportsOfImportDeclaration( + statements: Statement[] | undefined, + decl: ImportDeclaration, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } @@ -1907,7 +2153,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfImportEqualsDeclaration(statements: Statement[] | undefined, decl: ImportEqualsDeclaration): Statement[] | undefined { + function appendExportsOfImportEqualsDeclaration( + statements: Statement[] | undefined, + decl: ImportEqualsDeclaration, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } @@ -1924,8 +2173,15 @@ export function transformModule(context: TransformationContext): (x: SourceFile * appended. * @param node The VariableStatement whose exports are to be recorded. */ - function appendExportsOfVariableStatement(statements: Statement[] | undefined, node: VariableStatement): Statement[] | undefined { - return appendExportsOfVariableDeclarationList(statements, node.declarationList, /*isForInOrOfInitializer*/ false); + function appendExportsOfVariableStatement( + statements: Statement[] | undefined, + node: VariableStatement, + ): Statement[] | undefined { + return appendExportsOfVariableDeclarationList( + statements, + node.declarationList, + /*isForInOrOfInitializer*/ false, + ); } /** @@ -1937,7 +2193,11 @@ export function transformModule(context: TransformationContext): (x: SourceFile * appended. * @param node The VariableDeclarationList whose exports are to be recorded. */ - function appendExportsOfVariableDeclarationList(statements: Statement[] | undefined, node: VariableDeclarationList, isForInOrOfInitializer: boolean): Statement[] | undefined { + function appendExportsOfVariableDeclarationList( + statements: Statement[] | undefined, + node: VariableDeclarationList, + isForInOrOfInitializer: boolean, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } @@ -1958,7 +2218,11 @@ export function transformModule(context: TransformationContext): (x: SourceFile * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfBindingElement(statements: Statement[] | undefined, decl: VariableDeclaration | BindingElement, isForInOrOfInitializer: boolean): Statement[] | undefined { + function appendExportsOfBindingElement( + statements: Statement[] | undefined, + decl: VariableDeclaration | BindingElement, + isForInOrOfInitializer: boolean, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } @@ -1970,7 +2234,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile } } } - else if (!isGeneratedIdentifier(decl.name) && (!isVariableDeclaration(decl) || decl.initializer || isForInOrOfInitializer)) { + else if ( + !isGeneratedIdentifier(decl.name) + && (!isVariableDeclaration(decl) || decl.initializer || isForInOrOfInitializer) + ) { statements = appendExportsOfDeclaration(statements, new IdentifierNameMap(), decl); } @@ -1986,15 +2253,25 @@ export function transformModule(context: TransformationContext): (x: SourceFile * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfHoistedDeclaration(statements: Statement[] | undefined, decl: ClassDeclaration | FunctionDeclaration): Statement[] | undefined { + function appendExportsOfHoistedDeclaration( + statements: Statement[] | undefined, + decl: ClassDeclaration | FunctionDeclaration, + ): Statement[] | undefined { if (currentModuleInfo.exportEquals) { return statements; } const seen = new IdentifierNameMap(); if (hasSyntacticModifier(decl, ModifierFlags.Export)) { - const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) ? factory.createIdentifier("default") : factory.getDeclarationName(decl); - statements = appendExportStatement(statements, seen, exportName, factory.getLocalName(decl), /*location*/ decl); + const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) ? factory.createIdentifier("default") + : factory.getDeclarationName(decl); + statements = appendExportStatement( + statements, + seen, + exportName, + factory.getLocalName(decl), + /*location*/ decl, + ); } if (decl.name) { @@ -2012,12 +2289,25 @@ export function transformModule(context: TransformationContext): (x: SourceFile * appended. * @param decl The declaration to export. */ - function appendExportsOfDeclaration(statements: Statement[] | undefined, seen: IdentifierNameMap, decl: Declaration, liveBinding?: boolean): Statement[] | undefined { + function appendExportsOfDeclaration( + statements: Statement[] | undefined, + seen: IdentifierNameMap, + decl: Declaration, + liveBinding?: boolean, + ): Statement[] | undefined { const name = factory.getDeclarationName(decl); const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(name); if (exportSpecifiers) { for (const exportSpecifier of exportSpecifiers) { - statements = appendExportStatement(statements, seen, exportSpecifier.name, name, /*location*/ exportSpecifier.name, /*allowComments*/ undefined, liveBinding); + statements = appendExportStatement( + statements, + seen, + exportSpecifier.name, + name, + /*location*/ exportSpecifier.name, + /*allowComments*/ undefined, + liveBinding, + ); } } return statements; @@ -2035,10 +2325,21 @@ export function transformModule(context: TransformationContext): (x: SourceFile * @param location The location to use for source maps and comments for the export. * @param allowComments Whether to allow comments on the export. */ - function appendExportStatement(statements: Statement[] | undefined, seen: IdentifierNameMap, exportName: Identifier, expression: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean): Statement[] | undefined { + function appendExportStatement( + statements: Statement[] | undefined, + seen: IdentifierNameMap, + exportName: Identifier, + expression: Expression, + location?: TextRange, + allowComments?: boolean, + liveBinding?: boolean, + ): Statement[] | undefined { if (!seen.has(exportName)) { seen.set(exportName, true); - statements = append(statements, createExportStatement(exportName, expression, location, allowComments, liveBinding)); + statements = append( + statements, + createExportStatement(exportName, expression, location, allowComments, liveBinding), + ); } return statements; } @@ -2049,8 +2350,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile statement = factory.createExpressionStatement( createExportExpression( factory.createIdentifier("__esModule"), - factory.createTrue() - ) + factory.createTrue(), + ), ); } else { @@ -2062,10 +2363,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.createIdentifier("exports"), factory.createStringLiteral("__esModule"), factory.createObjectLiteralExpression([ - factory.createPropertyAssignment("value", factory.createTrue()) - ]) - ] - ) + factory.createPropertyAssignment("value", factory.createTrue()), + ]), + ], + ), ); } setEmitFlags(statement, EmitFlags.CustomPrologue); @@ -2080,8 +2381,17 @@ export function transformModule(context: TransformationContext): (x: SourceFile * @param location The location to use for source maps and comments for the export. * @param allowComments An optional value indicating whether to emit comments for the statement. */ - function createExportStatement(name: Identifier, value: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean) { - const statement = setTextRange(factory.createExpressionStatement(createExportExpression(name, value, /*location*/ undefined, liveBinding)), location); + function createExportStatement( + name: Identifier, + value: Expression, + location?: TextRange, + allowComments?: boolean, + liveBinding?: boolean, + ) { + const statement = setTextRange( + factory.createExpressionStatement(createExportExpression(name, value, /*location*/ undefined, liveBinding)), + location, + ); startOnNewLine(statement); if (!allowComments) { setEmitFlags(statement, EmitFlags.NoComments); @@ -2102,7 +2412,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile liveBinding && languageVersion !== ScriptTarget.ES3 ? factory.createCallExpression( factory.createPropertyAccessExpression( factory.createIdentifier("Object"), - "defineProperty" + "defineProperty", ), /*typeArguments*/ undefined, [ @@ -2110,25 +2420,28 @@ export function transformModule(context: TransformationContext): (x: SourceFile factory.createStringLiteralFromNode(name), factory.createObjectLiteralExpression([ factory.createPropertyAssignment("enumerable", factory.createTrue()), - factory.createPropertyAssignment("get", factory.createFunctionExpression( - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - /*name*/ undefined, - /*typeParameters*/ undefined, - /*parameters*/ [], - /*type*/ undefined, - factory.createBlock([factory.createReturnStatement(value)]) - )) - ]) - ] + factory.createPropertyAssignment( + "get", + factory.createFunctionExpression( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + /*name*/ undefined, + /*typeParameters*/ undefined, + /*parameters*/ [], + /*type*/ undefined, + factory.createBlock([factory.createReturnStatement(value)]), + ), + ), + ]), + ], ) : factory.createAssignment( factory.createPropertyAccessExpression( factory.createIdentifier("exports"), - factory.cloneNode(name) + factory.cloneNode(name), ), - value + value, ), - location + location, ); } @@ -2251,14 +2564,9 @@ export function transformModule(context: TransformationContext): (x: SourceFile noSubstitution[getNodeId(expression)] = true; if (!isIdentifier(expression) && !(getEmitFlags(node.expression) & EmitFlags.HelperName)) { return addInternalEmitFlags( - factory.updateCallExpression(node, - expression, - /*typeArguments*/ undefined, - node.arguments - ), - InternalEmitFlags.IndirectCall + factory.updateCallExpression(node, expression, /*typeArguments*/ undefined, node.arguments), + InternalEmitFlags.IndirectCall, ); - } } return node; @@ -2270,12 +2578,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile noSubstitution[getNodeId(tag)] = true; if (!isIdentifier(tag) && !(getEmitFlags(node.tag) & EmitFlags.HelperName)) { return addInternalEmitFlags( - factory.updateTaggedTemplateExpression(node, - tag, - /*typeArguments*/ undefined, - node.template - ), - InternalEmitFlags.IndirectCall + factory.updateTaggedTemplateExpression(node, tag, /*typeArguments*/ undefined, node.template), + InternalEmitFlags.IndirectCall, ); } } @@ -2296,15 +2600,19 @@ export function transformModule(context: TransformationContext): (x: SourceFile } return node; } - else if (!(isGeneratedIdentifier(node) && !(node.emitNode.autoGenerate.flags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node)) { + else if ( + !(isGeneratedIdentifier(node) + && !(node.emitNode.autoGenerate.flags & GeneratedIdentifierFlags.AllowNameSubstitution)) + && !isLocalName(node) + ) { const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node)); if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) { return setTextRange( factory.createPropertyAccessExpression( factory.createIdentifier("exports"), - factory.cloneNode(node) + factory.cloneNode(node), ), - /*location*/ node + /*location*/ node, ); } const importDeclaration = resolver.getReferencedImportDeclaration(node); @@ -2313,19 +2621,21 @@ export function transformModule(context: TransformationContext): (x: SourceFile return setTextRange( factory.createPropertyAccessExpression( factory.getGeneratedNameForNode(importDeclaration.parent), - factory.createIdentifier("default") + factory.createIdentifier("default"), ), - /*location*/ node + /*location*/ node, ); } else if (isImportSpecifier(importDeclaration)) { const name = importDeclaration.propertyName || importDeclaration.name; return setTextRange( factory.createPropertyAccessExpression( - factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration), - factory.cloneNode(name) + factory.getGeneratedNameForNode( + importDeclaration.parent?.parent?.parent || importDeclaration, + ), + factory.cloneNode(name), ), - /*location*/ node + /*location*/ node, ); } } @@ -2345,10 +2655,12 @@ export function transformModule(context: TransformationContext): (x: SourceFile // - We do not substitute generated identifiers unless they are file-level reserved names. // - We do not substitute identifiers tagged with the LocalName flag. // - We only substitute identifiers that are exported at the top level. - if (isAssignmentOperator(node.operatorToken.kind) + if ( + isAssignmentOperator(node.operatorToken.kind) && isIdentifier(node.left) && (!isGeneratedIdentifier(node.left) || isFileLevelReservedGeneratedIdentifier(node.left)) - && !isLocalName(node.left)) { + && !isLocalName(node.left) + ) { const exportedNames = getExports(node.left); if (exportedNames) { // For each additional export of the declaration, apply an export assignment. @@ -2414,5 +2726,5 @@ const dynamicImportUMDHelper: EmitHelper = { name: "typescript:dynamicimport-sync-require", scoped: true, text: ` - var __syncRequire = typeof module === "object" && typeof module.exports === "object";` + var __syncRequire = typeof module === "object" && typeof module.exports === "object";`, }; diff --git a/src/compiler/transformers/module/node.ts b/src/compiler/transformers/module/node.ts index 576c15fe6597e..7a36f5f8e86a0 100644 --- a/src/compiler/transformers/module/node.ts +++ b/src/compiler/transformers/module/node.ts @@ -71,7 +71,7 @@ export function transformNodeModule(context: TransformationContext) { return cjsOnEmitNode(hint, node, emitCallback); } - function getModuleTransformForFile(file: SourceFile): (typeof esmTransform) { + function getModuleTransformForFile(file: SourceFile): typeof esmTransform { return file.impliedNodeFormat === ModuleKind.ESNext ? esmTransform : cjsTransform; } diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index b83bf5244a7f3..128cdc8d2ce82 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -142,7 +142,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory, startLexicalEnvironment, endLexicalEnvironment, - hoistVariableDeclaration + hoistVariableDeclaration, } = context; const compilerOptions = context.getCompilerOptions(); @@ -179,7 +179,11 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param node The SourceFile node. */ function transformSourceFile(node: SourceFile) { - if (node.isDeclarationFile || !(isEffectiveExternalModule(node, compilerOptions) || node.transformFlags & TransformFlags.ContainsDynamicImport)) { + if ( + node.isDeclarationFile + || !(isEffectiveExternalModule(node, compilerOptions) + || node.transformFlags & TransformFlags.ContainsDynamicImport) + ) { return node; } @@ -218,18 +222,28 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc /*name*/ undefined, /*typeParameters*/ undefined, [ - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, exportFunction), - factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, contextObject) + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + exportFunction, + ), + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + contextObject, + ), ], /*type*/ undefined, - moduleBodyBlock + moduleBodyBlock, ); // Write the call to `System.register` // Clear the emit-helpers flag for later passes since we'll have already used it in the module body // So the helper will be emit at the correct position instead of at the top of the source-file const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions); - const dependencies = factory.createArrayLiteralExpression(map(dependencyGroups, dependencyGroup => dependencyGroup.name)); + const dependencies = factory.createArrayLiteralExpression( + map(dependencyGroups, dependencyGroup => dependencyGroup.name), + ); const updated = setEmitFlags( factory.updateSourceFile( node, @@ -241,13 +255,15 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc /*typeArguments*/ undefined, moduleName ? [moduleName, dependencies, moduleBodyFunction] - : [dependencies, moduleBodyFunction] - ) - ) + : [dependencies, moduleBodyFunction], + ), + ), ]), - node.statements - ) - ), EmitFlags.NoTrailingComments); + node.statements, + ), + ), + EmitFlags.NoTrailingComments, + ); if (!outFile(compilerOptions)) { moveEmitHelpers(updated, moduleBodyBlock, helper => !helper.scoped); @@ -272,11 +288,20 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param externalImports The imports for the file. */ - function collectDependencyGroups(externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]) { + function collectDependencyGroups( + externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[], + ) { const groupIndices = new Map(); const dependencyGroups: DependencyGroup[] = []; for (const externalImport of externalImports) { - const externalModuleName = getExternalModuleNameLiteral(factory, externalImport, currentSourceFile, host, resolver, compilerOptions); + const externalModuleName = getExternalModuleNameLiteral( + factory, + externalImport, + currentSourceFile, + host, + resolver, + compilerOptions, + ); if (externalModuleName) { const text = externalModuleName.text; const groupIndex = groupIndices.get(text); @@ -288,7 +313,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc groupIndices.set(text, dependencyGroups.length); dependencyGroups.push({ name: externalModuleName, - externalImports: [externalImport] + externalImports: [externalImport], }); } } @@ -353,7 +378,8 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc startLexicalEnvironment(); // Add any prologue directives. - const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); + const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") + || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); const statementOffset = factory.copyPrologue(node.statements, statements, ensureUseStrict, topLevelVisitor); // var __moduleName = context_1 && context_1.id; @@ -367,11 +393,11 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc /*type*/ undefined, factory.createLogicalAnd( contextObject, - factory.createPropertyAccessExpression(contextObject, "id") - ) - ) - ]) - ) + factory.createPropertyAccessExpression(contextObject, "id"), + ), + ), + ]), + ), ); // Visit the synthetic external helpers import declaration if present @@ -393,14 +419,13 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); const exportStarFunction = addExportStarIfNeeded(statements)!; // TODO: GH#18217 - const modifiers = node.transformFlags & TransformFlags.ContainsAwait ? - factory.createModifiersFromModifierFlags(ModifierFlags.Async) : - undefined; + const modifiers = node.transformFlags & TransformFlags.ContainsAwait + ? factory.createModifiersFromModifierFlags(ModifierFlags.Async) + : undefined; const moduleObject = factory.createObjectLiteralExpression([ - factory.createPropertyAssignment("setters", - createSettersArray(exportStarFunction, dependencyGroups) - ), - factory.createPropertyAssignment("execute", + factory.createPropertyAssignment("setters", createSettersArray(exportStarFunction, dependencyGroups)), + factory.createPropertyAssignment( + "execute", factory.createFunctionExpression( modifiers, /*asteriskToken*/ undefined, @@ -408,9 +433,9 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc /*typeParameters*/ undefined, /*parameters*/ [], /*type*/ undefined, - factory.createBlock(executeStatements, /*multiLine*/ true) - ) - ) + factory.createBlock(executeStatements, /*multiLine*/ true), + ), + ), ], /*multiLine*/ true); statements.push(factory.createReturnStatement(moduleObject)); @@ -463,8 +488,8 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc exportedNames.push( factory.createPropertyAssignment( factory.createStringLiteralFromNode(exportedLocalName), - factory.createTrue() - ) + factory.createTrue(), + ), ); } } @@ -478,10 +503,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc exportedNamesStorageRef, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createObjectLiteralExpression(exportedNames, /*multiLine*/ true) - ) - ]) - ) + factory.createObjectLiteralExpression(exportedNames, /*multiLine*/ true), + ), + ]), + ), ); const exportStarFunction = createExportStarFunction(exportedNamesStorageRef); @@ -509,9 +534,9 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory.createCallExpression( factory.createPropertyAccessExpression(localNames, "hasOwnProperty"), /*typeArguments*/ undefined, - [n] - ) - ) + [n], + ), + ), ); } @@ -530,13 +555,13 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc exports, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createObjectLiteralExpression([]) - ) - ]) + factory.createObjectLiteralExpression([]), + ), + ]), ), factory.createForInStatement( factory.createVariableDeclarationList([ - factory.createVariableDeclaration(n) + factory.createVariableDeclaration(n), ]), m, factory.createBlock([ @@ -546,22 +571,22 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory.createExpressionStatement( factory.createAssignment( factory.createElementAccessExpression(exports, n), - factory.createElementAccessExpression(m, n) - ) - ) + factory.createElementAccessExpression(m, n), + ), + ), ), - EmitFlags.SingleLine - ) - ]) + EmitFlags.SingleLine, + ), + ]), ), factory.createExpressionStatement( factory.createCallExpression( exportFunction, /*typeArguments*/ undefined, - [exports] - ) - ) - ], /*multiLine*/ true) + [exports], + ), + ), + ], /*multiLine*/ true), ); } @@ -575,7 +600,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc const setters: Expression[] = []; for (const group of dependencyGroups) { // derive a unique name for parameter from the first named entry in the group - const localName = forEach(group.externalImports, i => getLocalNameForExternalImport(factory, i, currentSourceFile)); + const localName = forEach( + group.externalImports, + i => getLocalNameForExternalImport(factory, i, currentSourceFile), + ); const parameterName = localName ? factory.getGeneratedNameForNode(localName) : factory.createUniqueName(""); const statements: Statement[] = []; for (const entry of group.externalImports) { @@ -594,8 +622,8 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc // save import into the local statements.push( factory.createExpressionStatement( - factory.createAssignment(importVariableName, parameterName) - ) + factory.createAssignment(importVariableName, parameterName), + ), ); if (hasSyntacticModifier(entry, ModifierFlags.Export)) { statements.push( @@ -606,9 +634,9 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc [ factory.createStringLiteral(idText(importVariableName)), parameterName, - ] - ) - ) + ], + ), + ), ); } break; @@ -632,9 +660,9 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory.createStringLiteral(idText(e.name)), factory.createElementAccessExpression( parameterName, - factory.createStringLiteral(idText(e.propertyName || e.name)) - ) - ) + factory.createStringLiteral(idText(e.propertyName || e.name)), + ), + ), ); } @@ -643,9 +671,9 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory.createCallExpression( exportFunction, /*typeArguments*/ undefined, - [factory.createObjectLiteralExpression(properties, /*multiLine*/ true)] - ) - ) + [factory.createObjectLiteralExpression(properties, /*multiLine*/ true)], + ), + ), ); } else { @@ -656,10 +684,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc /*typeArguments*/ undefined, [ factory.createStringLiteral(idText(entry.exportClause.name)), - parameterName - ] - ) - ) + parameterName, + ], + ), + ), ); } } @@ -674,9 +702,9 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory.createCallExpression( exportStarFunction, /*typeArguments*/ undefined, - [parameterName] - ) - ) + [parameterName], + ), + ), ); } break; @@ -689,10 +717,14 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)], + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + parameterName, + )], /*type*/ undefined, - factory.createBlock(statements, /*multiLine*/ true) - ) + factory.createBlock(statements, /*multiLine*/ true), + ), ); } @@ -751,7 +783,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param node The node to visit. */ function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { - Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); + Debug.assert( + isExternalModuleImportEqualsDeclaration(node), + "import= for internal module references should be handled in an earlier transformer.", + ); let statements: Statement[] | undefined; hoistVariableDeclaration(getLocalNameForExternalImport(factory, node, currentSourceFile)!); // TODO: GH#18217 @@ -780,7 +815,8 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc */ function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { if (hasSyntacticModifier(node, ModifierFlags.Export)) { - hoistedStatements = append(hoistedStatements, + hoistedStatements = append( + hoistedStatements, factory.updateFunctionDeclaration( node, visitNodes(node.modifiers, modifierVisitor, isModifierLike), @@ -789,7 +825,9 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc /*typeParameters*/ undefined, visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, - visitNode(node.body, visitor, isBlock))); + visitNode(node.body, visitor, isBlock), + ), + ); } else { hoistedStatements = append(hoistedStatements, visitEachChild(node, visitor, context)); @@ -812,7 +850,8 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc hoistVariableDeclaration(name); // Rewrite the class declaration into an assignment of a class expression. - statements = append(statements, + statements = append( + statements, setTextRange( factory.createExpressionStatement( factory.createAssignment( @@ -823,14 +862,14 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc node.name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - visitNodes(node.members, visitor, isClassElement) + visitNodes(node.members, visitor, isClassElement), ), - node - ) - ) + node, + ), + ), ), - node - ) + node, + ), ); statements = appendExportsOfHoistedDeclaration(statements, node); @@ -861,13 +900,13 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory.getGeneratedNameForNode(variable.name), /*exclamationToken*/ undefined, /*type*/ undefined, - transformInitializedVariable(variable, /*isExportedDeclaration*/ false) + transformInitializedVariable(variable, /*isExportedDeclaration*/ false), )); } const declarationList = factory.updateVariableDeclarationList( node.declarationList, - declarations + declarations, ); statements = append(statements, factory.updateVariableStatement(node, modifiers, declarationList)); } @@ -884,7 +923,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc } if (expressions) { - statements = append(statements, setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node)); + statements = append( + statements, + setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node), + ); } } @@ -929,7 +971,8 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param isExportedDeclaration A value indicating whether the variable is exported. */ function transformInitializedVariable(node: VariableDeclaration, isExportedDeclaration: boolean): Expression { - const createAssignment = isExportedDeclaration ? createExportedVariableAssignment : createNonExportedVariableAssignment; + const createAssignment = isExportedDeclaration ? createExportedVariableAssignment + : createNonExportedVariableAssignment; return isBindingPattern(node.name) ? flattenDestructuringAssignment( node, @@ -937,9 +980,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc context, FlattenLevel.All, /*needsValue*/ false, - createAssignment + createAssignment, ) - : node.initializer ? createAssignment(node.name, visitNode(node.initializer, visitor, isExpression)) : node.name; + : node.initializer ? createAssignment(node.name, visitNode(node.initializer, visitor, isExpression)) + : node.name; } /** @@ -972,10 +1016,18 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param location The source map location for the assignment. * @param isExportedDeclaration A value indicating whether the variable is exported. */ - function createVariableAssignment(name: Identifier, value: Expression, location: TextRange | undefined, isExportedDeclaration: boolean) { + function createVariableAssignment( + name: Identifier, + value: Expression, + location: TextRange | undefined, + isExportedDeclaration: boolean, + ) { hoistVariableDeclaration(factory.cloneNode(name)); return isExportedDeclaration - ? createExportExpression(name, preventSubstitution(setTextRange(factory.createAssignment(name, value), location))) + ? createExportExpression( + name, + preventSubstitution(setTextRange(factory.createAssignment(name, value), location)), + ) : preventSubstitution(setTextRange(factory.createAssignment(name, value), location)); } @@ -1030,7 +1082,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfImportEqualsDeclaration(statements: Statement[] | undefined, decl: ImportEqualsDeclaration): Statement[] | undefined { + function appendExportsOfImportEqualsDeclaration( + statements: Statement[] | undefined, + decl: ImportEqualsDeclaration, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } @@ -1049,7 +1104,11 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param exportSelf A value indicating whether to also export each VariableDeclaration of * `nodes` declaration list. */ - function appendExportsOfVariableStatement(statements: Statement[] | undefined, node: VariableStatement, exportSelf: boolean): Statement[] | undefined { + function appendExportsOfVariableStatement( + statements: Statement[] | undefined, + node: VariableStatement, + exportSelf: boolean, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } @@ -1073,7 +1132,11 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param decl The declaration whose exports are to be recorded. * @param exportSelf A value indicating whether to also export the declaration itself. */ - function appendExportsOfBindingElement(statements: Statement[] | undefined, decl: VariableDeclaration | BindingElement, exportSelf: boolean): Statement[] | undefined { + function appendExportsOfBindingElement( + statements: Statement[] | undefined, + decl: VariableDeclaration | BindingElement, + exportSelf: boolean, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } @@ -1107,14 +1170,18 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * appended. * @param decl The declaration whose exports are to be recorded. */ - function appendExportsOfHoistedDeclaration(statements: Statement[] | undefined, decl: ClassDeclaration | FunctionDeclaration): Statement[] | undefined { + function appendExportsOfHoistedDeclaration( + statements: Statement[] | undefined, + decl: ClassDeclaration | FunctionDeclaration, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } let excludeName: string | undefined; if (hasSyntacticModifier(decl, ModifierFlags.Export)) { - const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) ? factory.createStringLiteral("default") : decl.name!; + const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) + ? factory.createStringLiteral("default") : decl.name!; statements = appendExportStatement(statements, exportName, factory.getLocalName(decl)); excludeName = getTextOfIdentifierOrLiteral(exportName); } @@ -1135,7 +1202,11 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param decl The declaration to export. * @param excludeName An optional name to exclude from exports. */ - function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration, excludeName?: string): Statement[] | undefined { + function appendExportsOfDeclaration( + statements: Statement[] | undefined, + decl: Declaration, + excludeName?: string, + ): Statement[] | undefined { if (moduleInfo.exportEquals) { return statements; } @@ -1163,7 +1234,12 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param expression The expression to export. * @param allowComments Whether to allow comments on the export. */ - function appendExportStatement(statements: Statement[] | undefined, exportName: Identifier | StringLiteral, expression: Expression, allowComments?: boolean): Statement[] | undefined { + function appendExportStatement( + statements: Statement[] | undefined, + exportName: Identifier | StringLiteral, + expression: Expression, + allowComments?: boolean, + ): Statement[] | undefined { statements = append(statements, createExportStatement(exportName, expression, allowComments)); return statements; } @@ -1194,7 +1270,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc function createExportExpression(name: Identifier | StringLiteral, value: Expression) { const exportName = isIdentifier(name) ? factory.createStringLiteralFromNode(name) : name; setEmitFlags(value, getEmitFlags(value) | EmitFlags.NoComments); - return setCommentRange(factory.createCallExpression(exportFunction, /*typeArguments*/ undefined, [exportName, value]), value); + return setCommentRange( + factory.createCallExpression(exportFunction, /*typeArguments*/ undefined, [exportName, value]), + value, + ); } // @@ -1281,7 +1360,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc visitNode(node.initializer, isTopLevel ? visitForInitializer : discardedValueVisitor, isForInitializer), visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, discardedValueVisitor, isExpression), - visitIterationBody(node.statement, isTopLevel ? topLevelNestedVisitor : visitor, context) + visitIterationBody(node.statement, isTopLevel ? topLevelNestedVisitor : visitor, context), ); enclosingBlockScopedContainer = savedEnclosingBlockScopedContainer; @@ -1301,7 +1380,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc node, visitForInitializer(node.initializer), visitNode(node.expression, visitor, isExpression), - visitIterationBody(node.statement, topLevelNestedVisitor, context) + visitIterationBody(node.statement, topLevelNestedVisitor, context), ); enclosingBlockScopedContainer = savedEnclosingBlockScopedContainer; @@ -1322,7 +1401,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc node.awaitModifier, visitForInitializer(node.initializer), visitNode(node.expression, visitor, isExpression), - visitIterationBody(node.statement, topLevelNestedVisitor, context) + visitIterationBody(node.statement, topLevelNestedVisitor, context), ); enclosingBlockScopedContainer = savedEnclosingBlockScopedContainer; @@ -1349,7 +1428,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc if (shouldHoistForInitializer(node)) { let expressions: Expression[] | undefined; for (const variable of node.declarations) { - expressions = append(expressions, transformInitializedVariable(variable, /*isExportedDeclaration*/ false)); + expressions = append( + expressions, + transformInitializedVariable(variable, /*isExportedDeclaration*/ false), + ); if (!variable.initializer) { hoistBindingElement(variable); } @@ -1371,7 +1453,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateDoStatement( node, visitIterationBody(node.statement, topLevelNestedVisitor, context), - visitNode(node.expression, visitor, isExpression) + visitNode(node.expression, visitor, isExpression), ); } @@ -1384,7 +1466,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateWhileStatement( node, visitNode(node.expression, visitor, isExpression), - visitIterationBody(node.statement, topLevelNestedVisitor, context) + visitIterationBody(node.statement, topLevelNestedVisitor, context), ); } @@ -1397,7 +1479,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateLabeledStatement( node, node.label, - Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)) + Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)), ); } @@ -1410,7 +1492,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateWithStatement( node, visitNode(node.expression, visitor, isExpression), - Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)) + Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)), ); } @@ -1424,7 +1506,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc node, visitNode(node.expression, visitor, isExpression), Debug.checkDefined(visitNode(node.thenStatement, topLevelNestedVisitor, isStatement, factory.liftToBlock)), - visitNode(node.elseStatement, topLevelNestedVisitor, isStatement, factory.liftToBlock) + visitNode(node.elseStatement, topLevelNestedVisitor, isStatement, factory.liftToBlock), ); } @@ -1437,7 +1519,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateSwitchStatement( node, visitNode(node.expression, visitor, isExpression), - Debug.checkDefined(visitNode(node.caseBlock, topLevelNestedVisitor, isCaseBlock)) + Debug.checkDefined(visitNode(node.caseBlock, topLevelNestedVisitor, isCaseBlock)), ); } @@ -1452,7 +1534,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc node = factory.updateCaseBlock( node, - visitNodes(node.clauses, topLevelNestedVisitor, isCaseOrDefaultClause) + visitNodes(node.clauses, topLevelNestedVisitor, isCaseOrDefaultClause), ); enclosingBlockScopedContainer = savedEnclosingBlockScopedContainer; @@ -1468,7 +1550,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateCaseClause( node, visitNode(node.expression, visitor, isExpression), - visitNodes(node.statements, topLevelNestedVisitor, isStatement) + visitNodes(node.statements, topLevelNestedVisitor, isStatement), ); } @@ -1502,7 +1584,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc node = factory.updateCatchClause( node, node.variableDeclaration, - Debug.checkDefined(visitNode(node.block, topLevelNestedVisitor, isBlock)) + Debug.checkDefined(visitNode(node.block, topLevelNestedVisitor, isBlock)), ); enclosingBlockScopedContainer = savedEnclosingBlockScopedContainer; @@ -1534,7 +1616,11 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * @param node The node to visit. */ function visitorWorker(node: Node, valueIsDiscarded: boolean): VisitResult { - if (!(node.transformFlags & (TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsDynamicImport | TransformFlags.ContainsUpdateExpressionForIdentifier))) { + if ( + !(node.transformFlags + & (TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsDynamicImport + | TransformFlags.ContainsUpdateExpressionForIdentifier)) + ) { return node; } switch (node.kind) { @@ -1558,7 +1644,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc break; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - return visitPrefixOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded); + return visitPrefixOrPostfixUnaryExpression( + node as PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded, + ); } return visitEachChild(node, visitor, context); } @@ -1581,11 +1670,17 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc } function visitParenthesizedExpression(node: ParenthesizedExpression, valueIsDiscarded: boolean) { - return factory.updateParenthesizedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); + return factory.updateParenthesizedExpression( + node, + visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression), + ); } function visitPartiallyEmittedExpression(node: PartiallyEmittedExpression, valueIsDiscarded: boolean) { - return factory.updatePartiallyEmittedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); + return factory.updatePartiallyEmittedExpression( + node, + visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression), + ); } function visitImportCallExpression(node: ImportCall): Expression { @@ -1599,17 +1694,26 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc // } // }; // }); - const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); + const externalModuleName = getExternalModuleNameLiteral( + factory, + node, + currentSourceFile, + host, + resolver, + compilerOptions, + ); const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor, isExpression); // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. - const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; + const argument = externalModuleName + && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) + ? externalModuleName : firstArgument; return factory.createCallExpression( factory.createPropertyAccessExpression( contextObject, - factory.createIdentifier("import") + factory.createIdentifier("import"), ), /*typeArguments*/ undefined, - argument ? [argument] : [] + argument ? [argument] : [], ); } @@ -1618,14 +1722,17 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function visitDestructuringAssignment(node: DestructuringAssignment, valueIsDiscarded: boolean): VisitResult { + function visitDestructuringAssignment( + node: DestructuringAssignment, + valueIsDiscarded: boolean, + ): VisitResult { if (hasExportedReferenceInDestructuringTarget(node.left)) { return flattenDestructuringAssignment( node, visitor, context, FlattenLevel.All, - !valueIsDiscarded + !valueIsDiscarded, ); } @@ -1665,7 +1772,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc } } - function visitPrefixOrPostfixUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded: boolean) { + function visitPrefixOrPostfixUnaryExpression( + node: PrefixUnaryExpression | PostfixUnaryExpression, + valueIsDiscarded: boolean, + ) { // When we see a prefix or postfix increment expression whose operand is an exported // symbol, we should ensure all exports of that symbol are updated with the correct // value. @@ -1675,11 +1785,13 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc // - We do not transform identifiers that were originally the name of an enum or // namespace due to how they are transformed in TypeScript. // - We only transform identifiers that are exported at the top level. - if ((node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) + if ( + (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) && isIdentifier(node.operand) && !isGeneratedIdentifier(node.operand) && !isLocalName(node.operand) - && !isDeclarationNameOfEnumOrNamespace(node.operand)) { + && !isDeclarationNameOfEnumOrNamespace(node.operand) + ) { const exportedNames = getExports(node.operand); if (exportedNames) { let temp: Identifier | undefined; @@ -1823,10 +1935,10 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory.cloneNode(name), factory.createPropertyAccessExpression( factory.getGeneratedNameForNode(importDeclaration.parent), - factory.createIdentifier("default") - ) + factory.createIdentifier("default"), + ), ), - /*location*/ node + /*location*/ node, ); } else if (isImportSpecifier(importDeclaration)) { @@ -1834,11 +1946,13 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc factory.createPropertyAssignment( factory.cloneNode(name), factory.createPropertyAccessExpression( - factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration), - factory.cloneNode(importDeclaration.propertyName || importDeclaration.name) + factory.getGeneratedNameForNode( + importDeclaration.parent?.parent?.parent || importDeclaration, + ), + factory.cloneNode(importDeclaration.propertyName || importDeclaration.name), ), ), - /*location*/ node + /*location*/ node, ); } } @@ -1892,18 +2006,20 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return setTextRange( factory.createPropertyAccessExpression( factory.getGeneratedNameForNode(importDeclaration.parent), - factory.createIdentifier("default") + factory.createIdentifier("default"), ), - /*location*/ node + /*location*/ node, ); } else if (isImportSpecifier(importDeclaration)) { return setTextRange( factory.createPropertyAccessExpression( - factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration), - factory.cloneNode(importDeclaration.propertyName || importDeclaration.name) + factory.getGeneratedNameForNode( + importDeclaration.parent?.parent?.parent || importDeclaration, + ), + factory.cloneNode(importDeclaration.propertyName || importDeclaration.name), ), - /*location*/ node + /*location*/ node, ); } } @@ -1924,10 +2040,12 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc // - We do not substitute generated identifiers unless they are file-level reserved names. // - We do not substitute identifiers tagged with the LocalName flag. // - We only substitute identifiers that are exported at the top level. - if (isAssignmentOperator(node.operatorToken.kind) + if ( + isAssignmentOperator(node.operatorToken.kind) && isIdentifier(node.left) && (!isGeneratedIdentifier(node.left) || isFileLevelReservedGeneratedIdentifier(node.left)) - && !isLocalName(node.left)) { + && !isLocalName(node.left) + ) { const exportedNames = getExports(node.left); if (exportedNames) { // For each additional export of the declaration, apply an export assignment. @@ -1985,14 +2103,18 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc if (importDeclaration) return importDeclaration; const valueDeclaration = resolver.getReferencedValueDeclaration(name); - if (valueDeclaration && moduleInfo?.exportedBindings[getOriginalNodeId(valueDeclaration)]) return valueDeclaration; + if (valueDeclaration && moduleInfo?.exportedBindings[getOriginalNodeId(valueDeclaration)]) { + return valueDeclaration; + } // An exported namespace or enum may merge with an ambient declaration, which won't show up in // .js emit. When that happens, try to find bindings associated with a non-ambient declaration. const declarations = resolver.getReferencedValueDeclarations(name); if (declarations) { for (const declaration of declarations) { - if (declaration !== valueDeclaration && moduleInfo?.exportedBindings[getOriginalNodeId(declaration)]) return declaration; + if ( + declaration !== valueDeclaration && moduleInfo?.exportedBindings[getOriginalNodeId(declaration)] + ) return declaration; } } diff --git a/src/compiler/transformers/namedEvaluation.ts b/src/compiler/transformers/namedEvaluation.ts index 5af5d90781e63..b21df6b0b5f65 100644 --- a/src/compiler/transformers/namedEvaluation.ts +++ b/src/compiler/transformers/namedEvaluation.ts @@ -47,23 +47,33 @@ import { SyntaxKind, TransformationContext, VariableDeclaration, - WrappedExpression + WrappedExpression, } from "../_namespaces/ts"; /** * 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): StringLiteral { +export function getAssignedNameOfIdentifier( + factory: NodeFactory, + name: Identifier, + expression: WrappedExpression, +): StringLiteral { const original = getOriginalNode(skipOuterExpressions(expression)); - if ((isClassDeclaration(original) || isFunctionDeclaration(original)) && - !original.name && hasSyntacticModifier(original, ModifierFlags.Default)) { + if ( + (isClassDeclaration(original) || isFunctionDeclaration(original)) + && !original.name && hasSyntacticModifier(original, ModifierFlags.Default) + ) { return factory.createStringLiteral("default"); } return factory.createStringLiteralFromNode(name); } -function getAssignedNameOfPropertyName(context: TransformationContext, name: PropertyName, assignedNameText: string | undefined) { +function getAssignedNameOfPropertyName( + context: TransformationContext, + name: PropertyName, + assignedNameText: string | undefined, +) { const { factory } = context; if (assignedNameText !== undefined) { const assignedName = factory.createStringLiteral(assignedNameText); @@ -98,7 +108,11 @@ function getAssignedNameOfPropertyName(context: TransformationContext, name: Pro * 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 { +export function createClassNamedEvaluationHelperBlock( + context: TransformationContext, + assignedName: Expression, + thisExpression: Expression = context.factory.createThis(), +): ClassNamedEvaluationHelperBlock { // produces: // // static { __setFunctionName(this, "C"); } @@ -119,17 +133,18 @@ export function createClassNamedEvaluationHelperBlock(context: TransformationCon /** @internal */ export type ClassNamedEvaluationHelperBlock = ClassStaticBlockDeclaration & { readonly body: Block & { - readonly statements: NodeArray & readonly [ - ExpressionStatement & { - readonly expression: CallExpression & { - readonly expression: Identifier; - }; - } - ]; + readonly statements: + & NodeArray + & readonly [ + ExpressionStatement & { + readonly expression: CallExpression & { + readonly expression: Identifier; + }; + }, + ]; }; }; - /** * Gets whether a node is a `static {}` block containing only a single call to the `__setFunctionName` helper where that * call's second argument is the value stored in the `assignedName` property of the block's `EmitNode`. @@ -141,10 +156,10 @@ export function isClassNamedEvaluationHelperBlock(node: Node): node is ClassName } const statement = node.body.statements[0]; - return isExpressionStatement(statement) && - isCallToHelper(statement.expression, "___setFunctionName" as __String) && - (statement.expression as CallExpression).arguments.length >= 2 && - (statement.expression as CallExpression).arguments[1] === node.emitNode?.assignedName; + return isExpressionStatement(statement) + && isCallToHelper(statement.expression, "___setFunctionName" as __String) + && (statement.expression as CallExpression).arguments.length >= 2 + && (statement.expression as CallExpression).arguments[1] === node.emitNode?.assignedName; } /** @@ -173,13 +188,13 @@ export function injectClassNamedEvaluationHelperBlockIfMissing>; export function injectClassNamedEvaluationHelperBlockIfMissing( context: TransformationContext, node: ClassLikeDeclaration, assignedName: Expression, - thisExpression?: Expression + thisExpression?: Expression, ) { // given: // @@ -210,21 +225,23 @@ export function injectClassNamedEvaluationHelperBlockIfMissing( const members = factory.createNodeArray([...leading, namedEvaluationBlock, ...trailing]); setTextRange(members, node.members); - node = isClassDeclaration(node) ? - factory.updateClassDeclaration( + node = isClassDeclaration(node) + ? factory.updateClassDeclaration( node, node.modifiers, node.name, node.typeParameters, node.heritageClauses, - members) : - factory.updateClassExpression( + members, + ) + : factory.updateClassExpression( node, node.modifiers, node.name, node.typeParameters, node.heritageClauses, - members); + members, + ); getOrCreateEmitNode(node).assignedName = assignedName; return node; @@ -243,14 +260,22 @@ function finishTransformNamedEvaluation( const { factory } = context; const innerExpression = skipOuterExpressions(expression); - const updatedExpression = isClassExpression(innerExpression) ? - cast(injectClassNamedEvaluationHelperBlockIfMissing(context, innerExpression, assignedName), isClassExpression) : - context.getEmitHelperFactory().createSetFunctionNameHelper(innerExpression, assignedName); + const updatedExpression = isClassExpression(innerExpression) + ? cast( + injectClassNamedEvaluationHelperBlockIfMissing(context, innerExpression, assignedName), + isClassExpression, + ) + : context.getEmitHelperFactory().createSetFunctionNameHelper(innerExpression, assignedName); return factory.restoreOuterExpressions(expression, updatedExpression); } -function transformNamedEvaluationOfPropertyAssignment(context: TransformationContext, node: NamedEvaluation & PropertyAssignment, ignoreEmptyStringLiteral?: boolean, assignedNameText?: string) { +function transformNamedEvaluationOfPropertyAssignment( + context: TransformationContext, + node: NamedEvaluation & PropertyAssignment, + ignoreEmptyStringLiteral?: boolean, + assignedNameText?: string, +) { // 13.2.5.5 RS: PropertyDefinitionEvaluation // PropertyAssignment : PropertyName `:` AssignmentExpression // ... @@ -260,14 +285,25 @@ function transformNamedEvaluationOfPropertyAssignment(context: TransformationCon const { factory } = context; const { assignedName, name } = getAssignedNameOfPropertyName(context, node.name, assignedNameText); - const initializer = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral); + const initializer = finishTransformNamedEvaluation( + context, + node.initializer, + assignedName, + ignoreEmptyStringLiteral, + ); return factory.updatePropertyAssignment( node, name, - initializer); + initializer, + ); } -function transformNamedEvaluationOfShorthandAssignmentProperty(context: TransformationContext, node: NamedEvaluation & ShorthandPropertyAssignment, ignoreEmptyStringLiteral?: boolean, assignedNameText?: string) { +function transformNamedEvaluationOfShorthandAssignmentProperty( + context: TransformationContext, + node: NamedEvaluation & ShorthandPropertyAssignment, + ignoreEmptyStringLiteral?: boolean, + assignedNameText?: string, +) { // 13.15.5.3 RS: PropertyDestructuringAssignmentEvaluation // AssignmentProperty : IdentifierReference Initializer? // ... @@ -277,16 +313,27 @@ function transformNamedEvaluationOfShorthandAssignmentProperty(context: Transfor // ... const { factory } = context; - const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) : - getAssignedNameOfIdentifier(factory, node.name, node.objectAssignmentInitializer); - const objectAssignmentInitializer = finishTransformNamedEvaluation(context, node.objectAssignmentInitializer, assignedName, ignoreEmptyStringLiteral); + const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) + : getAssignedNameOfIdentifier(factory, node.name, node.objectAssignmentInitializer); + const objectAssignmentInitializer = finishTransformNamedEvaluation( + context, + node.objectAssignmentInitializer, + assignedName, + ignoreEmptyStringLiteral, + ); return factory.updateShorthandPropertyAssignment( node, node.name, - objectAssignmentInitializer); + objectAssignmentInitializer, + ); } -function transformNamedEvaluationOfVariableDeclaration(context: TransformationContext, node: NamedEvaluation & VariableDeclaration, ignoreEmptyStringLiteral?: boolean, assignedNameText?: string) { +function transformNamedEvaluationOfVariableDeclaration( + context: TransformationContext, + node: NamedEvaluation & VariableDeclaration, + ignoreEmptyStringLiteral?: boolean, + assignedNameText?: string, +) { // 14.3.1.2 RS: Evaluation // LexicalBinding : BindingIdentifier Initializer // ... @@ -302,18 +349,29 @@ function transformNamedEvaluationOfVariableDeclaration(context: TransformationCo // ... const { factory } = context; - const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) : - getAssignedNameOfIdentifier(factory, node.name, node.initializer); - const initializer = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral); + const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) + : getAssignedNameOfIdentifier(factory, node.name, node.initializer); + const initializer = finishTransformNamedEvaluation( + context, + node.initializer, + assignedName, + ignoreEmptyStringLiteral, + ); return factory.updateVariableDeclaration( node, node.name, node.exclamationToken, node.type, - initializer); + initializer, + ); } -function transformNamedEvaluationOfParameterDeclaration(context: TransformationContext, node: NamedEvaluation & ParameterDeclaration, ignoreEmptyStringLiteral?: boolean, assignedNameText?: string) { +function transformNamedEvaluationOfParameterDeclaration( + context: TransformationContext, + node: NamedEvaluation & ParameterDeclaration, + ignoreEmptyStringLiteral?: boolean, + assignedNameText?: string, +) { // 8.6.3 RS: IteratorBindingInitialization // SingleNameBinding : BindingIdentifier Initializer? // ... @@ -331,9 +389,14 @@ function transformNamedEvaluationOfParameterDeclaration(context: TransformationC // ... const { factory } = context; - const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) : - getAssignedNameOfIdentifier(factory, node.name, node.initializer); - const initializer = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral); + const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) + : getAssignedNameOfIdentifier(factory, node.name, node.initializer); + const initializer = finishTransformNamedEvaluation( + context, + node.initializer, + assignedName, + ignoreEmptyStringLiteral, + ); return factory.updateParameterDeclaration( node, node.modifiers, @@ -341,10 +404,16 @@ function transformNamedEvaluationOfParameterDeclaration(context: TransformationC node.name, node.questionToken, node.type, - initializer); + initializer, + ); } -function transformNamedEvaluationOfBindingElement(context: TransformationContext, node: NamedEvaluation & BindingElement, ignoreEmptyStringLiteral?: boolean, assignedNameText?: string) { +function transformNamedEvaluationOfBindingElement( + context: TransformationContext, + node: NamedEvaluation & BindingElement, + ignoreEmptyStringLiteral?: boolean, + assignedNameText?: string, +) { // 8.6.3 RS: IteratorBindingInitialization // SingleNameBinding : BindingIdentifier Initializer? // ... @@ -362,18 +431,29 @@ function transformNamedEvaluationOfBindingElement(context: TransformationContext // ... const { factory } = context; - const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) : - getAssignedNameOfIdentifier(factory, node.name, node.initializer); - const initializer = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral); + const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) + : getAssignedNameOfIdentifier(factory, node.name, node.initializer); + const initializer = finishTransformNamedEvaluation( + context, + node.initializer, + assignedName, + ignoreEmptyStringLiteral, + ); return factory.updateBindingElement( node, node.dotDotDotToken, node.propertyName, node.name, - initializer); + initializer, + ); } -function transformNamedEvaluationOfPropertyDeclaration(context: TransformationContext, node: NamedEvaluation & PropertyDeclaration, ignoreEmptyStringLiteral?: boolean, assignedNameText?: string) { +function transformNamedEvaluationOfPropertyDeclaration( + context: TransformationContext, + node: NamedEvaluation & PropertyDeclaration, + ignoreEmptyStringLiteral?: boolean, + assignedNameText?: string, +) { // 10.2.1.3 RS: EvaluateBody // Initializer : `=` AssignmentExpression // ... @@ -383,17 +463,28 @@ function transformNamedEvaluationOfPropertyDeclaration(context: TransformationCo const { factory } = context; const { assignedName, name } = getAssignedNameOfPropertyName(context, node.name, assignedNameText); - const initializer = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral); + const initializer = finishTransformNamedEvaluation( + context, + node.initializer, + assignedName, + ignoreEmptyStringLiteral, + ); return factory.updatePropertyDeclaration( node, node.modifiers, name, node.questionToken ?? node.exclamationToken, node.type, - initializer); + initializer, + ); } -function transformNamedEvaluationOfAssignmentExpression(context: TransformationContext, node: NamedEvaluation & BinaryExpression, ignoreEmptyStringLiteral?: boolean, assignedNameText?: string) { +function transformNamedEvaluationOfAssignmentExpression( + context: TransformationContext, + node: NamedEvaluation & BinaryExpression, + ignoreEmptyStringLiteral?: boolean, + assignedNameText?: string, +) { // 13.15.2 RS: Evaluation // AssignmentExpression : LeftHandSideExpression `=` AssignmentExpression // 1. If |LeftHandSideExpression| is neither an |ObjectLiteral| nor an |ArrayLiteral|, then @@ -421,17 +512,23 @@ function transformNamedEvaluationOfAssignmentExpression(context: TransformationC // ... const { factory } = context; - const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) : - getAssignedNameOfIdentifier(factory, node.left, node.right); + const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) + : getAssignedNameOfIdentifier(factory, node.left, node.right); const right = finishTransformNamedEvaluation(context, node.right, assignedName, ignoreEmptyStringLiteral); return factory.updateBinaryExpression( node, node.left, node.operatorToken, - right); + right, + ); } -function transformNamedEvaluationOfExportAssignment(context: TransformationContext, node: NamedEvaluation & ExportAssignment, ignoreEmptyStringLiteral?: boolean, assignedNameText?: string) { +function transformNamedEvaluationOfExportAssignment( + context: TransformationContext, + node: NamedEvaluation & ExportAssignment, + ignoreEmptyStringLiteral?: boolean, + assignedNameText?: string, +) { // 16.2.3.7 RS: Evaluation // ExportDeclaration : `export` `default` AssignmentExpression `;` // 1. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true*, then @@ -442,36 +539,62 @@ function transformNamedEvaluationOfExportAssignment(context: TransformationConte // is `""`. const { factory } = context; - const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) : - factory.createStringLiteral(node.isExportEquals ? "" : "default"); + const assignedName = assignedNameText !== undefined ? factory.createStringLiteral(assignedNameText) + : factory.createStringLiteral(node.isExportEquals ? "" : "default"); const expression = finishTransformNamedEvaluation(context, node.expression, assignedName, ignoreEmptyStringLiteral); return factory.updateExportAssignment( node, node.modifiers, - expression); + expression, + ); } /** * Performs a shallow transformation of a `NamedEvaluation` node, such that a valid name will be assigned. * @internal */ -export function transformNamedEvaluation(context: TransformationContext, node: T, ignoreEmptyStringLiteral?: boolean, assignedName?: string): Extract>; -export function transformNamedEvaluation(context: TransformationContext, node: NamedEvaluation, ignoreEmptyStringLiteral?: boolean, assignedName?: string) { +export function transformNamedEvaluation( + context: TransformationContext, + node: T, + ignoreEmptyStringLiteral?: boolean, + assignedName?: string, +): Extract>; +export function transformNamedEvaluation( + context: TransformationContext, + node: NamedEvaluation, + ignoreEmptyStringLiteral?: boolean, + assignedName?: string, +) { switch (node.kind) { case SyntaxKind.PropertyAssignment: return transformNamedEvaluationOfPropertyAssignment(context, node, ignoreEmptyStringLiteral, assignedName); case SyntaxKind.ShorthandPropertyAssignment: - return transformNamedEvaluationOfShorthandAssignmentProperty(context, node, ignoreEmptyStringLiteral, assignedName); + return transformNamedEvaluationOfShorthandAssignmentProperty( + context, + node, + ignoreEmptyStringLiteral, + assignedName, + ); case SyntaxKind.VariableDeclaration: return transformNamedEvaluationOfVariableDeclaration(context, node, ignoreEmptyStringLiteral, assignedName); case SyntaxKind.Parameter: - return transformNamedEvaluationOfParameterDeclaration(context, node, ignoreEmptyStringLiteral, assignedName); + return transformNamedEvaluationOfParameterDeclaration( + context, + node, + ignoreEmptyStringLiteral, + assignedName, + ); case SyntaxKind.BindingElement: return transformNamedEvaluationOfBindingElement(context, node, ignoreEmptyStringLiteral, assignedName); case SyntaxKind.PropertyDeclaration: return transformNamedEvaluationOfPropertyDeclaration(context, node, ignoreEmptyStringLiteral, assignedName); case SyntaxKind.BinaryExpression: - return transformNamedEvaluationOfAssignmentExpression(context, node, ignoreEmptyStringLiteral, assignedName); + return transformNamedEvaluationOfAssignmentExpression( + context, + node, + ignoreEmptyStringLiteral, + assignedName, + ); case SyntaxKind.ExportAssignment: return transformNamedEvaluationOfExportAssignment(context, node, ignoreEmptyStringLiteral, assignedName); } diff --git a/src/compiler/transformers/taggedTemplate.ts b/src/compiler/transformers/taggedTemplate.ts index ca23140c0d448..aa4120d7750ef 100644 --- a/src/compiler/transformers/taggedTemplate.ts +++ b/src/compiler/transformers/taggedTemplate.ts @@ -28,7 +28,7 @@ import { /** @internal */ export enum ProcessLevel { LiftRestriction, - All + All, } /** @internal */ @@ -38,8 +38,8 @@ export function processTaggedTemplateExpression( visitor: Visitor, currentSourceFile: SourceFile, recordTaggedTemplateString: (temp: Identifier) => void, - level: ProcessLevel): CallExpression | TaggedTemplateExpression { - + level: ProcessLevel, +): CallExpression | TaggedTemplateExpression { // Visit the tag expression const tag = visitNode(node.tag, visitor, isExpression); Debug.assert(tag); @@ -74,7 +74,8 @@ export function processTaggedTemplateExpression( const helperCall = context.getEmitHelperFactory().createTemplateObjectHelper( factory.createArrayLiteralExpression(cookedStrings), - factory.createArrayLiteralExpression(rawStrings)); + factory.createArrayLiteralExpression(rawStrings), + ); // Create a variable to cache the template object if we're in a module. // Do not do this in the global scope, as any variable we currently generate could conflict with @@ -86,7 +87,8 @@ export function processTaggedTemplateExpression( tempVar, factory.createAssignment( tempVar, - helperCall) + helperCall, + ), ); } else { @@ -96,8 +98,12 @@ export function processTaggedTemplateExpression( return factory.createCallExpression(tag, /*typeArguments*/ undefined, templateArguments); } -function createTemplateCooked(factory: NodeFactory, template: TemplateHead | TemplateMiddle | TemplateTail | NoSubstitutionTemplateLiteral) { - return template.templateFlags! & TokenFlags.IsInvalid ? factory.createVoidZero() : factory.createStringLiteral(template.text); +function createTemplateCooked( + factory: NodeFactory, + template: TemplateHead | TemplateMiddle | TemplateTail | NoSubstitutionTemplateLiteral, +) { + return template.templateFlags! & TokenFlags.IsInvalid ? factory.createVoidZero() + : factory.createStringLiteral(template.text); } /** @@ -111,8 +117,10 @@ function getRawLiteral(factory: NodeFactory, node: TemplateLiteralLikeNode, curr // Examples: `\n` is converted to "\\n", a template string with a newline to "\n". let text = node.rawText; if (text === undefined) { - Debug.assertIsDefined(currentSourceFile, - "Template literal node is missing 'rawText' and does not have a source file. Possibly bad transform."); + Debug.assertIsDefined( + currentSourceFile, + "Template literal node is missing 'rawText' and does not have a source file. Possibly bad transform.", + ); text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node); // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"), diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 04e56401f9dba..ce3cc9f812552 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -196,7 +196,7 @@ import { visitNode, visitNodes, visitParameterList, - VisitResult + VisitResult, } from "../_namespaces/ts"; /** @@ -208,7 +208,7 @@ const enum TypeScriptSubstitutionFlags { /** Enables substitutions for namespace exports. */ NamespaceExports = 1 << 1, /* Enables substitutions for unqualified enum members */ - NonQualifiedEnumMembers = 1 << 3 + NonQualifiedEnumMembers = 1 << 3, } const enum ClassFacts { @@ -286,12 +286,15 @@ export function transformTypeScript(context: TransformationContext) { } function transformBundle(node: Bundle) { - return factory.createBundle(node.sourceFiles.map(transformSourceFile), mapDefined(node.prepends, prepend => { - if (prepend.kind === SyntaxKind.InputFiles) { - return createUnparsedSourceFile(prepend, "js"); - } - return prepend; - })); + return factory.createBundle( + node.sourceFiles.map(transformSourceFile), + mapDefined(node.prepends, prepend => { + if (prepend.kind === SyntaxKind.InputFiles) { + return createUnparsedSourceFile(prepend, "js"); + } + return prepend; + }), + ); } /** @@ -368,7 +371,9 @@ export function transformTypeScript(context: TransformationContext) { // These nodes should always have names unless they are default-exports; // however, class declaration parsing allows for undefined names, so syntactically invalid // programs may also have an undefined name. - Debug.assert(node.kind === SyntaxKind.ClassDeclaration || hasSyntacticModifier(node, ModifierFlags.Default)); + Debug.assert( + node.kind === SyntaxKind.ClassDeclaration || hasSyntacticModifier(node, ModifierFlags.Default), + ); } break; @@ -416,13 +421,17 @@ export function transformTypeScript(context: TransformationContext) { case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ExportAssignment: case SyntaxKind.ExportDeclaration: - return visitElidableStatement(node as ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration); + return visitElidableStatement( + node as ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration, + ); default: return visitorWorker(node); } } - function visitElidableStatement(node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration): VisitResult { + function visitElidableStatement( + node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration, + ): VisitResult { const parsed = getParseTreeNode(node); if (parsed !== node) { // If the node has been transformed by a `before` transformer, perform no ellision on it @@ -465,15 +474,19 @@ export function transformTypeScript(context: TransformationContext) { * @param node The node to visit. */ function namespaceElementVisitorWorker(node: Node): VisitResult { - if (node.kind === SyntaxKind.ExportDeclaration || - node.kind === SyntaxKind.ImportDeclaration || - node.kind === SyntaxKind.ImportClause || - (node.kind === SyntaxKind.ImportEqualsDeclaration && - (node as ImportEqualsDeclaration).moduleReference.kind === SyntaxKind.ExternalModuleReference)) { + if ( + node.kind === SyntaxKind.ExportDeclaration + || node.kind === SyntaxKind.ImportDeclaration + || node.kind === SyntaxKind.ImportClause + || (node.kind === SyntaxKind.ImportEqualsDeclaration + && (node as ImportEqualsDeclaration).moduleReference.kind === SyntaxKind.ExternalModuleReference) + ) { // do not emit ES6 imports and exports since they are illegal inside a namespace return undefined; } - else if (node.transformFlags & TransformFlags.ContainsTypeScript || hasSyntacticModifier(node, ModifierFlags.Export)) { + else if ( + node.transformFlags & TransformFlags.ContainsTypeScript || hasSyntacticModifier(node, ModifierFlags.Export) + ) { return visitTypeScript(node); } @@ -532,11 +545,16 @@ export function transformTypeScript(context: TransformationContext) { } } - function getObjectLiteralElementVisitor(parent: ObjectLiteralExpression): (node: T) => VisitResult { + function getObjectLiteralElementVisitor( + parent: ObjectLiteralExpression, + ): (node: T) => VisitResult { return node => saveStateAndInvoke(node, n => objectLiteralElementVisitorWorker(n, parent)); } - function objectLiteralElementVisitorWorker(node: Node, parent: ObjectLiteralExpression): VisitResult { + function objectLiteralElementVisitorWorker( + node: Node, + parent: ObjectLiteralExpression, + ): VisitResult { switch (node.kind) { case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: @@ -641,7 +659,6 @@ export function transformTypeScript(context: TransformationContext) { case SyntaxKind.LiteralType: // TypeScript type nodes are elided. // falls through - case SyntaxKind.IndexSignature: // TypeScript index signatures are elided. return undefined; @@ -784,28 +801,36 @@ export function transformTypeScript(context: TransformationContext) { } function visitSourceFile(node: SourceFile) { - const alwaysStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") && - !(isExternalModule(node) && moduleKind >= ModuleKind.ES2015) && - !isJsonSourceFile(node); + const alwaysStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") + && !(isExternalModule(node) && moduleKind >= ModuleKind.ES2015) + && !isJsonSourceFile(node); return factory.updateSourceFile( node, - visitLexicalEnvironment(node.statements, sourceElementVisitor, context, /*start*/ 0, alwaysStrict)); + visitLexicalEnvironment(node.statements, sourceElementVisitor, context, /*start*/ 0, alwaysStrict), + ); } function visitObjectLiteralExpression(node: ObjectLiteralExpression) { return factory.updateObjectLiteralExpression( node, - visitNodes(node.properties, getObjectLiteralElementVisitor(node), isObjectLiteralElementLike) + visitNodes(node.properties, getObjectLiteralElementVisitor(node), isObjectLiteralElementLike), ); } function getClassFacts(node: ClassDeclaration) { let facts = ClassFacts.None; - if (some(getProperties(node, /*requireInitializer*/ true, /*isStatic*/ true))) facts |= ClassFacts.HasStaticInitializedProperties; + if (some(getProperties(node, /*requireInitializer*/ true, /*isStatic*/ true))) { + facts |= ClassFacts.HasStaticInitializedProperties; + } const extendsClauseElement = getEffectiveBaseTypeNode(node); - if (extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword) facts |= ClassFacts.IsDerivedClass; - if (classOrConstructorParameterIsDecorated(legacyDecorators, node)) facts |= ClassFacts.HasClassOrConstructorParameterDecorators; + if ( + extendsClauseElement + && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword + ) facts |= ClassFacts.IsDerivedClass; + if (classOrConstructorParameterIsDecorated(legacyDecorators, node)) { + facts |= ClassFacts.HasClassOrConstructorParameterDecorators; + } if (childIsDecorated(legacyDecorators, node)) facts |= ClassFacts.HasMemberDecorators; if (isExportOfNamespace(node)) facts |= ClassFacts.IsExportOfNamespace; else if (isDefaultExternalModuleExport(node)) facts |= ClassFacts.IsDefaultExternalExport; @@ -826,19 +851,21 @@ export function transformTypeScript(context: TransformationContext) { function visitClassDeclaration(node: ClassDeclaration): VisitResult { const facts = getClassFacts(node); - const promoteToIIFE = languageVersion <= ScriptTarget.ES5 && - !!(facts & ClassFacts.MayNeedImmediatelyInvokedFunctionExpression); - - if (!isClassLikeDeclarationWithTypeScriptSyntax(node) && - !classOrConstructorParameterIsDecorated(legacyDecorators, node) && - !isExportOfNamespace(node)) { + const promoteToIIFE = languageVersion <= ScriptTarget.ES5 + && !!(facts & ClassFacts.MayNeedImmediatelyInvokedFunctionExpression); + + if ( + !isClassLikeDeclarationWithTypeScriptSyntax(node) + && !classOrConstructorParameterIsDecorated(legacyDecorators, node) + && !isExportOfNamespace(node) + ) { return factory.updateClassDeclaration( node, visitNodes(node.modifiers, modifierVisitor, isModifier), node.name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - visitNodes(node.members, getClassElementVisitor(node), isClassElement) + visitNodes(node.members, getClassElementVisitor(node), isClassElement), ); } @@ -846,29 +873,27 @@ export function transformTypeScript(context: TransformationContext) { context.startLexicalEnvironment(); } - const moveModifiers = - promoteToIIFE || - facts & ClassFacts.IsExportOfNamespace; + const moveModifiers = promoteToIIFE + || facts & ClassFacts.IsExportOfNamespace; // elide modifiers on the declaration if we are emitting an IIFE or the class is // a namespace export - let modifiers = moveModifiers ? - visitNodes(node.modifiers, modifierElidingVisitor, isModifierLike) : - visitNodes(node.modifiers, visitor, isModifierLike); + let modifiers = moveModifiers + ? visitNodes(node.modifiers, modifierElidingVisitor, isModifierLike) + : visitNodes(node.modifiers, visitor, isModifierLike); // inject metadata only if the class is decorated if (facts & ClassFacts.HasClassOrConstructorParameterDecorators) { modifiers = injectClassTypeMetadata(modifiers, node); } - const needsName = - moveModifiers && !node.name || - facts & ClassFacts.HasMemberDecorators || - facts & ClassFacts.HasStaticInitializedProperties; + const needsName = moveModifiers && !node.name + || facts & ClassFacts.HasMemberDecorators + || facts & ClassFacts.HasStaticInitializedProperties; - const name = needsName ? - node.name ?? factory.getGeneratedNameForNode(node) : - node.name; + const name = needsName + ? node.name ?? factory.getGeneratedNameForNode(node) + : node.name; // ${modifiers} class ${name} ${heritageClauses} { // ${members} @@ -879,7 +904,7 @@ export function transformTypeScript(context: TransformationContext) { name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - transformClassMembers(node) + transformClassMembers(node), ); // To better align with the old emitter, we should not emit a trailing source map @@ -905,7 +930,10 @@ export function transformTypeScript(context: TransformationContext) { // }(); // const statements: Statement[] = [classDeclaration]; - const closingBraceLocation = createTokenRange(skipTrivia(currentSourceFile.text, node.members.end), SyntaxKind.CloseBraceToken); + const closingBraceLocation = createTokenRange( + skipTrivia(currentSourceFile.text, node.members.end), + SyntaxKind.CloseBraceToken, + ); const localName = factory.getInternalName(node); // The following partially-emitted expression exists purely to align our sourcemap @@ -929,13 +957,13 @@ export function transformTypeScript(context: TransformationContext) { factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ false), /*exclamationToken*/ undefined, /*type*/ undefined, - iife + iife, ); setOriginalNode(varDecl, node); const varStatement = factory.createVariableStatement( /*modifiers*/ undefined, - factory.createVariableDeclarationList([varDecl], NodeFlags.Let) + factory.createVariableDeclarationList([varDecl], NodeFlags.Let), ); setOriginalNode(varStatement, node); setCommentRange(varStatement, node); @@ -951,19 +979,23 @@ export function transformTypeScript(context: TransformationContext) { if (facts & ClassFacts.IsExportOfNamespace) { return [ statement, - createExportMemberAssignmentStatement(node) + createExportMemberAssignmentStatement(node), ]; } if (facts & ClassFacts.IsDefaultExternalExport) { return [ statement, - factory.createExportDefault(factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true)) + factory.createExportDefault( + factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true), + ), ]; } if (facts & ClassFacts.IsNamedExternalExport) { return [ statement, - factory.createExternalModuleExport(factory.getDeclarationName(node, /*allowComments*/ false, /*allowSourceMaps*/ true)) + factory.createExternalModuleExport( + factory.getDeclarationName(node, /*allowComments*/ false, /*allowSourceMaps*/ true), + ), ]; } } @@ -983,7 +1015,7 @@ export function transformTypeScript(context: TransformationContext) { node.name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - transformClassMembers(node) + transformClassMembers(node), ); } @@ -997,8 +1029,11 @@ export function transformTypeScript(context: TransformationContext) { let newMembers: ClassElement[] | undefined; const constructor = getFirstConstructorWithBody(node); - const parametersWithPropertyAssignments = constructor && - filter(constructor.parameters, (p): p is ParameterPropertyDeclaration => isParameterPropertyDeclaration(p, constructor)); + const parametersWithPropertyAssignments = constructor + && filter( + constructor.parameters, + (p): p is ParameterPropertyDeclaration => isParameterPropertyDeclaration(p, constructor), + ); if (parametersWithPropertyAssignments) { for (const parameter of parametersWithPropertyAssignments) { @@ -1007,7 +1042,8 @@ export function transformTypeScript(context: TransformationContext) { parameter.name, /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined); + /*initializer*/ undefined, + ); setOriginalNode(parameterProperty, parameter); newMembers = append(newMembers, parameterProperty); } @@ -1035,8 +1071,14 @@ export function transformTypeScript(context: TransformationContext) { return modifiers; } - function injectClassElementTypeMetadata(modifiers: NodeArray | undefined, node: ClassElement, container: ClassLikeDeclaration | ObjectLiteralExpression) { - if (isClassLike(container) && classElementOrClassElementParameterIsDecorated(legacyDecorators, node, container)) { + function injectClassElementTypeMetadata( + modifiers: NodeArray | undefined, + node: ClassElement, + container: ClassLikeDeclaration | ObjectLiteralExpression, + ) { + if ( + isClassLike(container) && classElementOrClassElementParameterIsDecorated(legacyDecorators, node, container) + ) { const metadata = getTypeMetadata(node, container); if (some(metadata)) { const modifiersArray: ModifierLike[] = []; @@ -1057,24 +1099,40 @@ export function transformTypeScript(context: TransformationContext) { function getTypeMetadata(node: Declaration, container: ClassLikeDeclaration) { // Decorator metadata is not yet supported for ES decorators. if (!legacyDecorators) return undefined; - return USE_NEW_TYPE_METADATA_FORMAT ? - getNewTypeMetadata(node, container) : - getOldTypeMetadata(node, container); + return USE_NEW_TYPE_METADATA_FORMAT + ? getNewTypeMetadata(node, container) + : getOldTypeMetadata(node, container); } function getOldTypeMetadata(node: Declaration, container: ClassLikeDeclaration) { if (typeSerializer) { let decorators: Decorator[] | undefined; if (shouldAddTypeMetadata(node)) { - const typeMetadata = emitHelpers().createMetadataHelper("design:type", typeSerializer.serializeTypeOfNode({ currentLexicalScope, currentNameScope: container }, node)); + const typeMetadata = emitHelpers().createMetadataHelper( + "design:type", + typeSerializer.serializeTypeOfNode({ currentLexicalScope, currentNameScope: container }, node), + ); decorators = append(decorators, factory.createDecorator(typeMetadata)); } if (shouldAddParamTypesMetadata(node)) { - const paramTypesMetadata = emitHelpers().createMetadataHelper("design:paramtypes", typeSerializer.serializeParameterTypesOfNode({ currentLexicalScope, currentNameScope: container }, node, container)); + const paramTypesMetadata = emitHelpers().createMetadataHelper( + "design:paramtypes", + typeSerializer.serializeParameterTypesOfNode( + { currentLexicalScope, currentNameScope: container }, + node, + container, + ), + ); decorators = append(decorators, factory.createDecorator(paramTypesMetadata)); } if (shouldAddReturnTypeMetadata(node)) { - const returnTypeMetadata = emitHelpers().createMetadataHelper("design:returntype", typeSerializer.serializeReturnTypeOfNode({ currentLexicalScope, currentNameScope: container }, node)); + const returnTypeMetadata = emitHelpers().createMetadataHelper( + "design:returntype", + typeSerializer.serializeReturnTypeOfNode( + { currentLexicalScope, currentNameScope: container }, + node, + ), + ); decorators = append(decorators, factory.createDecorator(returnTypeMetadata)); } return decorators; @@ -1085,19 +1143,59 @@ export function transformTypeScript(context: TransformationContext) { if (typeSerializer) { let properties: ObjectLiteralElementLike[] | undefined; if (shouldAddTypeMetadata(node)) { - const typeProperty = factory.createPropertyAssignment("type", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), typeSerializer.serializeTypeOfNode({ currentLexicalScope, currentNameScope: container }, node))); + const typeProperty = factory.createPropertyAssignment( + "type", + factory.createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, + [], + /*type*/ undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + typeSerializer.serializeTypeOfNode({ currentLexicalScope, currentNameScope: container }, node), + ), + ); properties = append(properties, typeProperty); } if (shouldAddParamTypesMetadata(node)) { - const paramTypeProperty = factory.createPropertyAssignment("paramTypes", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), typeSerializer.serializeParameterTypesOfNode({ currentLexicalScope, currentNameScope: container }, node, container))); + const paramTypeProperty = factory.createPropertyAssignment( + "paramTypes", + factory.createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, + [], + /*type*/ undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + typeSerializer.serializeParameterTypesOfNode( + { currentLexicalScope, currentNameScope: container }, + node, + container, + ), + ), + ); properties = append(properties, paramTypeProperty); } if (shouldAddReturnTypeMetadata(node)) { - const returnTypeProperty = factory.createPropertyAssignment("returnType", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), typeSerializer.serializeReturnTypeOfNode({ currentLexicalScope, currentNameScope: container }, node))); + const returnTypeProperty = factory.createPropertyAssignment( + "returnType", + factory.createArrowFunction( + /*modifiers*/ undefined, + /*typeParameters*/ undefined, + [], + /*type*/ undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + typeSerializer.serializeReturnTypeOfNode( + { currentLexicalScope, currentNameScope: container }, + node, + ), + ), + ); properties = append(properties, returnTypeProperty); } if (properties) { - const typeInfoMetadata = emitHelpers().createMetadataHelper("design:typeinfo", factory.createObjectLiteralExpression(properties, /*multiLine*/ true)); + const typeInfoMetadata = emitHelpers().createMetadataHelper( + "design:typeinfo", + factory.createObjectLiteralExpression(properties, /*multiLine*/ true), + ); return [factory.createDecorator(typeInfoMetadata)]; } } @@ -1110,7 +1208,9 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to test. */ - function shouldAddTypeMetadata(node: Declaration): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration { + function shouldAddTypeMetadata( + node: Declaration, + ): node is MethodDeclaration | AccessorDeclaration | PropertyDeclaration { const kind = node.kind; return kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.GetAccessor @@ -1136,7 +1236,9 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to test. */ - function shouldAddParamTypesMetadata(node: Declaration): node is ClassLikeDeclaration & { _hasConstructorBrand: never } | MethodDeclaration | AccessorDeclaration { + function shouldAddParamTypesMetadata( + node: Declaration, + ): node is ClassLikeDeclaration & { _hasConstructorBrand: never; } | MethodDeclaration | AccessorDeclaration { switch (node.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: @@ -1155,7 +1257,10 @@ export function transformTypeScript(context: TransformationContext) { * * @param member The member whose name should be converted into an expression. */ - function getExpressionForPropertyName(member: ClassElement | EnumMember, generateNameForComputedPropertyName: boolean): Expression { + function getExpressionForPropertyName( + member: ClassElement | EnumMember, + generateNameForComputedPropertyName: boolean, + ): Expression { const name = member.name!; if (isPrivateIdentifier(name)) { return factory.createIdentifier(""); @@ -1186,7 +1291,11 @@ export function transformTypeScript(context: TransformationContext) { // The names are used more than once when: // - the property is non-static and its initializer is moved to the constructor (when there are parameter property assignments). // - the property has a decorator. - if (isComputedPropertyName(name) && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || hasDecorators(member) && legacyDecorators)) { + if ( + isComputedPropertyName(name) + && ((!hasStaticModifier(member) && currentClassHasParameterProperties) + || hasDecorators(member) && legacyDecorators) + ) { const expression = visitNode(name.expression, visitor, isExpression); Debug.assert(expression); const innerExpression = skipPartiallyEmittedExpressions(expression); @@ -1228,7 +1337,7 @@ export function transformTypeScript(context: TransformationContext) { return factory.updateExpressionWithTypeArguments( node, Debug.checkDefined(visitNode(node.expression, visitor, isLeftHandSideExpression)), - /*typeArguments*/ undefined + /*typeArguments*/ undefined, ); } @@ -1238,7 +1347,9 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The declaration node. */ - function shouldEmitFunctionLikeDeclaration(node: T): node is T & { body: NonNullable } { + function shouldEmitFunctionLikeDeclaration( + node: T, + ): node is T & { body: NonNullable; } { return !nodeIsMissing(node.body); } @@ -1248,10 +1359,10 @@ export function transformTypeScript(context: TransformationContext) { return undefined; } - let modifiers = isClassLike(parent) ? !isAmbient ? - visitNodes(node.modifiers, visitor, isModifierLike) : - visitNodes(node.modifiers, modifierElidingVisitor, isModifierLike) : - visitNodes(node.modifiers, decoratorElidingVisitor, isModifierLike); + let modifiers = isClassLike(parent) ? !isAmbient + ? visitNodes(node.modifiers, visitor, isModifierLike) + : visitNodes(node.modifiers, modifierElidingVisitor, isModifierLike) + : visitNodes(node.modifiers, decoratorElidingVisitor, isModifierLike); modifiers = injectClassElementTypeMetadata(modifiers, node, parent); @@ -1263,7 +1374,7 @@ export function transformTypeScript(context: TransformationContext) { Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined + /*initializer*/ undefined, ); } @@ -1273,7 +1384,7 @@ export function transformTypeScript(context: TransformationContext) { visitPropertyNameOfClassElement(node), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression) + visitNode(node.initializer, visitor, isExpression), ); } @@ -1286,14 +1397,24 @@ export function transformTypeScript(context: TransformationContext) { node, /*modifiers*/ undefined, visitParameterList(node.parameters, visitor, context), - transformConstructorBody(node.body, node) + transformConstructorBody(node.body, node), ); } - function transformConstructorBodyWorker(statementsOut: Statement[], statementsIn: NodeArray, statementOffset: number, superPath: readonly number[], superPathDepth: number, initializerStatements: readonly Statement[]) { + function transformConstructorBodyWorker( + statementsOut: Statement[], + statementsIn: NodeArray, + statementOffset: number, + superPath: readonly number[], + superPathDepth: number, + initializerStatements: readonly Statement[], + ) { const superStatementIndex = superPath[superPathDepth]; const superStatement = statementsIn[superStatementIndex]; - addRange(statementsOut, visitNodes(statementsIn, visitor, isStatement, statementOffset, superStatementIndex - statementOffset)); + addRange( + statementsOut, + visitNodes(statementsIn, visitor, isStatement, statementOffset, superStatementIndex - statementOffset), + ); if (isTryStatement(superStatement)) { const tryBlockStatements: Statement[] = []; @@ -1303,7 +1424,8 @@ export function transformTypeScript(context: TransformationContext) { /*statementOffset*/ 0, superPath, superPathDepth + 1, - initializerStatements); + initializerStatements, + ); const tryBlockStatementsArray = factory.createNodeArray(tryBlockStatements); setTextRange(tryBlockStatementsArray, superStatement.tryBlock.statements); @@ -1312,7 +1434,8 @@ export function transformTypeScript(context: TransformationContext) { superStatement, factory.updateBlock(superStatement.tryBlock, tryBlockStatements), visitNode(superStatement.catchClause, visitor, isCatchClause), - visitNode(superStatement.finallyBlock, visitor, isBlock))); + visitNode(superStatement.finallyBlock, visitor, isBlock), + )); } else { addRange(statementsOut, visitNodes(statementsIn, visitor, isStatement, superStatementIndex, 1)); @@ -1322,8 +1445,10 @@ export function transformTypeScript(context: TransformationContext) { } function transformConstructorBody(body: Block, constructor: ConstructorDeclaration) { - const parametersWithPropertyAssignments = constructor && - filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor)) as readonly ParameterPropertyDeclaration[] | undefined; + const parametersWithPropertyAssignments = constructor + && filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor)) as + | readonly ParameterPropertyDeclaration[] + | undefined; if (!some(parametersWithPropertyAssignments)) { return visitFunctionBody(body, visitor, context); } @@ -1332,7 +1457,12 @@ export function transformTypeScript(context: TransformationContext) { resumeLexicalEnvironment(); - const prologueStatementCount = factory.copyPrologue(body.statements, statements, /*ensureUseStrict*/ false, visitor); + const prologueStatementCount = factory.copyPrologue( + body.statements, + statements, + /*ensureUseStrict*/ false, + visitor, + ); const superPath = findSuperStatementIndexPath(body.statements, prologueStatementCount); // Transform parameters into property assignments. Transforms this: @@ -1347,9 +1477,19 @@ export function transformTypeScript(context: TransformationContext) { // this.y = y; // } // - const parameterPropertyAssignments = mapDefined(parametersWithPropertyAssignments, transformParameterWithPropertyAssignment); + const parameterPropertyAssignments = mapDefined( + parametersWithPropertyAssignments, + transformParameterWithPropertyAssignment, + ); if (superPath.length) { - transformConstructorBodyWorker(statements, body.statements, prologueStatementCount, superPath, /*superPathDepth*/ 0, parameterPropertyAssignments); + transformConstructorBodyWorker( + statements, + body.statements, + prologueStatementCount, + superPath, + /*superPathDepth*/ 0, + parameterPropertyAssignments, + ); } else { addRange(statements, parameterPropertyAssignments); @@ -1358,7 +1498,10 @@ export function transformTypeScript(context: TransformationContext) { // End the lexical environment. statements = factory.mergeLexicalEnvironment(statements, endLexicalEnvironment()); - const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), body.statements), /*multiLine*/ true); + const block = factory.createBlock( + setTextRange(factory.createNodeArray(statements), body.statements), + /*multiLine*/ true, + ); setTextRange(block, /*location*/ body); setOriginalNode(block, body); return block; @@ -1392,18 +1535,18 @@ export function transformTypeScript(context: TransformationContext) { setTextRange( factory.createPropertyAccessExpression( factory.createThis(), - propertyName + propertyName, ), - node.name + node.name, ), - localName - ) + localName, + ), ), - node + node, ), - moveRangePos(node, -1) - ) - ) + moveRangePos(node, -1), + ), + ), ); } @@ -1416,9 +1559,9 @@ export function transformTypeScript(context: TransformationContext) { return undefined; } - let modifiers = isClassLike(parent) ? - visitNodes(node.modifiers, visitor, isModifierLike) : - visitNodes(node.modifiers, decoratorElidingVisitor, isModifierLike); + let modifiers = isClassLike(parent) + ? visitNodes(node.modifiers, visitor, isModifierLike) + : visitNodes(node.modifiers, decoratorElidingVisitor, isModifierLike); modifiers = injectClassElementTypeMetadata(modifiers, node, parent); @@ -1431,7 +1574,7 @@ export function transformTypeScript(context: TransformationContext) { /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - visitFunctionBody(node.body, visitor, context) + visitFunctionBody(node.body, visitor, context), ); } @@ -1454,9 +1597,9 @@ export function transformTypeScript(context: TransformationContext) { return undefined; } - let modifiers = isClassLike(parent) ? - visitNodes(node.modifiers, visitor, isModifierLike) : - visitNodes(node.modifiers, decoratorElidingVisitor, isModifierLike); + let modifiers = isClassLike(parent) + ? visitNodes(node.modifiers, visitor, isModifierLike) + : visitNodes(node.modifiers, decoratorElidingVisitor, isModifierLike); modifiers = injectClassElementTypeMetadata(modifiers, node, parent); @@ -1466,7 +1609,7 @@ export function transformTypeScript(context: TransformationContext) { visitPropertyNameOfClassElement(node), visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - visitFunctionBody(node.body, visitor, context) || factory.createBlock([]) + visitFunctionBody(node.body, visitor, context) || factory.createBlock([]), ); } @@ -1479,9 +1622,9 @@ export function transformTypeScript(context: TransformationContext) { return undefined; } - let modifiers = isClassLike(parent) ? - visitNodes(node.modifiers, visitor, isModifierLike) : - visitNodes(node.modifiers, decoratorElidingVisitor, isModifierLike); + let modifiers = isClassLike(parent) + ? visitNodes(node.modifiers, visitor, isModifierLike) + : visitNodes(node.modifiers, decoratorElidingVisitor, isModifierLike); modifiers = injectClassElementTypeMetadata(modifiers, node, parent); @@ -1490,7 +1633,7 @@ export function transformTypeScript(context: TransformationContext) { modifiers, visitPropertyNameOfClassElement(node), visitParameterList(node.parameters, visitor, context), - visitFunctionBody(node.body, visitor, context) || factory.createBlock([]) + visitFunctionBody(node.body, visitor, context) || factory.createBlock([]), ); } @@ -1506,7 +1649,7 @@ export function transformTypeScript(context: TransformationContext) { /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - visitFunctionBody(node.body, visitor, context) || factory.createBlock([]) + visitFunctionBody(node.body, visitor, context) || factory.createBlock([]), ); if (isExportOfNamespace(node)) { const statements: Statement[] = [updated]; @@ -1528,7 +1671,7 @@ export function transformTypeScript(context: TransformationContext) { /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - visitFunctionBody(node.body, visitor, context) || factory.createBlock([]) + visitFunctionBody(node.body, visitor, context) || factory.createBlock([]), ); return updated; } @@ -1558,7 +1701,7 @@ export function transformTypeScript(context: TransformationContext) { Debug.checkDefined(visitNode(node.name, visitor, isBindingName)), /*questionToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression) + visitNode(node.initializer, visitor, isExpression), ); if (updated !== node) { // While we emit the source map for the node after skipping decorators and modifiers, @@ -1582,10 +1725,10 @@ export function transformTypeScript(context: TransformationContext) { return setTextRange( factory.createExpressionStatement( factory.inlineExpressions( - map(variables, transformInitializedVariable) - ) + map(variables, transformInitializedVariable), + ), ), - node + node, ); } else { @@ -1602,16 +1745,16 @@ export function transformTypeScript(context: TransformationContext) { context, FlattenLevel.All, /*needsValue*/ false, - createNamespaceExportExpression + createNamespaceExportExpression, ); } else { return setTextRange( factory.createAssignment( getNamespaceMemberNameWithSourceMapsAndWithoutComments(name), - Debug.checkDefined(visitNode(node.initializer, visitor, isExpression)) + Debug.checkDefined(visitNode(node.initializer, visitor, isExpression)), ), - /*location*/ node + /*location*/ node, ); } } @@ -1622,7 +1765,8 @@ export function transformTypeScript(context: TransformationContext) { Debug.checkDefined(visitNode(node.name, visitor, isBindingName)), /*exclamationToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor, isExpression)); + visitNode(node.initializer, visitor, isExpression), + ); if (node.type) { setTypeNode(updated.name, node.type); } @@ -1683,7 +1827,8 @@ export function transformTypeScript(context: TransformationContext) { node, Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), /*typeArguments*/ undefined, - visitNodes(node.arguments, visitor, isExpression)); + visitNodes(node.arguments, visitor, isExpression), + ); } function visitNewExpression(node: NewExpression) { @@ -1691,7 +1836,8 @@ export function transformTypeScript(context: TransformationContext) { node, Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), /*typeArguments*/ undefined, - visitNodes(node.arguments, visitor, isExpression)); + visitNodes(node.arguments, visitor, isExpression), + ); } function visitTaggedTemplateExpression(node: TaggedTemplateExpression) { @@ -1699,7 +1845,8 @@ export function transformTypeScript(context: TransformationContext) { node, Debug.checkDefined(visitNode(node.tag, visitor, isExpression)), /*typeArguments*/ undefined, - Debug.checkDefined(visitNode(node.template, visitor, isTemplateLiteral))); + Debug.checkDefined(visitNode(node.template, visitor, isTemplateLiteral)), + ); } function visitJsxSelfClosingElement(node: JsxSelfClosingElement) { @@ -1707,7 +1854,8 @@ export function transformTypeScript(context: TransformationContext) { node, Debug.checkDefined(visitNode(node.tagName, visitor, isJsxTagNameExpression)), /*typeArguments*/ undefined, - Debug.checkDefined(visitNode(node.attributes, visitor, isJsxAttributes))); + Debug.checkDefined(visitNode(node.attributes, visitor, isJsxAttributes)), + ); } function visitJsxJsxOpeningElement(node: JsxOpeningElement) { @@ -1715,7 +1863,8 @@ export function transformTypeScript(context: TransformationContext) { node, Debug.checkDefined(visitNode(node.tagName, visitor, isJsxTagNameExpression)), /*typeArguments*/ undefined, - Debug.checkDefined(visitNode(node.attributes, visitor, isJsxAttributes))); + Debug.checkDefined(visitNode(node.attributes, visitor, isJsxAttributes)), + ); } /** @@ -1765,19 +1914,23 @@ export function transformTypeScript(context: TransformationContext) { // `exportName` is the expression used within this node's container for any exported references. const exportName = isExportOfNamespace(node) - ? factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true) + ? factory.getExternalModuleOrNamespaceExportName( + currentNamespaceContainerName, + node, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ) : factory.getDeclarationName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); // x || (x = {}) // exports.x || (exports.x = {}) - let moduleArg = - factory.createLogicalOr( + let moduleArg = factory.createLogicalOr( + exportName, + factory.createAssignment( exportName, - factory.createAssignment( - exportName, - factory.createObjectLiteralExpression() - ) - ); + factory.createObjectLiteralExpression(), + ), + ); if (isExportOfNamespace(node)) { // `localName` is the expression used within this node's containing scope for any local references. @@ -1798,13 +1951,17 @@ export function transformTypeScript(context: TransformationContext) { /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)], + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + parameterName, + )], /*type*/ undefined, - transformEnumBody(node, containerName) + transformEnumBody(node, containerName), ), /*typeArguments*/ undefined, - [moduleArg] - ) + [moduleArg], + ), ); setOriginalNode(enumStatement, node); @@ -1838,7 +1995,7 @@ export function transformTypeScript(context: TransformationContext) { currentNamespaceContainerName = savedCurrentNamespaceLocalName; return factory.createBlock( setTextRange(factory.createNodeArray(statements), /*location*/ node.members), - /*multiLine*/ true + /*multiLine*/ true, ); } @@ -1856,27 +2013,27 @@ export function transformTypeScript(context: TransformationContext) { const innerAssignment = factory.createAssignment( factory.createElementAccessExpression( currentNamespaceContainerName, - name + name, ), - valueExpression + valueExpression, ); - const outerAssignment = valueExpression.kind === SyntaxKind.StringLiteral ? - innerAssignment : - factory.createAssignment( + const outerAssignment = valueExpression.kind === SyntaxKind.StringLiteral + ? innerAssignment + : factory.createAssignment( factory.createElementAccessExpression( currentNamespaceContainerName, - innerAssignment + innerAssignment, ), - name + name, ); return setTextRange( factory.createExpressionStatement( setTextRange( outerAssignment, - member - ) + member, + ), ), - member + member, ); } @@ -1888,9 +2045,13 @@ export function transformTypeScript(context: TransformationContext) { function transformEnumMemberDeclarationValue(member: EnumMember): Expression { const value = resolver.getConstantValue(member); if (value !== undefined) { - return typeof value === "string" ? factory.createStringLiteral(value) : - value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(value))) : - factory.createNumericLiteral(value); + return typeof value === "string" ? factory.createStringLiteral(value) + : value < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(Math.abs(value)), + ) + : factory.createNumericLiteral(value); } else { enableSubstitutionForNonQualifiedEnumMembers(); @@ -1921,7 +2082,9 @@ export function transformTypeScript(context: TransformationContext) { * Records that a declaration was emitted in the current scope, if it was the first * declaration for the provided symbol. */ - function recordEmittedDeclarationInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration) { + function recordEmittedDeclarationInScope( + node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration, + ) { if (!currentScopeFirstDeclarationsOfName) { currentScopeFirstDeclarationsOfName = new Map(); } @@ -1944,7 +2107,9 @@ export function transformTypeScript(context: TransformationContext) { return true; } - function declaredNameInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration): __String { + function declaredNameInScope( + node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration, + ): __String { Debug.assertNode(node.name, isIdentifier); return node.name.escapedText; } @@ -1956,11 +2121,13 @@ export function transformTypeScript(context: TransformationContext) { // Emit a variable statement for the module. We emit top-level enums as a `var` // declaration to avoid static errors in global scripts scripts due to redeclaration. // enums in any other scope are emitted as a `let` declaration. - const varDecl = factory.createVariableDeclaration(factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true)); + const varDecl = factory.createVariableDeclaration( + factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true), + ); const varFlags = currentLexicalScope.kind === SyntaxKind.SourceFile ? NodeFlags.None : NodeFlags.Let; const statement = factory.createVariableStatement( visitNodes(node.modifiers, modifierVisitor, isModifier), - factory.createVariableDeclarationList([varDecl], varFlags) + factory.createVariableDeclarationList([varDecl], varFlags), ); setOriginalNode(varDecl, node); @@ -2048,19 +2215,23 @@ export function transformTypeScript(context: TransformationContext) { // `exportName` is the expression used within this node's container for any exported references. const exportName = isExportOfNamespace(node) - ? factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true) + ? factory.getExternalModuleOrNamespaceExportName( + currentNamespaceContainerName, + node, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ) : factory.getDeclarationName(node, /*allowComments*/ false, /*allowSourceMaps*/ true); // x || (x = {}) // exports.x || (exports.x = {}) - let moduleArg = - factory.createLogicalOr( + let moduleArg = factory.createLogicalOr( + exportName, + factory.createAssignment( exportName, - factory.createAssignment( - exportName, - factory.createObjectLiteralExpression() - ) - ); + factory.createObjectLiteralExpression(), + ), + ); if (isExportOfNamespace(node)) { // `localName` is the expression used within this node's containing scope for any local references. @@ -2080,13 +2251,17 @@ export function transformTypeScript(context: TransformationContext) { /*asteriskToken*/ undefined, /*name*/ undefined, /*typeParameters*/ undefined, - [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)], + [factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + parameterName, + )], /*type*/ undefined, - transformModuleBody(node, containerName) + transformModuleBody(node, containerName), ), /*typeArguments*/ undefined, - [moduleArg] - ) + [moduleArg], + ), ); setOriginalNode(moduleStatement, node); @@ -2122,7 +2297,10 @@ export function transformTypeScript(context: TransformationContext) { let blockLocation: TextRange | undefined; if (node.body) { if (node.body.kind === SyntaxKind.ModuleBlock) { - saveStateAndInvoke(node.body, body => addRange(statements, visitNodes(body.statements, namespaceElementVisitor, isStatement))); + saveStateAndInvoke( + node.body, + body => addRange(statements, visitNodes(body.statements, namespaceElementVisitor, isStatement)), + ); statementsLocation = node.body.statements; blockLocation = node.body; } @@ -2150,9 +2328,9 @@ export function transformTypeScript(context: TransformationContext) { const block = factory.createBlock( setTextRange( factory.createNodeArray(statements), - /*location*/ statementsLocation + /*location*/ statementsLocation, ), - /*multiLine*/ true + /*multiLine*/ true, ); setTextRange(block, blockLocation); @@ -2182,9 +2360,13 @@ export function transformTypeScript(context: TransformationContext) { return block; } - function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration | undefined { + function getInnerMostModuleDeclarationFromDottedModule( + moduleDeclaration: ModuleDeclaration, + ): ModuleDeclaration | undefined { if (moduleDeclaration.body!.kind === SyntaxKind.ModuleDeclaration) { - const recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration.body as ModuleDeclaration); + const recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule( + moduleDeclaration.body as ModuleDeclaration, + ); return recursiveInnerModule || moduleDeclaration.body as ModuleDeclaration; } } @@ -2207,15 +2389,16 @@ export function transformTypeScript(context: TransformationContext) { // Elide the declaration if the import clause was elided. const importClause = visitNode(node.importClause, visitImportClause, isImportClause); - return importClause || - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error + return importClause + || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve + || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error ? factory.updateImportDeclaration( node, /*modifiers*/ undefined, importClause, node.moduleSpecifier, - node.assertClause) + node.assertClause, + ) : undefined; } @@ -2229,7 +2412,8 @@ export function transformTypeScript(context: TransformationContext) { // Elide the import clause if we elide both its name and its named bindings. const name = shouldEmitAliasDeclaration(node) ? node.name : undefined; const namedBindings = visitNode(node.namedBindings, visitNamedImportBindings, isNamedImportBindings); - return (name || namedBindings) ? factory.updateImportClause(node, /*isTypeOnly*/ false, name, namedBindings) : undefined; + return (name || namedBindings) ? factory.updateImportClause(node, /*isTypeOnly*/ false, name, namedBindings) + : undefined; } /** @@ -2245,8 +2429,9 @@ export function transformTypeScript(context: TransformationContext) { else { // Elide named imports if all of its import specifiers are elided and settings allow. const allowEmpty = compilerOptions.verbatimModuleSyntax || compilerOptions.preserveValueImports && ( - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error); + compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve + || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error + ); const elements = visitNodes(node.elements, visitImportSpecifier, isImportSpecifier); return allowEmpty || some(elements) ? factory.updateNamedImports(node, elements) : undefined; } @@ -2293,12 +2478,14 @@ export function transformTypeScript(context: TransformationContext) { // Elide the export declaration if all of its named exports are elided. const allowEmpty = compilerOptions.verbatimModuleSyntax || !!node.moduleSpecifier && ( - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || - compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error); + compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve + || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error + ); const exportClause = visitNode( node.exportClause, (bindings: NamedExportBindings) => visitNamedExportBindings(bindings, allowEmpty), - isNamedExportBindings); + isNamedExportBindings, + ); return exportClause ? factory.updateExportDeclaration( @@ -2307,7 +2494,8 @@ export function transformTypeScript(context: TransformationContext) { node.isTypeOnly, exportClause, node.moduleSpecifier, - node.assertClause) + node.assertClause, + ) : undefined; } @@ -2327,7 +2515,10 @@ export function transformTypeScript(context: TransformationContext) { return factory.updateNamespaceExport(node, Debug.checkDefined(visitNode(node.name, visitor, isIdentifier))); } - function visitNamedExportBindings(node: NamedExportBindings, allowEmpty: boolean): VisitResult | undefined { + function visitNamedExportBindings( + node: NamedExportBindings, + allowEmpty: boolean, + ): VisitResult | undefined { return isNamespaceExport(node) ? visitNamespaceExports(node) : visitNamedExports(node, allowEmpty); } @@ -2338,7 +2529,8 @@ export function transformTypeScript(context: TransformationContext) { */ function visitExportSpecifier(node: ExportSpecifier): VisitResult | undefined { // Elide an export specifier if it does not reference a value. - return !node.isTypeOnly && (compilerOptions.verbatimModuleSyntax || resolver.isValueAliasDeclaration(node)) ? node : undefined; + return !node.isTypeOnly && (compilerOptions.verbatimModuleSyntax || resolver.isValueAliasDeclaration(node)) + ? node : undefined; } /** @@ -2376,7 +2568,7 @@ export function transformTypeScript(context: TransformationContext) { /*modifiers*/ undefined, /*importClause*/ undefined, node.moduleReference.expression, - /*assertClause*/ undefined + /*assertClause*/ undefined, ), node, ), @@ -2407,15 +2599,15 @@ export function transformTypeScript(context: TransformationContext) { node.name, /*exclamationToken*/ undefined, /*type*/ undefined, - moduleReference + moduleReference, ), - node - ) - ]) + node, + ), + ]), ), - node + node, ), - node + node, ); } else { @@ -2424,9 +2616,9 @@ export function transformTypeScript(context: TransformationContext) { createNamespaceExport( node.name, moduleReference, - node + node, ), - node + node, ); } } @@ -2471,8 +2663,13 @@ export function transformTypeScript(context: TransformationContext) { function createExportMemberAssignmentStatement(node: ClassDeclaration | FunctionDeclaration) { const expression = factory.createAssignment( - factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true), - factory.getLocalName(node) + factory.getExternalModuleOrNamespaceExportName( + currentNamespaceContainerName, + node, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ), + factory.getLocalName(node), ); setSourceMapRange(expression, createRange(node.name ? node.name.pos : node.pos, node.end)); @@ -2489,20 +2686,33 @@ export function transformTypeScript(context: TransformationContext) { return setTextRange( factory.createExpressionStatement( factory.createAssignment( - factory.getNamespaceMemberName(currentNamespaceContainerName, exportName, /*allowComments*/ false, /*allowSourceMaps*/ true), - exportValue - ) + factory.getNamespaceMemberName( + currentNamespaceContainerName, + exportName, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ), + exportValue, + ), ), - location + location, ); } function createNamespaceExportExpression(exportName: Identifier, exportValue: Expression, location?: TextRange) { - return setTextRange(factory.createAssignment(getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), exportValue), location); + return setTextRange( + factory.createAssignment(getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), exportValue), + location, + ); } function getNamespaceMemberNameWithSourceMapsAndWithoutComments(name: Identifier) { - return factory.getNamespaceMemberName(currentNamespaceContainerName, name, /*allowComments*/ false, /*allowSourceMaps*/ true); + return factory.getNamespaceMemberName( + currentNamespaceContainerName, + name, + /*allowComments*/ false, + /*allowSourceMaps*/ true, + ); } /** @@ -2566,11 +2776,16 @@ export function transformTypeScript(context: TransformationContext) { currentSourceFile = node; } - if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) { + if ( + enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node) + ) { applicableSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports; } - if (enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && isTransformedEnumDeclaration(node)) { + if ( + enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers + && isTransformedEnumDeclaration(node) + ) { applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers; } @@ -2640,13 +2855,14 @@ export function transformTypeScript(context: TransformationContext) { // an identifier that is exported from a merged namespace. const container = resolver.getReferencedExportContainer(node, /*prefixLocals*/ false); if (container && container.kind !== SyntaxKind.SourceFile) { - const substitute = - (applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) || - (applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration); + const substitute = (applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports + && container.kind === SyntaxKind.ModuleDeclaration) + || (applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers + && container.kind === SyntaxKind.EnumDeclaration); if (substitute) { return setTextRange( factory.createPropertyAccessExpression(factory.getGeneratedNameForNode(container), node), - /*location*/ node + /*location*/ node, ); } } @@ -2672,13 +2888,21 @@ export function transformTypeScript(context: TransformationContext) { if (constantValue !== undefined) { // track the constant value on the node for the printer in mayNeedDotDotForPropertyAccess setConstantValue(node, constantValue); - const substitute = typeof constantValue === "string" ? factory.createStringLiteral(constantValue) : - constantValue < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(Math.abs(constantValue))) : - factory.createNumericLiteral(constantValue); + const substitute = typeof constantValue === "string" ? factory.createStringLiteral(constantValue) + : constantValue < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(Math.abs(constantValue)), + ) + : factory.createNumericLiteral(constantValue); if (!compilerOptions.removeComments) { const originalNode = getOriginalNode(node, isAccessExpression); - addSyntheticTrailingComment(substitute, SyntaxKind.MultiLineCommentTrivia, ` ${safeMultiLineComment(getTextOfNode(originalNode))} `); + addSyntheticTrailingComment( + substitute, + SyntaxKind.MultiLineCommentTrivia, + ` ${safeMultiLineComment(getTextOfNode(originalNode))} `, + ); } return substitute; } @@ -2690,12 +2914,13 @@ export function transformTypeScript(context: TransformationContext) { return undefined; } - return isPropertyAccessExpression(node) || isElementAccessExpression(node) ? resolver.getConstantValue(node) : undefined; + return isPropertyAccessExpression(node) || isElementAccessExpression(node) ? resolver.getConstantValue(node) + : undefined; } function shouldEmitAliasDeclaration(node: Node): boolean { - return compilerOptions.verbatimModuleSyntax || isInJSFile(node) || - (compilerOptions.preserveValueImports + return compilerOptions.verbatimModuleSyntax || isInJSFile(node) + || (compilerOptions.preserveValueImports ? resolver.isValueAliasDeclaration(node) : resolver.isReferencedAliasDeclaration(node)); } diff --git a/src/compiler/transformers/typeSerializer.ts b/src/compiler/transformers/typeSerializer.ts index 831a581b8258b..9cf29a8fca73b 100644 --- a/src/compiler/transformers/typeSerializer.ts +++ b/src/compiler/transformers/typeSerializer.ts @@ -72,20 +72,15 @@ import { /** @internal */ export type SerializedEntityName = | Identifier // Globals (i.e., `String`, `Number`, etc.) - // Globals (i.e., `String`, `Number`, etc.) | PropertyAccessEntityNameExpression // `A.B` - // `A.B` - ; - +; /** @internal */ export type SerializedTypeNode = | SerializedEntityName | ConditionalExpression // Type Reference or Global fallback - // Type Reference or Global fallback | VoidExpression // `void 0` used for null/undefined/never - // `void 0` used for null/undefined/never - ; +; /** @internal */ export interface RuntimeTypeSerializerContext { @@ -120,12 +115,24 @@ export interface RuntimeTypeSerializer { * Serializes the type of a node for use with decorator type metadata. * @param node The node that should have its type serialized. */ - serializeTypeOfNode(serializerContext: RuntimeTypeSerializerContext, node: PropertyDeclaration | ParameterDeclaration | AccessorDeclaration | ClassLikeDeclaration | MethodDeclaration): Expression; + serializeTypeOfNode( + serializerContext: RuntimeTypeSerializerContext, + node: + | PropertyDeclaration + | ParameterDeclaration + | AccessorDeclaration + | ClassLikeDeclaration + | MethodDeclaration, + ): Expression; /** * Serializes the types of the parameters of a node for use with decorator type metadata. * @param node The node that should have its parameter types serialized. */ - serializeParameterTypesOfNode(serializerContext: RuntimeTypeSerializerContext, node: Node, container: ClassLikeDeclaration): ArrayLiteralExpression; + serializeParameterTypesOfNode( + serializerContext: RuntimeTypeSerializerContext, + node: Node, + container: ClassLikeDeclaration, + ): ArrayLiteralExpression; /** * Serializes the return type of a node for use with decorator type metadata. * @param node The node that should have its return type serialized. @@ -137,7 +144,7 @@ export interface RuntimeTypeSerializer { export function createRuntimeTypeSerializer(context: TransformationContext): RuntimeTypeSerializer { const { factory, - hoistVariableDeclaration + hoistVariableDeclaration, } = context; const resolver = context.getEmitResolver(); @@ -149,15 +156,33 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run let currentNameScope: ClassLikeDeclaration | undefined; return { - serializeTypeNode: (serializerContext, node) => setSerializerContextAnd(serializerContext, serializeTypeNode, node), - serializeTypeOfNode: (serializerContext, node) => setSerializerContextAnd(serializerContext, serializeTypeOfNode, node), - serializeParameterTypesOfNode: (serializerContext, node, container) => setSerializerContextAnd(serializerContext, serializeParameterTypesOfNode, node, container), - serializeReturnTypeOfNode: (serializerContext, node) => setSerializerContextAnd(serializerContext, serializeReturnTypeOfNode, node), + serializeTypeNode: (serializerContext, node) => + setSerializerContextAnd(serializerContext, serializeTypeNode, node), + serializeTypeOfNode: (serializerContext, node) => + setSerializerContextAnd(serializerContext, serializeTypeOfNode, node), + serializeParameterTypesOfNode: (serializerContext, node, container) => + setSerializerContextAnd(serializerContext, serializeParameterTypesOfNode, node, container), + serializeReturnTypeOfNode: (serializerContext, node) => + setSerializerContextAnd(serializerContext, serializeReturnTypeOfNode, node), }; - function setSerializerContextAnd(serializerContext: RuntimeTypeSerializerContext, cb: (node: TNode) => R, node: TNode): R; - function setSerializerContextAnd(serializerContext: RuntimeTypeSerializerContext, cb: (node: TNode, arg: T) => R, node: TNode, arg: T): R; - function setSerializerContextAnd(serializerContext: RuntimeTypeSerializerContext, cb: (node: TNode, arg?: T) => R, node: TNode, arg?: T) { + function setSerializerContextAnd( + serializerContext: RuntimeTypeSerializerContext, + cb: (node: TNode) => R, + node: TNode, + ): R; + function setSerializerContextAnd( + serializerContext: RuntimeTypeSerializerContext, + cb: (node: TNode, arg: T) => R, + node: TNode, + arg: T, + ): R; + function setSerializerContextAnd( + serializerContext: RuntimeTypeSerializerContext, + cb: (node: TNode, arg?: T) => R, + node: TNode, + arg?: T, + ) { const savedCurrentLexicalScope = currentLexicalScope; const savedCurrentNameScope = currentNameScope; @@ -181,7 +206,14 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run * Serializes the type of a node for use with decorator type metadata. * @param node The node that should have its type serialized. */ - function serializeTypeOfNode(node: PropertyDeclaration | ParameterDeclaration | AccessorDeclaration | ClassLikeDeclaration | MethodDeclaration): SerializedTypeNode { + function serializeTypeOfNode( + node: + | PropertyDeclaration + | ParameterDeclaration + | AccessorDeclaration + | ClassLikeDeclaration + | MethodDeclaration, + ): SerializedTypeNode { switch (node.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.Parameter: @@ -203,12 +235,11 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run * @param node The node that should have its type serialized. */ function serializeParameterTypesOfNode(node: Node, container: ClassLikeDeclaration): ArrayLiteralExpression { - const valueDeclaration = - isClassLike(node) - ? getFirstConstructorWithBody(node) - : isFunctionLike(node) && nodeIsPresent((node as FunctionLikeDeclaration).body) - ? node - : undefined; + const valueDeclaration = isClassLike(node) + ? getFirstConstructorWithBody(node) + : isFunctionLike(node) && nodeIsPresent((node as FunctionLikeDeclaration).body) + ? node + : undefined; const expressions: SerializedTypeNode[] = []; if (valueDeclaration) { @@ -296,9 +327,9 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run return factory.createIdentifier("Array"); case SyntaxKind.TypePredicate: - return (node as TypePredicateNode).assertsModifier ? - factory.createVoidZero() : - factory.createIdentifier("Boolean"); + return (node as TypePredicateNode).assertsModifier + ? factory.createVoidZero() + : factory.createIdentifier("Boolean"); case SyntaxKind.BooleanKeyword: return factory.createIdentifier("Boolean"); @@ -326,13 +357,22 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run return serializeTypeReferenceNode(node as TypeReferenceNode); case SyntaxKind.IntersectionType: - return serializeUnionOrIntersectionConstituents((node as UnionOrIntersectionTypeNode).types, /*isIntersection*/ true); + return serializeUnionOrIntersectionConstituents( + (node as UnionOrIntersectionTypeNode).types, + /*isIntersection*/ true, + ); case SyntaxKind.UnionType: - return serializeUnionOrIntersectionConstituents((node as UnionOrIntersectionTypeNode).types, /*isIntersection*/ false); + return serializeUnionOrIntersectionConstituents( + (node as UnionOrIntersectionTypeNode).types, + /*isIntersection*/ false, + ); case SyntaxKind.ConditionalType: - return serializeUnionOrIntersectionConstituents([(node as ConditionalTypeNode).trueType, (node as ConditionalTypeNode).falseType], /*isIntersection*/ false); + return serializeUnionOrIntersectionConstituents([ + (node as ConditionalTypeNode).trueType, + (node as ConditionalTypeNode).falseType, + ], /*isIntersection*/ false); case SyntaxKind.TypeOperator: if ((node as TypeOperatorNode).operator === SyntaxKind.ReadonlyKeyword) { @@ -405,7 +445,10 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run } } - function serializeUnionOrIntersectionConstituents(types: readonly TypeNode[], isIntersection: boolean): SerializedTypeNode { + function serializeUnionOrIntersectionConstituents( + types: readonly TypeNode[], + isIntersection: boolean, + ): SerializedTypeNode { // Note when updating logic here also update `getEntityNameForDecoratorMetadata` in checker.ts so that aliases can be marked as referenced let serializedType: SerializedTypeNode | undefined; for (let typeNode of types) { @@ -424,7 +467,11 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run return factory.createIdentifier("Object"); // Reduce to `any` in a union or intersection } - if (!strictNullChecks && ((isLiteralTypeNode(typeNode) && typeNode.literal.kind === SyntaxKind.NullKeyword) || typeNode.kind === SyntaxKind.UndefinedKeyword)) { + if ( + !strictNullChecks + && ((isLiteralTypeNode(typeNode) && typeNode.literal.kind === SyntaxKind.NullKeyword) + || typeNode.kind === SyntaxKind.UndefinedKeyword) + ) { continue; // Elide null and undefined from unions for metadata, just like what we did prior to the implementation of strict null checks } @@ -455,46 +502,37 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run function equateSerializedTypeNodes(left: Expression, right: Expression): boolean { return ( // temp vars used in fallback - isGeneratedIdentifier(left) ? isGeneratedIdentifier(right) : - - // entity names - isIdentifier(left) ? isIdentifier(right) - && left.escapedText === right.escapedText : - - isPropertyAccessExpression(left) ? isPropertyAccessExpression(right) - && equateSerializedTypeNodes(left.expression, right.expression) - && equateSerializedTypeNodes(left.name, right.name) : - - // `void 0` - isVoidExpression(left) ? isVoidExpression(right) - && isNumericLiteral(left.expression) && left.expression.text === "0" - && isNumericLiteral(right.expression) && right.expression.text === "0" : - - // `"undefined"` or `"function"` in `typeof` checks - isStringLiteral(left) ? isStringLiteral(right) - && left.text === right.text : - - // used in `typeof` checks for fallback - isTypeOfExpression(left) ? isTypeOfExpression(right) - && equateSerializedTypeNodes(left.expression, right.expression) : - - // parens in `typeof` checks with temps - isParenthesizedExpression(left) ? isParenthesizedExpression(right) - && equateSerializedTypeNodes(left.expression, right.expression) : - - // conditionals used in fallback - isConditionalExpression(left) ? isConditionalExpression(right) - && equateSerializedTypeNodes(left.condition, right.condition) - && equateSerializedTypeNodes(left.whenTrue, right.whenTrue) - && equateSerializedTypeNodes(left.whenFalse, right.whenFalse) : - - // logical binary and assignments used in fallback - isBinaryExpression(left) ? isBinaryExpression(right) - && left.operatorToken.kind === right.operatorToken.kind - && equateSerializedTypeNodes(left.left, right.left) - && equateSerializedTypeNodes(left.right, right.right) : - - false + isGeneratedIdentifier(left) ? isGeneratedIdentifier(right) + // entity names + : isIdentifier(left) ? isIdentifier(right) + && left.escapedText === right.escapedText + : isPropertyAccessExpression(left) ? isPropertyAccessExpression(right) + && equateSerializedTypeNodes(left.expression, right.expression) + && equateSerializedTypeNodes(left.name, right.name) + // `void 0` + : isVoidExpression(left) ? isVoidExpression(right) + && isNumericLiteral(left.expression) && left.expression.text === "0" + && isNumericLiteral(right.expression) && right.expression.text === "0" + // `"undefined"` or `"function"` in `typeof` checks + : isStringLiteral(left) ? isStringLiteral(right) + && left.text === right.text + // used in `typeof` checks for fallback + : isTypeOfExpression(left) ? isTypeOfExpression(right) + && equateSerializedTypeNodes(left.expression, right.expression) + // parens in `typeof` checks with temps + : isParenthesizedExpression(left) ? isParenthesizedExpression(right) + && equateSerializedTypeNodes(left.expression, right.expression) + // conditionals used in fallback + : isConditionalExpression(left) ? isConditionalExpression(right) + && equateSerializedTypeNodes(left.condition, right.condition) + && equateSerializedTypeNodes(left.whenTrue, right.whenTrue) + && equateSerializedTypeNodes(left.whenFalse, right.whenFalse) + // logical binary and assignments used in fallback + : isBinaryExpression(left) ? isBinaryExpression(right) + && left.operatorToken.kind === right.operatorToken.kind + && equateSerializedTypeNodes(left.left, right.left) + && equateSerializedTypeNodes(left.right, right.right) + : false ); } @@ -507,7 +545,11 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run switch (kind) { case TypeReferenceSerializationKind.Unknown: // From conditional type type reference that cannot be resolved is Similar to any or unknown - if (findAncestor(node, n => n.parent && isConditionalTypeNode(n.parent) && (n.parent.trueType === n || n.parent.falseType === n))) { + if ( + findAncestor(node, n => + n.parent && isConditionalTypeNode(n.parent) + && (n.parent.trueType === n || n.parent.falseType === n)) + ) { return factory.createIdentifier("Object"); } @@ -518,7 +560,7 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run /*questionToken*/ undefined, temp, /*colonToken*/ undefined, - factory.createIdentifier("Object") + factory.createIdentifier("Object"), ); case TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue: @@ -572,8 +614,11 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run */ function createCheckedValue(left: Expression, right: Expression) { return factory.createLogicalAnd( - factory.createStrictInequality(factory.createTypeOfExpression(left), factory.createStringLiteral("undefined")), - right + factory.createStrictInequality( + factory.createTypeOfExpression(left), + factory.createStringLiteral("undefined"), + ), + right, ); } @@ -589,7 +634,10 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run } if (node.left.kind === SyntaxKind.Identifier) { // A.B -> typeof A !== "undefined" && A.B - return createCheckedValue(serializeEntityNameAsExpression(node.left), serializeEntityNameAsExpression(node)); + return createCheckedValue( + serializeEntityNameAsExpression(node.left), + serializeEntityNameAsExpression(node), + ); } // A.B.C -> typeof A !== "undefined" && (_a = A.B) !== void 0 && _a.C const left = serializeEntityNameAsExpressionFallback(node.left); @@ -597,9 +645,9 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run return factory.createLogicalAnd( factory.createLogicalAnd( left.left, - factory.createStrictInequality(factory.createAssignment(temp, left.right), factory.createVoidZero()) + factory.createStrictInequality(factory.createAssignment(temp, left.right), factory.createVoidZero()), ), - factory.createPropertyAccessExpression(temp, node.right) + factory.createPropertyAccessExpression(temp, node.right), ); } @@ -627,7 +675,10 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run * @param node The qualified name to serialize. */ function serializeQualifiedNameAsExpression(node: QualifiedName): SerializedEntityName { - return factory.createPropertyAccessExpression(serializeEntityNameAsExpression(node.left), node.right) as PropertyAccessEntityNameExpression; + return factory.createPropertyAccessExpression( + serializeEntityNameAsExpression(node.left), + node.right, + ) as PropertyAccessEntityNameExpression; } function getGlobalConstructorWithFallback(name: string) { @@ -636,13 +687,13 @@ export function createRuntimeTypeSerializer(context: TransformationContext): Run /*questionToken*/ undefined, factory.createIdentifier(name), /*colonToken*/ undefined, - factory.createIdentifier("Object") + factory.createIdentifier("Object"), ); } function getGlobalConstructor(name: string, minLanguageVersion: ScriptTarget): SerializedTypeNode { - return languageVersion < minLanguageVersion ? - getGlobalConstructorWithFallback(name) : - factory.createIdentifier(name); + return languageVersion < minLanguageVersion + ? getGlobalConstructorWithFallback(name) + : factory.createIdentifier(name); } } diff --git a/src/compiler/transformers/utilities.ts b/src/compiler/transformers/utilities.ts index d01206af9057f..c57aa675e81cc 100644 --- a/src/compiler/transformers/utilities.ts +++ b/src/compiler/transformers/utilities.ts @@ -86,7 +86,7 @@ import { TransformationContext, unorderedRemoveItem, VariableDeclaration, - VariableStatement + VariableStatement, } from "../_namespaces/ts"; /** @internal */ @@ -117,7 +117,10 @@ function isNamedDefaultReference(e: ImportSpecifier): boolean { } /** @internal */ -export function chainBundle(context: CoreTransformationContext, transformSourceFile: (x: SourceFile) => SourceFile): (x: SourceFile | Bundle) => SourceFile | Bundle { +export function chainBundle( + context: CoreTransformationContext, + transformSourceFile: (x: SourceFile) => SourceFile, +): (x: SourceFile | Bundle) => SourceFile | Bundle { return transformSourceFileOrBundle; function transformSourceFileOrBundle(node: SourceFile | Bundle) { @@ -151,13 +154,17 @@ export function getImportNeedsImportStarHelper(node: ImportDeclaration): boolean } } // Import star is required if there's default named refs mixed with non-default refs, or if theres non-default refs and it has a default import - return (defaultRefCount > 0 && defaultRefCount !== bindings.elements.length) || (!!(bindings.elements.length - defaultRefCount) && isDefaultImport(node)); + return (defaultRefCount > 0 && defaultRefCount !== bindings.elements.length) + || (!!(bindings.elements.length - defaultRefCount) && isDefaultImport(node)); } /** @internal */ export function getImportNeedsImportDefaultHelper(node: ImportDeclaration): boolean { // Import default is needed if there's a default import or a default ref and no other refs (meaning an import star helper wasn't requested) - return !getImportNeedsImportStarHelper(node) && (isDefaultImport(node) || (!!node.importClause && isNamedImports(node.importClause.namedBindings!) && containsDefaultReference(node.importClause.namedBindings))); // TODO: GH#18217 + return !getImportNeedsImportStarHelper(node) + && (isDefaultImport(node) + || (!!node.importClause && isNamedImports(node.importClause.namedBindings!) + && containsDefaultReference(node.importClause.namedBindings))); // TODO: GH#18217 } /** @internal */ @@ -241,7 +248,12 @@ export function collectExternalModuleInfo(context: TransformationContext, source case SyntaxKind.VariableStatement: if (hasSyntacticModifier(node, ModifierFlags.Export)) { for (const decl of (node as VariableStatement).declarationList.declarations) { - exportedNames = collectExportedVariableInfo(decl, uniqueExports, exportedNames, exportedBindings); + exportedNames = collectExportedVariableInfo( + decl, + uniqueExports, + exportedNames, + exportedBindings, + ); } } break; @@ -251,7 +263,11 @@ export function collectExternalModuleInfo(context: TransformationContext, source if (hasSyntacticModifier(node, ModifierFlags.Default)) { // export default function() { } if (!hasExportDefault) { - multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), context.factory.getDeclarationName(node as FunctionDeclaration)); + multiMapSparseArrayAdd( + exportedBindings, + getOriginalNodeId(node), + context.factory.getDeclarationName(node as FunctionDeclaration), + ); hasExportDefault = true; } } @@ -272,7 +288,11 @@ export function collectExternalModuleInfo(context: TransformationContext, source if (hasSyntacticModifier(node, ModifierFlags.Default)) { // export default class { } if (!hasExportDefault) { - multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), context.factory.getDeclarationName(node as ClassDeclaration)); + multiMapSparseArrayAdd( + exportedBindings, + getOriginalNodeId(node), + context.factory.getDeclarationName(node as ClassDeclaration), + ); hasExportDefault = true; } } @@ -290,12 +310,28 @@ export function collectExternalModuleInfo(context: TransformationContext, source } } - const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded(context.factory, context.getEmitHelperFactory(), sourceFile, compilerOptions, hasExportStarsToExportValues, hasImportStar, hasImportDefault); + const externalHelpersImportDeclaration = createExternalHelpersImportDeclarationIfNeeded( + context.factory, + context.getEmitHelperFactory(), + sourceFile, + compilerOptions, + hasExportStarsToExportValues, + hasImportStar, + hasImportDefault, + ); if (externalHelpersImportDeclaration) { externalImports.unshift(externalHelpersImportDeclaration); } - return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration }; + return { + externalImports, + exportSpecifiers, + exportEquals, + hasExportStarsToExportValues, + exportedBindings, + exportedNames, + externalHelpersImportDeclaration, + }; function addExportedNamesForExportDeclaration(node: ExportDeclaration) { for (const specifier of cast(node.exportClause, isNamedExports).elements) { @@ -319,7 +355,12 @@ export function collectExternalModuleInfo(context: TransformationContext, source } } -function collectExportedVariableInfo(decl: VariableDeclaration | BindingElement, uniqueExports: Map, exportedNames: Identifier[] | undefined, exportedBindings: Identifier[][]) { +function collectExportedVariableInfo( + decl: VariableDeclaration | BindingElement, + uniqueExports: Map, + exportedNames: Identifier[] | undefined, + exportedBindings: Identifier[][], +) { if (isBindingPattern(decl.name)) { for (const element of decl.name.elements) { if (!isOmittedExpression(element)) { @@ -390,12 +431,25 @@ export class IdentifierNameMap { const autoGenerate = name.emitNode.autoGenerate; if ((autoGenerate.flags & GeneratedIdentifierFlags.KindMask) === GeneratedIdentifierFlags.Node) { const node = getNodeForGeneratedName(name); - const baseName = isMemberName(node) && node !== name ? IdentifierNameMap.toKey(node) : `(generated@${getNodeId(node)})`; - return formatGeneratedName(/*privateName*/ false, autoGenerate.prefix, baseName, autoGenerate.suffix, IdentifierNameMap.toKey); + const baseName = isMemberName(node) && node !== name ? IdentifierNameMap.toKey(node) + : `(generated@${getNodeId(node)})`; + return formatGeneratedName( + /*privateName*/ false, + autoGenerate.prefix, + baseName, + autoGenerate.suffix, + IdentifierNameMap.toKey, + ); } else { const baseName = `(auto@${autoGenerate.id})`; - return formatGeneratedName(/*privateName*/ false, autoGenerate.prefix, baseName, autoGenerate.suffix, IdentifierNameMap.toKey); + return formatGeneratedName( + /*privateName*/ false, + autoGenerate.prefix, + baseName, + autoGenerate.suffix, + IdentifierNameMap.toKey, + ); } } if (isPrivateIdentifier(name)) { @@ -437,10 +491,10 @@ export class IdentifierNameMultiMap extends IdentifierNameMap { * @internal */ export function isSimpleCopiableExpression(expression: Expression) { - return isStringLiteralLike(expression) || - expression.kind === SyntaxKind.NumericLiteral || - isKeyword(expression.kind) || - isIdentifier(expression); + return isStringLiteralLike(expression) + || expression.kind === SyntaxKind.NumericLiteral + || isKeyword(expression.kind) + || isIdentifier(expression); } /** @@ -461,24 +515,40 @@ export function isCompoundAssignment(kind: BinaryOperator): kind is CompoundAssi } /** @internal */ -export function getNonAssignmentOperatorForCompoundAssignment(kind: CompoundAssignmentOperator): LogicalOperatorOrHigher | SyntaxKind.QuestionQuestionToken { +export function getNonAssignmentOperatorForCompoundAssignment( + kind: CompoundAssignmentOperator, +): LogicalOperatorOrHigher | SyntaxKind.QuestionQuestionToken { switch (kind) { - case SyntaxKind.PlusEqualsToken: return SyntaxKind.PlusToken; - case SyntaxKind.MinusEqualsToken: return SyntaxKind.MinusToken; - case SyntaxKind.AsteriskEqualsToken: return SyntaxKind.AsteriskToken; - case SyntaxKind.AsteriskAsteriskEqualsToken: return SyntaxKind.AsteriskAsteriskToken; - case SyntaxKind.SlashEqualsToken: return SyntaxKind.SlashToken; - case SyntaxKind.PercentEqualsToken: return SyntaxKind.PercentToken; - case SyntaxKind.LessThanLessThanEqualsToken: return SyntaxKind.LessThanLessThanToken; - case SyntaxKind.GreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanToken; - case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken; - case SyntaxKind.AmpersandEqualsToken: return SyntaxKind.AmpersandToken; - case SyntaxKind.BarEqualsToken: return SyntaxKind.BarToken; - case SyntaxKind.CaretEqualsToken: return SyntaxKind.CaretToken; - case SyntaxKind.BarBarEqualsToken: return SyntaxKind.BarBarToken; - case SyntaxKind.AmpersandAmpersandEqualsToken: return SyntaxKind.AmpersandAmpersandToken; - case SyntaxKind.QuestionQuestionEqualsToken: return SyntaxKind.QuestionQuestionToken; - + case SyntaxKind.PlusEqualsToken: + return SyntaxKind.PlusToken; + case SyntaxKind.MinusEqualsToken: + return SyntaxKind.MinusToken; + case SyntaxKind.AsteriskEqualsToken: + return SyntaxKind.AsteriskToken; + case SyntaxKind.AsteriskAsteriskEqualsToken: + return SyntaxKind.AsteriskAsteriskToken; + case SyntaxKind.SlashEqualsToken: + return SyntaxKind.SlashToken; + case SyntaxKind.PercentEqualsToken: + return SyntaxKind.PercentToken; + case SyntaxKind.LessThanLessThanEqualsToken: + return SyntaxKind.LessThanLessThanToken; + case SyntaxKind.GreaterThanGreaterThanEqualsToken: + return SyntaxKind.GreaterThanGreaterThanToken; + case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: + return SyntaxKind.GreaterThanGreaterThanGreaterThanToken; + case SyntaxKind.AmpersandEqualsToken: + return SyntaxKind.AmpersandToken; + case SyntaxKind.BarEqualsToken: + return SyntaxKind.BarToken; + case SyntaxKind.CaretEqualsToken: + return SyntaxKind.CaretToken; + case SyntaxKind.BarBarEqualsToken: + return SyntaxKind.BarBarToken; + case SyntaxKind.AmpersandAmpersandEqualsToken: + return SyntaxKind.AmpersandAmpersandToken; + case SyntaxKind.QuestionQuestionEqualsToken: + return SyntaxKind.QuestionQuestionToken; } } @@ -505,7 +575,9 @@ function findSuperStatementIndexPathWorker(statements: NodeArray, sta indices.unshift(i); return true; } - else if (isTryStatement(statement) && findSuperStatementIndexPathWorker(statement.tryBlock.statements, 0, indices)) { + else if ( + isTryStatement(statement) && findSuperStatementIndexPathWorker(statement.tryBlock.statements, 0, indices) + ) { indices.unshift(i); return true; } @@ -536,24 +608,47 @@ export function findSuperStatementIndexPath(statements: NodeArray, st * * @internal */ -export function getProperties(node: ClassExpression | ClassDeclaration, requireInitializer: true, isStatic: boolean): readonly InitializedPropertyDeclaration[]; +export function getProperties( + node: ClassExpression | ClassDeclaration, + requireInitializer: true, + isStatic: boolean, +): readonly InitializedPropertyDeclaration[]; /** @internal */ -export function getProperties(node: ClassExpression | ClassDeclaration, requireInitializer: boolean, isStatic: boolean): readonly PropertyDeclaration[]; +export function getProperties( + node: ClassExpression | ClassDeclaration, + requireInitializer: boolean, + isStatic: boolean, +): readonly PropertyDeclaration[]; /** @internal */ -export function getProperties(node: ClassExpression | ClassDeclaration, requireInitializer: boolean, isStatic: boolean): readonly PropertyDeclaration[] { - return filter(node.members, m => isInitializedOrStaticProperty(m, requireInitializer, isStatic)) as PropertyDeclaration[]; -} - -function isStaticPropertyDeclarationOrClassStaticBlockDeclaration(element: ClassElement): element is PropertyDeclaration | ClassStaticBlockDeclaration { +export function getProperties( + node: ClassExpression | ClassDeclaration, + requireInitializer: boolean, + isStatic: boolean, +): readonly PropertyDeclaration[] { + return filter( + node.members, + m => isInitializedOrStaticProperty(m, requireInitializer, isStatic), + ) as PropertyDeclaration[]; +} + +function isStaticPropertyDeclarationOrClassStaticBlockDeclaration( + element: ClassElement, +): element is PropertyDeclaration | ClassStaticBlockDeclaration { return isStaticPropertyDeclaration(element) || isClassStaticBlockDeclaration(element); } /** @internal */ -export function getStaticPropertiesAndClassStaticBlock(node: ClassExpression | ClassDeclaration): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[]; +export function getStaticPropertiesAndClassStaticBlock( + node: ClassExpression | ClassDeclaration, +): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[]; /** @internal */ -export function getStaticPropertiesAndClassStaticBlock(node: ClassExpression | ClassDeclaration): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[]; +export function getStaticPropertiesAndClassStaticBlock( + node: ClassExpression | ClassDeclaration, +): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[]; /** @internal */ -export function getStaticPropertiesAndClassStaticBlock(node: ClassExpression | ClassDeclaration): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[] { +export function getStaticPropertiesAndClassStaticBlock( + node: ClassExpression | ClassDeclaration, +): readonly (PropertyDeclaration | ClassStaticBlockDeclaration)[] { return filter(node.members, isStaticPropertyDeclarationOrClassStaticBlockDeclaration); } @@ -581,7 +676,9 @@ function isStaticPropertyDeclaration(member: ClassElement) { * * @internal */ -export function isInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { +export function isInitializedProperty( + member: ClassElement, +): member is PropertyDeclaration & { initializer: Expression; } { return member.kind === SyntaxKind.PropertyDeclaration && (member as PropertyDeclaration).initializer !== undefined; } @@ -593,8 +690,15 @@ export function isInitializedProperty(member: ClassElement): member is PropertyD * * @internal */ -export function isNonStaticMethodOrAccessorWithPrivateName(member: ClassElement): member is PrivateIdentifierMethodDeclaration | PrivateIdentifierAccessorDeclaration | PrivateIdentifierAutoAccessorPropertyDeclaration { - return !isStatic(member) && (isMethodOrAccessor(member) || isAutoAccessorPropertyDeclaration(member)) && isPrivateIdentifier(member.name); +export function isNonStaticMethodOrAccessorWithPrivateName( + member: ClassElement, +): member is + | PrivateIdentifierMethodDeclaration + | PrivateIdentifierAccessorDeclaration + | PrivateIdentifierAutoAccessorPropertyDeclaration +{ + return !isStatic(member) && (isMethodOrAccessor(member) || isAutoAccessorPropertyDeclaration(member)) + && isPrivateIdentifier(member.name); } /** @@ -642,7 +746,7 @@ export function getAllDecoratorsOfClass(node: ClassLikeDeclaration): AllDecorato return { decorators, - parameters + parameters, }; } @@ -654,7 +758,11 @@ export function getAllDecoratorsOfClass(node: ClassLikeDeclaration): AllDecorato * * @internal */ -export function getAllDecoratorsOfClassElement(member: ClassElement, parent: ClassLikeDeclaration, useLegacyDecorators: boolean): AllDecorators | undefined { +export function getAllDecoratorsOfClassElement( + member: ClassElement, + parent: ClassLikeDeclaration, + useLegacyDecorators: boolean, +): AllDecorators | undefined { switch (member.kind) { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -680,16 +788,21 @@ export function getAllDecoratorsOfClassElement(member: ClassElement, parent: Cla * @param parent The class node that contains the accessor. * @param accessor The class accessor member. */ -function getAllDecoratorsOfAccessors(accessor: AccessorDeclaration, parent: ClassExpression | ClassDeclaration): AllDecorators | undefined { +function getAllDecoratorsOfAccessors( + accessor: AccessorDeclaration, + parent: ClassExpression | ClassDeclaration, +): AllDecorators | undefined { if (!accessor.body) { return undefined; } - const { firstAccessor, secondAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations(parent.members, accessor); - const firstAccessorWithDecorators = - hasDecorators(firstAccessor) ? firstAccessor : - secondAccessor && hasDecorators(secondAccessor) ? secondAccessor : - undefined; + const { firstAccessor, secondAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations( + parent.members, + accessor, + ); + const firstAccessorWithDecorators = hasDecorators(firstAccessor) ? firstAccessor + : secondAccessor && hasDecorators(secondAccessor) ? secondAccessor + : undefined; if (!firstAccessorWithDecorators || accessor !== firstAccessorWithDecorators) { return undefined; @@ -705,7 +818,7 @@ function getAllDecoratorsOfAccessors(accessor: AccessorDeclaration, parent: Clas decorators, parameters, getDecorators: getAccessor && getDecorators(getAccessor), - setDecorators: setAccessor && getDecorators(setAccessor) + setDecorators: setAccessor && getDecorators(setAccessor), }; } @@ -737,7 +850,6 @@ function getAllDecoratorsOfProperty(property: PropertyDeclaration): AllDecorator const decorators = getDecorators(property); if (!some(decorators)) { return undefined; - } return { decorators }; @@ -768,7 +880,7 @@ export interface LexicalEnvironment( env: LexicalEnvironment | undefined, - cb: (env: LexicalEnvironment) => U + cb: (env: LexicalEnvironment) => U, ): U | undefined { while (env) { const result = cb(env); @@ -785,18 +897,18 @@ export function newPrivateEnvironment(data: TData): PrivateEnviro /** @internal */ export function getPrivateIdentifier( privateEnv: PrivateEnvironment | undefined, - name: PrivateIdentifier + name: PrivateIdentifier, ) { - return isGeneratedPrivateIdentifier(name) ? - privateEnv?.generatedIdentifiers?.get(getNodeForGeneratedName(name)) : - privateEnv?.identifiers?.get(name.escapedText); + return isGeneratedPrivateIdentifier(name) + ? privateEnv?.generatedIdentifiers?.get(getNodeForGeneratedName(name)) + : privateEnv?.identifiers?.get(name.escapedText); } /** @internal */ export function setPrivateIdentifier( privateEnv: PrivateEnvironment, name: PrivateIdentifier, - entry: TEntry + entry: TEntry, ) { if (isGeneratedPrivateIdentifier(name)) { privateEnv.generatedIdentifiers ??= new Map(); diff --git a/src/compiler/tsbuild.ts b/src/compiler/tsbuild.ts index 741ffe0a8941d..74f2a164bb2a4 100644 --- a/src/compiler/tsbuild.ts +++ b/src/compiler/tsbuild.ts @@ -84,7 +84,10 @@ export namespace Status { * We track what the newest input file is. */ export interface UpToDate { - type: UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes | UpToDateStatusType.UpToDateWithInputFileText; + type: + | UpToDateStatusType.UpToDate + | UpToDateStatusType.UpToDateWithUpstreamTypes + | UpToDateStatusType.UpToDateWithInputFileText; newestInputFileTime?: Date; newestInputFileName?: string; oldestOutputFileName: string; @@ -135,7 +138,7 @@ export namespace Status { } export interface OutOfDateRoots { - type: UpToDateStatusType.OutOfDateRoots, + type: UpToDateStatusType.OutOfDateRoots; buildInfoFile: string; inputFile: Path; } diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index b734ca7eed949..70581b3042d01 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -185,13 +185,17 @@ enum BuildResultFlags { DeclarationEmitErrors = 1 << 5, EmitErrors = 1 << 6, - AnyErrors = ConfigFileErrors | SyntaxErrors | TypeErrors | DeclarationEmitErrors | EmitErrors + AnyErrors = ConfigFileErrors | SyntaxErrors | TypeErrors | DeclarationEmitErrors | EmitErrors, } /** @internal */ export type ResolvedConfigFilePath = ResolvedConfigFileName & Path; -function getOrCreateValueFromConfigFileMap(configFileMap: Map, resolved: ResolvedConfigFilePath, createT: () => T): T { +function getOrCreateValueFromConfigFileMap( + configFileMap: Map, + resolved: ResolvedConfigFilePath, + createT: () => T, +): T { const existingValue = configFileMap.get(resolved); let newValue: T | undefined; if (!existingValue) { @@ -201,7 +205,10 @@ function getOrCreateValueFromConfigFileMap(configFileMap: Map(configFileMap: Map>, resolved: ResolvedConfigFilePath): Map { +function getOrCreateValueMapFromConfigFileMap( + configFileMap: Map>, + resolved: ResolvedConfigFilePath, +): Map { return getOrCreateValueFromConfigFileMap(configFileMap, resolved, () => new Map()); } @@ -276,9 +283,19 @@ export function getBuildOrderFromAnyBuildOrder(anyBuildOrder: AnyBuildOrder): Bu } export interface SolutionBuilder { - build(project?: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers): ExitStatus; + build( + project?: string, + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + getCustomTransformers?: (project: string) => CustomTransformers, + ): ExitStatus; clean(project?: string): ExitStatus; - buildReferences(project: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers): ExitStatus; + buildReferences( + project: string, + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + getCustomTransformers?: (project: string) => CustomTransformers, + ): ExitStatus; cleanReferences(project?: string): ExitStatus; getNextInvalidatedProject(cancellationToken?: CancellationToken): InvalidatedProject | undefined; @@ -287,7 +304,10 @@ export interface SolutionBuilder { // Testing only /** @internal */ getUpToDateStatusOfProject(project: string): UpToDateStatus; - /** @internal */ invalidateProject(configFilePath: ResolvedConfigFilePath, reloadLevel?: ConfigFileProgramReloadLevel): void; + /** @internal */ invalidateProject( + configFilePath: ResolvedConfigFilePath, + reloadLevel?: ConfigFileProgramReloadLevel, + ): void; /** @internal */ close(): void; } @@ -296,13 +316,22 @@ export interface SolutionBuilder { */ export function createBuilderStatusReporter(system: System, pretty?: boolean): DiagnosticReporter { return diagnostic => { - let output = pretty ? `[${formatColorAndReset(getLocaleTimeString(system), ForegroundColorEscapeSequences.Grey)}] ` : `${getLocaleTimeString(system)} - `; - output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${system.newLine + system.newLine}`; + let output = pretty + ? `[${formatColorAndReset(getLocaleTimeString(system), ForegroundColorEscapeSequences.Grey)}] ` + : `${getLocaleTimeString(system)} - `; + output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${ + system.newLine + system.newLine + }`; system.write(output); }; } -function createSolutionBuilderHostBase(system: System, createProgram: CreateProgram | undefined, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter) { +function createSolutionBuilderHostBase( + system: System, + createProgram: CreateProgram | undefined, + reportDiagnostic?: DiagnosticReporter, + reportSolutionBuilderStatus?: DiagnosticReporter, +) { const host = createProgramHost(system, createProgram) as SolutionBuilderHostBase; host.getModifiedTime = system.getModifiedTime ? path => system.getModifiedTime!(path) : returnUndefined; host.setModifiedTime = system.setModifiedTime ? (path, date) => system.setModifiedTime!(path, date) : noop; @@ -313,14 +342,36 @@ function createSolutionBuilderHostBase(system: System, return host; } -export function createSolutionBuilderHost(system = sys, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportErrorSummary?: ReportEmitErrorSummary) { - const host = createSolutionBuilderHostBase(system, createProgram, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderHost; +export function createSolutionBuilderHost( + system = sys, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportSolutionBuilderStatus?: DiagnosticReporter, + reportErrorSummary?: ReportEmitErrorSummary, +) { + const host = createSolutionBuilderHostBase( + system, + createProgram, + reportDiagnostic, + reportSolutionBuilderStatus, + ) as SolutionBuilderHost; host.reportErrorSummary = reportErrorSummary; return host; } -export function createSolutionBuilderWithWatchHost(system = sys, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportSolutionBuilderStatus?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter) { - const host = createSolutionBuilderHostBase(system, createProgram, reportDiagnostic, reportSolutionBuilderStatus) as SolutionBuilderWithWatchHost; +export function createSolutionBuilderWithWatchHost( + system = sys, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportSolutionBuilderStatus?: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, +) { + const host = createSolutionBuilderHostBase( + system, + createProgram, + reportDiagnostic, + reportSolutionBuilderStatus, + ) as SolutionBuilderWithWatchHost; const watchHost = createWatchHost(system, reportWatchStatus); copyProperties(host, watchHost); return host; @@ -334,11 +385,20 @@ function getCompilerOptionsOfBuildOptions(buildOptions: BuildOptions): CompilerO return result; } -export function createSolutionBuilder(host: SolutionBuilderHost, rootNames: readonly string[], defaultOptions: BuildOptions): SolutionBuilder { +export function createSolutionBuilder( + host: SolutionBuilderHost, + rootNames: readonly string[], + defaultOptions: BuildOptions, +): SolutionBuilder { return createSolutionBuilderWorker(/*watch*/ false, host, rootNames, defaultOptions); } -export function createSolutionBuilderWithWatch(host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder { +export function createSolutionBuilderWithWatch( + host: SolutionBuilderWithWatchHost, + rootNames: readonly string[], + defaultOptions: BuildOptions, + baseWatchOptions?: WatchOptions, +): SolutionBuilder { return createSolutionBuilderWorker(/*watch*/ true, host, rootNames, defaultOptions, baseWatchOptions); } @@ -416,42 +476,70 @@ interface SolutionBuilderState extends WatchFactory; readonly outputTimeStamps: Map>; - readonly lastCachedPackageJsonLookups: Map; + readonly lastCachedPackageJsonLookups: Map< + ResolvedConfigFilePath, + readonly (readonly [Path, object | boolean])[] | undefined + >; timerToBuildInvalidatedProject: any; reportFileChangeDetected: boolean; writeLog: (s: string) => void; } -function createSolutionBuilderState(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: readonly string[], options: BuildOptions, baseWatchOptions: WatchOptions | undefined): SolutionBuilderState { +function createSolutionBuilderState( + watch: boolean, + hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, + rootNames: readonly string[], + options: BuildOptions, + baseWatchOptions: WatchOptions | undefined, +): SolutionBuilderState { const host = hostOrHostWithWatch as SolutionBuilderHost; const hostWithWatch = hostOrHostWithWatch as SolutionBuilderWithWatchHost; // State of the solution const baseCompilerOptions = getCompilerOptionsOfBuildOptions(options); - const compilerHost = createCompilerHostFromProgramHost(host, () => state.projectCompilerOptions) as CompilerHost & ReadBuildProgramHost; + const compilerHost = createCompilerHostFromProgramHost(host, () => state.projectCompilerOptions) as + & CompilerHost + & ReadBuildProgramHost; setGetSourceFileAsHashVersioned(compilerHost); - compilerHost.getParsedCommandLine = fileName => parseConfigFile(state, fileName as ResolvedConfigFileName, toResolvedConfigFilePath(state, fileName as ResolvedConfigFileName)); + compilerHost.getParsedCommandLine = fileName => + parseConfigFile( + state, + fileName as ResolvedConfigFileName, + toResolvedConfigFilePath(state, fileName as ResolvedConfigFileName), + ); compilerHost.resolveModuleNameLiterals = maybeBind(host, host.resolveModuleNameLiterals); - compilerHost.resolveTypeReferenceDirectiveReferences = maybeBind(host, host.resolveTypeReferenceDirectiveReferences); + compilerHost.resolveTypeReferenceDirectiveReferences = maybeBind( + host, + host.resolveTypeReferenceDirectiveReferences, + ); compilerHost.resolveLibrary = maybeBind(host, host.resolveLibrary); compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames); compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives); compilerHost.getModuleResolutionCache = maybeBind(host, host.getModuleResolutionCache); - let moduleResolutionCache: ModuleResolutionCache | undefined, typeReferenceDirectiveResolutionCache: TypeReferenceDirectiveResolutionCache | undefined; + let moduleResolutionCache: ModuleResolutionCache | undefined, + typeReferenceDirectiveResolutionCache: TypeReferenceDirectiveResolutionCache | undefined; if (!compilerHost.resolveModuleNameLiterals && !compilerHost.resolveModuleNames) { - moduleResolutionCache = createModuleResolutionCache(compilerHost.getCurrentDirectory(), compilerHost.getCanonicalFileName); - compilerHost.resolveModuleNameLiterals = (moduleNames, containingFile, redirectedReference, options, containingSourceFile) => - loadWithModeAwareCache( - moduleNames, - containingFile, - redirectedReference, - options, - containingSourceFile, - host, - moduleResolutionCache, - createModuleResolutionLoader, - ); + moduleResolutionCache = createModuleResolutionCache( + compilerHost.getCurrentDirectory(), + compilerHost.getCanonicalFileName, + ); + compilerHost.resolveModuleNameLiterals = ( + moduleNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + ) => loadWithModeAwareCache( + moduleNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + host, + moduleResolutionCache, + createModuleResolutionLoader, + ); compilerHost.getModuleResolutionCache = () => moduleResolutionCache; } if (!compilerHost.resolveTypeReferenceDirectiveReferences && !compilerHost.resolveTypeReferenceDirectives) { @@ -462,30 +550,47 @@ function createSolutionBuilderState(watch: boolean, ho moduleResolutionCache?.getPackageJsonInfoCache(), moduleResolutionCache?.optionsToRedirectsKey, ); - compilerHost.resolveTypeReferenceDirectiveReferences = (typeDirectiveNames, containingFile, redirectedReference, options, containingSourceFile) => - loadWithModeAwareCache( - typeDirectiveNames, - containingFile, - redirectedReference, - options, - containingSourceFile, - host, - typeReferenceDirectiveResolutionCache, - createTypeReferenceResolutionLoader, - ); + compilerHost.resolveTypeReferenceDirectiveReferences = ( + typeDirectiveNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + ) => loadWithModeAwareCache( + typeDirectiveNames, + containingFile, + redirectedReference, + options, + containingSourceFile, + host, + typeReferenceDirectiveResolutionCache, + createTypeReferenceResolutionLoader, + ); } let libraryResolutionCache: ModuleResolutionCache | undefined; if (!compilerHost.resolveLibrary) { - libraryResolutionCache = createModuleResolutionCache(compilerHost.getCurrentDirectory(), compilerHost.getCanonicalFileName, /*options*/ undefined, moduleResolutionCache?.getPackageJsonInfoCache()); - compilerHost.resolveLibrary = (libraryName, resolveFrom, options) => resolveLibrary( - libraryName, - resolveFrom, - options, - host, - libraryResolutionCache, + libraryResolutionCache = createModuleResolutionCache( + compilerHost.getCurrentDirectory(), + compilerHost.getCanonicalFileName, + /*options*/ undefined, + moduleResolutionCache?.getPackageJsonInfoCache(), ); + compilerHost.resolveLibrary = (libraryName, resolveFrom, options) => + resolveLibrary( + libraryName, + resolveFrom, + options, + host, + libraryResolutionCache, + ); } - compilerHost.getBuildInfo = (fileName, configFilePath) => getBuildInfo(state, fileName, toResolvedConfigFilePath(state, configFilePath as ResolvedConfigFileName), /*modifiedTime*/ undefined); + compilerHost.getBuildInfo = (fileName, configFilePath) => + getBuildInfo( + state, + fileName, + toResolvedConfigFilePath(state, configFilePath as ResolvedConfigFileName), + /*modifiedTime*/ undefined, + ); const { watchFile, watchDirectory, writeLog } = createWatchFactory(hostWithWatch, options); @@ -552,7 +657,10 @@ function toPath(state: SolutionBuilderState, fileNa return ts_toPath(fileName, state.compilerHost.getCurrentDirectory(), state.compilerHost.getCanonicalFileName); } -function toResolvedConfigFilePath(state: SolutionBuilderState, fileName: ResolvedConfigFileName): ResolvedConfigFilePath { +function toResolvedConfigFilePath( + state: SolutionBuilderState, + fileName: ResolvedConfigFileName, +): ResolvedConfigFilePath { const { resolvedConfigFilePaths } = state; const path = resolvedConfigFilePaths.get(fileName); if (path !== undefined) return path; @@ -566,12 +674,19 @@ function isParsedCommandLine(entry: ConfigFileCacheEntry): entry is ParsedComman return !!(entry as ParsedCommandLine).options; } -function getCachedParsedConfigFile(state: SolutionBuilderState, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { +function getCachedParsedConfigFile( + state: SolutionBuilderState, + configFilePath: ResolvedConfigFilePath, +): ParsedCommandLine | undefined { const value = state.configFileCache.get(configFilePath); return value && isParsedCommandLine(value) ? value : undefined; } -function parseConfigFile(state: SolutionBuilderState, configFileName: ResolvedConfigFileName, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { +function parseConfigFile( + state: SolutionBuilderState, + configFileName: ResolvedConfigFileName, + configFilePath: ResolvedConfigFilePath, +): ParsedCommandLine | undefined { const { configFileCache } = state; const value = configFileCache.get(configFilePath); if (value) { @@ -588,20 +703,36 @@ function parseConfigFile(state: SolutionBuilderState diagnostic = d; - parsed = getParsedCommandLineOfConfigFile(configFileName, baseCompilerOptions, parseConfigFileHost, extendedConfigCache, baseWatchOptions); + parsed = getParsedCommandLineOfConfigFile( + configFileName, + baseCompilerOptions, + parseConfigFileHost, + extendedConfigCache, + baseWatchOptions, + ); parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop; } configFileCache.set(configFilePath, parsed || diagnostic!); performance.mark("SolutionBuilder::afterConfigFileParsing"); - performance.measure("SolutionBuilder::Config file parsing", "SolutionBuilder::beforeConfigFileParsing", "SolutionBuilder::afterConfigFileParsing"); + performance.measure( + "SolutionBuilder::Config file parsing", + "SolutionBuilder::beforeConfigFileParsing", + "SolutionBuilder::afterConfigFileParsing", + ); return parsed; } -function resolveProjectName(state: SolutionBuilderState, name: string): ResolvedConfigFileName { +function resolveProjectName( + state: SolutionBuilderState, + name: string, +): ResolvedConfigFileName { return resolveConfigFileProjectName(resolvePath(state.compilerHost.getCurrentDirectory(), name)); } -function createBuildOrder(state: SolutionBuilderState, roots: readonly ResolvedConfigFileName[]): AnyBuildOrder { +function createBuildOrder( + state: SolutionBuilderState, + roots: readonly ResolvedConfigFileName[], +): AnyBuildOrder { const temporaryMarks = new Map(); const permanentMarks = new Map(); const circularityReportStack: string[] = []; @@ -611,9 +742,9 @@ function createBuildOrder(state: SolutionBuilderState< visit(root); } - return circularDiagnostics ? - { buildOrder: buildOrder || emptyArray, circularDiagnostics } : - buildOrder || emptyArray; + return circularDiagnostics + ? { buildOrder: buildOrder || emptyArray, circularDiagnostics } + : buildOrder || emptyArray; function visit(configFileName: ResolvedConfigFileName, inCircularContext?: boolean) { const projPath = toResolvedConfigFilePath(state, configFileName); @@ -625,8 +756,8 @@ function createBuildOrder(state: SolutionBuilderState< (circularDiagnostics || (circularDiagnostics = [])).push( createCompilerDiagnostic( Diagnostics.Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0, - circularityReportStack.join("\r\n") - ) + circularityReportStack.join("\r\n"), + ), ); } return; @@ -661,7 +792,8 @@ function createStateBuildOrder(state: SolutionBuilderS // TODO(rbuckton): Should be a `Set`, but that requires changing the code below that uses `mutateMapSkippingNewValues` const currentProjects = new Map( getBuildOrderFromAnyBuildOrder(buildOrder).map( - resolved => [toResolvedConfigFilePath(state, resolved), true as const]) + resolved => [toResolvedConfigFilePath(state, resolved), true as const], + ), ); const noopOnDelete = { onDeleteValue: noop }; @@ -680,7 +812,7 @@ function createStateBuildOrder(state: SolutionBuilderS mutateMapSkippingNewValues( state.allWatchedConfigFiles, currentProjects, - { onDeleteValue: closeFileWatcher } + { onDeleteValue: closeFileWatcher }, ); state.allWatchedExtendedConfigFiles.forEach(watcher => { @@ -695,25 +827,29 @@ function createStateBuildOrder(state: SolutionBuilderS mutateMapSkippingNewValues( state.allWatchedWildcardDirectories, currentProjects, - { onDeleteValue: existingMap => existingMap.forEach(closeFileWatcherOf) } + { onDeleteValue: existingMap => existingMap.forEach(closeFileWatcherOf) }, ); mutateMapSkippingNewValues( state.allWatchedInputFiles, currentProjects, - { onDeleteValue: existingMap => existingMap.forEach(closeFileWatcher) } + { onDeleteValue: existingMap => existingMap.forEach(closeFileWatcher) }, ); mutateMapSkippingNewValues( state.allWatchedPackageJsonFiles, currentProjects, - { onDeleteValue: existingMap => existingMap.forEach(closeFileWatcher) } + { onDeleteValue: existingMap => existingMap.forEach(closeFileWatcher) }, ); } return state.buildOrder = buildOrder; } -function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined): AnyBuildOrder | undefined { +function getBuildOrderFor( + state: SolutionBuilderState, + project: string | undefined, + onlyReferences: boolean | undefined, +): AnyBuildOrder | undefined { const resolvedProject = project && resolveProjectName(state, project); const buildOrderFromState = getBuildOrder(state); if (isCircularBuildOrder(buildOrderFromState)) return buildOrderFromState; @@ -721,7 +857,7 @@ function getBuildOrderFor(state: SolutionBuilderState< const projectPath = toResolvedConfigFilePath(state, resolvedProject); const projectIndex = findIndex( buildOrderFromState, - configFileName => toResolvedConfigFilePath(state, configFileName) === projectPath + configFileName => toResolvedConfigFilePath(state, configFileName) === projectPath, ); if (projectIndex === -1) return undefined; } @@ -743,13 +879,17 @@ function enableCache(state: SolutionBuilderState) { const originalGetSourceFile = compilerHost.getSourceFile; const { - originalReadFile, originalFileExists, originalDirectoryExists, - originalCreateDirectory, originalWriteFile, - getSourceFileWithCache, readFileWithCache + originalReadFile, + originalFileExists, + originalDirectoryExists, + originalCreateDirectory, + originalWriteFile, + getSourceFileWithCache, + readFileWithCache, } = changeCompilerHostLikeToUseCache( host, fileName => toPath(state, fileName), - (...args) => originalGetSourceFile.call(compilerHost, ...args) + (...args) => originalGetSourceFile.call(compilerHost, ...args), ); state.readFileWithCache = readFileWithCache; compilerHost.getSourceFile = getSourceFileWithCache!; @@ -768,7 +908,15 @@ function enableCache(state: SolutionBuilderState) { function disableCache(state: SolutionBuilderState) { if (!state.cache) return; - const { cache, host, compilerHost, extendedConfigCache, moduleResolutionCache, typeReferenceDirectiveResolutionCache, libraryResolutionCache } = state; + const { + cache, + host, + compilerHost, + extendedConfigCache, + moduleResolutionCache, + typeReferenceDirectiveResolutionCache, + libraryResolutionCache, + } = state; host.readFile = cache.originalReadFile; host.fileExists = cache.originalFileExists; @@ -784,12 +932,19 @@ function disableCache(state: SolutionBuilderState) state.cache = undefined; } -function clearProjectStatus(state: SolutionBuilderState, resolved: ResolvedConfigFilePath) { +function clearProjectStatus( + state: SolutionBuilderState, + resolved: ResolvedConfigFilePath, +) { state.projectStatus.delete(resolved); state.diagnostics.delete(resolved); } -function addProjToQueue({ projectPendingBuild }: SolutionBuilderState, proj: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function addProjToQueue( + { projectPendingBuild }: SolutionBuilderState, + proj: ResolvedConfigFilePath, + reloadLevel: ConfigFileProgramReloadLevel, +) { const value = projectPendingBuild.get(proj); if (value === undefined) { projectPendingBuild.set(proj, reloadLevel); @@ -799,7 +954,10 @@ function addProjToQueue({ projectPendingBuild }: Solut } } -function setupInitialBuild(state: SolutionBuilderState, cancellationToken: CancellationToken | undefined) { +function setupInitialBuild( + state: SolutionBuilderState, + cancellationToken: CancellationToken | undefined, +) { // Set initial build if not already built if (!state.allProjectBuildPending) return; state.allProjectBuildPending = false; @@ -809,7 +967,7 @@ function setupInitialBuild(state: SolutionBuilderState buildOrder.forEach(configFileName => state.projectPendingBuild.set( toResolvedConfigFilePath(state, configFileName), - ConfigFileProgramReloadLevel.None + ConfigFileProgramReloadLevel.None, ) ); @@ -821,7 +979,7 @@ function setupInitialBuild(state: SolutionBuilderState export enum InvalidatedProjectKind { Build, /** @deprecated */ UpdateBundle, - UpdateOutputFileStamps + UpdateOutputFileStamps, } export interface InvalidatedProjectBase { @@ -832,7 +990,11 @@ export interface InvalidatedProjectBase { /** * To dispose this project and ensure that all the necessary actions are taken and state is updated accordingly */ - done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): ExitStatus; + done( + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + customTransformers?: CustomTransformers, + ): ExitStatus; getCompilerOptions(): CompilerOptions; getCurrentDirectory(): string; } @@ -858,7 +1020,10 @@ export interface BuildInvalidedProject extends Invalid getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; getAllDependencies(sourceFile: SourceFile): readonly string[]; getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; - getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult; + getSemanticDiagnosticsOfNextAffectedFile( + cancellationToken?: CancellationToken, + ignoreSourceFile?: (sourceFile: SourceFile) => boolean, + ): AffectedFileResult; /* * Calling emit directly with targetSourceFile and emitOnlyDtsFiles set to true is not advised since * emit in build system is responsible in updating status of the project @@ -867,7 +1032,13 @@ export interface BuildInvalidedProject extends Invalid * (if that emit of that source file is required it would be emitted again when making sure invalidated project is completed) * This emit is not considered actual emit (and hence uptodate status is not reflected if */ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult | undefined; + emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): EmitResult | undefined; // TODO(shkamat):: investigate later if we can emit even when there are declaration diagnostics // emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): AffectedFileResult; } @@ -875,19 +1046,25 @@ export interface BuildInvalidedProject extends Invalid /** @deprecated */ export interface UpdateBundleProject extends InvalidatedProjectBase { readonly kind: InvalidatedProjectKind.UpdateBundle; - emit(writeFile?: WriteFileCallback, customTransformers?: CustomTransformers): EmitResult | BuildInvalidedProject | undefined; + emit( + writeFile?: WriteFileCallback, + customTransformers?: CustomTransformers, + ): EmitResult | BuildInvalidedProject | undefined; } -export type InvalidatedProject = UpdateOutputFileStampsProject | BuildInvalidedProject | UpdateBundleProject; +export type InvalidatedProject = + | UpdateOutputFileStampsProject + | BuildInvalidedProject + | UpdateBundleProject; function doneInvalidatedProject( state: SolutionBuilderState, - projectPath: ResolvedConfigFilePath + projectPath: ResolvedConfigFilePath, ) { state.projectPendingBuild.delete(projectPath); - return state.diagnostics.has(projectPath) ? - ExitStatus.DiagnosticsPresent_OutputsSkipped : - ExitStatus.Success; + return state.diagnostics.has(projectPath) + ? ExitStatus.DiagnosticsPresent_OutputsSkipped + : ExitStatus.Success; } function createUpdateOutputFileStampsProject( @@ -895,7 +1072,7 @@ function createUpdateOutputFileStampsProject( project: ResolvedConfigFileName, projectPath: ResolvedConfigFilePath, config: ParsedCommandLine, - buildOrder: readonly ResolvedConfigFileName[] + buildOrder: readonly ResolvedConfigFileName[], ): UpdateOutputFileStampsProject { let updateOutputFileStampsPending = true; return { @@ -915,7 +1092,7 @@ function createUpdateOutputFileStampsProject( } performance.mark("SolutionBuilder::Timestamps only updates"); return doneInvalidatedProject(state, projectPath); - } + }, }; } @@ -928,7 +1105,7 @@ enum BuildStep { EmitBuildInfo, /** @deprecated */ BuildInvalidatedProjectOfBundle, QueueReferencingProjects, - Done + Done, } function createBuildOrUpdateInvalidedProject( @@ -945,8 +1122,8 @@ function createBuildOrUpdateInvalidedProject( let buildResult: BuildResultFlags | undefined; let invalidatedProjectOfBundle: BuildInvalidedProject | undefined; - return kind === InvalidatedProjectKind.Build ? - { + return kind === InvalidatedProjectKind.Build + ? { kind, project, projectPath, @@ -956,50 +1133,58 @@ function createBuildOrUpdateInvalidedProject( getBuilderProgram: () => withProgramOrUndefined(identity), getProgram: () => withProgramOrUndefined( - program => program.getProgramOrUndefined() + program => program.getProgramOrUndefined(), ), getSourceFile: fileName => withProgramOrUndefined( - program => program.getSourceFile(fileName) + program => program.getSourceFile(fileName), ), getSourceFiles: () => withProgramOrEmptyArray( - program => program.getSourceFiles() + program => program.getSourceFiles(), ), getOptionsDiagnostics: cancellationToken => withProgramOrEmptyArray( - program => program.getOptionsDiagnostics(cancellationToken) + program => program.getOptionsDiagnostics(cancellationToken), ), getGlobalDiagnostics: cancellationToken => withProgramOrEmptyArray( - program => program.getGlobalDiagnostics(cancellationToken) + program => program.getGlobalDiagnostics(cancellationToken), ), getConfigFileParsingDiagnostics: () => withProgramOrEmptyArray( - program => program.getConfigFileParsingDiagnostics() + program => program.getConfigFileParsingDiagnostics(), ), getSyntacticDiagnostics: (sourceFile, cancellationToken) => withProgramOrEmptyArray( - program => program.getSyntacticDiagnostics(sourceFile, cancellationToken) + program => program.getSyntacticDiagnostics(sourceFile, cancellationToken), ), getAllDependencies: sourceFile => withProgramOrEmptyArray( - program => program.getAllDependencies(sourceFile) + program => program.getAllDependencies(sourceFile), ), getSemanticDiagnostics: (sourceFile, cancellationToken) => withProgramOrEmptyArray( - program => program.getSemanticDiagnostics(sourceFile, cancellationToken) + program => program.getSemanticDiagnostics(sourceFile, cancellationToken), ), getSemanticDiagnosticsOfNextAffectedFile: (cancellationToken, ignoreSourceFile) => withProgramOrUndefined( program => - ((program as any as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile) && - (program as any as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile(cancellationToken, ignoreSourceFile) + ((program as any as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile) + && (program as any as SemanticDiagnosticsBuilderProgram) + .getSemanticDiagnosticsOfNextAffectedFile(cancellationToken, ignoreSourceFile), ), emit: (targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers) => { if (targetSourceFile || emitOnlyDtsFiles) { return withProgramOrUndefined( - program => program.emit(targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers || state.host.getCustomTransformers?.(project)) + program => + program.emit( + targetSourceFile, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers || state.host.getCustomTransformers?.(project), + ), ); } executeSteps(BuildStep.SemanticDiagnostics, cancellationToken); @@ -1009,9 +1194,9 @@ function createBuildOrUpdateInvalidedProject( if (step !== BuildStep.Emit) return undefined; return emit(writeFile, cancellationToken, customTransformers); }, - done - } : - { + done, + } + : { kind, project, projectPath, @@ -1025,7 +1210,11 @@ function createBuildOrUpdateInvalidedProject( done, }; - function done(cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) { + function done( + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + customTransformers?: CustomTransformers, + ) { executeSteps(BuildStep.Done, cancellationToken, writeFile, customTransformers); if (kind === InvalidatedProjectKind.Build) performance.mark("SolutionBuilder::Projects built"); else performance.mark("SolutionBuilder::Bundles updated"); @@ -1074,13 +1263,21 @@ function createBuildOrUpdateInvalidedProject( compilerHost, getOldProgram(state, projectPath, config), getConfigFileParsingDiagnostics(config), - config.projectReferences + config.projectReferences, ); if (state.watch) { - state.lastCachedPackageJsonLookups.set(projectPath, state.moduleResolutionCache && map( - state.moduleResolutionCache.getPackageJsonInfoCache().entries(), - ([path, data]) => ([state.host.realpath && data ? toPath(state, state.host.realpath(path)) : path, data] as const) - )); + state.lastCachedPackageJsonLookups.set( + projectPath, + state.moduleResolutionCache && map( + state.moduleResolutionCache.getPackageJsonInfoCache().entries(), + ( + [path, data], + ) => ([ + state.host.realpath && data ? toPath(state, state.host.realpath(path)) : path, + data, + ] as const), + ), + ); state.builderPrograms.set(projectPath, program); } @@ -1096,7 +1293,7 @@ function createBuildOrUpdateInvalidedProject( config, diagnostics, errorFlags, - errorType + errorType, )); } else { @@ -1111,10 +1308,10 @@ function createBuildOrUpdateInvalidedProject( ...program.getConfigFileParsingDiagnostics(), ...program.getOptionsDiagnostics(cancellationToken), ...program.getGlobalDiagnostics(cancellationToken), - ...program.getSyntacticDiagnostics(/*sourceFile*/ undefined, cancellationToken) + ...program.getSyntacticDiagnostics(/*sourceFile*/ undefined, cancellationToken), ], BuildResultFlags.SyntaxErrors, - "Syntactic" + "Syntactic", ); } @@ -1122,11 +1319,15 @@ function createBuildOrUpdateInvalidedProject( handleDiagnostics( Debug.checkDefined(program).getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken), BuildResultFlags.TypeErrors, - "Semantic" + "Semantic", ); } - function emit(writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): EmitResult { + function emit( + writeFileCallback?: WriteFileCallback, + cancellationToken?: CancellationToken, + customTransformers?: CustomTransformers, + ): EmitResult { Debug.assertIsDefined(program); Debug.assert(step === BuildStep.Emit); // Before emitting lets backup state, so we can revert it back if there are declaration errors to handle emit and declaration errors correctly @@ -1139,10 +1340,11 @@ function createBuildOrUpdateInvalidedProject( reportDeclarationDiagnostics, /*write*/ undefined, /*reportSummary*/ undefined, - (name, text, writeByteOrderMark, _onError, _sourceFiles, data) => outputFiles.push({ name, text, writeByteOrderMark, data }), + (name, text, writeByteOrderMark, _onError, _sourceFiles, data) => + outputFiles.push({ name, text, writeByteOrderMark, data }), cancellationToken, /*emitOnlyDtsFiles*/ false, - customTransformers || state.host.getCustomTransformers?.(project) + customTransformers || state.host.getCustomTransformers?.(project), ); // Don't emit .d.ts if there are decl file errors if (declDiagnostics) { @@ -1154,17 +1356,18 @@ function createBuildOrUpdateInvalidedProject( config, declDiagnostics, BuildResultFlags.DeclarationEmitErrors, - "Declaration file" + "Declaration file", )); return { emitSkipped: true, - diagnostics: emitResult.diagnostics + diagnostics: emitResult.diagnostics, }; } // Actual Emit const { host, compilerHost } = state; - const resultFlags = program.hasChangedEmitSignature?.() ? BuildResultFlags.None : BuildResultFlags.DeclarationOutputUnchanged; + const resultFlags = program.hasChangedEmitSignature?.() ? BuildResultFlags.None + : BuildResultFlags.DeclarationOutputUnchanged; const emitterDiagnostics = createDiagnosticCollection(); const emittedOutputs = new Map(); const options = program.getCompilerOptions(); @@ -1176,11 +1379,20 @@ function createBuildOrUpdateInvalidedProject( emittedOutputs.set(toPath(state, name), name); if (data?.buildInfo) setBuildInfo(state, data.buildInfo, projectPath, options, resultFlags); const modifiedTime = data?.differsOnlyInMap ? ts_getModifiedTime(state.host, name) : undefined; - writeFile(writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, emitterDiagnostics, name, text, writeByteOrderMark); + writeFile( + writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, + emitterDiagnostics, + name, + text, + writeByteOrderMark, + ); // Revert the timestamp for the d.ts that is same if (data?.differsOnlyInMap) state.host.setModifiedTime(name, modifiedTime!); else if (!isIncremental && state.watch) { - (outputTimeStampMap ||= getOutputTimeStampMap(state, projectPath)!).set(path, now ||= getCurrentTime(state.host)); + (outputTimeStampMap ||= getOutputTimeStampMap(state, projectPath)!).set( + path, + now ||= getCurrentTime(state.host), + ); } }); @@ -1188,7 +1400,7 @@ function createBuildOrUpdateInvalidedProject( emitterDiagnostics, emittedOutputs, outputFiles.length ? outputFiles[0].name : getFirstProjectOutput(config, !host.useCaseSensitiveFileNames()), - resultFlags + resultFlags, ); return emitResult; } @@ -1197,7 +1409,15 @@ function createBuildOrUpdateInvalidedProject( Debug.assertIsDefined(program); Debug.assert(step === BuildStep.EmitBuildInfo); const emitResult = program.emitBuildInfo((name, text, writeByteOrderMark, onError, sourceFiles, data) => { - if (data?.buildInfo) setBuildInfo(state, data.buildInfo, projectPath, program!.getCompilerOptions(), BuildResultFlags.DeclarationOutputUnchanged); + if (data?.buildInfo) { + setBuildInfo( + state, + data.buildInfo, + projectPath, + program!.getCompilerOptions(), + BuildResultFlags.DeclarationOutputUnchanged, + ); + } if (writeFileCallback) writeFileCallback(name, text, writeByteOrderMark, onError, sourceFiles, data); else state.compilerHost.writeFile(name, text, writeByteOrderMark, onError, sourceFiles, data); }, cancellationToken); @@ -1219,7 +1439,7 @@ function createBuildOrUpdateInvalidedProject( emitterDiagnostics: DiagnosticCollection, emittedOutputs: Map, oldestOutputFileName: string, - resultFlags: BuildResultFlags + resultFlags: BuildResultFlags, ) { const emitDiagnostics = emitterDiagnostics.getDiagnostics(); if (emitDiagnostics.length) { @@ -1230,7 +1450,7 @@ function createBuildOrUpdateInvalidedProject( config, emitDiagnostics, BuildResultFlags.EmitErrors, - "Emit" + "Emit", )); return emitDiagnostics; } @@ -1240,11 +1460,17 @@ function createBuildOrUpdateInvalidedProject( } // Update time stamps for rest of the outputs - updateOutputTimestampsWorker(state, config, projectPath, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs); + updateOutputTimestampsWorker( + state, + config, + projectPath, + Diagnostics.Updating_unchanged_output_timestamps_of_project_0, + emittedOutputs, + ); state.diagnostics.delete(projectPath); state.projectStatus.set(projectPath, { type: UpToDateStatusType.UpToDate, - oldestOutputFileName + oldestOutputFileName, }); afterProgramDone(state, program, config); step = BuildStep.QueueReferencingProjects; @@ -1252,7 +1478,10 @@ function createBuildOrUpdateInvalidedProject( return emitDiagnostics; } - function emitBundle(writeFileCallback?: WriteFileCallback, customTransformers?: CustomTransformers): EmitResult | BuildInvalidedProject | undefined { + function emitBundle( + writeFileCallback?: WriteFileCallback, + customTransformers?: CustomTransformers, + ): EmitResult | BuildInvalidedProject | undefined { Debug.assert(kind === InvalidatedProjectKind.UpdateBundle); if (state.options.dry) { reportStatus(state, Diagnostics.A_non_dry_build_would_update_output_of_project_0, project); @@ -1274,11 +1503,16 @@ function createBuildOrUpdateInvalidedProject( const refName = resolveProjectName(state, ref.path); return parseConfigFile(state, refName, toResolvedConfigFilePath(state, refName)); }, - customTransformers || state.host.getCustomTransformers?.(project) + customTransformers || state.host.getCustomTransformers?.(project), ); if (isString(outputFiles)) { - reportStatus(state, Diagnostics.Cannot_update_output_of_project_0_because_there_was_error_reading_file_1, project, relName(state, outputFiles)); + reportStatus( + state, + Diagnostics.Cannot_update_output_of_project_0_because_there_was_error_reading_file_1, + project, + relName(state, outputFiles), + ); step = BuildStep.BuildInvalidatedProjectOfBundle; return invalidatedProjectOfBundle = createBuildOrUpdateInvalidedProject( InvalidatedProjectKind.Build, @@ -1287,7 +1521,7 @@ function createBuildOrUpdateInvalidedProject( projectPath, projectIndex, config, - buildOrder + buildOrder, ) as BuildInvalidedProject; } @@ -1300,24 +1534,38 @@ function createBuildOrUpdateInvalidedProject( outputFiles.forEach(({ name, text, writeByteOrderMark, data }) => { emittedOutputs.set(toPath(state, name), name); if (data?.buildInfo) { - if ((data.buildInfo.program as ProgramBundleEmitBuildInfo)?.outSignature !== (existingBuildInfo?.program as ProgramBundleEmitBuildInfo)?.outSignature) { + if ( + (data.buildInfo.program as ProgramBundleEmitBuildInfo)?.outSignature + !== (existingBuildInfo?.program as ProgramBundleEmitBuildInfo)?.outSignature + ) { resultFlags &= ~BuildResultFlags.DeclarationOutputUnchanged; } setBuildInfo(state, data.buildInfo, projectPath, config.options, resultFlags); } - writeFile(writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, emitterDiagnostics, name, text, writeByteOrderMark); + writeFile( + writeFileCallback ? { writeFile: writeFileCallback } : compilerHost, + emitterDiagnostics, + name, + text, + writeByteOrderMark, + ); }); const emitDiagnostics = finishEmit( emitterDiagnostics, emittedOutputs, outputFiles[0].name, - resultFlags + resultFlags, ); return { emitSkipped: false, diagnostics: emitDiagnostics }; } - function executeSteps(till: BuildStep, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, customTransformers?: CustomTransformers) { + function executeSteps( + till: BuildStep, + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + customTransformers?: CustomTransformers, + ) { while (step <= till && step < BuildStep.Done) { const currentStep = step; switch (step) { @@ -1346,12 +1594,24 @@ function createBuildOrUpdateInvalidedProject( break; case BuildStep.BuildInvalidatedProjectOfBundle: - Debug.checkDefined(invalidatedProjectOfBundle).done(cancellationToken, writeFile, customTransformers); + Debug.checkDefined(invalidatedProjectOfBundle).done( + cancellationToken, + writeFile, + customTransformers, + ); step = BuildStep.Done; break; case BuildStep.QueueReferencingProjects: - queueReferencingProjects(state, project, projectPath, projectIndex, config, buildOrder, Debug.checkDefined(buildResult)); + queueReferencingProjects( + state, + project, + projectPath, + projectIndex, + config, + buildOrder, + Debug.checkDefined(buildResult), + ); step++; break; @@ -1359,18 +1619,21 @@ function createBuildOrUpdateInvalidedProject( case BuildStep.Done: default: assertType(step); - } Debug.assert(step > currentStep); } } } -function needsBuild({ options }: SolutionBuilderState, status: UpToDateStatus, config: ParsedCommandLine) { +function needsBuild( + { options }: SolutionBuilderState, + status: UpToDateStatus, + config: ParsedCommandLine, +) { if (status.type !== UpToDateStatusType.OutOfDateWithPrepend || options.force) return true; - return config.fileNames.length === 0 || - !!getConfigFileParsingDiagnostics(config).length || - !isIncrementalCompilation(config.options); + return config.fileNames.length === 0 + || !!getConfigFileParsingDiagnostics(config).length + || !isIncrementalCompilation(config.options); } interface InvalidateProjectCreateInfo { @@ -1385,7 +1648,7 @@ interface InvalidateProjectCreateInfo { function getNextInvalidatedProjectCreateInfo( state: SolutionBuilderState, buildOrder: AnyBuildOrder, - reportQueue: boolean + reportQueue: boolean, ): InvalidateProjectCreateInfo | undefined { if (!state.projectPendingBuild.size) return undefined; if (isCircularBuildOrder(buildOrder)) return undefined; @@ -1418,8 +1681,19 @@ function getNextInvalidatedProjectCreateInfo( } else if (reloadLevel === ConfigFileProgramReloadLevel.Partial) { // Update file names - config.fileNames = getFileNamesFromConfigSpecs(config.options.configFile!.configFileSpecs!, getDirectoryPath(project), config.options, state.parseConfigFileHost); - updateErrorForNoInputFiles(config.fileNames, project, config.options.configFile!.configFileSpecs!, config.errors, canJsonReportNoInputFiles(config.raw)); + config.fileNames = getFileNamesFromConfigSpecs( + config.options.configFile!.configFileSpecs!, + getDirectoryPath(project), + config.options, + state.parseConfigFileHost, + ); + updateErrorForNoInputFiles( + config.fileNames, + project, + config.options.configFile!.configFileSpecs!, + config.errors, + canJsonReportNoInputFiles(config.raw), + ); watchInputFiles(state, project, projectPath, config); watchPackageJsonFiles(state, project, projectPath, config); } @@ -1438,7 +1712,10 @@ function getNextInvalidatedProjectCreateInfo( continue; } - if (status.type === UpToDateStatusType.UpToDateWithUpstreamTypes || status.type === UpToDateStatusType.UpToDateWithInputFileText) { + if ( + status.type === UpToDateStatusType.UpToDateWithUpstreamTypes + || status.type === UpToDateStatusType.UpToDateWithInputFileText + ) { reportAndStoreErrors(state, projectPath, getConfigFileParsingDiagnostics(config)); return { kind: InvalidatedProjectKind.UpdateOutputFileStamps, @@ -1446,7 +1723,7 @@ function getNextInvalidatedProjectCreateInfo( project, projectPath, projectIndex, - config + config, }; } } @@ -1458,11 +1735,11 @@ function getNextInvalidatedProjectCreateInfo( if (options.verbose) { reportStatus( state, - status.upstreamProjectBlocked ? - Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_was_not_built : - Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, + status.upstreamProjectBlocked + ? Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_was_not_built + : Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, project, - status.upstreamProjectName + status.upstreamProjectName, ); } continue; @@ -1477,9 +1754,9 @@ function getNextInvalidatedProjectCreateInfo( } return { - kind: needsBuild(state, status, config) ? - InvalidatedProjectKind.Build : - InvalidatedProjectKind.UpdateBundle, + kind: needsBuild(state, status, config) + ? InvalidatedProjectKind.Build + : InvalidatedProjectKind.UpdateBundle, status, project, projectPath, @@ -1497,8 +1774,8 @@ function createInvalidatedProjectWithInfo( buildOrder: AnyBuildOrder, ) { verboseReportProjectStatus(state, info.project, info.status); - return info.kind !== InvalidatedProjectKind.UpdateOutputFileStamps ? - createBuildOrUpdateInvalidedProject( + return info.kind !== InvalidatedProjectKind.UpdateOutputFileStamps + ? createBuildOrUpdateInvalidedProject( info.kind, state, info.project, @@ -1506,33 +1783,41 @@ function createInvalidatedProjectWithInfo( info.projectIndex, info.config, buildOrder as BuildOrder, - ) : - createUpdateOutputFileStampsProject( + ) + : createUpdateOutputFileStampsProject( state, info.project, info.projectPath, info.config, - buildOrder as BuildOrder + buildOrder as BuildOrder, ); } function getNextInvalidatedProject( state: SolutionBuilderState, buildOrder: AnyBuildOrder, - reportQueue: boolean + reportQueue: boolean, ): InvalidatedProject | undefined { const info = getNextInvalidatedProjectCreateInfo(state, buildOrder, reportQueue); if (!info) return info; return createInvalidatedProjectWithInfo(state, info, buildOrder); } -function listEmittedFile({ write }: SolutionBuilderState, proj: ParsedCommandLine, file: string) { +function listEmittedFile( + { write }: SolutionBuilderState, + proj: ParsedCommandLine, + file: string, +) { if (write && proj.options.listEmittedFiles) { write(`TSFILE: ${file}`); } } -function getOldProgram({ options, builderPrograms, compilerHost }: SolutionBuilderState, proj: ResolvedConfigFilePath, parsed: ParsedCommandLine) { +function getOldProgram( + { options, builderPrograms, compilerHost }: SolutionBuilderState, + proj: ResolvedConfigFilePath, + parsed: ParsedCommandLine, +) { if (options.force) return undefined; const value = builderPrograms.get(proj); if (value) return value; @@ -1542,7 +1827,7 @@ function getOldProgram({ options, builderPrograms, com function afterProgramDone( state: SolutionBuilderState, program: T | undefined, - config: ParsedCommandLine + config: ParsedCommandLine, ) { if (program) { if (state.write) listFiles(program, state.write); @@ -1576,7 +1861,9 @@ function buildErrors( return { buildResult, step: BuildStep.QueueReferencingProjects }; } -function isFileWatcherWithModifiedTime(value: FileWatcherWithModifiedTime | Date): value is FileWatcherWithModifiedTime { +function isFileWatcherWithModifiedTime( + value: FileWatcherWithModifiedTime | Date, +): value is FileWatcherWithModifiedTime { return !!(value as FileWatcherWithModifiedTime).watcher; } @@ -1598,7 +1885,15 @@ function getModifiedTime(state: SolutionBuilderState(state: SolutionBuilderState, file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined, watchType: WatchType, project?: ResolvedConfigFileName): FileWatcher { +function watchFile( + state: SolutionBuilderState, + file: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + watchType: WatchType, + project?: ResolvedConfigFileName, +): FileWatcher { const path = toPath(state, file); const existing = state.filesWatched.get(path); if (existing && isFileWatcherWithModifiedTime(existing)) { @@ -1616,7 +1911,7 @@ function watchFile(state: SolutionBuilderState, fil pollingInterval, options, watchType, - project + project, ); state.filesWatched.set(path, { callbacks: [callback], watcher, modifiedTime: existing }); } @@ -1632,11 +1927,14 @@ function watchFile(state: SolutionBuilderState, fil else { unorderedRemoveItem(existing.callbacks, callback); } - } + }, }; } -function getOutputTimeStampMap(state: SolutionBuilderState, resolvedConfigFilePath: ResolvedConfigFilePath) { +function getOutputTimeStampMap( + state: SolutionBuilderState, + resolvedConfigFilePath: ResolvedConfigFilePath, +) { // Output timestamps are stored only in watch mode if (!state.watch) return undefined; let result = state.outputTimeStamps.get(resolvedConfigFilePath); @@ -1669,13 +1967,22 @@ function setBuildInfo( } } -function getBuildInfoCacheEntry(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath) { +function getBuildInfoCacheEntry( + state: SolutionBuilderState, + buildInfoPath: string, + resolvedConfigPath: ResolvedConfigFilePath, +) { const path = toPath(state, buildInfoPath); const existing = state.buildInfoCache.get(resolvedConfigPath); return existing?.path === path ? existing : undefined; } -function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined { +function getBuildInfo( + state: SolutionBuilderState, + buildInfoPath: string, + resolvedConfigPath: ResolvedConfigFilePath, + modifiedTime: Date | undefined, +): BuildInfo | undefined { const path = toPath(state, buildInfoPath); const existing = state.buildInfoCache.get(resolvedConfigPath); if (existing !== undefined && existing.path === path) { @@ -1683,27 +1990,40 @@ function getBuildInfo(state: SolutionBuilderState, } const value = state.readFileWithCache(buildInfoPath); const buildInfo = value ? ts_getBuildInfo(buildInfoPath, value) : undefined; - state.buildInfoCache.set(resolvedConfigPath, { path, buildInfo: buildInfo || false, modifiedTime: modifiedTime || missingFileModifiedTime }); + state.buildInfoCache.set(resolvedConfigPath, { + path, + buildInfo: buildInfo || false, + modifiedTime: modifiedTime || missingFileModifiedTime, + }); return buildInfo; } -function checkConfigFileUpToDateStatus(state: SolutionBuilderState, configFile: string, oldestOutputFileTime: Date, oldestOutputFileName: string): Status.OutOfDateWithSelf | undefined { +function checkConfigFileUpToDateStatus( + state: SolutionBuilderState, + configFile: string, + oldestOutputFileTime: Date, + oldestOutputFileName: string, +): Status.OutOfDateWithSelf | undefined { // Check tsconfig time const tsconfigTime = getModifiedTime(state, configFile); if (oldestOutputFileTime < tsconfigTime) { return { type: UpToDateStatusType.OutOfDateWithSelf, outOfDateOutputFileName: oldestOutputFileName, - newerInputFileName: configFile + newerInputFileName: configFile, }; } } -function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { +function getUpToDateStatusWorker( + state: SolutionBuilderState, + project: ParsedCommandLine, + resolvedPath: ResolvedConfigFilePath, +): UpToDateStatus { // Container if no files are specified in the project if (!project.fileNames.length && !canJsonReportNoInputFiles(project.raw)) { return { - type: UpToDateStatusType.ContainerOnly + type: UpToDateStatusType.ContainerOnly, }; } @@ -1719,18 +2039,22 @@ function getUpToDateStatusWorker(state: SolutionBuilde const refStatus = getUpToDateStatus(state, resolvedConfig, resolvedRefPath); // Its a circular reference ignore the status of this project - if (refStatus.type === UpToDateStatusType.ComputingUpstream || - refStatus.type === UpToDateStatusType.ContainerOnly) { // Container only ignore this project + if ( + refStatus.type === UpToDateStatusType.ComputingUpstream + || refStatus.type === UpToDateStatusType.ContainerOnly + ) { // Container only ignore this project continue; } // An upstream project is blocked - if (refStatus.type === UpToDateStatusType.Unbuildable || - refStatus.type === UpToDateStatusType.UpstreamBlocked) { + if ( + refStatus.type === UpToDateStatusType.Unbuildable + || refStatus.type === UpToDateStatusType.UpstreamBlocked + ) { return { type: UpToDateStatusType.UpstreamBlocked, upstreamProjectName: ref.path, - upstreamProjectBlocked: refStatus.type === UpToDateStatusType.UpstreamBlocked + upstreamProjectBlocked: refStatus.type === UpToDateStatusType.UpstreamBlocked, }; } @@ -1738,7 +2062,7 @@ function getUpToDateStatusWorker(state: SolutionBuilde if (refStatus.type !== UpToDateStatusType.UpToDate) { return { type: UpToDateStatusType.UpstreamOutOfDate, - upstreamProjectName: ref.path + upstreamProjectName: ref.path, }; } @@ -1763,12 +2087,12 @@ function getUpToDateStatusWorker(state: SolutionBuilde state.buildInfoCache.set(resolvedPath, { path: toPath(state, buildInfoPath), buildInfo: false, - modifiedTime: buildInfoTime + modifiedTime: buildInfoTime, }); } return { type: UpToDateStatusType.OutputMissing, - missingOutputFileName: buildInfoPath + missingOutputFileName: buildInfoPath, }; } @@ -1777,13 +2101,13 @@ function getUpToDateStatusWorker(state: SolutionBuilde // Error reading buildInfo return { type: UpToDateStatusType.ErrorReadingFile, - fileName: buildInfoPath + fileName: buildInfoPath, }; } if ((buildInfo.bundle || buildInfo.program) && buildInfo.version !== version) { return { type: UpToDateStatusType.TsVersionOutputOfDate, - version: buildInfo.version + version: buildInfo.version, }; } @@ -1794,21 +2118,22 @@ function getUpToDateStatusWorker(state: SolutionBuilde // Checking presence of affectedFilesPendingEmit list is fast and good way to tell if there were semantic errors and file emit was blocked // But if noEmit is true, affectedFilesPendingEmit will have file list even if there are no semantic errors to preserve list of files to be emitted when running with noEmit false // So with noEmit set to true, check on semantic diagnostics needs to be explicit as oppose to when it is false when only files pending emit is sufficient - if ((buildInfo.program as ProgramMultiFileEmitBuildInfo).changeFileSet?.length || - (!project.options.noEmit ? - (buildInfo.program as ProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length : - some((buildInfo.program as ProgramMultiFileEmitBuildInfo).semanticDiagnosticsPerFile, isArray)) + if ( + (buildInfo.program as ProgramMultiFileEmitBuildInfo).changeFileSet?.length + || (!project.options.noEmit + ? (buildInfo.program as ProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit?.length + : some((buildInfo.program as ProgramMultiFileEmitBuildInfo).semanticDiagnosticsPerFile, isArray)) ) { return { type: UpToDateStatusType.OutOfDateBuildInfo, - buildInfoFile: buildInfoPath + buildInfoFile: buildInfoPath, }; } if (!project.options.noEmit && getPendingEmitKind(project.options, buildInfo.program.options || {})) { return { type: UpToDateStatusType.OutOfDateOptions, - buildInfoFile: buildInfoPath + buildInfoFile: buildInfoPath, }; } buildInfoProgram = buildInfo.program; @@ -1830,7 +2155,7 @@ function getUpToDateStatusWorker(state: SolutionBuilde if (inputTime === missingFileModifiedTime) { return { type: UpToDateStatusType.Unbuildable, - reason: `${inputFile} does not exist` + reason: `${inputFile} does not exist`, }; } @@ -1840,7 +2165,9 @@ function getUpToDateStatusWorker(state: SolutionBuilde let currentVersion: string | undefined; if (buildInfoProgram) { // Read files and see if they are same, read is anyways cached - if (!buildInfoVersionMap) buildInfoVersionMap = getBuildInfoFileVersionMap(buildInfoProgram, buildInfoPath!, host); + if (!buildInfoVersionMap) { + buildInfoVersionMap = getBuildInfoFileVersionMap(buildInfoProgram, buildInfoPath!, host); + } version = buildInfoVersionMap.fileInfos.get(toPath(state, inputFile)); const text = version ? state.readFileWithCache(inputFile) : undefined; currentVersion = text !== undefined ? getSourceFileVersionAsHashFromText(host, text) : undefined; @@ -1851,7 +2178,7 @@ function getUpToDateStatusWorker(state: SolutionBuilde return { type: UpToDateStatusType.OutOfDateWithSelf, outOfDateOutputFileName: buildInfoPath!, - newerInputFileName: inputFile + newerInputFileName: inputFile, }; } } @@ -1865,7 +2192,9 @@ function getUpToDateStatusWorker(state: SolutionBuilde } if (buildInfoProgram) { - if (!buildInfoVersionMap) buildInfoVersionMap = getBuildInfoFileVersionMap(buildInfoProgram, buildInfoPath!, host); + if (!buildInfoVersionMap) { + buildInfoVersionMap = getBuildInfoFileVersionMap(buildInfoProgram, buildInfoPath!, host); + } for (const existingRoot of buildInfoVersionMap.roots) { if (!seenRoots.has(existingRoot)) { // File was root file when project was built but its not any more @@ -1896,7 +2225,7 @@ function getUpToDateStatusWorker(state: SolutionBuilde if (outputTime === missingFileModifiedTime) { return { type: UpToDateStatusType.OutputMissing, - missingOutputFileName: output + missingOutputFileName: output, }; } @@ -1905,7 +2234,7 @@ function getUpToDateStatusWorker(state: SolutionBuilde return { type: UpToDateStatusType.OutOfDateWithSelf, outOfDateOutputFileName: output, - newerInputFileName: newestInputFileName + newerInputFileName: newestInputFileName, }; } @@ -1937,14 +2266,21 @@ function getUpToDateStatusWorker(state: SolutionBuilde return { type: UpToDateStatusType.OutOfDateWithUpstream, outOfDateOutputFileName: buildInfoPath!, - newerProjectName: ref.path + newerProjectName: ref.path, }; } // If the upstream project has only change .d.ts files, and we've built // *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild - const newestDeclarationFileContentChangedTime = getLatestChangedDtsTime(state, resolvedConfig.options, resolvedRefPath); - if (newestDeclarationFileContentChangedTime && newestDeclarationFileContentChangedTime <= oldestOutputFileTime) { + const newestDeclarationFileContentChangedTime = getLatestChangedDtsTime( + state, + resolvedConfig.options, + resolvedRefPath, + ); + if ( + newestDeclarationFileContentChangedTime + && newestDeclarationFileContentChangedTime <= oldestOutputFileTime + ) { pseudoUpToDate = true; upstreamChangedProject = ref.path; continue; @@ -1955,23 +2291,31 @@ function getUpToDateStatusWorker(state: SolutionBuilde return { type: UpToDateStatusType.OutOfDateWithUpstream, outOfDateOutputFileName: oldestOutputFileName, - newerProjectName: ref.path + newerProjectName: ref.path, }; } } // Check tsconfig time - const configStatus = checkConfigFileUpToDateStatus(state, project.options.configFilePath!, oldestOutputFileTime, oldestOutputFileName!); + const configStatus = checkConfigFileUpToDateStatus( + state, + project.options.configFilePath!, + oldestOutputFileTime, + oldestOutputFileName!, + ); if (configStatus) return configStatus; // Check extended config time - const extendedConfigStatus = forEach(project.options.configFile!.extendedSourceFiles || emptyArray, configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName!)); + const extendedConfigStatus = forEach( + project.options.configFile!.extendedSourceFiles || emptyArray, + configFile => checkConfigFileUpToDateStatus(state, configFile, oldestOutputFileTime, oldestOutputFileName!), + ); if (extendedConfigStatus) return extendedConfigStatus; // Check package file time const dependentPackageFileStatus = forEach( state.lastCachedPackageJsonLookups.get(resolvedPath) || emptyArray, - ([path]) => checkConfigFileUpToDateStatus(state, path, oldestOutputFileTime, oldestOutputFileName!) + ([path]) => checkConfigFileUpToDateStatus(state, path, oldestOutputFileTime, oldestOutputFileName!), ); if (dependentPackageFileStatus) return dependentPackageFileStatus; @@ -1979,29 +2323,37 @@ function getUpToDateStatusWorker(state: SolutionBuilde return { type: UpToDateStatusType.OutOfDateWithPrepend, outOfDateOutputFileName: oldestOutputFileName!, - newerProjectName: upstreamChangedProject! + newerProjectName: upstreamChangedProject!, }; } // Up to date return { - type: pseudoUpToDate ? - UpToDateStatusType.UpToDateWithUpstreamTypes : - pseudoInputUpToDate ? - UpToDateStatusType.UpToDateWithInputFileText : - UpToDateStatusType.UpToDate, + type: pseudoUpToDate + ? UpToDateStatusType.UpToDateWithUpstreamTypes + : pseudoInputUpToDate + ? UpToDateStatusType.UpToDateWithInputFileText + : UpToDateStatusType.UpToDate, newestInputFileTime, newestInputFileName, - oldestOutputFileName: oldestOutputFileName! + oldestOutputFileName: oldestOutputFileName!, }; } -function hasSameBuildInfo(state: SolutionBuilderState, buildInfoCacheEntry: BuildInfoCacheEntry, resolvedRefPath: ResolvedConfigFilePath) { +function hasSameBuildInfo( + state: SolutionBuilderState, + buildInfoCacheEntry: BuildInfoCacheEntry, + resolvedRefPath: ResolvedConfigFilePath, +) { const refBuildInfo = state.buildInfoCache.get(resolvedRefPath)!; return refBuildInfo.path === buildInfoCacheEntry.path; } -function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLine | undefined, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { +function getUpToDateStatus( + state: SolutionBuilderState, + project: ParsedCommandLine | undefined, + resolvedPath: ResolvedConfigFilePath, +): UpToDateStatus { if (project === undefined) { return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" }; } @@ -2014,7 +2366,11 @@ function getUpToDateStatus(state: SolutionBuilderState performance.mark("SolutionBuilder::beforeUpToDateCheck"); const actual = getUpToDateStatusWorker(state, project, resolvedPath); performance.mark("SolutionBuilder::afterUpToDateCheck"); - performance.measure("SolutionBuilder::Up-to-date check", "SolutionBuilder::beforeUpToDateCheck", "SolutionBuilder::afterUpToDateCheck"); + performance.measure( + "SolutionBuilder::Up-to-date check", + "SolutionBuilder::beforeUpToDateCheck", + "SolutionBuilder::afterUpToDateCheck", + ); state.projectStatus.set(resolvedPath, actual); return actual; } @@ -2024,7 +2380,7 @@ function updateOutputTimestampsWorker( proj: ParsedCommandLine, projectPath: ResolvedConfigFilePath, verboseMessage: DiagnosticMessage, - skipOutputs?: Map + skipOutputs?: Map, ) { if (proj.options.noEmit) return; let now: Date | undefined; @@ -2069,25 +2425,40 @@ function updateOutputTimestampsWorker( }); } -function getLatestChangedDtsTime(state: SolutionBuilderState, options: CompilerOptions, resolvedConfigPath: ResolvedConfigFilePath) { +function getLatestChangedDtsTime( + state: SolutionBuilderState, + options: CompilerOptions, + resolvedConfigPath: ResolvedConfigFilePath, +) { if (!options.composite) return undefined; const entry = Debug.checkDefined(state.buildInfoCache.get(resolvedConfigPath)); if (entry.latestChangedDtsTime !== undefined) return entry.latestChangedDtsTime || undefined; - const latestChangedDtsTime = entry.buildInfo && entry.buildInfo.program && entry.buildInfo.program.latestChangedDtsFile ? - state.host.getModifiedTime(getNormalizedAbsolutePath(entry.buildInfo.program.latestChangedDtsFile, getDirectoryPath(entry.path))) : - undefined; + const latestChangedDtsTime = + entry.buildInfo && entry.buildInfo.program && entry.buildInfo.program.latestChangedDtsFile + ? state.host.getModifiedTime( + getNormalizedAbsolutePath(entry.buildInfo.program.latestChangedDtsFile, getDirectoryPath(entry.path)), + ) + : undefined; entry.latestChangedDtsTime = latestChangedDtsTime || false; return latestChangedDtsTime; } -function updateOutputTimestamps(state: SolutionBuilderState, proj: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath) { +function updateOutputTimestamps( + state: SolutionBuilderState, + proj: ParsedCommandLine, + resolvedPath: ResolvedConfigFilePath, +) { if (state.options.dry) { - return reportStatus(state, Diagnostics.A_non_dry_build_would_update_timestamps_for_output_of_project_0, proj.options.configFilePath!); + return reportStatus( + state, + Diagnostics.A_non_dry_build_would_update_timestamps_for_output_of_project_0, + proj.options.configFilePath!, + ); } updateOutputTimestampsWorker(state, proj, resolvedPath, Diagnostics.Updating_output_timestamps_of_project_0); state.projectStatus.set(resolvedPath, { type: UpToDateStatusType.UpToDate, - oldestOutputFileName: getFirstProjectOutput(proj, !state.host.useCaseSensitiveFileNames()) + oldestOutputFileName: getFirstProjectOutput(proj, !state.host.useCaseSensitiveFileNames()), }); } @@ -2098,7 +2469,7 @@ function queueReferencingProjects( projectIndex: number, config: ParsedCommandLine, buildOrder: readonly ResolvedConfigFileName[], - buildResult: BuildResultFlags + buildResult: BuildResultFlags, ) { // Queue only if there are no errors if (buildResult & BuildResultFlags.AnyErrors) return; @@ -2127,7 +2498,7 @@ function queueReferencingProjects( state.projectStatus.set(nextProjectPath, { type: UpToDateStatusType.OutOfDateWithPrepend, outOfDateOutputFileName: status.oldestOutputFileName, - newerProjectName: project + newerProjectName: project, }); } else { @@ -2143,14 +2514,18 @@ function queueReferencingProjects( if (!(buildResult & BuildResultFlags.DeclarationOutputUnchanged)) { state.projectStatus.set(nextProjectPath, { type: UpToDateStatusType.OutOfDateWithUpstream, - outOfDateOutputFileName: status.type === UpToDateStatusType.OutOfDateWithPrepend ? status.outOfDateOutputFileName : status.oldestOutputFileName, - newerProjectName: project + outOfDateOutputFileName: status.type === UpToDateStatusType.OutOfDateWithPrepend + ? status.outOfDateOutputFileName : status.oldestOutputFileName, + newerProjectName: project, }); } break; case UpToDateStatusType.UpstreamBlocked: - if (toResolvedConfigFilePath(state, resolveProjectName(state, status.upstreamProjectName)) === projectPath) { + if ( + toResolvedConfigFilePath(state, resolveProjectName(state, status.upstreamProjectName)) + === projectPath + ) { clearProjectStatus(state, nextProjectPath); } break; @@ -2162,7 +2537,14 @@ function queueReferencingProjects( } } -function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers, onlyReferences?: boolean): ExitStatus { +function build( + state: SolutionBuilderState, + project?: string, + cancellationToken?: CancellationToken, + writeFile?: WriteFileCallback, + getCustomTransformers?: (project: string) => CustomTransformers, + onlyReferences?: boolean, +): ExitStatus { performance.mark("SolutionBuilder::beforeBuild"); const result = buildWorker(state, project, cancellationToken, writeFile, getCustomTransformers, onlyReferences); performance.mark("SolutionBuilder::afterBuild"); @@ -2170,7 +2552,14 @@ function build(state: SolutionBuilderState, project return result; } -function buildWorker(state: SolutionBuilderState, project: string | undefined, cancellationToken: CancellationToken | undefined, writeFile: WriteFileCallback | undefined, getCustomTransformers: ((project: string) => CustomTransformers) | undefined, onlyReferences: boolean | undefined): ExitStatus { +function buildWorker( + state: SolutionBuilderState, + project: string | undefined, + cancellationToken: CancellationToken | undefined, + writeFile: WriteFileCallback | undefined, + getCustomTransformers: ((project: string) => CustomTransformers) | undefined, + onlyReferences: boolean | undefined, +): ExitStatus { const buildOrder = getBuildOrderFor(state, project, onlyReferences); if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped; @@ -2193,13 +2582,17 @@ function buildWorker(state: SolutionBuilderState, p return isCircularBuildOrder(buildOrder) ? ExitStatus.ProjectReferenceCycle_OutputsSkipped : !buildOrder.some(p => state.diagnostics.has(toResolvedConfigFilePath(state, p))) - ? ExitStatus.Success - : successfulProjects - ? ExitStatus.DiagnosticsPresent_OutputsGenerated - : ExitStatus.DiagnosticsPresent_OutputsSkipped; + ? ExitStatus.Success + : successfulProjects + ? ExitStatus.DiagnosticsPresent_OutputsGenerated + : ExitStatus.DiagnosticsPresent_OutputsSkipped; } -function clean(state: SolutionBuilderState, project?: string, onlyReferences?: boolean): ExitStatus { +function clean( + state: SolutionBuilderState, + project?: string, + onlyReferences?: boolean, +): ExitStatus { performance.mark("SolutionBuilder::beforeClean"); const result = cleanWorker(state, project, onlyReferences); performance.mark("SolutionBuilder::afterClean"); @@ -2207,7 +2600,11 @@ function clean(state: SolutionBuilderState, project return result; } -function cleanWorker(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) { +function cleanWorker( + state: SolutionBuilderState, + project: string | undefined, + onlyReferences: boolean | undefined, +) { const buildOrder = getBuildOrderFor(state, project, onlyReferences); if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped; @@ -2245,13 +2642,21 @@ function cleanWorker(state: SolutionBuilderState, p } if (filesToDelete) { - reportStatus(state, Diagnostics.A_non_dry_build_would_delete_the_following_files_Colon_0, filesToDelete.map(f => `\r\n * ${f}`).join("")); + reportStatus( + state, + Diagnostics.A_non_dry_build_would_delete_the_following_files_Colon_0, + filesToDelete.map(f => `\r\n * ${f}`).join(""), + ); } return ExitStatus.Success; } -function invalidateProject(state: SolutionBuilderState, resolved: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function invalidateProject( + state: SolutionBuilderState, + resolved: ResolvedConfigFilePath, + reloadLevel: ConfigFileProgramReloadLevel, +) { // If host implements getParsedCommandLine, we cant get list of files from parseConfigFileHost if (state.host.getParsedCommandLine && reloadLevel === ConfigFileProgramReloadLevel.Partial) { reloadLevel = ConfigFileProgramReloadLevel.Full; @@ -2266,13 +2671,21 @@ function invalidateProject(state: SolutionBuilderState enableCache(state); } -function invalidateProjectAndScheduleBuilds(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function invalidateProjectAndScheduleBuilds( + state: SolutionBuilderState, + resolvedPath: ResolvedConfigFilePath, + reloadLevel: ConfigFileProgramReloadLevel, +) { state.reportFileChangeDetected = true; invalidateProject(state, resolvedPath, reloadLevel); scheduleBuildInvalidatedProject(state, 250, /*changeDetected*/ true); } -function scheduleBuildInvalidatedProject(state: SolutionBuilderState, time: number, changeDetected: boolean) { +function scheduleBuildInvalidatedProject( + state: SolutionBuilderState, + time: number, + changeDetected: boolean, +) { const { hostWithWatch } = state; if (!hostWithWatch.setTimeout || !hostWithWatch.clearTimeout) { return; @@ -2280,10 +2693,20 @@ function scheduleBuildInvalidatedProject(state: Soluti if (state.timerToBuildInvalidatedProject) { hostWithWatch.clearTimeout(state.timerToBuildInvalidatedProject); } - state.timerToBuildInvalidatedProject = hostWithWatch.setTimeout(buildNextInvalidatedProject, time, "timerToBuildInvalidatedProject", state, changeDetected); + state.timerToBuildInvalidatedProject = hostWithWatch.setTimeout( + buildNextInvalidatedProject, + time, + "timerToBuildInvalidatedProject", + state, + changeDetected, + ); } -function buildNextInvalidatedProject(_timeoutType: string, state: SolutionBuilderState, changeDetected: boolean) { +function buildNextInvalidatedProject( + _timeoutType: string, + state: SolutionBuilderState, + changeDetected: boolean, +) { performance.mark("SolutionBuilder::beforeBuild"); const buildOrder = buildNextInvalidatedProjectWorker(state, changeDetected); performance.mark("SolutionBuilder::afterBuild"); @@ -2291,7 +2714,10 @@ function buildNextInvalidatedProject(_timeoutType: str if (buildOrder) reportErrorSummary(state, buildOrder); } -function buildNextInvalidatedProjectWorker(state: SolutionBuilderState, changeDetected: boolean) { +function buildNextInvalidatedProjectWorker( + state: SolutionBuilderState, + changeDetected: boolean, +) { state.timerToBuildInvalidatedProject = undefined; if (state.reportFileChangeDetected) { state.reportFileChangeDetected = false; @@ -2310,7 +2736,9 @@ function buildNextInvalidatedProjectWorker(state: Solu // Before scheduling check if the next project needs build const info = getNextInvalidatedProjectCreateInfo(state, buildOrder, /*reportQueue*/ false); if (!info) break; // Nothing to build any more - if (info.kind !== InvalidatedProjectKind.UpdateOutputFileStamps && (changeDetected || projectsBuilt === 5)) { + if ( + info.kind !== InvalidatedProjectKind.UpdateOutputFileStamps && (changeDetected || projectsBuilt === 5) + ) { // Schedule next project for build scheduleBuildInvalidatedProject(state, 100, /*changeDetected*/ false); return; @@ -2324,105 +2752,146 @@ function buildNextInvalidatedProjectWorker(state: Solu return buildOrder; } -function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { +function watchConfigFile( + state: SolutionBuilderState, + resolved: ResolvedConfigFileName, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine | undefined, +) { if (!state.watch || state.allWatchedConfigFiles.has(resolvedPath)) return; - state.allWatchedConfigFiles.set(resolvedPath, watchFile( - state, - resolved, - () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Full), - PollingInterval.High, - parsed?.watchOptions, - WatchType.ConfigFile, - resolved - )); + state.allWatchedConfigFiles.set( + resolvedPath, + watchFile( + state, + resolved, + () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Full), + PollingInterval.High, + parsed?.watchOptions, + WatchType.ConfigFile, + resolved, + ), + ); } -function watchExtendedConfigFiles(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { +function watchExtendedConfigFiles( + state: SolutionBuilderState, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine | undefined, +) { updateSharedExtendedConfigFileWatcher( resolvedPath, parsed?.options, state.allWatchedExtendedConfigFiles, - (extendedConfigFileName, extendedConfigFilePath) => watchFile( - state, - extendedConfigFileName, - () => state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach(projectConfigFilePath => - invalidateProjectAndScheduleBuilds(state, projectConfigFilePath, ConfigFileProgramReloadLevel.Full)), - PollingInterval.High, - parsed?.watchOptions, - WatchType.ExtendedConfigFile, - ), + (extendedConfigFileName, extendedConfigFilePath) => + watchFile( + state, + extendedConfigFileName, + () => + state.allWatchedExtendedConfigFiles.get(extendedConfigFilePath)?.projects.forEach( + projectConfigFilePath => + invalidateProjectAndScheduleBuilds( + state, + projectConfigFilePath, + ConfigFileProgramReloadLevel.Full, + ), + ), + PollingInterval.High, + parsed?.watchOptions, + WatchType.ExtendedConfigFile, + ), fileName => toPath(state, fileName), ); } -function watchWildCardDirectories(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { +function watchWildCardDirectories( + state: SolutionBuilderState, + resolved: ResolvedConfigFileName, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine, +) { if (!state.watch) return; updateWatchingWildcardDirectories( getOrCreateValueMapFromConfigFileMap(state.allWatchedWildcardDirectories, resolvedPath), new Map(Object.entries(parsed.wildcardDirectories!)), - (dir, flags) => state.watchDirectory( - dir, - fileOrDirectory => { - if (isIgnoredFileFromWildCardWatching({ - watchedDirPath: toPath(state, dir), - fileOrDirectory, - fileOrDirectoryPath: toPath(state, fileOrDirectory), - configFileName: resolved, - currentDirectory: state.compilerHost.getCurrentDirectory(), - options: parsed.options, - program: state.builderPrograms.get(resolvedPath) || getCachedParsedConfigFile(state, resolvedPath)?.fileNames, - useCaseSensitiveFileNames: state.parseConfigFileHost.useCaseSensitiveFileNames, - writeLog: s => state.writeLog(s), - toPath: fileName => toPath(state, fileName) - })) return; - - invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Partial); - }, - flags, - parsed?.watchOptions, - WatchType.WildcardDirectory, - resolved - ) + (dir, flags) => + state.watchDirectory( + dir, + fileOrDirectory => { + if ( + isIgnoredFileFromWildCardWatching({ + watchedDirPath: toPath(state, dir), + fileOrDirectory, + fileOrDirectoryPath: toPath(state, fileOrDirectory), + configFileName: resolved, + currentDirectory: state.compilerHost.getCurrentDirectory(), + options: parsed.options, + program: state.builderPrograms.get(resolvedPath) + || getCachedParsedConfigFile(state, resolvedPath)?.fileNames, + useCaseSensitiveFileNames: state.parseConfigFileHost.useCaseSensitiveFileNames, + writeLog: s => state.writeLog(s), + toPath: fileName => toPath(state, fileName), + }) + ) return; + + invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.Partial); + }, + flags, + parsed?.watchOptions, + WatchType.WildcardDirectory, + resolved, + ), ); } -function watchInputFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { +function watchInputFiles( + state: SolutionBuilderState, + resolved: ResolvedConfigFileName, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine, +) { if (!state.watch) return; mutateMap( getOrCreateValueMapFromConfigFileMap(state.allWatchedInputFiles, resolvedPath), arrayToMap(parsed.fileNames, fileName => toPath(state, fileName)), { - createNewValue: (_path, input) => watchFile( - state, - input, - () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), - PollingInterval.Low, - parsed?.watchOptions, - WatchType.SourceFile, - resolved - ), + createNewValue: (_path, input) => + watchFile( + state, + input, + () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), + PollingInterval.Low, + parsed?.watchOptions, + WatchType.SourceFile, + resolved, + ), onDeleteValue: closeFileWatcher, - } + }, ); } -function watchPackageJsonFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { +function watchPackageJsonFiles( + state: SolutionBuilderState, + resolved: ResolvedConfigFileName, + resolvedPath: ResolvedConfigFilePath, + parsed: ParsedCommandLine, +) { if (!state.watch || !state.lastCachedPackageJsonLookups) return; mutateMap( getOrCreateValueMapFromConfigFileMap(state.allWatchedPackageJsonFiles, resolvedPath), new Map(state.lastCachedPackageJsonLookups.get(resolvedPath)), { - createNewValue: (path, _input) => watchFile( - state, - path, - () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), - PollingInterval.High, - parsed?.watchOptions, - WatchType.PackageJson, - resolved - ), + createNewValue: (path, _input) => + watchFile( + state, + path, + () => invalidateProjectAndScheduleBuilds(state, resolvedPath, ConfigFileProgramReloadLevel.None), + PollingInterval.High, + parsed?.watchOptions, + WatchType.PackageJson, + resolved, + ), onDeleteValue: closeFileWatcher, - } + }, ); } @@ -2448,29 +2917,61 @@ function startWatching(state: SolutionBuilderState, } } performance.mark("SolutionBuilder::afterWatcherCreation"); - performance.measure("SolutionBuilder::Watcher creation", "SolutionBuilder::beforeWatcherCreation", "SolutionBuilder::afterWatcherCreation"); + performance.measure( + "SolutionBuilder::Watcher creation", + "SolutionBuilder::beforeWatcherCreation", + "SolutionBuilder::afterWatcherCreation", + ); } function stopWatching(state: SolutionBuilderState) { clearMap(state.allWatchedConfigFiles, closeFileWatcher); clearMap(state.allWatchedExtendedConfigFiles, closeFileWatcherOf); - clearMap(state.allWatchedWildcardDirectories, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcherOf)); - clearMap(state.allWatchedInputFiles, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcher)); - clearMap(state.allWatchedPackageJsonFiles, watchedPacageJsonFiles => clearMap(watchedPacageJsonFiles, closeFileWatcher)); + clearMap( + state.allWatchedWildcardDirectories, + watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcherOf), + ); + clearMap( + state.allWatchedInputFiles, + watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcher), + ); + clearMap( + state.allWatchedPackageJsonFiles, + watchedPacageJsonFiles => clearMap(watchedPacageJsonFiles, closeFileWatcher), + ); } /** * A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but * can dynamically add/remove other projects based on changes on the rootNames' references */ -function createSolutionBuilderWorker(watch: false, host: SolutionBuilderHost, rootNames: readonly string[], defaultOptions: BuildOptions): SolutionBuilder; -function createSolutionBuilderWorker(watch: true, host: SolutionBuilderWithWatchHost, rootNames: readonly string[], defaultOptions: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder; -function createSolutionBuilderWorker(watch: boolean, hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, rootNames: readonly string[], options: BuildOptions, baseWatchOptions?: WatchOptions): SolutionBuilder { +function createSolutionBuilderWorker( + watch: false, + host: SolutionBuilderHost, + rootNames: readonly string[], + defaultOptions: BuildOptions, +): SolutionBuilder; +function createSolutionBuilderWorker( + watch: true, + host: SolutionBuilderWithWatchHost, + rootNames: readonly string[], + defaultOptions: BuildOptions, + baseWatchOptions?: WatchOptions, +): SolutionBuilder; +function createSolutionBuilderWorker( + watch: boolean, + hostOrHostWithWatch: SolutionBuilderHost | SolutionBuilderWithWatchHost, + rootNames: readonly string[], + options: BuildOptions, + baseWatchOptions?: WatchOptions, +): SolutionBuilder { const state = createSolutionBuilderState(watch, hostOrHostWithWatch, rootNames, options, baseWatchOptions); return { - build: (project, cancellationToken, writeFile, getCustomTransformers) => build(state, project, cancellationToken, writeFile, getCustomTransformers), + build: (project, cancellationToken, writeFile, getCustomTransformers) => + build(state, project, cancellationToken, writeFile, getCustomTransformers), clean: project => clean(state, project), - buildReferences: (project, cancellationToken, writeFile, getCustomTransformers) => build(state, project, cancellationToken, writeFile, getCustomTransformers, /*onlyReferences*/ true), + buildReferences: (project, cancellationToken, writeFile, getCustomTransformers) => + build(state, project, cancellationToken, writeFile, getCustomTransformers, /*onlyReferences*/ true), cleanReferences: project => clean(state, project, /*onlyReferences*/ true), getNextInvalidatedProject: cancellationToken => { setupInitialBuild(state, cancellationToken); @@ -2482,28 +2983,49 @@ function createSolutionBuilderWorker(watch: boolean, h const configFilePath = toResolvedConfigFilePath(state, configFileName); return getUpToDateStatus(state, parseConfigFile(state, configFileName, configFilePath), configFilePath); }, - invalidateProject: (configFilePath, reloadLevel) => invalidateProject(state, configFilePath, reloadLevel || ConfigFileProgramReloadLevel.None), + invalidateProject: (configFilePath, reloadLevel) => + invalidateProject(state, configFilePath, reloadLevel || ConfigFileProgramReloadLevel.None), close: () => stopWatching(state), }; } function relName(state: SolutionBuilderState, path: string): string { - return convertToRelativePath(path, state.compilerHost.getCurrentDirectory(), state.compilerHost.getCanonicalFileName); + return convertToRelativePath( + path, + state.compilerHost.getCurrentDirectory(), + state.compilerHost.getCanonicalFileName, + ); } -function reportStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: DiagnosticArguments) { +function reportStatus( + state: SolutionBuilderState, + message: DiagnosticMessage, + ...args: DiagnosticArguments +) { state.host.reportSolutionBuilderStatus(createCompilerDiagnostic(message, ...args)); } -function reportWatchStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: DiagnosticArguments) { - state.hostWithWatch.onWatchStatusChange?.(createCompilerDiagnostic(message, ...args), state.host.getNewLine(), state.baseCompilerOptions); +function reportWatchStatus( + state: SolutionBuilderState, + message: DiagnosticMessage, + ...args: DiagnosticArguments +) { + state.hostWithWatch.onWatchStatusChange?.( + createCompilerDiagnostic(message, ...args), + state.host.getNewLine(), + state.baseCompilerOptions, + ); } function reportErrors({ host }: SolutionBuilderState, errors: readonly Diagnostic[]) { errors.forEach(err => host.reportDiagnostic(err)); } -function reportAndStoreErrors(state: SolutionBuilderState, proj: ResolvedConfigFilePath, errors: readonly Diagnostic[]) { +function reportAndStoreErrors( + state: SolutionBuilderState, + proj: ResolvedConfigFilePath, + errors: readonly Diagnostic[], +) { reportErrors(state, errors); state.projectErrorsReported.set(proj, true); if (errors.length) { @@ -2511,7 +3033,10 @@ function reportAndStoreErrors(state: SolutionBuilderSt } } -function reportParseConfigFileDiagnostic(state: SolutionBuilderState, proj: ResolvedConfigFilePath) { +function reportParseConfigFileDiagnostic( + state: SolutionBuilderState, + proj: ResolvedConfigFilePath, +) { reportAndStoreErrors(state, proj, [state.configFileCache.get(proj) as Diagnostic]); } @@ -2526,7 +3051,9 @@ function reportErrorSummary(state: SolutionBuilderStat reportBuildQueue(state, buildOrder.buildOrder); reportErrors(state, buildOrder.circularDiagnostics); if (canReportSummary) totalErrors += getErrorCountForSummary(buildOrder.circularDiagnostics); - if (canReportSummary) filesInError = [...filesInError, ...getFilesInErrorForSummary(buildOrder.circularDiagnostics)]; + if (canReportSummary) { + filesInError = [...filesInError, ...getFilesInErrorForSummary(buildOrder.circularDiagnostics)]; + } } else { // Report errors from the other projects @@ -2536,8 +3063,14 @@ function reportErrorSummary(state: SolutionBuilderStat reportErrors(state, diagnostics.get(projectPath) || emptyArray); } }); - if (canReportSummary) diagnostics.forEach(singleProjectErrors => totalErrors += getErrorCountForSummary(singleProjectErrors)); - if (canReportSummary) diagnostics.forEach(singleProjectErrors => [...filesInError, ...getFilesInErrorForSummary(singleProjectErrors)]); + if (canReportSummary) { + diagnostics.forEach(singleProjectErrors => totalErrors += getErrorCountForSummary(singleProjectErrors)); + } + if (canReportSummary) { + diagnostics.forEach( + singleProjectErrors => [...filesInError, ...getFilesInErrorForSummary(singleProjectErrors)], + ); + } } if (state.watch) { @@ -2551,13 +3084,24 @@ function reportErrorSummary(state: SolutionBuilderStat /** * Report the build ordering inferred from the current project graph if we're in verbose mode */ -function reportBuildQueue(state: SolutionBuilderState, buildQueue: readonly ResolvedConfigFileName[]) { +function reportBuildQueue( + state: SolutionBuilderState, + buildQueue: readonly ResolvedConfigFileName[], +) { if (state.options.verbose) { - reportStatus(state, Diagnostics.Projects_in_this_build_Colon_0, buildQueue.map(s => "\r\n * " + relName(state, s)).join("")); + reportStatus( + state, + Diagnostics.Projects_in_this_build_Colon_0, + buildQueue.map(s => "\r\n * " + relName(state, s)).join(""), + ); } } -function reportUpToDateStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { +function reportUpToDateStatus( + state: SolutionBuilderState, + configFileName: string, + status: UpToDateStatus, +) { switch (status.type) { case UpToDateStatusType.OutOfDateWithSelf: return reportStatus( @@ -2565,7 +3109,7 @@ function reportUpToDateStatus(state: SolutionBuilderSt Diagnostics.Project_0_is_out_of_date_because_output_1_is_older_than_input_2, relName(state, configFileName), relName(state, status.outOfDateOutputFileName), - relName(state, status.newerInputFileName) + relName(state, status.newerInputFileName), ); case UpToDateStatusType.OutOfDateWithUpstream: return reportStatus( @@ -2573,40 +3117,43 @@ function reportUpToDateStatus(state: SolutionBuilderSt Diagnostics.Project_0_is_out_of_date_because_output_1_is_older_than_input_2, relName(state, configFileName), relName(state, status.outOfDateOutputFileName), - relName(state, status.newerProjectName) + relName(state, status.newerProjectName), ); case UpToDateStatusType.OutputMissing: return reportStatus( state, Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, relName(state, configFileName), - relName(state, status.missingOutputFileName) + relName(state, status.missingOutputFileName), ); case UpToDateStatusType.ErrorReadingFile: return reportStatus( state, Diagnostics.Project_0_is_out_of_date_because_there_was_error_reading_file_1, relName(state, configFileName), - relName(state, status.fileName) + relName(state, status.fileName), ); case UpToDateStatusType.OutOfDateBuildInfo: return reportStatus( state, - Diagnostics.Project_0_is_out_of_date_because_buildinfo_file_1_indicates_that_some_of_the_changes_were_not_emitted, + Diagnostics + .Project_0_is_out_of_date_because_buildinfo_file_1_indicates_that_some_of_the_changes_were_not_emitted, relName(state, configFileName), - relName(state, status.buildInfoFile) + relName(state, status.buildInfoFile), ); case UpToDateStatusType.OutOfDateOptions: return reportStatus( state, - Diagnostics.Project_0_is_out_of_date_because_buildinfo_file_1_indicates_there_is_change_in_compilerOptions, + Diagnostics + .Project_0_is_out_of_date_because_buildinfo_file_1_indicates_there_is_change_in_compilerOptions, relName(state, configFileName), - relName(state, status.buildInfoFile) + relName(state, status.buildInfoFile), ); case UpToDateStatusType.OutOfDateRoots: return reportStatus( state, - Diagnostics.Project_0_is_out_of_date_because_buildinfo_file_1_indicates_that_file_2_was_root_file_of_compilation_but_not_any_more, + Diagnostics + .Project_0_is_out_of_date_because_buildinfo_file_1_indicates_that_file_2_was_root_file_of_compilation_but_not_any_more, relName(state, configFileName), relName(state, status.buildInfoFile), relName(state, status.inputFile), @@ -2618,7 +3165,7 @@ function reportUpToDateStatus(state: SolutionBuilderSt Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_output_2, relName(state, configFileName), relName(state, status.newestInputFileName || ""), - relName(state, status.oldestOutputFileName || "") + relName(state, status.oldestOutputFileName || ""), ); } // Don't report anything for "up to date because it was already built" -- too verbose @@ -2628,56 +3175,58 @@ function reportUpToDateStatus(state: SolutionBuilderSt state, Diagnostics.Project_0_is_out_of_date_because_output_of_its_dependency_1_has_changed, relName(state, configFileName), - relName(state, status.newerProjectName) + relName(state, status.newerProjectName), ); case UpToDateStatusType.UpToDateWithUpstreamTypes: return reportStatus( state, Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies, - relName(state, configFileName) + relName(state, configFileName), ); case UpToDateStatusType.UpToDateWithInputFileText: return reportStatus( state, - Diagnostics.Project_0_is_up_to_date_but_needs_to_update_timestamps_of_output_files_that_are_older_than_input_files, - relName(state, configFileName) + Diagnostics + .Project_0_is_up_to_date_but_needs_to_update_timestamps_of_output_files_that_are_older_than_input_files, + relName(state, configFileName), ); case UpToDateStatusType.UpstreamOutOfDate: return reportStatus( state, Diagnostics.Project_0_is_out_of_date_because_its_dependency_1_is_out_of_date, relName(state, configFileName), - relName(state, status.upstreamProjectName) + relName(state, status.upstreamProjectName), ); case UpToDateStatusType.UpstreamBlocked: return reportStatus( state, - status.upstreamProjectBlocked ? - Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_was_not_built : - Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, + status.upstreamProjectBlocked + ? Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_was_not_built + : Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, relName(state, configFileName), - relName(state, status.upstreamProjectName) + relName(state, status.upstreamProjectName), ); case UpToDateStatusType.Unbuildable: return reportStatus( state, Diagnostics.Failed_to_parse_file_0_Colon_1, relName(state, configFileName), - status.reason + status.reason, ); case UpToDateStatusType.TsVersionOutputOfDate: return reportStatus( state, - Diagnostics.Project_0_is_out_of_date_because_output_for_it_was_generated_with_version_1_that_differs_with_current_version_2, + Diagnostics + .Project_0_is_out_of_date_because_output_for_it_was_generated_with_version_1_that_differs_with_current_version_2, relName(state, configFileName), status.version, - version + version, ); case UpToDateStatusType.ForceBuild: return reportStatus( state, Diagnostics.Project_0_is_being_forcibly_rebuilt, - relName(state, configFileName) + relName(state, configFileName), ); case UpToDateStatusType.ContainerOnly: // Don't report status on "solution" projects @@ -2693,7 +3242,11 @@ function reportUpToDateStatus(state: SolutionBuilderSt /** * Report the up-to-date status of a project if we're in verbose mode */ -function verboseReportProjectStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { +function verboseReportProjectStatus( + state: SolutionBuilderState, + configFileName: string, + status: UpToDateStatus, +) { if (state.options.verbose) { reportUpToDateStatus(state, configFileName, status); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5432adf33ebb5..a105994334a48 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -21,10 +21,11 @@ import { // branded string type used to store absolute, normalized and canonicalized paths // arbitrary file name can be converted to Path via toPath function -export type Path = string & { __pathBrand: any }; +export type Path = string & { __pathBrand: any; }; /** @internal */ -export type MatchingKeys = K extends (TRecord[K] extends TMatch ? K : never) ? K : never; +export type MatchingKeys = K extends + (TRecord[K] extends TMatch ? K : never) ? K : never; export interface TextRange { pos: number; @@ -500,8 +501,7 @@ export type TriviaSyntaxKind = | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia - | SyntaxKind.ConflictMarkerTrivia - ; + | SyntaxKind.ConflictMarkerTrivia; export type LiteralSyntaxKind = | SyntaxKind.NumericLiteral @@ -510,14 +510,12 @@ export type LiteralSyntaxKind = | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral - | SyntaxKind.NoSubstitutionTemplateLiteral - ; + | SyntaxKind.NoSubstitutionTemplateLiteral; export type PseudoLiteralSyntaxKind = | SyntaxKind.TemplateHead | SyntaxKind.TemplateMiddle - | SyntaxKind.TemplateTail - ; + | SyntaxKind.TemplateTail; export type PunctuationSyntaxKind = | SyntaxKind.OpenBraceToken @@ -580,8 +578,7 @@ export type PunctuationSyntaxKind = | SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken | SyntaxKind.AmpersandEqualsToken | SyntaxKind.BarEqualsToken - | SyntaxKind.CaretEqualsToken - ; + | SyntaxKind.CaretEqualsToken; /** @internal */ export type PunctuationOrKeywordSyntaxKind = PunctuationSyntaxKind | KeywordSyntaxKind; @@ -669,8 +666,7 @@ export type KeywordSyntaxKind = | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword - | SyntaxKind.YieldKeyword - ; + | SyntaxKind.YieldKeyword; export type ModifierSyntaxKind = | SyntaxKind.AbstractKeyword @@ -687,8 +683,7 @@ export type ModifierSyntaxKind = | SyntaxKind.ReadonlyKeyword | SyntaxKind.OutKeyword | SyntaxKind.OverrideKeyword - | SyntaxKind.StaticKeyword - ; + | SyntaxKind.StaticKeyword; export type KeywordTypeSyntaxKind = | SyntaxKind.AnyKeyword @@ -702,8 +697,7 @@ export type KeywordTypeSyntaxKind = | SyntaxKind.SymbolKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UnknownKeyword - | SyntaxKind.VoidKeyword - ; + | SyntaxKind.VoidKeyword; /** @internal */ export type TypeNodeSyntaxKind = @@ -743,8 +737,7 @@ export type TypeNodeSyntaxKind = | SyntaxKind.JSDocVariadicType | SyntaxKind.JSDocNamepathType | SyntaxKind.JSDocSignature - | SyntaxKind.JSDocTypeLiteral - ; + | SyntaxKind.JSDocTypeLiteral; export type TokenSyntaxKind = | SyntaxKind.Unknown @@ -754,8 +747,7 @@ export type TokenSyntaxKind = | PseudoLiteralSyntaxKind | PunctuationSyntaxKind | SyntaxKind.Identifier - | KeywordSyntaxKind - ; + | KeywordSyntaxKind; export type JsxTokenSyntaxKind = | SyntaxKind.LessThanSlashToken @@ -764,8 +756,7 @@ export type JsxTokenSyntaxKind = | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken - | SyntaxKind.LessThanToken - ; + | SyntaxKind.LessThanToken; export type JSDocSyntaxKind = | SyntaxKind.EndOfFileToken @@ -786,9 +777,9 @@ export type JSDocSyntaxKind = | SyntaxKind.BacktickToken | SyntaxKind.HashToken | SyntaxKind.Unknown - | KeywordSyntaxKind - ; + | KeywordSyntaxKind; +// dprint-ignore export const enum NodeFlags { None = 0, Let = 1 << 0, // Variable declaration @@ -856,6 +847,7 @@ export const enum NodeFlags { /** @internal */ IdentifierIsInJSDocNamespace = HasAsyncFunctions, // Indicates whether the identifier is part of a JSDoc namespace } +// dprint-ignore export const enum ModifierFlags { None = 0, Export = 1 << 0, // Declarations @@ -887,7 +879,7 @@ export const enum ModifierFlags { TypeScriptModifier = Ambient | Public | Private | Protected | Readonly | Abstract | Const | Override | In | Out, ExportDefault = Export | Default, All = Export | Ambient | Public | Private | Protected | Static | Readonly | Abstract | Accessor | Async | Default | Const | Deprecated | Override | In | Out | Decorator, - Modifier = All & ~Decorator + Modifier = All & ~Decorator, } export const enum JsxFlags { @@ -900,6 +892,7 @@ export const enum JsxFlags { IntrinsicElement = IntrinsicNamedElement | IntrinsicIndexedElement, } +// dprint-ignore /** @internal */ export const enum RelationComparisonResult { Succeeded = 1 << 0, // Should be truthy @@ -908,7 +901,7 @@ export const enum RelationComparisonResult { ReportsUnmeasurable = 1 << 3, ReportsUnreliable = 1 << 4, - ReportsMask = ReportsUnmeasurable | ReportsUnreliable + ReportsMask = ReportsUnmeasurable | ReportsUnreliable, } /** @internal */ @@ -919,10 +912,10 @@ export interface Node extends ReadonlyTextRange { readonly flags: NodeFlags; /** @internal */ modifierFlagsCache: ModifierFlags; /** @internal */ readonly transformFlags: TransformFlags; // Flags for transforms - /** @internal */ id?: NodeId; // Unique id (used to look up NodeLinks) - readonly parent: Node; // Parent node (initialized by binding) - /** @internal */ original?: Node; // The original node if this is an updated node. - /** @internal */ emitNode?: EmitNode; // Associated EmitNode (initialized by transforms) + /** @internal */ id?: NodeId; // Unique id (used to look up NodeLinks) + readonly parent: Node; // Parent node (initialized by binding) + /** @internal */ original?: Node; // The original node if this is an updated node. + /** @internal */ emitNode?: EmitNode; // Associated EmitNode (initialized by transforms) // NOTE: `symbol` and `localSymbol` have been moved to `Declaration` // `locals` and `nextContainer` have been moved to `LocalsContainer` // `flowNode` has been moved to `FlowContainer` @@ -931,23 +924,23 @@ export interface Node extends ReadonlyTextRange { export interface JSDocContainer extends Node { _jsdocContainerBrand: any; - /** @internal */ jsDoc?: JSDocArray; // JSDoc that directly precedes this node + /** @internal */ jsDoc?: JSDocArray; // JSDoc that directly precedes this node } /** @internal */ export interface JSDocArray extends Array { - jsDocCache?: readonly JSDocTag[]; // Cache for getJSDocTags + jsDocCache?: readonly JSDocTag[]; // Cache for getJSDocTags } export interface LocalsContainer extends Node { _localsContainerBrand: any; - /** @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) - /** @internal */ nextContainer?: HasLocals; // Next container in declaration order (initialized by binding) + /** @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) + /** @internal */ nextContainer?: HasLocals; // Next container in declaration order (initialized by binding) } export interface FlowContainer extends Node { _flowContainerBrand: any; - /** @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding) + /** @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding) } /** @internal */ @@ -981,8 +974,7 @@ export type HasFlowNode = | LabeledStatement | ThrowStatement | TryStatement - | DebuggerStatement - ; + | DebuggerStatement; // Ideally, `ForEachChildNodes` and `VisitEachChildNodes` would not differ. // However, `forEachChild` currently processes JSDoc comment syntax and missing declarations more thoroughly. @@ -1030,8 +1022,7 @@ export type ForEachChildNodes = | JSDocThrowsTag | JSDocOverrideTag | JSDocSatisfiesTag - | JSDocOverloadTag - ; + | JSDocOverloadTag; /** @internal */ export type HasChildren = @@ -1169,8 +1160,7 @@ export type HasChildren = | EnumMember | SourceFile | PartiallyEmittedExpression - | CommaListExpression - ; + | CommaListExpression; export type HasJSDoc = | AccessorDeclaration @@ -1236,8 +1226,7 @@ export type HasJSDoc = | VariableDeclaration | VariableStatement | WhileStatement - | WithStatement - ; + | WithStatement; export type HasType = | SignatureDeclaration @@ -1255,16 +1244,14 @@ export type HasType = | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType - | JSDocVariadicType - ; + | JSDocVariadicType; // NOTE: Changing the following list requires changes to: // - `canHaveIllegalType` in factory/utilities.ts /** @internal */ export type HasIllegalType = | ConstructorDeclaration - | SetAccessorDeclaration - ; + | SetAccessorDeclaration; // NOTE: Changing the following list requires changes to: // - `canHaveIllegalTypeParameters` in factory/utilities.ts @@ -1272,8 +1259,7 @@ export type HasIllegalType = export type HasIllegalTypeParameters = | ConstructorDeclaration | SetAccessorDeclaration - | GetAccessorDeclaration - ; + | GetAccessorDeclaration; export type HasTypeArguments = | CallExpression @@ -1287,8 +1273,7 @@ export type HasInitializer = | ForStatement | ForInStatement | ForOfStatement - | JsxAttribute - ; + | JsxAttribute; export type HasExpressionInitializer = | VariableDeclaration @@ -1296,13 +1281,10 @@ export type HasExpressionInitializer = | BindingElement | PropertyDeclaration | PropertyAssignment - | EnumMember - ; + | EnumMember; /** @internal */ -export type HasIllegalExpressionInitializer = - | PropertySignature - ; +export type HasIllegalExpressionInitializer = PropertySignature; // NOTE: Changing the following list requires changes to: // - `canHaveDecorators` in factory/utilities.ts @@ -1314,8 +1296,7 @@ export type HasDecorators = | GetAccessorDeclaration | SetAccessorDeclaration | ClassExpression - | ClassDeclaration - ; + | ClassDeclaration; // NOTE: Changing the following list requires changes to: // - `canHaveIllegalDecorators` in factory/utilities.ts @@ -1337,8 +1318,7 @@ export type HasIllegalDecorators = | ImportDeclaration | NamespaceExportDeclaration | ExportDeclaration - | ExportAssignment - ; + | ExportAssignment; // NOTE: Changing the following list requires changes to: // - `canHaveModifiers` in factory/utilitiesPublic.ts @@ -1368,8 +1348,7 @@ export type HasModifiers = | ImportEqualsDeclaration | ImportDeclaration | ExportAssignment - | ExportDeclaration - ; + | ExportDeclaration; // NOTE: Changing the following list requires changes to: // - `canHaveIllegalModifiers` in factory/utilities.ts @@ -1379,8 +1358,7 @@ export type HasIllegalModifiers = | PropertyAssignment | ShorthandPropertyAssignment | MissingDeclaration - | NamespaceExportDeclaration - ; + | NamespaceExportDeclaration; /** * Declarations that can contain other declarations. Corresponds with `ContainerFlags.IsContainer` in binder.ts. @@ -1415,8 +1393,7 @@ export type IsContainer = | ConstructorTypeNode | ClassStaticBlockDeclaration | FunctionExpression - | ArrowFunction - ; + | ArrowFunction; /** * Nodes that introduce a new block scope. Corresponds with `ContainerFlags.IsBlockScopedContainer` in binder.ts. @@ -1430,8 +1407,7 @@ export type IsBlockScopedContainer = | ForInStatement | ForOfStatement | CaseBlock - | Block - ; + | Block; /** * Corresponds with `ContainerFlags.IsControlFlowContainer` in binder.ts. @@ -1456,8 +1432,7 @@ export type IsControlFlowContainer = | FunctionExpression | ArrowFunction | ModuleBlock - | PropertyDeclaration - ; + | PropertyDeclaration; /** * Corresponds with `ContainerFlags.IsFunctionLike` in binder.ts. @@ -1479,8 +1454,7 @@ export type IsFunctionLike = | ConstructorTypeNode | ClassStaticBlockDeclaration | FunctionExpression - | ArrowFunction - ; + | ArrowFunction; /** * Corresponds with `ContainerFlags.IsFunctionExpression` in binder.ts. @@ -1489,8 +1463,7 @@ export type IsFunctionLike = */ export type IsFunctionExpression = | FunctionExpression - | ArrowFunction - ; + | ArrowFunction; /** * Nodes that can have local symbols. Corresponds with `ContainerFlags.HasLocals`. Constituents should extend @@ -1528,17 +1501,14 @@ export type HasLocals = | ModuleDeclaration | SetAccessorDeclaration | SourceFile - | TypeAliasDeclaration - ; + | TypeAliasDeclaration; /** * Corresponds with `ContainerFlags.IsInterface` in binder.ts. * * @internal */ -export type IsInterface = - | InterfaceDeclaration - ; +export type IsInterface = InterfaceDeclaration; /** * Corresponds with `ContainerFlags.IsObjectLiteralOrClassExpressionMethodOrAccessor` in binder.ts. @@ -1548,8 +1518,7 @@ export type IsInterface = export type IsObjectLiteralOrClassExpressionMethodOrAccessor = | GetAccessorDeclaration | SetAccessorDeclaration - | MethodDeclaration - ; + | MethodDeclaration; /** * Corresponds with `ContainerFlags` in binder.ts. @@ -1564,18 +1533,17 @@ export type HasContainerFlags = | IsFunctionExpression | HasLocals | IsInterface - | IsObjectLiteralOrClassExpressionMethodOrAccessor - ; + | IsObjectLiteralOrClassExpressionMethodOrAccessor; /** @internal */ export interface MutableNodeArray extends Array, TextRange { hasTrailingComma: boolean; - /** @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined + /** @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined } export interface NodeArray extends ReadonlyArray, ReadonlyTextRange { readonly hasTrailingComma: boolean; - /** @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined + /** @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined } // TODO(rbuckton): Constraint 'TKind' to 'TokenSyntaxKind' @@ -1647,31 +1615,28 @@ export type Modifier = | OutKeyword | OverrideKeyword | ReadonlyKeyword - | StaticKeyword - ; + | StaticKeyword; export type ModifierLike = Modifier | Decorator; export type AccessibilityModifier = | PublicKeyword | PrivateKeyword - | ProtectedKeyword - ; + | ProtectedKeyword; export type ParameterPropertyModifier = | AccessibilityModifier - | ReadonlyKeyword - ; + | ReadonlyKeyword; export type ClassMemberModifier = | AccessibilityModifier | ReadonlyKeyword | StaticKeyword - | AccessorKeyword - ; + | AccessorKeyword; export type ModifiersArray = NodeArray; +// dprint-ignore export const enum GeneratedIdentifierFlags { // Kinds None = 0, // Not automatically generated. @@ -1702,6 +1667,7 @@ export interface TransientIdentifier extends Identifier { resolvedSymbol: Symbol; } +// dprint-ignore /** @internal */ export interface AutoGenerateInfo { flags: GeneratedIdentifierFlags; // Specifies whether to auto-generate the text for an identifier. @@ -1737,8 +1703,8 @@ export type DeclarationName = export interface Declaration extends Node { _declarationBrand: any; - /** @internal */ symbol: Symbol; // Symbol declared by node (initialized by binding) - /** @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes) + /** @internal */ symbol: Symbol; // Symbol declared by node (initialized by binding) + /** @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes) } export interface NamedDeclaration extends Declaration { @@ -1791,7 +1757,7 @@ export interface PrivateIdentifier extends PrimaryExpression { /** @internal */ export interface GeneratedPrivateIdentifier extends PrivateIdentifier { - readonly emitNode: EmitNode & { autoGenerate: AutoGenerateInfo }; + readonly emitNode: EmitNode & { autoGenerate: AutoGenerateInfo; }; } /** @internal */ @@ -1853,6 +1819,7 @@ export interface ConstructSignatureDeclaration extends SignatureDeclarationBase, export type BindingName = Identifier | BindingPattern; +// dprint-ignore export interface VariableDeclaration extends NamedDeclaration, JSDocContainer { readonly kind: SyntaxKind.VariableDeclaration; readonly parent: VariableDeclarationList | CatchClause; @@ -1863,7 +1830,7 @@ export interface VariableDeclaration extends NamedDeclaration, JSDocContainer { } /** @internal */ -export type InitializedVariableDeclaration = VariableDeclaration & { readonly initializer: Expression }; +export type InitializedVariableDeclaration = VariableDeclaration & { readonly initializer: Expression; }; export interface VariableDeclarationList extends Node { readonly kind: SyntaxKind.VariableDeclarationList; @@ -1871,6 +1838,7 @@ export interface VariableDeclarationList extends Node { readonly declarations: NodeArray; } +// dprint-ignore export interface ParameterDeclaration extends NamedDeclaration, JSDocContainer { readonly kind: SyntaxKind.Parameter; readonly parent: SignatureDeclaration; @@ -1882,6 +1850,7 @@ export interface ParameterDeclaration extends NamedDeclaration, JSDocContainer { readonly initializer?: Expression; // Optional initializer } +// dprint-ignore export interface BindingElement extends NamedDeclaration, FlowContainer { readonly kind: SyntaxKind.BindingElement; readonly parent: BindingPattern; @@ -1894,6 +1863,7 @@ export interface BindingElement extends NamedDeclaration, FlowContainer { /** @internal */ export type BindingElementGrandparent = BindingElement["parent"]["parent"]; +// dprint-ignore export interface PropertySignature extends TypeElement, JSDocContainer { readonly kind: SyntaxKind.PropertySignature; readonly parent: TypeLiteralNode | InterfaceDeclaration; @@ -1906,6 +1876,7 @@ export interface PropertySignature extends TypeElement, JSDocContainer { /** @internal */ readonly initializer?: Expression | undefined; // A property signature cannot have an initializer } +// dprint-ignore export interface PropertyDeclaration extends ClassElement, JSDocContainer { readonly kind: SyntaxKind.PropertyDeclaration; readonly parent: ClassLikeDeclaration; @@ -1942,7 +1913,9 @@ export interface PrivateIdentifierSetAccessorDeclaration extends SetAccessorDecl name: PrivateIdentifier; } /** @internal */ -export type PrivateIdentifierAccessorDeclaration = PrivateIdentifierGetAccessorDeclaration | PrivateIdentifierSetAccessorDeclaration; +export type PrivateIdentifierAccessorDeclaration = + | PrivateIdentifierGetAccessorDeclaration + | PrivateIdentifierSetAccessorDeclaration; /** @internal */ export type PrivateClassElementDeclaration = | PrivateIdentifierPropertyDeclaration @@ -1952,7 +1925,7 @@ export type PrivateClassElementDeclaration = | PrivateIdentifierSetAccessorDeclaration; /** @internal */ -export type InitializedPropertyDeclaration = PropertyDeclaration & { readonly initializer: Expression }; +export type InitializedPropertyDeclaration = PropertyDeclaration & { readonly initializer: Expression; }; export interface ObjectLiteralElement extends NamedDeclaration { _objectLiteralBrand: any; @@ -1960,13 +1933,12 @@ export interface ObjectLiteralElement extends NamedDeclaration { } /** Unlike ObjectLiteralElement, excludes JSXAttribute and JSXSpreadAttribute. */ -export type ObjectLiteralElementLike - = PropertyAssignment +export type ObjectLiteralElementLike = + | PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment | MethodDeclaration - | AccessorDeclaration - ; + | AccessorDeclaration; export interface PropertyAssignment extends ObjectLiteralElement, JSDocContainer { readonly kind: SyntaxKind.PropertyAssignment; @@ -2083,7 +2055,15 @@ export interface MethodSignature extends SignatureDeclarationBase, TypeElement, // Because of this, it may be necessary to determine what sort of MethodDeclaration you have // at later stages of the compiler pipeline. In that case, you can either check the parent kind // of the method, or use helpers like isObjectLiteralMethodDeclaration -export interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer, LocalsContainer, FlowContainer { +export interface MethodDeclaration + extends + FunctionLikeDeclarationBase, + ClassElement, + ObjectLiteralElement, + JSDocContainer, + LocalsContainer, + FlowContainer +{ readonly kind: SyntaxKind.MethodDeclaration; readonly parent: ClassLikeDeclaration | ObjectLiteralExpression; readonly modifiers?: NodeArray | undefined; @@ -2094,7 +2074,9 @@ export interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassEle /** @internal */ readonly exclamationToken?: ExclamationToken | undefined; // A method cannot have an exclamation token } -export interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement, JSDocContainer, LocalsContainer { +export interface ConstructorDeclaration + extends FunctionLikeDeclarationBase, ClassElement, JSDocContainer, LocalsContainer +{ readonly kind: SyntaxKind.Constructor; readonly parent: ClassLikeDeclaration; readonly modifiers?: NodeArray | undefined; @@ -2113,7 +2095,16 @@ export interface SemicolonClassElement extends ClassElement, JSDocContainer { // See the comment on MethodDeclaration for the intuition behind GetAccessorDeclaration being a // ClassElement and an ObjectLiteralElement. -export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer, LocalsContainer, FlowContainer { +export interface GetAccessorDeclaration + extends + FunctionLikeDeclarationBase, + ClassElement, + TypeElement, + ObjectLiteralElement, + JSDocContainer, + LocalsContainer, + FlowContainer +{ readonly kind: SyntaxKind.GetAccessor; readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration; readonly modifiers?: NodeArray; @@ -2126,7 +2117,16 @@ export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, Cla // See the comment on MethodDeclaration for the intuition behind SetAccessorDeclaration being a // ClassElement and an ObjectLiteralElement. -export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, TypeElement, ObjectLiteralElement, JSDocContainer, LocalsContainer, FlowContainer { +export interface SetAccessorDeclaration + extends + FunctionLikeDeclarationBase, + ClassElement, + TypeElement, + ObjectLiteralElement, + JSDocContainer, + LocalsContainer, + FlowContainer +{ readonly kind: SyntaxKind.SetAccessor; readonly parent: ClassLikeDeclaration | ObjectLiteralExpression | TypeLiteralNode | InterfaceDeclaration; readonly modifiers?: NodeArray; @@ -2140,7 +2140,9 @@ export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, Cla export type AccessorDeclaration = GetAccessorDeclaration | SetAccessorDeclaration; -export interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement, LocalsContainer { +export interface IndexSignatureDeclaration + extends SignatureDeclarationBase, ClassElement, TypeElement, LocalsContainer +{ readonly kind: SyntaxKind.IndexSignature; readonly parent: ObjectTypeDeclaration; readonly modifiers?: NodeArray; @@ -2168,7 +2170,9 @@ export interface TypeNode extends Node { readonly kind: TypeNodeSyntaxKind; } -export interface KeywordTypeNode extends KeywordToken, TypeNode { +export interface KeywordTypeNode + extends KeywordToken, TypeNode +{ readonly kind: TKind; } @@ -2188,7 +2192,9 @@ export interface ImportTypeNode extends NodeWithTypeArguments { } /** @internal */ -export type LiteralImportTypeNode = ImportTypeNode & { readonly argument: LiteralTypeNode & { readonly literal: StringLiteral } }; +export type LiteralImportTypeNode = ImportTypeNode & { + readonly argument: LiteralTypeNode & { readonly literal: StringLiteral; }; +}; export interface ThisTypeNode extends TypeNode { readonly kind: SyntaxKind.ThisType; @@ -2336,7 +2342,12 @@ export interface LiteralTypeNode extends TypeNode { export interface StringLiteral extends LiteralExpression, Declaration { readonly kind: SyntaxKind.StringLiteral; - /** @internal */ readonly textSourceNode?: Identifier | StringLiteralLike | NumericLiteral | PrivateIdentifier | JsxNamespacedName; // Allows a StringLiteral to get its text from another node (used by transforms). + /** @internal */ readonly textSourceNode?: + | Identifier + | StringLiteralLike + | NumericLiteral + | PrivateIdentifier + | JsxNamespacedName; // Allows a StringLiteral to get its text from another node (used by transforms). /** * Note: this is only set when synthesizing a node, not during parsing. * @@ -2349,13 +2360,13 @@ export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral; export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral | JsxNamespacedName; export interface TemplateLiteralTypeNode extends TypeNode { - kind: SyntaxKind.TemplateLiteralType, + kind: SyntaxKind.TemplateLiteralType; readonly head: TemplateHead; readonly templateSpans: NodeArray; } export interface TemplateLiteralTypeSpan extends TypeNode { - readonly kind: SyntaxKind.TemplateLiteralTypeSpan, + readonly kind: SyntaxKind.TemplateLiteralTypeSpan; readonly parent: TemplateLiteralTypeNode; readonly type: TypeNode; readonly literal: TemplateMiddle | TemplateTail; @@ -2395,8 +2406,8 @@ export interface UpdateExpression extends UnaryExpression { // see: https://tc39.github.io/ecma262/#prod-UpdateExpression // see: https://tc39.github.io/ecma262/#prod-UnaryExpression -export type PrefixUnaryOperator - = SyntaxKind.PlusPlusToken +export type PrefixUnaryOperator = + | SyntaxKind.PlusPlusToken | SyntaxKind.MinusMinusToken | SyntaxKind.PlusToken | SyntaxKind.MinusToken @@ -2410,10 +2421,9 @@ export interface PrefixUnaryExpression extends UpdateExpression { } // see: https://tc39.github.io/ecma262/#prod-UpdateExpression -export type PostfixUnaryOperator - = SyntaxKind.PlusPlusToken - | SyntaxKind.MinusMinusToken - ; +export type PostfixUnaryOperator = + | SyntaxKind.PlusPlusToken + | SyntaxKind.MinusMinusToken; export interface PostfixUnaryExpression extends UpdateExpression { readonly kind: SyntaxKind.PostfixUnaryExpression; @@ -2493,47 +2503,39 @@ export interface SyntheticExpression extends Expression { } // see: https://tc39.github.io/ecma262/#prod-ExponentiationExpression -export type ExponentiationOperator = - | SyntaxKind.AsteriskAsteriskToken - ; +export type ExponentiationOperator = SyntaxKind.AsteriskAsteriskToken; // see: https://tc39.github.io/ecma262/#prod-MultiplicativeOperator export type MultiplicativeOperator = | SyntaxKind.AsteriskToken | SyntaxKind.SlashToken - | SyntaxKind.PercentToken - ; + | SyntaxKind.PercentToken; // see: https://tc39.github.io/ecma262/#prod-MultiplicativeExpression export type MultiplicativeOperatorOrHigher = | ExponentiationOperator - | MultiplicativeOperator - ; + | MultiplicativeOperator; // see: https://tc39.github.io/ecma262/#prod-AdditiveExpression export type AdditiveOperator = | SyntaxKind.PlusToken - | SyntaxKind.MinusToken - ; + | SyntaxKind.MinusToken; // see: https://tc39.github.io/ecma262/#prod-AdditiveExpression export type AdditiveOperatorOrHigher = | MultiplicativeOperatorOrHigher - | AdditiveOperator - ; + | AdditiveOperator; // see: https://tc39.github.io/ecma262/#prod-ShiftExpression export type ShiftOperator = | SyntaxKind.LessThanLessThanToken | SyntaxKind.GreaterThanGreaterThanToken - | SyntaxKind.GreaterThanGreaterThanGreaterThanToken - ; + | SyntaxKind.GreaterThanGreaterThanGreaterThanToken; // see: https://tc39.github.io/ecma262/#prod-ShiftExpression export type ShiftOperatorOrHigher = | AdditiveOperatorOrHigher - | ShiftOperator - ; + | ShiftOperator; // see: https://tc39.github.io/ecma262/#prod-RelationalExpression export type RelationalOperator = @@ -2542,22 +2544,19 @@ export type RelationalOperator = | SyntaxKind.GreaterThanToken | SyntaxKind.GreaterThanEqualsToken | SyntaxKind.InstanceOfKeyword - | SyntaxKind.InKeyword - ; + | SyntaxKind.InKeyword; // see: https://tc39.github.io/ecma262/#prod-RelationalExpression export type RelationalOperatorOrHigher = | ShiftOperatorOrHigher - | RelationalOperator - ; + | RelationalOperator; // see: https://tc39.github.io/ecma262/#prod-EqualityExpression export type EqualityOperator = | SyntaxKind.EqualsEqualsToken | SyntaxKind.EqualsEqualsEqualsToken | SyntaxKind.ExclamationEqualsEqualsToken - | SyntaxKind.ExclamationEqualsToken - ; + | SyntaxKind.ExclamationEqualsToken; // see: https://tc39.github.io/ecma262/#prod-EqualityExpression export type EqualityOperatorOrHigher = @@ -2570,30 +2569,26 @@ export type EqualityOperatorOrHigher = export type BitwiseOperator = | SyntaxKind.AmpersandToken | SyntaxKind.BarToken - | SyntaxKind.CaretToken - ; + | SyntaxKind.CaretToken; // see: https://tc39.github.io/ecma262/#prod-BitwiseANDExpression // see: https://tc39.github.io/ecma262/#prod-BitwiseXORExpression // see: https://tc39.github.io/ecma262/#prod-BitwiseORExpression export type BitwiseOperatorOrHigher = | EqualityOperatorOrHigher - | BitwiseOperator - ; + | BitwiseOperator; // see: https://tc39.github.io/ecma262/#prod-LogicalANDExpression // see: https://tc39.github.io/ecma262/#prod-LogicalORExpression export type LogicalOperator = | SyntaxKind.AmpersandAmpersandToken - | SyntaxKind.BarBarToken - ; + | SyntaxKind.BarBarToken; // see: https://tc39.github.io/ecma262/#prod-LogicalANDExpression // see: https://tc39.github.io/ecma262/#prod-LogicalORExpression export type LogicalOperatorOrHigher = | BitwiseOperatorOrHigher - | LogicalOperator - ; + | LogicalOperator; // see: https://tc39.github.io/ecma262/#prod-AssignmentOperator export type CompoundAssignmentOperator = @@ -2611,33 +2606,28 @@ export type CompoundAssignmentOperator = | SyntaxKind.GreaterThanGreaterThanEqualsToken | SyntaxKind.BarBarEqualsToken | SyntaxKind.AmpersandAmpersandEqualsToken - | SyntaxKind.QuestionQuestionEqualsToken - ; + | SyntaxKind.QuestionQuestionEqualsToken; // see: https://tc39.github.io/ecma262/#prod-AssignmentExpression export type AssignmentOperator = | SyntaxKind.EqualsToken - | CompoundAssignmentOperator - ; + | CompoundAssignmentOperator; // see: https://tc39.github.io/ecma262/#prod-AssignmentExpression export type AssignmentOperatorOrHigher = | SyntaxKind.QuestionQuestionToken | LogicalOperatorOrHigher - | AssignmentOperator - ; + | AssignmentOperator; // see: https://tc39.github.io/ecma262/#prod-Expression export type BinaryOperator = | AssignmentOperatorOrHigher - | SyntaxKind.CommaToken - ; + | SyntaxKind.CommaToken; -export type LogicalOrCoalescingAssignmentOperator - = SyntaxKind.AmpersandAmpersandEqualsToken +export type LogicalOrCoalescingAssignmentOperator = + | SyntaxKind.AmpersandAmpersandEqualsToken | SyntaxKind.BarBarEqualsToken - | SyntaxKind.QuestionQuestionEqualsToken - ; + | SyntaxKind.QuestionQuestionEqualsToken; export type BinaryOperatorToken = Token; @@ -2665,22 +2655,20 @@ export interface ArrayDestructuringAssignment extends AssignmentExpression; @@ -2695,7 +2683,7 @@ export type ArrayBindingOrAssignmentElement = | Identifier // DestructuringAssignmentTarget | PropertyAccessExpression // DestructuringAssignmentTarget | ElementAccessExpression // DestructuringAssignmentTarget - ; +; /** @internal */ export type ArrayAssignmentElement = Exclude; @@ -2704,7 +2692,7 @@ export type BindingOrAssignmentElementRestIndicator = | DotDotDotToken // from BindingElement | SpreadElement // AssignmentRestElement | SpreadAssignment // AssignmentRestProperty - ; +; export type BindingOrAssignmentElementTarget = | BindingOrAssignmentPattern @@ -2719,12 +2707,12 @@ export type AssignmentElementTarget = Exclude; readonly name?: Identifier; - readonly body: FunctionBody; // Required, whereas the member inherited from FunctionDeclaration is optional + readonly body: FunctionBody; // Required, whereas the member inherited from FunctionDeclaration is optional } -export interface ArrowFunction extends Expression, FunctionLikeDeclarationBase, JSDocContainer, LocalsContainer, FlowContainer { +export interface ArrowFunction + extends Expression, FunctionLikeDeclarationBase, JSDocContainer, LocalsContainer, FlowContainer +{ readonly kind: SyntaxKind.ArrowFunction; readonly modifiers?: NodeArray; readonly equalsGreaterThanToken: EqualsGreaterThanToken; @@ -2789,6 +2781,7 @@ export interface NoSubstitutionTemplateLiteral extends LiteralExpression, Templa templateFlags?: TokenFlags; } +// dprint-ignore export const enum TokenFlags { None = 0, /** @internal */ @@ -2846,8 +2839,7 @@ export type LiteralToken = | StringLiteral | JsxText | RegularExpressionLiteral - | NoSubstitutionTemplateLiteral - ; + | NoSubstitutionTemplateLiteral; export interface TemplateHead extends TemplateLiteralLikeNode { readonly kind: SyntaxKind.TemplateHead; @@ -2873,13 +2865,11 @@ export interface TemplateTail extends TemplateLiteralLikeNode { export type PseudoLiteralToken = | TemplateHead | TemplateMiddle - | TemplateTail - ; + | TemplateTail; export type TemplateLiteralToken = | NoSubstitutionTemplateLiteral - | PseudoLiteralToken - ; + | PseudoLiteralToken; export interface TemplateExpression extends PrimaryExpression { readonly kind: SyntaxKind.TemplateExpression; @@ -2889,8 +2879,7 @@ export interface TemplateExpression extends PrimaryExpression { export type TemplateLiteral = | TemplateExpression - | NoSubstitutionTemplateLiteral - ; + | NoSubstitutionTemplateLiteral; // Each of these corresponds to a substitution expression and a template literal, in that order. // The template literal must have kind TemplateMiddleLiteral or TemplateTailLiteral. @@ -3022,26 +3011,25 @@ export type OptionalChain = | PropertyAccessChain | ElementAccessChain | CallChain - | NonNullChain - ; + | NonNullChain; /** @internal */ export type OptionalChainRoot = | PropertyAccessChainRoot | ElementAccessChainRoot - | CallChainRoot - ; + | CallChainRoot; /** @internal */ export type BindableObjectDefinePropertyCall = CallExpression & { - readonly arguments: readonly [BindableStaticNameExpression, StringLiteralLike | NumericLiteral, ObjectLiteralExpression] & Readonly; + readonly arguments: + & readonly [BindableStaticNameExpression, StringLiteralLike | NumericLiteral, ObjectLiteralExpression] + & Readonly; }; /** @internal */ export type BindableStaticNameExpression = | EntityNameExpression - | BindableStaticElementAccessExpression - ; + | BindableStaticElementAccessExpression; /** @internal */ export type LiteralLikeElementAccessExpression = ElementAccessExpression & Declaration & { @@ -3061,14 +3049,12 @@ export type BindableElementAccessExpression = ElementAccessExpression & { /** @internal */ export type BindableStaticAccessExpression = | PropertyAccessEntityNameExpression - | BindableStaticElementAccessExpression - ; + | BindableStaticElementAccessExpression; /** @internal */ export type BindableAccessExpression = | PropertyAccessEntityNameExpression - | BindableElementAccessExpression - ; + | BindableElementAccessExpression; /** @internal */ export interface BindableStaticPropertyAssignmentExpression extends BinaryExpression { @@ -3114,8 +3100,7 @@ export type CallLikeExpression = | NewExpression | TaggedTemplateExpression | Decorator - | JsxOpeningLikeElement - ; + | JsxOpeningLikeElement; export interface AsExpression extends Expression { readonly kind: SyntaxKind.AsExpression; @@ -3137,8 +3122,7 @@ export interface SatisfiesExpression extends Expression { export type AssertionExpression = | TypeAssertion - | AsExpression - ; + | AsExpression; export interface NonNullExpression extends LeftHandSideExpression { readonly kind: SyntaxKind.NonNullExpression; @@ -3160,7 +3144,7 @@ export interface MetaProperty extends PrimaryExpression, FlowContainer { /** @internal */ export interface ImportMetaProperty extends MetaProperty { readonly keywordToken: SyntaxKind.ImportKeyword; - readonly name: Identifier & { readonly escapedText: __String & "meta" }; + readonly name: Identifier & { readonly escapedText: __String & "meta"; }; } /// A JSX expression of the form ... @@ -3174,25 +3158,21 @@ export interface JsxElement extends PrimaryExpression { /// Either the opening tag in a ... pair or the lone in a self-closing form export type JsxOpeningLikeElement = | JsxSelfClosingElement - | JsxOpeningElement - ; + | JsxOpeningElement; export type JsxAttributeLike = | JsxAttribute - | JsxSpreadAttribute - ; + | JsxSpreadAttribute; export type JsxAttributeName = | Identifier - | JsxNamespacedName - ; + | JsxNamespacedName; export type JsxTagNameExpression = | Identifier | ThisExpression | JsxTagNamePropertyAccess - | JsxNamespacedName - ; + | JsxNamespacedName; export interface JsxTagNamePropertyAccess extends PropertyAccessExpression { readonly expression: Identifier | ThisExpression | JsxTagNamePropertyAccess; @@ -3292,8 +3272,7 @@ export type JsxChild = | JsxExpression | JsxElement | JsxSelfClosingElement - | JsxFragment - ; + | JsxFragment; export interface Statement extends Node, JSDocContainer { _statementBrand: any; @@ -3313,7 +3292,6 @@ export interface CommaListExpression extends Expression { readonly elements: NodeArray; } - /** @internal */ export interface SyntheticReferenceExpression extends LeftHandSideExpression { readonly kind: SyntaxKind.SyntheticReferenceExpression; @@ -3341,8 +3319,7 @@ export type BlockLike = | SourceFile | Block | ModuleBlock - | CaseOrDefaultClause - ; + | CaseOrDefaultClause; export interface Block extends Statement, LocalsContainer { readonly kind: SyntaxKind.Block; @@ -3389,8 +3366,7 @@ export interface WhileStatement extends IterationStatement, FlowContainer { export type ForInitializer = | VariableDeclarationList - | Expression - ; + | Expression; export interface ForStatement extends IterationStatement, LocalsContainer, FlowContainer { readonly kind: SyntaxKind.ForStatement; @@ -3401,8 +3377,7 @@ export interface ForStatement extends IterationStatement, LocalsContainer, FlowC export type ForInOrOfStatement = | ForInStatement - | ForOfStatement - ; + | ForOfStatement; export interface ForInStatement extends IterationStatement, LocalsContainer, FlowContainer { readonly kind: SyntaxKind.ForInStatement; @@ -3429,8 +3404,7 @@ export interface ContinueStatement extends Statement, FlowContainer { export type BreakOrContinueStatement = | BreakStatement - | ContinueStatement - ; + | ContinueStatement; export interface ReturnStatement extends Statement, FlowContainer { readonly kind: SyntaxKind.ReturnStatement; @@ -3473,8 +3447,7 @@ export interface DefaultClause extends Node { export type CaseOrDefaultClause = | CaseClause - | DefaultClause - ; + | DefaultClause; export interface LabeledStatement extends Statement, FlowContainer { readonly kind: SyntaxKind.LabeledStatement; @@ -3504,23 +3477,20 @@ export interface CatchClause extends Node, LocalsContainer { export type ObjectTypeDeclaration = | ClassLikeDeclaration | InterfaceDeclaration - | TypeLiteralNode - ; + | TypeLiteralNode; export type DeclarationWithTypeParameters = | DeclarationWithTypeParameterChildren | JSDocTypedefTag | JSDocCallbackTag - | JSDocSignature - ; + | JSDocSignature; export type DeclarationWithTypeParameterChildren = | SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration - | JSDocTemplateTag - ; + | JSDocTemplateTag; export interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer { readonly kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression; @@ -3544,8 +3514,7 @@ export interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpres export type ClassLikeDeclaration = | ClassDeclaration - | ClassExpression - ; + | ClassExpression; export interface ClassElement extends NamedDeclaration { _classElementBrand: any; @@ -3600,13 +3569,11 @@ export interface EnumDeclaration extends DeclarationStatement, JSDocContainer { export type ModuleName = | Identifier - | StringLiteral - ; + | StringLiteral; export type ModuleBody = | NamespaceBody - | JSDocNamespaceBody - ; + | JSDocNamespaceBody; /** @internal */ export interface AmbientModuleDeclaration extends ModuleDeclaration { @@ -3623,8 +3590,7 @@ export interface ModuleDeclaration extends DeclarationStatement, JSDocContainer, export type NamespaceBody = | ModuleBlock - | NamespaceDeclaration - ; + | NamespaceDeclaration; export interface NamespaceDeclaration extends ModuleDeclaration { readonly name: Identifier; @@ -3633,8 +3599,7 @@ export interface NamespaceDeclaration extends ModuleDeclaration { export type JSDocNamespaceBody = | Identifier - | JSDocNamespaceDeclaration - ; + | JSDocNamespaceDeclaration; export interface JSDocNamespaceDeclaration extends ModuleDeclaration { readonly name: Identifier; @@ -3649,8 +3614,7 @@ export interface ModuleBlock extends Node, Statement { export type ModuleReference = | EntityName - | ExternalModuleReference - ; + | ExternalModuleReference; /** * One of: @@ -3691,13 +3655,11 @@ export interface ImportDeclaration extends Statement { export type NamedImportBindings = | NamespaceImport - | NamedImports - ; + | NamedImports; export type NamedExportBindings = | NamespaceExport - | NamedExports - ; + | NamedExports; // In case of: // import d from "mod" => name = d, namedBinding = undefined @@ -3724,7 +3686,7 @@ export interface AssertEntry extends Node { export interface AssertClause extends Node { readonly kind: SyntaxKind.AssertClause; - readonly parent: ImportDeclaration | ExportDeclaration + readonly parent: ImportDeclaration | ExportDeclaration; readonly elements: NodeArray; readonly multiLine?: boolean; } @@ -3738,7 +3700,7 @@ export interface NamespaceImport extends NamedDeclaration { export interface NamespaceExport extends NamedDeclaration { readonly kind: SyntaxKind.NamespaceExport; readonly parent: ExportDeclaration; - readonly name: Identifier + readonly name: Identifier; } export interface NamespaceExportDeclaration extends DeclarationStatement, JSDocContainer { @@ -3778,8 +3740,8 @@ export type NamedImportsOrExports = NamedImports | NamedExports; export interface ImportSpecifier extends NamedDeclaration { readonly kind: SyntaxKind.ImportSpecifier; readonly parent: NamedImports; - readonly propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) - readonly name: Identifier; // Declared name + readonly propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) + readonly name: Identifier; // Declared name readonly isTypeOnly: boolean; } @@ -3787,14 +3749,13 @@ export interface ExportSpecifier extends NamedDeclaration, JSDocContainer { readonly kind: SyntaxKind.ExportSpecifier; readonly parent: NamedExports; readonly isTypeOnly: boolean; - readonly propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) - readonly name: Identifier; // Declared name + readonly propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) + readonly name: Identifier; // Declared name } export type ImportOrExportSpecifier = | ImportSpecifier - | ExportSpecifier - ; + | ExportSpecifier; export type TypeOnlyCompatibleAliasDeclaration = | ImportClause @@ -3802,21 +3763,27 @@ export type TypeOnlyCompatibleAliasDeclaration = | NamespaceImport | ImportOrExportSpecifier | ExportDeclaration - | NamespaceExport - ; + | NamespaceExport; export type TypeOnlyImportDeclaration = - | ImportClause & { readonly isTypeOnly: true, readonly name: Identifier } - | ImportEqualsDeclaration & { readonly isTypeOnly: true } - | NamespaceImport & { readonly parent: ImportClause & { readonly isTypeOnly: true } } - | ImportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true } } }) - ; + | ImportClause & { readonly isTypeOnly: true; readonly name: Identifier; } + | ImportEqualsDeclaration & { readonly isTypeOnly: true; } + | NamespaceImport & { readonly parent: ImportClause & { readonly isTypeOnly: true; }; } + | ImportSpecifier + & ({ readonly isTypeOnly: true; } | { + readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true; }; }; + }); export type TypeOnlyExportDeclaration = - | ExportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } }) - | ExportDeclaration & { readonly isTypeOnly: true, readonly moduleSpecifier: Expression } // export * from "mod" - | NamespaceExport & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true, readonly moduleSpecifier: Expression } } // export * as ns from "mod" - ; + | ExportSpecifier + & ({ readonly isTypeOnly: true; } | { + readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true; }; }; + }) + | ExportDeclaration & { readonly isTypeOnly: true; readonly moduleSpecifier: Expression; } // export * from "mod" + | NamespaceExport & { + readonly parent: ExportDeclaration & { readonly isTypeOnly: true; readonly moduleSpecifier: Expression; }; + } // export * as ns from "mod" +; export type TypeOnlyAliasDeclaration = TypeOnlyImportDeclaration | TypeOnlyExportDeclaration; @@ -3920,8 +3887,7 @@ export type JSDocTypeReferencingNode = | JSDocVariadicType | JSDocOptionalType | JSDocNullableType - | JSDocNonNullableType - ; + | JSDocNonNullableType; export interface JSDoc extends Node { readonly kind: SyntaxKind.JSDoc; @@ -3971,12 +3937,16 @@ export interface JSDocUnknownTag extends JSDocTag { */ export interface JSDocAugmentsTag extends JSDocTag { readonly kind: SyntaxKind.JSDocAugmentsTag; - readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression }; + readonly class: ExpressionWithTypeArguments & { + readonly expression: Identifier | PropertyAccessEntityNameExpression; + }; } export interface JSDocImplementsTag extends JSDocTag { readonly kind: SyntaxKind.JSDocImplementsTag; - readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression }; + readonly class: ExpressionWithTypeArguments & { + readonly expression: Identifier | PropertyAccessEntityNameExpression; + }; } export interface JSDocAuthorTag extends JSDocTag { @@ -4059,7 +4029,6 @@ export interface JSDocCallbackTag extends JSDocTag, NamedDeclaration, LocalsCont readonly typeExpression: JSDocSignature; } - export interface JSDocOverloadTag extends JSDocTag { readonly kind: SyntaxKind.JSDocOverloadTag; readonly parent: JSDoc; @@ -4113,6 +4082,7 @@ export interface JSDocSatisfiesExpression extends ParenthesizedExpression { } // NOTE: Ensure this is up-to-date with src/debug/debug.ts +// dprint-ignore export const enum FlowFlags { Unreachable = 1 << 0, // Unreachable code Start = 1 << 1, // Start of flow graph @@ -4144,7 +4114,7 @@ export type FlowNode = export interface FlowNodeBase { flags: FlowFlags; - id?: number; // Node id used by flow type cache in checker + id?: number; // Node id used by flow type cache in checker } // FlowStart represents the start of a control flow. For a function expression or arrow @@ -4178,6 +4148,7 @@ export interface FlowCondition extends FlowNodeBase { antecedent: FlowNode; } +// dprint-ignore export interface FlowSwitchClause extends FlowNodeBase { switchStatement: SwitchStatement; clauseStart: number; // Start index of case/default clause range @@ -4203,6 +4174,7 @@ export type FlowType = Type | IncompleteType; // Incomplete types occur during control flow analysis of loops. An IncompleteType // is distinguished from a regular type by a flags value of zero. Incomplete type // objects are internal to the getFlowTypeOfReference function and never escape it. +// dprint-ignore export interface IncompleteType { flags: TypeFlags | 0; // No flags set type: Type; // The type marked incomplete @@ -4369,7 +4341,9 @@ export interface SourceFile extends Declaration, LocalsContainer { // It is used to resolve module names in the checker. // Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead /** @internal */ resolvedModules?: ModeAwareCache; - /** @internal */ resolvedTypeReferenceDirectiveNames?: ModeAwareCache; + /** @internal */ resolvedTypeReferenceDirectiveNames?: ModeAwareCache< + ResolvedTypeReferenceDirectiveWithFailedLookupLocations + >; /** @internal */ imports: readonly StringLiteralLike[]; // Identifier only if `declare global` /** @internal */ moduleAugmentations: readonly (StringLiteral | Identifier)[]; @@ -4415,7 +4389,7 @@ export interface SourceFile extends ReadonlyPragmaContext {} /** @internal */ export interface CommentDirective { range: TextRange; - type: CommentDirectiveType, + type: CommentDirectiveType; } /** @internal */ @@ -4481,15 +4455,13 @@ export interface UnparsedSource extends Node { /** @deprecated */ export type UnparsedSourceText = | UnparsedPrepend - | UnparsedTextLike - ; + | UnparsedTextLike; /** @deprecated */ export type UnparsedNode = | UnparsedPrologue | UnparsedSourceText - | UnparsedSyntheticReference - ; + | UnparsedSyntheticReference; /** @deprecated */ export interface UnparsedSection extends Node { @@ -4548,8 +4520,7 @@ export type JsonObjectExpression = | NumericLiteral | StringLiteral | BooleanLiteral - | NullLiteral - ; + | NullLiteral; export interface JsonObjectExpressionStatement extends ExpressionStatement { readonly expression: JsonObjectExpression; @@ -4565,7 +4536,13 @@ export interface ScriptReferenceHost { export interface ParseConfigHost extends ModuleResolutionHost { useCaseSensitiveFileNames: boolean; - readDirectory(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[], depth?: number): readonly string[]; + readDirectory( + rootDir: string, + extensions: readonly string[], + excludes: readonly string[] | undefined, + includes: readonly string[], + depth?: number, + ): readonly string[]; /** * Gets a value indicating whether the specified path exists and is a file. @@ -4582,7 +4559,7 @@ export interface ParseConfigHost extends ModuleResolutionHost { * specified like "./blah" to an absolute path to an actual * tsconfig file, e.g. "/root/blah/tsconfig.json" */ -export type ResolvedConfigFileName = string & { _isResolvedConfigFileName: never }; +export type ResolvedConfigFileName = string & { _isResolvedConfigFileName: never; }; export interface WriteFileCallbackData { /** @internal */ sourceMapUrlPos?: number; @@ -4599,7 +4576,7 @@ export type WriteFileCallback = ( data?: WriteFileCallbackData, ) => void; -export class OperationCanceledException { } +export class OperationCanceledException {} export interface CancellationToken { isCancellationRequested(): boolean; @@ -4618,12 +4595,12 @@ export enum FileIncludeKind { TypeReferenceDirective, LibFile, LibReferenceDirective, - AutomaticTypeDirectiveFile + AutomaticTypeDirectiveFile, } /** @internal */ export interface RootFile { - kind: FileIncludeKind.RootFile, + kind: FileIncludeKind.RootFile; index: number; } @@ -4634,8 +4611,9 @@ export interface LibFile { } /** @internal */ -export type ProjectReferenceFileKind = FileIncludeKind.SourceFromProjectReference | - FileIncludeKind.OutputFromProjectReference; +export type ProjectReferenceFileKind = + | FileIncludeKind.SourceFromProjectReference + | FileIncludeKind.OutputFromProjectReference; /** @internal */ export interface ProjectReferenceFile { @@ -4644,10 +4622,11 @@ export interface ProjectReferenceFile { } /** @internal */ -export type ReferencedFileKind = FileIncludeKind.Import | - FileIncludeKind.ReferenceFile | - FileIncludeKind.TypeReferenceDirective | - FileIncludeKind.LibReferenceDirective; +export type ReferencedFileKind = + | FileIncludeKind.Import + | FileIncludeKind.ReferenceFile + | FileIncludeKind.TypeReferenceDirective + | FileIncludeKind.LibReferenceDirective; /** @internal */ export interface ReferencedFile { @@ -4665,11 +4644,11 @@ export interface AutomaticTypeDirectiveFile { /** @internal */ export type FileIncludeReason = - RootFile | - LibFile | - ProjectReferenceFile | - ReferencedFile | - AutomaticTypeDirectiveFile; + | RootFile + | LibFile + | ProjectReferenceFile + | ReferencedFile + | AutomaticTypeDirectiveFile; /** @internal */ export const enum FilePreprocessingDiagnosticsKind { @@ -4702,16 +4681,21 @@ export interface ResolutionDiagnostics { } /** @internal */ -export type FilePreprocessingDiagnostics = FilePreprocessingReferencedDiagnostic | FilePreprocessingFileExplainingDiagnostic | ResolutionDiagnostics; +export type FilePreprocessingDiagnostics = + | FilePreprocessingReferencedDiagnostic + | FilePreprocessingFileExplainingDiagnostic + | ResolutionDiagnostics; /** @internal */ -export const enum EmitOnly{ +export const enum EmitOnly { Js, Dts, } /** @internal */ -export interface LibResolution { +export interface LibResolution< + T extends ResolvedModuleWithFailedLookupLocations = ResolvedModuleWithFailedLookupLocations, +> { resolution: T; actual: string; } @@ -4749,21 +4733,49 @@ export interface Program extends ScriptReferenceHost { * used for writing the JavaScript and declaration files. Otherwise, the writeFile parameter * will be invoked when writing the JavaScript and declaration files. */ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult; - /** @internal */ - emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnly?: boolean | EmitOnly, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult; + emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnlyDtsFiles?: boolean, + customTransformers?: CustomTransformers, + ): EmitResult; + /** @internal */ + emit( + targetSourceFile?: SourceFile, + writeFile?: WriteFileCallback, + cancellationToken?: CancellationToken, + emitOnly?: boolean | EmitOnly, + customTransformers?: CustomTransformers, + forceDtsEmit?: boolean, + ): EmitResult; getOptionsDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[]; getGlobalDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[]; - getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; + getSyntacticDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; /** The first time this is called, it will return global diagnostics (no location). */ getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; - getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; + getDeclarationDiagnostics( + sourceFile?: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; getConfigFileParsingDiagnostics(): readonly Diagnostic[]; - /** @internal */ getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; - - /** @internal */ getBindAndCheckDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; - /** @internal */ getProgramDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[]; + /** @internal */ getSuggestionDiagnostics( + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; + + /** @internal */ getBindAndCheckDiagnostics( + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[]; + /** @internal */ getProgramDiagnostics( + sourceFile: SourceFile, + cancellationToken?: CancellationToken, + ): readonly Diagnostic[]; /** * Gets a type checker that can be used to semantically analyze source files in the program. @@ -4781,12 +4793,16 @@ export interface Program extends ScriptReferenceHost { getSymbolCount(): number; getTypeCount(): number; getInstantiationCount(): number; - getRelationCacheSizes(): { assignable: number, identity: number, subtype: number, strictSubtype: number }; + getRelationCacheSizes(): { assignable: number; identity: number; subtype: number; strictSubtype: number; }; /** @internal */ getFileProcessingDiagnostics(): FilePreprocessingDiagnostics[] | undefined; - /** @internal */ getResolvedTypeReferenceDirectives(): ModeAwareCache; + /** @internal */ getResolvedTypeReferenceDirectives(): ModeAwareCache< + ResolvedTypeReferenceDirectiveWithFailedLookupLocations + >; /** @internal */ getAutomaticTypeDirectiveNames(): string[]; - /** @internal */ getAutomaticTypeDirectiveResolutions(): ModeAwareCache; + /** @internal */ getAutomaticTypeDirectiveResolutions(): ModeAwareCache< + ResolvedTypeReferenceDirectiveWithFailedLookupLocations + >; isSourceFileFromExternalLibrary(file: SourceFile): boolean; isSourceFileDefaultLibrary(file: SourceFile): boolean; @@ -4794,7 +4810,10 @@ export interface Program extends ScriptReferenceHost { // This is set on created program to let us know how the program was created using old program /** @internal */ readonly structureIsReused: StructureIsReused; - /** @internal */ getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined; + /** @internal */ getSourceFileFromReference( + referencingFile: SourceFile | UnparsedSource, + ref: FileReference, + ): SourceFile | undefined; /** @internal */ getLibFileFromReference(ref: FileReference): SourceFile | undefined; /** @@ -4835,8 +4854,12 @@ export interface Program extends ScriptReferenceHost { getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined; /** @internal */ getProjectReferenceRedirect(fileName: string): string | undefined; /** @internal */ getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined; - /** @internal */ forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined; - /** @internal */ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined; + /** @internal */ forEachResolvedProjectReference( + cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, + ): T | undefined; + /** @internal */ getResolvedProjectReferenceByPath( + projectReferencePath: Path, + ): ResolvedProjectReference | undefined; /** @internal */ isSourceOfProjectReferenceRedirect(fileName: string): boolean; /** @internal */ getBuildInfo?(bundle: BundleBuildInfo | undefined): BuildInfo; /** @internal */ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult; @@ -4913,7 +4936,7 @@ export interface SourceMapSpan { /** @internal */ export interface SourceMapEmitResult { - inputSourceFileNames: readonly string[]; // Input source file (which one can use on program to get the file), 1:1 mapping with the sourceMap.sources list + inputSourceFileNames: readonly string[]; // Input source file (which one can use on program to get the file), 1:1 mapping with the sourceMap.sources list sourceMap: RawSourceMap; } @@ -4942,7 +4965,7 @@ export interface EmitResult { /** Contains declaration emit diagnostics */ diagnostics: readonly Diagnostic[]; emittedFiles?: string[]; // Array of files the compiler wrote to disk - /** @internal */ sourceMaps?: SourceMapEmitResult[]; // Array of sourceMapData if compiler emitted sourcemaps + /** @internal */ sourceMaps?: SourceMapEmitResult[]; // Array of sourceMapData if compiler emitted sourcemaps } /** @internal */ @@ -4992,7 +5015,10 @@ export interface TypeChecker { * @internal */ getParameterType(signature: Signature, parameterIndex: number): Type; - /** @internal */ getParameterIdentifierInfoAtPosition(signature: Signature, parameterIndex: number): { parameter: Identifier, parameterName: __String, isRestParameter: boolean } | undefined; + /** @internal */ getParameterIdentifierInfoAtPosition( + signature: Signature, + parameterIndex: number, + ): { parameter: Identifier; parameterName: __String; isRestParameter: boolean; } | undefined; getNullableType(type: Type, flags: TypeFlags): Type; getNonNullableType(type: Type): Type; /** @internal */ getNonOptionalType(type: Type): Type; @@ -5001,30 +5027,86 @@ export interface TypeChecker { // TODO: GH#18217 `xToDeclaration` calls are frequently asserted as defined. /** Note that the resulting nodes cannot be checked. */ - typeToTypeNode(type: Type, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): TypeNode | undefined; - /** @internal */ typeToTypeNode(type: Type, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker?: SymbolTracker): TypeNode | undefined; // eslint-disable-line @typescript-eslint/unified-signatures + typeToTypeNode( + type: Type, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): TypeNode | undefined; + /** @internal */ typeToTypeNode( + type: Type, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + tracker?: SymbolTracker, + ): TypeNode | undefined; // eslint-disable-line @typescript-eslint/unified-signatures /** Note that the resulting nodes cannot be checked. */ - signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): SignatureDeclaration & {typeArguments?: NodeArray} | undefined; - /** @internal */ signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker?: SymbolTracker): SignatureDeclaration & {typeArguments?: NodeArray} | undefined; // eslint-disable-line @typescript-eslint/unified-signatures + signatureToSignatureDeclaration( + signature: Signature, + kind: SyntaxKind, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): SignatureDeclaration & { typeArguments?: NodeArray; } | undefined; + /** @internal */ signatureToSignatureDeclaration( + signature: Signature, + kind: SyntaxKind, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + tracker?: SymbolTracker, + ): SignatureDeclaration & { typeArguments?: NodeArray; } | undefined; // eslint-disable-line @typescript-eslint/unified-signatures /** Note that the resulting nodes cannot be checked. */ - indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): IndexSignatureDeclaration | undefined; - /** @internal */ indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined, tracker?: SymbolTracker): IndexSignatureDeclaration | undefined; // eslint-disable-line @typescript-eslint/unified-signatures + indexInfoToIndexSignatureDeclaration( + indexInfo: IndexInfo, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): IndexSignatureDeclaration | undefined; + /** @internal */ indexInfoToIndexSignatureDeclaration( + indexInfo: IndexInfo, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + tracker?: SymbolTracker, + ): IndexSignatureDeclaration | undefined; // eslint-disable-line @typescript-eslint/unified-signatures /** Note that the resulting nodes cannot be checked. */ - symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): EntityName | undefined; + symbolToEntityName( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): EntityName | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToExpression(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): Expression | undefined; + symbolToExpression( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): Expression | undefined; /** * Note that the resulting nodes cannot be checked. * * @internal */ - symbolToNode(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): Node | undefined; + symbolToNode( + symbol: Symbol, + meaning: SymbolFlags, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): Node | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToTypeParameterDeclarations(symbol: Symbol, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): NodeArray | undefined; + symbolToTypeParameterDeclarations( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): NodeArray | undefined; /** Note that the resulting nodes cannot be checked. */ - symbolToParameterDeclaration(symbol: Symbol, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): ParameterDeclaration | undefined; + symbolToParameterDeclaration( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): ParameterDeclaration | undefined; /** Note that the resulting nodes cannot be checked. */ - typeParameterToDeclaration(parameter: TypeParameter, enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): TypeParameterDeclaration | undefined; + typeParameterToDeclaration( + parameter: TypeParameter, + enclosingDeclaration: Node | undefined, + flags: NodeBuilderFlags | undefined, + ): TypeParameterDeclaration | undefined; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolAtLocation(node: Node): Symbol | undefined; @@ -5051,15 +5133,47 @@ export interface TypeChecker { getTypeAtLocation(node: Node): Type; getTypeFromTypeNode(node: TypeNode): Type; - signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string; + signatureToString( + signature: Signature, + enclosingDeclaration?: Node, + flags?: TypeFormatFlags, + kind?: SignatureKind, + ): string; typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; - symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): string; + symbolToString( + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags?: SymbolFormatFlags, + ): string; typePredicateToString(predicate: TypePredicate, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; - /** @internal */ writeSignature(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind, writer?: EmitTextWriter): string; - /** @internal */ writeType(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags, writer?: EmitTextWriter): string; - /** @internal */ writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags, writer?: EmitTextWriter): string; - /** @internal */ writeTypePredicate(predicate: TypePredicate, enclosingDeclaration?: Node, flags?: TypeFormatFlags, writer?: EmitTextWriter): string; + /** @internal */ writeSignature( + signature: Signature, + enclosingDeclaration?: Node, + flags?: TypeFormatFlags, + kind?: SignatureKind, + writer?: EmitTextWriter, + ): string; + /** @internal */ writeType( + type: Type, + enclosingDeclaration?: Node, + flags?: TypeFormatFlags, + writer?: EmitTextWriter, + ): string; + /** @internal */ writeSymbol( + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags?: SymbolFormatFlags, + writer?: EmitTextWriter, + ): string; + /** @internal */ writeTypePredicate( + predicate: TypePredicate, + enclosingDeclaration?: Node, + flags?: TypeFormatFlags, + writer?: EmitTextWriter, + ): string; getFullyQualifiedName(symbol: Symbol): string; getAugmentedPropertiesOfType(type: Type): Symbol[]; @@ -5071,7 +5185,9 @@ export interface TypeChecker { /** @internal */ getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike): Type | undefined; /** @internal */ getContextualTypeForArgumentAtIndex(call: CallLikeExpression, argIndex: number): Type | undefined; /** @internal */ getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute): Type | undefined; - /** @internal */ isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike): boolean; + /** @internal */ isContextSensitive( + node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike, + ): boolean; /** @internal */ getTypeOfPropertyOfContextualType(type: Type, name: __String): Type | undefined; /** @@ -5079,9 +5195,22 @@ export interface TypeChecker { * returns undefined if the node is not valid. * @param argumentCount Apparent number of arguments, passed in case of a possibly incomplete call. This should come from an ArgumentListInfo. See `signatureHelp.ts`. */ - getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined; - /** @internal */ getResolvedSignatureForSignatureHelp(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined; - /** @internal */ getResolvedSignatureForStringLiteralCompletions(call: CallLikeExpression, editingArgument: Node, candidatesOutArray: Signature[], checkMode?: CheckMode): Signature | undefined; + getResolvedSignature( + node: CallLikeExpression, + candidatesOutArray?: Signature[], + argumentCount?: number, + ): Signature | undefined; + /** @internal */ getResolvedSignatureForSignatureHelp( + node: CallLikeExpression, + candidatesOutArray?: Signature[], + argumentCount?: number, + ): Signature | undefined; + /** @internal */ getResolvedSignatureForStringLiteralCompletions( + call: CallLikeExpression, + editingArgument: Node, + candidatesOutArray: Signature[], + checkMode?: CheckMode, + ): Signature | undefined; /** @internal */ getExpandedParameters(sig: Signature): readonly (readonly Symbol[])[]; /** @internal */ hasEffectiveRestParameter(sig: Signature): boolean; /** @internal */ containsArgumentsReference(declaration: SignatureDeclaration): boolean; @@ -5093,14 +5222,23 @@ export interface TypeChecker { isUnknownSymbol(symbol: Symbol): boolean; /** @internal */ getMergedSymbol(symbol: Symbol): Symbol; - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; - isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: string): boolean; + getConstantValue( + node: EnumMember | PropertyAccessExpression | ElementAccessExpression, + ): string | number | undefined; + isValidPropertyAccess( + node: PropertyAccessExpression | QualifiedName | ImportTypeNode, + propertyName: string, + ): boolean; /** * Exclude accesses to private properties. * * @internal */ - isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode | QualifiedName, type: Type, property: Symbol): boolean; + isValidPropertyAccessForCompletions( + node: PropertyAccessExpression | ImportTypeNode | QualifiedName, + type: Type, + property: Symbol, + ): boolean; /** Follow all aliases to get the original symbol. */ getAliasedSymbol(symbol: Symbol): Symbol; /** Follow a *single* alias to get the immediately aliased symbol. */ @@ -5112,7 +5250,10 @@ export interface TypeChecker { * @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[]; - /** @internal */ forEachExportAndPropertyOfModule(moduleSymbol: Symbol, cb: (symbol: Symbol, key: __String) => void): void; + /** @internal */ forEachExportAndPropertyOfModule( + moduleSymbol: Symbol, + cb: (symbol: Symbol, key: __String) => void, + ): void; getJsxIntrinsicTagNamesAt(location: Node): Symbol[]; isOptionalParameter(node: ParameterDeclaration): boolean; getAmbientModules(): Symbol[]; @@ -5126,11 +5267,28 @@ export interface TypeChecker { */ tryGetMemberInModuleExportsAndProperties(memberName: string, moduleSymbol: Symbol): Symbol | undefined; getApparentType(type: Type): Type; - /** @internal */ getSuggestedSymbolForNonexistentProperty(name: MemberName | string, containingType: Type): Symbol | undefined; - /** @internal */ getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | string, containingType: Type): Symbol | undefined; - /** @internal */ getSuggestionForNonexistentProperty(name: MemberName | string, containingType: Type): string | undefined; - /** @internal */ getSuggestedSymbolForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined; - /** @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; + /** @internal */ getSuggestedSymbolForNonexistentProperty( + name: MemberName | string, + containingType: Type, + ): Symbol | undefined; + /** @internal */ getSuggestedSymbolForNonexistentJSXAttribute( + name: Identifier | string, + containingType: Type, + ): Symbol | undefined; + /** @internal */ getSuggestionForNonexistentProperty( + name: MemberName | string, + containingType: Type, + ): string | undefined; + /** @internal */ getSuggestedSymbolForNonexistentSymbol( + location: Node, + name: string, + meaning: SymbolFlags, + ): Symbol | undefined; + /** @internal */ getSuggestionForNonexistentSymbol( + location: Node, + name: string, + meaning: SymbolFlags, + ): string | undefined; /** @internal */ getSuggestedSymbolForNonexistentModule(node: Identifier, target: Symbol): Symbol | undefined; /** @internal */ getSuggestedSymbolForNonexistentClassMember(name: string, baseType: Type): Symbol | undefined; /** @internal */ getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined; @@ -5187,7 +5345,13 @@ export interface TypeChecker { /** @internal */ getAsyncIterableType(): Type | undefined; /** @internal */ isTypeAssignableTo(source: Type, target: Type): boolean; - /** @internal */ createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], indexInfos: IndexInfo[]): Type; + /** @internal */ createAnonymousType( + symbol: Symbol | undefined, + members: SymbolTable, + callSignatures: Signature[], + constructSignatures: Signature[], + indexInfos: IndexInfo[], + ): Type; /** @internal */ createSignature( declaration: SignatureDeclaration | undefined, typeParameters: readonly TypeParameter[] | undefined, @@ -5196,11 +5360,21 @@ export interface TypeChecker { resolvedReturnType: Type, typePredicate: TypePredicate | undefined, minArgumentCount: number, - flags: SignatureFlags + flags: SignatureFlags, ): Signature; /** @internal */ createSymbol(flags: SymbolFlags, name: __String): TransientSymbol; - /** @internal */ createIndexInfo(keyType: Type, type: Type, isReadonly: boolean, declaration?: SignatureDeclaration): IndexInfo; - /** @internal */ isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; + /** @internal */ createIndexInfo( + keyType: Type, + type: Type, + isReadonly: boolean, + declaration?: SignatureDeclaration, + ): IndexInfo; + /** @internal */ isSymbolAccessible( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + shouldComputeAliasToMarkVisible: boolean, + ): SymbolAccessibilityResult; /** @internal */ tryFindAmbientModule(moduleName: string): Symbol | undefined; /** @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol | undefined; @@ -5216,9 +5390,19 @@ export interface TypeChecker { /** @internal */ getSymbolCount(): number; /** @internal */ getTypeCount(): number; /** @internal */ getInstantiationCount(): number; - /** @internal */ getRelationCacheSizes(): { assignable: number, identity: number, subtype: number, strictSubtype: number }; + /** @internal */ getRelationCacheSizes(): { + assignable: number; + identity: number; + subtype: number; + strictSubtype: number; + }; /** @internal */ getRecursionIdentity(type: Type): object | undefined; - /** @internal */ getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean): IterableIterator; + /** @internal */ getUnmatchedProperties( + source: Type, + target: Type, + requireOptionalProperties: boolean, + matchDiscriminantProperties: boolean, + ): IterableIterator; /** * True if this type is the `Array` or `ReadonlyArray` type from lib.d.ts. @@ -5252,7 +5436,12 @@ export interface TypeChecker { * @internal */ getAllPossiblePropertiesOfTypes(type: readonly Type[]): Symbol[]; - /** @internal */ resolveName(name: string, location: Node | undefined, meaning: SymbolFlags, excludeGlobals: boolean): Symbol | undefined; + /** @internal */ resolveName( + name: string, + location: Node | undefined, + meaning: SymbolFlags, + excludeGlobals: boolean, + ): Symbol | undefined; /** @internal */ getJsxNamespace(location?: Node): string; /** @internal */ getJsxFragmentFactory(location: Node): string | undefined; @@ -5267,7 +5456,12 @@ export interface TypeChecker { * * @internal */ - getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined; + getAccessibleSymbolChain( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags, + useOnlyExternalAliasing: boolean, + ): Symbol[] | undefined; getTypePredicateOfSignature(signature: Signature): TypePredicate | undefined; /** @internal */ resolveExternalModuleName(moduleSpecifier: Expression): Symbol | undefined; /** @@ -5291,7 +5485,10 @@ export interface TypeChecker { * * @internal */ - getSuggestionDiagnostics(file: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[]; + getSuggestionDiagnostics( + file: SourceFile, + cancellationToken?: CancellationToken, + ): readonly DiagnosticWithLocation[]; /** * Depending on the operation performed, it may be appropriate to throw away the checker @@ -5300,11 +5497,23 @@ export interface TypeChecker { */ runWithCancellationToken(token: CancellationToken, cb: (checker: TypeChecker) => T): T; - /** @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): readonly TypeParameter[] | undefined; + /** @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias( + symbol: Symbol, + ): readonly TypeParameter[] | undefined; /** @internal */ isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean; - /** @internal */ isPropertyAccessible(node: Node, isSuper: boolean, isWrite: boolean, containingType: Type, property: Symbol): boolean; + /** @internal */ isPropertyAccessible( + node: Node, + isSuper: boolean, + isWrite: boolean, + containingType: Type, + property: Symbol, + ): boolean; /** @internal */ getTypeOnlyAliasDeclaration(symbol: Symbol): TypeOnlyAliasDeclaration | undefined; - /** @internal */ getMemberOverrideModifierStatus(node: ClassLikeDeclaration, member: ClassElement, memberSymbol: Symbol): MemberOverrideStatus; + /** @internal */ getMemberOverrideModifierStatus( + node: ClassLikeDeclaration, + member: ClassElement, + memberSymbol: Symbol, + ): MemberOverrideStatus; /** @internal */ isTypeParameterPossiblyReferenced(tp: TypeParameter, node: Node): boolean; /** @internal */ typeHasCallOrConstructSignatures(type: Type): boolean; } @@ -5313,7 +5522,7 @@ export interface TypeChecker { export const enum MemberOverrideStatus { Ok, NeedsOverride, - HasInvalidOverride + HasInvalidOverride, } /** @internal */ @@ -5323,6 +5532,7 @@ export const enum UnionReduction { Subtype, } +// dprint-ignore /** @internal */ export const enum ContextFlags { None = 0, @@ -5333,6 +5543,7 @@ export const enum ContextFlags { } // NOTE: If modifying this enum, must modify `TypeFormatFlags` too! +// dprint-ignore export const enum NodeBuilderFlags { None = 0, // Options @@ -5378,6 +5589,7 @@ export const enum NodeBuilderFlags { } // Ensure the shared flags between this and `NodeBuilderFlags` stay in alignment +// dprint-ignore export const enum TypeFormatFlags { None = 0, NoTruncation = 1 << 0, // Don't truncate typeToString result @@ -5416,9 +5628,10 @@ export const enum TypeFormatFlags { NodeBuilderFlagsMask = NoTruncation | WriteArrayAsGenericType | UseStructuralFallback | WriteTypeArgumentsOfSignature | UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals | WriteClassExpressionAsTypeLiteral | UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias | - UseSingleQuotesForStringLiteralType | NoTypeReduction | OmitThisParameter + UseSingleQuotesForStringLiteralType | NoTypeReduction | OmitThisParameter, } +// dprint-ignore export const enum SymbolFormatFlags { None = 0, @@ -5449,9 +5662,9 @@ export const enum SymbolFormatFlags { /** @internal */ export interface SymbolWalker { /** Note: Return values are not ordered. */ - walkType(root: Type): { visitedTypes: readonly Type[], visitedSymbols: readonly Symbol[] }; + walkType(root: Type): { visitedTypes: readonly Type[]; visitedSymbols: readonly Symbol[]; }; /** Note: Return values are not ordered. */ - walkSymbol(root: Symbol): { visitedTypes: readonly Type[], visitedSymbols: readonly Symbol[] }; + walkSymbol(root: Symbol): { visitedTypes: readonly Type[]; visitedSymbols: readonly Symbol[]; }; } // This was previously deprecated in our public API, but is still used internally @@ -5475,20 +5688,20 @@ export interface SymbolWriter { export const enum SymbolAccessibility { Accessible, NotAccessible, - CannotBeNamed + CannotBeNamed, } /** @internal */ export const enum SyntheticSymbolKind { UnionOrIntersection, - Spread + Spread, } export const enum TypePredicateKind { This, Identifier, AssertsThis, - AssertsIdentifier + AssertsIdentifier, } export interface TypePredicateBase { @@ -5524,7 +5737,11 @@ export interface AssertsIdentifierTypePredicate extends TypePredicateBase { type: Type | undefined; } -export type TypePredicate = ThisTypePredicate | IdentifierTypePredicate | AssertsThisTypePredicate | AssertsIdentifierTypePredicate; +export type TypePredicate = + | ThisTypePredicate + | IdentifierTypePredicate + | AssertsThisTypePredicate + | AssertsIdentifierTypePredicate; /** @internal */ export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; @@ -5533,13 +5750,17 @@ export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; export type AnyImportOrRequire = AnyImportSyntax | VariableDeclarationInitializedTo; /** @internal */ -export type AnyImportOrBareOrAccessedRequire = AnyImportSyntax | VariableDeclarationInitializedTo; +export type AnyImportOrBareOrAccessedRequire = + | AnyImportSyntax + | VariableDeclarationInitializedTo; /** @internal */ export type AliasDeclarationNode = | ImportEqualsDeclaration - | VariableDeclarationInitializedTo + | VariableDeclarationInitializedTo< + | RequireOrImportCall + | AccessExpression + > | ImportClause | NamespaceImport | ImportSpecifier @@ -5548,7 +5769,9 @@ export type AliasDeclarationNode = | BindingElementOfBareOrAccessedRequire; /** @internal */ -export type BindingElementOfBareOrAccessedRequire = BindingElement & { parent: { parent: VariableDeclarationInitializedTo } }; +export type BindingElementOfBareOrAccessedRequire = BindingElement & { + parent: { parent: VariableDeclarationInitializedTo; }; +}; /** @internal */ export type AnyImportOrRequireStatement = AnyImportSyntax | RequireVariableStatement; @@ -5558,18 +5781,18 @@ export type AnyImportOrReExport = AnyImportSyntax | ExportDeclaration; /** @internal */ export interface ValidImportTypeNode extends ImportTypeNode { - argument: LiteralTypeNode & { literal: StringLiteral }; + argument: LiteralTypeNode & { literal: StringLiteral; }; } /** @internal */ export type AnyValidImportOrReExport = - | (ImportDeclaration | ExportDeclaration) & { moduleSpecifier: StringLiteral } - | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral } } + | (ImportDeclaration | ExportDeclaration) & { moduleSpecifier: StringLiteral; } + | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral; }; } | RequireOrImportCall | ValidImportTypeNode; /** @internal */ -export type RequireOrImportCall = CallExpression & { expression: Identifier, arguments: [StringLiteralLike] }; +export type RequireOrImportCall = CallExpression & { expression: Identifier; arguments: [StringLiteralLike]; }; /** @internal */ export interface VariableDeclarationInitializedTo extends VariableDeclaration { @@ -5676,7 +5899,10 @@ export enum TypeReferenceSerializationKind { /** @internal */ export interface EmitResolver { hasGlobalName(name: string): boolean; - getReferencedExportContainer(node: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration | undefined; + getReferencedExportContainer( + node: Identifier, + prefixLocals?: boolean, + ): SourceFile | ModuleDeclaration | EnumDeclaration | undefined; getReferencedImportDeclaration(node: Identifier): Declaration | undefined; getReferencedDeclarationWithCollidingName(node: Identifier): Declaration | undefined; isDeclarationWithCollidingName(node: Declaration): boolean; @@ -5692,33 +5918,88 @@ export interface EmitResolver { isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean; isExpandoFunctionDeclaration(node: FunctionDeclaration): boolean; getPropertiesOfContainerFunction(node: Declaration): Symbol[]; - createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined; - createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined; - createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined; - createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression; - isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags | undefined, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; - isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult; + createTypeOfDeclaration( + declaration: + | AccessorDeclaration + | VariableLikeDeclaration + | PropertyAccessExpression + | ElementAccessExpression + | BinaryExpression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + addUndefined?: boolean, + ): TypeNode | undefined; + createReturnTypeOfSignatureDeclaration( + signatureDeclaration: SignatureDeclaration, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + ): TypeNode | undefined; + createTypeOfExpression( + expr: Expression, + enclosingDeclaration: Node, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + ): TypeNode | undefined; + createLiteralConstValue( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, + tracker: SymbolTracker, + ): Expression; + isSymbolAccessible( + symbol: Symbol, + enclosingDeclaration: Node | undefined, + meaning: SymbolFlags | undefined, + shouldComputeAliasToMarkVisible: boolean, + ): SymbolAccessibilityResult; + isEntityNameVisible( + entityName: EntityNameOrEntityNameExpression, + enclosingDeclaration: Node, + ): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; + getConstantValue( + node: EnumMember | PropertyAccessExpression | ElementAccessExpression, + ): string | number | undefined; getReferencedValueDeclaration(reference: Identifier): Declaration | undefined; getReferencedValueDeclarations(reference: Identifier): Declaration[] | undefined; getTypeReferenceSerializationKind(typeName: EntityName, location?: Node): TypeReferenceSerializationKind; isOptionalParameter(node: ParameterDeclaration): boolean; moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean; isArgumentsLocalBinding(node: Identifier): boolean; - getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined; - getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): [specifier: string, mode: ResolutionMode][] | undefined; - getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): [specifier: string, mode: ResolutionMode][] | undefined; - isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean; + getExternalModuleFileFromDeclaration( + declaration: + | ImportEqualsDeclaration + | ImportDeclaration + | ExportDeclaration + | ModuleDeclaration + | ImportTypeNode + | ImportCall, + ): SourceFile | undefined; + getTypeReferenceDirectivesForEntityName( + name: EntityNameOrEntityNameExpression, + ): [specifier: string, mode: ResolutionMode][] | undefined; + getTypeReferenceDirectivesForSymbol( + symbol: Symbol, + meaning?: SymbolFlags, + ): [specifier: string, mode: ResolutionMode][] | undefined; + isLiteralConstDeclaration( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, + ): boolean; getJsxFactoryEntity(location?: Node): EntityName | undefined; getJsxFragmentFactoryEntity(location?: Node): EntityName | undefined; getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations; getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined; isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean; - getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker, bundled?: boolean): Statement[] | undefined; + getDeclarationStatementsForSourceFile( + node: SourceFile, + flags: NodeBuilderFlags, + tracker: SymbolTracker, + bundled?: boolean, + ): Statement[] | undefined; isImportRequiredByAugmentation(decl: ImportDeclaration): boolean; } +// dprint-ignore export const enum SymbolFlags { None = 0, FunctionScopedVariable = 1 << 0, // Variable (var) or parameter @@ -5815,6 +6096,7 @@ export const enum SymbolFlags { /** @internal */ export type SymbolId = number; +// dprint-ignore export interface Symbol { flags: SymbolFlags; // Symbol flags escapedName: __String; // Name of symbol @@ -5834,6 +6116,7 @@ export interface Symbol { /** @internal */ assignmentDeclarationMembers?: Map; // detected late-bound assignment declarations associated with the symbol } +// dprint-ignore /** @internal */ export interface SymbolLinks { _symbolLinksBrand: any; @@ -5888,10 +6171,11 @@ export interface SymbolLinks { /** @internal */ export const enum EnumKind { - Numeric, // Numeric enum (each member has a TypeFlags.Enum type) - Literal // Literal enum (each member has a TypeFlags.EnumLiteral type) + Numeric, // Numeric enum (each member has a TypeFlags.Enum type) + Literal, // Literal enum (each member has a TypeFlags.EnumLiteral type) } +// dprint-ignore /** @internal */ export const enum CheckFlags { None = 0, @@ -5918,7 +6202,7 @@ export const enum CheckFlags { Unresolved = 1 << 20, // Unresolved type alias symbol Synthetic = SyntheticProperty | SyntheticMethod, Discriminant = HasNonUniformType | HasLiteralType, - Partial = ReadPartial | WritePartial + Partial = ReadPartial | WritePartial, } /** @internal */ @@ -5982,7 +6266,10 @@ export const enum InternalSymbolName { * with a normal string (which is good, it cannot be misused on assignment or on usage), * while still being comparable with a normal string via === (also good) and castable from a string. */ -export type __String = (string & { __escapedIdentifier: void }) | (void & { __escapedIdentifier: void }) | InternalSymbolName; +export type __String = + | (string & { __escapedIdentifier: void; }) + | (void & { __escapedIdentifier: void; }) + | InternalSymbolName; /** @deprecated Use ReadonlyMap<__String, T> instead. */ export type ReadonlyUnderscoreEscapedMap = ReadonlyMap<__String, T>; @@ -6003,6 +6290,7 @@ export interface PatternAmbientModule { symbol: Symbol; } +// dprint-ignore /** @internal */ export const enum NodeCheckFlags { None = 0, @@ -6031,6 +6319,7 @@ export const enum NodeCheckFlags { InCheckIdentifier = 1 << 22, } +// dprint-ignore /** @internal */ export interface NodeLinks { flags: NodeCheckFlags; // Set of flags specific to Node @@ -6073,6 +6362,7 @@ export interface SerializedTypeEntry { addedLength: number; } +// dprint-ignore export const enum TypeFlags { Any = 1 << 0, Unknown = 1 << 1, @@ -6172,6 +6462,7 @@ export type DestructuringPattern = BindingPattern | ObjectLiteralExpression | Ar export type TypeId = number; // Properties common to all types +// dprint-ignore export interface Type { flags: TypeFlags; // Flags /** @internal */ id: TypeId; // Unique ID @@ -6193,7 +6484,7 @@ export interface Type { /** @internal */ // Intrinsic types (TypeFlags.Intrinsic) export interface IntrinsicType extends Type { - intrinsicName: string; // Name of intrinsic type + intrinsicName: string; // Name of intrinsic type objectFlags: ObjectFlags; } @@ -6203,8 +6494,8 @@ export interface NullableType extends IntrinsicType { } export interface FreshableType extends Type { - freshType: FreshableType; // Fresh version of type - regularType: FreshableType; // Regular version of type + freshType: FreshableType; // Fresh version of type + regularType: FreshableType; // Regular version of type } /** @internal */ @@ -6243,6 +6534,7 @@ export interface EnumType extends FreshableType { // Types included in TypeFlags.ObjectFlagsType have an objectFlags property. Some ObjectFlags // are specific to certain types and reuse the same bit position. Those ObjectFlags require a check // for a certain TypeFlags value to determine their meaning. +// dprint-ignore export const enum ObjectFlags { None = 0, Class = 1 << 0, // Class @@ -6324,6 +6616,7 @@ export const enum ObjectFlags { export type ObjectFlagsType = NullableType | ObjectType | UnionType | IntersectionType | TemplateLiteralType; // Object types (TypeFlags.ObjectType) +// dprint-ignore export interface ObjectType extends Type { objectFlags: ObjectFlags; /** @internal */ members?: SymbolTable; // Properties by name @@ -6335,6 +6628,7 @@ export interface ObjectType extends Type { } /** Class and interface types (ObjectFlags.Class and ObjectFlags.Interface). */ +// dprint-ignore export interface InterfaceType extends ObjectType { typeParameters: TypeParameter[] | undefined; // Type parameters (undefined if non-generic) outerTypeParameters: TypeParameter[] | undefined; // Outer type parameters (undefined if none) @@ -6351,6 +6645,7 @@ export interface InterfaceType extends ObjectType { // Object type or intersection of object types export type BaseType = ObjectType | IntersectionType | TypeVariable; // Also `any` and `object` +// dprint-ignore export interface InterfaceTypeWithDeclaredMembers extends InterfaceType { declaredProperties: Symbol[]; // Declared members declaredCallSignatures: Signature[]; // Declared call signatures @@ -6369,14 +6664,14 @@ export interface InterfaceTypeWithDeclaredMembers extends InterfaceType { * explicit "this" argument. */ export interface TypeReference extends ObjectType { - target: GenericType; // Type reference target + target: GenericType; // Type reference target node?: TypeReferenceNode | ArrayTypeNode | TupleTypeNode; /** @internal */ mapper?: TypeMapper; /** @internal */ - resolvedTypeArguments?: readonly Type[]; // Resolved type reference type arguments + resolvedTypeArguments?: readonly Type[]; // Resolved type reference type arguments /** @internal */ - literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set + literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set /** @internal */ cachedEquivalentBaseType?: Type; // Only set on references to class or interfaces with a single base type and no augmentations } @@ -6390,6 +6685,7 @@ export interface DeferredTypeReference extends TypeReference { instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) } +// dprint-ignore /** @internal */ export const enum VarianceFlags { Invariant = 0, // Neither covariant nor contravariant @@ -6406,11 +6702,12 @@ export const enum VarianceFlags { // Generic class and interface types export interface GenericType extends InterfaceType, TypeReference { /** @internal */ - instantiations: Map; // Generic instantiation cache + instantiations: Map; // Generic instantiation cache /** @internal */ - variances?: VarianceFlags[]; // Variance of each type parameter + variances?: VarianceFlags[]; // Variance of each type parameter } +// dprint-ignore export const enum ElementFlags { Required = 1 << 0, // T Optional = 1 << 1, // T? @@ -6440,11 +6737,11 @@ export interface TupleTypeReference extends TypeReference { } export interface UnionOrIntersectionType extends Type { - types: Type[]; // Constituent types + types: Type[]; // Constituent types /** @internal */ objectFlags: ObjectFlags; /** @internal */ - propertyCache?: SymbolTable; // Cache of resolved properties + propertyCache?: SymbolTable; // Cache of resolved properties /** @internal */ propertyCacheWithoutObjectFunctionPropertyAugment?: SymbolTable; // Cache of resolved properties that does not augment function or object type properties /** @internal */ @@ -6463,11 +6760,11 @@ export interface UnionType extends UnionOrIntersectionType { /** @internal */ regularType?: UnionType; /** @internal */ - origin?: Type; // Denormalized union, intersection, or index type in which union originates + origin?: Type; // Denormalized union, intersection, or index type in which union originates /** @internal */ - keyPropertyName?: __String; // Property with unique unit type that exists in every object/intersection in union type + keyPropertyName?: __String; // Property with unique unit type that exists in every object/intersection in union type /** @internal */ - constituentMap?: Map; // Constituents keyed by unit type discriminants + constituentMap?: Map; // Constituents keyed by unit type discriminants /** @internal */ arrayFallbackSignatures?: readonly Signature[]; // Special remapped signature list for unions of arrays } @@ -6476,7 +6773,7 @@ export interface IntersectionType extends UnionOrIntersectionType { /** @internal */ resolvedApparentType: Type; /** @internal */ - uniqueLiteralFilledInstantiation?: Type; // Instantiation with type parameters mapped to never type + uniqueLiteralFilledInstantiation?: Type; // Instantiation with type parameters mapped to never type } export type StructuredType = ObjectType | UnionType | IntersectionType; @@ -6484,8 +6781,8 @@ export type StructuredType = ObjectType | UnionType | IntersectionType; /** @internal */ // An instantiated anonymous type has a target and a mapper export interface AnonymousType extends ObjectType { - target?: AnonymousType; // Instantiation target - mapper?: TypeMapper; // Instantiation mapper + target?: AnonymousType; // Instantiation target + mapper?: TypeMapper; // Instantiation mapper instantiations?: Map; // Instantiations of generic type alias (undefined if non-generic) } @@ -6507,8 +6804,8 @@ export interface MappedType extends AnonymousType { } export interface EvolvingArrayType extends ObjectType { - elementType: Type; // Element expressions of evolving array type - finalArrayType?: Type; // Final array type of evolving array type + elementType: Type; // Element expressions of evolving array type + finalArrayType?: Type; // Final array type of evolving array type } /** @internal */ @@ -6520,6 +6817,7 @@ export interface ReverseMappedType extends ObjectType { /** @internal */ // Resolved object, union, or intersection type +// dprint-ignore export interface ResolvedType extends ObjectType, UnionOrIntersectionType { members: SymbolTable; // Properties by name properties: Symbol[]; // Properties @@ -6533,7 +6831,7 @@ export interface ResolvedType extends ObjectType, UnionOrIntersectionType { // before a type assertion, or when an object literal's type is widened. The regular // version of a fresh type is identical except for the TypeFlags.FreshObjectLiteral flag. export interface FreshObjectLiteralType extends ResolvedType { - regularType: ResolvedType; // Regular version of fresh type + regularType: ResolvedType; // Regular version of fresh type } /** @internal */ @@ -6578,6 +6876,7 @@ export interface InstantiableType extends Type { } // Type parameters (TypeFlags.TypeParameter) +// dprint-ignore export interface TypeParameter extends InstantiableType { /** * Retrieve using getConstraintFromTypeParameter @@ -6618,7 +6917,7 @@ export interface IndexedAccessType extends InstantiableType { objectType: Type; indexType: Type; /** @internal */ - accessFlags: AccessFlags; // Only includes AccessFlags.Persistent + accessFlags: AccessFlags; // Only includes AccessFlags.Persistent constraint?: Type; simplifiedForReading?: Type; simplifiedForWriting?: Type; @@ -6675,8 +6974,8 @@ export interface ConditionalType extends InstantiableType { export interface TemplateLiteralType extends InstantiableType { /** @internal */ objectFlags: ObjectFlags; - texts: readonly string[]; // Always one element longer than types - types: readonly Type[]; // Always at least one element + texts: readonly string[]; // Always one element longer than types + types: readonly Type[]; // Always at least one element } export interface StringMappingType extends InstantiableType { @@ -6692,15 +6991,15 @@ export interface StringMappingType extends InstantiableType { // types disappear upon instantiation (just like type parameters). export interface SubstitutionType extends InstantiableType { objectFlags: ObjectFlags; - baseType: Type; // Target type - constraint: Type; // Constraint that target type is known to satisfy + baseType: Type; // Target type + constraint: Type; // Constraint that target type is known to satisfy } /** @internal */ export const enum JsxReferenceKind { Component, Function, - Mixed + Mixed, } export const enum SignatureKind { @@ -6708,6 +7007,7 @@ export const enum SignatureKind { Construct, } +// dprint-ignore /** @internal */ export const enum SignatureFlags { None = 0, @@ -6732,6 +7032,7 @@ export const enum SignatureFlags { CallChainFlags = IsInnerCallChain | IsOuterCallChain, } +// dprint-ignore export interface Signature { /** @internal */ flags: SignatureFlags; /** @internal */ checker?: TypeChecker; @@ -6798,12 +7099,13 @@ export const enum TypeMapKind { /** @internal */ export type TypeMapper = - | { kind: TypeMapKind.Simple, source: Type, target: Type } - | { kind: TypeMapKind.Array, sources: readonly Type[], targets: readonly Type[] | undefined } - | { kind: TypeMapKind.Deferred, sources: readonly Type[], targets: (() => Type)[] } - | { kind: TypeMapKind.Function, func: (t: Type) => Type, debugInfo?: () => string } - | { kind: TypeMapKind.Composite | TypeMapKind.Merged, mapper1: TypeMapper, mapper2: TypeMapper }; + | { kind: TypeMapKind.Simple; source: Type; target: Type; } + | { kind: TypeMapKind.Array; sources: readonly Type[]; targets: readonly Type[] | undefined; } + | { kind: TypeMapKind.Deferred; sources: readonly Type[]; targets: (() => Type)[]; } + | { kind: TypeMapKind.Function; func: (t: Type) => Type; debugInfo?: () => string; } + | { kind: TypeMapKind.Composite | TypeMapKind.Merged; mapper1: TypeMapper; mapper2: TypeMapper; }; +// dprint-ignore export const enum InferencePriority { None = 0, NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type @@ -6823,6 +7125,7 @@ export const enum InferencePriority { Circularity = -1, // Inference circularity (value less than all other priorities) } +// dprint-ignore /** @internal */ export interface InferenceInfo { typeParameter: TypeParameter; // Type parameter for which inferences are being made @@ -6835,6 +7138,7 @@ export interface InferenceInfo { impliedArity?: number; } +// dprint-ignore /** @internal */ export const enum InferenceFlags { None = 0, // No special inference behaviors @@ -6857,12 +7161,13 @@ export const enum Ternary { False = 0, Unknown = 1, Maybe = 3, - True = -1 + True = -1, } /** @internal */ export type TypeComparer = (s: Type, t: Type, reportErrors?: boolean) => Ternary; +// dprint-ignore /** @internal */ export interface InferenceContext { inferences: InferenceInfo[]; // Inferences made for each type parameter @@ -6882,6 +7187,7 @@ export interface IntraExpressionInferenceSite { type: Type; } +// dprint-ignore /** @internal */ export interface WideningContext { parent?: WideningContext; // Parent context @@ -6963,7 +7269,7 @@ export interface Diagnostic extends DiagnosticRelatedInformation { /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ reportsUnnecessary?: {}; - reportsDeprecated?: {} + reportsDeprecated?: {}; source?: string; relatedInformation?: DiagnosticRelatedInformation[]; /** @internal */ skippedOn?: keyof CompilerOptions; @@ -7002,31 +7308,31 @@ export enum DiagnosticCategory { Warning, Error, Suggestion, - Message + Message, } /** @internal */ -export function diagnosticCategoryName(d: { category: DiagnosticCategory }, lowerCase = true): string { +export function diagnosticCategoryName(d: { category: DiagnosticCategory; }, lowerCase = true): string { const name = DiagnosticCategory[d.category]; return lowerCase ? name.toLowerCase() : name; } export enum ModuleResolutionKind { - Classic = 1, + Classic = 1, /** * @deprecated * `NodeJs` was renamed to `Node10` to better reflect the version of Node that it targets. * Use the new name or consider switching to a modern module resolution target. */ - NodeJs = 2, - Node10 = 2, + NodeJs = 2, + Node10 = 2, // Starting with node12, node's module resolver has significant departures from traditional cjs resolution // to better support ecmascript modules and their use within node - however more features are still being added. // TypeScript's Node ESM support was introduced after Node 12 went end-of-life, and Node 14 is the earliest stable // version that supports both pattern trailers - *but*, Node 16 is the first version that also supports ECMASCript 2022. // In turn, we offer both a `NodeNext` moving resolution target, and a `Node16` version-anchored resolution target - Node16 = 3, + Node16 = 3, NodeNext = 99, // Not simply `Node16` so that compiled code linked against TS can use the `Next` value reliably (same as with `ModuleKind`) - Bundler = 100, + Bundler = 100, } export enum ModuleDetectionKind { @@ -7082,7 +7388,17 @@ export enum PollingWatchKind { FixedChunkSize, } -export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | ProjectReference[] | null | undefined; +export type CompilerOptionsValue = + | string + | number + | boolean + | (string | number)[] + | string[] + | MapLike + | PluginImport[] + | ProjectReference[] + | null + | undefined; export interface CompilerOptions { /** @internal */ all?: boolean; @@ -7094,7 +7410,7 @@ export interface CompilerOptions { allowUmdGlobalAccess?: boolean; allowUnreachableCode?: boolean; allowUnusedLabels?: boolean; - alwaysStrict?: boolean; // Always combine with strict property + alwaysStrict?: boolean; // Always combine with strict property baseUrl?: string; /** * An error if set - this should only go through the -b pipeline and not actually be observed @@ -7128,23 +7444,23 @@ export interface CompilerOptions { exactOptionalPropertyTypes?: boolean; experimentalDecorators?: boolean; forceConsistentCasingInFileNames?: boolean; - /** @internal */generateCpuProfile?: string; - /** @internal */generateTrace?: string; - /** @internal */help?: boolean; + /** @internal */ generateCpuProfile?: string; + /** @internal */ generateTrace?: string; + /** @internal */ help?: boolean; ignoreDeprecations?: string; importHelpers?: boolean; importsNotUsedAsValues?: ImportsNotUsedAsValues; - /** @internal */init?: boolean; + /** @internal */ init?: boolean; inlineSourceMap?: boolean; inlineSources?: boolean; isolatedModules?: boolean; jsx?: JsxEmit; keyofStringsOnly?: boolean; lib?: string[]; - /** @internal */listEmittedFiles?: boolean; - /** @internal */listFiles?: boolean; - /** @internal */explainFiles?: boolean; - /** @internal */listFilesOnly?: boolean; + /** @internal */ listEmittedFiles?: boolean; + /** @internal */ listFiles?: boolean; + /** @internal */ explainFiles?: boolean; + /** @internal */ listFilesOnly?: boolean; locale?: string; mapRoot?: string; maxNodeModuleJsDepth?: number; @@ -7154,14 +7470,14 @@ export interface CompilerOptions { moduleDetection?: ModuleDetectionKind; newLine?: NewLineKind; noEmit?: boolean; - /** @internal */noEmitForJsFiles?: boolean; + /** @internal */ noEmitForJsFiles?: boolean; noEmitHelpers?: boolean; noEmitOnError?: boolean; noErrorTruncation?: boolean; noFallthroughCasesInSwitch?: boolean; - noImplicitAny?: boolean; // Always combine with strict property + noImplicitAny?: boolean; // Always combine with strict property noImplicitReturns?: boolean; - noImplicitThis?: boolean; // Always combine with strict property + noImplicitThis?: boolean; // Always combine with strict property noStrictGenericChecks?: boolean; noUnusedLocals?: boolean; noUnusedParameters?: boolean; @@ -7208,10 +7524,10 @@ export interface CompilerOptions { sourceMap?: boolean; sourceRoot?: string; strict?: boolean; - strictFunctionTypes?: boolean; // Always combine with strict property - strictBindCallApply?: boolean; // Always combine with strict property - strictNullChecks?: boolean; // Always combine with strict property - strictPropertyInitialization?: boolean; // Always combine with strict property + strictFunctionTypes?: boolean; // Always combine with strict property + strictBindCallApply?: boolean; // Always combine with strict property + strictNullChecks?: boolean; // Always combine with strict property + strictPropertyInitialization?: boolean; // Always combine with strict property stripInternal?: boolean; suppressExcessPropertyErrors?: boolean; suppressImplicitAnyIndexErrors?: boolean; @@ -7289,7 +7605,7 @@ export const enum ImportsNotUsedAsValues { export const enum NewLineKind { CarriageReturnLineFeed = 0, - LineFeed = 1 + LineFeed = 1, } export interface LineAndCharacter { @@ -7313,7 +7629,7 @@ export const enum ScriptKind { * Used on extensions that doesn't define the ScriptKind but the content defines it. * Deferred extensions are going to be included in all project contexts. */ - Deferred = 7 + Deferred = 7, } export const enum ScriptTarget { @@ -7334,7 +7650,7 @@ export const enum ScriptTarget { export const enum LanguageVariant { Standard, - JSX + JSX, } /** Either a parsed command line or a parsed tsconfig.json */ @@ -7375,8 +7691,8 @@ export interface ConfigFileSpecs { /** @internal */ export type ModuleImportResult = - | { module: T, modulePath?: string, error: undefined } - | { module: undefined, modulePath?: undefined, error: { stack?: string, message?: string } }; + | { module: T; modulePath?: string; error: undefined; } + | { module: undefined; modulePath?: undefined; error: { stack?: string; message?: string; }; }; export interface CreateProgramOptions { rootNames: readonly string[]; @@ -7389,6 +7705,7 @@ export interface CreateProgramOptions { typeScriptVersion?: string; } +// dprint-ignore /** @internal */ export interface CommandLineOptionBase { name: string; @@ -7436,7 +7753,7 @@ export interface CommandLineOptionOfBooleanType extends CommandLineOptionBase { /** @internal */ export interface CommandLineOptionOfCustomType extends CommandLineOptionBase { - type: Map; // an object literal mapping named values to actual values + type: Map; // an object literal mapping named values to actual values defaultValueDescription: number | string | undefined | DiagnosticMessage; deprecatedKeys?: Set; } @@ -7451,8 +7768,8 @@ export interface AlternateModeDiagnostics { export interface DidYouMeanOptionsDiagnostics { alternateMode?: AlternateModeDiagnostics; optionDeclarations: CommandLineOption[]; - unknownOptionDiagnostic: DiagnosticMessage, - unknownDidYouMeanDiagnostic: DiagnosticMessage, + unknownOptionDiagnostic: DiagnosticMessage; + unknownDidYouMeanDiagnostic: DiagnosticMessage; } /** @internal */ @@ -7465,13 +7782,25 @@ export interface TsConfigOnlyOption extends CommandLineOptionBase { /** @internal */ export interface CommandLineOptionOfListType extends CommandLineOptionBase { type: "list" | "listOrElement"; - element: CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | TsConfigOnlyOption; + element: + | CommandLineOptionOfCustomType + | CommandLineOptionOfStringType + | CommandLineOptionOfNumberType + | CommandLineOptionOfBooleanType + | TsConfigOnlyOption; listPreserveFalsyValues?: boolean; } /** @internal */ -export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfStringType | CommandLineOptionOfNumberType | CommandLineOptionOfBooleanType | TsConfigOnlyOption | CommandLineOptionOfListType; +export type CommandLineOption = + | CommandLineOptionOfCustomType + | CommandLineOptionOfStringType + | CommandLineOptionOfNumberType + | CommandLineOptionOfBooleanType + | TsConfigOnlyOption + | CommandLineOptionOfListType; +// dprint-ignore /** @internal */ export const enum CharacterCodes { nullCharacter = 0, @@ -7720,7 +8049,7 @@ export interface ResolvedModuleWithFailedLookupLocations { /** @internal */ affectingLocations?: string[]; /** @internal */ - resolutionDiagnostics?: Diagnostic[] + resolutionDiagnostics?: Diagnostic[]; /** * @internal * Used to issue a diagnostic if typings for a non-relative import couldn't be found @@ -7760,8 +8089,19 @@ export type HasInvalidatedLibResolutions = (libFileName: string) => boolean; export type HasChangedAutomaticTypeDirectiveNames = () => boolean; export interface CompilerHost extends ModuleResolutionHost { - getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; - getSourceFileByPath?(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined; + getSourceFile( + fileName: string, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined; + getSourceFileByPath?( + fileName: string, + path: Path, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined; getCancellationToken?(): CancellationToken; getDefaultLibFileName(options: CompilerOptions): string; getDefaultLibLocation?(): string; @@ -7770,7 +8110,13 @@ export interface CompilerHost extends ModuleResolutionHost { getCanonicalFileName(fileName: string): string; useCaseSensitiveFileNames(): boolean; getNewLine(): string; - readDirectory?(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[], depth?: number): string[]; + readDirectory?( + rootDir: string, + extensions: readonly string[], + excludes: readonly string[] | undefined, + includes: readonly string[], + depth?: number, + ): string[]; /* * CompilerHost must either implement resolveModuleNames (in case if it wants to be completely in charge of @@ -7780,7 +8126,14 @@ export interface CompilerHost extends ModuleResolutionHost { * 'throw new Error("NotImplemented")' */ /** @deprecated supply resolveModuleNameLiterals instead for resolution that can handle newer resolution modes like nodenext */ - resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[]; + resolveModuleNames?( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingSourceFile?: SourceFile, + ): (ResolvedModule | undefined)[]; /** * Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it */ @@ -7790,7 +8143,13 @@ export interface CompilerHost extends ModuleResolutionHost { * * This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: ResolutionMode): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?( + typeReferenceDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingFileMode?: ResolutionMode, + ): (ResolvedTypeReferenceDirective | undefined)[]; resolveModuleNameLiterals?( moduleLiterals: readonly StringLiteralLike[], containingFile: string, @@ -7805,7 +8164,7 @@ export interface CompilerHost extends ModuleResolutionHost { redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile | undefined, - reusedNames: readonly T[] | undefined + reusedNames: readonly T[] | undefined, ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; /** @internal */ resolveLibrary?( @@ -7820,8 +8179,16 @@ export interface CompilerHost extends ModuleResolutionHost { */ hasInvalidatedLibResolutions?(libFileName: string): boolean; getEnvironmentVariable?(name: string): string | undefined; - /** @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void; - /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; + /** @internal */ onReleaseOldSourceFile?( + oldSourceFile: SourceFile, + oldOptions: CompilerOptions, + hasSourceFileByPath: boolean, + ): 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; /** @internal */ hasChangedAutomaticTypeDirectiveNames?: HasChangedAutomaticTypeDirectiveNames; @@ -7830,8 +8197,8 @@ export interface CompilerHost extends ModuleResolutionHost { /** @internal */ useSourceOfProjectReferenceRedirect?(): boolean; // TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base - /** @internal */createDirectory?(directory: string): void; - /** @internal */getSymlinkCache?(): SymlinkCache; + /** @internal */ createDirectory?(directory: string): void; + /** @internal */ getSymlinkCache?(): SymlinkCache; // For testing: /** @internal */ storeFilesChangingSignatureDuringEmit?: boolean; @@ -7846,7 +8213,9 @@ export type SourceOfProjectReferenceRedirect = string | true; /** @internal */ export interface ResolvedProjectReferenceCallbacks { getSourceOfProjectReferenceRedirect(fileName: string): SourceOfProjectReferenceRedirect | undefined; - forEachResolvedProjectReference(cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined): T | undefined; + forEachResolvedProjectReference( + cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, + ): T | undefined; } /** @internal */ @@ -7913,15 +8282,25 @@ export const enum TransformFlags { OuterExpressionExcludes = HasComputedFlags, PropertyAccessExcludes = OuterExpressionExcludes, NodeExcludes = PropertyAccessExcludes, - ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, - FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, - ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, - MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread, + ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsBlockScopedBinding | ContainsYield + | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread + | ContainsPossibleTopLevelAwait, + FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper + | ContainsBlockScopedBinding | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion + | ContainsBindingPattern | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, + ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding + | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern + | ContainsObjectRestOrSpread | ContainsPossibleTopLevelAwait, + MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding + | ContainsYield | ContainsAwait | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern + | ContainsObjectRestOrSpread, PropertyExcludes = NodeExcludes | ContainsLexicalThis | ContainsLexicalSuper, ClassExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName, - ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion | ContainsPossibleTopLevelAwait, + ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsLexicalSuper + | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion | ContainsPossibleTopLevelAwait, TypeExcludes = ~ContainsTypeScript, - ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName | ContainsObjectRestOrSpread, + ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName + | ContainsObjectRestOrSpread, ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsRestOrSpread, VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectRestOrSpread, ParameterExcludes = NodeExcludes, @@ -7932,7 +8311,6 @@ export const enum TransformFlags { // Propagating flags // - Bitmasks for flags that should propagate from a child PropertyNamePropagatingFlags = ContainsLexicalThis | ContainsLexicalSuper, - // Masks // - Additional bitmasks } @@ -7950,6 +8328,7 @@ export interface SourceMapSource { /** @internal */ // NOTE: Any new properties should be accounted for in `mergeEmitNode` in factory/nodeFactory.ts +// dprint-ignore export interface EmitNode { flags: EmitFlags; // Flags that customize emit internalFlags: InternalEmitFlags; // Internal flags that customize emit @@ -7989,6 +8368,7 @@ export interface Placeholder { } // Reference: https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax +// dprint-ignore /** @internal */ export const enum SnippetKind { TabStop, // `$1`, `$2` @@ -7997,6 +8377,7 @@ export const enum SnippetKind { Variable, // `$name`, `${name:default}` } +// dprint-ignore export const enum EmitFlags { None = 0, SingleLine = 1 << 0, // The contents of this node should be emitted on a single line. @@ -8029,6 +8410,7 @@ export const enum EmitFlags { NoAsciiEscaping = 1 << 24, // When synthesizing nodes that lack an original node or textSourceNode, we want to write the text on the node with ASCII escaping substitutions. } +// dprint-ignore /** @internal */ export const enum InternalEmitFlags { None = 0, @@ -8040,6 +8422,7 @@ export const enum InternalEmitFlags { TransformPrivateStaticElements = 1 << 5, // Indicates static private elements in a file or class should be transformed regardless of --target (used by esDecorators transform) } +// dprint-ignore export interface EmitHelperBase { readonly name: string; // A unique name for this helper. readonly scoped: boolean; // Indicates whether the helper MUST be emitted in the current scope. @@ -8052,6 +8435,7 @@ export interface ScopedEmitHelper extends EmitHelperBase { readonly scoped: true; } +// dprint-ignore export interface UnscopedEmitHelper extends EmitHelperBase { readonly scoped: false; // Indicates whether the helper MUST be emitted in the current scope. /** @internal */ @@ -8066,6 +8450,7 @@ export type UniqueNameHandler = (baseName: string, checkFn?: (name: string) => b export type EmitHelperUniqueNameCallback = (name: string) => string; +// dprint-ignore /** * Used by the checker, this enum keeps track of external emit helpers that should be type * checked. @@ -8120,6 +8505,7 @@ export const enum ExternalEmitHelpers { SpreadIncludes = Read | SpreadArray, } +// dprint-ignore export const enum EmitHint { SourceFile, // Emitting a SourceFile Expression, // Emitting an Expression @@ -8193,12 +8579,20 @@ export type OuterExpression = /** @internal */ export type WrappedExpression = - | OuterExpression & { readonly expression: WrappedExpression } - | T - ; + | OuterExpression & { readonly expression: WrappedExpression; } + | T; /** @internal */ -export type TypeOfTag = "null" | "undefined" | "number" | "bigint" | "boolean" | "string" | "symbol" | "object" | "function"; +export type TypeOfTag = + | "null" + | "undefined" + | "number" + | "bigint" + | "boolean" + | "string" + | "symbol" + | "object" + | "function"; /** @internal */ export interface CallBinding { @@ -8211,7 +8605,11 @@ export interface ParenthesizerRules { getParenthesizeLeftSideOfBinaryForOperator(binaryOperator: SyntaxKind): (leftSide: Expression) => Expression; getParenthesizeRightSideOfBinaryForOperator(binaryOperator: SyntaxKind): (rightSide: Expression) => Expression; parenthesizeLeftSideOfBinary(binaryOperator: SyntaxKind, leftSide: Expression): Expression; - parenthesizeRightSideOfBinary(binaryOperator: SyntaxKind, leftSide: Expression | undefined, rightSide: Expression): Expression; + parenthesizeRightSideOfBinary( + binaryOperator: SyntaxKind, + leftSide: Expression | undefined, + rightSide: Expression, + ): Expression; parenthesizeExpressionOfComputedPropertyName(expression: Expression): Expression; parenthesizeConditionOfConditionalExpression(condition: Expression): Expression; parenthesizeBranchOfConditionalExpression(branch: Expression): Expression; @@ -8264,7 +8662,9 @@ export interface GeneratedNamePart { } export type ImmediatelyInvokedFunctionExpression = CallExpression & { readonly expression: FunctionExpression; }; -export type ImmediatelyInvokedArrowFunction = CallExpression & { readonly expression: ParenthesizedExpression & { readonly expression: ArrowFunction; }; }; +export type ImmediatelyInvokedArrowFunction = CallExpression & { + readonly expression: ParenthesizedExpression & { readonly expression: ArrowFunction; }; +}; export interface NodeFactory { /** @internal */ readonly parenthesizer: ParenthesizerRules; @@ -8281,8 +8681,15 @@ export interface NodeFactory { createNumericLiteral(value: string | number, numericLiteralFlags?: TokenFlags): NumericLiteral; createBigIntLiteral(value: string | PseudoBigInt): BigIntLiteral; createStringLiteral(text: string, isSingleQuote?: boolean): StringLiteral; - /** @internal */ createStringLiteral(text: string, isSingleQuote?: boolean, hasExtendedUnicodeEscape?: boolean): StringLiteral; // eslint-disable-line @typescript-eslint/unified-signatures - createStringLiteralFromNode(sourceNode: PropertyNameLiteral | PrivateIdentifier, isSingleQuote?: boolean): StringLiteral; + /** @internal */ createStringLiteral( + text: string, + isSingleQuote?: boolean, + hasExtendedUnicodeEscape?: boolean, + ): StringLiteral; // eslint-disable-line @typescript-eslint/unified-signatures + createStringLiteralFromNode( + sourceNode: PropertyNameLiteral | PrivateIdentifier, + isSingleQuote?: boolean, + ): StringLiteral; createRegularExpressionLiteral(text: string): RegularExpressionLiteral; // @@ -8290,7 +8697,11 @@ export interface NodeFactory { // createIdentifier(text: string): Identifier; - /** @internal */ createIdentifier(text: string, originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures + /** @internal */ createIdentifier( + text: string, + originalKeywordKind?: SyntaxKind, + hasExtendedUnicodeEscape?: boolean, + ): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures /** * Create a unique temporary variable. @@ -8301,8 +8712,16 @@ export interface NodeFactory { * during emit so that the variable can be referenced in a nested function body. This is an alternative to * setting `EmitFlags.ReuseTempVariableScope` on the nested function itself. */ - createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean): Identifier; - /** @internal */ createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean, prefix?: string | GeneratedNamePart, suffix?: string): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures + createTempVariable( + recordTempVariable: ((node: Identifier) => void) | undefined, + reservedInNestedScopes?: boolean, + ): Identifier; + /** @internal */ createTempVariable( + recordTempVariable: ((node: Identifier) => void) | undefined, + reservedInNestedScopes?: boolean, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures /** * Create a unique temporary variable for use in a loop. @@ -8314,17 +8733,35 @@ export interface NodeFactory { /** Create a unique name based on the supplied text. */ createUniqueName(text: string, flags?: GeneratedIdentifierFlags): Identifier; - /** @internal */ createUniqueName(text: string, flags?: GeneratedIdentifierFlags, prefix?: string | GeneratedNamePart, suffix?: string): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures + /** @internal */ createUniqueName( + text: string, + flags?: GeneratedIdentifierFlags, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures /** Create a unique name generated for a node. */ getGeneratedNameForNode(node: Node | undefined, flags?: GeneratedIdentifierFlags): Identifier; - /** @internal */ getGeneratedNameForNode(node: Node | undefined, flags?: GeneratedIdentifierFlags, prefix?: string | GeneratedNamePart, suffix?: string): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures - - createPrivateIdentifier(text: string): PrivateIdentifier + /** @internal */ getGeneratedNameForNode( + node: Node | undefined, + flags?: GeneratedIdentifierFlags, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures + + createPrivateIdentifier(text: string): PrivateIdentifier; createUniquePrivateName(text?: string): PrivateIdentifier; - /** @internal */ createUniquePrivateName(text?: string, prefix?: string | GeneratedNamePart, suffix?: string): PrivateIdentifier; // eslint-disable-line @typescript-eslint/unified-signatures + /** @internal */ createUniquePrivateName( + text?: string, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): PrivateIdentifier; // eslint-disable-line @typescript-eslint/unified-signatures getGeneratedPrivateNameForNode(node: Node): PrivateIdentifier; - /** @internal */ getGeneratedPrivateNameForNode(node: Node, prefix?: string | GeneratedNamePart, suffix?: string): PrivateIdentifier; // eslint-disable-line @typescript-eslint/unified-signatures + /** @internal */ getGeneratedPrivateNameForNode( + node: Node, + prefix?: string | GeneratedNamePart, + suffix?: string, + ): PrivateIdentifier; // eslint-disable-line @typescript-eslint/unified-signatures // // Punctuation @@ -8373,10 +8810,36 @@ export interface NodeFactory { // Signature elements // - createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration; - updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration; - createParameterDeclaration(modifiers: readonly ModifierLike[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration; - updateParameterDeclaration(node: ParameterDeclaration, modifiers: readonly ModifierLike[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration; + createTypeParameterDeclaration( + modifiers: readonly Modifier[] | undefined, + name: string | Identifier, + constraint?: TypeNode, + defaultType?: TypeNode, + ): TypeParameterDeclaration; + updateTypeParameterDeclaration( + node: TypeParameterDeclaration, + modifiers: readonly Modifier[] | undefined, + name: Identifier, + constraint: TypeNode | undefined, + defaultType: TypeNode | undefined, + ): TypeParameterDeclaration; + createParameterDeclaration( + modifiers: readonly ModifierLike[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken?: QuestionToken, + type?: TypeNode, + initializer?: Expression, + ): ParameterDeclaration; + updateParameterDeclaration( + node: ParameterDeclaration, + modifiers: readonly ModifierLike[] | undefined, + dotDotDotToken: DotDotDotToken | undefined, + name: string | BindingName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): ParameterDeclaration; createDecorator(expression: Expression): Decorator; updateDecorator(node: Decorator, expression: Expression): Decorator; @@ -8384,29 +8847,155 @@ export interface NodeFactory { // Type Elements // - createPropertySignature(modifiers: readonly Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined): PropertySignature; - updatePropertySignature(node: PropertySignature, modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined): PropertySignature; - createPropertyDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration; - updatePropertyDeclaration(node: PropertyDeclaration, modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration; - createMethodSignature(modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): MethodSignature; - updateMethodSignature(node: MethodSignature, modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): MethodSignature; - createMethodDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration; - updateMethodDeclaration(node: MethodDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration; - createConstructorDeclaration(modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration; - updateConstructorDeclaration(node: ConstructorDeclaration, modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration; - createGetAccessorDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration; - updateGetAccessorDeclaration(node: GetAccessorDeclaration, modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration; - createSetAccessorDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration; - updateSetAccessorDeclaration(node: SetAccessorDeclaration, modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration; - createCallSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): CallSignatureDeclaration; - updateCallSignature(node: CallSignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): CallSignatureDeclaration; - createConstructSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructSignatureDeclaration; - updateConstructSignature(node: ConstructSignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): ConstructSignatureDeclaration; - createIndexSignature(modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration; - /** @internal */ createIndexSignature(modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): IndexSignatureDeclaration; // eslint-disable-line @typescript-eslint/unified-signatures - updateIndexSignature(node: IndexSignatureDeclaration, modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration; + createPropertySignature( + modifiers: readonly Modifier[] | undefined, + name: PropertyName | string, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + ): PropertySignature; + updatePropertySignature( + node: PropertySignature, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + type: TypeNode | undefined, + ): PropertySignature; + createPropertyDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration; + updatePropertyDeclaration( + node: PropertyDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): PropertyDeclaration; + createMethodSignature( + modifiers: readonly Modifier[] | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): MethodSignature; + updateMethodSignature( + node: MethodSignature, + modifiers: readonly Modifier[] | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode | undefined, + ): MethodSignature; + createMethodDeclaration( + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration; + updateMethodDeclaration( + node: MethodDeclaration, + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: PropertyName, + questionToken: QuestionToken | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): MethodDeclaration; + createConstructorDeclaration( + modifiers: readonly ModifierLike[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration; + updateConstructorDeclaration( + node: ConstructorDeclaration, + modifiers: readonly ModifierLike[] | undefined, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): ConstructorDeclaration; + createGetAccessorDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration; + updateGetAccessorDeclaration( + node: GetAccessorDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): GetAccessorDeclaration; + createSetAccessorDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration; + updateSetAccessorDeclaration( + node: SetAccessorDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: PropertyName, + parameters: readonly ParameterDeclaration[], + body: Block | undefined, + ): SetAccessorDeclaration; + createCallSignature( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): CallSignatureDeclaration; + updateCallSignature( + node: CallSignatureDeclaration, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode | undefined, + ): CallSignatureDeclaration; + createConstructSignature( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): ConstructSignatureDeclaration; + updateConstructSignature( + node: ConstructSignatureDeclaration, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode | undefined, + ): ConstructSignatureDeclaration; + createIndexSignature( + modifiers: readonly ModifierLike[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration; + /** @internal */ createIndexSignature( + modifiers: readonly ModifierLike[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): IndexSignatureDeclaration; // eslint-disable-line @typescript-eslint/unified-signatures + updateIndexSignature( + node: IndexSignatureDeclaration, + modifiers: readonly ModifierLike[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): IndexSignatureDeclaration; createTemplateLiteralTypeSpan(type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan; - updateTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan; + updateTemplateLiteralTypeSpan( + node: TemplateLiteralTypeSpan, + type: TypeNode, + literal: TemplateMiddle | TemplateTail, + ): TemplateLiteralTypeSpan; createClassStaticBlockDeclaration(body: Block): ClassStaticBlockDeclaration; updateClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, body: Block): ClassStaticBlockDeclaration; @@ -8415,14 +9004,47 @@ export interface NodeFactory { // createKeywordTypeNode(kind: TKind): KeywordTypeNode; - createTypePredicateNode(assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode; - updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode; + createTypePredicateNode( + assertsModifier: AssertsKeyword | undefined, + parameterName: Identifier | ThisTypeNode | string, + type: TypeNode | undefined, + ): TypePredicateNode; + updateTypePredicateNode( + node: TypePredicateNode, + assertsModifier: AssertsKeyword | undefined, + parameterName: Identifier | ThisTypeNode, + type: TypeNode | undefined, + ): TypePredicateNode; createTypeReferenceNode(typeName: string | EntityName, typeArguments?: readonly TypeNode[]): TypeReferenceNode; - updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined): TypeReferenceNode; - createFunctionTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): FunctionTypeNode; - updateFunctionTypeNode(node: FunctionTypeNode, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode): FunctionTypeNode; - createConstructorTypeNode(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): ConstructorTypeNode; - updateConstructorTypeNode(node: ConstructorTypeNode, modifiers: readonly Modifier[] | undefined, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode): ConstructorTypeNode; + updateTypeReferenceNode( + node: TypeReferenceNode, + typeName: EntityName, + typeArguments: NodeArray | undefined, + ): TypeReferenceNode; + createFunctionTypeNode( + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): FunctionTypeNode; + updateFunctionTypeNode( + node: FunctionTypeNode, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode, + ): FunctionTypeNode; + createConstructorTypeNode( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode, + ): ConstructorTypeNode; + updateConstructorTypeNode( + node: ConstructorTypeNode, + modifiers: readonly Modifier[] | undefined, + typeParameters: NodeArray | undefined, + parameters: NodeArray, + type: TypeNode, + ): ConstructorTypeNode; createTypeQueryNode(exprName: EntityName, typeArguments?: readonly TypeNode[]): TypeQueryNode; updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName, typeArguments?: readonly TypeNode[]): TypeQueryNode; createTypeLiteralNode(members: readonly TypeElement[] | undefined): TypeLiteralNode; @@ -8431,8 +9053,19 @@ export interface NodeFactory { updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode; createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode; updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode; - createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; - updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; + createNamedTupleMember( + dotDotDotToken: DotDotDotToken | undefined, + name: Identifier, + questionToken: QuestionToken | undefined, + type: TypeNode, + ): NamedTupleMember; + updateNamedTupleMember( + node: NamedTupleMember, + dotDotDotToken: DotDotDotToken | undefined, + name: Identifier, + questionToken: QuestionToken | undefined, + type: TypeNode, + ): NamedTupleMember; createOptionalTypeNode(type: TypeNode): OptionalTypeNode; updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode; createRestTypeNode(type: TypeNode): RestTypeNode; @@ -8441,25 +9074,78 @@ export interface NodeFactory { updateUnionTypeNode(node: UnionTypeNode, types: NodeArray): UnionTypeNode; createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode; updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray): IntersectionTypeNode; - createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; - updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode; + createConditionalTypeNode( + checkType: TypeNode, + extendsType: TypeNode, + trueType: TypeNode, + falseType: TypeNode, + ): ConditionalTypeNode; + updateConditionalTypeNode( + node: ConditionalTypeNode, + checkType: TypeNode, + extendsType: TypeNode, + trueType: TypeNode, + falseType: TypeNode, + ): ConditionalTypeNode; createInferTypeNode(typeParameter: TypeParameterDeclaration): InferTypeNode; updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration): InferTypeNode; - createImportTypeNode(argument: TypeNode, assertions?: ImportTypeAssertionContainer, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode; - updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, assertions: ImportTypeAssertionContainer | undefined, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf?: boolean): ImportTypeNode; + createImportTypeNode( + argument: TypeNode, + assertions?: ImportTypeAssertionContainer, + qualifier?: EntityName, + typeArguments?: readonly TypeNode[], + isTypeOf?: boolean, + ): ImportTypeNode; + updateImportTypeNode( + node: ImportTypeNode, + argument: TypeNode, + assertions: ImportTypeAssertionContainer | undefined, + qualifier: EntityName | undefined, + typeArguments: readonly TypeNode[] | undefined, + isTypeOf?: boolean, + ): ImportTypeNode; createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; createThisTypeNode(): ThisTypeNode; - createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode; + createTypeOperatorNode( + operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, + type: TypeNode, + ): TypeOperatorNode; updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; - updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; - createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: NodeArray | undefined): MappedTypeNode; - updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: NodeArray | undefined): MappedTypeNode; + updateIndexedAccessTypeNode( + node: IndexedAccessTypeNode, + objectType: TypeNode, + indexType: TypeNode, + ): IndexedAccessTypeNode; + createMappedTypeNode( + readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, + typeParameter: TypeParameterDeclaration, + nameType: TypeNode | undefined, + questionToken: QuestionToken | PlusToken | MinusToken | undefined, + type: TypeNode | undefined, + members: NodeArray | undefined, + ): MappedTypeNode; + updateMappedTypeNode( + node: MappedTypeNode, + readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, + typeParameter: TypeParameterDeclaration, + nameType: TypeNode | undefined, + questionToken: QuestionToken | PlusToken | MinusToken | undefined, + type: TypeNode | undefined, + members: NodeArray | undefined, + ): MappedTypeNode; createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode; updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode; - createTemplateLiteralType(head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]): TemplateLiteralTypeNode; - updateTemplateLiteralType(node: TemplateLiteralTypeNode, head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]): TemplateLiteralTypeNode; + createTemplateLiteralType( + head: TemplateHead, + templateSpans: readonly TemplateLiteralTypeSpan[], + ): TemplateLiteralTypeNode; + updateTemplateLiteralType( + node: TemplateLiteralTypeNode, + head: TemplateHead, + templateSpans: readonly TemplateLiteralTypeSpan[], + ): TemplateLiteralTypeNode; // // Binding Patterns @@ -8469,8 +9155,19 @@ export interface NodeFactory { updateObjectBindingPattern(node: ObjectBindingPattern, elements: readonly BindingElement[]): ObjectBindingPattern; createArrayBindingPattern(elements: readonly ArrayBindingElement[]): ArrayBindingPattern; updateArrayBindingPattern(node: ArrayBindingPattern, elements: readonly ArrayBindingElement[]): ArrayBindingPattern; - createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression): BindingElement; - updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined): BindingElement; + createBindingElement( + dotDotDotToken: DotDotDotToken | undefined, + propertyName: string | PropertyName | undefined, + name: string | BindingName, + initializer?: Expression, + ): BindingElement; + updateBindingElement( + node: BindingElement, + dotDotDotToken: DotDotDotToken | undefined, + propertyName: PropertyName | undefined, + name: BindingName, + initializer: Expression | undefined, + ): BindingElement; // // Expression @@ -8478,32 +9175,134 @@ export interface NodeFactory { createArrayLiteralExpression(elements?: readonly Expression[], multiLine?: boolean): ArrayLiteralExpression; updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression; - createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression; - updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression; + createObjectLiteralExpression( + properties?: readonly ObjectLiteralElementLike[], + multiLine?: boolean, + ): ObjectLiteralExpression; + updateObjectLiteralExpression( + node: ObjectLiteralExpression, + properties: readonly ObjectLiteralElementLike[], + ): ObjectLiteralExpression; createPropertyAccessExpression(expression: Expression, name: string | MemberName): PropertyAccessExpression; - updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: MemberName): PropertyAccessExpression; - createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName): PropertyAccessChain; - updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName): PropertyAccessChain; + updatePropertyAccessExpression( + node: PropertyAccessExpression, + expression: Expression, + name: MemberName, + ): PropertyAccessExpression; + createPropertyAccessChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: string | MemberName, + ): PropertyAccessChain; + updatePropertyAccessChain( + node: PropertyAccessChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + name: MemberName, + ): PropertyAccessChain; createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression; - updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression; - createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain; - updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression): ElementAccessChain; - createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallExpression; - updateCallExpression(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallExpression; - createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallChain; - updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallChain; - createNewExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression; - updateNewExpression(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression; - createTaggedTemplateExpression(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression; - updateTaggedTemplateExpression(node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression; + updateElementAccessExpression( + node: ElementAccessExpression, + expression: Expression, + argumentExpression: Expression, + ): ElementAccessExpression; + createElementAccessChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + index: number | Expression, + ): ElementAccessChain; + updateElementAccessChain( + node: ElementAccessChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + argumentExpression: Expression, + ): ElementAccessChain; + createCallExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ): CallExpression; + updateCallExpression( + node: CallExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[], + ): CallExpression; + createCallChain( + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ): CallChain; + updateCallChain( + node: CallChain, + expression: Expression, + questionDotToken: QuestionDotToken | undefined, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[], + ): CallChain; + createNewExpression( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ): NewExpression; + updateNewExpression( + node: NewExpression, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + argumentsArray: readonly Expression[] | undefined, + ): NewExpression; + createTaggedTemplateExpression( + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ): TaggedTemplateExpression; + updateTaggedTemplateExpression( + node: TaggedTemplateExpression, + tag: Expression, + typeArguments: readonly TypeNode[] | undefined, + template: TemplateLiteral, + ): TaggedTemplateExpression; createTypeAssertion(type: TypeNode, expression: Expression): TypeAssertion; updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression): TypeAssertion; createParenthesizedExpression(expression: Expression): ParenthesizedExpression; updateParenthesizedExpression(node: ParenthesizedExpression, expression: Expression): ParenthesizedExpression; - createFunctionExpression(modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, body: Block): FunctionExpression; - updateFunctionExpression(node: FunctionExpression, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block): FunctionExpression; - createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction; - updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction; + createFunctionExpression( + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[] | undefined, + type: TypeNode | undefined, + body: Block, + ): FunctionExpression; + updateFunctionExpression( + node: FunctionExpression, + modifiers: readonly Modifier[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block, + ): FunctionExpression; + createArrowFunction( + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanToken: EqualsGreaterThanToken | undefined, + body: ConciseBody, + ): ArrowFunction; + updateArrowFunction( + node: ArrowFunction, + modifiers: readonly Modifier[] | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + equalsGreaterThanToken: EqualsGreaterThanToken, + body: ConciseBody, + ): ArrowFunction; createDeleteExpression(expression: Expression): DeleteExpression; updateDeleteExpression(node: DeleteExpression, expression: Expression): DeleteExpression; createTypeOfExpression(expression: Expression): TypeOfExpression; @@ -8516,12 +9315,38 @@ export interface NodeFactory { updatePrefixUnaryExpression(node: PrefixUnaryExpression, operand: Expression): PrefixUnaryExpression; createPostfixUnaryExpression(operand: Expression, operator: PostfixUnaryOperator): PostfixUnaryExpression; updatePostfixUnaryExpression(node: PostfixUnaryExpression, operand: Expression): PostfixUnaryExpression; - createBinaryExpression(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression; - updateBinaryExpression(node: BinaryExpression, left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression; - createConditionalExpression(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression): ConditionalExpression; - updateConditionalExpression(node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression; + createBinaryExpression( + left: Expression, + operator: BinaryOperator | BinaryOperatorToken, + right: Expression, + ): BinaryExpression; + updateBinaryExpression( + node: BinaryExpression, + left: Expression, + operator: BinaryOperator | BinaryOperatorToken, + right: Expression, + ): BinaryExpression; + createConditionalExpression( + condition: Expression, + questionToken: QuestionToken | undefined, + whenTrue: Expression, + colonToken: ColonToken | undefined, + whenFalse: Expression, + ): ConditionalExpression; + updateConditionalExpression( + node: ConditionalExpression, + condition: Expression, + questionToken: QuestionToken, + whenTrue: Expression, + colonToken: ColonToken, + whenFalse: Expression, + ): ConditionalExpression; createTemplateExpression(head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression; - updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression; + updateTemplateExpression( + node: TemplateExpression, + head: TemplateHead, + templateSpans: readonly TemplateSpan[], + ): TemplateExpression; createTemplateHead(text: string, rawText?: string, templateFlags?: TokenFlags): TemplateHead; createTemplateHead(text: string | undefined, rawText: string, templateFlags?: TokenFlags): TemplateHead; createTemplateMiddle(text: string, rawText?: string, templateFlags?: TokenFlags): TemplateMiddle; @@ -8530,19 +9355,54 @@ export interface NodeFactory { createTemplateTail(text: string | undefined, rawText: string, templateFlags?: TokenFlags): TemplateTail; createNoSubstitutionTemplateLiteral(text: string, rawText?: string): NoSubstitutionTemplateLiteral; createNoSubstitutionTemplateLiteral(text: string | undefined, rawText: string): NoSubstitutionTemplateLiteral; - /** @internal */ createLiteralLikeNode(kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, text: string): LiteralToken; - /** @internal */ createTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string, rawText: string, templateFlags: TokenFlags | undefined): TemplateLiteralLikeNode; + /** @internal */ createLiteralLikeNode( + kind: LiteralToken["kind"] | SyntaxKind.JsxTextAllWhiteSpaces, + text: string, + ): LiteralToken; + /** @internal */ createTemplateLiteralLikeNode( + kind: TemplateLiteralToken["kind"], + text: string, + rawText: string, + templateFlags: TokenFlags | undefined, + ): TemplateLiteralLikeNode; createYieldExpression(asteriskToken: AsteriskToken, expression: Expression): YieldExpression; createYieldExpression(asteriskToken: undefined, expression: Expression | undefined): YieldExpression; - /** @internal */ createYieldExpression(asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression; // eslint-disable-line @typescript-eslint/unified-signatures - updateYieldExpression(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression; + /** @internal */ createYieldExpression( + asteriskToken: AsteriskToken | undefined, + expression: Expression | undefined, + ): YieldExpression; // eslint-disable-line @typescript-eslint/unified-signatures + updateYieldExpression( + node: YieldExpression, + asteriskToken: AsteriskToken | undefined, + expression: Expression | undefined, + ): YieldExpression; createSpreadElement(expression: Expression): SpreadElement; updateSpreadElement(node: SpreadElement, expression: Expression): SpreadElement; - createClassExpression(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression; - updateClassExpression(node: ClassExpression, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression; + createClassExpression( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression; + updateClassExpression( + node: ClassExpression, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassExpression; createOmittedExpression(): OmittedExpression; - createExpressionWithTypeArguments(expression: Expression, typeArguments: readonly TypeNode[] | undefined): ExpressionWithTypeArguments; - updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, expression: Expression, typeArguments: readonly TypeNode[] | undefined): ExpressionWithTypeArguments; + createExpressionWithTypeArguments( + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + ): ExpressionWithTypeArguments; + updateExpressionWithTypeArguments( + node: ExpressionWithTypeArguments, + expression: Expression, + typeArguments: readonly TypeNode[] | undefined, + ): ExpressionWithTypeArguments; createAsExpression(expression: Expression, type: TypeNode): AsExpression; updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode): AsExpression; createNonNullExpression(expression: Expression): NonNullExpression; @@ -8559,7 +9419,11 @@ export interface NodeFactory { // createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan; - updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan; + updateTemplateSpan( + node: TemplateSpan, + expression: Expression, + literal: TemplateMiddle | TemplateTail, + ): TemplateSpan; createSemicolonClassElement(): SemicolonClassElement; // @@ -8568,23 +9432,62 @@ export interface NodeFactory { createBlock(statements: readonly Statement[], multiLine?: boolean): Block; updateBlock(node: Block, statements: readonly Statement[]): Block; - createVariableStatement(modifiers: readonly ModifierLike[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]): VariableStatement; - updateVariableStatement(node: VariableStatement, modifiers: readonly ModifierLike[] | undefined, declarationList: VariableDeclarationList): VariableStatement; + createVariableStatement( + modifiers: readonly ModifierLike[] | undefined, + declarationList: VariableDeclarationList | readonly VariableDeclaration[], + ): VariableStatement; + updateVariableStatement( + node: VariableStatement, + modifiers: readonly ModifierLike[] | undefined, + declarationList: VariableDeclarationList, + ): VariableStatement; createEmptyStatement(): EmptyStatement; createExpressionStatement(expression: Expression): ExpressionStatement; updateExpressionStatement(node: ExpressionStatement, expression: Expression): ExpressionStatement; createIfStatement(expression: Expression, thenStatement: Statement, elseStatement?: Statement): IfStatement; - updateIfStatement(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined): IfStatement; + updateIfStatement( + node: IfStatement, + expression: Expression, + thenStatement: Statement, + elseStatement: Statement | undefined, + ): IfStatement; createDoStatement(statement: Statement, expression: Expression): DoStatement; updateDoStatement(node: DoStatement, statement: Statement, expression: Expression): DoStatement; createWhileStatement(expression: Expression, statement: Statement): WhileStatement; updateWhileStatement(node: WhileStatement, expression: Expression, statement: Statement): WhileStatement; - createForStatement(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement): ForStatement; - updateForStatement(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement): ForStatement; + createForStatement( + initializer: ForInitializer | undefined, + condition: Expression | undefined, + incrementor: Expression | undefined, + statement: Statement, + ): ForStatement; + updateForStatement( + node: ForStatement, + initializer: ForInitializer | undefined, + condition: Expression | undefined, + incrementor: Expression | undefined, + statement: Statement, + ): ForStatement; createForInStatement(initializer: ForInitializer, expression: Expression, statement: Statement): ForInStatement; - updateForInStatement(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement): ForInStatement; - createForOfStatement(awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement): ForOfStatement; - updateForOfStatement(node: ForOfStatement, awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement): ForOfStatement; + updateForInStatement( + node: ForInStatement, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ): ForInStatement; + createForOfStatement( + awaitModifier: AwaitKeyword | undefined, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ): ForOfStatement; + updateForOfStatement( + node: ForOfStatement, + awaitModifier: AwaitKeyword | undefined, + initializer: ForInitializer, + expression: Expression, + statement: Statement, + ): ForOfStatement; createContinueStatement(label?: string | Identifier): ContinueStatement; updateContinueStatement(node: ContinueStatement, label: Identifier | undefined): ContinueStatement; createBreakStatement(label?: string | Identifier): BreakStatement; @@ -8599,43 +9502,177 @@ export interface NodeFactory { updateLabeledStatement(node: LabeledStatement, label: Identifier, statement: Statement): LabeledStatement; createThrowStatement(expression: Expression): ThrowStatement; updateThrowStatement(node: ThrowStatement, expression: Expression): ThrowStatement; - createTryStatement(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined): TryStatement; - updateTryStatement(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined): TryStatement; + createTryStatement( + tryBlock: Block, + catchClause: CatchClause | undefined, + finallyBlock: Block | undefined, + ): TryStatement; + updateTryStatement( + node: TryStatement, + tryBlock: Block, + catchClause: CatchClause | undefined, + finallyBlock: Block | undefined, + ): TryStatement; createDebuggerStatement(): DebuggerStatement; - createVariableDeclaration(name: string | BindingName, exclamationToken?: ExclamationToken, type?: TypeNode, initializer?: Expression): VariableDeclaration; - updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): VariableDeclaration; - createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags?: NodeFlags): VariableDeclarationList; - updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]): VariableDeclarationList; - createFunctionDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; - updateFunctionDeclaration(node: FunctionDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration; - createClassDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; - updateClassDeclaration(node: ClassDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration; - createInterfaceDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; - updateInterfaceDeclaration(node: InterfaceDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration; - createTypeAliasDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; - updateTypeAliasDeclaration(node: TypeAliasDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration; - createEnumDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration; - updateEnumDeclaration(node: EnumDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration; - createModuleDeclaration(modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration; - updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly ModifierLike[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration; + createVariableDeclaration( + name: string | BindingName, + exclamationToken?: ExclamationToken, + type?: TypeNode, + initializer?: Expression, + ): VariableDeclaration; + updateVariableDeclaration( + node: VariableDeclaration, + name: BindingName, + exclamationToken: ExclamationToken | undefined, + type: TypeNode | undefined, + initializer: Expression | undefined, + ): VariableDeclaration; + createVariableDeclarationList( + declarations: readonly VariableDeclaration[], + flags?: NodeFlags, + ): VariableDeclarationList; + updateVariableDeclarationList( + node: VariableDeclarationList, + declarations: readonly VariableDeclaration[], + ): VariableDeclarationList; + createFunctionDeclaration( + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration; + updateFunctionDeclaration( + node: FunctionDeclaration, + modifiers: readonly ModifierLike[] | undefined, + asteriskToken: AsteriskToken | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + body: Block | undefined, + ): FunctionDeclaration; + createClassDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration; + updateClassDeclaration( + node: ClassDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier | undefined, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly ClassElement[], + ): ClassDeclaration; + createInterfaceDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration; + updateInterfaceDeclaration( + node: InterfaceDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + heritageClauses: readonly HeritageClause[] | undefined, + members: readonly TypeElement[], + ): InterfaceDeclaration; + createTypeAliasDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration; + updateTypeAliasDeclaration( + node: TypeAliasDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier, + typeParameters: readonly TypeParameterDeclaration[] | undefined, + type: TypeNode, + ): TypeAliasDeclaration; + createEnumDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: string | Identifier, + members: readonly EnumMember[], + ): EnumDeclaration; + updateEnumDeclaration( + node: EnumDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: Identifier, + members: readonly EnumMember[], + ): EnumDeclaration; + createModuleDeclaration( + modifiers: readonly ModifierLike[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + flags?: NodeFlags, + ): ModuleDeclaration; + updateModuleDeclaration( + node: ModuleDeclaration, + modifiers: readonly ModifierLike[] | undefined, + name: ModuleName, + body: ModuleBody | undefined, + ): ModuleDeclaration; createModuleBlock(statements: readonly Statement[]): ModuleBlock; updateModuleBlock(node: ModuleBlock, statements: readonly Statement[]): ModuleBlock; createCaseBlock(clauses: readonly CaseOrDefaultClause[]): CaseBlock; updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock; createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration; updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration; - createImportEqualsDeclaration(modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; - updateImportEqualsDeclaration(node: ImportEqualsDeclaration, modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration; - createImportDeclaration(modifiers: readonly ModifierLike[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause?: AssertClause): ImportDeclaration; - updateImportDeclaration(node: ImportDeclaration, modifiers: readonly ModifierLike[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, assertClause: AssertClause | undefined): ImportDeclaration; - createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause; - updateImportClause(node: ImportClause, isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause; + createImportEqualsDeclaration( + modifiers: readonly ModifierLike[] | undefined, + isTypeOnly: boolean, + name: string | Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration; + updateImportEqualsDeclaration( + node: ImportEqualsDeclaration, + modifiers: readonly ModifierLike[] | undefined, + isTypeOnly: boolean, + name: Identifier, + moduleReference: ModuleReference, + ): ImportEqualsDeclaration; + createImportDeclaration( + modifiers: readonly ModifierLike[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause?: AssertClause, + ): ImportDeclaration; + updateImportDeclaration( + node: ImportDeclaration, + modifiers: readonly ModifierLike[] | undefined, + importClause: ImportClause | undefined, + moduleSpecifier: Expression, + assertClause: AssertClause | undefined, + ): ImportDeclaration; + createImportClause( + isTypeOnly: boolean, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + ): ImportClause; + updateImportClause( + node: ImportClause, + isTypeOnly: boolean, + name: Identifier | undefined, + namedBindings: NamedImportBindings | undefined, + ): ImportClause; createAssertClause(elements: NodeArray, multiLine?: boolean): AssertClause; updateAssertClause(node: AssertClause, elements: NodeArray, multiLine?: boolean): AssertClause; createAssertEntry(name: AssertionKey, value: Expression): AssertEntry; updateAssertEntry(node: AssertEntry, name: AssertionKey, value: Expression): AssertEntry; createImportTypeAssertionContainer(clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer; - updateImportTypeAssertionContainer(node: ImportTypeAssertionContainer, clause: AssertClause, multiLine?: boolean): ImportTypeAssertionContainer; + updateImportTypeAssertionContainer( + node: ImportTypeAssertionContainer, + clause: AssertClause, + multiLine?: boolean, + ): ImportTypeAssertionContainer; createNamespaceImport(name: Identifier): NamespaceImport; updateNamespaceImport(node: NamespaceImport, name: Identifier): NamespaceImport; createNamespaceExport(name: Identifier): NamespaceExport; @@ -8643,15 +9680,50 @@ export interface NodeFactory { createNamedImports(elements: readonly ImportSpecifier[]): NamedImports; updateNamedImports(node: NamedImports, elements: readonly ImportSpecifier[]): NamedImports; createImportSpecifier(isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier; - updateImportSpecifier(node: ImportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ImportSpecifier; - createExportAssignment(modifiers: readonly ModifierLike[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment; - updateExportAssignment(node: ExportAssignment, modifiers: readonly ModifierLike[] | undefined, expression: Expression): ExportAssignment; - createExportDeclaration(modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, assertClause?: AssertClause): ExportDeclaration; - updateExportDeclaration(node: ExportDeclaration, modifiers: readonly ModifierLike[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, assertClause: AssertClause | undefined): ExportDeclaration; + updateImportSpecifier( + node: ImportSpecifier, + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ): ImportSpecifier; + createExportAssignment( + modifiers: readonly ModifierLike[] | undefined, + isExportEquals: boolean | undefined, + expression: Expression, + ): ExportAssignment; + updateExportAssignment( + node: ExportAssignment, + modifiers: readonly ModifierLike[] | undefined, + expression: Expression, + ): ExportAssignment; + createExportDeclaration( + modifiers: readonly ModifierLike[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier?: Expression, + assertClause?: AssertClause, + ): ExportDeclaration; + updateExportDeclaration( + node: ExportDeclaration, + modifiers: readonly ModifierLike[] | undefined, + isTypeOnly: boolean, + exportClause: NamedExportBindings | undefined, + moduleSpecifier: Expression | undefined, + assertClause: AssertClause | undefined, + ): ExportDeclaration; createNamedExports(elements: readonly ExportSpecifier[]): NamedExports; updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]): NamedExports; - createExportSpecifier(isTypeOnly: boolean, propertyName: string | Identifier | undefined, name: string | Identifier): ExportSpecifier; - updateExportSpecifier(node: ExportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier): ExportSpecifier; + createExportSpecifier( + isTypeOnly: boolean, + propertyName: string | Identifier | undefined, + name: string | Identifier, + ): ExportSpecifier; + updateExportSpecifier( + node: ExportSpecifier, + isTypeOnly: boolean, + propertyName: Identifier | undefined, + name: Identifier, + ): ExportSpecifier; /** @internal */ createMissingDeclaration(): MissingDeclaration; // @@ -8674,7 +9746,11 @@ export interface NodeFactory { createJSDocOptionalType(type: TypeNode): JSDocOptionalType; updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType; createJSDocFunctionType(parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType; - updateJSDocFunctionType(node: JSDocFunctionType, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType; + updateJSDocFunctionType( + node: JSDocFunctionType, + parameters: readonly ParameterDeclaration[], + type: TypeNode | undefined, + ): JSDocFunctionType; createJSDocVariadicType(type: TypeNode): JSDocVariadicType; updateJSDocVariadicType(node: JSDocVariadicType, type: TypeNode): JSDocVariadicType; createJSDocNamepathType(type: TypeNode): JSDocNamepathType; @@ -8684,90 +9760,366 @@ export interface NodeFactory { createJSDocNameReference(name: EntityName | JSDocMemberName): JSDocNameReference; updateJSDocNameReference(node: JSDocNameReference, name: EntityName | JSDocMemberName): JSDocNameReference; createJSDocMemberName(left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName; - updateJSDocMemberName(node: JSDocMemberName, left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName; + updateJSDocMemberName( + node: JSDocMemberName, + left: EntityName | JSDocMemberName, + right: Identifier, + ): JSDocMemberName; createJSDocLink(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink; updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink; createJSDocLinkCode(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode; - updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode; + updateJSDocLinkCode( + node: JSDocLinkCode, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLinkCode; createJSDocLinkPlain(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain; - updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain; - createJSDocTypeLiteral(jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], isArrayType?: boolean): JSDocTypeLiteral; - updateJSDocTypeLiteral(node: JSDocTypeLiteral, jsDocPropertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean | undefined): JSDocTypeLiteral; - createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature; - updateJSDocSignature(node: JSDocSignature, typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type: JSDocReturnTag | undefined): JSDocSignature; - createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string | NodeArray): JSDocTemplateTag; - updateJSDocTemplateTag(node: JSDocTemplateTag, tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment: string | NodeArray | undefined): JSDocTemplateTag; - createJSDocTypedefTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression | JSDocTypeLiteral, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray): JSDocTypedefTag; - updateJSDocTypedefTag(node: JSDocTypedefTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocTypedefTag; - createJSDocParameterTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray): JSDocParameterTag; - updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray | undefined): JSDocParameterTag; - createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray): JSDocPropertyTag; - updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray | undefined): JSDocPropertyTag; - createJSDocTypeTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocTypeTag; - updateJSDocTypeTag(node: JSDocTypeTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocTypeTag; - createJSDocSeeTag(tagName: Identifier | undefined, nameExpression: JSDocNameReference | undefined, comment?: string | NodeArray): JSDocSeeTag; - updateJSDocSeeTag(node: JSDocSeeTag, tagName: Identifier | undefined, nameExpression: JSDocNameReference | undefined, comment?: string | NodeArray): JSDocSeeTag; - createJSDocReturnTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string | NodeArray): JSDocReturnTag; - updateJSDocReturnTag(node: JSDocReturnTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray | undefined): JSDocReturnTag; - createJSDocThisTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocThisTag; - updateJSDocThisTag(node: JSDocThisTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray | undefined): JSDocThisTag; - createJSDocEnumTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocEnumTag; - updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocEnumTag; - createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray): JSDocCallbackTag; - updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocCallbackTag; - createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray): JSDocOverloadTag; - updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, comment: string | NodeArray | undefined): JSDocOverloadTag; - createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray): JSDocAugmentsTag; - updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray | undefined): JSDocAugmentsTag; - createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray): JSDocImplementsTag; - updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | NodeArray | undefined): JSDocImplementsTag; + updateJSDocLinkPlain( + node: JSDocLinkPlain, + name: EntityName | JSDocMemberName | undefined, + text: string, + ): JSDocLinkPlain; + createJSDocTypeLiteral( + jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], + isArrayType?: boolean, + ): JSDocTypeLiteral; + updateJSDocTypeLiteral( + node: JSDocTypeLiteral, + jsDocPropertyTags: readonly JSDocPropertyLikeTag[] | undefined, + isArrayType: boolean | undefined, + ): JSDocTypeLiteral; + createJSDocSignature( + typeParameters: readonly JSDocTemplateTag[] | undefined, + parameters: readonly JSDocParameterTag[], + type?: JSDocReturnTag, + ): JSDocSignature; + updateJSDocSignature( + node: JSDocSignature, + typeParameters: readonly JSDocTemplateTag[] | undefined, + parameters: readonly JSDocParameterTag[], + type: JSDocReturnTag | undefined, + ): JSDocSignature; + createJSDocTemplateTag( + tagName: Identifier | undefined, + constraint: JSDocTypeExpression | undefined, + typeParameters: readonly TypeParameterDeclaration[], + comment?: string | NodeArray, + ): JSDocTemplateTag; + updateJSDocTemplateTag( + node: JSDocTemplateTag, + tagName: Identifier | undefined, + constraint: JSDocTypeExpression | undefined, + typeParameters: readonly TypeParameterDeclaration[], + comment: string | NodeArray | undefined, + ): JSDocTemplateTag; + createJSDocTypedefTag( + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression | JSDocTypeLiteral, + fullName?: Identifier | JSDocNamespaceDeclaration, + comment?: string | NodeArray, + ): JSDocTypedefTag; + updateJSDocTypedefTag( + node: JSDocTypedefTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined, + fullName: Identifier | JSDocNamespaceDeclaration | undefined, + comment: string | NodeArray | undefined, + ): JSDocTypedefTag; + createJSDocParameterTag( + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression, + isNameFirst?: boolean, + comment?: string | NodeArray, + ): JSDocParameterTag; + updateJSDocParameterTag( + node: JSDocParameterTag, + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression: JSDocTypeExpression | undefined, + isNameFirst: boolean, + comment: string | NodeArray | undefined, + ): JSDocParameterTag; + createJSDocPropertyTag( + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression?: JSDocTypeExpression, + isNameFirst?: boolean, + comment?: string | NodeArray, + ): JSDocPropertyTag; + updateJSDocPropertyTag( + node: JSDocPropertyTag, + tagName: Identifier | undefined, + name: EntityName, + isBracketed: boolean, + typeExpression: JSDocTypeExpression | undefined, + isNameFirst: boolean, + comment: string | NodeArray | undefined, + ): JSDocPropertyTag; + createJSDocTypeTag( + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocTypeTag; + updateJSDocTypeTag( + node: JSDocTypeTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment: string | NodeArray | undefined, + ): JSDocTypeTag; + createJSDocSeeTag( + tagName: Identifier | undefined, + nameExpression: JSDocNameReference | undefined, + comment?: string | NodeArray, + ): JSDocSeeTag; + updateJSDocSeeTag( + node: JSDocSeeTag, + tagName: Identifier | undefined, + nameExpression: JSDocNameReference | undefined, + comment?: string | NodeArray, + ): JSDocSeeTag; + createJSDocReturnTag( + tagName: Identifier | undefined, + typeExpression?: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocReturnTag; + updateJSDocReturnTag( + node: JSDocReturnTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression | undefined, + comment: string | NodeArray | undefined, + ): JSDocReturnTag; + createJSDocThisTag( + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocThisTag; + updateJSDocThisTag( + node: JSDocThisTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression | undefined, + comment: string | NodeArray | undefined, + ): JSDocThisTag; + createJSDocEnumTag( + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocEnumTag; + updateJSDocEnumTag( + node: JSDocEnumTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment: string | NodeArray | undefined, + ): JSDocEnumTag; + createJSDocCallbackTag( + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + fullName?: Identifier | JSDocNamespaceDeclaration, + comment?: string | NodeArray, + ): JSDocCallbackTag; + updateJSDocCallbackTag( + node: JSDocCallbackTag, + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + fullName: Identifier | JSDocNamespaceDeclaration | undefined, + comment: string | NodeArray | undefined, + ): JSDocCallbackTag; + createJSDocOverloadTag( + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + comment?: string | NodeArray, + ): JSDocOverloadTag; + updateJSDocOverloadTag( + node: JSDocOverloadTag, + tagName: Identifier | undefined, + typeExpression: JSDocSignature, + comment: string | NodeArray | undefined, + ): JSDocOverloadTag; + createJSDocAugmentsTag( + tagName: Identifier | undefined, + className: JSDocAugmentsTag["class"], + comment?: string | NodeArray, + ): JSDocAugmentsTag; + updateJSDocAugmentsTag( + node: JSDocAugmentsTag, + tagName: Identifier | undefined, + className: JSDocAugmentsTag["class"], + comment: string | NodeArray | undefined, + ): JSDocAugmentsTag; + createJSDocImplementsTag( + tagName: Identifier | undefined, + className: JSDocImplementsTag["class"], + comment?: string | NodeArray, + ): JSDocImplementsTag; + updateJSDocImplementsTag( + node: JSDocImplementsTag, + tagName: Identifier | undefined, + className: JSDocImplementsTag["class"], + comment: string | NodeArray | undefined, + ): JSDocImplementsTag; createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocAuthorTag; - updateJSDocAuthorTag(node: JSDocAuthorTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocAuthorTag; + updateJSDocAuthorTag( + node: JSDocAuthorTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocAuthorTag; createJSDocClassTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocClassTag; - updateJSDocClassTag(node: JSDocClassTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocClassTag; + updateJSDocClassTag( + node: JSDocClassTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocClassTag; createJSDocPublicTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocPublicTag; - updateJSDocPublicTag(node: JSDocPublicTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocPublicTag; + updateJSDocPublicTag( + node: JSDocPublicTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocPublicTag; createJSDocPrivateTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocPrivateTag; - updateJSDocPrivateTag(node: JSDocPrivateTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocPrivateTag; - createJSDocProtectedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocProtectedTag; - updateJSDocProtectedTag(node: JSDocProtectedTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocProtectedTag; - createJSDocReadonlyTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocReadonlyTag; - updateJSDocReadonlyTag(node: JSDocReadonlyTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocReadonlyTag; + updateJSDocPrivateTag( + node: JSDocPrivateTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocPrivateTag; + createJSDocProtectedTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocProtectedTag; + updateJSDocProtectedTag( + node: JSDocProtectedTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocProtectedTag; + createJSDocReadonlyTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocReadonlyTag; + updateJSDocReadonlyTag( + node: JSDocReadonlyTag, + tagName: Identifier | undefined, + comment: string | NodeArray | undefined, + ): JSDocReadonlyTag; createJSDocUnknownTag(tagName: Identifier, comment?: string | NodeArray): JSDocUnknownTag; - updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag; - createJSDocDeprecatedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; - updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; - createJSDocOverrideTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; - updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; - createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray): JSDocThrowsTag; - updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; - createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; - updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray | undefined): JSDocSatisfiesTag; + updateJSDocUnknownTag( + node: JSDocUnknownTag, + tagName: Identifier, + comment: string | NodeArray | undefined, + ): JSDocUnknownTag; + createJSDocDeprecatedTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocDeprecatedTag; + updateJSDocDeprecatedTag( + node: JSDocDeprecatedTag, + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocDeprecatedTag; + createJSDocOverrideTag( + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocOverrideTag; + updateJSDocOverrideTag( + node: JSDocOverrideTag, + tagName: Identifier | undefined, + comment?: string | NodeArray, + ): JSDocOverrideTag; + createJSDocThrowsTag( + tagName: Identifier, + typeExpression: JSDocTypeExpression | undefined, + comment?: string | NodeArray, + ): JSDocThrowsTag; + updateJSDocThrowsTag( + node: JSDocThrowsTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression | undefined, + comment?: string | NodeArray | undefined, + ): JSDocThrowsTag; + createJSDocSatisfiesTag( + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment?: string | NodeArray, + ): JSDocSatisfiesTag; + updateJSDocSatisfiesTag( + node: JSDocSatisfiesTag, + tagName: Identifier | undefined, + typeExpression: JSDocTypeExpression, + comment: string | NodeArray | undefined, + ): JSDocSatisfiesTag; createJSDocText(text: string): JSDocText; updateJSDocText(node: JSDocText, text: string): JSDocText; - createJSDocComment(comment?: string | NodeArray | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc; - updateJSDocComment(node: JSDoc, comment: string | NodeArray | undefined, tags: readonly JSDocTag[] | undefined): JSDoc; + createJSDocComment( + comment?: string | NodeArray | undefined, + tags?: readonly JSDocTag[] | undefined, + ): JSDoc; + updateJSDocComment( + node: JSDoc, + comment: string | NodeArray | undefined, + tags: readonly JSDocTag[] | undefined, + ): JSDoc; // // JSX // - createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement): JsxElement; - updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement): JsxElement; - createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxSelfClosingElement; - updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxSelfClosingElement; - createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxOpeningElement; - updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxOpeningElement; + createJsxElement( + openingElement: JsxOpeningElement, + children: readonly JsxChild[], + closingElement: JsxClosingElement, + ): JsxElement; + updateJsxElement( + node: JsxElement, + openingElement: JsxOpeningElement, + children: readonly JsxChild[], + closingElement: JsxClosingElement, + ): JsxElement; + createJsxSelfClosingElement( + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ): JsxSelfClosingElement; + updateJsxSelfClosingElement( + node: JsxSelfClosingElement, + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ): JsxSelfClosingElement; + createJsxOpeningElement( + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ): JsxOpeningElement; + updateJsxOpeningElement( + node: JsxOpeningElement, + tagName: JsxTagNameExpression, + typeArguments: readonly TypeNode[] | undefined, + attributes: JsxAttributes, + ): JsxOpeningElement; createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement; updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement; - createJsxFragment(openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment): JsxFragment; + createJsxFragment( + openingFragment: JsxOpeningFragment, + children: readonly JsxChild[], + closingFragment: JsxClosingFragment, + ): JsxFragment; createJsxText(text: string, containsOnlyTriviaWhiteSpaces?: boolean): JsxText; updateJsxText(node: JsxText, text: string, containsOnlyTriviaWhiteSpaces?: boolean): JsxText; createJsxOpeningFragment(): JsxOpeningFragment; createJsxJsxClosingFragment(): JsxClosingFragment; - updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment): JsxFragment; + updateJsxFragment( + node: JsxFragment, + openingFragment: JsxOpeningFragment, + children: readonly JsxChild[], + closingFragment: JsxClosingFragment, + ): JsxFragment; createJsxAttribute(name: JsxAttributeName, initializer: JsxAttributeValue | undefined): JsxAttribute; - updateJsxAttribute(node: JsxAttribute, name: JsxAttributeName, initializer: JsxAttributeValue | undefined): JsxAttribute; + updateJsxAttribute( + node: JsxAttribute, + name: JsxAttributeName, + initializer: JsxAttributeValue | undefined, + ): JsxAttribute; createJsxAttributes(properties: readonly JsxAttributeLike[]): JsxAttributes; updateJsxAttributes(node: JsxAttributes, properties: readonly JsxAttributeLike[]): JsxAttributes; createJsxSpreadAttribute(expression: Expression): JsxSpreadAttribute; @@ -8787,8 +10139,15 @@ export interface NodeFactory { updateDefaultClause(node: DefaultClause, statements: readonly Statement[]): DefaultClause; createHeritageClause(token: HeritageClause["token"], types: readonly ExpressionWithTypeArguments[]): HeritageClause; updateHeritageClause(node: HeritageClause, types: readonly ExpressionWithTypeArguments[]): HeritageClause; - createCatchClause(variableDeclaration: string | BindingName | VariableDeclaration | undefined, block: Block): CatchClause; - updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block): CatchClause; + createCatchClause( + variableDeclaration: string | BindingName | VariableDeclaration | undefined, + block: Block, + ): CatchClause; + updateCatchClause( + node: CatchClause, + variableDeclaration: VariableDeclaration | undefined, + block: Block, + ): CatchClause; // // Property assignments @@ -8796,8 +10155,15 @@ export interface NodeFactory { createPropertyAssignment(name: string | PropertyName, initializer: Expression): PropertyAssignment; updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression): PropertyAssignment; - createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression): ShorthandPropertyAssignment; - updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined): ShorthandPropertyAssignment; + createShorthandPropertyAssignment( + name: string | Identifier, + objectAssignmentInitializer?: Expression, + ): ShorthandPropertyAssignment; + updateShorthandPropertyAssignment( + node: ShorthandPropertyAssignment, + name: Identifier, + objectAssignmentInitializer: Expression | undefined, + ): ShorthandPropertyAssignment; createSpreadAssignment(expression: Expression): SpreadAssignment; updateSpreadAssignment(node: SpreadAssignment, expression: Expression): SpreadAssignment; @@ -8813,21 +10179,42 @@ export interface NodeFactory { // createSourceFile(statements: readonly Statement[], endOfFileToken: EndOfFileToken, flags: NodeFlags): SourceFile; - updateSourceFile(node: SourceFile, statements: readonly Statement[], isDeclarationFile?: boolean, referencedFiles?: readonly FileReference[], typeReferences?: readonly FileReference[], hasNoDefaultLib?: boolean, libReferences?: readonly FileReference[]): SourceFile; + updateSourceFile( + node: SourceFile, + statements: readonly Statement[], + isDeclarationFile?: boolean, + referencedFiles?: readonly FileReference[], + typeReferences?: readonly FileReference[], + hasNoDefaultLib?: boolean, + libReferences?: readonly FileReference[], + ): SourceFile; /** @internal */ createRedirectedSourceFile(redirectInfo: RedirectInfo): SourceFile; - /** @deprecated @internal */ createUnparsedSource(prologues: readonly UnparsedPrologue[], syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, texts: readonly UnparsedSourceText[]): UnparsedSource; + /** @deprecated @internal */ createUnparsedSource( + prologues: readonly UnparsedPrologue[], + syntheticReferences: readonly UnparsedSyntheticReference[] | undefined, + texts: readonly UnparsedSourceText[], + ): UnparsedSource; /** @deprecated @internal */ createUnparsedPrologue(data?: string): UnparsedPrologue; - /** @deprecated @internal */ createUnparsedPrepend(data: string | undefined, texts: readonly UnparsedSourceText[]): UnparsedPrepend; + /** @deprecated @internal */ createUnparsedPrepend( + data: string | undefined, + texts: readonly UnparsedSourceText[], + ): UnparsedPrepend; /** @deprecated @internal */ createUnparsedTextLike(data: string | undefined, internal: boolean): UnparsedTextLike; - /** @deprecated @internal */ createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference): UnparsedSyntheticReference; + /** @deprecated @internal */ createUnparsedSyntheticReference( + section: BundleFileHasNoDefaultLib | BundleFileReference, + ): UnparsedSyntheticReference; /** @deprecated @internal */ createInputFiles(): InputFiles; // // Synthetic Nodes // - /** @internal */ createSyntheticExpression(type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember): SyntheticExpression; + /** @internal */ createSyntheticExpression( + type: Type, + isSpread?: boolean, + tupleNameSource?: ParameterDeclaration | NamedTupleMember, + ): SyntheticExpression; /** @internal */ createSyntaxList(children: Node[]): SyntaxList; // @@ -8836,22 +10223,42 @@ export interface NodeFactory { createNotEmittedStatement(original: Node): NotEmittedStatement; createPartiallyEmittedExpression(expression: Expression, original?: Node): PartiallyEmittedExpression; - updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression): PartiallyEmittedExpression; - /** @internal */ createSyntheticReferenceExpression(expression: Expression, thisArg: Expression): SyntheticReferenceExpression; - /** @internal */ updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression): SyntheticReferenceExpression; + updatePartiallyEmittedExpression( + node: PartiallyEmittedExpression, + expression: Expression, + ): PartiallyEmittedExpression; + /** @internal */ createSyntheticReferenceExpression( + expression: Expression, + thisArg: Expression, + ): SyntheticReferenceExpression; + /** @internal */ updateSyntheticReferenceExpression( + node: SyntheticReferenceExpression, + expression: Expression, + thisArg: Expression, + ): SyntheticReferenceExpression; createCommaListExpression(elements: readonly Expression[]): CommaListExpression; updateCommaListExpression(node: CommaListExpression, elements: readonly Expression[]): CommaListExpression; createBundle(sourceFiles: readonly SourceFile[]): Bundle; - /** @deprecated*/ createBundle(sourceFiles: readonly SourceFile[], prepends?: readonly (UnparsedSource | InputFiles)[]): Bundle; // eslint-disable-line @typescript-eslint/unified-signatures + /** @deprecated*/ createBundle( + sourceFiles: readonly SourceFile[], + prepends?: readonly (UnparsedSource | InputFiles)[], + ): Bundle; // eslint-disable-line @typescript-eslint/unified-signatures updateBundle(node: Bundle, sourceFiles: readonly SourceFile[]): Bundle; - /** @deprecated*/ updateBundle(node: Bundle, sourceFiles: readonly SourceFile[], prepends?: readonly (UnparsedSource | InputFiles)[]): Bundle; // eslint-disable-line @typescript-eslint/unified-signatures + /** @deprecated*/ updateBundle( + node: Bundle, + sourceFiles: readonly SourceFile[], + prepends?: readonly (UnparsedSource | InputFiles)[], + ): Bundle; // eslint-disable-line @typescript-eslint/unified-signatures // // Common operators // createComma(left: Expression, right: Expression): BinaryExpression; - createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression): DestructuringAssignment; + createAssignment( + left: ObjectLiteralExpression | ArrayLiteralExpression, + right: Expression, + ): DestructuringAssignment; createAssignment(left: Expression, right: Expression): AssignmentExpression; createLogicalOr(left: Expression, right: Expression): BinaryExpression; createLogicalAnd(left: Expression, right: Expression): BinaryExpression; @@ -8889,10 +10296,17 @@ export interface NodeFactory { // createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression; - createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; + createImmediatelyInvokedFunctionExpression( + statements: readonly Statement[], + param: ParameterDeclaration, + paramValue: Expression, + ): CallExpression; createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): ImmediatelyInvokedArrowFunction; - createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): ImmediatelyInvokedArrowFunction; - + createImmediatelyInvokedArrowFunction( + statements: readonly Statement[], + param: ParameterDeclaration, + paramValue: Expression, + ): ImmediatelyInvokedArrowFunction; createVoidZero(): VoidExpression; createExportDefault(expression: Expression): ExportAssignment; @@ -8900,19 +10314,63 @@ export interface NodeFactory { /** @internal */ createTypeCheck(value: Expression, tag: TypeOfTag): Expression; /** @internal */ createIsNotTypeCheck(value: Expression, tag: TypeOfTag): Expression; - /** @internal */ createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]): CallExpression; - /** @internal */ createGlobalMethodCall(globalObjectName: string, globalMethodName: string, argumentsList: readonly Expression[]): CallExpression; - /** @internal */ createFunctionBindCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]): CallExpression; - /** @internal */ createFunctionCallCall(target: Expression, thisArg: Expression, argumentsList: readonly Expression[]): CallExpression; - /** @internal */ createFunctionApplyCall(target: Expression, thisArg: Expression, argumentsExpression: Expression): CallExpression; - /** @internal */ createObjectDefinePropertyCall(target: Expression, propertyName: string | Expression, attributes: Expression): CallExpression; - /** @internal */ createObjectGetOwnPropertyDescriptorCall(target: Expression, propertyName: string | Expression): CallExpression; - /** @internal */ createReflectGetCall(target: Expression, propertyKey: Expression, receiver?: Expression): CallExpression; - /** @internal */ createReflectSetCall(target: Expression, propertyKey: Expression, value: Expression, receiver?: Expression): CallExpression; - /** @internal */ createPropertyDescriptor(attributes: PropertyDescriptorAttributes, singleLine?: boolean): ObjectLiteralExpression; + /** @internal */ createMethodCall( + object: Expression, + methodName: string | Identifier, + argumentsList: readonly Expression[], + ): CallExpression; + /** @internal */ createGlobalMethodCall( + globalObjectName: string, + globalMethodName: string, + argumentsList: readonly Expression[], + ): CallExpression; + /** @internal */ createFunctionBindCall( + target: Expression, + thisArg: Expression, + argumentsList: readonly Expression[], + ): CallExpression; + /** @internal */ createFunctionCallCall( + target: Expression, + thisArg: Expression, + argumentsList: readonly Expression[], + ): CallExpression; + /** @internal */ createFunctionApplyCall( + target: Expression, + thisArg: Expression, + argumentsExpression: Expression, + ): CallExpression; + /** @internal */ createObjectDefinePropertyCall( + target: Expression, + propertyName: string | Expression, + attributes: Expression, + ): CallExpression; + /** @internal */ createObjectGetOwnPropertyDescriptorCall( + target: Expression, + propertyName: string | Expression, + ): CallExpression; + /** @internal */ createReflectGetCall( + target: Expression, + propertyKey: Expression, + receiver?: Expression, + ): CallExpression; + /** @internal */ createReflectSetCall( + target: Expression, + propertyKey: Expression, + value: Expression, + receiver?: Expression, + ): CallExpression; + /** @internal */ createPropertyDescriptor( + attributes: PropertyDescriptorAttributes, + singleLine?: boolean, + ): ObjectLiteralExpression; /** @internal */ createArraySliceCall(array: Expression, start?: number | Expression): CallExpression; /** @internal */ createArrayConcatCall(array: Expression, values: readonly Expression[]): CallExpression; - /** @internal */ createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget, cacheIdentifiers?: boolean): CallBinding; + /** @internal */ createCallBinding( + expression: Expression, + recordTempVariable: (temp: Identifier) => void, + languageVersion?: ScriptTarget, + cacheIdentifiers?: boolean, + ): CallBinding; /** * Wraps an expression that cannot be an assignment target in an expression that can be. * @@ -8959,7 +10417,12 @@ export interface NodeFactory { * * @internal */ - getLocalName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean, ignoreAssignedName?: boolean): Identifier; + getLocalName( + node: Declaration, + allowComments?: boolean, + allowSourceMaps?: boolean, + ignoreAssignedName?: boolean, + ): Identifier; /** * Gets the export name of a declaration. This is primarily used for declarations that can be * referred to by name in the declaration's immediate scope (classes, enums, namespaces). An @@ -8993,7 +10456,12 @@ export interface NodeFactory { * * @internal */ - getNamespaceMemberName(ns: Identifier, name: Identifier, allowComments?: boolean, allowSourceMaps?: boolean): PropertyAccessExpression; + getNamespaceMemberName( + ns: Identifier, + name: Identifier, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): PropertyAccessExpression; /** * Gets the exported name of a declaration for use in expressions. * @@ -9007,14 +10475,27 @@ export interface NodeFactory { * * @internal */ - getExternalModuleOrNamespaceExportName(ns: Identifier | undefined, node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier | PropertyAccessExpression; + getExternalModuleOrNamespaceExportName( + ns: Identifier | undefined, + node: Declaration, + allowComments?: boolean, + allowSourceMaps?: boolean, + ): Identifier | PropertyAccessExpression; // // Utilities // - restoreOuterExpressions(outerExpression: Expression | undefined, innerExpression: Expression, kinds?: OuterExpressionKinds): Expression; - /** @internal */ restoreEnclosingLabel(node: Statement, outermostLabeledStatement: LabeledStatement | undefined, afterRestoreLabelCallback?: (node: LabeledStatement) => void): Statement; + restoreOuterExpressions( + outerExpression: Expression | undefined, + innerExpression: Expression, + kinds?: OuterExpressionKinds, + ): Expression; + /** @internal */ restoreEnclosingLabel( + node: Statement, + outermostLabeledStatement: LabeledStatement | undefined, + afterRestoreLabelCallback?: (node: LabeledStatement) => void, + ): Statement; /** @internal */ createUseStrictPrologue(): PrologueDirective; /** * Copies any necessary standard and custom prologue-directives into target array. @@ -9025,7 +10506,12 @@ export interface NodeFactory { * * @internal */ - copyPrologue(source: readonly Statement[], target: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number; + copyPrologue( + source: readonly Statement[], + target: Statement[], + ensureUseStrict?: boolean, + visitor?: (node: Node) => VisitResult, + ): number; /** * Copies only the standard (string-expression) prologue-directives into the target statement-array. * @param source origin statements array @@ -9035,7 +10521,12 @@ export interface NodeFactory { * * @internal */ - copyStandardPrologue(source: readonly Statement[], target: Statement[], statementOffset: number | undefined, ensureUseStrict?: boolean): number; + copyStandardPrologue( + source: readonly Statement[], + target: Statement[], + statementOffset: number | undefined, + ensureUseStrict?: boolean, + ): number; /** * Copies only the custom prologue-directives into target statement-array. * @param source origin statements array @@ -9045,8 +10536,20 @@ export interface NodeFactory { * * @internal */ - copyCustomPrologue(source: readonly Statement[], target: Statement[], statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Statement) => boolean): number; - /** @internal */ copyCustomPrologue(source: readonly Statement[], target: Statement[], statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Statement) => boolean): number | undefined; + copyCustomPrologue( + source: readonly Statement[], + target: Statement[], + statementOffset: number, + visitor?: (node: Node) => VisitResult, + filter?: (node: Statement) => boolean, + ): number; + /** @internal */ copyCustomPrologue( + source: readonly Statement[], + target: Statement[], + statementOffset: number | undefined, + visitor?: (node: Node) => VisitResult, + filter?: (node: Statement) => boolean, + ): number | undefined; /** @internal */ ensureUseStrict(statements: NodeArray): NodeArray; /** @internal */ liftToBlock(nodes: readonly Node[]): Statement; /** @@ -9054,7 +10557,10 @@ export interface NodeFactory { * * @internal */ - mergeLexicalEnvironment(statements: NodeArray, declarations: readonly Statement[] | undefined): NodeArray; + mergeLexicalEnvironment( + statements: NodeArray, + declarations: readonly Statement[] | undefined, + ): NodeArray; /** * Appends generated lexical declarations to an array of statements. * @@ -9070,15 +10576,21 @@ export interface NodeFactory { * @internal */ cloneNode(node: T): T; - /** @internal */ updateModifiers(node: T, modifiers: readonly Modifier[] | ModifierFlags | undefined): T; - /** @internal */ updateModifierLike(node: T, modifierLike: readonly ModifierLike[] | undefined): T; + /** @internal */ updateModifiers( + node: T, + modifiers: readonly Modifier[] | ModifierFlags | undefined, + ): T; + /** @internal */ updateModifierLike( + node: T, + modifierLike: readonly ModifierLike[] | undefined, + ): T; } /** @internal */ export const enum LexicalEnvironmentFlags { None = 0, InParameters = 1 << 0, // currently visiting a parameter list - VariablesHoistedInParameters = 1 << 1 // a temp variable was hoisted while visiting a parameter list + VariablesHoistedInParameters = 1 << 1, // a temp variable was hoisted while visiting a parameter list } export interface CoreTransformationContext { @@ -9223,7 +10735,9 @@ export type Transformer = (node: T) => T; /** * A function that accepts and possibly transforms a node. */ -export type Visitor = (node: TIn) => VisitResult; +export type Visitor = ( + node: TIn, +) => VisitResult; /** * A function that walks a node using the given visitor, lifting node arrays into single nodes, @@ -9309,10 +10823,28 @@ export interface Printer { * Prints a bundle of source files as-is, without any emit transformations. */ printBundle(bundle: Bundle): string; - /** @internal */ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; - /** @internal */ writeList(format: ListFormat, list: NodeArray | undefined, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; - /** @internal */ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; - /** @internal */ writeBundle(bundle: Bundle, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; + /** @internal */ writeNode( + hint: EmitHint, + node: Node, + sourceFile: SourceFile | undefined, + writer: EmitTextWriter, + ): void; + /** @internal */ writeList( + format: ListFormat, + list: NodeArray | undefined, + sourceFile: SourceFile | undefined, + writer: EmitTextWriter, + ): void; + /** @internal */ writeFile( + sourceFile: SourceFile, + writer: EmitTextWriter, + sourceMapGenerator: SourceMapGenerator | undefined, + ): void; + /** @internal */ writeBundle( + bundle: Bundle, + writer: EmitTextWriter, + sourceMapGenerator: SourceMapGenerator | undefined, + ): void; /** @deprecated @internal */ bundleFileInfo?: BundleFileInfo; } @@ -9357,7 +10889,12 @@ export interface BundleFileHasNoDefaultLib extends BundleFileSectionBase { /** @deprecated @internal */ export interface BundleFileReference extends BundleFileSectionBase { - kind: BundleFileSectionKind.Reference | BundleFileSectionKind.Type | BundleFileSectionKind.Lib | BundleFileSectionKind.TypeResolutionModeImport | BundleFileSectionKind.TypeResolutionModeRequire; + kind: + | BundleFileSectionKind.Reference + | BundleFileSectionKind.Type + | BundleFileSectionKind.Lib + | BundleFileSectionKind.TypeResolutionModeImport + | BundleFileSectionKind.TypeResolutionModeRequire; data: string; } @@ -9378,7 +10915,7 @@ export interface BundleFileTextLike extends BundleFileSectionBase { /** @deprecated @internal */ export type BundleFileSection = - BundleFilePrologue + | BundleFilePrologue | BundleFileEmitHelpers | BundleFileHasNoDefaultLib | BundleFileReference @@ -9481,8 +11018,18 @@ export interface PrintHandlers { * ``` */ substituteNode?(hint: EmitHint, node: Node): Node; - /** @internal */ onEmitSourceMapOfNode?: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void; - /** @internal */ onEmitSourceMapOfToken?: (node: Node | undefined, token: SyntaxKind, writer: (s: string) => void, pos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, pos: number) => number) => number; + /** @internal */ onEmitSourceMapOfNode?: ( + hint: EmitHint, + node: Node, + emitCallback: (hint: EmitHint, node: Node) => void, + ) => void; + /** @internal */ onEmitSourceMapOfToken?: ( + node: Node | undefined, + token: SyntaxKind, + writer: (s: string) => void, + pos: number, + emitCallback: (token: SyntaxKind, writer: (s: string) => void, pos: number) => number, + ) => number; /** @internal */ onEmitSourceMapOfPosition?: (pos: number) => void; /** @internal */ onSetSourceFile?: (node: SourceFile) => void; /** @internal */ onBeforeEmitNode?: (node: Node | undefined) => void; @@ -9551,11 +11098,25 @@ export interface SourceMapGenerator { /** * Adds a mapping with source information. */ - addMapping(generatedLine: number, generatedCharacter: number, sourceIndex: number, sourceLine: number, sourceCharacter: number, nameIndex?: number): void; + addMapping( + generatedLine: number, + generatedCharacter: number, + sourceIndex: number, + sourceLine: number, + sourceCharacter: number, + nameIndex?: number, + ): void; /** * Appends a source map. */ - appendSourceMap(generatedLine: number, generatedCharacter: number, sourceMap: RawSourceMap, sourceMapPath: string, start?: LineAndCharacter, end?: LineAndCharacter): void; + appendSourceMap( + generatedLine: number, + generatedCharacter: number, + sourceMap: RawSourceMap, + sourceMapPath: string, + start?: LineAndCharacter, + end?: LineAndCharacter, + ): void; /** * Gets the source map as a `RawSourceMap` object. */ @@ -9658,10 +11219,34 @@ export interface ModuleSpecifierOptions { /** @internal */ export interface ModuleSpecifierCache { - get(fromFileName: Path, toFileName: Path, preferences: UserPreferences, options: ModuleSpecifierOptions): Readonly | undefined; - set(fromFileName: Path, toFileName: Path, preferences: UserPreferences, options: ModuleSpecifierOptions, modulePaths: readonly ModulePath[], moduleSpecifiers: readonly string[]): void; - setBlockedByPackageJsonDependencies(fromFileName: Path, toFileName: Path, preferences: UserPreferences, options: ModuleSpecifierOptions, isBlockedByPackageJsonDependencies: boolean): void; - setModulePaths(fromFileName: Path, toFileName: Path, preferences: UserPreferences, options: ModuleSpecifierOptions, modulePaths: readonly ModulePath[]): void; + get( + fromFileName: Path, + toFileName: Path, + preferences: UserPreferences, + options: ModuleSpecifierOptions, + ): Readonly | undefined; + set( + fromFileName: Path, + toFileName: Path, + preferences: UserPreferences, + options: ModuleSpecifierOptions, + modulePaths: readonly ModulePath[], + moduleSpecifiers: readonly string[], + ): void; + setBlockedByPackageJsonDependencies( + fromFileName: Path, + toFileName: Path, + preferences: UserPreferences, + options: ModuleSpecifierOptions, + isBlockedByPackageJsonDependencies: boolean, + ): void; + setModulePaths( + fromFileName: Path, + toFileName: Path, + preferences: UserPreferences, + options: ModuleSpecifierOptions, + modulePaths: readonly ModulePath[], + ): void; clear(): void; count(): number; } @@ -9679,7 +11264,7 @@ export interface SymbolTracker { reportCyclicStructureError?(): void; reportLikelyUnsafeImportRequiredError?(specifier: string): void; reportTruncationError?(): void; - moduleResolverHost?: ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string }; + moduleResolverHost?: ModuleSpecifierResolutionHost & { getCommonSourceDirectory(): string; }; trackReferencedAmbientModule?(decl: ModuleDeclaration, symbol: Symbol): void; trackExternalModuleSymbolOfImportTypeNode?(symbol: Symbol): void; reportNonlocalAugmentation?(containingFile: SourceFile, parentSymbol: Symbol, augmentingSymbol: Symbol): void; @@ -9720,6 +11305,7 @@ export interface SyntaxList extends Node { _children: Node[]; } +// dprint-ignore export const enum ListFormat { None = 0, @@ -9808,24 +11394,24 @@ export const enum ListFormat { /** @internal */ export const enum PragmaKindFlags { - None = 0, + None = 0, /** * Triple slash comment of the form * /// */ - TripleSlashXML = 1 << 0, + TripleSlashXML = 1 << 0, /** * Single line comment of the form * // @pragma-name argval1 argval2 * or * /// @pragma-name argval1 argval2 */ - SingleLine = 1 << 1, + SingleLine = 1 << 1, /** * Multiline non-jsdoc pragma of the form * /* @pragma-name argval1 argval2 * / */ - MultiLine = 1 << 2, + MultiLine = 1 << 2, All = TripleSlashXML | SingleLine | MultiLine, Default = All, } @@ -9838,12 +11424,22 @@ export interface PragmaArgumentSpecification { } /** @internal */ -export interface PragmaDefinition { +export interface PragmaDefinition< + T1 extends string = string, + T2 extends string = string, + T3 extends string = string, + T4 extends string = string, +> { args?: | readonly [PragmaArgumentSpecification] | readonly [PragmaArgumentSpecification, PragmaArgumentSpecification] | readonly [PragmaArgumentSpecification, PragmaArgumentSpecification, PragmaArgumentSpecification] - | readonly [PragmaArgumentSpecification, PragmaArgumentSpecification, PragmaArgumentSpecification, PragmaArgumentSpecification]; + | readonly [ + PragmaArgumentSpecification, + PragmaArgumentSpecification, + PragmaArgumentSpecification, + PragmaArgumentSpecification, + ]; // If not present, defaults to PragmaKindFlags.Default kind?: PragmaKindFlags; } @@ -9858,58 +11454,62 @@ export const commentPragmas = { { name: "lib", optional: true, captureSpan: true }, { name: "path", optional: true, captureSpan: true }, { name: "no-default-lib", optional: true }, - { name: "resolution-mode", optional: true } + { name: "resolution-mode", optional: true }, ], - kind: PragmaKindFlags.TripleSlashXML + kind: PragmaKindFlags.TripleSlashXML, }, "amd-dependency": { args: [{ name: "path" }, { name: "name", optional: true }], - kind: PragmaKindFlags.TripleSlashXML + kind: PragmaKindFlags.TripleSlashXML, }, "amd-module": { args: [{ name: "name" }], - kind: PragmaKindFlags.TripleSlashXML + kind: PragmaKindFlags.TripleSlashXML, }, "ts-check": { - kind: PragmaKindFlags.SingleLine + kind: PragmaKindFlags.SingleLine, }, "ts-nocheck": { - kind: PragmaKindFlags.SingleLine + kind: PragmaKindFlags.SingleLine, }, "jsx": { args: [{ name: "factory" }], - kind: PragmaKindFlags.MultiLine + kind: PragmaKindFlags.MultiLine, }, "jsxfrag": { args: [{ name: "factory" }], - kind: PragmaKindFlags.MultiLine + kind: PragmaKindFlags.MultiLine, }, "jsximportsource": { args: [{ name: "factory" }], - kind: PragmaKindFlags.MultiLine + kind: PragmaKindFlags.MultiLine, }, "jsxruntime": { args: [{ name: "factory" }], - kind: PragmaKindFlags.MultiLine + kind: PragmaKindFlags.MultiLine, }, } as const; /** @internal */ -export type PragmaArgTypeMaybeCapture = TDesc extends {captureSpan: true} ? {value: string, pos: number, end: number} : string; +export type PragmaArgTypeMaybeCapture = TDesc extends { captureSpan: true; } + ? { value: string; pos: number; end: number; } + : string; /** @internal */ -export type PragmaArgTypeOptional = - TDesc extends {optional: true} - ? {[K in TName]?: PragmaArgTypeMaybeCapture} - : {[K in TName]: PragmaArgTypeMaybeCapture}; +export type PragmaArgTypeOptional = TDesc extends { optional: true; } + ? { [K in TName]?: PragmaArgTypeMaybeCapture; } + : { [K in TName]: PragmaArgTypeMaybeCapture; }; /** @internal */ -export type UnionToIntersection = - (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; +export type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I + : never; /** @internal */ export type ArgumentDefinitionToFieldUnion[]> = { - [K in keyof T]: PragmaArgTypeOptional + [K in keyof T]: PragmaArgTypeOptional< + T[K], + T[K] extends { name: infer TName; } ? TName extends string ? TName : never : never + >; }[Extract]; // The mapped type maps over only the tuple members, but this reindex gets _all_ members - by extracting only `number` keys, we get only the tuple members /** @@ -9917,24 +11517,36 @@ export type ArgumentDefinitionToFieldUnion = - ConcretePragmaSpecs[KPrag] extends { args: readonly PragmaArgumentSpecification[] } - ? UnionToIntersection> - : never; +export type PragmaArgumentType = ConcretePragmaSpecs[KPrag] extends + { args: readonly PragmaArgumentSpecification[]; } + ? UnionToIntersection> + : never; /** @internal */ export type ConcretePragmaSpecs = typeof commentPragmas; /** @internal */ -export type PragmaPseudoMap = {[K in keyof ConcretePragmaSpecs]: {arguments: PragmaArgumentType, range: CommentRange}}; +export type PragmaPseudoMap = { + [K in keyof ConcretePragmaSpecs]: { arguments: PragmaArgumentType; range: CommentRange; }; +}; /** @internal */ -export type PragmaPseudoMapEntry = {[K in keyof PragmaPseudoMap]: {name: K, args: PragmaPseudoMap[K]}}[keyof PragmaPseudoMap]; +export type PragmaPseudoMapEntry = { + [K in keyof PragmaPseudoMap]: { name: K; args: PragmaPseudoMap[K]; }; +}[keyof PragmaPseudoMap]; /** @internal */ -export interface ReadonlyPragmaMap extends ReadonlyMap { +export interface ReadonlyPragmaMap + extends ReadonlyMap +{ get(key: TKey): PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][]; - forEach(action: (value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], key: TKey, map: ReadonlyPragmaMap) => void): void; + forEach( + action: ( + value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], + key: TKey, + map: ReadonlyPragmaMap, + ) => void, + ): void; } /** @@ -9944,10 +11556,20 @@ export interface ReadonlyPragmaMap extends ReadonlyMap, ReadonlyPragmaMap { +export interface PragmaMap + extends + Map, + ReadonlyPragmaMap +{ set(key: TKey, value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][]): this; get(key: TKey): PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][]; - forEach(action: (value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], key: TKey, map: PragmaMap) => void): void; + forEach( + action: ( + value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], + key: TKey, + map: PragmaMap, + ) => void, + ): void; } /** @internal */ @@ -9978,7 +11600,7 @@ export interface UserPreferences { readonly jsxAttributeCompletionStyle?: "auto" | "braces" | "none"; readonly includeInlayParameterNameHints?: "none" | "literals" | "all"; readonly includeInlayParameterNameHintsWhenArgumentMatchesName?: boolean; - readonly includeInlayFunctionParameterTypeHints?: boolean, + readonly includeInlayFunctionParameterTypeHints?: boolean; readonly includeInlayVariableTypeHints?: boolean; readonly includeInlayVariableTypeHintsWhenTypeMatchesName?: boolean; readonly includeInlayPropertyDeclarationTypeHints?: boolean; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f00b10dbc7bb6..66917c439d60e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -652,8 +652,8 @@ function createSingleLineStringWriter(): EmitTextWriter { /** @internal */ export function changesAffectModuleResolution(oldOptions: CompilerOptions, newOptions: CompilerOptions): boolean { - return oldOptions.configFilePath !== newOptions.configFilePath || - optionsHaveModuleResolutionChanges(oldOptions, newOptions); + return oldOptions.configFilePath !== newOptions.configFilePath + || optionsHaveModuleResolutionChanges(oldOptions, newOptions); } /** @internal */ @@ -667,9 +667,15 @@ export function changesAffectingProgramStructure(oldOptions: CompilerOptions, ne } /** @internal */ -export function optionsHaveChanges(oldOptions: CompilerOptions, newOptions: CompilerOptions, optionDeclarations: readonly CommandLineOption[]) { - return oldOptions !== newOptions && optionDeclarations.some(o => - !isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o))); +export function optionsHaveChanges( + oldOptions: CompilerOptions, + newOptions: CompilerOptions, + optionDeclarations: readonly CommandLineOption[], +) { + return oldOptions !== newOptions + && optionDeclarations.some(o => + !isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o)) + ); } /** @internal */ @@ -689,7 +695,10 @@ export function forEachAncestor(node: Node, callback: (n: Node) => T | undefi * * @internal */ -export function forEachEntry(map: ReadonlyMap, callback: (value: V, key: K) => U | undefined): U | undefined { +export function forEachEntry( + map: ReadonlyMap, + callback: (value: V, key: K) => U | undefined, +): U | undefined { const iterator = map.entries(); for (const [key, value] of iterator) { const result = callback(value, key); @@ -746,12 +755,21 @@ export function getFullWidth(node: Node) { } /** @internal */ -export function getResolvedModule(sourceFile: SourceFile | undefined, moduleNameText: string, mode: ResolutionMode): ResolvedModuleFull | undefined { +export function getResolvedModule( + sourceFile: SourceFile | undefined, + moduleNameText: string, + mode: ResolutionMode, +): ResolvedModuleFull | undefined { return sourceFile?.resolvedModules?.get(moduleNameText, mode)?.resolvedModule; } /** @internal */ -export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModuleWithFailedLookupLocations, mode: ResolutionMode): void { +export function setResolvedModule( + sourceFile: SourceFile, + moduleNameText: string, + resolvedModule: ResolvedModuleWithFailedLookupLocations, + mode: ResolutionMode, +): void { if (!sourceFile.resolvedModules) { sourceFile.resolvedModules = createModeAwareCache(); } @@ -760,66 +778,106 @@ export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string } /** @internal */ -export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, mode: ResolutionMode): void { +export function setResolvedTypeReferenceDirective( + sourceFile: SourceFile, + typeReferenceDirectiveName: string, + resolvedTypeReferenceDirective: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, + mode: ResolutionMode, +): void { if (!sourceFile.resolvedTypeReferenceDirectiveNames) { sourceFile.resolvedTypeReferenceDirectiveNames = createModeAwareCache(); } - sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, mode, resolvedTypeReferenceDirective); + sourceFile.resolvedTypeReferenceDirectiveNames.set( + typeReferenceDirectiveName, + mode, + resolvedTypeReferenceDirective, + ); } /** @internal */ -export function getResolvedTypeReferenceDirective(sourceFile: SourceFile | undefined, typeReferenceDirectiveName: string, mode: ResolutionMode): ResolvedTypeReferenceDirective | undefined { - return sourceFile?.resolvedTypeReferenceDirectiveNames?.get(typeReferenceDirectiveName, mode)?.resolvedTypeReferenceDirective; +export function getResolvedTypeReferenceDirective( + sourceFile: SourceFile | undefined, + typeReferenceDirectiveName: string, + mode: ResolutionMode, +): ResolvedTypeReferenceDirective | undefined { + return sourceFile?.resolvedTypeReferenceDirectiveNames?.get(typeReferenceDirectiveName, mode) + ?.resolvedTypeReferenceDirective; } /** @internal */ export function projectReferenceIsEqualTo(oldRef: ProjectReference, newRef: ProjectReference) { - return oldRef.path === newRef.path && - !oldRef.prepend === !newRef.prepend && - !oldRef.circular === !newRef.circular; -} - -/** @internal */ -export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleWithFailedLookupLocations, newResolution: ResolvedModuleWithFailedLookupLocations): boolean { - return oldResolution === newResolution || - oldResolution.resolvedModule === newResolution.resolvedModule || - !!oldResolution.resolvedModule && - !!newResolution.resolvedModule && - oldResolution.resolvedModule.isExternalLibraryImport === newResolution.resolvedModule.isExternalLibraryImport && - oldResolution.resolvedModule.extension === newResolution.resolvedModule.extension && - oldResolution.resolvedModule.resolvedFileName === newResolution.resolvedModule.resolvedFileName && - oldResolution.resolvedModule.originalPath === newResolution.resolvedModule.originalPath && - packageIdIsEqual(oldResolution.resolvedModule.packageId, newResolution.resolvedModule.packageId) && - oldResolution.node10Result === newResolution.node10Result; + return oldRef.path === newRef.path + && !oldRef.prepend === !newRef.prepend + && !oldRef.circular === !newRef.circular; } /** @internal */ -export function createModuleNotFoundChain(sourceFile: SourceFile, host: TypeCheckerHost, moduleReference: string, mode: ResolutionMode, packageName: string) { +export function moduleResolutionIsEqualTo( + oldResolution: ResolvedModuleWithFailedLookupLocations, + newResolution: ResolvedModuleWithFailedLookupLocations, +): boolean { + return oldResolution === newResolution + || oldResolution.resolvedModule === newResolution.resolvedModule + || !!oldResolution.resolvedModule + && !!newResolution.resolvedModule + && oldResolution.resolvedModule.isExternalLibraryImport + === newResolution.resolvedModule.isExternalLibraryImport + && oldResolution.resolvedModule.extension === newResolution.resolvedModule.extension + && oldResolution.resolvedModule.resolvedFileName === newResolution.resolvedModule.resolvedFileName + && oldResolution.resolvedModule.originalPath === newResolution.resolvedModule.originalPath + && packageIdIsEqual(oldResolution.resolvedModule.packageId, newResolution.resolvedModule.packageId) + && oldResolution.node10Result === newResolution.node10Result; +} + +/** @internal */ +export function createModuleNotFoundChain( + sourceFile: SourceFile, + host: TypeCheckerHost, + moduleReference: string, + mode: ResolutionMode, + packageName: string, +) { const node10Result = sourceFile.resolvedModules?.get(moduleReference, mode)?.node10Result; const result = node10Result ? chainDiagnosticMessages( /*details*/ undefined, - Diagnostics.There_are_types_at_0_but_this_result_could_not_be_resolved_when_respecting_package_json_exports_The_1_library_may_need_to_update_its_package_json_or_typings, + Diagnostics + .There_are_types_at_0_but_this_result_could_not_be_resolved_when_respecting_package_json_exports_The_1_library_may_need_to_update_its_package_json_or_typings, node10Result, - node10Result.indexOf(nodeModulesPathPart + "@types/") > -1 ? `@types/${mangleScopedPackageName(packageName)}` : packageName) + node10Result.indexOf(nodeModulesPathPart + "@types/") > -1 + ? `@types/${mangleScopedPackageName(packageName)}` : packageName, + ) : host.typesPackageExists(packageName) - ? chainDiagnosticMessages( - /*details*/ undefined, - Diagnostics.If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_1, - packageName, mangleScopedPackageName(packageName)) - : host.packageBundlesTypes(packageName) - ? chainDiagnosticMessages( - /*details*/ undefined, - Diagnostics.If_the_0_package_actually_exposes_this_module_try_adding_a_new_declaration_d_ts_file_containing_declare_module_1, - packageName, - moduleReference) - : chainDiagnosticMessages( - /*details*/ undefined, - Diagnostics.Try_npm_i_save_dev_types_Slash_1_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, - moduleReference, - mangleScopedPackageName(packageName)); - if (result) result.repopulateInfo = () => ({ moduleReference, mode, packageName: packageName === moduleReference ? undefined : packageName }); + ? chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics + .If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_1, + packageName, + mangleScopedPackageName(packageName), + ) + : host.packageBundlesTypes(packageName) + ? chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics + .If_the_0_package_actually_exposes_this_module_try_adding_a_new_declaration_d_ts_file_containing_declare_module_1, + packageName, + moduleReference, + ) + : chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics + .Try_npm_i_save_dev_types_Slash_1_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, + moduleReference, + mangleScopedPackageName(packageName), + ); + if (result) { + result.repopulateInfo = () => ({ + moduleReference, + mode, + packageName: packageName === moduleReference ? undefined : packageName, + }); + } return result; } @@ -838,14 +896,20 @@ export function packageIdToString(packageId: PackageId): string { } /** @internal */ -export function typeDirectiveIsEqualTo(oldResolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, newResolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations): boolean { - return oldResolution === newResolution || - oldResolution.resolvedTypeReferenceDirective === newResolution.resolvedTypeReferenceDirective || - !!oldResolution.resolvedTypeReferenceDirective && - !!newResolution.resolvedTypeReferenceDirective && - oldResolution.resolvedTypeReferenceDirective.resolvedFileName === newResolution.resolvedTypeReferenceDirective.resolvedFileName && - !!oldResolution.resolvedTypeReferenceDirective.primary === !!newResolution.resolvedTypeReferenceDirective.primary && - oldResolution.resolvedTypeReferenceDirective.originalPath === newResolution.resolvedTypeReferenceDirective.originalPath; +export function typeDirectiveIsEqualTo( + oldResolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, + newResolution: ResolvedTypeReferenceDirectiveWithFailedLookupLocations, +): boolean { + return oldResolution === newResolution + || oldResolution.resolvedTypeReferenceDirective === newResolution.resolvedTypeReferenceDirective + || !!oldResolution.resolvedTypeReferenceDirective + && !!newResolution.resolvedTypeReferenceDirective + && oldResolution.resolvedTypeReferenceDirective.resolvedFileName + === newResolution.resolvedTypeReferenceDirective.resolvedFileName + && !!oldResolution.resolvedTypeReferenceDirective.primary + === !!newResolution.resolvedTypeReferenceDirective.primary + && oldResolution.resolvedTypeReferenceDirective.originalPath + === newResolution.resolvedTypeReferenceDirective.originalPath; } /** @internal */ @@ -865,10 +929,9 @@ export function hasChangesInResolutions( const name = nameAndModeGetter.getName(entry); const mode = nameAndModeGetter.getMode(entry, newSourceFile); const oldResolution = oldResolutions && oldResolutions.get(name, mode); - const changed = - oldResolution - ? !newResolution || !comparer(oldResolution, newResolution) - : newResolution; + const changed = oldResolution + ? !newResolution || !comparer(oldResolution, newResolution) + : newResolution; if (changed) { return true; } @@ -888,8 +951,8 @@ function aggregateChildData(node: Node): void { // A node is considered to contain a parse error if: // a) the parser explicitly marked that it had an error // b) any of it's children reported that it had an error. - const thisNodeOrAnySubNodesHasError = ((node.flags & NodeFlags.ThisNodeHasError) !== 0) || - forEachChild(node, containsParseError); + const thisNodeOrAnySubNodesHasError = ((node.flags & NodeFlags.ThisNodeHasError) !== 0) + || forEachChild(node, containsParseError); // If so, mark ourselves accordingly. if (thisNodeOrAnySubNodesHasError) { @@ -922,7 +985,8 @@ export function getSourceFileOfModule(module: Symbol) { /** @internal */ export function isPlainJsFile(file: SourceFile | undefined, checkJs: boolean | undefined): boolean { - return !!file && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX) && !file.checkJsDirective && checkJs === undefined; + return !!file && (file.scriptKind === ScriptKind.JS || file.scriptKind === ScriptKind.JSX) && !file.checkJsDirective + && checkJs === undefined; } /** @internal */ @@ -986,7 +1050,11 @@ export function getEndLinePosition(line: number, sourceFile: SourceFileLike): nu * * @internal */ -export function isFileLevelUniqueName(sourceFile: SourceFile, name: string, hasGlobalName?: PrintHandlers["hasGlobalName"]): boolean { +export function isFileLevelUniqueName( + sourceFile: SourceFile, + name: string, + hasGlobalName?: PrintHandlers["hasGlobalName"], +): boolean { return !(hasGlobalName && hasGlobalName(name)) && !sourceFile.identifiers.has(name); } @@ -1024,23 +1092,50 @@ export function isGrammarError(parent: Node, child: Node | NodeArray) { if (isTypeParameterDeclaration(parent)) return child === parent.expression; if (isClassStaticBlockDeclaration(parent)) return child === parent.modifiers; if (isPropertySignature(parent)) return child === parent.initializer; - if (isPropertyDeclaration(parent)) return child === parent.questionToken && isAutoAccessorPropertyDeclaration(parent); - if (isPropertyAssignment(parent)) return child === parent.modifiers || child === parent.questionToken || child === parent.exclamationToken || isGrammarErrorElement(parent.modifiers, child, isModifierLike); - if (isShorthandPropertyAssignment(parent)) return child === parent.equalsToken || child === parent.modifiers || child === parent.questionToken || child === parent.exclamationToken || isGrammarErrorElement(parent.modifiers, child, isModifierLike); + if (isPropertyDeclaration(parent)) { + return child === parent.questionToken && isAutoAccessorPropertyDeclaration(parent); + } + if (isPropertyAssignment(parent)) { + return child === parent.modifiers || child === parent.questionToken || child === parent.exclamationToken + || isGrammarErrorElement(parent.modifiers, child, isModifierLike); + } + if (isShorthandPropertyAssignment(parent)) { + return child === parent.equalsToken || child === parent.modifiers || child === parent.questionToken + || child === parent.exclamationToken || isGrammarErrorElement(parent.modifiers, child, isModifierLike); + } if (isMethodDeclaration(parent)) return child === parent.exclamationToken; - if (isConstructorDeclaration(parent)) return child === parent.typeParameters || child === parent.type || isGrammarErrorElement(parent.typeParameters, child, isTypeParameterDeclaration); - if (isGetAccessorDeclaration(parent)) return child === parent.typeParameters || isGrammarErrorElement(parent.typeParameters, child, isTypeParameterDeclaration); - if (isSetAccessorDeclaration(parent)) return child === parent.typeParameters || child === parent.type || isGrammarErrorElement(parent.typeParameters, child, isTypeParameterDeclaration); - if (isNamespaceExportDeclaration(parent)) return child === parent.modifiers || isGrammarErrorElement(parent.modifiers, child, isModifierLike); + if (isConstructorDeclaration(parent)) { + return child === parent.typeParameters || child === parent.type + || isGrammarErrorElement(parent.typeParameters, child, isTypeParameterDeclaration); + } + if (isGetAccessorDeclaration(parent)) { + return child === parent.typeParameters + || isGrammarErrorElement(parent.typeParameters, child, isTypeParameterDeclaration); + } + if (isSetAccessorDeclaration(parent)) { + return child === parent.typeParameters || child === parent.type + || isGrammarErrorElement(parent.typeParameters, child, isTypeParameterDeclaration); + } + if (isNamespaceExportDeclaration(parent)) { + return child === parent.modifiers || isGrammarErrorElement(parent.modifiers, child, isModifierLike); + } return false; } -function isGrammarErrorElement(nodeArray: NodeArray | undefined, child: Node | NodeArray, isElement: (node: Node) => node is T) { +function isGrammarErrorElement( + nodeArray: NodeArray | undefined, + child: Node | NodeArray, + isElement: (node: Node) => node is T, +) { if (!nodeArray || isArray(child) || !isElement(child)) return false; return contains(nodeArray, child); } -function insertStatementsAfterPrologue(to: T[], from: readonly T[] | undefined, isPrologueDirective: (node: Node) => boolean): T[] { +function insertStatementsAfterPrologue( + to: T[], + from: readonly T[] | undefined, + isPrologueDirective: (node: Node) => boolean, +): T[] { if (from === undefined || from.length === 0) return to; let statementIndex = 0; // skip all prologue directives to insert at the correct position @@ -1053,7 +1148,11 @@ function insertStatementsAfterPrologue(to: T[], from: reado return to; } -function insertStatementAfterPrologue(to: T[], statement: T | undefined, isPrologueDirective: (node: Node) => boolean): T[] { +function insertStatementAfterPrologue( + to: T[], + statement: T | undefined, + isPrologueDirective: (node: Node) => boolean, +): T[] { if (statement === undefined) return to; let statementIndex = 0; // skip all prologue directives to insert at the correct position @@ -1066,7 +1165,6 @@ function insertStatementAfterPrologue(to: T[], statement: T return to; } - function isAnyPrologueDirective(node: Node) { return isPrologueDirective(node) || !!(getEmitFlags(node) & EmitFlags.CustomPrologue); } @@ -1076,7 +1174,10 @@ function isAnyPrologueDirective(node: Node) { * * @internal */ -export function insertStatementsAfterStandardPrologue(to: T[], from: readonly T[] | undefined): T[] { +export function insertStatementsAfterStandardPrologue( + to: T[], + from: readonly T[] | undefined, +): T[] { return insertStatementsAfterPrologue(to, from, isPrologueDirective); } @@ -1109,34 +1210,39 @@ export function insertStatementAfterCustomPrologue(to: T[], export function isRecognizedTripleSlashComment(text: string, commentPos: number, commentEnd: number) { // Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text // so that we don't end up computing comment string and doing match for all // comments - if (text.charCodeAt(commentPos + 1) === CharacterCodes.slash && - commentPos + 2 < commentEnd && - text.charCodeAt(commentPos + 2) === CharacterCodes.slash) { + if ( + text.charCodeAt(commentPos + 1) === CharacterCodes.slash + && commentPos + 2 < commentEnd + && text.charCodeAt(commentPos + 2) === CharacterCodes.slash + ) { const textSubStr = text.substring(commentPos, commentEnd); - return fullTripleSlashReferencePathRegEx.test(textSubStr) || - fullTripleSlashAMDReferencePathRegEx.test(textSubStr) || - fullTripleSlashAMDModuleRegEx.test(textSubStr) || - fullTripleSlashReferenceTypeReferenceDirectiveRegEx.test(textSubStr) || - fullTripleSlashLibReferenceRegEx.test(textSubStr) || - defaultLibReferenceRegEx.test(textSubStr) ? - true : false; + return fullTripleSlashReferencePathRegEx.test(textSubStr) + || fullTripleSlashAMDReferencePathRegEx.test(textSubStr) + || fullTripleSlashAMDModuleRegEx.test(textSubStr) + || fullTripleSlashReferenceTypeReferenceDirectiveRegEx.test(textSubStr) + || fullTripleSlashLibReferenceRegEx.test(textSubStr) + || defaultLibReferenceRegEx.test(textSubStr) + ? true : false; } return false; } /** @internal */ export function isPinnedComment(text: string, start: number) { - return text.charCodeAt(start + 1) === CharacterCodes.asterisk && - text.charCodeAt(start + 2) === CharacterCodes.exclamation; + return text.charCodeAt(start + 1) === CharacterCodes.asterisk + && text.charCodeAt(start + 2) === CharacterCodes.exclamation; } /** @internal */ -export function createCommentDirectivesMap(sourceFile: SourceFile, commentDirectives: CommentDirective[]): CommentDirectivesMap { +export function createCommentDirectivesMap( + sourceFile: SourceFile, + commentDirectives: CommentDirective[], +): CommentDirectivesMap { const directivesByLine = new Map( - commentDirectives.map(commentDirective => ([ + commentDirectives.map(commentDirective => [ `${getLineAndCharacterOfPosition(sourceFile, commentDirective.range.end).line}`, commentDirective, - ])) + ]), ); const usedLines = new Map(); @@ -1169,7 +1275,12 @@ 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)) { @@ -1189,12 +1300,14 @@ export function getTokenPosOfNode(node: Node, sourceFile?: SourceFileLike, inclu node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ false, - isInJSDoc(node)); + isInJSDoc(node), + ); } /** @internal */ export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFileLike): number { - const lastDecorator = !nodeIsMissing(node) && canHaveModifiers(node) ? findLast(node.modifiers, isDecorator) : undefined; + const lastDecorator = !nodeIsMissing(node) && canHaveModifiers(node) ? findLast(node.modifiers, isDecorator) + : undefined; if (!lastDecorator) { return getTokenPosOfNode(node, sourceFile); } @@ -1213,7 +1326,8 @@ function isJSDocTypeExpressionOrChild(node: Node): boolean { /** @internal */ export function isExportNamespaceAsDefaultDeclaration(node: Node): boolean { - return !!(isExportDeclaration(node) && node.exportClause && isNamespaceExport(node.exportClause) && node.exportClause.name.escapedText === "default"); + return !!(isExportDeclaration(node) && node.exportClause && isNamespaceExport(node.exportClause) + && node.exportClause.name.escapedText === "default"); } /** @internal */ @@ -1275,7 +1389,6 @@ export function getInternalEmitFlags(node: Node): InternalEmitFlags { /** @internal */ export type ScriptTargetFeatures = ReadonlyMap>; - /** @internal */ export function getScriptTargetFeatures(): ScriptTargetFeatures { return new Map(Object.entries({ @@ -1287,21 +1400,21 @@ export function getScriptTargetFeatures(): ScriptTargetFeatures { "copyWithin", "entries", "keys", - "values" + "values", ], es2016: [ - "includes" + "includes", ], es2019: [ "flat", - "flatMap" + "flatMap", ], es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Iterator: new Map(Object.entries({ @@ -1332,11 +1445,11 @@ export function getScriptTargetFeatures(): ScriptTargetFeatures { es2015: [ "flags", "sticky", - "unicode" + "unicode", ], es2018: [ - "dotAll" - ] + "dotAll", + ], })), Reflect: new Map(Object.entries({ es2015: [ @@ -1352,14 +1465,14 @@ export function getScriptTargetFeatures(): ScriptTargetFeatures { "ownKeys", "preventExtensions", "set", - "setPrototypeOf" - ] + "setPrototypeOf", + ], })), ArrayConstructor: new Map(Object.entries({ es2015: [ "from", - "of" - ] + "of", + ], })), ObjectConstructor: new Map(Object.entries({ es2015: [ @@ -1367,19 +1480,19 @@ export function getScriptTargetFeatures(): ScriptTargetFeatures { "getOwnPropertySymbols", "keys", "is", - "setPrototypeOf" + "setPrototypeOf", ], es2017: [ "values", "entries", - "getOwnPropertyDescriptors" + "getOwnPropertyDescriptors", ], es2019: [ - "fromEntries" + "fromEntries", ], es2022: [ - "hasOwn" - ] + "hasOwn", + ], })), NumberConstructor: new Map(Object.entries({ es2015: [ @@ -1388,8 +1501,8 @@ export function getScriptTargetFeatures(): ScriptTargetFeatures { "isNaN", "isSafeInteger", "parseFloat", - "parseInt" - ] + "parseInt", + ], })), Math: new Map(Object.entries({ es2015: [ @@ -1409,59 +1522,59 @@ export function getScriptTargetFeatures(): ScriptTargetFeatures { "hypot", "trunc", "fround", - "cbrt" - ] + "cbrt", + ], })), Map: new Map(Object.entries({ es2015: [ "entries", "keys", - "values" - ] + "values", + ], })), Set: new Map(Object.entries({ es2015: [ "entries", "keys", - "values" - ] + "values", + ], })), PromiseConstructor: new Map(Object.entries({ es2015: [ "all", "race", "reject", - "resolve" + "resolve", ], es2020: [ - "allSettled" + "allSettled", ], es2021: [ - "any" - ] + "any", + ], })), Symbol: new Map(Object.entries({ es2015: [ "for", - "keyFor" + "keyFor", ], es2019: [ - "description" - ] + "description", + ], })), WeakMap: new Map(Object.entries({ es2015: [ "entries", "keys", - "values" - ] + "values", + ], })), WeakSet: new Map(Object.entries({ es2015: [ "entries", "keys", - "values" - ] + "values", + ], })), String: new Map(Object.entries({ es2015: [ @@ -1483,193 +1596,193 @@ export function getScriptTargetFeatures(): ScriptTargetFeatures { "small", "strike", "sub", - "sup" + "sup", ], es2017: [ "padStart", - "padEnd" + "padEnd", ], es2019: [ "trimStart", "trimEnd", "trimLeft", - "trimRight" + "trimRight", ], es2020: [ - "matchAll" + "matchAll", ], es2021: [ - "replaceAll" + "replaceAll", ], es2022: [ - "at" - ] + "at", + ], })), StringConstructor: new Map(Object.entries({ es2015: [ "fromCodePoint", - "raw" - ] + "raw", + ], })), DateTimeFormat: new Map(Object.entries({ es2017: [ - "formatToParts" - ] + "formatToParts", + ], })), Promise: new Map(Object.entries({ es2015: emptyArray, es2018: [ - "finally" - ] + "finally", + ], })), RegExpMatchArray: new Map(Object.entries({ es2018: [ - "groups" - ] + "groups", + ], })), RegExpExecArray: new Map(Object.entries({ es2018: [ - "groups" - ] + "groups", + ], })), Intl: new Map(Object.entries({ es2018: [ - "PluralRules" - ] + "PluralRules", + ], })), NumberFormat: new Map(Object.entries({ es2018: [ - "formatToParts" - ] + "formatToParts", + ], })), SymbolConstructor: new Map(Object.entries({ es2020: [ - "matchAll" - ] + "matchAll", + ], })), DataView: new Map(Object.entries({ es2020: [ "setBigInt64", "setBigUint64", "getBigInt64", - "getBigUint64" - ] + "getBigUint64", + ], })), BigInt: new Map(Object.entries({ - es2020: emptyArray + es2020: emptyArray, })), RelativeTimeFormat: new Map(Object.entries({ es2020: [ "format", "formatToParts", - "resolvedOptions" - ] + "resolvedOptions", + ], })), Int8Array: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Uint8Array: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Uint8ClampedArray: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Int16Array: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Uint16Array: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Int32Array: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Uint32Array: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Float32Array: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Float64Array: new Map(Object.entries({ es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), BigInt64Array: new Map(Object.entries({ es2020: emptyArray, es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), BigUint64Array: new Map(Object.entries({ es2020: emptyArray, es2022: [ - "at" + "at", ], es2023: [ "findLastIndex", - "findLast" + "findLast", ], })), Error: new Map(Object.entries({ es2022: [ - "cause" - ] + "cause", + ], })), })); } @@ -1680,7 +1793,7 @@ export const enum GetLiteralTextFlags { NeverAsciiEscape = 1 << 0, JsxAttributeEscape = 1 << 1, TerminateUnterminatedLiterals = 1 << 2, - AllowNumericSeparator = 1 << 3 + AllowNumericSeparator = 1 << 3, } /** @internal */ @@ -1695,9 +1808,10 @@ export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile | u // or a (possibly escaped) quoted form of the original text if it's string-like. switch (node.kind) { case SyntaxKind.StringLiteral: { - const escapeText = flags & GetLiteralTextFlags.JsxAttributeEscape ? escapeJsxAttributeString : - flags & GetLiteralTextFlags.NeverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : - escapeNonAsciiString; + const escapeText = flags & GetLiteralTextFlags.JsxAttributeEscape ? escapeJsxAttributeString + : flags & GetLiteralTextFlags.NeverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) + ? escapeString + : escapeNonAsciiString; if ((node as StringLiteral).singleQuote) { return "'" + escapeText(node.text, CharacterCodes.singleQuote) + "'"; } @@ -1711,10 +1825,13 @@ export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile | u case SyntaxKind.TemplateTail: { // If a NoSubstitutionTemplateLiteral appears to have a substitution in it, the original text // had to include a backslash: `not \${a} substitution`. - const escapeText = flags & GetLiteralTextFlags.NeverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : - escapeNonAsciiString; + const escapeText = + flags & GetLiteralTextFlags.NeverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) + ? escapeString + : escapeNonAsciiString; - const rawText = (node as TemplateLiteralLikeNode).rawText ?? escapeTemplateSubstitution(escapeText(node.text, CharacterCodes.backtick)); + const rawText = (node as TemplateLiteralLikeNode).rawText + ?? escapeTemplateSubstitution(escapeText(node.text, CharacterCodes.backtick)); switch (node.kind) { case SyntaxKind.NoSubstitutionTemplateLiteral: return "`" + rawText + "`"; @@ -1732,7 +1849,8 @@ export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile | u return node.text; case SyntaxKind.RegularExpressionLiteral: if (flags & GetLiteralTextFlags.TerminateUnterminatedLiterals && node.isUnterminated) { - return node.text + (node.text.charCodeAt(node.text.length - 1) === CharacterCodes.backslash ? " /" : "/"); + return node.text + + (node.text.charCodeAt(node.text.length - 1) === CharacterCodes.backslash ? " /" : "/"); } return node.text; } @@ -1741,7 +1859,10 @@ export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile | u } function canUseOriginalText(node: LiteralLikeNode, flags: GetLiteralTextFlags): boolean { - if (nodeIsSynthesized(node) || !node.parent || (flags & GetLiteralTextFlags.TerminateUnterminatedLiterals && node.isUnterminated)) { + if ( + nodeIsSynthesized(node) || !node.parent + || (flags & GetLiteralTextFlags.TerminateUnterminatedLiterals && node.isUnterminated) + ) { return false; } @@ -1771,8 +1892,8 @@ export function makeIdentifierFromModuleName(moduleName: string): string { /** @internal */ export function isBlockOrCatchScoped(declaration: Declaration) { - return (getCombinedNodeFlags(declaration) & NodeFlags.BlockScoped) !== 0 || - isCatchClauseVariableDeclarationOrBindingElement(declaration); + return (getCombinedNodeFlags(declaration) & NodeFlags.BlockScoped) !== 0 + || isCatchClauseVariableDeclarationOrBindingElement(declaration); } /** @internal */ @@ -1783,7 +1904,8 @@ export function isCatchClauseVariableDeclarationOrBindingElement(declaration: De /** @internal */ export function isAmbientModule(node: Node): node is AmbientModuleDeclaration { - return isModuleDeclaration(node) && (node.name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)); + return isModuleDeclaration(node) + && (node.name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)); } /** @internal */ @@ -1792,7 +1914,7 @@ export function isModuleWithStringLiteralName(node: Node): node is ModuleDeclara } /** @internal */ -export function isNonGlobalAmbientModule(node: Node): node is ModuleDeclaration & { name: StringLiteral } { +export function isNonGlobalAmbientModule(node: Node): node is ModuleDeclaration & { name: StringLiteral; } { return isModuleDeclaration(node) && isStringLiteral(node.name); } @@ -1824,9 +1946,9 @@ function isShorthandAmbientModule(node: Node | undefined): boolean { /** @internal */ export function isBlockScopedContainerTopLevel(node: Node): boolean { - return node.kind === SyntaxKind.SourceFile || - node.kind === SyntaxKind.ModuleDeclaration || - isFunctionLikeOrClassStaticBlockDeclaration(node); + return node.kind === SyntaxKind.SourceFile + || node.kind === SyntaxKind.ModuleDeclaration + || isFunctionLikeOrClassStaticBlockDeclaration(node); } /** @internal */ @@ -1848,14 +1970,17 @@ export function isModuleAugmentationExternal(node: AmbientModuleDeclaration) { case SyntaxKind.SourceFile: return isExternalModule(node.parent); case SyntaxKind.ModuleBlock: - return isAmbientModule(node.parent.parent) && isSourceFile(node.parent.parent.parent) && !isExternalModule(node.parent.parent.parent); + return isAmbientModule(node.parent.parent) && isSourceFile(node.parent.parent.parent) + && !isExternalModule(node.parent.parent.parent); } return false; } /** @internal */ export function getNonAugmentationDeclaration(symbol: Symbol) { - return symbol.declarations?.find(d => !isExternalModuleAugmentation(d) && !(isModuleDeclaration(d) && isGlobalScopeAugmentation(d))); + return symbol.declarations?.find(d => + !isExternalModuleAugmentation(d) && !(isModuleDeclaration(d) && isGlobalScopeAugmentation(d)) + ); } function isCommonJSContainingModuleKind(kind: ModuleKind) { @@ -1864,7 +1989,8 @@ function isCommonJSContainingModuleKind(kind: ModuleKind) { /** @internal */ export function isEffectiveExternalModule(node: SourceFile, compilerOptions: CompilerOptions) { - return isExternalModule(node) || (isCommonJSContainingModuleKind(getEmitModuleKind(compilerOptions)) && !!node.commonJsModuleIndicator); + return isExternalModule(node) + || (isCommonJSContainingModuleKind(getEmitModuleKind(compilerOptions)) && !!node.commonJsModuleIndicator); } /** @@ -2020,7 +2146,9 @@ export function isLateVisibilityPaintedStatement(node: Node): node is LateVisibi } /** @internal */ -export function hasPossibleExternalModuleReference(node: Node): node is AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall { +export function hasPossibleExternalModuleReference( + node: Node, +): node is AnyImportOrReExport | ModuleDeclaration | ImportTypeNode | ImportCall { return isAnyImportOrReExport(node) || isModuleDeclaration(node) || isImportTypeNode(node) || isImportCall(node); } @@ -2069,7 +2197,9 @@ export function isComputedNonLiteralName(name: PropertyName): boolean { } /** @internal */ -export function tryGetTextOfPropertyName(name: PropertyName | NoSubstitutionTemplateLiteral | JsxAttributeName): __String | undefined { +export function tryGetTextOfPropertyName( + name: PropertyName | NoSubstitutionTemplateLiteral | JsxAttributeName, +): __String | undefined { switch (name.kind) { case SyntaxKind.Identifier: case SyntaxKind.PrivateIdentifier: @@ -2094,7 +2224,9 @@ export function getTextOfPropertyName(name: PropertyName | NoSubstitutionTemplat } /** @internal */ -export function entityNameToString(name: EntityNameOrEntityNameExpression | JSDocMemberName | JsxTagNameExpression | PrivateIdentifier): string { +export function entityNameToString( + name: EntityNameOrEntityNameExpression | JSDocMemberName | JsxTagNameExpression | PrivateIdentifier, +): string { switch (name.kind) { case SyntaxKind.ThisKeyword: return "this"; @@ -2120,31 +2252,55 @@ export function entityNameToString(name: EntityNameOrEntityNameExpression | JSDo } /** @internal */ -export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { +export function createDiagnosticForNode( + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments +): DiagnosticWithLocation { const sourceFile = getSourceFileOfNode(node); return createDiagnosticForNodeInSourceFile(sourceFile, node, message, ...args); } /** @internal */ -export function createDiagnosticForNodeArray(sourceFile: SourceFile, nodes: NodeArray, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { +export function createDiagnosticForNodeArray( + sourceFile: SourceFile, + nodes: NodeArray, + message: DiagnosticMessage, + ...args: DiagnosticArguments +): DiagnosticWithLocation { const start = skipTrivia(sourceFile.text, nodes.pos); return createFileDiagnostic(sourceFile, start, nodes.end - start, message, ...args); } /** @internal */ -export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { +export function createDiagnosticForNodeInSourceFile( + sourceFile: SourceFile, + node: Node, + message: DiagnosticMessage, + ...args: DiagnosticArguments +): DiagnosticWithLocation { const span = getErrorSpanForNode(sourceFile, node); return createFileDiagnostic(sourceFile, span.start, span.length, message, ...args); } /** @internal */ -export function createDiagnosticForNodeFromMessageChain(sourceFile: SourceFile, node: Node, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { +export function createDiagnosticForNodeFromMessageChain( + sourceFile: SourceFile, + node: Node, + messageChain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], +): DiagnosticWithLocation { const span = getErrorSpanForNode(sourceFile, node); return createFileDiagnosticFromMessageChain(sourceFile, span.start, span.length, messageChain, relatedInformation); } /** @internal */ -export function createDiagnosticForNodeArrayFromMessageChain(sourceFile: SourceFile, nodes: NodeArray, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { +export function createDiagnosticForNodeArrayFromMessageChain( + sourceFile: SourceFile, + nodes: NodeArray, + messageChain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], +): DiagnosticWithLocation { const start = skipTrivia(sourceFile.text, nodes.pos); return createFileDiagnosticFromMessageChain(sourceFile, start, nodes.end - start, messageChain, relatedInformation); } @@ -2157,7 +2313,13 @@ function assertDiagnosticLocation(sourceText: string, start: number, length: num } /** @internal */ -export function createFileDiagnosticFromMessageChain(file: SourceFile, start: number, length: number, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { +export function createFileDiagnosticFromMessageChain( + file: SourceFile, + start: number, + length: number, + messageChain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], +): DiagnosticWithLocation { assertDiagnosticLocation(file.text, start, length); return { file, @@ -2166,12 +2328,16 @@ export function createFileDiagnosticFromMessageChain(file: SourceFile, start: nu code: messageChain.code, category: messageChain.category, messageText: messageChain.next ? messageChain : messageChain.messageText, - relatedInformation + relatedInformation, }; } /** @internal */ -export function createDiagnosticForFileFromMessageChain(sourceFile: SourceFile, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { +export function createDiagnosticForFileFromMessageChain( + sourceFile: SourceFile, + messageChain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], +): DiagnosticWithLocation { return { file: sourceFile, start: 0, @@ -2179,12 +2345,14 @@ export function createDiagnosticForFileFromMessageChain(sourceFile: SourceFile, code: messageChain.code, category: messageChain.category, messageText: messageChain.next ? messageChain : messageChain.messageText, - relatedInformation + relatedInformation, }; } /** @internal */ -export function createDiagnosticMessageChainFromDiagnostic(diagnostic: DiagnosticRelatedInformation): DiagnosticMessageChain { +export function createDiagnosticMessageChainFromDiagnostic( + diagnostic: DiagnosticRelatedInformation, +): DiagnosticMessageChain { return typeof diagnostic.messageText === "string" ? { code: diagnostic.code, category: diagnostic.category, @@ -2194,7 +2362,11 @@ export function createDiagnosticMessageChainFromDiagnostic(diagnostic: Diagnosti } /** @internal */ -export function createDiagnosticForRange(sourceFile: SourceFile, range: TextRange, message: DiagnosticMessage): DiagnosticWithLocation { +export function createDiagnosticForRange( + sourceFile: SourceFile, + range: TextRange, + message: DiagnosticMessage, +): DiagnosticWithLocation { return { file: sourceFile, start: range.pos, @@ -2207,7 +2379,14 @@ export function createDiagnosticForRange(sourceFile: SourceFile, range: TextRang /** @internal */ export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): TextSpan { - const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.languageVariant, sourceFile.text, /*onError*/ undefined, pos); + const scanner = createScanner( + sourceFile.languageVersion, + /*skipTrivia*/ true, + sourceFile.languageVariant, + sourceFile.text, + /*onError*/ undefined, + pos, + ); scanner.scan(); const start = scanner.getTokenStart(); return createTextSpanFromBounds(start, scanner.getTokenEnd()); @@ -2215,7 +2394,14 @@ export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): T /** @internal */ export function scanTokenAtPosition(sourceFile: SourceFile, pos: number) { - const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.languageVariant, sourceFile.text, /*onError*/ undefined, pos); + const scanner = createScanner( + sourceFile.languageVersion, + /*skipTrivia*/ true, + sourceFile.languageVariant, + sourceFile.text, + /*onError*/ undefined, + pos, + ); scanner.scan(); return scanner.getToken(); } @@ -2272,7 +2458,8 @@ export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpa case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: { const start = skipTrivia(sourceFile.text, (node as CaseOrDefaultClause).pos); - const end = (node as CaseOrDefaultClause).statements.length > 0 ? (node as CaseOrDefaultClause).statements[0].pos : (node as CaseOrDefaultClause).end; + const end = (node as CaseOrDefaultClause).statements.length > 0 + ? (node as CaseOrDefaultClause).statements[0].pos : (node as CaseOrDefaultClause).end; return createTextSpanFromBounds(start, end); } case SyntaxKind.ReturnStatement: @@ -2305,12 +2492,24 @@ export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpa // These asserts should all be satisfied for a properly constructed `errorNode`. if (isMissing) { - Debug.assert(pos === errorNode.pos, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); - Debug.assert(pos === errorNode.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); + Debug.assert( + pos === errorNode.pos, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809", + ); + Debug.assert( + pos === errorNode.end, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809", + ); } else { - Debug.assert(pos >= errorNode.pos, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); - Debug.assert(pos <= errorNode.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809"); + Debug.assert( + pos >= errorNode.pos, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809", + ); + Debug.assert( + pos <= errorNode.end, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809", + ); } return createTextSpanFromBounds(pos, errorNode.end); @@ -2321,7 +2520,6 @@ export function isExternalOrCommonJsModule(file: SourceFile): boolean { return (file.externalModuleIndicator || file.commonJsModuleIndicator) !== undefined; } - /** @internal */ export function isJsonSourceFile(file: SourceFile): file is JsonSourceFile { return file.scriptKind === ScriptKind.JSON; @@ -2334,7 +2532,8 @@ export function isEnumConst(node: EnumDeclaration): boolean { /** @internal */ export function isDeclarationReadonly(declaration: Declaration): boolean { - return !!(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration, declaration.parent)); + return !!(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly + && !isParameterPropertyDeclaration(declaration, declaration.parent)); } /** @@ -2427,28 +2626,30 @@ export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode: Sour /** @internal */ export function getJSDocCommentRanges(node: Node, text: string) { - const commentRanges = (node.kind === SyntaxKind.Parameter || - node.kind === SyntaxKind.TypeParameter || - node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.ArrowFunction || - node.kind === SyntaxKind.ParenthesizedExpression || - node.kind === SyntaxKind.VariableDeclaration || - node.kind === SyntaxKind.ExportSpecifier) ? - concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) : - getLeadingCommentRanges(text, node.pos); + const commentRanges = (node.kind === SyntaxKind.Parameter + || node.kind === SyntaxKind.TypeParameter + || node.kind === SyntaxKind.FunctionExpression + || node.kind === SyntaxKind.ArrowFunction + || node.kind === SyntaxKind.ParenthesizedExpression + || node.kind === SyntaxKind.VariableDeclaration + || node.kind === SyntaxKind.ExportSpecifier) + ? concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) + : getLeadingCommentRanges(text, node.pos); // True if the comment starts with '/**' but not if it is '/**/' return filter(commentRanges, comment => - text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk && - text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk && - text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash); + text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk + && text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk + && text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash); } /** @internal */ export const fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*/; -const fullTripleSlashReferenceTypeReferenceDirectiveRegEx = /^(\/\/\/\s*/; +const fullTripleSlashReferenceTypeReferenceDirectiveRegEx = + /^(\/\/\/\s*/; const fullTripleSlashLibReferenceRegEx = /^(\/\/\/\s*/; /** @internal */ -export const fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*/; +export const fullTripleSlashAMDReferencePathRegEx = + /^(\/\/\/\s*/; const fullTripleSlashAMDModuleRegEx = /^\/\/\/\s*/; const defaultLibReferenceRegEx = /^(\/\/\/\s*/; @@ -2485,12 +2686,18 @@ export function isPartOfTypeNode(node: Node): boolean { if (node.parent.kind === SyntaxKind.QualifiedName && (node.parent as QualifiedName).right === node) { node = node.parent; } - else if (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent as PropertyAccessExpression).name === node) { + else if ( + node.parent.kind === SyntaxKind.PropertyAccessExpression + && (node.parent as PropertyAccessExpression).name === node + ) { node = node.parent; } // At this point, node is either a qualified name or an identifier - Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression, - "'node' was expected to be a qualified name, identifier or property access in 'isPartOfTypeNode'."); + Debug.assert( + node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName + || node.kind === SyntaxKind.PropertyAccessExpression, + "'node' was expected to be a qualified name, identifier or property access in 'isPartOfTypeNode'.", + ); // falls through case SyntaxKind.QualifiedName: @@ -2514,7 +2721,8 @@ export function isPartOfTypeNode(node: Node): boolean { } switch (parent.kind) { case SyntaxKind.ExpressionWithTypeArguments: - return isHeritageClause(parent.parent) && !isExpressionWithTypeArgumentsInClassExtendsClause(parent); + return isHeritageClause(parent.parent) + && !isExpressionWithTypeArgumentsInClassExtendsClause(parent); case SyntaxKind.TypeParameter: return node === (parent as TypeParameterDeclaration).constraint; case SyntaxKind.JSDocTemplateTag: @@ -2564,8 +2772,10 @@ export function isChildOfNodeWithKind(node: Node, kind: SyntaxKind): boolean { // 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 */ -export function forEachReturnStatement(body: Block | Statement, visitor: (stmt: ReturnStatement) => T): T | undefined { - +export function forEachReturnStatement( + body: Block | Statement, + visitor: (stmt: ReturnStatement) => T, +): T | undefined { return traverse(body); function traverse(node: Node): T | undefined { @@ -2594,7 +2804,6 @@ export function forEachReturnStatement(body: Block | Statement, visitor: (stm /** @internal */ export function forEachYieldExpression(body: Block, visitor: (expr: YieldExpression) => void): void { - return traverse(body); function traverse(node: Node): void { @@ -2652,7 +2861,9 @@ export function getRestParameterElementType(node: TypeNode | undefined) { } /** @internal */ -export function getMembersOfDeclaration(node: Declaration): NodeArray | undefined { +export function getMembersOfDeclaration( + node: Declaration, +): NodeArray | undefined { switch (node.kind) { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.ClassDeclaration: @@ -2696,21 +2907,24 @@ export function isVariableDeclarationInVariableStatement(node: VariableDeclarati /** @internal */ export function isCommonJsExportedExpression(node: Node) { if (!isInJSFile(node)) return false; - return (isObjectLiteralExpression(node.parent) && isBinaryExpression(node.parent.parent) && getAssignmentDeclarationKind(node.parent.parent) === AssignmentDeclarationKind.ModuleExports) || - isCommonJsExportPropertyAssignment(node.parent); + return (isObjectLiteralExpression(node.parent) && isBinaryExpression(node.parent.parent) + && getAssignmentDeclarationKind(node.parent.parent) === AssignmentDeclarationKind.ModuleExports) + || isCommonJsExportPropertyAssignment(node.parent); } /** @internal */ export function isCommonJsExportPropertyAssignment(node: Node) { if (!isInJSFile(node)) return false; - return (isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ExportsProperty); + return (isBinaryExpression(node) + && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ExportsProperty); } /** @internal */ export function isValidESSymbolDeclaration(node: Node): boolean { - return (isVariableDeclaration(node) ? isVarConst(node) && isIdentifier(node.name) && isVariableDeclarationInVariableStatement(node) : - isPropertyDeclaration(node) ? hasEffectiveReadonlyModifier(node) && hasStaticModifier(node) : - isPropertySignature(node) && hasEffectiveReadonlyModifier(node)) || isCommonJsExportPropertyAssignment(node); + return (isVariableDeclaration(node) + ? isVarConst(node) && isIdentifier(node.name) && isVariableDeclarationInVariableStatement(node) + : isPropertyDeclaration(node) ? hasEffectiveReadonlyModifier(node) && hasStaticModifier(node) + : isPropertySignature(node) && hasEffectiveReadonlyModifier(node)) || isCommonJsExportPropertyAssignment(node); } /** @internal */ @@ -2729,7 +2943,10 @@ export function introducesArgumentsExoticObject(node: Node) { } /** @internal */ -export function unwrapInnermostStatementOfLabel(node: LabeledStatement, beforeUnwrapLabelCallback?: (node: LabeledStatement) => void): Statement { +export function unwrapInnermostStatementOfLabel( + node: LabeledStatement, + beforeUnwrapLabelCallback?: (node: LabeledStatement) => void, +): Statement { while (true) { if (beforeUnwrapLabelCallback) { beforeUnwrapLabelCallback(node); @@ -2748,14 +2965,18 @@ export function isFunctionBlock(node: Node): boolean { /** @internal */ export function isObjectLiteralMethod(node: Node): node is MethodDeclaration { - return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression; + return node && node.kind === SyntaxKind.MethodDeclaration + && node.parent.kind === SyntaxKind.ObjectLiteralExpression; } /** @internal */ -export function isObjectLiteralOrClassExpressionMethodOrAccessor(node: Node): node is MethodDeclaration | AccessorDeclaration { - return (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) && - (node.parent.kind === SyntaxKind.ObjectLiteralExpression || - node.parent.kind === SyntaxKind.ClassExpression); +export function isObjectLiteralOrClassExpressionMethodOrAccessor( + node: Node, +): node is MethodDeclaration | AccessorDeclaration { + return (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.GetAccessor + || node.kind === SyntaxKind.SetAccessor) + && (node.parent.kind === SyntaxKind.ObjectLiteralExpression + || node.parent.kind === SyntaxKind.ClassExpression); } /** @internal */ @@ -2769,27 +2990,38 @@ export function isThisTypePredicate(predicate: TypePredicate): predicate is This } /** @internal */ -export function forEachPropertyAssignment(objectLiteral: ObjectLiteralExpression | undefined, key: string, callback: (property: PropertyAssignment) => T | undefined, key2?: string) { +export function forEachPropertyAssignment( + objectLiteral: ObjectLiteralExpression | undefined, + key: string, + callback: (property: PropertyAssignment) => T | undefined, + key2?: string, +) { return forEach(objectLiteral?.properties, property => { if (!isPropertyAssignment(property)) return undefined; const propName = tryGetTextOfPropertyName(property.name); - return key === propName || (key2 && key2 === propName) ? - callback(property) : - undefined; + return key === propName || (key2 && key2 === propName) + ? callback(property) + : undefined; }); } /** @internal */ -export function getPropertyArrayElementValue(objectLiteral: ObjectLiteralExpression, propKey: string, elementValue: string): StringLiteral | undefined { +export function getPropertyArrayElementValue( + objectLiteral: ObjectLiteralExpression, + propKey: string, + elementValue: string, +): StringLiteral | undefined { return forEachPropertyAssignment(objectLiteral, propKey, property => - isArrayLiteralExpression(property.initializer) ? - find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) : - undefined - ); + isArrayLiteralExpression(property.initializer) + ? find(property.initializer.elements, (element): element is StringLiteral => + isStringLiteral(element) && element.text === elementValue) + : undefined); } /** @internal */ -export function getTsConfigObjectLiteralExpression(tsConfigSourceFile: TsConfigSourceFile | undefined): ObjectLiteralExpression | undefined { +export function getTsConfigObjectLiteralExpression( + tsConfigSourceFile: TsConfigSourceFile | undefined, +): ObjectLiteralExpression | undefined { if (tsConfigSourceFile && tsConfigSourceFile.statements.length) { const expression = tsConfigSourceFile.statements[0].expression; return tryCast(expression, isObjectLiteralExpression); @@ -2797,15 +3029,30 @@ export function getTsConfigObjectLiteralExpression(tsConfigSourceFile: TsConfigS } /** @internal */ -export function getTsConfigPropArrayElementValue(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string, elementValue: string): StringLiteral | undefined { - return forEachTsConfigPropArray(tsConfigSourceFile, propKey, property => - isArrayLiteralExpression(property.initializer) ? - find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) : - undefined); +export function getTsConfigPropArrayElementValue( + tsConfigSourceFile: TsConfigSourceFile | undefined, + propKey: string, + elementValue: string, +): StringLiteral | undefined { + return forEachTsConfigPropArray( + tsConfigSourceFile, + propKey, + property => + isArrayLiteralExpression(property.initializer) + ? find( + property.initializer.elements, + (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue, + ) + : undefined, + ); } /** @internal */ -export function forEachTsConfigPropArray(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string, callback: (property: PropertyAssignment) => T | undefined) { +export function forEachTsConfigPropArray( + tsConfigSourceFile: TsConfigSourceFile | undefined, + propKey: string, + callback: (property: PropertyAssignment) => T | undefined, +) { return forEachPropertyAssignment(getTsConfigObjectLiteralExpression(tsConfigSourceFile), propKey, callback); } @@ -2835,14 +3082,17 @@ export function getContainingClassStaticBlock(node: Node): Node | undefined { } /** @internal */ -export function getContainingFunctionOrClassStaticBlock(node: Node): SignatureDeclaration | ClassStaticBlockDeclaration | undefined { +export function getContainingFunctionOrClassStaticBlock( + node: Node, +): SignatureDeclaration | ClassStaticBlockDeclaration | undefined { return findAncestor(node.parent, isFunctionLikeOrClassStaticBlockDeclaration); } /** @internal */ export function getContainingClassExcludingClassDecorators(node: Node): ClassLikeDeclaration | undefined { const decorator = findAncestor(node.parent, n => isClassLike(n) ? "quit" : isDecorator(n)); - return decorator && isClassLike(decorator.parent) ? getContainingClass(decorator.parent) : getContainingClass(decorator ?? node); + return decorator && isClassLike(decorator.parent) ? getContainingClass(decorator.parent) + : getContainingClass(decorator ?? node); } /** @internal */ @@ -2862,18 +3112,37 @@ export type ThisContainer = | ConstructSignatureDeclaration | IndexSignatureDeclaration | EnumDeclaration - | SourceFile - ; - -/** @internal */ -export function getThisContainer(node: Node, includeArrowFunctions: false, includeClassComputedPropertyName: false): ThisContainer; -/** @internal */ -export function getThisContainer(node: Node, includeArrowFunctions: false, includeClassComputedPropertyName: boolean): ThisContainer | ComputedPropertyName; -/** @internal */ -export function getThisContainer(node: Node, includeArrowFunctions: boolean, includeClassComputedPropertyName: false): ThisContainer | ArrowFunction; -/** @internal */ -export function getThisContainer(node: Node, includeArrowFunctions: boolean, includeClassComputedPropertyName: boolean): ThisContainer | ArrowFunction | ComputedPropertyName; -export function getThisContainer(node: Node, includeArrowFunctions: boolean, includeClassComputedPropertyName: boolean) { + | SourceFile; + +/** @internal */ +export function getThisContainer( + node: Node, + includeArrowFunctions: false, + includeClassComputedPropertyName: false, +): ThisContainer; +/** @internal */ +export function getThisContainer( + node: Node, + includeArrowFunctions: false, + includeClassComputedPropertyName: boolean, +): ThisContainer | ComputedPropertyName; +/** @internal */ +export function getThisContainer( + node: Node, + includeArrowFunctions: boolean, + includeClassComputedPropertyName: false, +): ThisContainer | ArrowFunction; +/** @internal */ +export function getThisContainer( + node: Node, + includeArrowFunctions: boolean, + includeClassComputedPropertyName: boolean, +): ThisContainer | ArrowFunction | ComputedPropertyName; +export function getThisContainer( + node: Node, + includeArrowFunctions: boolean, + includeClassComputedPropertyName: boolean, +) { Debug.assert(node.kind !== SyntaxKind.SourceFile); while (true) { node = node.parent; @@ -2969,16 +3238,27 @@ export function isThisContainerOrFunctionBlock(node: Node): boolean { /** @internal */ export function isInTopLevelContext(node: Node) { // The name of a class or function declaration is a BindingIdentifier in its surrounding scope. - if (isIdentifier(node) && (isClassDeclaration(node.parent) || isFunctionDeclaration(node.parent)) && node.parent.name === node) { + if ( + isIdentifier(node) && (isClassDeclaration(node.parent) || isFunctionDeclaration(node.parent)) + && node.parent.name === node + ) { node = node.parent; } - const container = getThisContainer(node, /*includeArrowFunctions*/ true, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ true, + /*includeClassComputedPropertyName*/ false, + ); return isSourceFile(container); } /** @internal */ export function getNewTargetContainer(node: Node) { - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); if (container) { switch (container.kind) { case SyntaxKind.Constructor: @@ -3000,16 +3280,14 @@ export type SuperContainer = | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration - | ClassStaticBlockDeclaration - ; + | ClassStaticBlockDeclaration; /** @internal */ export type SuperContainerOrFunctions = | SuperContainer | FunctionDeclaration | FunctionExpression - | ArrowFunction - ; + | ArrowFunction; /** * Given an super call/property node, returns the closest node where @@ -3167,7 +3445,12 @@ export function nodeCanBeDecorated(useLegacyDecorators: boolean, node: ClassElem /** @internal */ export function nodeCanBeDecorated(useLegacyDecorators: boolean, node: Node, parent: Node, grandparent: Node): boolean; /** @internal */ -export function nodeCanBeDecorated(useLegacyDecorators: boolean, node: Node, parent?: Node, grandparent?: Node): boolean { +export function nodeCanBeDecorated( + useLegacyDecorators: boolean, + node: Node, + parent?: Node, + grandparent?: Node, +): boolean { // private names cannot be used with decorators yet if (useLegacyDecorators && isNamedDeclaration(node) && isPrivateIdentifier(node.name)) { return false; @@ -3185,7 +3468,8 @@ export function nodeCanBeDecorated(useLegacyDecorators: boolean, node: Node, par case SyntaxKind.PropertyDeclaration: // property declarations are valid if their parent is a class declaration. return parent !== undefined - && (useLegacyDecorators ? isClassDeclaration(parent) : isClassLike(parent) && !hasAbstractModifier(node) && !hasAmbientModifier(node)); + && (useLegacyDecorators ? isClassDeclaration(parent) + : isClassLike(parent) && !hasAbstractModifier(node) && !hasAmbientModifier(node)); case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -3205,8 +3489,8 @@ export function nodeCanBeDecorated(useLegacyDecorators: boolean, node: Node, par || parent.kind === SyntaxKind.MethodDeclaration || parent.kind === SyntaxKind.SetAccessor) && getThisParameter(parent as FunctionLikeDeclaration) !== node - && grandparent !== undefined - && grandparent.kind === SyntaxKind.ClassDeclaration; + && grandparent !== undefined + && grandparent.kind === SyntaxKind.ClassDeclaration; } return false; @@ -3229,9 +3513,19 @@ export function nodeOrChildIsDecorated(useLegacyDecorators: boolean, node: Class /** @internal */ export function nodeOrChildIsDecorated(useLegacyDecorators: boolean, node: ClassElement, parent: Node): boolean; /** @internal */ -export function nodeOrChildIsDecorated(useLegacyDecorators: boolean, node: Node, parent: Node, grandparent: Node): boolean; -/** @internal */ -export function nodeOrChildIsDecorated(useLegacyDecorators: boolean, node: Node, parent?: Node, grandparent?: Node): boolean { +export function nodeOrChildIsDecorated( + useLegacyDecorators: boolean, + node: Node, + parent: Node, + grandparent: Node, +): boolean; +/** @internal */ +export function nodeOrChildIsDecorated( + useLegacyDecorators: boolean, + node: Node, + parent?: Node, + grandparent?: Node, +): boolean { return nodeIsDecorated(useLegacyDecorators, node, parent!, grandparent!) || childIsDecorated(useLegacyDecorators, node, parent!); } @@ -3244,34 +3538,50 @@ export function childIsDecorated(useLegacyDecorators: boolean, node: Node, paren export function childIsDecorated(useLegacyDecorators: boolean, node: Node, parent?: Node): boolean { switch (node.kind) { case SyntaxKind.ClassDeclaration: - return some((node as ClassDeclaration).members, m => nodeOrChildIsDecorated(useLegacyDecorators, m, node, parent!)); - case SyntaxKind.ClassExpression: - return !useLegacyDecorators && some((node as ClassExpression).members, m => nodeOrChildIsDecorated(useLegacyDecorators, m, node, parent!)); + return some( + (node as ClassDeclaration).members, + m => nodeOrChildIsDecorated(useLegacyDecorators, m, node, parent!), + ); + case SyntaxKind.ClassExpression: + return !useLegacyDecorators + && some( + (node as ClassExpression).members, + m => nodeOrChildIsDecorated(useLegacyDecorators, m, node, parent!), + ); case SyntaxKind.MethodDeclaration: case SyntaxKind.SetAccessor: case SyntaxKind.Constructor: - return some((node as FunctionLikeDeclaration).parameters, p => nodeIsDecorated(useLegacyDecorators, p, node, parent!)); + return some( + (node as FunctionLikeDeclaration).parameters, + p => nodeIsDecorated(useLegacyDecorators, p, node, parent!), + ); default: return false; } } /** @internal */ -export function classOrConstructorParameterIsDecorated(useLegacyDecorators: boolean, node: ClassDeclaration | ClassExpression): boolean { +export function classOrConstructorParameterIsDecorated( + useLegacyDecorators: boolean, + node: ClassDeclaration | ClassExpression, +): boolean { if (nodeIsDecorated(useLegacyDecorators, node)) return true; const constructor = getFirstConstructorWithBody(node); return !!constructor && childIsDecorated(useLegacyDecorators, constructor, node); } /** @internal */ -export function classElementOrClassElementParameterIsDecorated(useLegacyDecorators: boolean, node: ClassElement, parent: ClassDeclaration | ClassExpression): boolean { +export function classElementOrClassElementParameterIsDecorated( + useLegacyDecorators: boolean, + node: ClassElement, + parent: ClassDeclaration | ClassExpression, +): boolean { let parameters: NodeArray | undefined; if (isAccessor(node)) { const { firstAccessor, secondAccessor, setAccessor } = getAllAccessorDeclarations(parent.members, node); - const firstAccessorWithDecorators = - hasDecorators(firstAccessor) ? firstAccessor : - secondAccessor && hasDecorators(secondAccessor) ? secondAccessor : - undefined; + const firstAccessorWithDecorators = hasDecorators(firstAccessor) ? firstAccessor + : secondAccessor && hasDecorators(secondAccessor) ? secondAccessor + : undefined; if (!firstAccessorWithDecorators || node !== firstAccessorWithDecorators) { return false; } @@ -3309,9 +3619,11 @@ export function isEmptyStringLiteral(node: StringLiteral): boolean { /** @internal */ export function isJSXTagName(node: Node) { const { parent } = node; - if (parent.kind === SyntaxKind.JsxOpeningElement || - parent.kind === SyntaxKind.JsxSelfClosingElement || - parent.kind === SyntaxKind.JsxClosingElement) { + if ( + parent.kind === SyntaxKind.JsxOpeningElement + || parent.kind === SyntaxKind.JsxSelfClosingElement + || parent.kind === SyntaxKind.JsxClosingElement + ) { return (parent as JsxOpeningLikeElement).tagName === node; } return false; @@ -3363,16 +3675,22 @@ export function isExpressionNode(node: Node): boolean { while (node.parent.kind === SyntaxKind.QualifiedName) { node = node.parent; } - return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node); + return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) + || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node); case SyntaxKind.JSDocMemberName: while (isJSDocMemberName(node.parent)) { node = node.parent; } - return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node); + return node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) + || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node); case SyntaxKind.PrivateIdentifier: - return isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.InKeyword; + return isBinaryExpression(node.parent) && node.parent.left === node + && node.parent.operatorToken.kind === SyntaxKind.InKeyword; case SyntaxKind.Identifier: - if (node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node)) { + if ( + node.parent.kind === SyntaxKind.TypeQuery || isJSDocLinkLike(node.parent) + || isJSDocNameReference(node.parent) || isJSDocMemberName(node.parent) || isJSXTagName(node) + ) { return true; } // falls through @@ -3412,14 +3730,16 @@ export function isInExpressionContext(node: Node): boolean { return (parent as ExpressionStatement).expression === node; case SyntaxKind.ForStatement: const forStatement = parent as ForStatement; - return (forStatement.initializer === node && forStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) || - forStatement.condition === node || - forStatement.incrementor === node; + return (forStatement.initializer === node + && forStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) + || forStatement.condition === node + || forStatement.incrementor === node; case SyntaxKind.ForInStatement: case SyntaxKind.ForOfStatement: const forInOrOfStatement = parent as ForInOrOfStatement; - return (forInOrOfStatement.initializer === node && forInOrOfStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) || - forInOrOfStatement.expression === node; + return (forInOrOfStatement.initializer === node + && forInOrOfStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) + || forInOrOfStatement.expression === node; case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: return node === (parent as AssertionExpression).expression; @@ -3457,8 +3777,11 @@ export function isNamespaceReexportDeclaration(node: Node): boolean { } /** @internal */ -export function isExternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference } { - return node.kind === SyntaxKind.ImportEqualsDeclaration && (node as ImportEqualsDeclaration).moduleReference.kind === SyntaxKind.ExternalModuleReference; +export function isExternalModuleImportEqualsDeclaration( + node: Node, +): node is ImportEqualsDeclaration & { moduleReference: ExternalModuleReference; } { + return node.kind === SyntaxKind.ImportEqualsDeclaration + && (node as ImportEqualsDeclaration).moduleReference.kind === SyntaxKind.ExternalModuleReference; } /** @internal */ @@ -3469,12 +3792,14 @@ export function getExternalModuleImportEqualsDeclarationExpression(node: Node) { /** @internal */ export function getExternalModuleRequireArgument(node: Node) { - return isVariableDeclarationInitializedToBareOrAccessedRequire(node) && (getLeftmostAccessExpression(node.initializer) as CallExpression).arguments[0] as StringLiteral; + return isVariableDeclarationInitializedToBareOrAccessedRequire(node) + && (getLeftmostAccessExpression(node.initializer) as CallExpression).arguments[0] as StringLiteral; } /** @internal */ export function isInternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration { - return node.kind === SyntaxKind.ImportEqualsDeclaration && (node as ImportEqualsDeclaration).moduleReference.kind !== SyntaxKind.ExternalModuleReference; + return node.kind === SyntaxKind.ImportEqualsDeclaration + && (node as ImportEqualsDeclaration).moduleReference.kind !== SyntaxKind.ExternalModuleReference; } /** @internal */ @@ -3509,11 +3834,12 @@ export function isInJSDoc(node: Node | undefined): boolean { /** @internal */ export function isJSDocIndexSignature(node: TypeReferenceNode | ExpressionWithTypeArguments) { - return isTypeReferenceNode(node) && - isIdentifier(node.typeName) && - node.typeName.escapedText === "Object" && - node.typeArguments && node.typeArguments.length === 2 && - (node.typeArguments[0].kind === SyntaxKind.StringKeyword || node.typeArguments[0].kind === SyntaxKind.NumberKeyword); + return isTypeReferenceNode(node) + && isIdentifier(node.typeName) + && node.typeName.escapedText === "Object" + && node.typeArguments && node.typeArguments.length === 2 + && (node.typeArguments[0].kind === SyntaxKind.StringKeyword + || node.typeArguments[0].kind === SyntaxKind.NumberKeyword); } /** @@ -3523,11 +3849,20 @@ export function isJSDocIndexSignature(node: TypeReferenceNode | ExpressionWithTy * * @internal */ -export function isRequireCall(callExpression: Node, requireStringLiteralLikeArgument: true): callExpression is RequireOrImportCall & { expression: Identifier, arguments: [StringLiteralLike] }; -/** @internal */ -export function isRequireCall(callExpression: Node, requireStringLiteralLikeArgument: boolean): callExpression is CallExpression; -/** @internal */ -export function isRequireCall(callExpression: Node, requireStringLiteralLikeArgument: boolean): callExpression is CallExpression { +export function isRequireCall( + callExpression: Node, + requireStringLiteralLikeArgument: true, +): callExpression is RequireOrImportCall & { expression: Identifier; arguments: [StringLiteralLike]; }; +/** @internal */ +export function isRequireCall( + callExpression: Node, + requireStringLiteralLikeArgument: boolean, +): callExpression is CallExpression; +/** @internal */ +export function isRequireCall( + callExpression: Node, + requireStringLiteralLikeArgument: boolean, +): callExpression is CallExpression { if (callExpression.kind !== SyntaxKind.CallExpression) { return false; } @@ -3550,7 +3885,9 @@ export function isRequireCall(callExpression: Node, requireStringLiteralLikeArgu * * @internal */ -export function isVariableDeclarationInitializedToRequire(node: Node): node is VariableDeclarationInitializedTo { +export function isVariableDeclarationInitializedToRequire( + node: Node, +): node is VariableDeclarationInitializedTo { return isVariableDeclarationInitializedWithRequireHelper(node, /*allowAccessedRequire*/ false); } @@ -3559,7 +3896,9 @@ export function isVariableDeclarationInitializedToRequire(node: Node): node is V * * @internal */ -export function isVariableDeclarationInitializedToBareOrAccessedRequire(node: Node): node is VariableDeclarationInitializedTo { +export function isVariableDeclarationInitializedToBareOrAccessedRequire( + node: Node, +): node is VariableDeclarationInitializedTo { return isVariableDeclarationInitializedWithRequireHelper(node, /*allowAccessedRequire*/ true); } @@ -3569,9 +3908,12 @@ export function isBindingElementOfBareOrAccessedRequire(node: Node): node is Bin } function isVariableDeclarationInitializedWithRequireHelper(node: Node, allowAccessedRequire: boolean) { - return isVariableDeclaration(node) && - !!node.initializer && - isRequireCall(allowAccessedRequire ? getLeftmostAccessExpression(node.initializer) : node.initializer, /*requireStringLiteralLikeArgument*/ true); + return isVariableDeclaration(node) + && !!node.initializer + && isRequireCall( + allowAccessedRequire ? getLeftmostAccessExpression(node.initializer) : node.initializer, + /*requireStringLiteralLikeArgument*/ true, + ); } /** @internal */ @@ -3602,10 +3944,13 @@ export function isAssignmentDeclaration(decl: Declaration) { * @internal */ export function getEffectiveInitializer(node: HasExpressionInitializer) { - if (isInJSFile(node) && node.initializer && - isBinaryExpression(node.initializer) && - (node.initializer.operatorToken.kind === SyntaxKind.BarBarToken || node.initializer.operatorToken.kind === SyntaxKind.QuestionQuestionToken) && - node.name && isEntityNameExpression(node.name) && isSameEntityName(node.name, node.initializer.left)) { + if ( + isInJSFile(node) && node.initializer + && isBinaryExpression(node.initializer) + && (node.initializer.operatorToken.kind === SyntaxKind.BarBarToken + || node.initializer.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + && node.name && isEntityNameExpression(node.name) && isSameEntityName(node.name, node.initializer.left) + ) { return node.initializer.right; } return node.initializer; @@ -3623,11 +3968,11 @@ export function getDeclaredExpandoInitializer(node: HasExpressionInitializer) { function hasExpandoValueProperty(node: ObjectLiteralExpression, isPrototypeAssignment: boolean) { return forEach(node.properties, p => - isPropertyAssignment(p) && - isIdentifier(p.name) && - p.name.escapedText === "value" && - p.initializer && - getExpandoInitializer(p.initializer, isPrototypeAssignment)); + isPropertyAssignment(p) + && isIdentifier(p.name) + && p.name.escapedText === "value" + && p.initializer + && getExpandoInitializer(p.initializer, isPrototypeAssignment)); } /** @@ -3637,10 +3982,13 @@ function hasExpandoValueProperty(node: ObjectLiteralExpression, isPrototypeAssig * @internal */ export function getAssignedExpandoInitializer(node: Node | undefined): Expression | undefined { - if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + node && node.parent && isBinaryExpression(node.parent) + && node.parent.operatorToken.kind === SyntaxKind.EqualsToken + ) { const isPrototypeAssignment = isPrototypeAccess(node.parent.left); - return getExpandoInitializer(node.parent.right, isPrototypeAssignment) || - getDefaultedExpandoInitializer(node.parent.left, node.parent.right, isPrototypeAssignment); + return getExpandoInitializer(node.parent.right, isPrototypeAssignment) + || getDefaultedExpandoInitializer(node.parent.left, node.parent.right, isPrototypeAssignment); } if (node && isCallExpression(node) && isBindableObjectDefinePropertyCall(node)) { const result = hasExpandoValueProperty(node.arguments[2], node.arguments[1].text === "prototype"); @@ -3665,11 +4013,14 @@ export function getAssignedExpandoInitializer(node: Node | undefined): Expressio export function getExpandoInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression | undefined { if (isCallExpression(initializer)) { const e = skipParentheses(initializer.expression); - return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined; + return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer + : undefined; } - if (initializer.kind === SyntaxKind.FunctionExpression || - initializer.kind === SyntaxKind.ClassExpression || - initializer.kind === SyntaxKind.ArrowFunction) { + if ( + initializer.kind === SyntaxKind.FunctionExpression + || initializer.kind === SyntaxKind.ClassExpression + || initializer.kind === SyntaxKind.ArrowFunction + ) { return initializer as Expression; } if (isObjectLiteralExpression(initializer) && (initializer.properties.length === 0 || isPrototypeAssignment)) { @@ -3687,7 +4038,8 @@ export function getExpandoInitializer(initializer: Node, isPrototypeAssignment: */ function getDefaultedExpandoInitializer(name: Expression, initializer: Expression, isPrototypeAssignment: boolean) { const e = isBinaryExpression(initializer) - && (initializer.operatorToken.kind === SyntaxKind.BarBarToken || initializer.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + && (initializer.operatorToken.kind === SyntaxKind.BarBarToken + || initializer.operatorToken.kind === SyntaxKind.QuestionQuestionToken) && getExpandoInitializer(initializer.right, isPrototypeAssignment); if (e && isSameEntityName(name, initializer.left)) { return e; @@ -3696,10 +4048,12 @@ function getDefaultedExpandoInitializer(name: Expression, initializer: Expressio /** @internal */ export function isDefaultedExpandoInitializer(node: BinaryExpression) { - const name = isVariableDeclaration(node.parent) ? node.parent.name : - isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken ? node.parent.left : - undefined; - return name && getExpandoInitializer(node.right, isPrototypeAccess(name)) && isEntityNameExpression(name) && isSameEntityName(name, node.left); + const name = isVariableDeclaration(node.parent) ? node.parent.name + : isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken + ? node.parent.left + : undefined; + return name && getExpandoInitializer(node.right, isPrototypeAccess(name)) && isEntityNameExpression(name) + && isSameEntityName(name, node.left); } /** @@ -3709,7 +4063,9 @@ export function isDefaultedExpandoInitializer(node: BinaryExpression) { */ export function getNameOfExpando(node: Declaration): DeclarationName | undefined { if (isBinaryExpression(node.parent)) { - const parent = ((node.parent.operatorToken.kind === SyntaxKind.BarBarToken || node.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken) && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent; + const parent = ((node.parent.operatorToken.kind === SyntaxKind.BarBarToken + || node.parent.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent; if (parent.operatorToken.kind === SyntaxKind.EqualsToken && isIdentifier(parent.left)) { return parent.left; } @@ -3734,12 +4090,14 @@ export function isSameEntityName(name: Expression, initializer: Expression): boo if (isPropertyNameLiteral(name) && isPropertyNameLiteral(initializer)) { return getTextOfIdentifierOrLiteral(name) === getTextOfIdentifierOrLiteral(initializer); } - if (isMemberName(name) && isLiteralLikeAccess(initializer) && - (initializer.expression.kind === SyntaxKind.ThisKeyword || - isIdentifier(initializer.expression) && - (initializer.expression.escapedText === "window" || - initializer.expression.escapedText === "self" || - initializer.expression.escapedText === "global"))) { + if ( + isMemberName(name) && isLiteralLikeAccess(initializer) + && (initializer.expression.kind === SyntaxKind.ThisKeyword + || isIdentifier(initializer.expression) + && (initializer.expression.escapedText === "window" + || initializer.expression.escapedText === "self" + || initializer.expression.escapedText === "global")) + ) { return isSameEntityName(name, getNameOrArgument(initializer)); } if (isLiteralLikeAccess(name) && isLiteralLikeAccess(initializer)) { @@ -3768,7 +4126,9 @@ export function isModuleIdentifier(node: Node) { } /** @internal */ -export function isModuleExportsAccessExpression(node: Node): node is LiteralLikeElementAccessExpression & { expression: Identifier } { +export function isModuleExportsAccessExpression( + node: Node, +): node is LiteralLikeElementAccessExpression & { expression: Identifier; } { return (isPropertyAccessExpression(node) || isLiteralLikeElementAccess(node)) && isModuleIdentifier(node.expression) && getElementOrPropertyAccessName(node) === "exports"; @@ -3779,18 +4139,19 @@ export function isModuleExportsAccessExpression(node: Node): node is LiteralLike /** @internal */ export function getAssignmentDeclarationKind(expr: BinaryExpression | CallExpression): AssignmentDeclarationKind { const special = getAssignmentDeclarationKindWorker(expr); - return special === AssignmentDeclarationKind.Property || isInJSFile(expr) ? special : AssignmentDeclarationKind.None; + return special === AssignmentDeclarationKind.Property || isInJSFile(expr) ? special + : AssignmentDeclarationKind.None; } /** @internal */ export function isBindableObjectDefinePropertyCall(expr: CallExpression): expr is BindableObjectDefinePropertyCall { - return length(expr.arguments) === 3 && - isPropertyAccessExpression(expr.expression) && - isIdentifier(expr.expression.expression) && - idText(expr.expression.expression) === "Object" && - idText(expr.expression.name) === "defineProperty" && - isStringOrNumericLiteralLike(expr.arguments[1]) && - isBindableStaticNameExpression(expr.arguments[0], /*excludeThisKeyword*/ true); + return length(expr.arguments) === 3 + && isPropertyAccessExpression(expr.expression) + && isIdentifier(expr.expression.expression) + && idText(expr.expression.expression) === "Object" + && idText(expr.expression.name) === "defineProperty" + && isStringOrNumericLiteralLike(expr.arguments[1]) + && isBindableStaticNameExpression(expr.arguments[0], /*excludeThisKeyword*/ true); } /** @@ -3816,8 +4177,14 @@ export function isLiteralLikeElementAccess(node: Node): node is LiteralLikeEleme * * @internal */ -export function isBindableStaticAccessExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticAccessExpression { - return isPropertyAccessExpression(node) && (!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword || isIdentifier(node.name) && isBindableStaticNameExpression(node.expression, /*excludeThisKeyword*/ true)) +export function isBindableStaticAccessExpression( + node: Node, + excludeThisKeyword?: boolean, +): node is BindableStaticAccessExpression { + return isPropertyAccessExpression(node) + && (!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword + || isIdentifier(node.name) + && isBindableStaticNameExpression(node.expression, /*excludeThisKeyword*/ true)) || isBindableStaticElementAccessExpression(node, excludeThisKeyword); } @@ -3826,15 +4193,21 @@ export function isBindableStaticAccessExpression(node: Node, excludeThisKeyword? * * @internal */ -export function isBindableStaticElementAccessExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticElementAccessExpression { +export function isBindableStaticElementAccessExpression( + node: Node, + excludeThisKeyword?: boolean, +): node is BindableStaticElementAccessExpression { return isLiteralLikeElementAccess(node) - && ((!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword) || - isEntityNameExpression(node.expression) || - isBindableStaticAccessExpression(node.expression, /*excludeThisKeyword*/ true)); + && ((!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword) + || isEntityNameExpression(node.expression) + || isBindableStaticAccessExpression(node.expression, /*excludeThisKeyword*/ true)); } /** @internal */ -export function isBindableStaticNameExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticNameExpression { +export function isBindableStaticNameExpression( + node: Node, + excludeThisKeyword?: boolean, +): node is BindableStaticNameExpression { return isEntityNameExpression(node) || isBindableStaticAccessExpression(node, excludeThisKeyword); } @@ -3855,15 +4228,24 @@ function getAssignmentDeclarationKindWorker(expr: BinaryExpression | CallExpress if (isExportsIdentifier(entityName) || isModuleExportsAccessExpression(entityName)) { return AssignmentDeclarationKind.ObjectDefinePropertyExports; } - if (isBindableStaticAccessExpression(entityName) && getElementOrPropertyAccessName(entityName) === "prototype") { + if ( + isBindableStaticAccessExpression(entityName) && getElementOrPropertyAccessName(entityName) === "prototype" + ) { return AssignmentDeclarationKind.ObjectDefinePrototypeProperty; } return AssignmentDeclarationKind.ObjectDefinePropertyValue; } - if (expr.operatorToken.kind !== SyntaxKind.EqualsToken || !isAccessExpression(expr.left) || isVoidZero(getRightMostAssignedExpression(expr))) { + if ( + expr.operatorToken.kind !== SyntaxKind.EqualsToken || !isAccessExpression(expr.left) + || isVoidZero(getRightMostAssignedExpression(expr)) + ) { return AssignmentDeclarationKind.None; } - if (isBindableStaticNameExpression(expr.left.expression, /*excludeThisKeyword*/ true) && getElementOrPropertyAccessName(expr.left) === "prototype" && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr))) { + if ( + isBindableStaticNameExpression(expr.left.expression, /*excludeThisKeyword*/ true) + && getElementOrPropertyAccessName(expr.left) === "prototype" + && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr)) + ) { // F.prototype = { ... } return AssignmentDeclarationKind.Prototype; } @@ -3880,7 +4262,9 @@ function isVoidZero(node: Node) { * * @internal */ -export function getElementOrPropertyAccessArgumentExpressionOrName(node: AccessExpression): Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ElementAccessExpression | undefined { +export function getElementOrPropertyAccessArgumentExpressionOrName( + node: AccessExpression, +): Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ElementAccessExpression | undefined { if (isPropertyAccessExpression(node)) { return node.name; } @@ -3892,7 +4276,9 @@ export function getElementOrPropertyAccessArgumentExpressionOrName(node: AccessE } /** @internal */ -export function getElementOrPropertyAccessName(node: LiteralLikeElementAccessExpression | PropertyAccessExpression): __String; +export function getElementOrPropertyAccessName( + node: LiteralLikeElementAccessExpression | PropertyAccessExpression, +): __String; /** @internal */ export function getElementOrPropertyAccessName(node: AccessExpression): __String | undefined; /** @internal */ @@ -3929,14 +4315,19 @@ export function getAssignmentDeclarationPropertyAccessKind(lhs: AccessExpression nextToLast = nextToLast.expression as Exclude; } const id = nextToLast.expression; - if ((id.escapedText === "exports" || - id.escapedText === "module" && getElementOrPropertyAccessName(nextToLast) === "exports") && + if ( + (id.escapedText === "exports" + || id.escapedText === "module" && getElementOrPropertyAccessName(nextToLast) === "exports") // ExportsProperty does not support binding with computed names - isBindableStaticAccessExpression(lhs)) { + && isBindableStaticAccessExpression(lhs) + ) { // exports.name = expr OR module.exports.name = expr OR exports["name"] = expr ... return AssignmentDeclarationKind.ExportsProperty; } - if (isBindableStaticNameExpression(lhs, /*excludeThisKeyword*/ true) || (isElementAccessExpression(lhs) && isDynamicName(lhs))) { + if ( + isBindableStaticNameExpression(lhs, /*excludeThisKeyword*/ true) + || (isElementAccessExpression(lhs) && isDynamicName(lhs)) + ) { // F.G...x = expr return AssignmentDeclarationKind.Property; } @@ -3961,24 +4352,29 @@ export interface PrototypePropertyAssignment extends AssignmentExpression isRequireCall(node, /*requireStringLiteralLikeArgument*/ true))?.arguments[0]; + return findAncestor( + node.initializer, + (node): node is RequireOrImportCall => isRequireCall(node, /*requireStringLiteralLikeArgument*/ true), + )?.arguments[0]; case SyntaxKind.ImportDeclaration: return tryCast(node.moduleSpecifier, isStringLiteralLike); case SyntaxKind.ImportEqualsDeclaration: @@ -4030,7 +4432,8 @@ export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyVal case SyntaxKind.ExternalModuleReference: return (node.parent as ExternalModuleReference).parent as AnyValidImportOrReExport; case SyntaxKind.CallExpression: - return isImportCall(node.parent) || isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) ? node.parent as RequireOrImportCall : undefined; + return isImportCall(node.parent) || isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) + ? node.parent as RequireOrImportCall : undefined; case SyntaxKind.LiteralType: Debug.assert(isStringLiteral(node)); return tryCast(node.parent.parent, isImportTypeNode) as ValidImportTypeNode | undefined; @@ -4040,13 +4443,16 @@ export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyVal } /** @internal */ -export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration): Expression | undefined { +export function getExternalModuleName( + node: AnyImportOrReExport | ImportTypeNode | ImportCall | ModuleDeclaration, +): Expression | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: return node.moduleSpecifier; case SyntaxKind.ImportEqualsDeclaration: - return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression : undefined; + return node.moduleReference.kind === SyntaxKind.ExternalModuleReference ? node.moduleReference.expression + : undefined; case SyntaxKind.ImportType: return isLiteralImportTypeNode(node) ? node.argument.literal : undefined; case SyntaxKind.CallExpression: @@ -4059,7 +4465,9 @@ export function getExternalModuleName(node: AnyImportOrReExport | ImportTypeNode } /** @internal */ -export function getNamespaceDeclarationNode(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): ImportEqualsDeclaration | NamespaceImport | NamespaceExport | undefined { +export function getNamespaceDeclarationNode( + node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration, +): ImportEqualsDeclaration | NamespaceImport | NamespaceExport | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: return node.importClause && tryCast(node.importClause.namedBindings, isNamespaceImport); @@ -4078,7 +4486,10 @@ export function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaratio } /** @internal */ -export function forEachImportClauseDeclaration(node: ImportClause, action: (declaration: ImportClause | NamespaceImport | ImportSpecifier) => T | undefined): T | undefined { +export function forEachImportClauseDeclaration( + node: ImportClause, + action: (declaration: ImportClause | NamespaceImport | ImportSpecifier) => T | undefined, +): T | undefined { if (node.name) { const result = action(node); if (result) return result; @@ -4102,7 +4513,8 @@ export function hasQuestionToken(node: Node) { case SyntaxKind.PropertyAssignment: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - return (node as ParameterDeclaration | MethodDeclaration | PropertyDeclaration).questionToken !== undefined; + return (node as ParameterDeclaration | MethodDeclaration | PropertyDeclaration).questionToken + !== undefined; } } @@ -4118,28 +4530,32 @@ export function isJSDocConstructSignature(node: Node) { /** @internal */ export function isJSDocTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag { - return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag || node.kind === SyntaxKind.JSDocEnumTag; + return node.kind === SyntaxKind.JSDocTypedefTag || node.kind === SyntaxKind.JSDocCallbackTag + || node.kind === SyntaxKind.JSDocEnumTag; } /** @internal */ -export function isTypeAlias(node: Node): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | TypeAliasDeclaration { +export function isTypeAlias( + node: Node, +): node is JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | TypeAliasDeclaration { return isJSDocTypeAlias(node) || isTypeAliasDeclaration(node); } function getSourceOfAssignment(node: Node): Node | undefined { - return isExpressionStatement(node) && - isBinaryExpression(node.expression) && - node.expression.operatorToken.kind === SyntaxKind.EqualsToken + return isExpressionStatement(node) + && isBinaryExpression(node.expression) + && node.expression.operatorToken.kind === SyntaxKind.EqualsToken ? getRightMostAssignedExpression(node.expression) : undefined; } function getSourceOfDefaultedAssignment(node: Node): Node | undefined { - return isExpressionStatement(node) && - isBinaryExpression(node.expression) && - getAssignmentDeclarationKind(node.expression) !== AssignmentDeclarationKind.None && - isBinaryExpression(node.expression.right) && - (node.expression.right.operatorToken.kind === SyntaxKind.BarBarToken || node.expression.right.operatorToken.kind === SyntaxKind.QuestionQuestionToken) + return isExpressionStatement(node) + && isBinaryExpression(node.expression) + && getAssignmentDeclarationKind(node.expression) !== AssignmentDeclarationKind.None + && isBinaryExpression(node.expression.right) + && (node.expression.right.operatorToken.kind === SyntaxKind.BarBarToken + || node.expression.right.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? node.expression.right.right : undefined; } @@ -4163,9 +4579,9 @@ export function getSingleVariableOfVariableStatement(node: Node): VariableDeclar } function getNestedModuleDeclaration(node: Node): Node | undefined { - return isModuleDeclaration(node) && - node.body && - node.body.kind === SyntaxKind.ModuleDeclaration + return isModuleDeclaration(node) + && node.body + && node.body.kind === SyntaxKind.ModuleDeclaration ? node.body : undefined; } @@ -4308,11 +4724,19 @@ export function getJSDocCommentsAndTags(hostNode: Node, noCache?: boolean): read } if (node.kind === SyntaxKind.Parameter) { - result = addRange(result, (noCache ? getJSDocParameterTagsNoCache : getJSDocParameterTags)(node as ParameterDeclaration)); + result = addRange( + result, + (noCache ? getJSDocParameterTagsNoCache : getJSDocParameterTags)(node as ParameterDeclaration), + ); break; } if (node.kind === SyntaxKind.TypeParameter) { - result = addRange(result, (noCache ? getJSDocTypeParameterTagsNoCache : getJSDocTypeParameterTags)(node as TypeParameterDeclaration)); + result = addRange( + result, + (noCache ? getJSDocTypeParameterTagsNoCache : getJSDocTypeParameterTags)( + node as TypeParameterDeclaration, + ), + ); break; } node = getNextJSDocCommentLocation(node); @@ -4343,13 +4767,15 @@ function ownsJSDocTag(hostNode: Node, tag: JSDocTag) { /** @internal */ export function getNextJSDocCommentLocation(node: Node) { const parent = node.parent; - if (parent.kind === SyntaxKind.PropertyAssignment || - parent.kind === SyntaxKind.ExportAssignment || - parent.kind === SyntaxKind.PropertyDeclaration || - parent.kind === SyntaxKind.ExpressionStatement && node.kind === SyntaxKind.PropertyAccessExpression || - parent.kind === SyntaxKind.ReturnStatement || - getNestedModuleDeclaration(parent) || - isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + parent.kind === SyntaxKind.PropertyAssignment + || parent.kind === SyntaxKind.ExportAssignment + || parent.kind === SyntaxKind.PropertyDeclaration + || parent.kind === SyntaxKind.ExpressionStatement && node.kind === SyntaxKind.PropertyAccessExpression + || parent.kind === SyntaxKind.ReturnStatement + || getNestedModuleDeclaration(parent) + || isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.EqualsToken + ) { return parent; } // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. @@ -4358,15 +4784,19 @@ export function getNextJSDocCommentLocation(node: Node) { // * @returns {number} // */ // var x = function(name) { return name.length; } - else if (parent.parent && - (getSingleVariableOfVariableStatement(parent.parent) === node || - isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken)) { + else if ( + parent.parent + && (getSingleVariableOfVariableStatement(parent.parent) === node + || isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken) + ) { return parent.parent; } - else if (parent.parent && parent.parent.parent && - (getSingleVariableOfVariableStatement(parent.parent.parent) || - getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node || - getSourceOfDefaultedAssignment(parent.parent.parent))) { + else if ( + parent.parent && parent.parent.parent + && (getSingleVariableOfVariableStatement(parent.parent.parent) + || getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node + || getSourceOfDefaultedAssignment(parent.parent.parent)) + ) { return parent.parent.parent; } } @@ -4409,8 +4839,8 @@ export function getEffectiveContainerForJSDocTemplateTag(node: JSDocTemplateTag) export function getHostSignatureFromJSDoc(node: Node): SignatureDeclaration | undefined { const host = getEffectiveJSDocHost(node); if (host) { - return isPropertySignature(host) && host.type && isFunctionLike(host.type) ? host.type : - isFunctionLike(host) ? host : undefined; + return isPropertySignature(host) && host.type && isFunctionLike(host.type) ? host.type + : isFunctionLike(host) ? host : undefined; } return undefined; } @@ -4451,9 +4881,14 @@ export function getJSDocRoot(node: Node): JSDoc | undefined { } /** @internal */ -export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag }): TypeParameterDeclaration | undefined { +export function getTypeParameterFromJsDoc( + node: TypeParameterDeclaration & { parent: JSDocTemplateTag; }, +): TypeParameterDeclaration | undefined { const name = node.name.escapedText; - const { typeParameters } = (node.parent.parent.parent as SignatureDeclaration | InterfaceDeclaration | ClassDeclaration); + const { typeParameters } = node.parent.parent.parent as + | SignatureDeclaration + | InterfaceDeclaration + | ClassDeclaration; return typeParameters && find(typeParameters, p => p.name.escapedText === name); } @@ -4464,7 +4899,9 @@ export function hasTypeArguments(node: Node): node is HasTypeArguments { /** @internal */ export const enum AssignmentKind { - None, Definite, Compound + None, + Definite, + Compound, } type AssignmentTarget = @@ -4480,12 +4917,14 @@ function getAssignmentTarget(node: Node): AssignmentTarget | undefined { case SyntaxKind.BinaryExpression: const binaryExpression = parent as BinaryExpression; const binaryOperator = binaryExpression.operatorToken.kind; - return isAssignmentOperator(binaryOperator) && binaryExpression.left === node ? binaryExpression : undefined; + return isAssignmentOperator(binaryOperator) && binaryExpression.left === node ? binaryExpression + : undefined; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: - const unaryExpression = (parent as PrefixUnaryExpression | PostfixUnaryExpression); + const unaryExpression = parent as PrefixUnaryExpression | PostfixUnaryExpression; const unaryOperator = unaryExpression.operator; - return unaryOperator === SyntaxKind.PlusPlusToken || unaryOperator === SyntaxKind.MinusMinusToken ? unaryExpression : undefined; + return unaryOperator === SyntaxKind.PlusPlusToken || unaryOperator === SyntaxKind.MinusMinusToken + ? unaryExpression : undefined; case SyntaxKind.ForInStatement: case SyntaxKind.ForOfStatement: const forInOrOfStatement = parent as ForInOrOfStatement; @@ -4527,9 +4966,9 @@ export function getAssignmentTargetKind(node: Node): AssignmentKind { switch (target.kind) { case SyntaxKind.BinaryExpression: const binaryOperator = target.operatorToken.kind; - return binaryOperator === SyntaxKind.EqualsToken || isLogicalOrCoalescingAssignmentOperator(binaryOperator) ? - AssignmentKind.Definite : - AssignmentKind.Compound; + return binaryOperator === SyntaxKind.EqualsToken || isLogicalOrCoalescingAssignmentOperator(binaryOperator) + ? AssignmentKind.Definite + : AssignmentKind.Compound; case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: return AssignmentKind.Compound; @@ -4550,13 +4989,15 @@ export function isAssignmentTarget(node: Node): boolean { function isCompoundLikeAssignment(assignment: AssignmentExpression): boolean { const right = skipParentheses(assignment.right); - return right.kind === SyntaxKind.BinaryExpression && isShiftOperatorOrHigher((right as BinaryExpression).operatorToken.kind); + return right.kind === SyntaxKind.BinaryExpression + && isShiftOperatorOrHigher((right as BinaryExpression).operatorToken.kind); } /** @internal */ export function isInCompoundLikeAssignment(node: Node): boolean { const target = getAssignmentTarget(node); - return !!target && isAssignmentExpression(target, /*excludeCompoundAssignment*/ true) && isCompoundLikeAssignment(target); + return !!target && isAssignmentExpression(target, /*excludeCompoundAssignment*/ true) + && isCompoundLikeAssignment(target); } /** @internal */ @@ -4617,7 +5058,8 @@ export type ValueSignatureDeclaration = /** @internal */ export function isValueSignatureDeclaration(node: Node): node is ValueSignatureDeclaration { - return isFunctionExpression(node) || isArrowFunction(node) || isMethodOrAccessor(node) || isFunctionDeclaration(node) || isConstructorDeclaration(node); + return isFunctionExpression(node) || isArrowFunction(node) || isMethodOrAccessor(node) + || isFunctionDeclaration(node) || isConstructorDeclaration(node); } function walkUp(node: Node, kind: SyntaxKind) { @@ -4665,9 +5107,9 @@ export function skipParentheses(node: Expression, excludeJSDocTypeAssertions?: b export function skipParentheses(node: Node, excludeJSDocTypeAssertions?: boolean): Node; /** @internal */ export function skipParentheses(node: Node, excludeJSDocTypeAssertions?: boolean): Node { - const flags = excludeJSDocTypeAssertions ? - OuterExpressionKinds.Parentheses | OuterExpressionKinds.ExcludeJSDocTypeAssertion : - OuterExpressionKinds.Parentheses; + const flags = excludeJSDocTypeAssertions + ? OuterExpressionKinds.Parentheses | OuterExpressionKinds.ExcludeJSDocTypeAssertion + : OuterExpressionKinds.Parentheses; return skipOuterExpressions(node, flags); } @@ -4716,10 +5158,10 @@ export function getDeclarationFromName(name: Node): Declaration | undefined { } else { const binExp = parent.parent; - return isBinaryExpression(binExp) && - getAssignmentDeclarationKind(binExp) !== AssignmentDeclarationKind.None && - ((binExp.left as BindableStaticNameExpression).symbol || binExp.symbol) && - getNameOfDeclaration(binExp) === name + return isBinaryExpression(binExp) + && getAssignmentDeclarationKind(binExp) !== AssignmentDeclarationKind.None + && ((binExp.left as BindableStaticNameExpression).symbol || binExp.symbol) + && getNameOfDeclaration(binExp) === name ? binExp : undefined; } @@ -4732,9 +5174,9 @@ export function getDeclarationFromName(name: Node): Declaration | undefined { /** @internal */ export function isLiteralComputedPropertyDeclarationName(node: Node) { - return isStringOrNumericLiteralLike(node) && - node.parent.kind === SyntaxKind.ComputedPropertyName && - isDeclaration(node.parent.parent); + return isStringOrNumericLiteralLike(node) + && node.parent.kind === SyntaxKind.ComputedPropertyName + && isDeclaration(node.parent.parent); } // Return true if the given identifier is classified as an IdentifierName @@ -4788,25 +5230,28 @@ export function isIdentifierName(node: Identifier): boolean { // 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) + 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) && 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)); + && isAliasableExpression(node.parent.right) + ); } /** @internal */ @@ -4823,7 +5268,8 @@ export function getAliasDeclarationFromName(node: EntityName): Declaration | und case SyntaxKind.QualifiedName: do { node = node.parent as QualifiedName; - } while (node.parent.kind === SyntaxKind.QualifiedName); + } + while (node.parent.kind === SyntaxKind.QualifiedName); return getAliasDeclarationFromName(node); } } @@ -4845,9 +5291,12 @@ export function getExportAssignmentExpression(node: ExportAssignment | BinaryExp } /** @internal */ -export function getPropertyAssignmentAliasLikeExpression(node: PropertyAssignment | ShorthandPropertyAssignment | PropertyAccessExpression): Expression { - return node.kind === SyntaxKind.ShorthandPropertyAssignment ? node.name : node.kind === SyntaxKind.PropertyAssignment ? node.initializer : - (node.parent as BinaryExpression).right; +export function getPropertyAssignmentAliasLikeExpression( + node: PropertyAssignment | ShorthandPropertyAssignment | PropertyAccessExpression, +): Expression { + return node.kind === SyntaxKind.ShorthandPropertyAssignment ? node.name + : node.kind === SyntaxKind.PropertyAssignment ? node.initializer + : (node.parent as BinaryExpression).right; } /** @internal */ @@ -4870,7 +5319,9 @@ export function getClassExtendsHeritageElement(node: ClassLikeDeclaration | Inte } /** @internal */ -export function getEffectiveImplementsTypeNodes(node: ClassLikeDeclaration): undefined | readonly ExpressionWithTypeArguments[]{ +export function getEffectiveImplementsTypeNodes( + node: ClassLikeDeclaration, +): undefined | readonly ExpressionWithTypeArguments[] { if (isInJSFile(node)) { return getJSDocImplementsTags(node).map(n => n.class); } @@ -4886,9 +5337,11 @@ export function getEffectiveImplementsTypeNodes(node: ClassLikeDeclaration): und * @internal */ export function getAllSuperTypeNodes(node: Node): readonly TypeNode[] { - return isInterfaceDeclaration(node) ? getInterfaceBaseTypeNodes(node) || emptyArray : - isClassLike(node) ? concatenate(singleElementArray(getEffectiveBaseTypeNode(node)), getEffectiveImplementsTypeNodes(node)) || emptyArray : - emptyArray; + return isInterfaceDeclaration(node) ? getInterfaceBaseTypeNodes(node) || emptyArray + : isClassLike(node) + ? concatenate(singleElementArray(getEffectiveBaseTypeNode(node)), getEffectiveImplementsTypeNodes(node)) + || emptyArray + : emptyArray; } /** @internal */ @@ -4974,6 +5427,7 @@ export function isTrivia(token: SyntaxKind): token is TriviaSyntaxKind { return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken; } +// dprint-ignore /** @internal */ export const enum FunctionFlags { Normal = 0, // Function is a normal function @@ -5033,8 +5487,10 @@ export function isStringOrNumericLiteralLike(node: Node): node is StringLiteralL } /** @internal */ -export function isSignedNumericLiteral(node: Node): node is PrefixUnaryExpression & { operand: NumericLiteral } { - return isPrefixUnaryExpression(node) && (node.operator === SyntaxKind.PlusToken || node.operator === SyntaxKind.MinusToken) && isNumericLiteral(node.operand); +export function isSignedNumericLiteral(node: Node): node is PrefixUnaryExpression & { operand: NumericLiteral; } { + return isPrefixUnaryExpression(node) + && (node.operator === SyntaxKind.PlusToken || node.operator === SyntaxKind.MinusToken) + && isNumericLiteral(node.operand); } /** @@ -5047,7 +5503,9 @@ export function isSignedNumericLiteral(node: Node): node is PrefixUnaryExpressio * * @internal */ -export function hasDynamicName(declaration: Declaration): declaration is DynamicNamedDeclaration | DynamicNamedBinaryExpression { +export function hasDynamicName( + declaration: Declaration, +): declaration is DynamicNamedDeclaration | DynamicNamedBinaryExpression { const name = getNameOfDeclaration(declaration); return !!name && isDynamicName(name); } @@ -5058,8 +5516,8 @@ export function isDynamicName(name: DeclarationName): boolean { return false; } const expr = isElementAccessExpression(name) ? skipParentheses(name.argumentExpression) : name.expression; - return !isStringOrNumericLiteralLike(expr) && - !isSignedNumericLiteral(expr); + return !isStringOrNumericLiteralLike(expr) + && !isSignedNumericLiteral(expr); } /** @internal */ @@ -5109,7 +5567,8 @@ export function getTextOfIdentifierOrLiteral(node: PropertyNameLiteral | Private /** @internal */ export function getEscapedTextOfIdentifierOrLiteral(node: PropertyNameLiteral): __String { - return isMemberName(node) ? node.escapedText : isJsxNamespacedName(node) ? getEscapedTextOfJsxNamespacedName(node) : escapeLeadingUnderscores(node.text); + return isMemberName(node) ? node.escapedText + : isJsxNamespacedName(node) ? getEscapedTextOfJsxNamespacedName(node) : escapeLeadingUnderscores(node.text); } /** @internal */ @@ -5150,16 +5609,15 @@ export function isESSymbolIdentifier(node: Node): boolean { * @internal */ export function isProtoSetter(node: PropertyName) { - return isIdentifier(node) ? idText(node) === "__proto__" : - isStringLiteral(node) && node.text === "__proto__"; + return isIdentifier(node) ? idText(node) === "__proto__" + : isStringLiteral(node) && node.text === "__proto__"; } /** @internal */ export type AnonymousFunctionDefinition = - | ClassExpression & { readonly name?: undefined } - | FunctionExpression & { readonly name?: undefined } - | ArrowFunction - ; + | ClassExpression & { readonly name?: undefined; } + | FunctionExpression & { readonly name?: undefined; } + | ArrowFunction; /** * Indicates whether an expression is an anonymous function definition. @@ -5167,7 +5625,10 @@ export type AnonymousFunctionDefinition = * @see https://tc39.es/ecma262/#sec-isanonymousfunctiondefinition * @internal */ -export function isAnonymousFunctionDefinition(node: Expression, cb?: (node: AnonymousFunctionDefinition) => boolean): node is WrappedExpression { +export function isAnonymousFunctionDefinition( + node: Expression, + cb?: (node: AnonymousFunctionDefinition) => boolean, +): node is WrappedExpression { node = skipOuterExpressions(node); switch (node.kind) { case SyntaxKind.ClassExpression: @@ -5190,15 +5651,25 @@ export function isAnonymousFunctionDefinition(node: Expression, cb?: (node: Anon /** @internal */ export type NamedEvaluationSource = - | PropertyAssignment & { readonly name: Identifier } - | ShorthandPropertyAssignment & { readonly objectAssignmentInitializer: Expression } - | VariableDeclaration & { readonly name: Identifier, readonly initializer: Expression } - | ParameterDeclaration & { readonly name: Identifier, readonly initializer: Expression, readonly dotDotDotToken: undefined } - | BindingElement & { readonly name: Identifier, readonly initializer: Expression, readonly dotDotDotToken: undefined } - | PropertyDeclaration & { readonly initializer: Expression } - | AssignmentExpression & { readonly left: Identifier } - | ExportAssignment - ; + | PropertyAssignment & { readonly name: Identifier; } + | ShorthandPropertyAssignment & { readonly objectAssignmentInitializer: Expression; } + | VariableDeclaration & { readonly name: Identifier; readonly initializer: Expression; } + | ParameterDeclaration & { + readonly name: Identifier; + readonly initializer: Expression; + readonly dotDotDotToken: undefined; + } + | BindingElement & { + readonly name: Identifier; + readonly initializer: Expression; + readonly dotDotDotToken: undefined; + } + | PropertyDeclaration & { readonly initializer: Expression; } + | AssignmentExpression< + EqualsToken | AmpersandAmpersandEqualsToken | BarBarEqualsToken | QuestionQuestionEqualsToken + > + & { readonly left: Identifier; } + | ExportAssignment; /** * Indicates whether a node is a potential source of an assigned name for a class, function, or arrow function. @@ -5214,9 +5685,11 @@ export function isNamedEvaluationSource(node: Node): node is NamedEvaluationSour case SyntaxKind.VariableDeclaration: return isIdentifier((node as VariableDeclaration).name) && !!(node as VariableDeclaration).initializer; case SyntaxKind.Parameter: - return isIdentifier((node as ParameterDeclaration).name) && !!(node as VariableDeclaration).initializer && !(node as BindingElement).dotDotDotToken; + return isIdentifier((node as ParameterDeclaration).name) && !!(node as VariableDeclaration).initializer + && !(node as BindingElement).dotDotDotToken; case SyntaxKind.BindingElement: - return isIdentifier((node as BindingElement).name) && !!(node as VariableDeclaration).initializer && !(node as BindingElement).dotDotDotToken; + return isIdentifier((node as BindingElement).name) && !!(node as VariableDeclaration).initializer + && !(node as BindingElement).dotDotDotToken; case SyntaxKind.PropertyDeclaration: return !!(node as PropertyDeclaration).initializer; case SyntaxKind.BinaryExpression: @@ -5236,19 +5709,43 @@ export function isNamedEvaluationSource(node: Node): node is NamedEvaluationSour /** @internal */ export type NamedEvaluation = - | PropertyAssignment & { readonly name: Identifier, readonly initializer: WrappedExpression } - | ShorthandPropertyAssignment & { readonly objectAssignmentInitializer: WrappedExpression } - | VariableDeclaration & { readonly name: Identifier, readonly initializer: WrappedExpression } - | ParameterDeclaration & { readonly name: Identifier, readonly dotDotDotToken: undefined, readonly initializer: WrappedExpression } - | BindingElement & { readonly name: Identifier, readonly dotDotDotToken: undefined, readonly initializer: WrappedExpression } - | PropertyDeclaration & { readonly initializer: WrappedExpression } - | AssignmentExpression & { readonly left: Identifier, readonly right: WrappedExpression } - | AssignmentExpression & { readonly left: Identifier, readonly right: WrappedExpression } - | ExportAssignment & { readonly expression: WrappedExpression } - ; - -/** @internal */ -export function isNamedEvaluation(node: Node, cb?: (node: AnonymousFunctionDefinition) => boolean): node is NamedEvaluation { + | PropertyAssignment & { + readonly name: Identifier; + readonly initializer: WrappedExpression; + } + | ShorthandPropertyAssignment & { + readonly objectAssignmentInitializer: WrappedExpression; + } + | VariableDeclaration & { + readonly name: Identifier; + readonly initializer: WrappedExpression; + } + | ParameterDeclaration & { + readonly name: Identifier; + readonly dotDotDotToken: undefined; + readonly initializer: WrappedExpression; + } + | BindingElement & { + readonly name: Identifier; + readonly dotDotDotToken: undefined; + readonly initializer: WrappedExpression; + } + | PropertyDeclaration & { readonly initializer: WrappedExpression; } + | AssignmentExpression & { + readonly left: Identifier; + readonly right: WrappedExpression; + } + | AssignmentExpression & { + readonly left: Identifier; + readonly right: WrappedExpression; + } + | ExportAssignment & { readonly expression: WrappedExpression; }; + +/** @internal */ +export function isNamedEvaluation( + node: Node, + cb?: (node: AnonymousFunctionDefinition) => boolean, +): node is NamedEvaluation { if (!isNamedEvaluationSource(node)) return false; switch (node.kind) { case SyntaxKind.PropertyAssignment: @@ -5326,13 +5823,14 @@ export function getOriginalSourceFile(sourceFile: SourceFile) { /** @internal */ export const enum Associativity { Left, - Right + Right, } /** @internal */ export function getExpressionAssociativity(expression: Expression) { const operator = getOperator(expression); - const hasArguments = expression.kind === SyntaxKind.NewExpression && (expression as NewExpression).arguments !== undefined; + const hasArguments = expression.kind === SyntaxKind.NewExpression + && (expression as NewExpression).arguments !== undefined; return getOperatorAssociativity(expression.kind, operator, hasArguments); } @@ -5379,7 +5877,8 @@ export function getOperatorAssociativity(kind: SyntaxKind, operator: SyntaxKind, /** @internal */ export function getExpressionPrecedence(expression: Expression) { const operator = getOperator(expression); - const hasArguments = expression.kind === SyntaxKind.NewExpression && (expression as NewExpression).arguments !== undefined; + const hasArguments = expression.kind === SyntaxKind.NewExpression + && (expression as NewExpression).arguments !== undefined; return getOperatorPrecedence(expression.kind, operator, hasArguments); } @@ -5388,7 +5887,9 @@ export function getOperator(expression: Expression): SyntaxKind { if (expression.kind === SyntaxKind.BinaryExpression) { return (expression as BinaryExpression).operatorToken.kind; } - else if (expression.kind === SyntaxKind.PrefixUnaryExpression || expression.kind === SyntaxKind.PostfixUnaryExpression) { + else if ( + expression.kind === SyntaxKind.PrefixUnaryExpression || expression.kind === SyntaxKind.PostfixUnaryExpression + ) { return (expression as PrefixUnaryExpression | PostfixUnaryExpression).operator; } else { @@ -5533,7 +6034,6 @@ export const enum OperatorPrecedence { // `--` UnaryExpression Unary, - // UpdateExpression: // LeftHandSideExpression // LeftHandSideExpression `++` @@ -5843,7 +6343,8 @@ function containsInvalidEscapeFlag(node: TemplateLiteralToken): boolean { export function hasInvalidEscape(template: TemplateLiteral): boolean { return template && !!(isNoSubstitutionTemplateLiteral(template) ? containsInvalidEscapeFlag(template) - : (containsInvalidEscapeFlag(template.head) || some(template.templateSpans, span => containsInvalidEscapeFlag(span.literal)))); + : (containsInvalidEscapeFlag(template.head) + || some(template.templateSpans, span => containsInvalidEscapeFlag(span.literal)))); } // This consists of the first 19 unprintable ASCII characters, canonical escapes, lineSeparator, @@ -5863,7 +6364,7 @@ const escapedCharsMap = new Map(Object.entries({ "\r": "\\r", "\n": "\\n", "\\": "\\\\", - "\"": "\\\"", + '"': '\\"', "'": "\\'", "`": "\\`", "\u2028": "\\u2028", // lineSeparator @@ -5898,23 +6399,28 @@ function getReplacement(c: string, offset: number, input: string) { * * @internal */ -export function escapeString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string { - const escapedCharsRegExp = - quoteChar === CharacterCodes.backtick ? backtickQuoteEscapedCharsRegExp : - quoteChar === CharacterCodes.singleQuote ? singleQuoteEscapedCharsRegExp : - doubleQuoteEscapedCharsRegExp; +export function escapeString( + s: string, + quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick, +): string { + const escapedCharsRegExp = quoteChar === CharacterCodes.backtick ? backtickQuoteEscapedCharsRegExp + : quoteChar === CharacterCodes.singleQuote ? singleQuoteEscapedCharsRegExp + : doubleQuoteEscapedCharsRegExp; return s.replace(escapedCharsRegExp, getReplacement); } const nonAsciiCharacters = /[^\u0000-\u007F]/g; /** @internal */ -export function escapeNonAsciiString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string { +export function escapeNonAsciiString( + s: string, + quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick, +): string { s = escapeString(s, quoteChar); // Replace non-ASCII characters with '\uNNNN' escapes if any exist. // Otherwise just return the original string. - return nonAsciiCharacters.test(s) ? - s.replace(nonAsciiCharacters, c => encodeUtf16EscapeSequence(c.charCodeAt(0))) : - s; + return nonAsciiCharacters.test(s) + ? s.replace(nonAsciiCharacters, c => encodeUtf16EscapeSequence(c.charCodeAt(0))) + : s; } // This consists of the first 19 unprintable ASCII characters, JSX canonical escapes, lineSeparator, @@ -5924,8 +6430,8 @@ export function escapeNonAsciiString(s: string, quoteChar?: CharacterCodes.doubl const jsxDoubleQuoteEscapedCharsRegExp = /["\u0000-\u001f\u2028\u2029\u0085]/g; const jsxSingleQuoteEscapedCharsRegExp = /['\u0000-\u001f\u2028\u2029\u0085]/g; const jsxEscapedCharsMap = new Map(Object.entries({ - "\"": """, - "'": "'" + '"': """, + "'": "'", })); function encodeJsxCharacterEntity(charCode: number): string { @@ -5941,10 +6447,12 @@ function getJsxAttributeStringReplacement(c: string) { } /** @internal */ -export function escapeJsxAttributeString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote) { - const escapedCharsRegExp = - quoteChar === CharacterCodes.singleQuote ? jsxSingleQuoteEscapedCharsRegExp : - jsxDoubleQuoteEscapedCharsRegExp; +export function escapeJsxAttributeString( + s: string, + quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote, +) { + const escapedCharsRegExp = quoteChar === CharacterCodes.singleQuote ? jsxSingleQuoteEscapedCharsRegExp + : jsxDoubleQuoteEscapedCharsRegExp; return s.replace(escapedCharsRegExp, getJsxAttributeStringReplacement); } @@ -5964,15 +6472,15 @@ export function stripQuotes(name: string) { } function isQuoteOrBacktick(charCode: number) { - return charCode === CharacterCodes.singleQuote || - charCode === CharacterCodes.doubleQuote || - charCode === CharacterCodes.backtick; + return charCode === CharacterCodes.singleQuote + || charCode === CharacterCodes.doubleQuote + || charCode === CharacterCodes.backtick; } /** @internal */ export function isIntrinsicJsxName(name: __String | string) { const ch = (name as string).charCodeAt(0); - return (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || stringContains((name as string), "-"); + return (ch >= CharacterCodes.a && ch <= CharacterCodes.z) || stringContains(name as string, "-"); } const indentStrings: string[] = ["", " "]; @@ -6086,8 +6594,12 @@ export function createTextWriter(newLine: string): EmitTextWriter { rawWrite, writeLiteral, writeLine, - increaseIndent: () => { indent++; }, - decreaseIndent: () => { indent--; }, + increaseIndent: () => { + indent++; + }, + decreaseIndent: () => { + indent--; + }, getIndent: () => indent, getTextPos: () => output.length, getLine: () => lineCount, @@ -6107,7 +6619,7 @@ export function createTextWriter(newLine: string): EmitTextWriter { writeSymbol: (s, _) => write(s), writeTrailingSemicolon: write, writeComment, - getTextPosWithWriteLine + getTextPosWithWriteLine, }; } @@ -6200,8 +6712,13 @@ export interface ResolveModuleNameResolutionHost { } /** @internal */ -export function getResolvedExternalModuleName(host: ResolveModuleNameResolutionHost, file: SourceFile, referenceFile?: SourceFile): string { - return file.moduleName || getExternalModuleNameFromPath(host, file.fileName, referenceFile && referenceFile.fileName); +export function getResolvedExternalModuleName( + host: ResolveModuleNameResolutionHost, + file: SourceFile, + referenceFile?: SourceFile, +): string { + return file.moduleName + || getExternalModuleNameFromPath(host, file.fileName, referenceFile && referenceFile.fileName); } function getCanonicalAbsolutePath(host: ResolveModuleNameResolutionHost, path: string) { @@ -6209,15 +6726,23 @@ function getCanonicalAbsolutePath(host: ResolveModuleNameResolutionHost, path: s } /** @internal */ -export function getExternalModuleNameFromDeclaration(host: ResolveModuleNameResolutionHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string | undefined { +export function getExternalModuleNameFromDeclaration( + host: ResolveModuleNameResolutionHost, + resolver: EmitResolver, + declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode, +): string | undefined { const file = resolver.getExternalModuleFileFromDeclaration(declaration); if (!file || file.isDeclarationFile) { return undefined; } // If the declaration already uses a non-relative name, and is outside the common source directory, continue to use it const specifier = getExternalModuleName(declaration); - if (specifier && isStringLiteralLike(specifier) && !pathIsRelative(specifier.text) && - getCanonicalAbsolutePath(host, file.path).indexOf(getCanonicalAbsolutePath(host, ensureTrailingDirectorySeparator(host.getCommonSourceDirectory()))) === -1) { + if ( + specifier && isStringLiteralLike(specifier) && !pathIsRelative(specifier.text) + && getCanonicalAbsolutePath(host, file.path).indexOf( + getCanonicalAbsolutePath(host, ensureTrailingDirectorySeparator(host.getCommonSourceDirectory())), + ) === -1 + ) { return undefined; } return getResolvedExternalModuleName(host, file); @@ -6228,11 +6753,25 @@ export function getExternalModuleNameFromDeclaration(host: ResolveModuleNameReso * * @internal */ -export function getExternalModuleNameFromPath(host: ResolveModuleNameResolutionHost, fileName: string, referencePath?: string): string { +export function getExternalModuleNameFromPath( + host: ResolveModuleNameResolutionHost, + fileName: string, + referencePath?: string, +): string { const getCanonicalFileName = (f: string) => host.getCanonicalFileName(f); - const dir = toPath(referencePath ? getDirectoryPath(referencePath) : host.getCommonSourceDirectory(), host.getCurrentDirectory(), getCanonicalFileName); + const dir = toPath( + referencePath ? getDirectoryPath(referencePath) : host.getCommonSourceDirectory(), + host.getCurrentDirectory(), + getCanonicalFileName, + ); const filePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory()); - const relativePath = getRelativePathToDirectoryOrUrl(dir, filePath, dir, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); + const relativePath = getRelativePathToDirectoryOrUrl( + dir, + filePath, + dir, + getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false, + ); const extensionless = removeFileExtension(relativePath); return referencePath ? ensurePathIsNonModuleName(extensionless) : extensionless; } @@ -6242,7 +6781,9 @@ export function getOwnEmitOutputFilePath(fileName: string, host: EmitHost, exten const compilerOptions = host.getCompilerOptions(); let emitOutputFilePathWithoutExtension: string; if (compilerOptions.outDir) { - emitOutputFilePathWithoutExtension = removeFileExtension(getSourceFilePathInNewDir(fileName, host, compilerOptions.outDir)); + emitOutputFilePathWithoutExtension = removeFileExtension( + getSourceFilePathInNewDir(fileName, host, compilerOptions.outDir), + ); } else { emitOutputFilePathWithoutExtension = removeFileExtension(fileName); @@ -6253,15 +6794,33 @@ 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.getCurrentDirectory(), + host.getCommonSourceDirectory(), + f => host.getCanonicalFileName(f), + ); } /** @internal */ -export function getDeclarationEmitOutputFilePathWorker(fileName: string, options: CompilerOptions, currentDirectory: string, commonSourceDirectory: string, getCanonicalFileName: GetCanonicalFileName): string { +export function getDeclarationEmitOutputFilePathWorker( + fileName: string, + options: CompilerOptions, + currentDirectory: string, + commonSourceDirectory: string, + getCanonicalFileName: 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, + currentDirectory, + commonSourceDirectory, + getCanonicalFileName, + ) : fileName; const declarationExtension = getDeclarationEmitExtensionForPath(path); return removeFileExtension(path) + declarationExtension; @@ -6269,10 +6828,10 @@ export function getDeclarationEmitOutputFilePathWorker(fileName: string, options /** @internal */ export function getDeclarationEmitExtensionForPath(path: string) { - return fileExtensionIsOneOf(path, [Extension.Mjs, Extension.Mts]) ? Extension.Dmts : - fileExtensionIsOneOf(path, [Extension.Cjs, Extension.Cts]) ? Extension.Dcts : - fileExtensionIsOneOf(path, [Extension.Json]) ? `.d.json.ts` : // Drive-by redefinition of json declaration file output name so if it's ever enabled, it behaves well - Extension.Dts; + return fileExtensionIsOneOf(path, [Extension.Mjs, Extension.Mts]) ? Extension.Dmts + : fileExtensionIsOneOf(path, [Extension.Cjs, Extension.Cts]) ? Extension.Dcts + : fileExtensionIsOneOf(path, [Extension.Json]) ? `.d.json.ts` // Drive-by redefinition of json declaration file output name so if it's ever enabled, it behaves well + : Extension.Dts; } /** @@ -6281,10 +6840,10 @@ export function getDeclarationEmitExtensionForPath(path: string) { * @internal */ export function getPossibleOriginalInputExtensionForExtension(path: string) { - return fileExtensionIsOneOf(path, [Extension.Dmts, Extension.Mjs, Extension.Mts]) ? [Extension.Mts, Extension.Mjs] : - fileExtensionIsOneOf(path, [Extension.Dcts, Extension.Cjs, Extension.Cts]) ? [Extension.Cts, Extension.Cjs]: - fileExtensionIsOneOf(path, [`.d.json.ts`]) ? [Extension.Json] : - [Extension.Tsx, Extension.Ts, Extension.Jsx, Extension.Js]; + return fileExtensionIsOneOf(path, [Extension.Dmts, Extension.Mjs, Extension.Mts]) ? [Extension.Mts, Extension.Mjs] + : fileExtensionIsOneOf(path, [Extension.Dcts, Extension.Cjs, Extension.Cts]) ? [Extension.Cts, Extension.Cjs] + : fileExtensionIsOneOf(path, [`.d.json.ts`]) ? [Extension.Json] + : [Extension.Tsx, Extension.Ts, Extension.Jsx, Extension.Js]; } /** @internal */ @@ -6297,9 +6856,13 @@ export function outFile(options: CompilerOptions) { * * @internal */ -export function getPathsBasePath(options: CompilerOptions, host: { getCurrentDirectory?(): string }) { +export function getPathsBasePath(options: CompilerOptions, host: { getCurrentDirectory?(): string; }) { if (!options.paths) return undefined; - return options.baseUrl ?? Debug.checkDefined(options.pathsBasePath || host.getCurrentDirectory?.(), "Encountered 'paths' without a 'baseUrl', config file, or host 'getCurrentDirectory'."); + return options.baseUrl + ?? Debug.checkDefined( + options.pathsBasePath || host.getCurrentDirectory?.(), + "Encountered 'paths' without a 'baseUrl', config file, or host 'getCurrentDirectory'.", + ); } /** @internal */ @@ -6322,24 +6885,29 @@ export interface EmitFileNames { * * @internal */ -export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile, forceDtsEmit?: boolean): readonly SourceFile[] { +export function getSourceFilesToEmit( + host: EmitHost, + targetSourceFile?: SourceFile, + forceDtsEmit?: boolean, +): readonly SourceFile[] { const options = host.getCompilerOptions(); if (outFile(options)) { const moduleKind = getEmitModuleKind(options); - const moduleEmitEnabled = options.emitDeclarationOnly || moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System; + const moduleEmitEnabled = options.emitDeclarationOnly || moduleKind === ModuleKind.AMD + || moduleKind === ModuleKind.System; // Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified return filter( host.getSourceFiles(), sourceFile => - (moduleEmitEnabled || !isExternalModule(sourceFile)) && - sourceFileMayBeEmitted(sourceFile, host, forceDtsEmit) + (moduleEmitEnabled || !isExternalModule(sourceFile)) + && sourceFileMayBeEmitted(sourceFile, host, forceDtsEmit), ); } else { const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile]; return filter( sourceFiles, - sourceFile => sourceFileMayBeEmitted(sourceFile, host, forceDtsEmit) + sourceFile => sourceFileMayBeEmitted(sourceFile, host, forceDtsEmit), ); } } @@ -6349,41 +6917,77 @@ export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFi * * @internal */ -export function sourceFileMayBeEmitted(sourceFile: SourceFile, host: SourceFileMayBeEmittedHost, forceDtsEmit?: boolean) { +export function sourceFileMayBeEmitted( + sourceFile: SourceFile, + host: SourceFileMayBeEmittedHost, + forceDtsEmit?: boolean, +) { const options = host.getCompilerOptions(); - return !(options.noEmitForJsFiles && isSourceFileJS(sourceFile)) && - !sourceFile.isDeclarationFile && - !host.isSourceFileFromExternalLibrary(sourceFile) && - (forceDtsEmit || ( - !(isJsonSourceFile(sourceFile) && host.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) && - !host.isSourceOfProjectReferenceRedirect(sourceFile.fileName) + return !(options.noEmitForJsFiles && isSourceFileJS(sourceFile)) + && !sourceFile.isDeclarationFile + && !host.isSourceFileFromExternalLibrary(sourceFile) + && (forceDtsEmit || ( + !(isJsonSourceFile(sourceFile) && host.getResolvedProjectReferenceToRedirect(sourceFile.fileName)) + && !host.isSourceOfProjectReferenceRedirect(sourceFile.fileName) )); } /** @internal */ export function getSourceFilePathInNewDir(fileName: string, host: EmitHost, newDirPath: string): string { - return getSourceFilePathInNewDirWorker(fileName, newDirPath, host.getCurrentDirectory(), host.getCommonSourceDirectory(), f => host.getCanonicalFileName(f)); + 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 { +export 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; + const isSourceFileInCommonSourceDirectory = + getCanonicalFileName(sourceFilePath).indexOf(getCanonicalFileName(commonSourceDirectory)) === 0; + sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) + : sourceFilePath; return combinePaths(newDirPath, sourceFilePath); } /** @internal */ -export function writeFile(host: { writeFile: WriteFileCallback; }, diagnostics: DiagnosticCollection, fileName: string, text: string, writeByteOrderMark: boolean, sourceFiles?: readonly SourceFile[], data?: WriteFileCallbackData) { - host.writeFile(fileName, text, writeByteOrderMark, hostErrorMessage => { - diagnostics.add(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage)); - }, sourceFiles, data); +export function writeFile( + host: { writeFile: WriteFileCallback; }, + diagnostics: DiagnosticCollection, + fileName: string, + text: string, + writeByteOrderMark: boolean, + sourceFiles?: readonly SourceFile[], + data?: WriteFileCallbackData, +) { + host.writeFile( + fileName, + text, + writeByteOrderMark, + hostErrorMessage => { + diagnostics.add( + createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage), + ); + }, + sourceFiles, + data, + ); } function ensureDirectoriesExist( directoryPath: string, createDirectory: (path: string) => void, - directoryExists: (path: string) => boolean): void { + directoryExists: (path: string) => boolean, +): void { if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) { const parentDirectory = getDirectoryPath(directoryPath); ensureDirectoriesExist(parentDirectory, createDirectory, directoryExists); @@ -6398,8 +7002,8 @@ export function writeFileEnsuringDirectories( writeByteOrderMark: boolean, writeFile: (path: string, data: string, writeByteOrderMark: boolean) => void, createDirectory: (path: string) => void, - directoryExists: (path: string) => boolean): void { - + directoryExists: (path: string) => boolean, +): void { // PERF: Checking for directory existence is expensive. Instead, assume the directory exists // and fall back to creating it if the file write fails. try { @@ -6423,8 +7027,14 @@ export function getLineOfLocalPositionFromLineMap(lineMap: readonly number[], po } /** @internal */ -export function getFirstConstructorWithBody(node: ClassLikeDeclaration): ConstructorDeclaration & { body: FunctionBody } | undefined { - return find(node.members, (member): member is ConstructorDeclaration & { body: FunctionBody } => isConstructorDeclaration(member) && nodeIsPresent(member.body)); +export function getFirstConstructorWithBody( + node: ClassLikeDeclaration, +): ConstructorDeclaration & { body: FunctionBody; } | undefined { + return find( + node.members, + (member): member is ConstructorDeclaration & { body: FunctionBody; } => + isConstructorDeclaration(member) && nodeIsPresent(member.body), + ); } /** @internal */ @@ -6473,7 +7083,9 @@ export function isInTypeQuery(node: Node): boolean { // The expression is restricted to a single identifier or a sequence of identifiers separated by periods return !!findAncestor( node, - n => n.kind === SyntaxKind.TypeQuery ? true : n.kind === SyntaxKind.Identifier || n.kind === SyntaxKind.QualifiedName ? false : "quit"); + n => n.kind === SyntaxKind.TypeQuery ? true + : n.kind === SyntaxKind.Identifier || n.kind === SyntaxKind.QualifiedName ? false : "quit", + ); } /** @internal */ @@ -6495,7 +7107,10 @@ export function identifierIsThisKeyword(id: Identifier): boolean { } /** @internal */ -export function getAllAccessorDeclarations(declarations: readonly Declaration[], accessor: AccessorDeclaration): AllAccessorDeclarations { +export function getAllAccessorDeclarations( + declarations: readonly Declaration[], + accessor: AccessorDeclaration, +): AllAccessorDeclarations { // TODO: GH#18217 let firstAccessor!: AccessorDeclaration; let secondAccessor!: AccessorDeclaration; @@ -6515,8 +7130,10 @@ export function getAllAccessorDeclarations(declarations: readonly Declaration[], } else { forEach(declarations, member => { - if (isAccessor(member) - && isStatic(member) === isStatic(accessor)) { + if ( + isAccessor(member) + && isStatic(member) === isStatic(accessor) + ) { const memberName = getPropertyNameForPropertyNameNode(member.name); const accessorName = getPropertyNameForPropertyNameNode(accessor.name); if (memberName === accessorName) { @@ -6542,7 +7159,7 @@ export function getAllAccessorDeclarations(declarations: readonly Declaration[], firstAccessor, secondAccessor, getAccessor, - setAccessor + setAccessor, }; } @@ -6572,19 +7189,23 @@ export function getTypeAnnotationNode(node: Node): TypeNode | undefined { * @internal */ export function getEffectiveReturnTypeNode(node: SignatureDeclaration | JSDocSignature): TypeNode | undefined { - return isJSDocSignature(node) ? - node.type && node.type.typeExpression && node.type.typeExpression.type : - node.type || (isInJSFile(node) ? getJSDocReturnType(node) : undefined); + return isJSDocSignature(node) + ? node.type && node.type.typeExpression && node.type.typeExpression.type + : node.type || (isInJSFile(node) ? getJSDocReturnType(node) : undefined); } /** @internal */ -export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] { +export function getJSDocTypeParameterDeclarations( + node: DeclarationWithTypeParameters, +): readonly TypeParameterDeclaration[] { return flatMap(getJSDocTags(node), tag => isNonTypeAliasTemplate(tag) ? tag.typeParameters : undefined); } /** template tags are only available when a typedef isn't already using them */ function isNonTypeAliasTemplate(tag: JSDocTag): tag is JSDocTemplateTag { - return isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDoc && (tag.parent.tags!.some(isJSDocTypeAlias) || tag.parent.tags!.some(isJSDocOverloadTag))); + return isJSDocTemplateTag(tag) + && !(tag.parent.kind === SyntaxKind.JSDoc + && (tag.parent.tags!.some(isJSDocTypeAlias) || tag.parent.tags!.some(isJSDocOverloadTag))); } /** @@ -6599,24 +7220,44 @@ export function getEffectiveSetAccessorTypeAnnotationNode(node: SetAccessorDecla } /** @internal */ -export function emitNewLineBeforeLeadingComments(lineMap: readonly number[], writer: EmitTextWriter, node: TextRange, leadingComments: readonly CommentRange[] | undefined) { +export 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) { +export 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 && - getLineOfLocalPositionFromLineMap(lineMap, pos) !== getLineOfLocalPositionFromLineMap(lineMap, leadingComments[0].pos)) { + if ( + leadingComments && leadingComments.length && pos !== leadingComments[0].pos + && getLineOfLocalPositionFromLineMap(lineMap, pos) + !== getLineOfLocalPositionFromLineMap(lineMap, leadingComments[0].pos) + ) { writer.writeLine(); } } /** @internal */ -export function emitNewLineBeforeLeadingCommentOfPosition(lineMap: readonly number[], writer: EmitTextWriter, pos: number, commentPos: number) { +export function emitNewLineBeforeLeadingCommentOfPosition( + lineMap: readonly number[], + writer: EmitTextWriter, + pos: number, + commentPos: number, +) { // If the leading comments start on different line than the start of node, write new line - if (pos !== commentPos && - getLineOfLocalPositionFromLineMap(lineMap, pos) !== getLineOfLocalPositionFromLineMap(lineMap, commentPos)) { + if ( + pos !== commentPos + && getLineOfLocalPositionFromLineMap(lineMap, pos) !== getLineOfLocalPositionFromLineMap(lineMap, commentPos) + ) { writer.writeLine(); } } @@ -6630,7 +7271,15 @@ export function emitComments( leadingSeparator: boolean, trailingSeparator: boolean, newLine: string, - writeComment: (text: string, lineMap: readonly number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void) { + writeComment: ( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + commentPos: number, + commentEnd: number, + newLine: string, + ) => void, +) { if (comments && comments.length > 0) { if (leadingSeparator) { writer.writeSpace(" "); @@ -6664,11 +7313,24 @@ export function emitComments( * * @internal */ -export function emitDetachedComments(text: string, lineMap: readonly number[], writer: EmitTextWriter, - writeComment: (text: string, lineMap: readonly number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void, - node: TextRange, newLine: string, removeComments: boolean) { +export function emitDetachedComments( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + writeComment: ( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + commentPos: number, + commentEnd: number, + newLine: string, + ) => void, + node: TextRange, + newLine: string, + removeComments: boolean, +) { let leadingComments: CommentRange[] | undefined; - let currentDetachedCommentInfo: { nodePos: number, detachedCommentEndPos: number } | undefined; + let currentDetachedCommentInfo: { nodePos: number; detachedCommentEndPos: number; } | undefined; if (removeComments) { // removeComments is true, only reserve pinned comment at the top of file // For example: @@ -6714,7 +7376,16 @@ export function emitDetachedComments(text: string, lineMap: readonly number[], w if (nodeLine >= lastCommentLine + 2) { // Valid detachedComments emitNewLineBeforeLeadingComments(lineMap, writer, node, leadingComments); - emitComments(text, lineMap, writer, detachedComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); + emitComments( + text, + lineMap, + writer, + detachedComments, + /*leadingSeparator*/ false, + /*trailingSeparator*/ true, + newLine, + writeComment, + ); currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: last(detachedComments).end }; } } @@ -6725,11 +7396,17 @@ export function emitDetachedComments(text: string, lineMap: readonly number[], w function isPinnedCommentLocal(comment: CommentRange) { return isPinnedComment(text, comment.pos); } - } /** @internal */ -export function writeCommentRange(text: string, lineMap: readonly number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) { +export function writeCommentRange( + text: string, + lineMap: readonly number[], + writer: EmitTextWriter, + commentPos: number, + commentEnd: number, + newLine: string, +) { if (text.charCodeAt(commentPos + 1) === CharacterCodes.asterisk) { const firstCommentLineAndCharacter = computeLineAndCharacterOfPosition(lineMap, commentPos); const lineCount = lineMap.length; @@ -6742,7 +7419,11 @@ export function writeCommentRange(text: string, lineMap: readonly number[], writ if (pos !== commentPos) { // If we are not emitting first line, we need to write the spaces to adjust the alignment if (firstCommentLineIndent === undefined) { - firstCommentLineIndent = calculateIndent(text, lineMap[firstCommentLineAndCharacter.line], commentPos); + firstCommentLineIndent = calculateIndent( + text, + lineMap[firstCommentLineAndCharacter.line], + commentPos, + ); } // These are number of spaces writer is going to write at current indent @@ -6762,10 +7443,13 @@ export function writeCommentRange(text: string, lineMap: readonly number[], writ // More right indented comment */ --4 = 8 - 4 + 11 // class c { } // } - const spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + calculateIndent(text, pos, nextLineStart); + const spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + + calculateIndent(text, pos, nextLineStart); if (spacesToEmit > 0) { let numberOfSingleSpacesToEmit = spacesToEmit % getIndentSize(); - const indentSizeSpaceString = getIndentString((spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize()); + const indentSizeSpaceString = getIndentString( + (spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize(), + ); // Write indent size string ( in eg 1: = "", 2: "" , 3: string with 8 spaces 4: string with 12 spaces writer.rawWrite(indentSizeSpaceString); @@ -6794,7 +7478,14 @@ export function writeCommentRange(text: string, lineMap: readonly number[], writ } } -function writeTrimmedCurrentLine(text: string, commentEnd: number, writer: EmitTextWriter, newLine: string, pos: number, nextLineStart: number) { +function writeTrimmedCurrentLine( + text: string, + commentEnd: number, + writer: EmitTextWriter, + newLine: string, + pos: number, + nextLineStart: number, +) { const end = Math.min(commentEnd, nextLineStart - 1); const currentLineText = trimString(text.substring(pos, end)); if (currentLineText) { @@ -6906,7 +7597,10 @@ function getModifierFlagsWorker(node: Node, includeJSDoc: boolean, alwaysInclude node.modifierFlagsCache = getSyntacticModifierFlagsNoCache(node) | ModifierFlags.HasComputedFlags; } - if (includeJSDoc && !(node.modifierFlagsCache & ModifierFlags.HasComputedJSDocModifiers) && (alwaysIncludeJSDoc || isInJSFile(node)) && node.parent) { + if ( + includeJSDoc && !(node.modifierFlagsCache & ModifierFlags.HasComputedJSDocModifiers) + && (alwaysIncludeJSDoc || isInJSFile(node)) && node.parent + ) { node.modifierFlagsCache |= getJSDocModifierFlagsNoCache(node) | ModifierFlags.HasComputedJSDocModifiers; } @@ -6976,7 +7670,10 @@ export function getEffectiveModifierFlagsNoCache(node: Node): ModifierFlags { */ export function getSyntacticModifierFlagsNoCache(node: Node): ModifierFlags { let flags = canHaveModifiers(node) ? modifiersToFlags(node.modifiers) : ModifierFlags.None; - if (node.flags & NodeFlags.NestedNamespace || node.kind === SyntaxKind.Identifier && node.flags & NodeFlags.IdentifierIsInJSDocNamespace) { + if ( + node.flags & NodeFlags.NestedNamespace + || node.kind === SyntaxKind.Identifier && node.flags & NodeFlags.IdentifierIsInJSDocNamespace + ) { flags |= ModifierFlags.Export; } return flags; @@ -6996,22 +7693,38 @@ export function modifiersToFlags(modifiers: readonly ModifierLike[] | undefined) /** @internal */ export function modifierToFlag(token: SyntaxKind): ModifierFlags { switch (token) { - case SyntaxKind.StaticKeyword: return ModifierFlags.Static; - case SyntaxKind.PublicKeyword: return ModifierFlags.Public; - case SyntaxKind.ProtectedKeyword: return ModifierFlags.Protected; - case SyntaxKind.PrivateKeyword: return ModifierFlags.Private; - case SyntaxKind.AbstractKeyword: return ModifierFlags.Abstract; - case SyntaxKind.AccessorKeyword: return ModifierFlags.Accessor; - case SyntaxKind.ExportKeyword: return ModifierFlags.Export; - case SyntaxKind.DeclareKeyword: return ModifierFlags.Ambient; - case SyntaxKind.ConstKeyword: return ModifierFlags.Const; - case SyntaxKind.DefaultKeyword: return ModifierFlags.Default; - case SyntaxKind.AsyncKeyword: return ModifierFlags.Async; - case SyntaxKind.ReadonlyKeyword: return ModifierFlags.Readonly; - case SyntaxKind.OverrideKeyword: return ModifierFlags.Override; - case SyntaxKind.InKeyword: return ModifierFlags.In; - case SyntaxKind.OutKeyword: return ModifierFlags.Out; - case SyntaxKind.Decorator: return ModifierFlags.Decorator; + case SyntaxKind.StaticKeyword: + return ModifierFlags.Static; + case SyntaxKind.PublicKeyword: + return ModifierFlags.Public; + case SyntaxKind.ProtectedKeyword: + return ModifierFlags.Protected; + case SyntaxKind.PrivateKeyword: + return ModifierFlags.Private; + case SyntaxKind.AbstractKeyword: + return ModifierFlags.Abstract; + case SyntaxKind.AccessorKeyword: + return ModifierFlags.Accessor; + case SyntaxKind.ExportKeyword: + return ModifierFlags.Export; + case SyntaxKind.DeclareKeyword: + return ModifierFlags.Ambient; + case SyntaxKind.ConstKeyword: + return ModifierFlags.Const; + case SyntaxKind.DefaultKeyword: + return ModifierFlags.Default; + case SyntaxKind.AsyncKeyword: + return ModifierFlags.Async; + case SyntaxKind.ReadonlyKeyword: + return ModifierFlags.Readonly; + case SyntaxKind.OverrideKeyword: + return ModifierFlags.Override; + case SyntaxKind.InKeyword: + return ModifierFlags.In; + case SyntaxKind.OutKeyword: + return ModifierFlags.Out; + case SyntaxKind.Decorator: + return ModifierFlags.Decorator; } return ModifierFlags.None; } @@ -7026,19 +7739,25 @@ export function isLogicalOperator(token: SyntaxKind): boolean { } /** @internal */ -export function isLogicalOrCoalescingAssignmentOperator(token: SyntaxKind): token is LogicalOrCoalescingAssignmentOperator { +export function isLogicalOrCoalescingAssignmentOperator( + token: SyntaxKind, +): token is LogicalOrCoalescingAssignmentOperator { return token === SyntaxKind.BarBarEqualsToken || token === SyntaxKind.AmpersandAmpersandEqualsToken || token === SyntaxKind.QuestionQuestionEqualsToken; } /** @internal */ -export function isLogicalOrCoalescingAssignmentExpression(expr: Node): expr is AssignmentExpression> { +export function isLogicalOrCoalescingAssignmentExpression( + expr: Node, +): expr is AssignmentExpression> { return isBinaryExpression(expr) && isLogicalOrCoalescingAssignmentOperator(expr.operatorToken.kind); } /** @internal */ -export function isLogicalOrCoalescingBinaryOperator(token: SyntaxKind): token is LogicalOperator | SyntaxKind.QuestionQuestionToken { +export function isLogicalOrCoalescingBinaryOperator( + token: SyntaxKind, +): token is LogicalOperator | SyntaxKind.QuestionQuestionToken { return isBinaryLogicalOperator(token) || token === SyntaxKind.QuestionQuestionToken; } @@ -7068,7 +7787,9 @@ export interface ClassImplementingOrExtendingExpressionWithTypeArguments { readonly isImplements: boolean; } /** @internal */ -export function tryGetClassImplementingOrExtendingExpressionWithTypeArguments(node: Node): ClassImplementingOrExtendingExpressionWithTypeArguments | undefined { +export function tryGetClassImplementingOrExtendingExpressionWithTypeArguments( + node: Node, +): ClassImplementingOrExtendingExpressionWithTypeArguments | undefined { if (isExpressionWithTypeArguments(node)) { if (isHeritageClause(node.parent) && isClassLike(node.parent.parent)) { return { class: node.parent.parent, isImplements: node.parent.token === SyntaxKind.ImplementsKeyword }; @@ -7084,11 +7805,20 @@ export function tryGetClassImplementingOrExtendingExpressionWithTypeArguments(no } /** @internal */ -export function isAssignmentExpression(node: Node, excludeCompoundAssignment: true): node is AssignmentExpression; +export function isAssignmentExpression( + node: Node, + excludeCompoundAssignment: true, +): node is AssignmentExpression; /** @internal */ -export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: false): node is AssignmentExpression; +export function isAssignmentExpression( + node: Node, + excludeCompoundAssignment?: false, +): node is AssignmentExpression; /** @internal */ -export function isAssignmentExpression(node: Node, excludeCompoundAssignment?: boolean): node is AssignmentExpression { +export function isAssignmentExpression( + node: Node, + excludeCompoundAssignment?: boolean, +): node is AssignmentExpression { return isBinaryExpression(node) && (excludeCompoundAssignment ? node.operatorToken.kind === SyntaxKind.EqualsToken @@ -7129,12 +7859,14 @@ export function getFirstIdentifier(node: EntityNameOrEntityNameExpression): Iden case SyntaxKind.QualifiedName: do { node = node.left; - } while (node.kind !== SyntaxKind.Identifier); + } + while (node.kind !== SyntaxKind.Identifier); return node; case SyntaxKind.PropertyAccessExpression: do { node = node.expression; - } while (node.kind !== SyntaxKind.Identifier); + } + while (node.kind !== SyntaxKind.Identifier); return node; } } @@ -7145,8 +7877,10 @@ export function isDottedName(node: Expression): boolean { || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword || node.kind === SyntaxKind.MetaProperty - || node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((node as PropertyAccessExpression).expression) - || node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((node as ParenthesizedExpression).expression); + || node.kind === SyntaxKind.PropertyAccessExpression + && isDottedName((node as PropertyAccessExpression).expression) + || node.kind === SyntaxKind.ParenthesizedExpression + && isDottedName((node as ParenthesizedExpression).expression); } /** @internal */ @@ -7184,9 +7918,10 @@ export function isPrototypeAccess(node: Node): node is BindableStaticAccessExpre /** @internal */ export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) { - return (node.parent.kind === SyntaxKind.QualifiedName && (node.parent as QualifiedName).right === node) || - (node.parent.kind === SyntaxKind.PropertyAccessExpression && (node.parent as PropertyAccessExpression).name === node) || - (node.parent.kind === SyntaxKind.MetaProperty && (node.parent as MetaProperty).name === node); + return (node.parent.kind === SyntaxKind.QualifiedName && (node.parent as QualifiedName).right === node) + || (node.parent.kind === SyntaxKind.PropertyAccessExpression + && (node.parent as PropertyAccessExpression).name === node) + || (node.parent.kind === SyntaxKind.MetaProperty && (node.parent as MetaProperty).name === node); } /** @internal */ @@ -7204,14 +7939,14 @@ export function isRightSideOfQualifiedNameOrPropertyAccessOrJSDocMemberName(node /** @internal */ export function isEmptyObjectLiteral(expression: Node): boolean { - return expression.kind === SyntaxKind.ObjectLiteralExpression && - (expression as ObjectLiteralExpression).properties.length === 0; + return expression.kind === SyntaxKind.ObjectLiteralExpression + && (expression as ObjectLiteralExpression).properties.length === 0; } /** @internal */ export function isEmptyArrayLiteral(expression: Node): boolean { - return expression.kind === SyntaxKind.ArrayLiteralExpression && - (expression as ArrayLiteralExpression).elements.length === 0; + return expression.kind === SyntaxKind.ArrayLiteralExpression + && (expression as ArrayLiteralExpression).elements.length === 0; } /** @internal */ @@ -7224,7 +7959,8 @@ export function getLocalSymbolForExportDefault(symbol: Symbol) { } function isExportDefaultSymbol(symbol: Symbol): boolean { - return symbol && length(symbol.declarations) > 0 && hasSyntacticModifier(symbol.declarations![0], ModifierFlags.Default); + return symbol && length(symbol.declarations) > 0 + && hasSyntacticModifier(symbol.declarations![0], ModifierFlags.Default); } /** @@ -7305,7 +8041,8 @@ export function convertToBase64(input: string): string { } // Write to the output - result += base64Digits.charAt(byte1) + base64Digits.charAt(byte2) + base64Digits.charAt(byte3) + base64Digits.charAt(byte4); + result += base64Digits.charAt(byte1) + base64Digits.charAt(byte2) + base64Digits.charAt(byte3) + + base64Digits.charAt(byte4); i += 3; } @@ -7347,7 +8084,7 @@ function getStringFromExpandedCharCodes(codes: number[]): string { } /** @internal */ -export function base64encode(host: { base64encode?(input: string): string } | undefined, input: string): string { +export function base64encode(host: { base64encode?(input: string): string; } | undefined, input: string): string { if (host && host.base64encode) { return host.base64encode(input); } @@ -7355,7 +8092,7 @@ export function base64encode(host: { base64encode?(input: string): string } | un } /** @internal */ -export function base64decode(host: { base64decode?(input: string): string } | undefined, input: string): string { +export function base64decode(host: { base64decode?(input: string): string; } | undefined, input: string): string { if (host && host.base64decode) { return host.base64decode(input); } @@ -7392,7 +8129,10 @@ export function base64decode(host: { base64decode?(input: string): string } | un } /** @internal */ -export function readJsonOrUndefined(path: string, hostOrText: { readFile(fileName: string): string | undefined } | string): object | undefined { +export function readJsonOrUndefined( + path: string, + hostOrText: { readFile(fileName: string): string | undefined; } | string, +): object | undefined { const jsonText = isString(hostOrText) ? hostOrText : hostOrText.readFile(path); if (!jsonText) return undefined; // gracefully handle if readFile fails or returns not JSON @@ -7401,12 +8141,15 @@ export function readJsonOrUndefined(path: string, hostOrText: { readFile(fileNam } /** @internal */ -export function readJson(path: string, host: { readFile(fileName: string): string | undefined }): object { +export function readJson(path: string, host: { readFile(fileName: string): string | undefined; }): object { return readJsonOrUndefined(path, host) || {}; } /** @internal */ -export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean }): boolean { +export function directoryProbablyExists( + directoryName: string, + host: { directoryExists?: (directoryName: string) => boolean; }, +): boolean { // if host does not support 'directoryExists' assume that directory will exist return !host.directoryExists || host.directoryExists(directoryName); } @@ -7420,7 +8163,7 @@ export function getNewLineCharacter(options: CompilerOptions | PrinterOptions): return carriageReturnLineFeed; case NewLineKind.LineFeed: case undefined: - return lineFeed; + return lineFeed; } } @@ -7522,7 +8265,8 @@ export function rangeStartPositionsAreOnSameLine(range1: TextRange, range2: Text return positionsAreOnSameLine( getStartPositionOfRange(range1, sourceFile, /*includeComments*/ false), getStartPositionOfRange(range2, sourceFile, /*includeComments*/ false), - sourceFile); + sourceFile, + ); } /** @internal */ @@ -7532,16 +8276,29 @@ export function rangeEndPositionsAreOnSameLine(range1: TextRange, range2: TextRa /** @internal */ export function rangeStartIsOnSameLineAsRangeEnd(range1: TextRange, range2: TextRange, sourceFile: SourceFile) { - return positionsAreOnSameLine(getStartPositionOfRange(range1, sourceFile, /*includeComments*/ false), range2.end, sourceFile); + return positionsAreOnSameLine( + getStartPositionOfRange(range1, sourceFile, /*includeComments*/ false), + range2.end, + sourceFile, + ); } /** @internal */ export function rangeEndIsOnSameLineAsRangeStart(range1: TextRange, range2: TextRange, sourceFile: SourceFile) { - return positionsAreOnSameLine(range1.end, getStartPositionOfRange(range2, sourceFile, /*includeComments*/ false), sourceFile); + return positionsAreOnSameLine( + range1.end, + getStartPositionOfRange(range2, sourceFile, /*includeComments*/ false), + sourceFile, + ); } /** @internal */ -export function getLinesBetweenRangeEndAndRangeStart(range1: TextRange, range2: TextRange, sourceFile: SourceFile, includeSecondRangeComments: boolean) { +export function getLinesBetweenRangeEndAndRangeStart( + range1: TextRange, + range2: TextRange, + sourceFile: SourceFile, + includeSecondRangeComments: boolean, +) { const range2Start = getStartPositionOfRange(range2, sourceFile, includeSecondRangeComments); return getLinesBetweenPositions(sourceFile, range1.end, range2Start); } @@ -7563,18 +8320,29 @@ export function positionsAreOnSameLine(pos1: number, pos2: number, sourceFile: S /** @internal */ export function getStartPositionOfRange(range: TextRange, sourceFile: SourceFile, includeComments: boolean) { - return positionIsSynthesized(range.pos) ? -1 : skipTrivia(sourceFile.text, range.pos, /*stopAfterLineBreak*/ false, includeComments); + return positionIsSynthesized(range.pos) ? -1 + : skipTrivia(sourceFile.text, range.pos, /*stopAfterLineBreak*/ false, includeComments); } /** @internal */ -export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter(pos: number, stopPos: number, sourceFile: SourceFile, includeComments?: boolean) { +export function getLinesBetweenPositionAndPrecedingNonWhitespaceCharacter( + pos: number, + stopPos: number, + sourceFile: SourceFile, + includeComments?: boolean, +) { const startPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments); const prevPos = getPreviousNonWhitespacePosition(startPos, stopPos, sourceFile); return getLinesBetweenPositions(sourceFile, prevPos ?? stopPos, startPos); } /** @internal */ -export function getLinesBetweenPositionAndNextNonWhitespaceCharacter(pos: number, stopPos: number, sourceFile: SourceFile, includeComments?: boolean) { +export function getLinesBetweenPositionAndNextNonWhitespaceCharacter( + pos: number, + stopPos: number, + sourceFile: SourceFile, + includeComments?: boolean, +) { const nextPos = skipTrivia(sourceFile.text, pos, /*stopAfterLineBreak*/ false, includeComments); return getLinesBetweenPositions(sourceFile, pos, Math.min(stopPos, nextPos)); } @@ -7635,16 +8403,17 @@ export function getCheckFlags(symbol: Symbol): CheckFlags { export function getDeclarationModifierFlagsFromSymbol(s: Symbol, isWrite = false): ModifierFlags { if (s.valueDeclaration) { const declaration = (isWrite && s.declarations && find(s.declarations, isSetAccessorDeclaration)) - || (s.flags & SymbolFlags.GetAccessor && find(s.declarations, isGetAccessorDeclaration)) || s.valueDeclaration; + || (s.flags & SymbolFlags.GetAccessor && find(s.declarations, isGetAccessorDeclaration)) + || s.valueDeclaration; const flags = getCombinedModifierFlags(declaration); return s.parent && s.parent.flags & SymbolFlags.Class ? flags : flags & ~ModifierFlags.AccessibilityModifier; } if (getCheckFlags(s) & CheckFlags.Synthetic) { // NOTE: potentially unchecked cast to TransientSymbol const checkFlags = (s as TransientSymbol).links.checkFlags; - const accessModifier = checkFlags & CheckFlags.ContainsPrivate ? ModifierFlags.Private : - checkFlags & CheckFlags.ContainsPublic ? ModifierFlags.Public : - ModifierFlags.Protected; + const accessModifier = checkFlags & CheckFlags.ContainsPrivate ? ModifierFlags.Private + : checkFlags & CheckFlags.ContainsPublic ? ModifierFlags.Public + : ModifierFlags.Protected; const staticModifier = checkFlags & CheckFlags.ContainsStatic ? ModifierFlags.Static : 0; return accessModifier | staticModifier; } @@ -7684,7 +8453,7 @@ const enum AccessKind { /** Only writes to a variable without ever reading it. E.g.: `x=1;`. */ Write, /** Reads from and writes to a variable. E.g.: `f(x++);`, `x/=1`. */ - ReadWrite + ReadWrite, } function accessKind(node: Node): AccessKind { const { parent } = node; @@ -7695,11 +8464,12 @@ function accessKind(node: Node): AccessKind { case SyntaxKind.PostfixUnaryExpression: case SyntaxKind.PrefixUnaryExpression: const { operator } = parent as PrefixUnaryExpression | PostfixUnaryExpression; - return operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken ? AccessKind.ReadWrite : AccessKind.Read; + return operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken + ? AccessKind.ReadWrite : AccessKind.Read; case SyntaxKind.BinaryExpression: const { left, operatorToken } = parent as BinaryExpression; - return left === node && isAssignmentOperator(operatorToken.kind) ? - operatorToken.kind === SyntaxKind.EqualsToken ? AccessKind.Write : AccessKind.ReadWrite + return left === node && isAssignmentOperator(operatorToken.kind) + ? operatorToken.kind === SyntaxKind.EqualsToken ? AccessKind.Write : AccessKind.ReadWrite : AccessKind.Read; case SyntaxKind.PropertyAccessExpression: return (parent as PropertyAccessExpression).name !== node ? AccessKind.Read : accessKind(parent); @@ -7710,7 +8480,8 @@ function accessKind(node: Node): AccessKind { } case SyntaxKind.ShorthandPropertyAssignment: // Assume it's the local variable being accessed, since we don't check public properties for --noUnusedLocals. - return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read : accessKind(parent.parent); + return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read + : accessKind(parent.parent); case SyntaxKind.ArrayLiteralExpression: return accessKind(parent); default: @@ -7756,7 +8527,10 @@ export function compareDataObjects(dst: any, src: any): boolean { * * @internal */ -export function clearMap(map: { forEach: Map["forEach"]; clear: Map["clear"]; }, onDeleteValue: (valueInMap: T, key: K) => void) { +export function clearMap( + map: { forEach: Map["forEach"]; clear: Map["clear"]; }, + onDeleteValue: (valueInMap: T, key: K) => void, +) { // Remove all map.forEach(onDeleteValue); map.clear(); @@ -7783,7 +8557,7 @@ export interface MutateMapSkippingNewValuesOptions { export function mutateMapSkippingNewValues( map: Map, newMap: ReadonlyMap, - options: MutateMapSkippingNewValuesOptions + options: MutateMapSkippingNewValuesOptions, ) { const { onDeleteValue, onExistingValue } = options; // Needs update @@ -7851,7 +8625,8 @@ export function forSomeAncestorDirectory(directory: string, callback: (directory /** @internal */ export function isUMDExportSymbol(symbol: Symbol | undefined): boolean { - return !!symbol && !!symbol.declarations && !!symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]); + return !!symbol && !!symbol.declarations && !!symbol.declarations[0] + && isNamespaceExportDeclaration(symbol.declarations[0]); } /** @internal */ @@ -7862,19 +8637,17 @@ export function showModuleSpecifier({ moduleSpecifier }: ImportDeclaration): str /** @internal */ export function getLastChild(node: Node): Node | undefined { let lastChild: Node | undefined; - forEachChild(node, - child => { - if (nodeIsPresent(child)) lastChild = child; - }, - children => { - // As an optimization, jump straight to the end of the list. - for (let i = children.length - 1; i >= 0; i--) { - if (nodeIsPresent(children[i])) { - lastChild = children[i]; - break; - } + forEachChild(node, child => { + if (nodeIsPresent(child)) lastChild = child; + }, children => { + // As an optimization, jump straight to the end of the list. + for (let i = children.length - 1; i >= 0; i--) { + if (nodeIsPresent(children[i])) { + lastChild = children[i]; + break; } - }); + } + }); return lastChild; } @@ -7964,7 +8737,10 @@ export function getLeftmostAccessExpression(expr: Expression): Expression { } /** @internal */ -export function forEachNameInAccessChainWalkingLeft(name: MemberName | StringLiteralLike, action: (name: MemberName | StringLiteralLike) => T | undefined): T | undefined { +export function forEachNameInAccessChainWalkingLeft( + name: MemberName | StringLiteralLike, + action: (name: MemberName | StringLiteralLike) => T | undefined, +): T | undefined { if (isAccessExpression(name.parent) && isRightSideOfAccessExpression(name)) { return walkAccessExpression(name.parent); } @@ -8001,8 +8777,6 @@ export function forEachNameInAccessChainWalkingLeft(name: MemberName | String } } - - /** @internal */ export function getLeftmostExpression(node: Expression, stopAtCallExpressions: boolean) { while (true) { @@ -8034,7 +8808,14 @@ export function getLeftmostExpression(node: Expression, stopAtCallExpressions: b case SyntaxKind.NonNullExpression: case SyntaxKind.PartiallyEmittedExpression: case SyntaxKind.SatisfiesExpression: - node = (node as CallExpression | PropertyAccessExpression | ElementAccessExpression | AsExpression | NonNullExpression | PartiallyEmittedExpression | SatisfiesExpression).expression; + node = (node as + | CallExpression + | PropertyAccessExpression + | ElementAccessExpression + | AsExpression + | NonNullExpression + | PartiallyEmittedExpression + | SatisfiesExpression).expression; continue; } @@ -8047,12 +8828,20 @@ export interface ObjectAllocator { getNodeConstructor(): new (kind: SyntaxKind, pos: number, end: number) => Node; getTokenConstructor(): new (kind: TKind, pos: number, end: number) => Token; getIdentifierConstructor(): new (kind: SyntaxKind.Identifier, pos: number, end: number) => Identifier; - getPrivateIdentifierConstructor(): new (kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) => PrivateIdentifier; + getPrivateIdentifierConstructor(): new ( + kind: SyntaxKind.PrivateIdentifier, + pos: number, + end: number, + ) => PrivateIdentifier; getSourceFileConstructor(): new (kind: SyntaxKind.SourceFile, pos: number, end: number) => SourceFile; getSymbolConstructor(): new (flags: SymbolFlags, name: __String) => Symbol; getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type; getSignatureConstructor(): new (checker: TypeChecker, flags: SignatureFlags) => Signature; - getSourceMapSourceConstructor(): new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource; + getSourceMapSourceConstructor(): new ( + fileName: string, + text: string, + skipTrivia?: (pos: number) => number, + ) => SourceMapSource; } function Symbol(this: Symbol, flags: SymbolFlags, name: __String) { @@ -8185,7 +8974,14 @@ export function getLocaleSpecificMessage(message: DiagnosticMessage) { } /** @internal */ -export function createDetachedDiagnostic(fileName: string, sourceText: string, start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation { +export function createDetachedDiagnostic( + fileName: string, + sourceText: string, + start: number, + length: number, + message: DiagnosticMessage, + ...args: DiagnosticArguments +): DiagnosticWithDetachedLocation { if ((start + length) > sourceText.length) { length = sourceText.length - start; } @@ -8210,7 +9006,9 @@ export function createDetachedDiagnostic(fileName: string, sourceText: string, s }; } -function isDiagnosticWithDetachedLocation(diagnostic: DiagnosticRelatedInformation | DiagnosticWithDetachedLocation): diagnostic is DiagnosticWithDetachedLocation { +function isDiagnosticWithDetachedLocation( + diagnostic: DiagnosticRelatedInformation | DiagnosticWithDetachedLocation, +): diagnostic is DiagnosticWithDetachedLocation { return diagnostic.file === undefined && diagnostic.start !== undefined && diagnostic.length !== undefined @@ -8230,7 +9028,7 @@ function attachFileToDiagnostic(diagnostic: DiagnosticWithDetachedLocation, file messageText: diagnostic.messageText, category: diagnostic.category, code: diagnostic.code, - reportsUnnecessary: diagnostic.reportsUnnecessary + reportsUnnecessary: diagnostic.reportsUnnecessary, }; if (diagnostic.relatedInformation) { diagnosticWithLocation.relatedInformation = []; @@ -8249,7 +9047,10 @@ function attachFileToDiagnostic(diagnostic: DiagnosticWithDetachedLocation, file } /** @internal */ -export function attachFileToDiagnostics(diagnostics: DiagnosticWithDetachedLocation[], file: SourceFile): DiagnosticWithLocation[] { +export function attachFileToDiagnostics( + diagnostics: DiagnosticWithDetachedLocation[], + file: SourceFile, +): DiagnosticWithLocation[] { const diagnosticsWithLocation: DiagnosticWithLocation[] = []; for (const diagnostic of diagnostics) { diagnosticsWithLocation.push(attachFileToDiagnostic(diagnostic, file)); @@ -8258,7 +9059,13 @@ export function attachFileToDiagnostics(diagnostics: DiagnosticWithDetachedLocat } /** @internal */ -export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { +export function createFileDiagnostic( + file: SourceFile, + start: number, + length: number, + message: DiagnosticMessage, + ...args: DiagnosticArguments +): DiagnosticWithLocation { assertDiagnosticLocation(file.text, start, length); let text = getLocaleSpecificMessage(message); @@ -8276,7 +9083,7 @@ export function createFileDiagnostic(file: SourceFile, start: number, length: nu category: message.category, code: message.code, reportsUnnecessary: message.reportsUnnecessary, - reportsDeprecated: message.reportsDeprecated + reportsDeprecated: message.reportsDeprecated, }; } @@ -8308,12 +9115,15 @@ export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: Di category: message.category, code: message.code, reportsUnnecessary: message.reportsUnnecessary, - reportsDeprecated: message.reportsDeprecated + reportsDeprecated: message.reportsDeprecated, }; } /** @internal */ -export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): Diagnostic { +export function createCompilerDiagnosticFromMessageChain( + chain: DiagnosticMessageChain, + relatedInformation?: DiagnosticRelatedInformation[], +): Diagnostic { return { file: undefined, start: undefined, @@ -8322,12 +9132,16 @@ export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessag code: chain.code, category: chain.category, messageText: chain.next ? chain : chain.messageText, - relatedInformation + relatedInformation, }; } /** @internal */ -export function chainDiagnosticMessages(details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticMessageChain { +export function chainDiagnosticMessages( + details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, + message: DiagnosticMessage, + ...args: DiagnosticArguments +): DiagnosticMessageChain { let text = getLocaleSpecificMessage(message); if (some(args)) { @@ -8338,12 +9152,15 @@ export function chainDiagnosticMessages(details: DiagnosticMessageChain | Diagno category: message.category, code: message.code, - next: details === undefined || Array.isArray(details) ? details : [details] + next: details === undefined || Array.isArray(details) ? details : [details], }; } /** @internal */ -export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): void { +export function concatenateDiagnosticMessageChains( + headChain: DiagnosticMessageChain, + tailChain: DiagnosticMessageChain, +): void { let lastChain = headChain; while (lastChain.next) { lastChain = lastChain.next[0]; @@ -8358,19 +9175,19 @@ function getDiagnosticFilePath(diagnostic: Diagnostic): string | undefined { /** @internal */ export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison { - return compareDiagnosticsSkipRelatedInformation(d1, d2) || - compareRelatedInformation(d1, d2) || - Comparison.EqualTo; + return compareDiagnosticsSkipRelatedInformation(d1, d2) + || compareRelatedInformation(d1, d2) + || Comparison.EqualTo; } /** @internal */ export function compareDiagnosticsSkipRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison { - return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) || - compareValues(d1.start, d2.start) || - compareValues(d1.length, d2.length) || - compareValues(d1.code, d2.code) || - compareMessageText(d1.messageText, d2.messageText) || - Comparison.EqualTo; + return compareStringsCaseSensitive(getDiagnosticFilePath(d1), getDiagnosticFilePath(d2)) + || compareValues(d1.start, d2.start) + || compareValues(d1.length, d2.length) + || compareValues(d1.code, d2.code) + || compareMessageText(d1.messageText, d2.messageText) + || Comparison.EqualTo; } function compareRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison { @@ -8378,10 +9195,11 @@ function compareRelatedInformation(d1: Diagnostic, d2: Diagnostic): Comparison { return Comparison.EqualTo; } if (d1.relatedInformation && d2.relatedInformation) { - return compareValues(d1.relatedInformation.length, d2.relatedInformation.length) || forEach(d1.relatedInformation, (d1i, index) => { - const d2i = d2.relatedInformation![index]; - return compareDiagnostics(d1i, d2i); // EqualTo is 0, so falsy, and will cause the next item to be compared - }) || Comparison.EqualTo; + return compareValues(d1.relatedInformation.length, d2.relatedInformation.length) + || forEach(d1.relatedInformation, (d1i, index) => { + const d2i = d2.relatedInformation![index]; + return compareDiagnostics(d1i, d2i); // EqualTo is 0, so falsy, and will cause the next item to be compared + }) || Comparison.EqualTo; } return d1.relatedInformation ? Comparison.LessThan : Comparison.GreaterThan; } @@ -8428,7 +9246,8 @@ function compareMessageText(t1: string | DiagnosticMessageChain, t2: string | Di /** @internal */ export function getLanguageVariant(scriptKind: ScriptKind) { // .tsx and .jsx files are treated as jsx language variant. - return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSON ? LanguageVariant.JSX : LanguageVariant.Standard; + return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS + || scriptKind === ScriptKind.JSON ? LanguageVariant.JSX : LanguageVariant.Standard; } /** @@ -8455,7 +9274,9 @@ function isFileForcedToBeModuleByFormat(file: SourceFile): true | undefined { // Excludes declaration files - they still require an explicit `export {}` or the like // for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files // that aren't esm-mode (meaning not in a `type: module` scope). - return (file.impliedNodeFormat === ModuleKind.ESNext || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts, Extension.Mjs, Extension.Mts]))) && !file.isDeclarationFile ? true : undefined; + return (file.impliedNodeFormat === ModuleKind.ESNext + || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts, Extension.Mjs, Extension.Mts]))) + && !file.isDeclarationFile ? true : undefined; } /** @internal */ @@ -8465,7 +9286,8 @@ export function getSetExternalModuleIndicator(options: CompilerOptions): (file: case ModuleDetectionKind.Force: // All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule return (file: SourceFile) => { - file.externalModuleIndicator = isFileProbablyExternalModule(file) || !file.isDeclarationFile || undefined; + file.externalModuleIndicator = isFileProbablyExternalModule(file) || !file.isDeclarationFile + || undefined; }; case ModuleDetectionKind.Legacy: // Files are modules if they have imports, exports, or import.meta @@ -8488,18 +9310,22 @@ export function getSetExternalModuleIndicator(options: CompilerOptions): (file: } /** @internal */ -export function getEmitScriptTarget(compilerOptions: {module?: CompilerOptions["module"], target?: CompilerOptions["target"]}): ScriptTarget { - return compilerOptions.target ?? - ((compilerOptions.module === ModuleKind.Node16 && ScriptTarget.ES2022) || - (compilerOptions.module === ModuleKind.NodeNext && ScriptTarget.ESNext) || - ScriptTarget.ES5); +export function getEmitScriptTarget( + compilerOptions: { module?: CompilerOptions["module"]; target?: CompilerOptions["target"]; }, +): ScriptTarget { + return compilerOptions.target + ?? ((compilerOptions.module === ModuleKind.Node16 && ScriptTarget.ES2022) + || (compilerOptions.module === ModuleKind.NodeNext && ScriptTarget.ESNext) + || ScriptTarget.ES5); } /** @internal */ -export function getEmitModuleKind(compilerOptions: {module?: CompilerOptions["module"], target?: CompilerOptions["target"]}) { - return typeof compilerOptions.module === "number" ? - compilerOptions.module : - getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 ? ModuleKind.ES2015 : ModuleKind.CommonJS; +export function getEmitModuleKind( + compilerOptions: { module?: CompilerOptions["module"]; target?: CompilerOptions["target"]; }, +) { + return typeof compilerOptions.module === "number" + ? compilerOptions.module + : getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 ? ModuleKind.ES2015 : ModuleKind.CommonJS; } /** @internal */ @@ -8531,8 +9357,9 @@ export function getEmitModuleResolutionKind(compilerOptions: CompilerOptions) { /** @internal */ export function getEmitModuleDetectionKind(options: CompilerOptions) { - return options.moduleDetection || - (getEmitModuleKind(options) === ModuleKind.Node16 || getEmitModuleKind(options) === ModuleKind.NodeNext ? ModuleDetectionKind.Force : ModuleDetectionKind.Auto); + return options.moduleDetection + || (getEmitModuleKind(options) === ModuleKind.Node16 || getEmitModuleKind(options) === ModuleKind.NodeNext + ? ModuleDetectionKind.Force : ModuleDetectionKind.Auto); } /** @internal */ @@ -8609,7 +9436,8 @@ export function moduleResolutionSupportsPackageJsonExportsAndImports(moduleResol /** @internal */ export function shouldResolveJsRequire(compilerOptions: CompilerOptions): boolean { // `bundler` doesn't support resolving `require`, but needs to in `noDtsResolution` to support Find Source Definition - return !!compilerOptions.noDtsResolution || getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler; + return !!compilerOptions.noDtsResolution + || getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler; } /** @internal */ @@ -8680,8 +9508,7 @@ export type StrictOptionName = | "strictBindCallApply" | "strictPropertyInitialization" | "alwaysStrict" - | "useUnknownInCatchVariables" - ; + | "useUnknownInCatchVariables"; /** @internal */ export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: StrictOptionName): boolean { @@ -8695,16 +9522,21 @@ export function getAllowJSCompilerOption(compilerOptions: CompilerOptions): bool /** @internal */ export function getUseDefineForClassFields(compilerOptions: CompilerOptions): boolean { - return compilerOptions.useDefineForClassFields === undefined ? getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 : compilerOptions.useDefineForClassFields; + return compilerOptions.useDefineForClassFields === undefined + ? getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 : compilerOptions.useDefineForClassFields; } /** @internal */ export function getEmitStandardClassFields(compilerOptions: CompilerOptions) { - return compilerOptions.useDefineForClassFields !== false && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022; + return compilerOptions.useDefineForClassFields !== false + && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022; } /** @internal */ -export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean { +export function compilerOptionsAffectSemanticDiagnostics( + newOptions: CompilerOptions, + oldOptions: CompilerOptions, +): boolean { return optionsHaveChanges(oldOptions, newOptions, semanticDiagnosticsOptionDeclarations); } @@ -8714,7 +9546,10 @@ export function compilerOptionsAffectEmit(newOptions: CompilerOptions, oldOption } /** @internal */ -export function compilerOptionsAffectDeclarationPath(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean { +export function compilerOptionsAffectDeclarationPath( + newOptions: CompilerOptions, + oldOptions: CompilerOptions, +): boolean { return optionsHaveChanges(oldOptions, newOptions, affectsDeclarationPathOptionDeclarations); } @@ -8732,13 +9567,14 @@ export function getJSXTransformEnabled(options: CompilerOptions): boolean { /** @internal */ export function getJSXImplicitImportBase(compilerOptions: CompilerOptions, file?: SourceFile): string | undefined { const jsxImportSourcePragmas = file?.pragmas.get("jsximportsource"); - const jsxImportSourcePragma = isArray(jsxImportSourcePragmas) ? jsxImportSourcePragmas[jsxImportSourcePragmas.length - 1] : jsxImportSourcePragmas; - return compilerOptions.jsx === JsxEmit.ReactJSX || - compilerOptions.jsx === JsxEmit.ReactJSXDev || - compilerOptions.jsxImportSource || - jsxImportSourcePragma ? - jsxImportSourcePragma?.arguments.factory || compilerOptions.jsxImportSource || "react" : - undefined; + const jsxImportSourcePragma = isArray(jsxImportSourcePragmas) + ? jsxImportSourcePragmas[jsxImportSourcePragmas.length - 1] : jsxImportSourcePragmas; + return compilerOptions.jsx === JsxEmit.ReactJSX + || compilerOptions.jsx === JsxEmit.ReactJSXDev + || compilerOptions.jsxImportSource + || jsxImportSourcePragma + ? jsxImportSourcePragma?.arguments.factory || compilerOptions.jsxImportSource || "react" + : undefined; } /** @internal */ @@ -8787,7 +9623,10 @@ export interface SymlinkCache { * don't include automatic type reference directives. Must be called only when * `hasProcessedResolutions` returns false (once per cache instance). */ - setSymlinksFromResolutions(files: readonly SourceFile[], typeReferenceDirectives: ModeAwareCache): void; + setSymlinksFromResolutions( + files: readonly SourceFile[], + typeReferenceDirectives: ModeAwareCache, + ): void; /** * @internal * Whether `setSymlinksFromResolutions` has already been called. @@ -8814,7 +9653,10 @@ export function createSymlinkCache(cwd: string, getCanonicalFileName: GetCanonic if (!containsIgnoredPath(symlinkPath)) { symlinkPath = ensureTrailingDirectorySeparator(symlinkPath); if (real !== false && !symlinkedDirectories?.has(symlinkPath)) { - (symlinkedDirectoriesByRealpath ||= createMultiMap()).add(ensureTrailingDirectorySeparator(real.realPath), symlink); + (symlinkedDirectoriesByRealpath ||= createMultiMap()).add( + ensureTrailingDirectorySeparator(real.realPath), + symlink, + ); } (symlinkedDirectories || (symlinkedDirectories = new Map())).set(symlinkPath, real); } @@ -8824,35 +9666,49 @@ export function createSymlinkCache(cwd: string, getCanonicalFileName: GetCanonic hasProcessedResolutions = true; for (const file of files) { file.resolvedModules?.forEach(resolution => processResolution(this, resolution.resolvedModule)); - file.resolvedTypeReferenceDirectiveNames?.forEach(resolution => processResolution(this, resolution.resolvedTypeReferenceDirective)); + file.resolvedTypeReferenceDirectiveNames?.forEach(resolution => + processResolution(this, resolution.resolvedTypeReferenceDirective) + ); } - typeReferenceDirectives.forEach(resolution => processResolution(this, resolution.resolvedTypeReferenceDirective)); + typeReferenceDirectives.forEach(resolution => + processResolution(this, resolution.resolvedTypeReferenceDirective) + ); }, hasProcessedResolutions: () => hasProcessedResolutions, }; - function processResolution(cache: SymlinkCache, resolution: ResolvedModuleFull | ResolvedTypeReferenceDirective | undefined) { + function processResolution( + cache: SymlinkCache, + resolution: ResolvedModuleFull | ResolvedTypeReferenceDirective | undefined, + ) { if (!resolution || !resolution.originalPath || !resolution.resolvedFileName) return; const { resolvedFileName, originalPath } = resolution; cache.setSymlinkedFile(toPath(originalPath, cwd, getCanonicalFileName), resolvedFileName); - const [commonResolved, commonOriginal] = guessDirectorySymlink(resolvedFileName, originalPath, cwd, getCanonicalFileName) || emptyArray; + const [commonResolved, commonOriginal] = + guessDirectorySymlink(resolvedFileName, originalPath, cwd, getCanonicalFileName) || emptyArray; if (commonResolved && commonOriginal) { cache.setSymlinkedDirectory( commonOriginal, - { real: commonResolved, realPath: toPath(commonResolved, cwd, getCanonicalFileName) }); + { real: commonResolved, realPath: toPath(commonResolved, cwd, getCanonicalFileName) }, + ); } } } -function guessDirectorySymlink(a: string, b: string, cwd: string, getCanonicalFileName: GetCanonicalFileName): [string, string] | undefined { +function guessDirectorySymlink( + a: string, + b: string, + cwd: string, + getCanonicalFileName: GetCanonicalFileName, +): [string, string] | undefined { const aParts = getPathComponents(getNormalizedAbsolutePath(a, cwd)); const bParts = getPathComponents(getNormalizedAbsolutePath(b, cwd)); let isDirectory = false; while ( - aParts.length >= 2 && bParts.length >= 2 && - !isNodeModulesOrScopedPackageDirectory(aParts[aParts.length - 2], getCanonicalFileName) && - !isNodeModulesOrScopedPackageDirectory(bParts[bParts.length - 2], getCanonicalFileName) && - getCanonicalFileName(aParts[aParts.length - 1]) === getCanonicalFileName(bParts[bParts.length - 1]) + aParts.length >= 2 && bParts.length >= 2 + && !isNodeModulesOrScopedPackageDirectory(aParts[aParts.length - 2], getCanonicalFileName) + && !isNodeModulesOrScopedPackageDirectory(bParts[bParts.length - 2], getCanonicalFileName) + && getCanonicalFileName(aParts[aParts.length - 1]) === getCanonicalFileName(bParts[bParts.length - 1]) ) { aParts.pop(); bParts.pop(); @@ -8863,7 +9719,10 @@ function guessDirectorySymlink(a: string, b: string, cwd: string, getCanonicalFi // KLUDGE: Don't assume one 'node_modules' links to another. More likely a single directory inside the node_modules is the symlink. // ALso, don't assume that an `@foo` directory is linked. More likely the contents of that are linked. -function isNodeModulesOrScopedPackageDirectory(s: string | undefined, getCanonicalFileName: GetCanonicalFileName): boolean { +function isNodeModulesOrScopedPackageDirectory( + s: string | undefined, + getCanonicalFileName: GetCanonicalFileName, +): boolean { return s !== undefined && (getCanonicalFileName(s) === "node_modules" || startsWith(s, "@")); } @@ -8872,7 +9731,11 @@ function stripLeadingDirectorySeparator(s: string): string | undefined { } /** @internal */ -export function tryRemoveDirectoryPrefix(path: string, dirPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined { +export function tryRemoveDirectoryPrefix( + path: string, + dirPath: string, + getCanonicalFileName: GetCanonicalFileName, +): string | undefined { const withoutPrefix = tryRemovePrefix(path, dirPath, getCanonicalFileName); return withoutPrefix === undefined ? undefined : stripLeadingDirectorySeparator(withoutPrefix); } @@ -8917,7 +9780,7 @@ const filesMatcher: WildcardMatcher = { * files or directories, does not match subdirectories that start with a . character */ doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`, - replaceWildcardCharacter: match => replaceWildcardCharacter(match, filesMatcher.singleAsteriskRegexFragment) + replaceWildcardCharacter: match => replaceWildcardCharacter(match, filesMatcher.singleAsteriskRegexFragment), }; const directoriesMatcher: WildcardMatcher = { @@ -8927,23 +9790,27 @@ const directoriesMatcher: WildcardMatcher = { * files or directories, does not match subdirectories that start with a . character */ doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`, - replaceWildcardCharacter: match => replaceWildcardCharacter(match, directoriesMatcher.singleAsteriskRegexFragment) + replaceWildcardCharacter: match => replaceWildcardCharacter(match, directoriesMatcher.singleAsteriskRegexFragment), }; const excludeMatcher: WildcardMatcher = { singleAsteriskRegexFragment: "[^/]*", doubleAsteriskRegexFragment: "(/.+?)?", - replaceWildcardCharacter: match => replaceWildcardCharacter(match, excludeMatcher.singleAsteriskRegexFragment) + replaceWildcardCharacter: match => replaceWildcardCharacter(match, excludeMatcher.singleAsteriskRegexFragment), }; const wildcardMatchers = { files: filesMatcher, directories: directoriesMatcher, - exclude: excludeMatcher + exclude: excludeMatcher, }; /** @internal */ -export function getRegularExpressionForWildcard(specs: readonly string[] | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string | undefined { +export function getRegularExpressionForWildcard( + specs: readonly string[] | undefined, + basePath: string, + usage: "files" | "directories" | "exclude", +): string | undefined { const patterns = getRegularExpressionsForWildcards(specs, basePath, usage); if (!patterns || !patterns.length) { return undefined; @@ -8956,13 +9823,16 @@ export function getRegularExpressionForWildcard(specs: readonly string[] | undef } /** @internal */ -export function getRegularExpressionsForWildcards(specs: readonly string[] | undefined, basePath: string, usage: "files" | "directories" | "exclude"): readonly string[] | undefined { +export function getRegularExpressionsForWildcards( + specs: readonly string[] | undefined, + basePath: string, + usage: "files" | "directories" | "exclude", +): readonly string[] | undefined { if (specs === undefined || specs.length === 0) { return undefined; } - return flatMap(specs, spec => - spec && getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage])); + return flatMap(specs, spec => spec && getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage])); } /** @@ -8981,7 +9851,12 @@ export function getPatternFromSpec(spec: string, basePath: string, usage: "files return pattern && `^(${pattern})${usage === "exclude" ? "($|/)" : "$"}`; } -function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher): string | undefined { +function getSubPatternFromSpec( + spec: string, + basePath: string, + usage: "files" | "directories" | "exclude", + { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher, +): string | undefined { let subpattern = ""; let hasWrittenComponent = false; const components = getNormalizedPathComponents(spec, basePath); @@ -9083,17 +9958,26 @@ export interface FileMatcherPatterns { * * @internal */ -export function getFileMatcherPatterns(path: string, excludes: readonly string[] | undefined, includes: readonly string[] | undefined, useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns { +export function getFileMatcherPatterns( + path: string, + excludes: readonly string[] | undefined, + includes: readonly string[] | undefined, + useCaseSensitiveFileNames: boolean, + currentDirectory: string, +): FileMatcherPatterns { path = normalizePath(path); currentDirectory = normalizePath(currentDirectory); const absolutePath = combinePaths(currentDirectory, path); return { - includeFilePatterns: map(getRegularExpressionsForWildcards(includes, absolutePath, "files"), pattern => `^${pattern}$`), + includeFilePatterns: map( + getRegularExpressionsForWildcards(includes, absolutePath, "files"), + pattern => `^${pattern}$`, + ), includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"), includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"), excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"), - basePaths: getBasePaths(path, includes, useCaseSensitiveFileNames) + basePaths: getBasePaths(path, includes, useCaseSensitiveFileNames), }; } @@ -9107,15 +9991,28 @@ export function getRegexFromPattern(pattern: string, useCaseSensitiveFileNames: * * @internal */ -export function matchFiles(path: string, extensions: readonly string[] | undefined, excludes: readonly string[] | undefined, includes: readonly string[] | undefined, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries, realpath: (path: string) => string): string[] { +export function matchFiles( + path: string, + extensions: readonly string[] | undefined, + excludes: readonly string[] | undefined, + includes: readonly string[] | undefined, + useCaseSensitiveFileNames: boolean, + currentDirectory: string, + depth: number | undefined, + getFileSystemEntries: (path: string) => FileSystemEntries, + realpath: (path: string) => string, +): string[] { path = normalizePath(path); currentDirectory = normalizePath(currentDirectory); const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory); - const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames)); - const includeDirectoryRegex = patterns.includeDirectoryPattern && getRegexFromPattern(patterns.includeDirectoryPattern, useCaseSensitiveFileNames); - const excludeRegex = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, useCaseSensitiveFileNames); + const includeFileRegexes = patterns.includeFilePatterns + && patterns.includeFilePatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames)); + const includeDirectoryRegex = patterns.includeDirectoryPattern + && getRegexFromPattern(patterns.includeDirectoryPattern, useCaseSensitiveFileNames); + const excludeRegex = patterns.excludePattern + && getRegexFromPattern(patterns.excludePattern, useCaseSensitiveFileNames); // Associate an array of results with each include regex. This keeps results in order of the "include" order. // If there are no "includes", then just put everything in results[0]. @@ -9160,8 +10057,10 @@ export function matchFiles(path: string, extensions: readonly string[] | undefin for (const current of sort(directories, compareStringsCaseSensitive)) { const name = combinePaths(path, current); const absoluteName = combinePaths(absolutePath, current); - if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) && - (!excludeRegex || !excludeRegex.test(absoluteName))) { + if ( + (!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) + && (!excludeRegex || !excludeRegex.test(absoluteName)) + ) { visitDirectory(name, absoluteName, depth); } } @@ -9171,7 +10070,11 @@ export function matchFiles(path: string, extensions: readonly string[] | undefin /** * Computes the unique non-wildcard base paths amongst the provided include patterns. */ -function getBasePaths(path: string, includes: readonly string[] | undefined, useCaseSensitiveFileNames: boolean): string[] { +function getBasePaths( + path: string, + includes: readonly string[] | undefined, + useCaseSensitiveFileNames: boolean, +): string[] { // Storage for our results in the form of literal paths (e.g. the paths as written by the user). const basePaths: string[] = [path]; @@ -9192,7 +10095,9 @@ function getBasePaths(path: string, includes: readonly string[] | undefined, use // Iterate over each include base path and include unique base paths that are not a // subpath of an existing base path for (const includeBasePath of includeBasePaths) { - if (every(basePaths, basePath => !containsPath(basePath, includeBasePath, path, !useCaseSensitiveFileNames))) { + if ( + every(basePaths, basePath => !containsPath(basePath, includeBasePath, path, !useCaseSensitiveFileNames)) + ) { basePaths.push(includeBasePath); } } @@ -9251,31 +10156,66 @@ export function getScriptKindFromFileName(fileName: string): ScriptKind { * * @internal */ -export const supportedTSExtensions: readonly Extension[][] = [[Extension.Ts, Extension.Tsx, Extension.Dts], [Extension.Cts, Extension.Dcts], [Extension.Mts, Extension.Dmts]]; +export 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 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, +]]; /** @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]]; +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], +]; const allSupportedExtensionsWithJson: readonly Extension[][] = [...allSupportedExtensions, [Extension.Json]]; /** @internal */ export const supportedDeclarationExtensions: readonly Extension[] = [Extension.Dts, Extension.Dcts, Extension.Dmts]; /** @internal */ -export const supportedTSImplementationExtensions: readonly Extension[] = [Extension.Ts, Extension.Cts, Extension.Mts, Extension.Tsx]; +export const supportedTSImplementationExtensions: readonly Extension[] = [ + Extension.Ts, + Extension.Cts, + Extension.Mts, + Extension.Tsx, +]; /** @internal */ -export const extensionsNotSupportingExtensionlessResolution: readonly Extension[] = [Extension.Mts, Extension.Dmts, Extension.Mjs, Extension.Cts, Extension.Dcts, Extension.Cjs]; +export const extensionsNotSupportingExtensionlessResolution: readonly Extension[] = [ + Extension.Mts, + Extension.Dmts, + Extension.Mjs, + Extension.Cts, + Extension.Dcts, + Extension.Cjs, +]; /** @internal */ export function getSupportedExtensions(options?: CompilerOptions): readonly Extension[][]; /** @internal */ -export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: readonly FileExtensionInfo[]): readonly string[][]; +export function getSupportedExtensions( + options?: CompilerOptions, + extraFileExtensions?: readonly FileExtensionInfo[], +): readonly string[][]; /** @internal */ -export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: readonly FileExtensionInfo[]): readonly string[][] { +export function getSupportedExtensions( + options?: CompilerOptions, + extraFileExtensions?: readonly FileExtensionInfo[], +): readonly string[][] { const needJsExtensions = options && getAllowJSCompilerOption(options); if (!extraFileExtensions || extraFileExtensions.length === 0) { @@ -9286,18 +10226,32 @@ export function getSupportedExtensions(options?: CompilerOptions, extraFileExten const flatBuiltins = flatten(builtins); const extensions = [ ...builtins, - ...mapDefined(extraFileExtensions, x => x.scriptKind === ScriptKind.Deferred || needJsExtensions && isJSLike(x.scriptKind) && flatBuiltins.indexOf(x.extension as Extension) === -1 ? [x.extension] : undefined) + ...mapDefined( + extraFileExtensions, + x => x.scriptKind === ScriptKind.Deferred + || needJsExtensions && isJSLike(x.scriptKind) + && flatBuiltins.indexOf(x.extension as Extension) === -1 ? [x.extension] : undefined, + ), ]; return extensions; } /** @internal */ -export function getSupportedExtensionsWithJsonIfResolveJsonModule(options: CompilerOptions | undefined, supportedExtensions: readonly Extension[][]): readonly Extension[][]; +export function getSupportedExtensionsWithJsonIfResolveJsonModule( + options: CompilerOptions | undefined, + supportedExtensions: readonly Extension[][], +): readonly Extension[][]; /** @internal */ -export function getSupportedExtensionsWithJsonIfResolveJsonModule(options: CompilerOptions | undefined, supportedExtensions: readonly string[][]): readonly string[][]; +export function getSupportedExtensionsWithJsonIfResolveJsonModule( + options: CompilerOptions | undefined, + supportedExtensions: readonly string[][], +): readonly string[][]; /** @internal */ -export function getSupportedExtensionsWithJsonIfResolveJsonModule(options: CompilerOptions | undefined, supportedExtensions: readonly string[][]): readonly string[][] { +export function getSupportedExtensionsWithJsonIfResolveJsonModule( + options: CompilerOptions | undefined, + supportedExtensions: readonly string[][], +): readonly string[][] { if (!options || !getResolveJsonModule(options)) return supportedExtensions; if (supportedExtensions === allSupportedExtensions) return allSupportedExtensionsWithJson; if (supportedExtensions === supportedTSExtensions) return supportedTSExtensionsWithJson; @@ -9330,14 +10284,26 @@ export const enum ModuleSpecifierEnding { } /** @internal */ -export function usesExtensionsOnImports({ imports }: SourceFile, hasExtension: (text: string) => boolean = or(hasJSFileExtension, hasTSFileExtension)): boolean { - return firstDefined(imports, ({ text }) => pathIsRelative(text) && !fileExtensionIsOneOf(text, extensionsNotSupportingExtensionlessResolution) - ? hasExtension(text) - : undefined) || false; -} - -/** @internal */ -export function getModuleSpecifierEndingPreference(preference: UserPreferences["importModuleSpecifierEnding"], resolutionMode: ResolutionMode, compilerOptions: CompilerOptions, sourceFile: SourceFile): ModuleSpecifierEnding { +export function usesExtensionsOnImports( + { imports }: SourceFile, + hasExtension: (text: string) => boolean = or(hasJSFileExtension, hasTSFileExtension), +): boolean { + return firstDefined( + imports, + ({ text }) => + pathIsRelative(text) && !fileExtensionIsOneOf(text, extensionsNotSupportingExtensionlessResolution) + ? hasExtension(text) + : undefined, + ) || false; +} + +/** @internal */ +export function getModuleSpecifierEndingPreference( + preference: UserPreferences["importModuleSpecifierEnding"], + resolutionMode: ResolutionMode, + compilerOptions: CompilerOptions, + sourceFile: SourceFile, +): ModuleSpecifierEnding { if (preference === "js" || resolutionMode === ModuleKind.ESNext) { // Extensions are explicitly requested or required. Now choose between .js and .ts. if (!shouldAllowImportingTsExtension(compilerOptions)) { @@ -9369,9 +10335,9 @@ export function getModuleSpecifierEndingPreference(preference: UserPreferences[" function inferPreference() { let usesJsExtensions = false; - const specifiers = sourceFile.imports.length ? sourceFile.imports.map(i => i.text) : - isSourceFileJS(sourceFile) ? getRequiresAtTopOfFile(sourceFile).map(r => r.arguments[0].text) : - emptyArray; + const specifiers = sourceFile.imports.length ? sourceFile.imports.map(i => i.text) + : isSourceFileJS(sourceFile) ? getRequiresAtTopOfFile(sourceFile).map(r => r.arguments[0].text) + : emptyArray; for (const specifier of specifiers) { if (pathIsRelative(specifier)) { if (fileExtensionIsOneOf(specifier, extensionsNotSupportingExtensionlessResolution)) { @@ -9400,7 +10366,10 @@ function getRequiresAtTopOfFile(sourceFile: SourceFile): readonly RequireOrImpor if (isRequireVariableStatement(statement)) { requires = concatenate(requires, statement.declarationList.declarations.map(d => d.initializer)); } - else if (isExpressionStatement(statement) && isRequireCall(statement.expression, /*requireStringLiteralLikeArgument*/ true)) { + else if ( + isExpressionStatement(statement) + && isRequireCall(statement.expression, /*requireStringLiteralLikeArgument*/ true) + ) { requires = append(requires, statement.expression); } else { @@ -9411,11 +10380,19 @@ function getRequiresAtTopOfFile(sourceFile: SourceFile): readonly RequireOrImpor } /** @internal */ -export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: readonly FileExtensionInfo[]) { +export function isSupportedSourceFileName( + fileName: string, + compilerOptions?: CompilerOptions, + extraFileExtensions?: readonly FileExtensionInfo[], +) { if (!fileName) return false; const supportedExtensions = getSupportedExtensions(compilerOptions, extraFileExtensions); - for (const extension of flatten(getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, supportedExtensions))) { + for ( + const extension of flatten( + getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, supportedExtensions), + ) + ) { if (fileExtensionIs(fileName, extension)) { return true; } @@ -9432,11 +10409,24 @@ function numberOfDirectorySeparators(str: string) { export function compareNumberOfDirectorySeparators(path1: string, path2: string) { return compareValues( numberOfDirectorySeparators(path1), - numberOfDirectorySeparators(path2) + numberOfDirectorySeparators(path2), ); } -const extensionsToRemove = [Extension.Dts, Extension.Dmts, Extension.Dcts, Extension.Mjs, Extension.Mts, Extension.Cjs, Extension.Cts, Extension.Ts, Extension.Js, Extension.Tsx, Extension.Jsx, Extension.Json]; +const extensionsToRemove = [ + Extension.Dts, + Extension.Dmts, + Extension.Dcts, + Extension.Mjs, + Extension.Mts, + Extension.Cjs, + Extension.Cts, + Extension.Ts, + Extension.Js, + Extension.Tsx, + Extension.Jsx, + Extension.Json, +]; /** @internal */ export function removeFileExtension(path: string): string { for (const ext of extensionsToRemove) { @@ -9478,7 +10468,7 @@ export function tryParsePattern(pattern: string): string | Pattern | undefined { ? undefined : { prefix: pattern.substr(0, indexOfStar), - suffix: pattern.substr(indexOfStar + 1) + suffix: pattern.substr(indexOfStar + 1), }; } @@ -9500,7 +10490,9 @@ export function positionIsSynthesized(pos: number): boolean { * @internal */ export function extensionIsTS(ext: string): boolean { - return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts || ext === Extension.Cts || ext === Extension.Mts || ext === Extension.Dmts || ext === Extension.Dcts || (startsWith(ext, ".d.") && endsWith(ext, ".ts")); + return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts || ext === Extension.Cts + || ext === Extension.Mts || ext === Extension.Dmts || ext === Extension.Dcts + || (startsWith(ext, ".d.") && endsWith(ext, ".ts")); } /** @internal */ @@ -9537,10 +10529,9 @@ export function isCheckJsEnabledForFile(sourceFile: SourceFile, compilerOptions: /** @internal */ export const emptyFileSystemEntries: FileSystemEntries = { files: emptyArray, - directories: emptyArray + directories: emptyArray, }; - /** * patternOrStrings contains both patterns (containing "*") and regular strings. * Return an exact match if possible, or a pattern match, or undefined. @@ -9548,7 +10539,10 @@ export const emptyFileSystemEntries: FileSystemEntries = { * * @internal */ -export function matchPatternOrExact(patternOrStrings: readonly (string | Pattern)[], candidate: string): string | Pattern | undefined { +export function matchPatternOrExact( + patternOrStrings: readonly (string | Pattern)[], + candidate: string, +): string | Pattern | undefined { const patterns: Pattern[] = []; for (const patternOrString of patternOrStrings) { if (patternOrString === candidate) { @@ -9564,7 +10558,7 @@ export function matchPatternOrExact(patternOrStrings: readonly (string | Pattern } /** @internal */ -export type Mutable = { -readonly [K in keyof T]: T[K] }; +export type Mutable = { -readonly [K in keyof T]: T[K]; }; /** @internal */ export function sliceAfter(arr: readonly T[], value: T): readonly T[] { @@ -9574,20 +10568,29 @@ export function sliceAfter(arr: readonly T[], value: T): readonly T[] { } /** @internal */ -export function addRelatedInfo(diagnostic: T, ...relatedInformation: DiagnosticRelatedInformation[]): T { +export function addRelatedInfo( + diagnostic: T, + ...relatedInformation: DiagnosticRelatedInformation[] +): T { if (!relatedInformation.length) { return diagnostic; } if (!diagnostic.relatedInformation) { diagnostic.relatedInformation = []; } - Debug.assert(diagnostic.relatedInformation !== emptyArray, "Diagnostic had empty array singleton for related info, but is still being constructed!"); + Debug.assert( + diagnostic.relatedInformation !== emptyArray, + "Diagnostic had empty array singleton for related info, but is still being constructed!", + ); diagnostic.relatedInformation.push(...relatedInformation); return diagnostic; } /** @internal */ -export function minAndMax(arr: readonly T[], getValue: (value: T) => number): { readonly min: number, readonly max: number } { +export function minAndMax( + arr: readonly T[], + getValue: (value: T) => number, +): { readonly min: number; readonly max: number; } { Debug.assert(arr.length !== 0); let min = getValue(arr[0]); let max = min; @@ -9609,7 +10612,10 @@ export function rangeOfNode(node: Node): TextRange { } /** @internal */ -export function rangeOfTypeParameters(sourceFile: SourceFile, typeParameters: NodeArray): TextRange { +export function rangeOfTypeParameters( + sourceFile: SourceFile, + typeParameters: NodeArray, +): TextRange { // Include the `<>` const pos = typeParameters.pos - 1; const end = Math.min(sourceFile.text.length, skipTrivia(sourceFile.text, typeParameters.end) + 1); @@ -9621,19 +10627,25 @@ export interface HostWithIsSourceOfProjectReferenceRedirect { isSourceOfProjectReferenceRedirect(fileName: string): boolean; } /** @internal */ -export function skipTypeChecking(sourceFile: SourceFile, options: CompilerOptions, host: HostWithIsSourceOfProjectReferenceRedirect) { +export function skipTypeChecking( + sourceFile: SourceFile, + options: CompilerOptions, + host: HostWithIsSourceOfProjectReferenceRedirect, +) { // If skipLibCheck is enabled, skip reporting errors if file is a declaration file. // If skipDefaultLibCheck is enabled, skip reporting errors if file contains a // '/// ' directive. - return (options.skipLibCheck && sourceFile.isDeclarationFile || - options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib) || - host.isSourceOfProjectReferenceRedirect(sourceFile.fileName); + return (options.skipLibCheck && sourceFile.isDeclarationFile + || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib) + || host.isSourceOfProjectReferenceRedirect(sourceFile.fileName); } /** @internal */ export function isJsonEqual(a: unknown, b: unknown): boolean { // eslint-disable-next-line no-null/no-null - return a === b || typeof a === "object" && a !== null && typeof b === "object" && b !== null && equalOwnProperties(a as MapLike, b as MapLike, isJsonEqual); + return a === b + || typeof a === "object" && a !== null && typeof b === "object" && b !== null + && equalOwnProperties(a as MapLike, b as MapLike, isJsonEqual); } /** @@ -9680,8 +10692,8 @@ export function parsePseudoBigInt(stringValue: string): string { // Find character range: 0-9 < A-F < a-f const digit = digitChar <= CharacterCodes._9 ? digitChar - CharacterCodes._0 - : 10 + digitChar - - (digitChar <= CharacterCodes.F ? CharacterCodes.A : CharacterCodes.a); + : 10 + digitChar + - (digitChar <= CharacterCodes.F ? CharacterCodes.A : CharacterCodes.a); const shiftedDigit = digit << (bitOffset & 15); segments[segment] |= shiftedDigit; const residual = shiftedDigit >>> 16; @@ -9710,7 +10722,7 @@ export function parsePseudoBigInt(stringValue: string): string { } /** @internal */ -export function pseudoBigIntToString({negative, base10Value}: PseudoBigInt): string { +export function pseudoBigIntToString({ negative, base10Value }: PseudoBigInt): string { return (negative && base10Value !== "0" ? "-" : "") + base10Value; } @@ -9755,8 +10767,10 @@ export function isValidBigIntString(s: string, roundTripOnly: boolean): boolean // * a bigint can be scanned, and that when it is scanned, it is // * the full length of the input string (so the scanner is one character beyond the augmented input length) // * it does not contain a numeric seperator (the `BigInt` constructor does not accept a numeric seperator in its input) - return success && result === SyntaxKind.BigIntLiteral && scanner.getTokenEnd() === (s.length + 1) && !(flags & TokenFlags.ContainsSeparator) - && (!roundTripOnly || s === pseudoBigIntToString({ negative, base10Value: parsePseudoBigInt(scanner.getTokenValue()) })); + return success && result === SyntaxKind.BigIntLiteral && scanner.getTokenEnd() === (s.length + 1) + && !(flags & TokenFlags.ContainsSeparator) + && (!roundTripOnly + || s === pseudoBigIntToString({ negative, base10Value: parsePseudoBigInt(scanner.getTokenValue()) })); } /** @internal */ @@ -9800,11 +10814,12 @@ function isIdentifierInNonEmittingHeritageClause(node: Node): boolean { return "quit"; } }) as HeritageClause | undefined; - return heritageClause?.token === SyntaxKind.ImplementsKeyword || heritageClause?.parent.kind === SyntaxKind.InterfaceDeclaration; + return heritageClause?.token === SyntaxKind.ImplementsKeyword + || heritageClause?.parent.kind === SyntaxKind.InterfaceDeclaration; } /** @internal */ -export function isIdentifierTypeReference(node: Node): node is TypeReferenceNode & { typeName: Identifier } { +export function isIdentifierTypeReference(node: Node): node is TypeReferenceNode & { typeName: Identifier; } { return isTypeReferenceNode(node) && isIdentifier(node.typeName); } @@ -9897,9 +10912,15 @@ export function setParent(child: T | undefined, parent: T["paren */ export function setEachParent(children: T, parent: T[number]["parent"]): T; /** @internal */ -export function setEachParent(children: T | undefined, parent: T[number]["parent"]): T | undefined; +export function setEachParent( + children: T | undefined, + parent: T[number]["parent"], +): T | undefined; /** @internal */ -export function setEachParent(children: T | undefined, parent: T[number]["parent"]): T | undefined { +export function setEachParent( + children: T | undefined, + parent: T[number]["parent"], +): T | undefined { if (children) { for (const child of children) { setParent(child, parent); @@ -9976,9 +10997,11 @@ export function expressionResultIsUnused(node: Expression): boolean { continue; } // result is unused in an expression statement, `void` expression, or the initializer or incrementer of a `for` loop - if (isExpressionStatement(parent) || - isVoidExpression(parent) || - isForStatement(parent) && (parent.initializer === node || parent.incrementor === node)) { + if ( + isExpressionStatement(parent) + || isVoidExpression(parent) + || isForStatement(parent) && (parent.initializer === node || parent.incrementor === node) + ) { return true; } if (isCommaListExpression(parent)) { @@ -10019,8 +11042,8 @@ export function getContainingNodeArray(node: Node): NodeArray | undefined return (node as TemplateSpan).parent.templateSpans; case SyntaxKind.Decorator: { const { parent } = node as Decorator; - return canHaveDecorators(parent) ? parent.modifiers : - undefined; + return canHaveDecorators(parent) ? parent.modifiers + : undefined; } case SyntaxKind.HeritageClause: return (node as HeritageClause).parent.heritageClauses; @@ -10043,15 +11066,20 @@ export function getContainingNodeArray(node: Node): NodeArray | undefined case SyntaxKind.CommaListExpression: case SyntaxKind.NamedImports: case SyntaxKind.NamedExports: - return (parent as TupleTypeNode | ArrayLiteralExpression | CommaListExpression | NamedImports | NamedExports).elements; + return (parent as + | TupleTypeNode + | ArrayLiteralExpression + | CommaListExpression + | NamedImports + | NamedExports).elements; case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.JsxAttributes: return (parent as ObjectLiteralExpressionBase).properties; case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: - return isTypeNode(node) ? (parent as CallExpression | NewExpression).typeArguments : - (parent as CallExpression | NewExpression).expression === node ? undefined : - (parent as CallExpression | NewExpression).arguments; + return isTypeNode(node) ? (parent as CallExpression | NewExpression).typeArguments + : (parent as CallExpression | NewExpression).expression === node ? undefined + : (parent as CallExpression | NewExpression).arguments; case SyntaxKind.JsxElement: case SyntaxKind.JsxFragment: return isJsxChild(node) ? (parent as JsxElement | JsxFragment).children : undefined; @@ -10148,10 +11176,15 @@ export function isNumericLiteralName(name: string | __String) { } /** @internal */ -export function createPropertyNameNodeForIdentifierOrLiteral(name: string, target: ScriptTarget, singleQuote?: boolean, stringNamed?: boolean) { - return isIdentifierText(name, target) ? factory.createIdentifier(name) : - !stringNamed && isNumericLiteralName(name) && +name >= 0 ? factory.createNumericLiteral(+name) : - factory.createStringLiteral(name, !!singleQuote); +export function createPropertyNameNodeForIdentifierOrLiteral( + name: string, + target: ScriptTarget, + singleQuote?: boolean, + stringNamed?: boolean, +) { + return isIdentifierText(name, target) ? factory.createIdentifier(name) + : !stringNamed && isNumericLiteralName(name) && +name >= 0 ? factory.createNumericLiteral(+name) + : factory.createStringLiteral(name, !!singleQuote); } /** @internal */ @@ -10181,7 +11214,7 @@ export function getNodeModulePathParts(fullPath: string): NodeModulePathParts | BeforeNodeModules, NodeModules, Scope, - PackageContent + PackageContent, } let partStart = 0; @@ -10222,7 +11255,8 @@ export function getNodeModulePathParts(fullPath: string): NodeModulePathParts | fileNameIndex = partStart; - return state > States.NodeModules ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined; + return state > States.NodeModules + ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined; } /** @internal */ @@ -10231,7 +11265,21 @@ export function getParameterTypeNode(parameter: ParameterDeclaration | JSDocPara } /** @internal */ -export function isTypeDeclaration(node: Node): node is TypeParameterDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag | EnumDeclaration | ImportClause | ImportSpecifier | ExportSpecifier { +export function isTypeDeclaration( + node: Node, +): node is + | TypeParameterDeclaration + | ClassDeclaration + | InterfaceDeclaration + | TypeAliasDeclaration + | JSDocTypedefTag + | JSDocCallbackTag + | JSDocEnumTag + | EnumDeclaration + | ImportClause + | ImportSpecifier + | ExportSpecifier +{ switch (node.kind) { case SyntaxKind.TypeParameter: case SyntaxKind.ClassDeclaration: @@ -10254,8 +11302,10 @@ export function isTypeDeclaration(node: Node): node is TypeParameterDeclaration /** @internal */ export function canHaveExportModifier(node: Node): node is Extract { - return isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node) - || isInterfaceDeclaration(node) || isTypeDeclaration(node) || (isModuleDeclaration(node) && !isExternalModuleAugmentation(node) && !isGlobalScopeAugmentation(node)); + return isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) + || isClassDeclaration(node) + || isInterfaceDeclaration(node) || isTypeDeclaration(node) + || (isModuleDeclaration(node) && !isExternalModuleAugmentation(node) && !isGlobalScopeAugmentation(node)); } /** @internal */ @@ -10265,7 +11315,6 @@ export function isOptionalJSDocPropertyLikeTag(node: Node): node is JSDocPropert } const { isBracketed, typeExpression } = node; return isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType; - } /** @internal */ @@ -10274,9 +11323,9 @@ export function canUsePropertyAccess(name: string, languageVersion: ScriptTarget return false; } const firstChar = name.charCodeAt(0); - return firstChar === CharacterCodes.hash ? - name.length > 1 && isIdentifierStart(name.charCodeAt(1), languageVersion) : - isIdentifierStart(firstChar, languageVersion); + return firstChar === CharacterCodes.hash + ? name.length > 1 && isIdentifierStart(name.charCodeAt(1), languageVersion) + : isIdentifierStart(firstChar, languageVersion); } /** @internal */ @@ -10290,7 +11339,9 @@ export function isJSDocOptionalParameter(node: ParameterDeclaration) { // node.type should only be a JSDocOptionalType when node is a parameter of a JSDocFunctionType node.type && node.type.kind === SyntaxKind.JSDocOptionalType || getJSDocParameterTags(node).some(({ isBracketed, typeExpression }) => - isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType)); + isBracketed || !!typeExpression && typeExpression.type.kind === SyntaxKind.JSDocOptionalType + ) + ); } /** @internal */ @@ -10300,7 +11351,8 @@ export function isOptionalDeclaration(declaration: Declaration): boolean { case SyntaxKind.PropertySignature: return !!(declaration as PropertyDeclaration | PropertySignature).questionToken; case SyntaxKind.Parameter: - return !!(declaration as ParameterDeclaration).questionToken || isJSDocOptionalParameter(declaration as ParameterDeclaration); + return !!(declaration as ParameterDeclaration).questionToken + || isJSDocOptionalParameter(declaration as ParameterDeclaration); case SyntaxKind.JSDocPropertyTag: case SyntaxKind.JSDocParameterTag: return isOptionalJSDocPropertyLikeTag(declaration); @@ -10368,7 +11420,9 @@ export function intrinsicTagNameToString(node: Identifier | JsxNamespacedName) { * Indicates whether a type can be used as a property name. * @internal */ -export function isTypeUsableAsPropertyName(type: Type): type is StringLiteralType | NumberLiteralType | UniqueESSymbolType { +export function isTypeUsableAsPropertyName( + type: Type, +): type is StringLiteralType | NumberLiteralType | UniqueESSymbolType { return !!(type.flags & TypeFlags.StringOrNumberLiteralOrUnique); } diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 56574d44d1d65..a5caf41e70e57 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -311,7 +311,7 @@ export function getDefaultLibFileName(options: CompilerOptions): string { case ScriptTarget.ES2016: return "lib.es2016.full.d.ts"; case ScriptTarget.ES2015: - return "lib.es6.d.ts"; // We don't use lib.es2015.full.d.ts due to breaking change. + return "lib.es6.d.ts"; // We don't use lib.es2015.full.d.ts due to breaking change. default: return "lib.d.ts"; } @@ -539,10 +539,11 @@ export function getTypeParameterOwner(d: Declaration): Declaration | undefined { } } -export type ParameterPropertyDeclaration = ParameterDeclaration & { parent: ConstructorDeclaration, name: Identifier }; +export type ParameterPropertyDeclaration = ParameterDeclaration & { parent: ConstructorDeclaration; name: Identifier; }; export function isParameterPropertyDeclaration(node: Node, parent: Node): node is ParameterPropertyDeclaration { - return isParameter(node) && hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) && parent.kind === SyntaxKind.Constructor; + return isParameter(node) && hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) + && parent.kind === SyntaxKind.Constructor; } export function isEmptyBindingPattern(node: BindingName): node is BindingPattern { @@ -613,7 +614,21 @@ function getNodeFlags(node: Node) { } /** @internal */ -export const supportedLocaleDirectories = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"]; +export const supportedLocaleDirectories = [ + "cs", + "de", + "es", + "fr", + "it", + "ja", + "ko", + "pl", + "pt-br", + "ru", + "tr", + "zh-cn", + "zh-tw", +]; /** * Checks to see if the locale is in the appropriate format, @@ -621,14 +636,26 @@ export const supportedLocaleDirectories = ["cs", "de", "es", "fr", "it", "ja", " */ export function validateLocaleAndSetLanguage( locale: string, - sys: { getExecutingFilePath(): string, resolvePath(path: string): string, fileExists(fileName: string): boolean, readFile(fileName: string): string | undefined }, - errors?: Diagnostic[]) { + sys: { + getExecutingFilePath(): string; + resolvePath(path: string): string; + fileExists(fileName: string): boolean; + readFile(fileName: string): string | undefined; + }, + errors?: Diagnostic[], +) { const lowerCaseLocale = locale.toLowerCase(); const matchResult = /^([a-z]+)([_-]([a-z]+))?$/.exec(lowerCaseLocale); if (!matchResult) { if (errors) { - errors.push(createCompilerDiagnostic(Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, "en", "ja-jp")); + errors.push( + createCompilerDiagnostic( + Diagnostics.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, + "en", + "ja-jp", + ), + ); } return; } @@ -638,14 +665,21 @@ export function validateLocaleAndSetLanguage( // First try the entire locale, then fall back to just language if that's all we have. // Either ways do not fail, and fallback to the English diagnostic strings. - if (contains(supportedLocaleDirectories, lowerCaseLocale) && !trySetLanguageAndTerritory(language, territory, errors)) { + if ( + contains(supportedLocaleDirectories, lowerCaseLocale) + && !trySetLanguageAndTerritory(language, territory, errors) + ) { trySetLanguageAndTerritory(language, /*territory*/ undefined, errors); } // Set the UI locale for string collation setUILocale(locale); - function trySetLanguageAndTerritory(language: string, territory: string | undefined, errors?: Diagnostic[]): boolean { + function trySetLanguageAndTerritory( + language: string, + territory: string | undefined, + errors?: Diagnostic[], + ): boolean { const compilerFilePath = normalizePath(sys.getExecutingFilePath()); const containingDirectoryPath = getDirectoryPath(compilerFilePath); @@ -690,8 +724,14 @@ export function validateLocaleAndSetLanguage( export function getOriginalNode(node: Node): Node; export function getOriginalNode(node: Node, nodeTest: (node: Node) => node is T): T; export function getOriginalNode(node: Node | undefined): Node | undefined; -export function getOriginalNode(node: Node | undefined, nodeTest: (node: Node) => node is T): T | undefined; -export function getOriginalNode(node: Node | undefined, nodeTest?: (node: Node) => node is T): T | undefined { +export function getOriginalNode( + node: Node | undefined, + nodeTest: (node: Node) => node is T, +): T | undefined; +export function getOriginalNode( + node: Node | undefined, + nodeTest?: (node: Node) => node is T, +): T | undefined { if (node) { while (node.original !== undefined) { node = node.original; @@ -711,7 +751,10 @@ export function getOriginalNode(node: Node | undefined, nodeTest * If no such value is found, it applies the callback until the parent pointer is undefined or the callback returns "quit" * At that point findAncestor returns undefined. */ -export function findAncestor(node: Node | undefined, callback: (element: Node) => element is T): T | undefined; +export function findAncestor( + node: Node | undefined, + callback: (element: Node) => element is T, +): T | undefined; export function findAncestor(node: Node | undefined, callback: (element: Node) => boolean | "quit"): Node | undefined; export function findAncestor(node: Node | undefined, callback: (element: Node) => boolean | "quit"): Node | undefined { while (node) { @@ -751,7 +794,10 @@ export function getParseTreeNode(node: Node | undefined): Node | undefined; * @param nodeTest A callback used to ensure the correct type of parse tree node is returned. * @returns The original parse tree node if found; otherwise, undefined. */ -export function getParseTreeNode(node: T | undefined, nodeTest?: (node: Node) => node is T): T | undefined; +export function getParseTreeNode( + node: T | undefined, + nodeTest?: (node: Node) => node is T, +): T | undefined; export function getParseTreeNode(node: Node | undefined, nodeTest?: (node: Node) => boolean): Node | undefined { if (node === undefined || isParseTreeNode(node)) { return node; @@ -768,7 +814,8 @@ export function getParseTreeNode(node: Node | undefined, nodeTest?: (node: Node) /** Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' */ export function escapeLeadingUnderscores(identifier: string): __String { - return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier) as __String; + return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ + && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier) as __String; } /** @@ -779,7 +826,8 @@ export function escapeLeadingUnderscores(identifier: string): __String { */ export function unescapeLeadingUnderscores(identifier: __String): string { const id = identifier as string; - return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ && id.charCodeAt(2) === CharacterCodes._ ? id.substr(1) : id; + return id.length >= 3 && id.charCodeAt(0) === CharacterCodes._ && id.charCodeAt(1) === CharacterCodes._ + && id.charCodeAt(2) === CharacterCodes._ ? id.substr(1) : id; } export function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string { @@ -807,7 +855,9 @@ export function symbolName(symbol: Symbol): string { * attempt to draw the name from the node the declaration is on (as that declaration is what its' symbol * will be merged with) */ -function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag | JSDocEnumTag): Identifier | PrivateIdentifier | undefined { +function nameForNamelessJSDocTypedef( + declaration: JSDocTypedefTag | JSDocEnumTag, +): Identifier | PrivateIdentifier | undefined { const hostNode = declaration.parent.parent; if (!hostNode) { return undefined; @@ -825,7 +875,10 @@ function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag | JSDocEnumTag break; case SyntaxKind.ExpressionStatement: let expr = hostNode.expression; - if (expr.kind === SyntaxKind.BinaryExpression && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + expr.kind === SyntaxKind.BinaryExpression + && (expr as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { expr = (expr as BinaryExpression).left; } switch (expr.kind) { @@ -857,7 +910,10 @@ function getDeclarationIdentifier(node: Declaration | Expression): Identifier | /** @internal */ export function nodeHasName(statement: Node, name: Identifier) { - if (isNamedDeclaration(statement) && isIdentifier(statement.name) && idText(statement.name as Identifier) === idText(name)) { + if ( + isNamedDeclaration(statement) && isIdentifier(statement.name) + && idText(statement.name as Identifier) === idText(name) + ) { return true; } if (isVariableStatement(statement) && some(statement.declarationList.declarations, d => nodeHasName(d, name))) { @@ -871,7 +927,7 @@ export function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier } /** @internal */ -export function isNamedDeclaration(node: Node): node is NamedDeclaration & { name: DeclarationName } { +export function isNamedDeclaration(node: Node): node is NamedDeclaration & { name: DeclarationName; } { return !!(node as NamedDeclaration).name; // A 'name' property should always be a DeclarationName. } @@ -896,7 +952,9 @@ export function getNonAssignedNameOfDeclaration(declaration: Declaration | Expre case AssignmentDeclarationKind.ThisProperty: case AssignmentDeclarationKind.Property: case AssignmentDeclarationKind.PrototypeProperty: - return getElementOrPropertyAccessArgumentExpressionOrName((expr as BinaryExpression).left as AccessExpression); + return getElementOrPropertyAccessArgumentExpressionOrName( + (expr as BinaryExpression).left as AccessExpression, + ); case AssignmentDeclarationKind.ObjectDefinePropertyValue: case AssignmentDeclarationKind.ObjectDefinePropertyExports: case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: @@ -924,8 +982,9 @@ export function getNonAssignedNameOfDeclaration(declaration: Declaration | Expre export function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined { if (declaration === undefined) return undefined; - return getNonAssignedNameOfDeclaration(declaration) || - (isFunctionExpression(declaration) || isArrowFunction(declaration) || isClassExpression(declaration) ? getAssignedName(declaration) : undefined); + return getNonAssignedNameOfDeclaration(declaration) + || (isFunctionExpression(declaration) || isArrowFunction(declaration) || isClassExpression(declaration) + ? getAssignedName(declaration) : undefined); } /** @internal */ @@ -965,7 +1024,9 @@ function getJSDocParameterTagsWorker(param: ParameterDeclaration, noCache?: bool if (param.name) { if (isIdentifier(param.name)) { const name = param.name.escapedText; - return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name); + return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocParameterTag => + isJSDocParameterTag(tag) && isIdentifier(tag.name) && tag.name.escapedText === name + ); } else { const i = param.parent.parameters.indexOf(param); @@ -1001,10 +1062,14 @@ export function getJSDocParameterTagsNoCache(param: ParameterDeclaration): reado return getJSDocParameterTagsWorker(param, /*noCache*/ true); } -function getJSDocTypeParameterTagsWorker(param: TypeParameterDeclaration, noCache?: boolean): readonly JSDocTemplateTag[] { +function getJSDocTypeParameterTagsWorker( + param: TypeParameterDeclaration, + noCache?: boolean, +): readonly JSDocTemplateTag[] { const name = param.name.escapedText; return getJSDocTagsWorker(param.parent, noCache).filter((tag): tag is JSDocTemplateTag => - isJSDocTemplateTag(tag) && tag.typeParameters.some(tp => tp.name.escapedText === name)); + isJSDocTemplateTag(tag) && tag.typeParameters.some(tp => tp.name.escapedText === name) + ); } /** @@ -1210,7 +1275,11 @@ export function getJSDocTagsNoCache(node: Node): readonly JSDocTag[] { } /** Get the first JSDoc tag of a specified kind, or undefined if not present. */ -function getFirstJSDocTag(node: Node, predicate: (tag: JSDocTag) => tag is T, noCache?: boolean): T | undefined { +function getFirstJSDocTag( + node: Node, + predicate: (tag: JSDocTag) => tag is T, + noCache?: boolean, +): T | undefined { return find(getJSDocTagsWorker(node, noCache), predicate); } @@ -1249,7 +1318,9 @@ function formatJSDocLink(link: JSDocLink | JSDocLinkCode | JSDocLinkPlain) { * /** @type {Id} / * function id(x) { return x } */ -export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] { +export function getEffectiveTypeParameterDeclarations( + node: DeclarationWithTypeParameters, +): readonly TypeParameterDeclaration[] { if (isJSDocSignature(node)) { if (isJSDocOverloadTag(node.parent)) { const jsDoc = getJSDocRoot(node.parent); @@ -1283,9 +1354,9 @@ export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeP } export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined { - return node.constraint ? node.constraint : - isJSDocTemplateTag(node.parent) && node === node.parent.typeParameters[0] ? node.parent.constraint : - undefined; + return node.constraint ? node.constraint + : isJSDocTemplateTag(node.parent) && node === node.parent.typeParameters[0] ? node.parent.constraint + : undefined; } // #region @@ -1311,10 +1382,12 @@ export function isCallChain(node: Node): node is CallChain { return isCallExpression(node) && !!(node.flags & NodeFlags.OptionalChain); } -export function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain { +export function isOptionalChain( + node: Node, +): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain { const kind = node.kind; - return !!(node.flags & NodeFlags.OptionalChain) && - (kind === SyntaxKind.PropertyAccessExpression + return !!(node.flags & NodeFlags.OptionalChain) + && (kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.ElementAccessExpression || kind === SyntaxKind.CallExpression || kind === SyntaxKind.NonNullExpression); @@ -1330,7 +1403,7 @@ export function isOptionalChainRoot(node: Node): node is OptionalChainRoot { * * @internal */ -export function isExpressionOfOptionalChainRoot(node: Node): node is Expression & { parent: OptionalChainRoot } { +export function isExpressionOfOptionalChainRoot(node: Node): node is Expression & { parent: OptionalChainRoot; } { return isOptionalChainRoot(node.parent) && node.parent.expression === node; } @@ -1354,12 +1427,13 @@ export function isOutermostOptionalChain(node: OptionalChain) { } export function isNullishCoalesce(node: Node) { - return node.kind === SyntaxKind.BinaryExpression && (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken; + return node.kind === SyntaxKind.BinaryExpression + && (node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken; } export function isConstTypeReference(node: Node) { - return isTypeReferenceNode(node) && isIdentifier(node.typeName) && - node.typeName.escapedText === "const" && !node.typeArguments; + return isTypeReferenceNode(node) && isIdentifier(node.typeName) + && node.typeName.escapedText === "const" && !node.typeArguments; } export function skipPartiallyEmittedExpressions(node: Expression): Expression; @@ -1393,9 +1467,9 @@ export function isUnparsedTextLike(node: Node): node is UnparsedTextLike { /** @deprecated */ export function isUnparsedNode(node: Node): node is UnparsedNode { - return isUnparsedTextLike(node) || - node.kind === SyntaxKind.UnparsedPrologue || - node.kind === SyntaxKind.UnparsedSyntheticReference; + return isUnparsedTextLike(node) + || node.kind === SyntaxKind.UnparsedPrologue + || node.kind === SyntaxKind.UnparsedSyntheticReference; } export function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag { @@ -1507,7 +1581,8 @@ export function isTypeOnlyExportDeclaration(node: Node): node is TypeOnlyExportD case SyntaxKind.ExportSpecifier: return (node as ExportSpecifier).isTypeOnly || (node as ExportSpecifier).parent.parent.isTypeOnly; case SyntaxKind.ExportDeclaration: - return (node as ExportDeclaration).isTypeOnly && !!(node as ExportDeclaration).moduleSpecifier && !(node as ExportDeclaration).exportClause; + return (node as ExportDeclaration).isTypeOnly && !!(node as ExportDeclaration).moduleSpecifier + && !(node as ExportDeclaration).exportClause; case SyntaxKind.NamespaceExport: return (node as NamespaceExport).parent.isTypeOnly; } @@ -1553,7 +1628,9 @@ export function isPrivateIdentifierClassElementDeclaration(node: Node): node is } /** @internal */ -export function isPrivateIdentifierPropertyAccessExpression(node: Node): node is PrivateIdentifierPropertyAccessExpression { +export function isPrivateIdentifierPropertyAccessExpression( + node: Node, +): node is PrivateIdentifierPropertyAccessExpression { return isPropertyAccessExpression(node) && isPrivateIdentifier(node.name); } @@ -1589,10 +1666,10 @@ export function isParameterPropertyModifier(kind: SyntaxKind): boolean { /** @internal */ export function isClassMemberModifier(idToken: SyntaxKind): boolean { - return isParameterPropertyModifier(idToken) || - idToken === SyntaxKind.StaticKeyword || - idToken === SyntaxKind.OverrideKeyword || - idToken === SyntaxKind.AccessorKeyword; + return isParameterPropertyModifier(idToken) + || idToken === SyntaxKind.StaticKeyword + || idToken === SyntaxKind.OverrideKeyword + || idToken === SyntaxKind.AccessorKeyword; } export function isModifier(node: Node): node is Modifier { @@ -1628,7 +1705,9 @@ export function isFunctionLike(node: Node | undefined): node is SignatureDeclara } /** @internal */ -export function isFunctionLikeOrClassStaticBlockDeclaration(node: Node | undefined): node is SignatureDeclaration | ClassStaticBlockDeclaration { +export function isFunctionLikeOrClassStaticBlockDeclaration( + node: Node | undefined, +): node is SignatureDeclaration | ClassStaticBlockDeclaration { return !!node && (isFunctionLikeKind(node.kind) || isClassStaticBlockDeclaration(node)); } @@ -1801,20 +1880,20 @@ export function isAssignmentPattern(node: Node): node is AssignmentPattern { || kind === SyntaxKind.ObjectLiteralExpression; } - export function isArrayBindingElement(node: Node): node is ArrayBindingElement { const kind = node.kind; return kind === SyntaxKind.BindingElement || kind === SyntaxKind.OmittedExpression; } - /** * Determines whether the BindingOrAssignmentElement is a BindingElement-like declaration * * @internal */ -export function isDeclarationBindingElement(bindingElement: BindingOrAssignmentElement): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { +export function isDeclarationBindingElement( + bindingElement: BindingOrAssignmentElement, +): bindingElement is VariableDeclaration | ParameterDeclaration | BindingElement { switch (bindingElement.kind) { case SyntaxKind.VariableDeclaration: case SyntaxKind.Parameter: @@ -1838,7 +1917,9 @@ export function isBindingOrAssignmentElement(node: Node): node is BindingOrAssig * * @internal */ -export function isBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is BindingOrAssignmentPattern { +export function isBindingOrAssignmentPattern( + node: BindingOrAssignmentElementTarget, +): node is BindingOrAssignmentPattern { return isObjectBindingOrAssignmentPattern(node) || isArrayBindingOrAssignmentPattern(node); } @@ -1848,7 +1929,9 @@ export function isBindingOrAssignmentPattern(node: BindingOrAssignmentElementTar * * @internal */ -export function isObjectBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ObjectBindingOrAssignmentPattern { +export function isObjectBindingOrAssignmentPattern( + node: BindingOrAssignmentElementTarget, +): node is ObjectBindingOrAssignmentPattern { switch (node.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ObjectLiteralExpression: @@ -1875,7 +1958,9 @@ export function isObjectBindingOrAssignmentElement(node: Node): node is ObjectBi * * @internal */ -export function isArrayBindingOrAssignmentPattern(node: BindingOrAssignmentElementTarget): node is ArrayBindingOrAssignmentPattern { +export function isArrayBindingOrAssignmentPattern( + node: BindingOrAssignmentElementTarget, +): node is ArrayBindingOrAssignmentPattern { switch (node.kind) { case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ArrayLiteralExpression: @@ -1902,7 +1987,9 @@ export function isArrayBindingOrAssignmentElement(node: Node): node is ArrayBind } /** @internal */ -export function isPropertyAccessOrQualifiedNameOrImportTypeNode(node: Node): node is PropertyAccessExpression | QualifiedName | ImportTypeNode { +export function isPropertyAccessOrQualifiedNameOrImportTypeNode( + node: Node, +): node is PropertyAccessExpression | QualifiedName | ImportTypeNode { const kind = node.kind; return kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.QualifiedName @@ -2010,14 +2097,16 @@ export function isUnaryExpressionWithWrite(expr: Node): expr is PrefixUnaryExpre case SyntaxKind.PostfixUnaryExpression: return true; case SyntaxKind.PrefixUnaryExpression: - return (expr as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken || - (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken; + return (expr as PrefixUnaryExpression).operator === SyntaxKind.PlusPlusToken + || (expr as PrefixUnaryExpression).operator === SyntaxKind.MinusMinusToken; default: return false; } } -export function isLiteralTypeLiteral(node: Node): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression { +export function isLiteralTypeLiteral( + node: Node, +): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression { switch (node.kind) { case SyntaxKind.NullKeyword: case SyntaxKind.TrueKeyword: @@ -2061,7 +2150,9 @@ export function isAssertionExpression(node: Node): node is AssertionExpression { } /** @internal */ -export function isNotEmittedOrPartiallyEmittedNode(node: Node): node is NotEmittedStatement | PartiallyEmittedExpression { +export function isNotEmittedOrPartiallyEmittedNode( + node: Node, +): node is NotEmittedStatement | PartiallyEmittedExpression { return isNotEmittedStatement(node) || isPartiallyEmittedExpression(node); } @@ -2069,7 +2160,10 @@ export function isNotEmittedOrPartiallyEmittedNode(node: Node): node is NotEmitt // Statement export function isIterationStatement(node: Node, lookInLabeledStatements: false): node is IterationStatement; -export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement | LabeledStatement; +export function isIterationStatement( + node: Node, + lookInLabeledStatements: boolean, +): node is IterationStatement | LabeledStatement; export function isIterationStatement(node: Node, lookInLabeledStatements: boolean): node is IterationStatement { switch (node.kind) { case SyntaxKind.ForStatement: @@ -2079,7 +2173,8 @@ export function isIterationStatement(node: Node, lookInLabeledStatements: boolea case SyntaxKind.WhileStatement: return true; case SyntaxKind.LabeledStatement: - return lookInLabeledStatements && isIterationStatement((node as LabeledStatement).statement, lookInLabeledStatements); + return lookInLabeledStatements + && isIterationStatement((node as LabeledStatement).statement, lookInLabeledStatements); } return false; @@ -2097,13 +2192,15 @@ export function hasScopeMarker(statements: readonly Statement[]) { /** @internal */ export function needsScopeMarker(result: Statement) { - return !isAnyImportOrReExport(result) && !isExportAssignment(result) && !hasSyntacticModifier(result, ModifierFlags.Export) && !isAmbientModule(result); + return !isAnyImportOrReExport(result) && !isExportAssignment(result) + && !hasSyntacticModifier(result, ModifierFlags.Export) && !isAmbientModule(result); } /** @internal */ export function isExternalModuleIndicator(result: Statement) { // Exported top-level member indicates moduleness - return isAnyImportOrReExport(result) || isExportAssignment(result) || hasSyntacticModifier(result, ModifierFlags.Export); + return isAnyImportOrReExport(result) || isExportAssignment(result) + || hasSyntacticModifier(result, ModifierFlags.Export); } /** @internal */ @@ -2539,7 +2636,8 @@ export function hasOnlyExpressionInitializer(node: Node): node is HasExpressionI } export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement { - return node.kind === SyntaxKind.JsxAttribute || node.kind === SyntaxKind.JsxSpreadAttribute || isObjectLiteralElementLike(node); + return node.kind === SyntaxKind.JsxAttribute || node.kind === SyntaxKind.JsxSpreadAttribute + || isObjectLiteralElementLike(node); } /** @internal */ @@ -2572,11 +2670,13 @@ export function guessIndentation(lines: string[]) { } export function isStringLiteralLike(node: Node | FileReference): node is StringLiteralLike { - return (node as Node).kind === SyntaxKind.StringLiteral || (node as Node).kind === SyntaxKind.NoSubstitutionTemplateLiteral; + return (node as Node).kind === SyntaxKind.StringLiteral + || (node as Node).kind === SyntaxKind.NoSubstitutionTemplateLiteral; } export function isJSDocLinkLike(node: Node): node is JSDocLink | JSDocLinkCode | JSDocLinkPlain { - return node.kind === SyntaxKind.JSDocLink || node.kind === SyntaxKind.JSDocLinkCode || node.kind === SyntaxKind.JSDocLinkPlain; + return node.kind === SyntaxKind.JSDocLink || node.kind === SyntaxKind.JSDocLinkCode + || node.kind === SyntaxKind.JSDocLinkPlain; } export function hasRestParameter(s: SignatureDeclaration | JSDocSignature): boolean { @@ -2586,5 +2686,6 @@ export function hasRestParameter(s: SignatureDeclaration | JSDocSignature): bool export function isRestParameter(node: ParameterDeclaration | JSDocParameterTag): boolean { const type = isJSDocParameterTag(node) ? (node.typeExpression && node.typeExpression.type) : node.type; - return (node as ParameterDeclaration).dotDotDotToken !== undefined || !!type && type.kind === SyntaxKind.JSDocVariadicType; + return (node as ParameterDeclaration).dotDotDotToken !== undefined + || !!type && type.kind === SyntaxKind.JSDocVariadicType; } diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 08475d5c0ae7a..eb9e4361a9c57 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -377,7 +377,14 @@ function visitArrayWorker( * Starts a new lexical environment and visits a statement list, ending the lexical environment * and merging hoisted declarations upon completion. */ -export function visitLexicalEnvironment(statements: NodeArray, visitor: Visitor, context: TransformationContext, start?: number, ensureUseStrict?: boolean, nodesVisitor: NodesVisitor = visitNodes) { +export function visitLexicalEnvironment( + statements: NodeArray, + visitor: Visitor, + context: TransformationContext, + start?: number, + ensureUseStrict?: boolean, + nodesVisitor: NodesVisitor = visitNodes, +) { context.startLexicalEnvironment(); statements = nodesVisitor(statements, visitor, isStatement, start); if (ensureUseStrict) statements = context.factory.ensureUseStrict(statements); @@ -388,9 +395,24 @@ export function visitLexicalEnvironment(statements: NodeArray, visito * Starts a new lexical environment and visits a parameter list, suspending the lexical * environment upon completion. */ -export function visitParameterList(nodes: NodeArray, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor): NodeArray; -export function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor): NodeArray | undefined; -export function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes) { +export function visitParameterList( + nodes: NodeArray, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: NodesVisitor, +): NodeArray; +export function visitParameterList( + nodes: NodeArray | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: NodesVisitor, +): NodeArray | undefined; +export function visitParameterList( + nodes: NodeArray | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor = visitNodes, +) { let updated: NodeArray | undefined; context.startLexicalEnvironment(); if (nodes) { @@ -403,8 +425,10 @@ export function visitParameterList(nodes: NodeArray | unde // exists in a different lexical scope. To address this, we move any binding patterns and initializers // in a parameter list to the body if we detect a variable being hoisted while visiting a parameter list // when the emit target is greater than ES2015. - if (context.getLexicalEnvironmentFlags() & LexicalEnvironmentFlags.VariablesHoistedInParameters && - getEmitScriptTarget(context.getCompilerOptions()) >= ScriptTarget.ES2015) { + if ( + context.getLexicalEnvironmentFlags() & LexicalEnvironmentFlags.VariablesHoistedInParameters + && getEmitScriptTarget(context.getCompilerOptions()) >= ScriptTarget.ES2015 + ) { updated = addDefaultValueAssignmentsIfNeeded(updated, context); } context.setLexicalEnvironmentFlags(LexicalEnvironmentFlags.InParameters, false); @@ -413,7 +437,10 @@ export function visitParameterList(nodes: NodeArray | unde return updated; } -function addDefaultValueAssignmentsIfNeeded(parameters: NodeArray, context: TransformationContext) { +function addDefaultValueAssignmentsIfNeeded( + parameters: NodeArray, + context: TransformationContext, +) { let result: ParameterDeclaration[] | undefined; for (let i = 0; i < parameters.length; i++) { const parameter = parameters[i]; @@ -432,10 +459,11 @@ function addDefaultValueAssignmentsIfNeeded(parameters: NodeArray, visitor: Visitor, discardVisitor = visitor): NodeArray { +export function visitCommaListElements( + elements: NodeArray, + visitor: Visitor, + discardVisitor = visitor, +): NodeArray { if (discardVisitor === visitor || elements.length <= 1) { return visitNodes(elements, visitor, isExpression); } @@ -592,7 +671,14 @@ export function visitCommaListElements(elements: NodeArray, visitor: */ export function visitEachChild(node: T, visitor: Visitor, context: TransformationContext): T; /** @internal */ -export function visitEachChild(node: T, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor, tokenVisitor?: Visitor, nodeVisitor?: NodeVisitor): T; // eslint-disable-line @typescript-eslint/unified-signatures +export function visitEachChild( + node: T, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: NodesVisitor, + tokenVisitor?: Visitor, + nodeVisitor?: NodeVisitor, +): T; // eslint-disable-line @typescript-eslint/unified-signatures /** * Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place. * @@ -600,10 +686,30 @@ export function visitEachChild(node: T, visitor: Visitor, contex * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ -export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes, tokenVisitor?: Visitor): T | undefined; +export function visitEachChild( + node: T | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: typeof visitNodes, + tokenVisitor?: Visitor, +): T | undefined; /** @internal */ -export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor, tokenVisitor?: Visitor, nodeVisitor?: NodeVisitor): T | undefined; -export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes, tokenVisitor?: Visitor, nodeVisitor: NodeVisitor = visitNode): T | undefined { +export function visitEachChild( + node: T | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor?: NodesVisitor, + tokenVisitor?: Visitor, + nodeVisitor?: NodeVisitor, +): T | undefined; +export function visitEachChild( + node: T | undefined, + visitor: Visitor, + context: TransformationContext, + nodesVisitor = visitNodes, + tokenVisitor?: Visitor, + nodeVisitor: NodeVisitor = visitNode, +): T | undefined { if (node === undefined) { return undefined; } @@ -612,7 +718,14 @@ export function visitEachChild(node: T | undefined, visitor: Vis return fn === undefined ? node : fn(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor); } -type VisitEachChildFunction = (node: T, visitor: Visitor, context: TransformationContext, nodesVisitor: NodesVisitor, nodeVisitor: NodeVisitor, tokenVisitor: Visitor | undefined) => T; +type VisitEachChildFunction = ( + node: T, + visitor: Visitor, + context: TransformationContext, + nodesVisitor: NodesVisitor, + nodeVisitor: NodeVisitor, + tokenVisitor: Visitor | undefined, +) => T; // A type that correlates a `SyntaxKind` to a `VisitEachChildFunction`, for nodes in the `HasChildren` union. // This looks something like: @@ -624,77 +737,159 @@ type VisitEachChildFunction = (node: T, visitor: Visitor, contex // } // // This is then used as the expected type for `visitEachChildTable`. -type VisitEachChildTable = { [TNode in HasChildren as TNode["kind"]]: VisitEachChildFunction }; +type VisitEachChildTable = { [TNode in HasChildren as TNode["kind"]]: VisitEachChildFunction; }; // NOTE: Before you can add a new method to `visitEachChildTable`, you must first ensure the `Node` subtype you // wish to add is defined in the `HasChildren` union in types.ts. const visitEachChildTable: VisitEachChildTable = { - [SyntaxKind.QualifiedName]: function visitEachChildOfQualifiedName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateQualifiedName(node, + [SyntaxKind.QualifiedName]: function visitEachChildOfQualifiedName( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateQualifiedName( + node, Debug.checkDefined(nodeVisitor(node.left, visitor, isEntityName)), - Debug.checkDefined(nodeVisitor(node.right, visitor, isIdentifier))); + Debug.checkDefined(nodeVisitor(node.right, visitor, isIdentifier)), + ); }, - [SyntaxKind.ComputedPropertyName]: function visitEachChildOfComputedPropertyName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateComputedPropertyName(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.ComputedPropertyName]: function visitEachChildOfComputedPropertyName( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateComputedPropertyName( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, // Signature elements - [SyntaxKind.TypeParameter]: function visitEachChildOfTypeParameterDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeParameterDeclaration(node, + [SyntaxKind.TypeParameter]: function visitEachChildOfTypeParameterDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeParameterDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifier), Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodeVisitor(node.constraint, visitor, isTypeNode), - nodeVisitor(node.default, visitor, isTypeNode)); + nodeVisitor(node.default, visitor, isTypeNode), + ); }, - [SyntaxKind.Parameter]: function visitEachChildOfParameterDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateParameterDeclaration(node, + [SyntaxKind.Parameter]: function visitEachChildOfParameterDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateParameterDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), tokenVisitor ? nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken) : node.dotDotDotToken, Debug.checkDefined(nodeVisitor(node.name, visitor, isBindingName)), tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, nodeVisitor(node.type, visitor, isTypeNode), - nodeVisitor(node.initializer, visitor, isExpression)); + nodeVisitor(node.initializer, visitor, isExpression), + ); }, - [SyntaxKind.Decorator]: function visitEachChildOfDecorator(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateDecorator(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.Decorator]: function visitEachChildOfDecorator( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateDecorator( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, // Type elements - [SyntaxKind.PropertySignature]: function visitEachChildOfPropertySignature(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updatePropertySignature(node, + [SyntaxKind.PropertySignature]: function visitEachChildOfPropertySignature( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updatePropertySignature( + node, nodesVisitor(node.modifiers, visitor, isModifier), Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, - nodeVisitor(node.type, visitor, isTypeNode)); + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.PropertyDeclaration]: function visitEachChildOfPropertyDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updatePropertyDeclaration(node, + [SyntaxKind.PropertyDeclaration]: function visitEachChildOfPropertyDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updatePropertyDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), // QuestionToken and ExclamationToken are mutually exclusive in PropertyDeclaration - tokenVisitor ? nodeVisitor(node.questionToken ?? node.exclamationToken, tokenVisitor, isQuestionOrExclamationToken) : node.questionToken ?? node.exclamationToken, + tokenVisitor + ? nodeVisitor(node.questionToken ?? node.exclamationToken, tokenVisitor, isQuestionOrExclamationToken) + : node.questionToken ?? node.exclamationToken, nodeVisitor(node.type, visitor, isTypeNode), - nodeVisitor(node.initializer, visitor, isExpression)); + nodeVisitor(node.initializer, visitor, isExpression), + ); }, - [SyntaxKind.MethodSignature]: function visitEachChildOfMethodSignature(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateMethodSignature(node, + [SyntaxKind.MethodSignature]: function visitEachChildOfMethodSignature( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateMethodSignature( + node, nodesVisitor(node.modifiers, visitor, isModifier), Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameter), - nodeVisitor(node.type, visitor, isTypeNode)); + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.MethodDeclaration]: function visitEachChildOfMethodDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateMethodDeclaration(node, + [SyntaxKind.MethodDeclaration]: function visitEachChildOfMethodDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateMethodDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), tokenVisitor ? nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken) : node.asteriskToken, Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), @@ -702,163 +897,377 @@ const visitEachChildTable: VisitEachChildTable = { nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), - visitFunctionBody(node.body!, visitor, context, nodeVisitor)); + visitFunctionBody(node.body!, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.Constructor]: function visitEachChildOfConstructorDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateConstructorDeclaration(node, + [SyntaxKind.Constructor]: function visitEachChildOfConstructorDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateConstructorDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), visitParameterList(node.parameters, visitor, context, nodesVisitor), - visitFunctionBody(node.body!, visitor, context, nodeVisitor)); + visitFunctionBody(node.body!, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.GetAccessor]: function visitEachChildOfGetAccessorDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateGetAccessorDeclaration(node, + [SyntaxKind.GetAccessor]: function visitEachChildOfGetAccessorDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateGetAccessorDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), - visitFunctionBody(node.body!, visitor, context, nodeVisitor)); + visitFunctionBody(node.body!, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.SetAccessor]: function visitEachChildOfSetAccessorDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateSetAccessorDeclaration(node, + [SyntaxKind.SetAccessor]: function visitEachChildOfSetAccessorDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSetAccessorDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), visitParameterList(node.parameters, visitor, context, nodesVisitor), - visitFunctionBody(node.body!, visitor, context, nodeVisitor)); + visitFunctionBody(node.body!, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ClassStaticBlockDeclaration]: function visitEachChildOfClassStaticBlockDeclaration(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { + [SyntaxKind.ClassStaticBlockDeclaration]: function visitEachChildOfClassStaticBlockDeclaration( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { context.startLexicalEnvironment(); context.suspendLexicalEnvironment(); - return context.factory.updateClassStaticBlockDeclaration(node, - visitFunctionBody(node.body, visitor, context, nodeVisitor)); + return context.factory.updateClassStaticBlockDeclaration( + node, + visitFunctionBody(node.body, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.CallSignature]: function visitEachChildOfCallSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateCallSignature(node, + [SyntaxKind.CallSignature]: function visitEachChildOfCallSignatureDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateCallSignature( + node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameter), - nodeVisitor(node.type, visitor, isTypeNode)); + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.ConstructSignature]: function visitEachChildOfConstructSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateConstructSignature(node, + [SyntaxKind.ConstructSignature]: function visitEachChildOfConstructSignatureDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateConstructSignature( + node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameter), - nodeVisitor(node.type, visitor, isTypeNode)); + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.IndexSignature]: function visitEachChildOfIndexSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateIndexSignature(node, + [SyntaxKind.IndexSignature]: function visitEachChildOfIndexSignatureDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateIndexSignature( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodesVisitor(node.parameters, visitor, isParameter), - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, // Types - [SyntaxKind.TypePredicate]: function visitEachChildOfTypePredicateNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypePredicateNode(node, + [SyntaxKind.TypePredicate]: function visitEachChildOfTypePredicateNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypePredicateNode( + node, nodeVisitor(node.assertsModifier, visitor, isAssertsKeyword), Debug.checkDefined(nodeVisitor(node.parameterName, visitor, isIdentifierOrThisTypeNode)), - nodeVisitor(node.type, visitor, isTypeNode)); + nodeVisitor(node.type, visitor, isTypeNode), + ); }, - [SyntaxKind.TypeReference]: function visitEachChildOfTypeReferenceNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeReferenceNode(node, + [SyntaxKind.TypeReference]: function visitEachChildOfTypeReferenceNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeReferenceNode( + node, Debug.checkDefined(nodeVisitor(node.typeName, visitor, isEntityName)), - nodesVisitor(node.typeArguments, visitor, isTypeNode)); + nodesVisitor(node.typeArguments, visitor, isTypeNode), + ); }, - [SyntaxKind.FunctionType]: function visitEachChildOfFunctionTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateFunctionTypeNode(node, + [SyntaxKind.FunctionType]: function visitEachChildOfFunctionTypeNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateFunctionTypeNode( + node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameter), - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.ConstructorType]: function visitEachChildOfConstructorTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateConstructorTypeNode(node, + [SyntaxKind.ConstructorType]: function visitEachChildOfConstructorTypeNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateConstructorTypeNode( + node, nodesVisitor(node.modifiers, visitor, isModifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.parameters, visitor, isParameter), - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.TypeQuery]: function visitEachChildOfTypeQueryNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeQueryNode(node, + [SyntaxKind.TypeQuery]: function visitEachChildOfTypeQueryNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeQueryNode( + node, Debug.checkDefined(nodeVisitor(node.exprName, visitor, isEntityName)), - nodesVisitor(node.typeArguments, visitor, isTypeNode)); + nodesVisitor(node.typeArguments, visitor, isTypeNode), + ); }, - [SyntaxKind.TypeLiteral]: function visitEachChildOfTypeLiteralNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeLiteralNode(node, - nodesVisitor(node.members, visitor, isTypeElement)); + [SyntaxKind.TypeLiteral]: function visitEachChildOfTypeLiteralNode( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeLiteralNode( + node, + nodesVisitor(node.members, visitor, isTypeElement), + ); }, - [SyntaxKind.ArrayType]: function visitEachChildOfArrayTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateArrayTypeNode(node, - Debug.checkDefined(nodeVisitor(node.elementType, visitor, isTypeNode))); + [SyntaxKind.ArrayType]: function visitEachChildOfArrayTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateArrayTypeNode( + node, + Debug.checkDefined(nodeVisitor(node.elementType, visitor, isTypeNode)), + ); }, - [SyntaxKind.TupleType]: function visitEachChildOfTupleTypeNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateTupleTypeNode(node, - nodesVisitor(node.elements, visitor, isTypeNode)); + [SyntaxKind.TupleType]: function visitEachChildOfTupleTypeNode( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTupleTypeNode( + node, + nodesVisitor(node.elements, visitor, isTypeNode), + ); }, - [SyntaxKind.OptionalType]: function visitEachChildOfOptionalTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateOptionalTypeNode(node, - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + [SyntaxKind.OptionalType]: function visitEachChildOfOptionalTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateOptionalTypeNode( + node, + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.RestType]: function visitEachChildOfRestTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateRestTypeNode(node, - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + [SyntaxKind.RestType]: function visitEachChildOfRestTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateRestTypeNode( + node, + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.UnionType]: function visitEachChildOfUnionTypeNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateUnionTypeNode(node, - nodesVisitor(node.types, visitor, isTypeNode)); + [SyntaxKind.UnionType]: function visitEachChildOfUnionTypeNode( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateUnionTypeNode( + node, + nodesVisitor(node.types, visitor, isTypeNode), + ); }, - [SyntaxKind.IntersectionType]: function visitEachChildOfIntersectionTypeNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateIntersectionTypeNode(node, - nodesVisitor(node.types, visitor, isTypeNode)); + [SyntaxKind.IntersectionType]: function visitEachChildOfIntersectionTypeNode( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateIntersectionTypeNode( + node, + nodesVisitor(node.types, visitor, isTypeNode), + ); }, - [SyntaxKind.ConditionalType]: function visitEachChildOfConditionalTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateConditionalTypeNode(node, + [SyntaxKind.ConditionalType]: function visitEachChildOfConditionalTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateConditionalTypeNode( + node, Debug.checkDefined(nodeVisitor(node.checkType, visitor, isTypeNode)), Debug.checkDefined(nodeVisitor(node.extendsType, visitor, isTypeNode)), Debug.checkDefined(nodeVisitor(node.trueType, visitor, isTypeNode)), - Debug.checkDefined(nodeVisitor(node.falseType, visitor, isTypeNode))); + Debug.checkDefined(nodeVisitor(node.falseType, visitor, isTypeNode)), + ); }, - [SyntaxKind.InferType]: function visitEachChildOfInferTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateInferTypeNode(node, - Debug.checkDefined(nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration))); + [SyntaxKind.InferType]: function visitEachChildOfInferTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateInferTypeNode( + node, + Debug.checkDefined(nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration)), + ); }, - [SyntaxKind.ImportType]: function visitEachChildOfImportTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportTypeNode(node, + [SyntaxKind.ImportType]: function visitEachChildOfImportTypeNode( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportTypeNode( + node, Debug.checkDefined(nodeVisitor(node.argument, visitor, isTypeNode)), nodeVisitor(node.assertions, visitor, isImportTypeAssertionContainer), nodeVisitor(node.qualifier, visitor, isEntityName), nodesVisitor(node.typeArguments, visitor, isTypeNode), - node.isTypeOf + node.isTypeOf, ); }, - [SyntaxKind.ImportTypeAssertionContainer]: function visitEachChildOfImportTypeAssertionContainer(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportTypeAssertionContainer(node, + [SyntaxKind.ImportTypeAssertionContainer]: function visitEachChildOfImportTypeAssertionContainer( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportTypeAssertionContainer( + node, Debug.checkDefined(nodeVisitor(node.assertClause, visitor, isAssertClause)), - node.multiLine + node.multiLine, ); }, - [SyntaxKind.NamedTupleMember]: function visitEachChildOfNamedTupleMember(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateNamedTupleMember(node, + [SyntaxKind.NamedTupleMember]: function visitEachChildOfNamedTupleMember( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateNamedTupleMember( + node, tokenVisitor ? nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken) : node.dotDotDotToken, Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, @@ -866,667 +1275,1603 @@ const visitEachChildTable: VisitEachChildTable = { ); }, - [SyntaxKind.ParenthesizedType]: function visitEachChildOfParenthesizedType(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateParenthesizedType(node, - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + [SyntaxKind.ParenthesizedType]: function visitEachChildOfParenthesizedType( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateParenthesizedType( + node, + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.TypeOperator]: function visitEachChildOfTypeOperatorNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeOperatorNode(node, - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + [SyntaxKind.TypeOperator]: function visitEachChildOfTypeOperatorNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeOperatorNode( + node, + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.IndexedAccessType]: function visitEachChildOfIndexedAccessType(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateIndexedAccessTypeNode(node, + [SyntaxKind.IndexedAccessType]: function visitEachChildOfIndexedAccessType( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateIndexedAccessTypeNode( + node, Debug.checkDefined(nodeVisitor(node.objectType, visitor, isTypeNode)), - Debug.checkDefined(nodeVisitor(node.indexType, visitor, isTypeNode))); + Debug.checkDefined(nodeVisitor(node.indexType, visitor, isTypeNode)), + ); }, - [SyntaxKind.MappedType]: function visitEachChildOfMappedType(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateMappedTypeNode(node, - tokenVisitor ? nodeVisitor(node.readonlyToken, tokenVisitor, isReadonlyKeywordOrPlusOrMinusToken) : node.readonlyToken, + [SyntaxKind.MappedType]: function visitEachChildOfMappedType( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateMappedTypeNode( + node, + tokenVisitor ? nodeVisitor(node.readonlyToken, tokenVisitor, isReadonlyKeywordOrPlusOrMinusToken) + : node.readonlyToken, Debug.checkDefined(nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration)), nodeVisitor(node.nameType, visitor, isTypeNode), - tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionOrPlusOrMinusToken) : node.questionToken, + tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionOrPlusOrMinusToken) + : node.questionToken, nodeVisitor(node.type, visitor, isTypeNode), - nodesVisitor(node.members, visitor, isTypeElement)); + nodesVisitor(node.members, visitor, isTypeElement), + ); }, - [SyntaxKind.LiteralType]: function visitEachChildOfLiteralTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateLiteralTypeNode(node, - Debug.checkDefined(nodeVisitor(node.literal, visitor, isLiteralTypeLiteral))); + [SyntaxKind.LiteralType]: function visitEachChildOfLiteralTypeNode( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateLiteralTypeNode( + node, + Debug.checkDefined(nodeVisitor(node.literal, visitor, isLiteralTypeLiteral)), + ); }, - [SyntaxKind.TemplateLiteralType]: function visitEachChildOfTemplateLiteralType(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTemplateLiteralType(node, + [SyntaxKind.TemplateLiteralType]: function visitEachChildOfTemplateLiteralType( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTemplateLiteralType( + node, Debug.checkDefined(nodeVisitor(node.head, visitor, isTemplateHead)), - nodesVisitor(node.templateSpans, visitor, isTemplateLiteralTypeSpan)); + nodesVisitor(node.templateSpans, visitor, isTemplateLiteralTypeSpan), + ); }, - [SyntaxKind.TemplateLiteralTypeSpan]: function visitEachChildOfTemplateLiteralTypeSpan(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTemplateLiteralTypeSpan(node, + [SyntaxKind.TemplateLiteralTypeSpan]: function visitEachChildOfTemplateLiteralTypeSpan( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTemplateLiteralTypeSpan( + node, Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), - Debug.checkDefined(nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail))); + Debug.checkDefined(nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail)), + ); }, // Binding patterns - [SyntaxKind.ObjectBindingPattern]: function visitEachChildOfObjectBindingPattern(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateObjectBindingPattern(node, - nodesVisitor(node.elements, visitor, isBindingElement)); + [SyntaxKind.ObjectBindingPattern]: function visitEachChildOfObjectBindingPattern( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateObjectBindingPattern( + node, + nodesVisitor(node.elements, visitor, isBindingElement), + ); }, - [SyntaxKind.ArrayBindingPattern]: function visitEachChildOfArrayBindingPattern(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateArrayBindingPattern(node, - nodesVisitor(node.elements, visitor, isArrayBindingElement)); + [SyntaxKind.ArrayBindingPattern]: function visitEachChildOfArrayBindingPattern( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateArrayBindingPattern( + node, + nodesVisitor(node.elements, visitor, isArrayBindingElement), + ); }, - [SyntaxKind.BindingElement]: function visitEachChildOfBindingElement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateBindingElement(node, + [SyntaxKind.BindingElement]: function visitEachChildOfBindingElement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateBindingElement( + node, tokenVisitor ? nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken) : node.dotDotDotToken, nodeVisitor(node.propertyName, visitor, isPropertyName), Debug.checkDefined(nodeVisitor(node.name, visitor, isBindingName)), - nodeVisitor(node.initializer, visitor, isExpression)); + nodeVisitor(node.initializer, visitor, isExpression), + ); }, // Expression - [SyntaxKind.ArrayLiteralExpression]: function visitEachChildOfArrayLiteralExpression(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateArrayLiteralExpression(node, - nodesVisitor(node.elements, visitor, isExpression)); + [SyntaxKind.ArrayLiteralExpression]: function visitEachChildOfArrayLiteralExpression( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateArrayLiteralExpression( + node, + nodesVisitor(node.elements, visitor, isExpression), + ); }, - [SyntaxKind.ObjectLiteralExpression]: function visitEachChildOfObjectLiteralExpression(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateObjectLiteralExpression(node, - nodesVisitor(node.properties, visitor, isObjectLiteralElementLike)); + [SyntaxKind.ObjectLiteralExpression]: function visitEachChildOfObjectLiteralExpression( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateObjectLiteralExpression( + node, + nodesVisitor(node.properties, visitor, isObjectLiteralElementLike), + ); }, - [SyntaxKind.PropertyAccessExpression]: function visitEachChildOfPropertyAccessExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return isPropertyAccessChain(node) ? - context.factory.updatePropertyAccessChain(node, + [SyntaxKind.PropertyAccessExpression]: function visitEachChildOfPropertyAccessExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return isPropertyAccessChain(node) + ? context.factory.updatePropertyAccessChain( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) : node.questionDotToken, - Debug.checkDefined(nodeVisitor(node.name, visitor, isMemberName))) : - context.factory.updatePropertyAccessExpression(node, + tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) + : node.questionDotToken, + Debug.checkDefined(nodeVisitor(node.name, visitor, isMemberName)), + ) + : context.factory.updatePropertyAccessExpression( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - Debug.checkDefined(nodeVisitor(node.name, visitor, isMemberName))); - }, - - [SyntaxKind.ElementAccessExpression]: function visitEachChildOfElementAccessExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return isElementAccessChain(node) ? - context.factory.updateElementAccessChain(node, + Debug.checkDefined(nodeVisitor(node.name, visitor, isMemberName)), + ); + }, + + [SyntaxKind.ElementAccessExpression]: function visitEachChildOfElementAccessExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return isElementAccessChain(node) + ? context.factory.updateElementAccessChain( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) : node.questionDotToken, - Debug.checkDefined(nodeVisitor(node.argumentExpression, visitor, isExpression))) : - context.factory.updateElementAccessExpression(node, + tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) + : node.questionDotToken, + Debug.checkDefined(nodeVisitor(node.argumentExpression, visitor, isExpression)), + ) + : context.factory.updateElementAccessExpression( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - Debug.checkDefined(nodeVisitor(node.argumentExpression, visitor, isExpression))); - }, - - [SyntaxKind.CallExpression]: function visitEachChildOfCallExpression(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return isCallChain(node) ? - context.factory.updateCallChain(node, + Debug.checkDefined(nodeVisitor(node.argumentExpression, visitor, isExpression)), + ); + }, + + [SyntaxKind.CallExpression]: function visitEachChildOfCallExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return isCallChain(node) + ? context.factory.updateCallChain( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) : node.questionDotToken, + tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) + : node.questionDotToken, nodesVisitor(node.typeArguments, visitor, isTypeNode), - nodesVisitor(node.arguments, visitor, isExpression)) : - context.factory.updateCallExpression(node, + nodesVisitor(node.arguments, visitor, isExpression), + ) + : context.factory.updateCallExpression( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), - nodesVisitor(node.arguments, visitor, isExpression)); - }, - - [SyntaxKind.NewExpression]: function visitEachChildOfNewExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateNewExpression(node, + nodesVisitor(node.arguments, visitor, isExpression), + ); + }, + + [SyntaxKind.NewExpression]: function visitEachChildOfNewExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateNewExpression( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), - nodesVisitor(node.arguments, visitor, isExpression)); + nodesVisitor(node.arguments, visitor, isExpression), + ); }, - [SyntaxKind.TaggedTemplateExpression]: function visitEachChildOfTaggedTemplateExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTaggedTemplateExpression(node, + [SyntaxKind.TaggedTemplateExpression]: function visitEachChildOfTaggedTemplateExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTaggedTemplateExpression( + node, Debug.checkDefined(nodeVisitor(node.tag, visitor, isExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), - Debug.checkDefined(nodeVisitor(node.template, visitor, isTemplateLiteral))); + Debug.checkDefined(nodeVisitor(node.template, visitor, isTemplateLiteral)), + ); }, - [SyntaxKind.TypeAssertionExpression]: function visitEachChildOfTypeAssertionExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeAssertion(node, + [SyntaxKind.TypeAssertionExpression]: function visitEachChildOfTypeAssertionExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeAssertion( + node, Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.ParenthesizedExpression]: function visitEachChildOfParenthesizedExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateParenthesizedExpression(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.ParenthesizedExpression]: function visitEachChildOfParenthesizedExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateParenthesizedExpression( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.FunctionExpression]: function visitEachChildOfFunctionExpression(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateFunctionExpression(node, + [SyntaxKind.FunctionExpression]: function visitEachChildOfFunctionExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateFunctionExpression( + node, nodesVisitor(node.modifiers, visitor, isModifier), tokenVisitor ? nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken) : node.asteriskToken, nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), - visitFunctionBody(node.body, visitor, context, nodeVisitor)); + visitFunctionBody(node.body, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ArrowFunction]: function visitEachChildOfArrowFunction(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateArrowFunction(node, + [SyntaxKind.ArrowFunction]: function visitEachChildOfArrowFunction( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateArrowFunction( + node, nodesVisitor(node.modifiers, visitor, isModifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), - tokenVisitor ? Debug.checkDefined(nodeVisitor(node.equalsGreaterThanToken, tokenVisitor, isEqualsGreaterThanToken)) : node.equalsGreaterThanToken, - visitFunctionBody(node.body, visitor, context, nodeVisitor)); + tokenVisitor + ? Debug.checkDefined(nodeVisitor(node.equalsGreaterThanToken, tokenVisitor, isEqualsGreaterThanToken)) + : node.equalsGreaterThanToken, + visitFunctionBody(node.body, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.DeleteExpression]: function visitEachChildOfDeleteExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateDeleteExpression(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.DeleteExpression]: function visitEachChildOfDeleteExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateDeleteExpression( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.TypeOfExpression]: function visitEachChildOfTypeOfExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeOfExpression(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.TypeOfExpression]: function visitEachChildOfTypeOfExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeOfExpression( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.VoidExpression]: function visitEachChildOfVoidExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateVoidExpression(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.VoidExpression]: function visitEachChildOfVoidExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateVoidExpression( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.AwaitExpression]: function visitEachChildOfAwaitExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateAwaitExpression(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.AwaitExpression]: function visitEachChildOfAwaitExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateAwaitExpression( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.PrefixUnaryExpression]: function visitEachChildOfPrefixUnaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updatePrefixUnaryExpression(node, - Debug.checkDefined(nodeVisitor(node.operand, visitor, isExpression))); + [SyntaxKind.PrefixUnaryExpression]: function visitEachChildOfPrefixUnaryExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updatePrefixUnaryExpression( + node, + Debug.checkDefined(nodeVisitor(node.operand, visitor, isExpression)), + ); }, - [SyntaxKind.PostfixUnaryExpression]: function visitEachChildOfPostfixUnaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updatePostfixUnaryExpression(node, - Debug.checkDefined(nodeVisitor(node.operand, visitor, isExpression))); + [SyntaxKind.PostfixUnaryExpression]: function visitEachChildOfPostfixUnaryExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updatePostfixUnaryExpression( + node, + Debug.checkDefined(nodeVisitor(node.operand, visitor, isExpression)), + ); }, - [SyntaxKind.BinaryExpression]: function visitEachChildOfBinaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateBinaryExpression(node, + [SyntaxKind.BinaryExpression]: function visitEachChildOfBinaryExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateBinaryExpression( + node, Debug.checkDefined(nodeVisitor(node.left, visitor, isExpression)), - tokenVisitor ? Debug.checkDefined(nodeVisitor(node.operatorToken, tokenVisitor, isBinaryOperatorToken)) : node.operatorToken, - Debug.checkDefined(nodeVisitor(node.right, visitor, isExpression))); + tokenVisitor ? Debug.checkDefined(nodeVisitor(node.operatorToken, tokenVisitor, isBinaryOperatorToken)) + : node.operatorToken, + Debug.checkDefined(nodeVisitor(node.right, visitor, isExpression)), + ); }, - [SyntaxKind.ConditionalExpression]: function visitEachChildOfConditionalExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateConditionalExpression(node, + [SyntaxKind.ConditionalExpression]: function visitEachChildOfConditionalExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateConditionalExpression( + node, Debug.checkDefined(nodeVisitor(node.condition, visitor, isExpression)), - tokenVisitor ? Debug.checkDefined(nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken)) : node.questionToken, + tokenVisitor ? Debug.checkDefined(nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken)) + : node.questionToken, Debug.checkDefined(nodeVisitor(node.whenTrue, visitor, isExpression)), - tokenVisitor ? Debug.checkDefined(nodeVisitor(node.colonToken, tokenVisitor, isColonToken)) : node.colonToken, - Debug.checkDefined(nodeVisitor(node.whenFalse, visitor, isExpression))); + tokenVisitor ? Debug.checkDefined(nodeVisitor(node.colonToken, tokenVisitor, isColonToken)) + : node.colonToken, + Debug.checkDefined(nodeVisitor(node.whenFalse, visitor, isExpression)), + ); }, - [SyntaxKind.TemplateExpression]: function visitEachChildOfTemplateExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTemplateExpression(node, + [SyntaxKind.TemplateExpression]: function visitEachChildOfTemplateExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTemplateExpression( + node, Debug.checkDefined(nodeVisitor(node.head, visitor, isTemplateHead)), - nodesVisitor(node.templateSpans, visitor, isTemplateSpan)); + nodesVisitor(node.templateSpans, visitor, isTemplateSpan), + ); }, - [SyntaxKind.YieldExpression]: function visitEachChildOfYieldExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateYieldExpression(node, + [SyntaxKind.YieldExpression]: function visitEachChildOfYieldExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateYieldExpression( + node, tokenVisitor ? nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken) : node.asteriskToken, - nodeVisitor(node.expression, visitor, isExpression)); + nodeVisitor(node.expression, visitor, isExpression), + ); }, - [SyntaxKind.SpreadElement]: function visitEachChildOfSpreadElement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateSpreadElement(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.SpreadElement]: function visitEachChildOfSpreadElement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSpreadElement( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.ClassExpression]: function visitEachChildOfClassExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateClassExpression(node, + [SyntaxKind.ClassExpression]: function visitEachChildOfClassExpression( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateClassExpression( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.heritageClauses, visitor, isHeritageClause), - nodesVisitor(node.members, visitor, isClassElement)); + nodesVisitor(node.members, visitor, isClassElement), + ); }, - [SyntaxKind.ExpressionWithTypeArguments]: function visitEachChildOfExpressionWithTypeArguments(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExpressionWithTypeArguments(node, + [SyntaxKind.ExpressionWithTypeArguments]: function visitEachChildOfExpressionWithTypeArguments( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExpressionWithTypeArguments( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - nodesVisitor(node.typeArguments, visitor, isTypeNode)); + nodesVisitor(node.typeArguments, visitor, isTypeNode), + ); }, - [SyntaxKind.AsExpression]: function visitEachChildOfAsExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateAsExpression(node, + [SyntaxKind.AsExpression]: function visitEachChildOfAsExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateAsExpression( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.SatisfiesExpression]: function visitEachChildOfSatisfiesExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateSatisfiesExpression(node, + [SyntaxKind.SatisfiesExpression]: function visitEachChildOfSatisfiesExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSatisfiesExpression( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); - }, - - [SyntaxKind.NonNullExpression]: function visitEachChildOfNonNullExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return isOptionalChain(node) ? - context.factory.updateNonNullChain(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))) : - context.factory.updateNonNullExpression(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.MetaProperty]: function visitEachChildOfMetaProperty(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateMetaProperty(node, - Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); + [SyntaxKind.NonNullExpression]: function visitEachChildOfNonNullExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return isOptionalChain(node) + ? context.factory.updateNonNullChain( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ) + : context.factory.updateNonNullExpression( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); + }, + + [SyntaxKind.MetaProperty]: function visitEachChildOfMetaProperty( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateMetaProperty( + node, + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + ); }, // Misc - [SyntaxKind.TemplateSpan]: function visitEachChildOfTemplateSpan(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTemplateSpan(node, + [SyntaxKind.TemplateSpan]: function visitEachChildOfTemplateSpan( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTemplateSpan( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - Debug.checkDefined(nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail))); + Debug.checkDefined(nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail)), + ); }, // Element - [SyntaxKind.Block]: function visitEachChildOfBlock(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateBlock(node, - nodesVisitor(node.statements, visitor, isStatement)); + [SyntaxKind.Block]: function visitEachChildOfBlock( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateBlock( + node, + nodesVisitor(node.statements, visitor, isStatement), + ); }, - [SyntaxKind.VariableStatement]: function visitEachChildOfVariableStatement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateVariableStatement(node, + [SyntaxKind.VariableStatement]: function visitEachChildOfVariableStatement( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateVariableStatement( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), - Debug.checkDefined(nodeVisitor(node.declarationList, visitor, isVariableDeclarationList))); + Debug.checkDefined(nodeVisitor(node.declarationList, visitor, isVariableDeclarationList)), + ); }, - [SyntaxKind.ExpressionStatement]: function visitEachChildOfExpressionStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExpressionStatement(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.ExpressionStatement]: function visitEachChildOfExpressionStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExpressionStatement( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.IfStatement]: function visitEachChildOfIfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateIfStatement(node, + [SyntaxKind.IfStatement]: function visitEachChildOfIfStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateIfStatement( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), Debug.checkDefined(nodeVisitor(node.thenStatement, visitor, isStatement, context.factory.liftToBlock)), - nodeVisitor(node.elseStatement, visitor, isStatement, context.factory.liftToBlock)); + nodeVisitor(node.elseStatement, visitor, isStatement, context.factory.liftToBlock), + ); }, - [SyntaxKind.DoStatement]: function visitEachChildOfDoStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateDoStatement(node, + [SyntaxKind.DoStatement]: function visitEachChildOfDoStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateDoStatement( + node, visitIterationBody(node.statement, visitor, context, nodeVisitor), - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.WhileStatement]: function visitEachChildOfWhileStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateWhileStatement(node, + [SyntaxKind.WhileStatement]: function visitEachChildOfWhileStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateWhileStatement( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - visitIterationBody(node.statement, visitor, context, nodeVisitor)); + visitIterationBody(node.statement, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ForStatement]: function visitEachChildOfForStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateForStatement(node, + [SyntaxKind.ForStatement]: function visitEachChildOfForStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateForStatement( + node, nodeVisitor(node.initializer, visitor, isForInitializer), nodeVisitor(node.condition, visitor, isExpression), nodeVisitor(node.incrementor, visitor, isExpression), - visitIterationBody(node.statement, visitor, context, nodeVisitor)); + visitIterationBody(node.statement, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ForInStatement]: function visitEachChildOfForInStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateForInStatement(node, + [SyntaxKind.ForInStatement]: function visitEachChildOfForInStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateForInStatement( + node, Debug.checkDefined(nodeVisitor(node.initializer, visitor, isForInitializer)), Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - visitIterationBody(node.statement, visitor, context, nodeVisitor)); + visitIterationBody(node.statement, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ForOfStatement]: function visitEachChildOfForOfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateForOfStatement(node, + [SyntaxKind.ForOfStatement]: function visitEachChildOfForOfStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateForOfStatement( + node, tokenVisitor ? nodeVisitor(node.awaitModifier, tokenVisitor, isAwaitKeyword) : node.awaitModifier, Debug.checkDefined(nodeVisitor(node.initializer, visitor, isForInitializer)), Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - visitIterationBody(node.statement, visitor, context, nodeVisitor)); + visitIterationBody(node.statement, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ContinueStatement]: function visitEachChildOfContinueStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateContinueStatement(node, - nodeVisitor(node.label, visitor, isIdentifier)); + [SyntaxKind.ContinueStatement]: function visitEachChildOfContinueStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateContinueStatement( + node, + nodeVisitor(node.label, visitor, isIdentifier), + ); }, - [SyntaxKind.BreakStatement]: function visitEachChildOfBreakStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateBreakStatement(node, - nodeVisitor(node.label, visitor, isIdentifier)); + [SyntaxKind.BreakStatement]: function visitEachChildOfBreakStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateBreakStatement( + node, + nodeVisitor(node.label, visitor, isIdentifier), + ); }, - [SyntaxKind.ReturnStatement]: function visitEachChildOfReturnStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateReturnStatement(node, - nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.ReturnStatement]: function visitEachChildOfReturnStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateReturnStatement( + node, + nodeVisitor(node.expression, visitor, isExpression), + ); }, - [SyntaxKind.WithStatement]: function visitEachChildOfWithStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateWithStatement(node, + [SyntaxKind.WithStatement]: function visitEachChildOfWithStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateWithStatement( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - Debug.checkDefined(nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock))); + Debug.checkDefined(nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock)), + ); }, - [SyntaxKind.SwitchStatement]: function visitEachChildOfSwitchStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateSwitchStatement(node, + [SyntaxKind.SwitchStatement]: function visitEachChildOfSwitchStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSwitchStatement( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - Debug.checkDefined(nodeVisitor(node.caseBlock, visitor, isCaseBlock))); + Debug.checkDefined(nodeVisitor(node.caseBlock, visitor, isCaseBlock)), + ); }, - [SyntaxKind.LabeledStatement]: function visitEachChildOfLabeledStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateLabeledStatement(node, + [SyntaxKind.LabeledStatement]: function visitEachChildOfLabeledStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateLabeledStatement( + node, Debug.checkDefined(nodeVisitor(node.label, visitor, isIdentifier)), - Debug.checkDefined(nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock))); + Debug.checkDefined(nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock)), + ); }, - [SyntaxKind.ThrowStatement]: function visitEachChildOfThrowStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateThrowStatement(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.ThrowStatement]: function visitEachChildOfThrowStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateThrowStatement( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.TryStatement]: function visitEachChildOfTryStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTryStatement(node, + [SyntaxKind.TryStatement]: function visitEachChildOfTryStatement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTryStatement( + node, Debug.checkDefined(nodeVisitor(node.tryBlock, visitor, isBlock)), nodeVisitor(node.catchClause, visitor, isCatchClause), - nodeVisitor(node.finallyBlock, visitor, isBlock)); + nodeVisitor(node.finallyBlock, visitor, isBlock), + ); }, - [SyntaxKind.VariableDeclaration]: function visitEachChildOfVariableDeclaration(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateVariableDeclaration(node, + [SyntaxKind.VariableDeclaration]: function visitEachChildOfVariableDeclaration( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateVariableDeclaration( + node, Debug.checkDefined(nodeVisitor(node.name, visitor, isBindingName)), tokenVisitor ? nodeVisitor(node.exclamationToken, tokenVisitor, isExclamationToken) : node.exclamationToken, nodeVisitor(node.type, visitor, isTypeNode), - nodeVisitor(node.initializer, visitor, isExpression)); + nodeVisitor(node.initializer, visitor, isExpression), + ); }, - [SyntaxKind.VariableDeclarationList]: function visitEachChildOfVariableDeclarationList(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateVariableDeclarationList(node, - nodesVisitor(node.declarations, visitor, isVariableDeclaration)); + [SyntaxKind.VariableDeclarationList]: function visitEachChildOfVariableDeclarationList( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateVariableDeclarationList( + node, + nodesVisitor(node.declarations, visitor, isVariableDeclaration), + ); }, - [SyntaxKind.FunctionDeclaration]: function visitEachChildOfFunctionDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { - return context.factory.updateFunctionDeclaration(node, + [SyntaxKind.FunctionDeclaration]: function visitEachChildOfFunctionDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + tokenVisitor, + ) { + return context.factory.updateFunctionDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifier), tokenVisitor ? nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken) : node.asteriskToken, nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), - visitFunctionBody(node.body, visitor, context, nodeVisitor)); + visitFunctionBody(node.body, visitor, context, nodeVisitor), + ); }, - [SyntaxKind.ClassDeclaration]: function visitEachChildOfClassDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateClassDeclaration(node, + [SyntaxKind.ClassDeclaration]: function visitEachChildOfClassDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateClassDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.heritageClauses, visitor, isHeritageClause), - nodesVisitor(node.members, visitor, isClassElement)); + nodesVisitor(node.members, visitor, isClassElement), + ); }, - [SyntaxKind.InterfaceDeclaration]: function visitEachChildOfInterfaceDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateInterfaceDeclaration(node, + [SyntaxKind.InterfaceDeclaration]: function visitEachChildOfInterfaceDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateInterfaceDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.heritageClauses, visitor, isHeritageClause), - nodesVisitor(node.members, visitor, isTypeElement)); + nodesVisitor(node.members, visitor, isTypeElement), + ); }, - [SyntaxKind.TypeAliasDeclaration]: function visitEachChildOfTypeAliasDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateTypeAliasDeclaration(node, + [SyntaxKind.TypeAliasDeclaration]: function visitEachChildOfTypeAliasDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateTypeAliasDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), - Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + ); }, - [SyntaxKind.EnumDeclaration]: function visitEachChildOfEnumDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateEnumDeclaration(node, + [SyntaxKind.EnumDeclaration]: function visitEachChildOfEnumDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateEnumDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), - nodesVisitor(node.members, visitor, isEnumMember)); + nodesVisitor(node.members, visitor, isEnumMember), + ); }, - [SyntaxKind.ModuleDeclaration]: function visitEachChildOfModuleDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateModuleDeclaration(node, + [SyntaxKind.ModuleDeclaration]: function visitEachChildOfModuleDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateModuleDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), Debug.checkDefined(nodeVisitor(node.name, visitor, isModuleName)), - nodeVisitor(node.body, visitor, isModuleBody)); + nodeVisitor(node.body, visitor, isModuleBody), + ); }, - [SyntaxKind.ModuleBlock]: function visitEachChildOfModuleBlock(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateModuleBlock(node, - nodesVisitor(node.statements, visitor, isStatement)); + [SyntaxKind.ModuleBlock]: function visitEachChildOfModuleBlock( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateModuleBlock( + node, + nodesVisitor(node.statements, visitor, isStatement), + ); }, - [SyntaxKind.CaseBlock]: function visitEachChildOfCaseBlock(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateCaseBlock(node, - nodesVisitor(node.clauses, visitor, isCaseOrDefaultClause)); + [SyntaxKind.CaseBlock]: function visitEachChildOfCaseBlock( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateCaseBlock( + node, + nodesVisitor(node.clauses, visitor, isCaseOrDefaultClause), + ); }, - [SyntaxKind.NamespaceExportDeclaration]: function visitEachChildOfNamespaceExportDeclaration(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateNamespaceExportDeclaration(node, - Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); + [SyntaxKind.NamespaceExportDeclaration]: function visitEachChildOfNamespaceExportDeclaration( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateNamespaceExportDeclaration( + node, + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + ); }, - [SyntaxKind.ImportEqualsDeclaration]: function visitEachChildOfImportEqualsDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportEqualsDeclaration(node, + [SyntaxKind.ImportEqualsDeclaration]: function visitEachChildOfImportEqualsDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportEqualsDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), node.isTypeOnly, Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), - Debug.checkDefined(nodeVisitor(node.moduleReference, visitor, isModuleReference))); + Debug.checkDefined(nodeVisitor(node.moduleReference, visitor, isModuleReference)), + ); }, - [SyntaxKind.ImportDeclaration]: function visitEachChildOfImportDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportDeclaration(node, + [SyntaxKind.ImportDeclaration]: function visitEachChildOfImportDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), nodeVisitor(node.importClause, visitor, isImportClause), Debug.checkDefined(nodeVisitor(node.moduleSpecifier, visitor, isExpression)), - nodeVisitor(node.assertClause, visitor, isAssertClause)); + nodeVisitor(node.assertClause, visitor, isAssertClause), + ); }, - [SyntaxKind.AssertClause]: function visitEachChildOfAssertClause(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateAssertClause(node, + [SyntaxKind.AssertClause]: function visitEachChildOfAssertClause( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateAssertClause( + node, nodesVisitor(node.elements, visitor, isAssertEntry), - node.multiLine); + node.multiLine, + ); }, - [SyntaxKind.AssertEntry]: function visitEachChildOfAssertEntry(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateAssertEntry(node, + [SyntaxKind.AssertEntry]: function visitEachChildOfAssertEntry( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateAssertEntry( + node, Debug.checkDefined(nodeVisitor(node.name, visitor, isAssertionKey)), - Debug.checkDefined(nodeVisitor(node.value, visitor, isExpression))); + Debug.checkDefined(nodeVisitor(node.value, visitor, isExpression)), + ); }, - [SyntaxKind.ImportClause]: function visitEachChildOfImportClause(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportClause(node, + [SyntaxKind.ImportClause]: function visitEachChildOfImportClause( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportClause( + node, node.isTypeOnly, nodeVisitor(node.name, visitor, isIdentifier), - nodeVisitor(node.namedBindings, visitor, isNamedImportBindings)); + nodeVisitor(node.namedBindings, visitor, isNamedImportBindings), + ); }, - [SyntaxKind.NamespaceImport]: function visitEachChildOfNamespaceImport(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateNamespaceImport(node, - Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); + [SyntaxKind.NamespaceImport]: function visitEachChildOfNamespaceImport( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateNamespaceImport( + node, + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + ); }, - [SyntaxKind.NamespaceExport]: function visitEachChildOfNamespaceExport(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateNamespaceExport(node, - Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); + [SyntaxKind.NamespaceExport]: function visitEachChildOfNamespaceExport( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateNamespaceExport( + node, + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + ); }, - [SyntaxKind.NamedImports]: function visitEachChildOfNamedImports(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateNamedImports(node, - nodesVisitor(node.elements, visitor, isImportSpecifier)); + [SyntaxKind.NamedImports]: function visitEachChildOfNamedImports( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateNamedImports( + node, + nodesVisitor(node.elements, visitor, isImportSpecifier), + ); }, - [SyntaxKind.ImportSpecifier]: function visitEachChildOfImportSpecifier(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateImportSpecifier(node, + [SyntaxKind.ImportSpecifier]: function visitEachChildOfImportSpecifier( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateImportSpecifier( + node, node.isTypeOnly, nodeVisitor(node.propertyName, visitor, isIdentifier), - Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + ); }, - [SyntaxKind.ExportAssignment]: function visitEachChildOfExportAssignment(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExportAssignment(node, + [SyntaxKind.ExportAssignment]: function visitEachChildOfExportAssignment( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExportAssignment( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.ExportDeclaration]: function visitEachChildOfExportDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExportDeclaration(node, + [SyntaxKind.ExportDeclaration]: function visitEachChildOfExportDeclaration( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExportDeclaration( + node, nodesVisitor(node.modifiers, visitor, isModifierLike), node.isTypeOnly, nodeVisitor(node.exportClause, visitor, isNamedExportBindings), nodeVisitor(node.moduleSpecifier, visitor, isExpression), - nodeVisitor(node.assertClause, visitor, isAssertClause)); + nodeVisitor(node.assertClause, visitor, isAssertClause), + ); }, - [SyntaxKind.NamedExports]: function visitEachChildOfNamedExports(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateNamedExports(node, - nodesVisitor(node.elements, visitor, isExportSpecifier)); + [SyntaxKind.NamedExports]: function visitEachChildOfNamedExports( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateNamedExports( + node, + nodesVisitor(node.elements, visitor, isExportSpecifier), + ); }, - [SyntaxKind.ExportSpecifier]: function visitEachChildOfExportSpecifier(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExportSpecifier(node, + [SyntaxKind.ExportSpecifier]: function visitEachChildOfExportSpecifier( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExportSpecifier( + node, node.isTypeOnly, nodeVisitor(node.propertyName, visitor, isIdentifier), - Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + ); }, // Module references - [SyntaxKind.ExternalModuleReference]: function visitEachChildOfExternalModuleReference(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateExternalModuleReference(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.ExternalModuleReference]: function visitEachChildOfExternalModuleReference( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateExternalModuleReference( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, // JSX - [SyntaxKind.JsxElement]: function visitEachChildOfJsxElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxElement(node, + [SyntaxKind.JsxElement]: function visitEachChildOfJsxElement( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxElement( + node, Debug.checkDefined(nodeVisitor(node.openingElement, visitor, isJsxOpeningElement)), nodesVisitor(node.children, visitor, isJsxChild), - Debug.checkDefined(nodeVisitor(node.closingElement, visitor, isJsxClosingElement))); + Debug.checkDefined(nodeVisitor(node.closingElement, visitor, isJsxClosingElement)), + ); }, - [SyntaxKind.JsxSelfClosingElement]: function visitEachChildOfJsxSelfClosingElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxSelfClosingElement(node, + [SyntaxKind.JsxSelfClosingElement]: function visitEachChildOfJsxSelfClosingElement( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxSelfClosingElement( + node, Debug.checkDefined(nodeVisitor(node.tagName, visitor, isJsxTagNameExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), - Debug.checkDefined(nodeVisitor(node.attributes, visitor, isJsxAttributes))); + Debug.checkDefined(nodeVisitor(node.attributes, visitor, isJsxAttributes)), + ); }, - [SyntaxKind.JsxOpeningElement]: function visitEachChildOfJsxOpeningElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxOpeningElement(node, + [SyntaxKind.JsxOpeningElement]: function visitEachChildOfJsxOpeningElement( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxOpeningElement( + node, Debug.checkDefined(nodeVisitor(node.tagName, visitor, isJsxTagNameExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), - Debug.checkDefined(nodeVisitor(node.attributes, visitor, isJsxAttributes))); + Debug.checkDefined(nodeVisitor(node.attributes, visitor, isJsxAttributes)), + ); }, - [SyntaxKind.JsxClosingElement]: function visitEachChildOfJsxClosingElement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxClosingElement(node, - Debug.checkDefined(nodeVisitor(node.tagName, visitor, isJsxTagNameExpression))); + [SyntaxKind.JsxClosingElement]: function visitEachChildOfJsxClosingElement( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxClosingElement( + node, + Debug.checkDefined(nodeVisitor(node.tagName, visitor, isJsxTagNameExpression)), + ); }, - [SyntaxKind.JsxNamespacedName]: function forEachChildInJsxNamespacedName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxNamespacedName(node, + [SyntaxKind.JsxNamespacedName]: function forEachChildInJsxNamespacedName( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxNamespacedName( + node, Debug.checkDefined(nodeVisitor(node.namespace, visitor, isIdentifier)), - Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + ); }, - [SyntaxKind.JsxFragment]: function visitEachChildOfJsxFragment(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxFragment(node, + [SyntaxKind.JsxFragment]: function visitEachChildOfJsxFragment( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxFragment( + node, Debug.checkDefined(nodeVisitor(node.openingFragment, visitor, isJsxOpeningFragment)), nodesVisitor(node.children, visitor, isJsxChild), - Debug.checkDefined(nodeVisitor(node.closingFragment, visitor, isJsxClosingFragment))); + Debug.checkDefined(nodeVisitor(node.closingFragment, visitor, isJsxClosingFragment)), + ); }, - [SyntaxKind.JsxAttribute]: function visitEachChildOfJsxAttribute(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxAttribute(node, + [SyntaxKind.JsxAttribute]: function visitEachChildOfJsxAttribute( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxAttribute( + node, Debug.checkDefined(nodeVisitor(node.name, visitor, isJsxAttributeName)), - nodeVisitor(node.initializer, visitor, isStringLiteralOrJsxExpression)); + nodeVisitor(node.initializer, visitor, isStringLiteralOrJsxExpression), + ); }, - [SyntaxKind.JsxAttributes]: function visitEachChildOfJsxAttributes(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxAttributes(node, - nodesVisitor(node.properties, visitor, isJsxAttributeLike)); + [SyntaxKind.JsxAttributes]: function visitEachChildOfJsxAttributes( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxAttributes( + node, + nodesVisitor(node.properties, visitor, isJsxAttributeLike), + ); }, - [SyntaxKind.JsxSpreadAttribute]: function visitEachChildOfJsxSpreadAttribute(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxSpreadAttribute(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.JsxSpreadAttribute]: function visitEachChildOfJsxSpreadAttribute( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxSpreadAttribute( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.JsxExpression]: function visitEachChildOfJsxExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateJsxExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + [SyntaxKind.JsxExpression]: function visitEachChildOfJsxExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateJsxExpression( + node, + nodeVisitor(node.expression, visitor, isExpression), + ); }, // Clauses - [SyntaxKind.CaseClause]: function visitEachChildOfCaseClause(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateCaseClause(node, + [SyntaxKind.CaseClause]: function visitEachChildOfCaseClause( + node, + visitor, + context, + nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateCaseClause( + node, Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), - nodesVisitor(node.statements, visitor, isStatement)); + nodesVisitor(node.statements, visitor, isStatement), + ); }, - [SyntaxKind.DefaultClause]: function visitEachChildOfDefaultClause(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateDefaultClause(node, - nodesVisitor(node.statements, visitor, isStatement)); + [SyntaxKind.DefaultClause]: function visitEachChildOfDefaultClause( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateDefaultClause( + node, + nodesVisitor(node.statements, visitor, isStatement), + ); }, - [SyntaxKind.HeritageClause]: function visitEachChildOfHeritageClause(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateHeritageClause(node, - nodesVisitor(node.types, visitor, isExpressionWithTypeArguments)); + [SyntaxKind.HeritageClause]: function visitEachChildOfHeritageClause( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateHeritageClause( + node, + nodesVisitor(node.types, visitor, isExpressionWithTypeArguments), + ); }, - [SyntaxKind.CatchClause]: function visitEachChildOfCatchClause(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateCatchClause(node, + [SyntaxKind.CatchClause]: function visitEachChildOfCatchClause( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateCatchClause( + node, nodeVisitor(node.variableDeclaration, visitor, isVariableDeclaration), - Debug.checkDefined(nodeVisitor(node.block, visitor, isBlock))); + Debug.checkDefined(nodeVisitor(node.block, visitor, isBlock)), + ); }, // Property assignments - [SyntaxKind.PropertyAssignment]: function visitEachChildOfPropertyAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updatePropertyAssignment(node, + [SyntaxKind.PropertyAssignment]: function visitEachChildOfPropertyAssignment( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updatePropertyAssignment( + node, Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), - Debug.checkDefined(nodeVisitor(node.initializer, visitor, isExpression))); + Debug.checkDefined(nodeVisitor(node.initializer, visitor, isExpression)), + ); }, - [SyntaxKind.ShorthandPropertyAssignment]: function visitEachChildOfShorthandPropertyAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateShorthandPropertyAssignment(node, + [SyntaxKind.ShorthandPropertyAssignment]: function visitEachChildOfShorthandPropertyAssignment( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateShorthandPropertyAssignment( + node, Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), - nodeVisitor(node.objectAssignmentInitializer, visitor, isExpression)); + nodeVisitor(node.objectAssignmentInitializer, visitor, isExpression), + ); }, - [SyntaxKind.SpreadAssignment]: function visitEachChildOfSpreadAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateSpreadAssignment(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.SpreadAssignment]: function visitEachChildOfSpreadAssignment( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSpreadAssignment( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, // Enum - [SyntaxKind.EnumMember]: function visitEachChildOfEnumMember(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updateEnumMember(node, + [SyntaxKind.EnumMember]: function visitEachChildOfEnumMember( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateEnumMember( + node, Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), - nodeVisitor(node.initializer, visitor, isExpression)); + nodeVisitor(node.initializer, visitor, isExpression), + ); }, // Top-level nodes - [SyntaxKind.SourceFile]: function visitEachChildOfSourceFile(node, visitor, context, _nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateSourceFile(node, - visitLexicalEnvironment(node.statements, visitor, context)); + [SyntaxKind.SourceFile]: function visitEachChildOfSourceFile( + node, + visitor, + context, + _nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateSourceFile( + node, + visitLexicalEnvironment(node.statements, visitor, context), + ); }, // Transformation nodes - [SyntaxKind.PartiallyEmittedExpression]: function visitEachChildOfPartiallyEmittedExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { - return context.factory.updatePartiallyEmittedExpression(node, - Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); + [SyntaxKind.PartiallyEmittedExpression]: function visitEachChildOfPartiallyEmittedExpression( + node, + visitor, + context, + _nodesVisitor, + nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updatePartiallyEmittedExpression( + node, + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + ); }, - [SyntaxKind.CommaListExpression]: function visitEachChildOfCommaListExpression(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateCommaListExpression(node, - nodesVisitor(node.elements, visitor, isExpression)); + [SyntaxKind.CommaListExpression]: function visitEachChildOfCommaListExpression( + node, + visitor, + context, + nodesVisitor, + _nodeVisitor, + _tokenVisitor, + ) { + return context.factory.updateCommaListExpression( + node, + nodesVisitor(node.elements, visitor, isExpression), + ); }, }; diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index a829f95d17fbd..ffef55ce3b9e7 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -111,7 +111,7 @@ import { const sysFormatDiagnosticsHost: FormatDiagnosticsHost | undefined = sys ? { getCurrentDirectory: () => sys.getCurrentDirectory(), getNewLine: () => sys.newLine, - getCanonicalFileName: createGetCanonicalFileName(sys.useCaseSensitiveFileNames) + getCanonicalFileName: createGetCanonicalFileName(sys.useCaseSensitiveFileNames), } : undefined; /** @@ -140,12 +140,18 @@ export function createDiagnosticReporter(system: System, pretty?: boolean): Diag /** * @returns Whether the screen was cleared. */ -function clearScreenIfNotWatchingForFileChanges(system: System, diagnostic: Diagnostic, options: CompilerOptions): boolean { - if (system.clearScreen && - !options.preserveWatchOutput && - !options.extendedDiagnostics && - !options.diagnostics && - contains(screenStartingMessageCodes, diagnostic.code)) { +function clearScreenIfNotWatchingForFileChanges( + system: System, + diagnostic: Diagnostic, + options: CompilerOptions, +): boolean { + if ( + system.clearScreen + && !options.preserveWatchOutput + && !options.extendedDiagnostics + && !options.diagnostics + && contains(screenStartingMessageCodes, diagnostic.code) + ) { system.clearScreen(); return true; } @@ -171,14 +177,14 @@ function getPlainDiagnosticFollowingNewLines(diagnostic: Diagnostic, newLine: st * @internal */ export function getLocaleTimeString(system: System) { - return !system.now ? - new Date().toLocaleTimeString() : + return !system.now + ? new Date().toLocaleTimeString() // On some systems / builds of Node, there's a non-breaking space between the time and AM/PM. // This branch is solely for testing, so just switch it to a normal space for baseline stability. // See: // - https://github.com/nodejs/node/issues/45171 // - https://github.com/nodejs/node/issues/45753 - system.now().toLocaleTimeString("en-US", { timeZone: "UTC" }).replace("\u202f", " "); + : system.now().toLocaleTimeString("en-US", { timeZone: "UTC" }).replace("\u202f", " "); } /** @@ -187,14 +193,14 @@ export function getLocaleTimeString(system: System) { * @internal */ export function createWatchStatusReporter(system: System, pretty?: boolean): WatchStatusReporter { - return pretty ? - (diagnostic, newLine, options) => { + return pretty + ? (diagnostic, newLine, options) => { clearScreenIfNotWatchingForFileChanges(system, diagnostic, options); let output = `[${formatColorAndReset(getLocaleTimeString(system), ForegroundColorEscapeSequences.Grey)}] `; output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${newLine + newLine}`; system.write(output); - } : - (diagnostic, newLine, options) => { + } + : (diagnostic, newLine, options) => { let output = ""; if (!clearScreenIfNotWatchingForFileChanges(system, diagnostic, options)) { @@ -202,7 +208,9 @@ export function createWatchStatusReporter(system: System, pretty?: boolean): Wat } output += `${getLocaleTimeString(system)} - `; - output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${getPlainDiagnosticFollowingNewLines(diagnostic, newLine)}`; + output += `${flattenDiagnosticMessageText(diagnostic.messageText, system.newLine)}${ + getPlainDiagnosticFollowingNewLines(diagnostic, newLine) + }`; system.write(output); }; @@ -213,10 +221,24 @@ export function createWatchStatusReporter(system: System, pretty?: boolean): Wat * * @internal */ -export function parseConfigFileWithSystem(configFileName: string, optionsToExtend: CompilerOptions, extendedConfigCache: Map | undefined, watchOptionsToExtend: WatchOptions | undefined, system: System, reportDiagnostic: DiagnosticReporter): ParsedCommandLine | undefined { +export function parseConfigFileWithSystem( + configFileName: string, + optionsToExtend: CompilerOptions, + extendedConfigCache: Map | undefined, + watchOptionsToExtend: WatchOptions | undefined, + system: System, + reportDiagnostic: DiagnosticReporter, +): ParsedCommandLine | undefined { const host: ParseConfigFileHost = system as any; - host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, reportDiagnostic, diagnostic); - const result = getParsedCommandLineOfConfigFile(configFileName, optionsToExtend, host, extendedConfigCache, watchOptionsToExtend); + host.onUnRecoverableConfigFileDiagnostic = diagnostic => + reportUnrecoverableDiagnostic(system, reportDiagnostic, diagnostic); + const result = getParsedCommandLineOfConfigFile( + configFileName, + optionsToExtend, + host, + extendedConfigCache, + watchOptionsToExtend, + ); host.onUnRecoverableConfigFileDiagnostic = undefined!; // TODO: GH#18217 return result; } @@ -228,20 +250,21 @@ export function getErrorCountForSummary(diagnostics: readonly Diagnostic[]) { /** @internal */ export function getFilesInErrorForSummary(diagnostics: readonly Diagnostic[]): (ReportFileInError | undefined)[] { - const filesInError = - filter(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error) - .map( - errorDiagnostic => { - if (errorDiagnostic.file === undefined) return; - return `${errorDiagnostic.file.fileName}`; - }); - return filesInError.map((fileName) => { + const filesInError = filter(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error) + .map( + errorDiagnostic => { + if (errorDiagnostic.file === undefined) return; + return `${errorDiagnostic.file.fileName}`; + }, + ); + return filesInError.map(fileName => { if (fileName === undefined) { return undefined; } - const diagnosticForFileName = find(diagnostics, diagnostic => - diagnostic.file !== undefined && diagnostic.file.fileName === fileName + const diagnosticForFileName = find( + diagnostics, + diagnostic => diagnostic.file !== undefined && diagnostic.file.fileName === fileName, ); if (diagnosticForFileName !== undefined) { @@ -256,9 +279,9 @@ export function getFilesInErrorForSummary(diagnostics: readonly Diagnostic[]): ( /** @internal */ export function getWatchErrorSummaryDiagnosticMessage(errorCount: number) { - return errorCount === 1 ? - Diagnostics.Found_1_error_Watching_for_file_changes : - Diagnostics.Found_0_errors_Watching_for_file_changes; + return errorCount === 1 + ? Diagnostics.Found_1_error_Watching_for_file_changes + : Diagnostics.Found_0_errors_Watching_for_file_changes; } function prettyPathForFileError(error: ReportFileInError, cwd: string) { @@ -275,7 +298,7 @@ export function getErrorSummaryText( errorCount: number, filesInError: readonly (ReportFileInError | undefined)[], newLine: string, - host: HasCurrentDirectory + host: HasCurrentDirectory, ) { if (errorCount === 0) return ""; const nonNilFiles = filesInError.filter(fileInError => fileInError !== undefined); @@ -286,13 +309,14 @@ export function getErrorSummaryText( 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!] : - [Diagnostics.Found_0_errors_in_1_files, errorCount, distinctFileNamesWithLines.length]; + 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!] + : [Diagnostics.Found_0_errors_in_1_files, errorCount, distinctFileNamesWithLines.length]; } const d = createCompilerDiagnostic(...messageAndArgs); @@ -301,11 +325,15 @@ export function getErrorSummaryText( } function createTabularErrorsDisplay(filesInError: (ReportFileInError | undefined)[], host: HasCurrentDirectory) { - const distinctFiles = filesInError.filter((value, index, self) => index === self.findIndex(file => file?.fileName === value?.fileName)); + const distinctFiles = filesInError.filter((value, index, self) => + index === self.findIndex(file => file?.fileName === value?.fileName) + ); if (distinctFiles.length === 0) return ""; const numberLength = (num: number) => Math.log(num) * Math.LOG10E + 1; - const fileToErrorCount = distinctFiles.map(file => ([file, countWhere(filesInError, fileInError => fileInError!.fileName === file!.fileName)] as const)); + const fileToErrorCount = distinctFiles.map( + file => ([file, countWhere(filesInError, fileInError => fileInError!.fileName === file!.fileName)] as const), + ); const maxErrors = fileToErrorCount.reduce((acc, value) => Math.max(acc, value[1] || 0), 0); const headerRow = Diagnostics.Errors_Files.message; @@ -315,11 +343,11 @@ function createTabularErrorsDisplay(filesInError: (ReportFileInError | undefined let tabularData = ""; tabularData += " ".repeat(headerPadding) + headerRow + "\n"; - fileToErrorCount.forEach((row) => { + fileToErrorCount.forEach(row => { const [file, errorCount] = row; const errorCountDigitsLength = Math.log(errorCount) * Math.LOG10E + 1 | 0; - const leftPadding = errorCountDigitsLength < leftPaddingGoal ? - " ".repeat(leftPaddingGoal - errorCountDigitsLength) + const leftPadding = errorCountDigitsLength < leftPaddingGoal + ? " ".repeat(leftPaddingGoal - errorCountDigitsLength) : ""; const fileRef = prettyPathForFileError(file!, host.getCurrentDirectory()); @@ -350,10 +378,13 @@ export function listFiles(program: Program | T, write: /** @internal */ export function explainFiles(program: Program, write: (s: string) => void) { const reasons = program.getFileIncludeReasons(); - const relativeFileName = (fileName: string) => convertToRelativePath(fileName, program.getCurrentDirectory(), program.getCanonicalFileName); + const relativeFileName = (fileName: string) => + convertToRelativePath(fileName, program.getCurrentDirectory(), program.getCanonicalFileName); for (const file of program.getSourceFiles()) { write(`${toFileName(file, relativeFileName)}`); - reasons.get(file.path)?.forEach(reason => write(` ${fileIncludeReasonToDiagnostics(program, reason, relativeFileName).messageText}`)); + reasons.get(file.path)?.forEach(reason => + write(` ${fileIncludeReasonToDiagnostics(program, reason, relativeFileName).messageText}`) + ); explainIfFileIsRedirectAndImpliedFormat(file, relativeFileName)?.forEach(d => write(` ${d.messageText}`)); } } @@ -368,14 +399,14 @@ export function explainIfFileIsRedirectAndImpliedFormat( (result ??= []).push(chainDiagnosticMessages( /*details*/ undefined, Diagnostics.File_is_output_of_project_reference_source_0, - toFileName(file.originalFileName, fileNameConvertor) + toFileName(file.originalFileName, fileNameConvertor), )); } if (file.redirectInfo) { (result ??= []).push(chainDiagnosticMessages( /*details*/ undefined, Diagnostics.File_redirects_to_file_0, - toFileName(file.redirectInfo.redirectTarget, fileNameConvertor) + toFileName(file.redirectInfo.redirectTarget, fileNameConvertor), )); } if (isExternalOrCommonJsModule(file)) { @@ -385,7 +416,7 @@ export function explainIfFileIsRedirectAndImpliedFormat( (result ??= []).push(chainDiagnosticMessages( /*details*/ undefined, Diagnostics.File_is_ECMAScript_module_because_0_has_field_type_with_value_module, - toFileName(last(file.packageJsonLocations!), fileNameConvertor) + toFileName(last(file.packageJsonLocations!), fileNameConvertor), )); } break; @@ -393,10 +424,10 @@ export function explainIfFileIsRedirectAndImpliedFormat( if (file.packageJsonScope) { (result ??= []).push(chainDiagnosticMessages( /*details*/ undefined, - file.packageJsonScope.contents.packageJsonContent.type ? - Diagnostics.File_is_CommonJS_module_because_0_has_field_type_whose_value_is_not_module : - Diagnostics.File_is_CommonJS_module_because_0_does_not_have_field_type, - toFileName(last(file.packageJsonLocations!), fileNameConvertor) + file.packageJsonScope.contents.packageJsonContent.type + ? Diagnostics.File_is_CommonJS_module_because_0_has_field_type_whose_value_is_not_module + : Diagnostics.File_is_CommonJS_module_because_0_does_not_have_field_type, + toFileName(last(file.packageJsonLocations!), fileNameConvertor), )); } else if (file.packageJsonLocations?.length) { @@ -418,7 +449,10 @@ export function getMatchedFileSpec(program: Program, fileName: string) { const filePath = program.getCanonicalFileName(fileName); const basePath = getDirectoryPath(getNormalizedAbsolutePath(configFile.fileName, program.getCurrentDirectory())); - return find(configFile.configFileSpecs.validatedFilesSpec, fileSpec => program.getCanonicalFileName(getNormalizedAbsolutePath(fileSpec, basePath)) === filePath); + return find( + configFile.configFileSpecs.validatedFilesSpec, + fileSpec => program.getCanonicalFileName(getNormalizedAbsolutePath(fileSpec, basePath)) === filePath, + ); } /** @internal */ @@ -440,29 +474,41 @@ export function getMatchedIncludeSpec(program: Program, fileName: string) { } /** @internal */ -export function fileIncludeReasonToDiagnostics(program: Program, reason: FileIncludeReason, fileNameConvertor?: (fileName: string) => string,): DiagnosticMessageChain { +export function fileIncludeReasonToDiagnostics( + program: Program, + reason: FileIncludeReason, + fileNameConvertor?: (fileName: string) => string, +): DiagnosticMessageChain { const options = program.getCompilerOptions(); if (isReferencedFile(reason)) { const referenceLocation = getReferencedFileLocation(path => program.getSourceFileByPath(path), reason); - const referenceText = isReferenceFileLocation(referenceLocation) ? referenceLocation.file.text.substring(referenceLocation.pos, referenceLocation.end) : `"${referenceLocation.text}"`; + const referenceText = isReferenceFileLocation(referenceLocation) + ? referenceLocation.file.text.substring(referenceLocation.pos, referenceLocation.end) + : `"${referenceLocation.text}"`; let message: DiagnosticMessage; - Debug.assert(isReferenceFileLocation(referenceLocation) || reason.kind === FileIncludeKind.Import, "Only synthetic references are imports"); + Debug.assert( + isReferenceFileLocation(referenceLocation) || reason.kind === FileIncludeKind.Import, + "Only synthetic references are imports", + ); switch (reason.kind) { case FileIncludeKind.Import: if (isReferenceFileLocation(referenceLocation)) { - message = referenceLocation.packageId ? - Diagnostics.Imported_via_0_from_file_1_with_packageId_2 : - Diagnostics.Imported_via_0_from_file_1; + message = referenceLocation.packageId + ? Diagnostics.Imported_via_0_from_file_1_with_packageId_2 + : Diagnostics.Imported_via_0_from_file_1; } else if (referenceLocation.text === externalHelpersModuleNameText) { - message = referenceLocation.packageId ? - Diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_importHelpers_as_specified_in_compilerOptions : - Diagnostics.Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions; + message = referenceLocation.packageId + ? Diagnostics + .Imported_via_0_from_file_1_with_packageId_2_to_import_importHelpers_as_specified_in_compilerOptions + : Diagnostics + .Imported_via_0_from_file_1_to_import_importHelpers_as_specified_in_compilerOptions; } else { - message = referenceLocation.packageId ? - Diagnostics.Imported_via_0_from_file_1_with_packageId_2_to_import_jsx_and_jsxs_factory_functions : - Diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions; + message = referenceLocation.packageId + ? Diagnostics + .Imported_via_0_from_file_1_with_packageId_2_to_import_jsx_and_jsxs_factory_functions + : Diagnostics.Imported_via_0_from_file_1_to_import_jsx_and_jsxs_factory_functions; } break; case FileIncludeKind.ReferenceFile: @@ -470,9 +516,9 @@ export function fileIncludeReasonToDiagnostics(program: Program, reason: FileInc message = Diagnostics.Referenced_via_0_from_file_1; break; case FileIncludeKind.TypeReferenceDirective: - message = referenceLocation.packageId ? - Diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2 : - Diagnostics.Type_library_referenced_via_0_from_file_1; + message = referenceLocation.packageId + ? Diagnostics.Type_library_referenced_via_0_from_file_1_with_packageId_2 + : Diagnostics.Type_library_referenced_via_0_from_file_1; break; case FileIncludeKind.LibReferenceDirective: Debug.assert(!referenceLocation.packageId); @@ -486,27 +532,36 @@ export function fileIncludeReasonToDiagnostics(program: Program, reason: FileInc message, referenceText, toFileName(referenceLocation.file, fileNameConvertor), - (referenceLocation.packageId && packageIdToString(referenceLocation.packageId))! + (referenceLocation.packageId && packageIdToString(referenceLocation.packageId))!, ); } switch (reason.kind) { case FileIncludeKind.RootFile: - if (!options.configFile?.configFileSpecs) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Root_file_specified_for_compilation); - const fileName = getNormalizedAbsolutePath(program.getRootFileNames()[reason.index], program.getCurrentDirectory()); + if (!options.configFile?.configFileSpecs) { + return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Root_file_specified_for_compilation); + } + const fileName = getNormalizedAbsolutePath( + program.getRootFileNames()[reason.index], + program.getCurrentDirectory(), + ); const matchedByFiles = getMatchedFileSpec(program, fileName); - if (matchedByFiles) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Part_of_files_list_in_tsconfig_json); + if (matchedByFiles) { + return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Part_of_files_list_in_tsconfig_json); + } const matchedByInclude = getMatchedIncludeSpec(program, fileName); - return isString(matchedByInclude) ? - chainDiagnosticMessages( + return isString(matchedByInclude) + ? chainDiagnosticMessages( /*details*/ undefined, Diagnostics.Matched_by_include_pattern_0_in_1, matchedByInclude, - toFileName(options.configFile, fileNameConvertor) - ) : + toFileName(options.configFile, fileNameConvertor), + ) // Could be additional files specified as roots or matched by default include - chainDiagnosticMessages(/*details*/ undefined, matchedByInclude ? - Diagnostics.Matched_by_default_include_pattern_Asterisk_Asterisk_Slash_Asterisk : - Diagnostics.Root_file_specified_for_compilation + : chainDiagnosticMessages( + /*details*/ undefined, + matchedByInclude + ? Diagnostics.Matched_by_default_include_pattern_Asterisk_Asterisk_Slash_Asterisk + : Diagnostics.Root_file_specified_for_compilation, ); case FileIncludeKind.SourceFromProjectReference: case FileIncludeKind.OutputFromProjectReference: @@ -514,31 +569,49 @@ export function fileIncludeReasonToDiagnostics(program: Program, reason: FileInc const referencedResolvedRef = Debug.checkDefined(program.getResolvedProjectReferences()?.[reason.index]); return chainDiagnosticMessages( /*details*/ undefined, - outFile(options) ? - isOutput ? - Diagnostics.Output_from_referenced_project_0_included_because_1_specified : - Diagnostics.Source_from_referenced_project_0_included_because_1_specified : - isOutput ? - Diagnostics.Output_from_referenced_project_0_included_because_module_is_specified_as_none : - Diagnostics.Source_from_referenced_project_0_included_because_module_is_specified_as_none, + outFile(options) + ? isOutput + ? Diagnostics.Output_from_referenced_project_0_included_because_1_specified + : Diagnostics.Source_from_referenced_project_0_included_because_1_specified + : isOutput + ? Diagnostics.Output_from_referenced_project_0_included_because_module_is_specified_as_none + : Diagnostics.Source_from_referenced_project_0_included_because_module_is_specified_as_none, toFileName(referencedResolvedRef.sourceFile.fileName, fileNameConvertor), options.outFile ? "--outFile" : "--out", ); case FileIncludeKind.AutomaticTypeDirectiveFile: { - const messageAndArgs: DiagnosticAndArguments = options.types ? - reason.packageId ? - [Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1, reason.typeReference, packageIdToString(reason.packageId)] : - [Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions, reason.typeReference] : - reason.packageId ? - [Diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1, reason.typeReference, packageIdToString(reason.packageId)] : - [Diagnostics.Entry_point_for_implicit_type_library_0, reason.typeReference]; + const messageAndArgs: DiagnosticAndArguments = options.types + ? reason.packageId + ? [ + Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1, + reason.typeReference, + packageIdToString(reason.packageId), + ] + : [Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions, reason.typeReference] + : reason.packageId + ? [ + Diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1, + reason.typeReference, + packageIdToString(reason.packageId), + ] + : [Diagnostics.Entry_point_for_implicit_type_library_0, reason.typeReference]; return chainDiagnosticMessages(/*details*/ undefined, ...messageAndArgs); } case FileIncludeKind.LibFile: { - if (reason.index !== undefined) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Library_0_specified_in_compilerOptions, options.lib![reason.index]); - const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === getEmitScriptTarget(options) ? key : undefined); - const messageAndArgs: DiagnosticAndArguments = target ? [Diagnostics.Default_library_for_target_0, target] : [Diagnostics.Default_library]; + if (reason.index !== undefined) { + return chainDiagnosticMessages( + /*details*/ undefined, + Diagnostics.Library_0_specified_in_compilerOptions, + options.lib![reason.index], + ); + } + const target = forEachEntry( + targetOptionDeclaration.type, + (value, key) => value === getEmitScriptTarget(options) ? key : undefined, + ); + const messageAndArgs: DiagnosticAndArguments = target ? [Diagnostics.Default_library_for_target_0, target] + : [Diagnostics.Default_library]; return chainDiagnosticMessages(/*details*/ undefined, ...messageAndArgs); } default: @@ -564,7 +637,7 @@ export function emitFilesAndReportErrors( writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, - customTransformers?: CustomTransformers + customTransformers?: CustomTransformers, ): { emitResult: EmitResult; diagnostics: SortedReadonlyArray; @@ -593,7 +666,13 @@ export function emitFilesAndReportErrors( // Emit and report any errors we ran into. const emitResult = isListFilesOnly ? { emitSkipped: true, diagnostics: emptyArray } - : program.emit(/*targetSourceFile*/ undefined, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); + : program.emit( + /*targetSourceFile*/ undefined, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers, + ); const { emittedFiles, diagnostics: emitDiagnostics } = emitResult; addRange(allDiagnostics, emitDiagnostics); @@ -627,7 +706,7 @@ export function emitFilesAndReportErrorsAndGetExitStatus 0) { @@ -665,7 +744,7 @@ export function createWatchHost(system = sys, reportWatchStatus?: WatchStatusRep watchFile: maybeBind(system, system.watchFile) || returnNoopFileWatcher, watchDirectory: maybeBind(system, system.watchDirectory) || returnNoopFileWatcher, setTimeout: maybeBind(system, system.setTimeout) || noop, - clearTimeout: maybeBind(system, system.clearTimeout) || noop + clearTimeout: maybeBind(system, system.clearTimeout) || noop, }; } @@ -698,29 +777,29 @@ export const WatchType: WatchTypeRegistry = { /** @internal */ export interface WatchTypeRegistry { - ConfigFile: "Config file", - ExtendedConfigFile: "Extended config file", - SourceFile: "Source file", - MissingFile: "Missing file", - WildcardDirectory: "Wild card directory", - FailedLookupLocations: "Failed Lookup Locations", - AffectingFileLocation: "File location affecting resolution", - TypeRoots: "Type roots", - ConfigFileOfReferencedProject: "Config file of referened project", - ExtendedConfigOfReferencedProject: "Extended config file of referenced project", - WildcardDirectoryOfReferencedProject: "Wild card directory of referenced project", - PackageJson: "package.json file", + ConfigFile: "Config file"; + ExtendedConfigFile: "Extended config file"; + SourceFile: "Source file"; + MissingFile: "Missing file"; + WildcardDirectory: "Wild card directory"; + FailedLookupLocations: "Failed Lookup Locations"; + AffectingFileLocation: "File location affecting resolution"; + TypeRoots: "Type roots"; + ConfigFileOfReferencedProject: "Config file of referened project"; + ExtendedConfigOfReferencedProject: "Extended config file of referenced project"; + WildcardDirectoryOfReferencedProject: "Wild card directory of referenced project"; + PackageJson: "package.json file"; // Additional tsserver specific watch information - ClosedScriptInfo: "Closed Script info", - ConfigFileForInferredRoot: "Config file for the inferred project root", - NodeModules: "node_modules for closed script infos and package.jsons affecting module specifier cache", - MissingSourceMapFile: "Missing source map file", - NoopConfigFileForInferredRoot: "Noop Config file for the inferred project root", - MissingGeneratedFile: "Missing generated file", - NodeModulesForModuleSpecifierCache: "node_modules for module specifier cache invalidation", - TypingInstallerLocationFile: "File location for typing installer", - TypingInstallerLocationDirectory: "Directory location for typing installer", + ClosedScriptInfo: "Closed Script info"; + ConfigFileForInferredRoot: "Config file for the inferred project root"; + NodeModules: "node_modules for closed script infos and package.jsons affecting module specifier cache"; + MissingSourceMapFile: "Missing source map file"; + NoopConfigFileForInferredRoot: "Noop Config file for the inferred project root"; + MissingGeneratedFile: "Missing generated file"; + NodeModulesForModuleSpecifierCache: "node_modules for module specifier cache invalidation"; + TypingInstallerLocationFile: "File location for typing installer"; + TypingInstallerLocationDirectory: "Directory location for typing installer"; } /** @internal */ @@ -729,8 +808,13 @@ export interface WatchFactoryWithLog extends WatchFactory(host: WatchFactoryHost & { trace?(s: string): void; }, options: { extendedDiagnostics?: boolean; diagnostics?: boolean; }) { - const watchLogLevel = host.trace ? options.extendedDiagnostics ? WatchLogLevel.Verbose : options.diagnostics ? WatchLogLevel.TriggerOnly : WatchLogLevel.None : WatchLogLevel.None; +export function createWatchFactory( + host: WatchFactoryHost & { trace?(s: string): void; }, + options: { extendedDiagnostics?: boolean; diagnostics?: boolean; }, +) { + const watchLogLevel = host.trace + ? options.extendedDiagnostics ? WatchLogLevel.Verbose + : options.diagnostics ? WatchLogLevel.TriggerOnly : WatchLogLevel.None : WatchLogLevel.None; const writeLog: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => host.trace!(s)) : noop; const result = getWatchFactory(host, watchLogLevel, writeLog) as WatchFactoryWithLog; result.writeLog = writeLog; @@ -738,20 +822,24 @@ export function createWatchFactory(host: WatchFactoryHost & { tra } /** @internal */ -export function createCompilerHostFromProgramHost(host: ProgramHost, getCompilerOptions: () => CompilerOptions, directoryStructureHost: DirectoryStructureHost = host): CompilerHost { +export function createCompilerHostFromProgramHost( + host: ProgramHost, + getCompilerOptions: () => CompilerOptions, + directoryStructureHost: DirectoryStructureHost = host, +): CompilerHost { const useCaseSensitiveFileNames = host.useCaseSensitiveFileNames(); const compilerHost: CompilerHost = { getSourceFile: createGetSourceFile( (fileName, encoding) => !encoding ? compilerHost.readFile(fileName) : host.readFile(fileName, encoding), getCompilerOptions, - /*setParentNodes*/ undefined + /*setParentNodes*/ undefined, ), getDefaultLibLocation: maybeBind(host, host.getDefaultLibLocation), getDefaultLibFileName: options => host.getDefaultLibFileName(options), writeFile: createWriteFileMeasuringIO( (path, data, writeByteOrderMark) => host.writeFile!(path, data, writeByteOrderMark), path => host.createDirectory!(path), - path => host.directoryExists!(path) + path => host.directoryExists!(path), ), getCurrentDirectory: memoize(() => host.getCurrentDirectory()), useCaseSensitiveFileNames: () => useCaseSensitiveFileNames, @@ -827,7 +915,10 @@ export function setGetSourceFileAsHashVersioned(compilerHost: CompilerHost) { * * @internal */ -export function createProgramHost(system: System, createProgram: CreateProgram | undefined): ProgramHost { +export function createProgramHost( + system: System, + createProgram: CreateProgram | undefined, +): ProgramHost { const getDefaultLibLocation = memoize(() => getDirectoryPath(normalizePath(system.getExecutingFilePath()))); return { useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames, @@ -839,7 +930,8 @@ export function createProgramHost system.readFile(path, encoding), directoryExists: path => system.directoryExists(path), getDirectories: path => system.getDirectories(path), - readDirectory: (path, extensions, exclude, include, depth) => system.readDirectory(path, extensions, exclude, include, depth), + readDirectory: (path, extensions, exclude, include, depth) => + system.readDirectory(path, extensions, exclude, include, depth), realpath: maybeBind(system, system.realpath), getEnvironmentVariable: maybeBind(system, system.getEnvironmentVariable), trace: s => system.write(s + system.newLine), @@ -855,7 +947,12 @@ export function createProgramHost(system = sys, createProgram: CreateProgram | undefined, reportDiagnostic: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHost { +function createWatchCompilerHost( + system = sys, + createProgram: CreateProgram | undefined, + reportDiagnostic: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, +): WatchCompilerHost { const write = (s: string) => system.write(s + system.newLine); const result = createProgramHost(system, createProgram) as WatchCompilerHost; copyProperties(result, createWatchHost(system, reportWatchStatus)); @@ -867,12 +964,13 @@ function createWatchCompilerHost result.onWatchStatusChange!( - createCompilerDiagnostic(getWatchErrorSummaryDiagnosticMessage(errorCount), errorCount), - newLine, - compilerOptions, - errorCount - ) + errorCount => + result.onWatchStatusChange!( + createCompilerDiagnostic(getWatchErrorSummaryDiagnosticMessage(errorCount), errorCount), + newLine, + compilerOptions, + errorCount, + ), ); }; return result; @@ -895,7 +993,9 @@ export interface CreateWatchCompilerHostInput { } /** @internal */ -export interface CreateWatchCompilerHostOfConfigFileInput extends CreateWatchCompilerHostInput { +export interface CreateWatchCompilerHostOfConfigFileInput + extends CreateWatchCompilerHostInput +{ configFileName: string; optionsToExtend?: CompilerOptions; watchOptionsToExtend?: WatchOptions; @@ -906,13 +1006,27 @@ export interface CreateWatchCompilerHostOfConfigFileInput({ - configFileName, optionsToExtend, watchOptionsToExtend, extraFileExtensions, - system, createProgram, reportDiagnostic, reportWatchStatus +export function createWatchCompilerHostOfConfigFile< + T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram, +>({ + configFileName, + optionsToExtend, + watchOptionsToExtend, + extraFileExtensions, + system, + createProgram, + reportDiagnostic, + reportWatchStatus, }: CreateWatchCompilerHostOfConfigFileInput): WatchCompilerHostOfConfigFile { const diagnosticReporter = reportDiagnostic || createDiagnosticReporter(system); - const host = createWatchCompilerHost(system, createProgram, diagnosticReporter, reportWatchStatus) as WatchCompilerHostOfConfigFile; - host.onUnRecoverableConfigFileDiagnostic = diagnostic => reportUnrecoverableDiagnostic(system, diagnosticReporter, diagnostic); + const host = createWatchCompilerHost( + system, + createProgram, + diagnosticReporter, + reportWatchStatus, + ) as WatchCompilerHostOfConfigFile; + host.onUnRecoverableConfigFileDiagnostic = diagnostic => + reportUnrecoverableDiagnostic(system, diagnosticReporter, diagnostic); host.configFileName = configFileName; host.optionsToExtend = optionsToExtend; host.watchOptionsToExtend = watchOptionsToExtend; @@ -921,7 +1035,9 @@ export function createWatchCompilerHostOfConfigFile extends CreateWatchCompilerHostInput { +export interface CreateWatchCompilerHostOfFilesAndCompilerOptionsInput + extends CreateWatchCompilerHostInput +{ rootFiles: string[]; options: CompilerOptions; watchOptions: WatchOptions | undefined; @@ -932,11 +1048,24 @@ export interface CreateWatchCompilerHostOfFilesAndCompilerOptionsInput({ - rootFiles, options, watchOptions, projectReferences, - system, createProgram, reportDiagnostic, reportWatchStatus +export function createWatchCompilerHostOfFilesAndCompilerOptions< + T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram, +>({ + rootFiles, + options, + watchOptions, + projectReferences, + system, + createProgram, + reportDiagnostic, + reportWatchStatus, }: CreateWatchCompilerHostOfFilesAndCompilerOptionsInput): WatchCompilerHostOfFilesAndCompilerOptions { - const host = createWatchCompilerHost(system, createProgram, reportDiagnostic || createDiagnosticReporter(system), reportWatchStatus) as WatchCompilerHostOfFilesAndCompilerOptions; + const host = createWatchCompilerHost( + system, + createProgram, + reportDiagnostic || createDiagnosticReporter(system), + reportWatchStatus, + ) as WatchCompilerHostOfFilesAndCompilerOptions; host.rootFiles = rootFiles; host.options = options; host.watchOptions = watchOptions; @@ -965,7 +1094,9 @@ export function performIncrementalCompilation(input: IncrementalCompilationOptio builderProgram, input.reportDiagnostic || createDiagnosticReporter(system), s => host.trace && host.trace(s), - input.reportErrorSummary || input.options.pretty ? (errorCount, filesInError) => system.write(getErrorSummaryText(errorCount, filesInError, system.newLine, host)) : undefined + input.reportErrorSummary || input.options.pretty + ? (errorCount, filesInError) => + system.write(getErrorSummaryText(errorCount, filesInError, system.newLine, host)) : undefined, ); if (input.afterProgramEmitAndDiagnostics) input.afterProgramEmitAndDiagnostics(builderProgram); return exitStatus; diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index b216c8cb75de0..f64373dfd863e 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -123,7 +123,10 @@ export function createIncrementalCompilerHost(options: CompilerOptions, system = host.createHash = maybeBind(system, system.createHash); host.storeFilesChangingSignatureDuringEmit = system.storeFilesChangingSignatureDuringEmit; setGetSourceFileAsHashVersioned(host); - changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName)); + changeCompilerHostLikeToUseCache( + host, + fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName), + ); return host; } @@ -137,7 +140,12 @@ export interface IncrementalProgramOptions { } export function createIncrementalProgram({ - rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram + rootNames, + options, + configFileParsingDiagnostics, + projectReferences, + host, + createProgram, }: IncrementalProgramOptions): T { host = host || createIncrementalCompilerHost(options); createProgram = createProgram || createEmitAndSemanticDiagnosticsBuilderProgram as any as CreateProgram; @@ -145,9 +153,21 @@ export function createIncrementalProgram void; +export type WatchStatusReporter = ( + diagnostic: Diagnostic, + newLine: string, + options: CompilerOptions, + errorCount?: number, +) => void; /** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */ -export type CreateProgram = (rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[] | undefined) => T; +export type CreateProgram = ( + rootNames: readonly string[] | undefined, + options: CompilerOptions | undefined, + host?: CompilerHost, + oldProgram?: T, + configFileParsingDiagnostics?: readonly Diagnostic[], + projectReferences?: readonly ProjectReference[] | undefined, +) => T; /** Host that has watch functionality used in --watch mode */ export interface WatchHost { @@ -155,9 +175,19 @@ export interface WatchHost { onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions, errorCount?: number): void; /** Used to watch changes in source files, missing files needed to update the program or config file */ - watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; + watchFile( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; /** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */ - watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; + watchDirectory( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; /** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */ setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any; /** If provided, will be used to reset existing delayed compilation */ @@ -193,7 +223,13 @@ export interface ProgramHost { /** If provided, used in resolutions as well as handling directory structure */ getDirectories?(path: string): string[]; /** If provided, used to cache and handle directory structure modifications */ - readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory?( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; /** Symbol links resolution */ realpath?(path: string): string; @@ -207,13 +243,26 @@ export interface ProgramHost { * * If provided, used to resolve the module names, otherwise typescript's default module resolution */ - resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[]; + resolveModuleNames?( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingSourceFile?: SourceFile, + ): (ResolvedModule | undefined)[]; /** * @deprecated supply resolveTypeReferenceDirectiveReferences instead for resolution that can handle newer resolution modes like nodenext * * If provided, used to resolve type reference directives, otherwise typescript's default resolution */ - resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: ResolutionMode): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?( + typeReferenceDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingFileMode?: ResolutionMode, + ): (ResolvedTypeReferenceDirective | undefined)[]; resolveModuleNameLiterals?( moduleLiterals: readonly StringLiteralLike[], containingFile: string, @@ -228,7 +277,7 @@ export interface ProgramHost { redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile | undefined, - reusedNames: readonly T[] | undefined + reusedNames: readonly T[] | undefined, ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; /** @internal */ resolveLibrary?( @@ -294,7 +343,9 @@ export interface WatchCompilerHostOfFilesAndCompilerOptions extends WatchCompilerHost, ConfigFileDiagnosticsReporter { +export interface WatchCompilerHostOfConfigFile + extends WatchCompilerHost, ConfigFileDiagnosticsReporter +{ /** Name of the config file to compile */ configFileName: string; @@ -303,13 +354,19 @@ export interface WatchCompilerHostOfConfigFile extends watchOptionsToExtend?: WatchOptions; - extraFileExtensions?: readonly FileExtensionInfo[] + extraFileExtensions?: readonly FileExtensionInfo[]; /** * Used to generate source file names from the config file and its include, exclude, files rules * and also to cache the directory stucture */ - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; } /** @@ -352,9 +409,36 @@ export interface WatchOfFilesAndCompilerOptions extends Watch { /** * Create the watch compiler host for either configFile or fileNames and its options */ -export function createWatchCompilerHost(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, watchOptionsToExtend?: WatchOptions, extraFileExtensions?: readonly FileExtensionInfo[]): WatchCompilerHostOfConfigFile; -export function createWatchCompilerHost(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: readonly ProjectReference[], watchOptions?: WatchOptions): WatchCompilerHostOfFilesAndCompilerOptions; -export function createWatchCompilerHost(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, createProgram?: CreateProgram, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferencesOrWatchOptionsToExtend?: readonly ProjectReference[] | WatchOptions, watchOptionsOrExtraFileExtensions?: WatchOptions | readonly FileExtensionInfo[]): WatchCompilerHostOfFilesAndCompilerOptions | WatchCompilerHostOfConfigFile { +export function createWatchCompilerHost( + configFileName: string, + optionsToExtend: CompilerOptions | undefined, + system: System, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, + watchOptionsToExtend?: WatchOptions, + extraFileExtensions?: readonly FileExtensionInfo[], +): WatchCompilerHostOfConfigFile; +export function createWatchCompilerHost( + rootFiles: string[], + options: CompilerOptions, + system: System, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, + projectReferences?: readonly ProjectReference[], + watchOptions?: WatchOptions, +): WatchCompilerHostOfFilesAndCompilerOptions; +export function createWatchCompilerHost( + rootFilesOrConfigFileName: string | string[], + options: CompilerOptions | undefined, + system: System, + createProgram?: CreateProgram, + reportDiagnostic?: DiagnosticReporter, + reportWatchStatus?: WatchStatusReporter, + projectReferencesOrWatchOptionsToExtend?: readonly ProjectReference[] | WatchOptions, + watchOptionsOrExtraFileExtensions?: WatchOptions | readonly FileExtensionInfo[], +): WatchCompilerHostOfFilesAndCompilerOptions | WatchCompilerHostOfConfigFile { if (isArray(rootFilesOrConfigFileName)) { return createWatchCompilerHostOfFilesAndCompilerOptions({ rootFiles: rootFilesOrConfigFileName, @@ -400,12 +484,18 @@ type WatchCompilerHostOfFilesAndCompilerOptionsOrConfigFile(host: WatchCompilerHostOfFilesAndCompilerOptions): WatchOfFilesAndCompilerOptions; +export function createWatchProgram( + host: WatchCompilerHostOfFilesAndCompilerOptions, +): WatchOfFilesAndCompilerOptions; /** * Creates the watch from the host for config file */ -export function createWatchProgram(host: WatchCompilerHostOfConfigFile): WatchOfConfigFile; -export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptionsOrConfigFile): WatchOfFilesAndCompilerOptions | WatchOfConfigFile { +export function createWatchProgram( + host: WatchCompilerHostOfConfigFile, +): WatchOfConfigFile; +export function createWatchProgram( + host: WatchCompilerHostOfFilesAndCompilerOptionsOrConfigFile, +): WatchOfFilesAndCompilerOptions | WatchOfConfigFile { interface FilePresentOnHost { version: string; sourceFile: SourceFile; @@ -420,30 +510,37 @@ export function createWatchProgram(host: WatchCompiler type HostFileInfo = FilePresentOnHost | FileMissingOnHost | FilePresenceUnknownOnHost; let builderProgram: T; - let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc - let missingFilesMap: Map; // Map of file watchers for the missing files + let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc + let missingFilesMap: Map; // Map of file watchers for the missing files let watchedWildcardDirectories: Map; // map of watchers for the wild card directories in the config file - let timerToUpdateProgram: any; // timer callback to recompile the program - let timerToInvalidateFailedLookupResolutions: any; // timer callback to invalidate resolutions for changes in failed lookup locations - let parsedConfigs: Map | undefined; // Parsed commandline and watching cached for referenced projects + let timerToUpdateProgram: any; // timer callback to recompile the program + let timerToInvalidateFailedLookupResolutions: any; // timer callback to invalidate resolutions for changes in failed lookup locations + let parsedConfigs: Map | undefined; // Parsed commandline and watching cached for referenced projects let sharedExtendedConfigFileWatchers: Map>; // Map of file watchers for extended files, shared between different referenced projects - let extendedConfigCache = host.extendedConfigCache; // Cache for extended config evaluation - let reportFileChangeDetectedOnCreateProgram = false; // True if synchronizeProgram should report "File change detected..." when a new program is created + let extendedConfigCache = host.extendedConfigCache; // Cache for extended config evaluation + let reportFileChangeDetectedOnCreateProgram = false; // True if synchronizeProgram should report "File change detected..." when a new program is created - const sourceFilesCache = new Map(); // Cache that stores the source file and version info - let missingFilePathsRequestedForRelease: Path[] | undefined; // These paths are held temporarily so that we can remove the entry from source file cache if the file is not tracked by missing files - let hasChangedCompilerOptions = false; // True if the compiler options have changed between compilations + const sourceFilesCache = new Map(); // Cache that stores the source file and version info + let missingFilePathsRequestedForRelease: Path[] | undefined; // These paths are held temporarily so that we can remove the entry from source file cache if the file is not tracked by missing files + let hasChangedCompilerOptions = false; // True if the compiler options have changed between compilations const useCaseSensitiveFileNames = host.useCaseSensitiveFileNames(); const currentDirectory = host.getCurrentDirectory(); - const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {}, watchOptionsToExtend, extraFileExtensions, createProgram } = host; + const { + configFileName, + optionsToExtend: optionsToExtendForConfigFile = {}, + watchOptionsToExtend, + extraFileExtensions, + createProgram, + } = host; let { rootFiles: rootFileNames, options: compilerOptions, watchOptions, projectReferences } = host; let wildcardDirectories: MapLike | undefined; let configFileParsingDiagnostics: Diagnostic[] | undefined; let canConfigFileJsonReportNoInputFiles = false; let hasChangedConfigFileParsingErrors = false; - const cachedDirectoryStructureHost = configFileName === undefined ? undefined : createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames); + const cachedDirectoryStructureHost = configFileName === undefined ? undefined + : createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames); const directoryStructureHost: DirectoryStructureHost = cachedDirectoryStructureHost || host; const parseConfigFileHost = parseConfigHostFromCompilerHostLike(host, directoryStructureHost); @@ -470,14 +567,23 @@ export function createWatchProgram(host: WatchCompiler writeLog(`Current directory: ${currentDirectory} CaseSensitiveFileNames: ${useCaseSensitiveFileNames}`); let configFileWatcher: FileWatcher | undefined; if (configFileName) { - configFileWatcher = watchFile(configFileName, scheduleProgramReload, PollingInterval.High, watchOptions, WatchType.ConfigFile); + configFileWatcher = watchFile( + configFileName, + scheduleProgramReload, + PollingInterval.High, + watchOptions, + WatchType.ConfigFile, + ); } - const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions!, directoryStructureHost) as CompilerHost & ResolutionCacheHost; + const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions!, directoryStructureHost) as + & CompilerHost + & ResolutionCacheHost; setGetSourceFileAsHashVersioned(compilerHost); // Members for CompilerHost const getNewSourceFile = compilerHost.getSourceFile; - compilerHost.getSourceFile = (fileName, ...args) => getVersionedSourceFileByPath(fileName, toPath(fileName), ...args); + compilerHost.getSourceFile = (fileName, ...args) => + getVersionedSourceFileByPath(fileName, toPath(fileName), ...args); compilerHost.getSourceFileByPath = getVersionedSourceFileByPath; compilerHost.getNewLine = () => newLine; compilerHost.fileExists = fileExists; @@ -487,11 +593,15 @@ export function createWatchProgram(host: WatchCompiler compilerHost.toPath = toPath; compilerHost.getCompilationSettings = () => compilerOptions!; compilerHost.useSourceOfProjectReferenceRedirect = maybeBind(host, host.useSourceOfProjectReferenceRedirect); - 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); + 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); compilerHost.getCachedDirectoryStructureHost = () => cachedDirectoryStructureHost; - compilerHost.scheduleInvalidateResolutionsOfFailedLookupLocations = scheduleInvalidateResolutionsOfFailedLookupLocations; + compilerHost.scheduleInvalidateResolutionsOfFailedLookupLocations = + scheduleInvalidateResolutionsOfFailedLookupLocations; compilerHost.onInvalidatedResolution = scheduleProgramUpdate; compilerHost.onChangedAutomaticTypeDirectiveNames = scheduleProgramUpdate; compilerHost.fileIsOpen = returnFalse; @@ -500,11 +610,12 @@ export function createWatchProgram(host: WatchCompiler compilerHost.getParsedCommandLine = getParsedCommandLine; // Cache for the module resolution - const resolutionCache = createResolutionCache(compilerHost, - configFileName ? - getDirectoryPath(getNormalizedAbsolutePath(configFileName, currentDirectory)) : - currentDirectory, - /*logChangesWhenResolvingModule*/ false + const resolutionCache = createResolutionCache( + compilerHost, + configFileName + ? getDirectoryPath(getNormalizedAbsolutePath(configFileName, currentDirectory)) + : currentDirectory, + /*logChangesWhenResolvingModule*/ false, ); // Resolve module using host module resolution strategy if provided otherwise use resolution cache to resolve module names compilerHost.resolveModuleNameLiterals = maybeBind(host, host.resolveModuleNameLiterals); @@ -512,26 +623,30 @@ export function createWatchProgram(host: WatchCompiler if (!compilerHost.resolveModuleNameLiterals && !compilerHost.resolveModuleNames) { compilerHost.resolveModuleNameLiterals = resolutionCache.resolveModuleNameLiterals.bind(resolutionCache); } - compilerHost.resolveTypeReferenceDirectiveReferences = maybeBind(host, host.resolveTypeReferenceDirectiveReferences); + compilerHost.resolveTypeReferenceDirectiveReferences = maybeBind( + host, + host.resolveTypeReferenceDirectiveReferences, + ); compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives); if (!compilerHost.resolveTypeReferenceDirectiveReferences && !compilerHost.resolveTypeReferenceDirectives) { - compilerHost.resolveTypeReferenceDirectiveReferences = resolutionCache.resolveTypeReferenceDirectiveReferences.bind(resolutionCache); + compilerHost.resolveTypeReferenceDirectiveReferences = resolutionCache.resolveTypeReferenceDirectiveReferences + .bind(resolutionCache); } - compilerHost.resolveLibrary = !host.resolveLibrary ? - resolutionCache.resolveLibrary.bind(resolutionCache) : - host.resolveLibrary.bind(host); - compilerHost.getModuleResolutionCache = host.resolveModuleNameLiterals || host.resolveModuleNames ? - maybeBind(host, host.getModuleResolutionCache) : - (() => resolutionCache.getModuleResolutionCache()); - const userProvidedResolution = !!host.resolveModuleNameLiterals || !!host.resolveTypeReferenceDirectiveReferences || - !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives; + compilerHost.resolveLibrary = !host.resolveLibrary + ? resolutionCache.resolveLibrary.bind(resolutionCache) + : host.resolveLibrary.bind(host); + compilerHost.getModuleResolutionCache = host.resolveModuleNameLiterals || host.resolveModuleNames + ? maybeBind(host, host.getModuleResolutionCache) + : (() => resolutionCache.getModuleResolutionCache()); + const userProvidedResolution = !!host.resolveModuleNameLiterals || !!host.resolveTypeReferenceDirectiveReferences + || !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives; // All resolutions are invalid if user provided resolutions and didnt supply hasInvalidatedResolutions - const customHasInvalidatedResolutions = userProvidedResolution ? - maybeBind(host, host.hasInvalidatedResolutions) || returnTrue : - returnFalse; - const customHasInvalidLibResolutions = host.resolveLibrary ? - maybeBind(host, host.hasInvalidatedLibResolutions) || returnTrue : - returnFalse; + const customHasInvalidatedResolutions = userProvidedResolution + ? maybeBind(host, host.hasInvalidatedResolutions) || returnTrue + : returnFalse; + const customHasInvalidLibResolutions = host.resolveLibrary + ? maybeBind(host, host.hasInvalidatedLibResolutions) || returnTrue + : returnFalse; builderProgram = readBuilderProgram(compilerOptions, compilerHost) as any as T; synchronizeProgram(); @@ -540,11 +655,18 @@ export function createWatchProgram(host: WatchCompiler watchConfigFileWildCardDirectories(); // Update extended config file watch - if (configFileName) updateExtendedConfigFilesWatches(toPath(configFileName), compilerOptions, watchOptions, WatchType.ExtendedConfigFile); + if (configFileName) { + updateExtendedConfigFilesWatches( + toPath(configFileName), + compilerOptions, + watchOptions, + WatchType.ExtendedConfigFile, + ); + } - return configFileName ? - { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close } : - { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close }; + return configFileName + ? { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, close } + : { getCurrentProgram: getCurrentBuilderProgram, getProgram: updateProgram, updateRootFileNames, close }; function close() { clearInvalidateResolutionsOfFailedLookupLocations(); @@ -608,17 +730,42 @@ export function createWatchProgram(host: WatchCompiler } } - const { hasInvalidatedResolutions, hasInvalidatedLibResolutions } = resolutionCache.createHasInvalidatedResolutions(customHasInvalidatedResolutions, customHasInvalidLibResolutions); + const { hasInvalidatedResolutions, hasInvalidatedLibResolutions } = resolutionCache + .createHasInvalidatedResolutions(customHasInvalidatedResolutions, customHasInvalidLibResolutions); const { - originalReadFile, originalFileExists, originalDirectoryExists, - originalCreateDirectory, originalWriteFile, readFileWithCache + originalReadFile, + originalFileExists, + originalDirectoryExists, + originalCreateDirectory, + originalWriteFile, + readFileWithCache, } = changeCompilerHostLikeToUseCache(compilerHost, toPath); - if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, path => getSourceVersion(path, readFileWithCache), fileName => compilerHost.fileExists(fileName), hasInvalidatedResolutions, hasInvalidatedLibResolutions, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { + if ( + isProgramUptoDate( + getCurrentProgram(), + rootFileNames, + compilerOptions, + path => getSourceVersion(path, readFileWithCache), + fileName => compilerHost.fileExists(fileName), + hasInvalidatedResolutions, + hasInvalidatedLibResolutions, + hasChangedAutomaticTypeDirectiveNames, + getParsedCommandLine, + projectReferences, + ) + ) { if (hasChangedConfigFileParsingErrors) { if (reportFileChangeDetectedOnCreateProgram) { reportWatchDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation); } - builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences); + builderProgram = createProgram( + /*rootNames*/ undefined, + /*options*/ undefined, + compilerHost, + builderProgram, + configFileParsingDiagnostics, + projectReferences, + ); hasChangedConfigFileParsingErrors = false; } } @@ -643,7 +790,10 @@ export function createWatchProgram(host: WatchCompiler return builderProgram; } - function createNewProgram(hasInvalidatedResolutions: HasInvalidatedResolutions, hasInvalidatedLibResolutions: HasInvalidatedLibResolutions) { + function createNewProgram( + hasInvalidatedResolutions: HasInvalidatedResolutions, + hasInvalidatedLibResolutions: HasInvalidatedLibResolutions, + ) { // Compile the program writeLog("CreatingProgramWith::"); writeLog(` roots: ${JSON.stringify(rootFileNames)}`); @@ -658,11 +808,22 @@ export function createWatchProgram(host: WatchCompiler compilerHost.hasInvalidatedLibResolutions = hasInvalidatedLibResolutions; compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames; const oldProgram = getCurrentProgram(); - builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences); + builderProgram = createProgram( + rootFileNames, + compilerOptions, + compilerHost, + builderProgram, + configFileParsingDiagnostics, + projectReferences, + ); resolutionCache.finishCachingPerDirectoryResolution(builderProgram.getProgram(), oldProgram); // Update watches - updateMissingFilePathsWatch(builderProgram.getProgram(), missingFilesMap || (missingFilesMap = new Map()), watchMissingFilePath); + updateMissingFilePathsWatch( + builderProgram.getProgram(), + missingFilesMap || (missingFilesMap = new Map()), + watchMissingFilePath, + ); if (needsUpdateInTypeRootWatch) { resolutionCache.updateTypeRootsWatch(); } @@ -700,7 +861,9 @@ export function createWatchProgram(host: WatchCompiler return typeof hostSourceFile === "boolean"; } - function isFilePresenceUnknownOnHost(hostSourceFile: FileMayBePresentOnHost): hostSourceFile is FilePresenceUnknownOnHost { + function isFilePresenceUnknownOnHost( + hostSourceFile: FileMayBePresentOnHost, + ): hostSourceFile is FilePresenceUnknownOnHost { return typeof (hostSourceFile as FilePresenceUnknownOnHost).version === "boolean"; } @@ -715,7 +878,13 @@ export function createWatchProgram(host: WatchCompiler return directoryStructureHost.fileExists(fileName); } - function getVersionedSourceFileByPath(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { + function getVersionedSourceFileByPath( + fileName: string, + path: Path, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined { const hostSourceFile = sourceFilesCache.get(path); // No source file on the host if (isFileMissingOnHost(hostSourceFile)) { @@ -723,8 +892,12 @@ export function createWatchProgram(host: WatchCompiler } // Create new source file if requested or the versions dont match - const impliedNodeFormat = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.impliedNodeFormat : undefined; - if (hostSourceFile === undefined || shouldCreateNewSourceFile || isFilePresenceUnknownOnHost(hostSourceFile) || hostSourceFile.sourceFile.impliedNodeFormat !== impliedNodeFormat) { + const impliedNodeFormat = typeof languageVersionOrOptions === "object" + ? languageVersionOrOptions.impliedNodeFormat : undefined; + if ( + hostSourceFile === undefined || shouldCreateNewSourceFile || isFilePresenceUnknownOnHost(hostSourceFile) + || hostSourceFile.sourceFile.impliedNodeFormat !== impliedNodeFormat + ) { const sourceFile = getNewSourceFile(fileName, languageVersionOrOptions, onError); if (hostSourceFile) { if (sourceFile) { @@ -732,7 +905,14 @@ export function createWatchProgram(host: WatchCompiler (hostSourceFile as FilePresentOnHost).sourceFile = sourceFile; hostSourceFile.version = sourceFile.version; if (!hostSourceFile.fileWatcher) { - hostSourceFile.fileWatcher = watchFilePath(path, fileName, onSourceFileChange, PollingInterval.Low, watchOptions, WatchType.SourceFile); + hostSourceFile.fileWatcher = watchFilePath( + path, + fileName, + onSourceFileChange, + PollingInterval.Low, + watchOptions, + WatchType.SourceFile, + ); } } else { @@ -745,7 +925,14 @@ export function createWatchProgram(host: WatchCompiler } else { if (sourceFile) { - const fileWatcher = watchFilePath(path, fileName, onSourceFileChange, PollingInterval.Low, watchOptions, WatchType.SourceFile); + const fileWatcher = watchFilePath( + path, + fileName, + onSourceFileChange, + PollingInterval.Low, + watchOptions, + WatchType.SourceFile, + ); sourceFilesCache.set(path, { sourceFile, version: sourceFile.version, fileWatcher }); } else { @@ -779,7 +966,11 @@ export function createWatchProgram(host: WatchCompiler return text !== undefined ? getSourceFileVersionAsHashFromText(compilerHost, text) : undefined; } - function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions, hasSourceFileByPath: boolean) { + function onReleaseOldSourceFile( + oldSourceFile: SourceFile, + _oldOptions: CompilerOptions, + hasSourceFileByPath: boolean, + ) { const hostSourceFileInfo = sourceFilesCache.get(oldSourceFile.resolvedPath); // If this is the source file thats in the cache and new program doesnt need it, // remove the cached entry. @@ -788,7 +979,9 @@ export function createWatchProgram(host: WatchCompiler if (hostSourceFileInfo !== undefined) { // record the missing file paths so they can be removed later if watchers arent tracking them if (isFileMissingOnHost(hostSourceFileInfo)) { - (missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push(oldSourceFile.path); + (missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push( + oldSourceFile.path, + ); } else if ((hostSourceFileInfo as FilePresentOnHost).sourceFile === oldSourceFile) { if (hostSourceFileInfo.fileWatcher) { @@ -804,7 +997,11 @@ export function createWatchProgram(host: WatchCompiler function reportWatchDiagnostic(message: DiagnosticMessage) { if (host.onWatchStatusChange) { - host.onWatchStatusChange(createCompilerDiagnostic(message), newLine, compilerOptions || optionsToExtendForConfigFile); + host.onWatchStatusChange( + createCompilerDiagnostic(message), + newLine, + compilerOptions || optionsToExtendForConfigFile, + ); } } @@ -825,7 +1022,11 @@ export function createWatchProgram(host: WatchCompiler } const pending = clearInvalidateResolutionsOfFailedLookupLocations(); writeLog(`Scheduling invalidateFailedLookup${pending ? ", Cancelled earlier one" : ""}`); - timerToInvalidateFailedLookupResolutions = host.setTimeout(invalidateResolutionsOfFailedLookup, 250, "timerToInvalidateFailedLookupResolutions"); + timerToInvalidateFailedLookupResolutions = host.setTimeout( + invalidateResolutionsOfFailedLookup, + 250, + "timerToInvalidateFailedLookupResolutions", + ); } function invalidateResolutionsOfFailedLookup() { @@ -888,8 +1089,22 @@ export function createWatchProgram(host: WatchCompiler Debug.assert(configFileName); reloadLevel = ConfigFileProgramReloadLevel.None; - rootFileNames = getFileNamesFromConfigSpecs(compilerOptions.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), compilerOptions, parseConfigFileHost, extraFileExtensions); - if (updateErrorForNoInputFiles(rootFileNames, getNormalizedAbsolutePath(configFileName, currentDirectory), compilerOptions.configFile!.configFileSpecs!, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) { + rootFileNames = getFileNamesFromConfigSpecs( + compilerOptions.configFile!.configFileSpecs!, + getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), + compilerOptions, + parseConfigFileHost, + extraFileExtensions, + ); + if ( + updateErrorForNoInputFiles( + rootFileNames, + getNormalizedAbsolutePath(configFileName, currentDirectory), + compilerOptions.configFile!.configFileSpecs!, + configFileParsingDiagnostics!, + canConfigFileJsonReportNoInputFiles, + ) + ) { hasChangedConfigFileParsingErrors = true; } @@ -913,19 +1128,26 @@ export function createWatchProgram(host: WatchCompiler watchConfigFileWildCardDirectories(); // Update extended config file watch - updateExtendedConfigFilesWatches(toPath(configFileName), compilerOptions, watchOptions, WatchType.ExtendedConfigFile); + updateExtendedConfigFilesWatches( + toPath(configFileName), + compilerOptions, + watchOptions, + WatchType.ExtendedConfigFile, + ); } function parseConfigFile() { Debug.assert(configFileName); - setConfigFileParsingResult(getParsedCommandLineOfConfigFile( - configFileName, - optionsToExtendForConfigFile, - parseConfigFileHost, - extendedConfigCache ||= new Map(), - watchOptionsToExtend, - extraFileExtensions - )!); // TODO: GH#18217 + setConfigFileParsingResult( + getParsedCommandLineOfConfigFile( + configFileName, + optionsToExtendForConfigFile, + parseConfigFileHost, + extendedConfigCache ||= new Map(), + watchOptionsToExtend, + extraFileExtensions, + )!, + ); // TODO: GH#18217 } function setConfigFileParsingResult(configFileParseResult: ParsedCommandLine) { @@ -945,7 +1167,10 @@ export function createWatchProgram(host: WatchCompiler if (config) { if (!config.reloadLevel) return config.parsedCommandLine; // With host implementing getParsedCommandLine we cant just update file names - if (config.parsedCommandLine && config.reloadLevel === ConfigFileProgramReloadLevel.Partial && !host.getParsedCommandLine) { + if ( + config.parsedCommandLine && config.reloadLevel === ConfigFileProgramReloadLevel.Partial + && !host.getParsedCommandLine + ) { writeLog("Reloading new file names and options"); Debug.assert(compilerOptions); const fileNames = getFileNamesFromConfigSpecs( @@ -961,9 +1186,9 @@ export function createWatchProgram(host: WatchCompiler } writeLog(`Loading config file: ${configFileName}`); - const parsedCommandLine = host.getParsedCommandLine ? - host.getParsedCommandLine(configFileName) : - getParsedCommandLineFromConfigFileHost(configFileName); + const parsedCommandLine = host.getParsedCommandLine + ? host.getParsedCommandLine(configFileName) + : getParsedCommandLineFromConfigFileHost(configFileName); if (config) { config.parsedCommandLine = parsedCommandLine; config.reloadLevel = undefined; @@ -984,7 +1209,7 @@ export function createWatchProgram(host: WatchCompiler /*optionsToExtend*/ undefined, parseConfigFileHost, extendedConfigCache ||= new Map(), - watchOptionsToExtend + watchOptionsToExtend, ); parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = onUnRecoverableConfigFileDiagnostic; return parsedCommandLine; @@ -1007,9 +1232,15 @@ export function createWatchProgram(host: WatchCompiler callback: (fileName: string, eventKind: FileWatcherEventKind, filePath: Path) => void, pollingInterval: PollingInterval, options: WatchOptions | undefined, - watchType: WatchType + watchType: WatchType, ): FileWatcher { - return watchFile(file, (fileName, eventKind) => callback(fileName, eventKind, path), pollingInterval, options, watchType); + return watchFile( + file, + (fileName, eventKind) => callback(fileName, eventKind, path), + pollingInterval, + options, + watchType, + ); } function onSourceFileChange(fileName: string, eventKind: FileWatcherEventKind, path: Path) { @@ -1033,9 +1264,16 @@ export function createWatchProgram(host: WatchCompiler function watchMissingFilePath(missingFilePath: Path) { // If watching missing referenced config file, we are already watching it so no need for separate watcher - return parsedConfigs?.has(missingFilePath) ? - noopFileWatcher : - watchFilePath(missingFilePath, missingFilePath, onMissingFileChange, PollingInterval.Medium, watchOptions, WatchType.MissingFile); + return parsedConfigs?.has(missingFilePath) + ? noopFileWatcher + : watchFilePath( + missingFilePath, + missingFilePath, + onMissingFileChange, + PollingInterval.Medium, + watchOptions, + WatchType.MissingFile, + ); } function onMissingFileChange(fileName: string, eventKind: FileWatcherEventKind, missingFilePath: Path) { @@ -1058,7 +1296,7 @@ export function createWatchProgram(host: WatchCompiler updateWatchingWildcardDirectories( watchedWildcardDirectories || (watchedWildcardDirectories = new Map()), new Map(Object.entries(wildcardDirectories)), - watchWildcardDirectory + watchWildcardDirectory, ); } else if (watchedWildcardDirectories) { @@ -1081,19 +1319,21 @@ export function createWatchProgram(host: WatchCompiler } nextSourceFileVersion(fileOrDirectoryPath); - if (isIgnoredFileFromWildCardWatching({ - watchedDirPath: toPath(directory), - fileOrDirectory, - fileOrDirectoryPath, - configFileName, - extraFileExtensions, - options: compilerOptions, - program: getCurrentBuilderProgram() || rootFileNames, - currentDirectory, - useCaseSensitiveFileNames, - writeLog, - toPath, - })) return; + if ( + isIgnoredFileFromWildCardWatching({ + watchedDirPath: toPath(directory), + fileOrDirectory, + fileOrDirectoryPath, + configFileName, + extraFileExtensions, + options: compilerOptions, + program: getCurrentBuilderProgram() || rootFileNames, + currentDirectory, + useCaseSensitiveFileNames, + writeLog, + toPath, + }) + ) return; // Reload is pending, do the reload if (reloadLevel !== ConfigFileProgramReloadLevel.Full) { @@ -1105,43 +1345,55 @@ export function createWatchProgram(host: WatchCompiler }, flags, watchOptions, - WatchType.WildcardDirectory + WatchType.WildcardDirectory, ); } - function updateExtendedConfigFilesWatches(forProjectPath: Path, options: CompilerOptions | undefined, watchOptions: WatchOptions | undefined, watchType: WatchTypeRegistry["ExtendedConfigFile"] | WatchTypeRegistry["ExtendedConfigOfReferencedProject"]) { + function updateExtendedConfigFilesWatches( + forProjectPath: Path, + options: CompilerOptions | undefined, + watchOptions: WatchOptions | undefined, + watchType: WatchTypeRegistry["ExtendedConfigFile"] | WatchTypeRegistry["ExtendedConfigOfReferencedProject"], + ) { updateSharedExtendedConfigFileWatcher( forProjectPath, options, sharedExtendedConfigFileWatchers ||= new Map(), - (extendedConfigFileName, extendedConfigFilePath) => watchFile( - extendedConfigFileName, - (_fileName, eventKind) => { - updateCachedSystemWithFile(extendedConfigFileName, extendedConfigFilePath, eventKind); - // Update extended config cache - if (extendedConfigCache) cleanExtendedConfigCache(extendedConfigCache, extendedConfigFilePath, toPath); - // Update projects - const projects = sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects; - // If there are no referenced projects this extended config file watcher depend on ignore - if (!projects?.size) return; - projects.forEach(projectPath => { - if (configFileName && toPath(configFileName) === projectPath) { - // If this is the config file of the project, reload completely - reloadLevel = ConfigFileProgramReloadLevel.Full; + (extendedConfigFileName, extendedConfigFilePath) => + watchFile( + extendedConfigFileName, + (_fileName, eventKind) => { + updateCachedSystemWithFile(extendedConfigFileName, extendedConfigFilePath, eventKind); + // Update extended config cache + if (extendedConfigCache) { + cleanExtendedConfigCache( + extendedConfigCache, + extendedConfigFilePath, + toPath, + ); } - else { - // Reload config for the referenced projects and remove the resolutions from referenced projects since the config file changed - const config = parsedConfigs?.get(projectPath); - if (config) config.reloadLevel = ConfigFileProgramReloadLevel.Full; - resolutionCache.removeResolutionsFromProjectReferenceRedirects(projectPath); - } - scheduleProgramUpdate(); - }); - }, - PollingInterval.High, - watchOptions, - watchType - ), + // Update projects + const projects = sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects; + // If there are no referenced projects this extended config file watcher depend on ignore + if (!projects?.size) return; + projects.forEach(projectPath => { + if (configFileName && toPath(configFileName) === projectPath) { + // If this is the config file of the project, reload completely + reloadLevel = ConfigFileProgramReloadLevel.Full; + } + else { + // Reload config for the referenced projects and remove the resolutions from referenced projects since the config file changed + const config = parsedConfigs?.get(projectPath); + if (config) config.reloadLevel = ConfigFileProgramReloadLevel.Full; + resolutionCache.removeResolutionsFromProjectReferenceRedirects(projectPath); + } + scheduleProgramUpdate(); + }); + }, + PollingInterval.High, + watchOptions, + watchType, + ), toPath, ); } @@ -1159,50 +1411,56 @@ export function createWatchProgram(host: WatchCompiler }, PollingInterval.High, commandLine.parsedCommandLine?.watchOptions || watchOptions, - WatchType.ConfigFileOfReferencedProject + WatchType.ConfigFileOfReferencedProject, ); // Watch Wild card if (commandLine.parsedCommandLine?.wildcardDirectories) { updateWatchingWildcardDirectories( commandLine.watchedDirectories ||= new Map(), new Map(Object.entries(commandLine.parsedCommandLine?.wildcardDirectories)), - (directory, flags) => watchDirectory( - directory, - fileOrDirectory => { - const fileOrDirectoryPath = toPath(fileOrDirectory); - // Since the file existence changed, update the sourceFiles cache - if (cachedDirectoryStructureHost) { - cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); - } - nextSourceFileVersion(fileOrDirectoryPath); - - const config = parsedConfigs?.get(configPath); - if (!config?.parsedCommandLine) return; - if (isIgnoredFileFromWildCardWatching({ - watchedDirPath: toPath(directory), - fileOrDirectory, - fileOrDirectoryPath, - configFileName, - options: config.parsedCommandLine.options, - program: config.parsedCommandLine.fileNames, - currentDirectory, - useCaseSensitiveFileNames, - writeLog, - toPath, - })) return; - - // Reload is pending, do the reload - if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) { - config.reloadLevel = ConfigFileProgramReloadLevel.Partial; - - // Schedule Update the program - scheduleProgramUpdate(); - } - }, - flags, - commandLine.parsedCommandLine?.watchOptions || watchOptions, - WatchType.WildcardDirectoryOfReferencedProject - ) + (directory, flags) => + watchDirectory( + directory, + fileOrDirectory => { + const fileOrDirectoryPath = toPath(fileOrDirectory); + // Since the file existence changed, update the sourceFiles cache + if (cachedDirectoryStructureHost) { + cachedDirectoryStructureHost.addOrDeleteFileOrDirectory( + fileOrDirectory, + fileOrDirectoryPath, + ); + } + nextSourceFileVersion(fileOrDirectoryPath); + + const config = parsedConfigs?.get(configPath); + if (!config?.parsedCommandLine) return; + if ( + isIgnoredFileFromWildCardWatching({ + watchedDirPath: toPath(directory), + fileOrDirectory, + fileOrDirectoryPath, + configFileName, + options: config.parsedCommandLine.options, + program: config.parsedCommandLine.fileNames, + currentDirectory, + useCaseSensitiveFileNames, + writeLog, + toPath, + }) + ) return; + + // Reload is pending, do the reload + if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) { + config.reloadLevel = ConfigFileProgramReloadLevel.Partial; + + // Schedule Update the program + scheduleProgramUpdate(); + } + }, + flags, + commandLine.parsedCommandLine?.watchOptions || watchOptions, + WatchType.WildcardDirectoryOfReferencedProject, + ), ); } else if (commandLine.watchedDirectories) { @@ -1214,7 +1472,7 @@ export function createWatchProgram(host: WatchCompiler configPath, commandLine.parsedCommandLine?.options, commandLine.parsedCommandLine?.watchOptions || watchOptions, - WatchType.ExtendedConfigOfReferencedProject + WatchType.ExtendedConfigOfReferencedProject, ); } } diff --git a/src/compiler/watchUtilities.ts b/src/compiler/watchUtilities.ts index 1c7eb04b1193f..30b291379db84 100644 --- a/src/compiler/watchUtilities.ts +++ b/src/compiler/watchUtilities.ts @@ -67,7 +67,13 @@ export interface DirectoryStructureHost { // TODO: GH#18217 Optional methods are frequently used as non-optional directoryExists?(path: string): boolean; getDirectories?(path: string): string[]; - readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory?( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; realpath?(path: string): string; createDirectory?(path: string): void; @@ -85,38 +91,53 @@ export interface CachedDirectoryStructureHost extends DirectoryStructureHost { useCaseSensitiveFileNames: boolean; getDirectories(path: string): string[]; - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; /** Returns the queried result for the file exists and directory exists if at all it was done */ - addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path): FileAndDirectoryExistence | undefined; + addOrDeleteFileOrDirectory( + fileOrDirectory: string, + fileOrDirectoryPath: Path, + ): FileAndDirectoryExistence | undefined; addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind): void; clearCache(): void; } -type Canonicalized = string & { __canonicalized: void }; +type Canonicalized = string & { __canonicalized: void; }; interface MutableFileSystemEntries { readonly files: string[]; readonly directories: string[]; - sortedAndCanonicalizedFiles?: SortedArray - sortedAndCanonicalizedDirectories?: SortedArray + sortedAndCanonicalizedFiles?: SortedArray; + sortedAndCanonicalizedDirectories?: SortedArray; } interface SortedAndCanonicalizedMutableFileSystemEntries { readonly files: string[]; readonly directories: string[]; - readonly sortedAndCanonicalizedFiles: SortedArray - readonly sortedAndCanonicalizedDirectories: SortedArray + readonly sortedAndCanonicalizedFiles: SortedArray; + readonly sortedAndCanonicalizedDirectories: SortedArray; } /** @internal */ -export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, currentDirectory: string, useCaseSensitiveFileNames: boolean): CachedDirectoryStructureHost | undefined { +export function createCachedDirectoryStructureHost( + host: DirectoryStructureHost, + currentDirectory: string, + useCaseSensitiveFileNames: boolean, +): CachedDirectoryStructureHost | undefined { if (!host.getDirectories || !host.readDirectory) { return undefined; } const cachedReadDirectoryResult = new Map(); - const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames) as ((name: string) => Canonicalized); + const getCanonicalFileName = createGetCanonicalFileName( + useCaseSensitiveFileNames, + ) as ((name: string) => Canonicalized); return { useCaseSensitiveFileNames, fileExists, @@ -129,7 +150,7 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, addOrDeleteFileOrDirectory, addOrDeleteFile, clearCache, - realpath: host.realpath && realpath + realpath: host.realpath && realpath, }; function toPath(fileName: string) { @@ -148,8 +169,11 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, // If we're looking for the base directory, we're definitely going to search the entries if (!entries.sortedAndCanonicalizedFiles) { - entries.sortedAndCanonicalizedFiles = entries.files.map(getCanonicalFileName).sort() as SortedArray; - entries.sortedAndCanonicalizedDirectories = entries.directories.map(getCanonicalFileName).sort() as SortedArray; + entries.sortedAndCanonicalizedFiles = entries.files.map(getCanonicalFileName).sort() as SortedArray< + Canonicalized + >; + entries.sortedAndCanonicalizedDirectories = entries.directories.map(getCanonicalFileName) + .sort() as SortedArray; } return entries as SortedAndCanonicalizedMutableFileSystemEntries; } @@ -161,8 +185,13 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, function createCachedFileSystemEntries(rootDir: string, rootDirPath: Path) { if (!host.realpath || ensureTrailingDirectorySeparator(toPath(host.realpath(rootDir))) === rootDirPath) { const resultFromHost: MutableFileSystemEntries = { - files: map(host.readDirectory!(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/["*.*"]), getBaseNameOfFileName) || [], - directories: host.getDirectories!(rootDir) || [] + files: map( + host.readDirectory!(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/ [ + "*.*", + ]), + getBaseNameOfFileName, + ) || [], + directories: host.getDirectories!(rootDir) || [], }; cachedReadDirectoryResult.set(ensureTrailingDirectorySeparator(rootDirPath), resultFromHost); @@ -219,8 +248,9 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, function fileExists(fileName: string): boolean { const path = toPath(fileName); const result = getCachedFileSystemEntriesForBaseDir(path); - return result && hasEntry(result.sortedAndCanonicalizedFiles, getCanonicalFileName(getBaseNameOfFileName(fileName))) || - host.fileExists(fileName); + return result + && hasEntry(result.sortedAndCanonicalizedFiles, getCanonicalFileName(getBaseNameOfFileName(fileName))) + || host.fileExists(fileName); } function directoryExists(dirPath: string): boolean { @@ -252,12 +282,28 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, return host.getDirectories!(rootDir); } - function readDirectory(rootDir: string, extensions?: readonly string[], excludes?: readonly string[], includes?: readonly string[], depth?: number): string[] { + function readDirectory( + rootDir: string, + extensions?: readonly string[], + excludes?: readonly string[], + includes?: readonly string[], + depth?: number, + ): string[] { const rootDirPath = toPath(rootDir); const rootResult = tryReadDirectory(rootDir, rootDirPath); let rootSymLinkResult: FileSystemEntries | undefined; if (rootResult !== undefined) { - return matchFiles(rootDir, extensions, excludes, includes, useCaseSensitiveFileNames, currentDirectory, depth, getFileSystemEntries, realpath); + return matchFiles( + rootDir, + extensions, + excludes, + includes, + useCaseSensitiveFileNames, + currentDirectory, + depth, + getFileSystemEntries, + realpath, + ); } return host.readDirectory!(rootDir, extensions, excludes, includes, depth); @@ -267,16 +313,19 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, return rootResult || getFileSystemEntriesFromHost(dir, path); } const result = tryReadDirectory(dir, path); - return result !== undefined ? - result || getFileSystemEntriesFromHost(dir, path) : - emptyFileSystemEntries; + return result !== undefined + ? result || getFileSystemEntriesFromHost(dir, path) + : emptyFileSystemEntries; } function getFileSystemEntriesFromHost(dir: string, path: Path): FileSystemEntries { if (rootSymLinkResult && path === rootDirPath) return rootSymLinkResult; const result: FileSystemEntries = { - files: map(host.readDirectory!(dir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/["*.*"]), getBaseNameOfFileName) || emptyArray, - directories: host.getDirectories!(dir) || emptyArray + files: map( + host.readDirectory!(dir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/ ["*.*"]), + getBaseNameOfFileName, + ) || emptyArray, + directories: host.getDirectories!(dir) || emptyArray, }; if (path === rootDirPath) rootSymLinkResult = result; return result; @@ -313,9 +362,12 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, const baseName = getBaseNameOfFileName(fileOrDirectory); const fsQueryResult: FileAndDirectoryExistence = { fileExists: host.fileExists(fileOrDirectoryPath), - directoryExists: host.directoryExists(fileOrDirectoryPath) + directoryExists: host.directoryExists(fileOrDirectoryPath), }; - if (fsQueryResult.directoryExists || hasEntry(parentResult.sortedAndCanonicalizedDirectories, getCanonicalFileName(baseName))) { + if ( + fsQueryResult.directoryExists + || hasEntry(parentResult.sortedAndCanonicalizedDirectories, getCanonicalFileName(baseName)) + ) { // Folder added or removed, clear the cache instead of updating the folder and its structure clearCache(); } @@ -324,7 +376,6 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, updateFilesOfFileSystemEntry(parentResult, baseName, fsQueryResult.fileExists); } return fsQueryResult; - } function addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind) { @@ -334,11 +385,19 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, const parentResult = getCachedFileSystemEntriesForBaseDir(filePath); if (parentResult) { - updateFilesOfFileSystemEntry(parentResult, getBaseNameOfFileName(fileName), eventKind === FileWatcherEventKind.Created); + updateFilesOfFileSystemEntry( + parentResult, + getBaseNameOfFileName(fileName), + eventKind === FileWatcherEventKind.Created, + ); } } - function updateFilesOfFileSystemEntry(parentResult: SortedAndCanonicalizedMutableFileSystemEntries, baseName: string, fileExists: boolean): void { + function updateFilesOfFileSystemEntry( + parentResult: SortedAndCanonicalizedMutableFileSystemEntries, + baseName: string, + fileExists: boolean, + ): void { const canonicalizedFiles = parentResult.sortedAndCanonicalizedFiles; const canonicalizedBaseName = getCanonicalFileName(baseName); if (fileExists) { @@ -349,10 +408,17 @@ export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, } else { // Case-sensitive comparison since already canonicalized - const sortedIndex = binarySearch(canonicalizedFiles, canonicalizedBaseName, identity, compareStringsCaseSensitive); + const sortedIndex = binarySearch( + canonicalizedFiles, + canonicalizedBaseName, + identity, + compareStringsCaseSensitive, + ); if (sortedIndex >= 0) { canonicalizedFiles.splice(sortedIndex, 1); - const unsortedIndex = parentResult.files.findIndex(entry => getCanonicalFileName(entry) === canonicalizedBaseName); + const unsortedIndex = parentResult.files.findIndex(entry => + getCanonicalFileName(entry) === canonicalizedBaseName + ); parentResult.files.splice(unsortedIndex, 1); } } @@ -369,7 +435,7 @@ export enum ConfigFileProgramReloadLevel { /** Update the file name list from the disk */ Partial, /** Reload completely by re-reading contents of config file from disk and updating program */ - Full + Full, } /** @internal */ @@ -468,8 +534,8 @@ export function updatePackageJsonWatch( newMap, { createNewValue: createPackageJsonWatch, - onDeleteValue: closeFileWatcher - } + onDeleteValue: closeFileWatcher, + }, ); } @@ -495,8 +561,8 @@ export function updateMissingFilePathsWatch( createNewValue: createMissingFileWatch, // Files that are no longer missing (e.g. because they are no longer required) // should no longer be watched. - onDeleteValue: closeFileWatcher - } + onDeleteValue: closeFileWatcher, + }, ); } @@ -517,7 +583,7 @@ export interface WildcardDirectoryWatcher { export function updateWatchingWildcardDirectories( existingWatchedForWildcards: Map, wildcardDirectories: Map, - watchDirectory: (directory: string, flags: WatchDirectoryFlags) => FileWatcher + watchDirectory: (directory: string, flags: WatchDirectoryFlags) => FileWatcher, ) { mutateMap( existingWatchedForWildcards, @@ -528,19 +594,23 @@ export function updateWatchingWildcardDirectories( // Close existing watch thats not needed any more onDeleteValue: closeFileWatcherOf, // Close existing watch that doesnt match in the flags - onExistingValue: updateWildcardDirectoryWatcher - } + onExistingValue: updateWildcardDirectoryWatcher, + }, ); function createWildcardDirectoryWatcher(directory: string, flags: WatchDirectoryFlags): WildcardDirectoryWatcher { // Create new watch and recursive info return { watcher: watchDirectory(directory, flags), - flags + flags, }; } - function updateWildcardDirectoryWatcher(existingWatcher: WildcardDirectoryWatcher, flags: WatchDirectoryFlags, directory: string) { + function updateWildcardDirectoryWatcher( + existingWatcher: WildcardDirectoryWatcher, + flags: WatchDirectoryFlags, + directory: string, + ) { // Watcher needs to be updated if the recursive flags dont match if (existingWatcher.flags === flags) { return; @@ -567,10 +637,17 @@ export interface IsIgnoredFileFromWildCardWatchingInput { } /** @internal */ export function isIgnoredFileFromWildCardWatching({ - watchedDirPath, fileOrDirectory, fileOrDirectoryPath, - configFileName, options, program, extraFileExtensions, - currentDirectory, useCaseSensitiveFileNames, - writeLog, toPath, + watchedDirPath, + fileOrDirectory, + fileOrDirectoryPath, + configFileName, + options, + program, + extraFileExtensions, + currentDirectory, + useCaseSensitiveFileNames, + writeLog, + toPath, }: IsIgnoredFileFromWildCardWatchingInput): boolean { const newPath = removeIgnoredPath(fileOrDirectoryPath); if (!newPath) { @@ -583,12 +660,22 @@ export function isIgnoredFileFromWildCardWatching({ // If the the added or created file or directory is not supported file name, ignore the file // But when watched directory is added/removed, we need to reload the file list - if (hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, options, extraFileExtensions)) { + if ( + hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, options, extraFileExtensions) + ) { writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrDirectory}`); return true; } - if (isExcludedFile(fileOrDirectory, options.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), useCaseSensitiveFileNames, currentDirectory)) { + if ( + isExcludedFile( + fileOrDirectory, + options.configFile!.configFileSpecs!, + getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), + useCaseSensitiveFileNames, + currentDirectory, + ) + ) { writeLog(`Project: ${configFileName} Detected excluded file: ${fileOrDirectory}`); return true; } @@ -610,21 +697,24 @@ export function isIgnoredFileFromWildCardWatching({ // just check if sourceFile with the name exists const filePathWithoutExtension = removeFileExtension(fileOrDirectoryPath); - const realProgram = isArray(program) ? undefined : isBuilderProgram(program) ? program.getProgramOrUndefined() : program; + const realProgram = isArray(program) ? undefined + : isBuilderProgram(program) ? program.getProgramOrUndefined() : program; const builderProgram = !realProgram && !isArray(program) ? program as BuilderProgram : undefined; - if (hasSourceFile((filePathWithoutExtension + Extension.Ts) as Path) || - hasSourceFile((filePathWithoutExtension + Extension.Tsx) as Path)) { + if ( + hasSourceFile((filePathWithoutExtension + Extension.Ts) as Path) + || hasSourceFile((filePathWithoutExtension + Extension.Tsx) as Path) + ) { writeLog(`Project: ${configFileName} Detected output file: ${fileOrDirectory}`); return true; } return false; function hasSourceFile(file: Path): boolean { - return realProgram ? - !!realProgram.getSourceFileByPath(file) : - builderProgram ? - builderProgram.getState().fileInfos.has(file) : - !!find(program as readonly string[], rootFile => toPath(rootFile) === file); + return realProgram + ? !!realProgram.getSourceFileByPath(file) + : builderProgram + ? builderProgram.getState().fileInfos.has(file) + : !!find(program as readonly string[], rootFile => toPath(rootFile) === file); } } @@ -645,51 +735,82 @@ export function isEmittedFileOfProgram(program: Program | undefined, file: strin export enum WatchLogLevel { None, TriggerOnly, - Verbose + Verbose, } /** @internal */ export interface WatchFactoryHost { - watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number, options?: WatchOptions): FileWatcher; - watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean, options?: WatchOptions): FileWatcher; + watchFile( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; + watchDirectory( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; getCurrentDirectory?(): string; useCaseSensitiveFileNames: boolean | (() => boolean); } /** @internal */ export interface WatchFactory { - watchFile: (file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined, detailInfo1: X, detailInfo2?: Y) => FileWatcher; - watchDirectory: (directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags, options: WatchOptions | undefined, detailInfo1: X, detailInfo2?: Y) => FileWatcher; + watchFile: ( + file: string, + callback: FileWatcherCallback, + pollingInterval: PollingInterval, + options: WatchOptions | undefined, + detailInfo1: X, + detailInfo2?: Y, + ) => FileWatcher; + watchDirectory: ( + directory: string, + callback: DirectoryWatcherCallback, + flags: WatchDirectoryFlags, + options: WatchOptions | undefined, + detailInfo1: X, + detailInfo2?: Y, + ) => FileWatcher; } /** @internal */ export type GetDetailWatchInfo = (detailInfo1: X, detailInfo2: Y | undefined) => string; /** @internal */ -export function getWatchFactory(host: WatchFactoryHost, watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo): WatchFactory { +export function getWatchFactory( + host: WatchFactoryHost, + watchLogLevel: WatchLogLevel, + log: (s: string) => void, + getDetailWatchInfo?: GetDetailWatchInfo, +): WatchFactory { setSysLog(watchLogLevel === WatchLogLevel.Verbose ? log : noop); const plainInvokeFactory: WatchFactory = { - watchFile: (file, callback, pollingInterval, options) => host.watchFile(file, callback, pollingInterval, options), - watchDirectory: (directory, callback, flags, options) => host.watchDirectory(directory, callback, (flags & WatchDirectoryFlags.Recursive) !== 0, options), + watchFile: (file, callback, pollingInterval, options) => + host.watchFile(file, callback, pollingInterval, options), + watchDirectory: (directory, callback, flags, options) => + host.watchDirectory(directory, callback, (flags & WatchDirectoryFlags.Recursive) !== 0, options), }; - const triggerInvokingFactory: WatchFactory | undefined = watchLogLevel !== WatchLogLevel.None ? - { + const triggerInvokingFactory: WatchFactory | undefined = watchLogLevel !== WatchLogLevel.None + ? { watchFile: createTriggerLoggingAddWatch("watchFile"), - watchDirectory: createTriggerLoggingAddWatch("watchDirectory") - } : - undefined; - const factory = watchLogLevel === WatchLogLevel.Verbose ? - { + watchDirectory: createTriggerLoggingAddWatch("watchDirectory"), + } + : undefined; + const factory = watchLogLevel === WatchLogLevel.Verbose + ? { watchFile: createFileWatcherWithLogging, - watchDirectory: createDirectoryWatcherWithLogging - } : - triggerInvokingFactory || plainInvokeFactory; - const excludeWatcherFactory = watchLogLevel === WatchLogLevel.Verbose ? - createExcludeWatcherWithLogging : - returnNoopFileWatcher; + watchDirectory: createDirectoryWatcherWithLogging, + } + : triggerInvokingFactory || plainInvokeFactory; + const excludeWatcherFactory = watchLogLevel === WatchLogLevel.Verbose + ? createExcludeWatcherWithLogging + : returnNoopFileWatcher; return { watchFile: createExcludeHandlingAddWatch("watchFile"), - watchDirectory: createExcludeHandlingAddWatch("watchDirectory") + watchDirectory: createExcludeHandlingAddWatch("watchDirectory"), }; function createExcludeHandlingAddWatch>(key: T): WatchFactory[T] { @@ -699,16 +820,21 @@ export function getWatchFactory(host: WatchFactoryHost, watchL flags: PollingInterval | WatchDirectoryFlags, options: WatchOptions | undefined, detailInfo1: X, - detailInfo2?: Y - ) => !matchesExclude(file, key === "watchFile" ? options?.excludeFiles : options?.excludeDirectories, useCaseSensitiveFileNames(), host.getCurrentDirectory?.() || "") ? - factory[key].call(/*thisArgs*/ undefined, file, cb, flags, options, detailInfo1, detailInfo2) : - excludeWatcherFactory(file, flags, options, detailInfo1, detailInfo2); + detailInfo2?: Y, + ) => !matchesExclude( + file, + key === "watchFile" ? options?.excludeFiles : options?.excludeDirectories, + useCaseSensitiveFileNames(), + host.getCurrentDirectory?.() || "", + ) + ? factory[key].call(/*thisArgs*/ undefined, file, cb, flags, options, detailInfo1, detailInfo2) + : excludeWatcherFactory(file, flags, options, detailInfo1, detailInfo2); } function useCaseSensitiveFileNames() { - return typeof host.useCaseSensitiveFileNames === "boolean" ? - host.useCaseSensitiveFileNames : - host.useCaseSensitiveFileNames(); + return typeof host.useCaseSensitiveFileNames === "boolean" + ? host.useCaseSensitiveFileNames + : host.useCaseSensitiveFileNames(); } function createExcludeWatcherWithLogging( @@ -716,11 +842,16 @@ export function getWatchFactory(host: WatchFactoryHost, watchL flags: PollingInterval | WatchDirectoryFlags, options: WatchOptions | undefined, detailInfo1: X, - detailInfo2?: Y + detailInfo2?: Y, ) { - log(`ExcludeWatcher:: Added:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`); + log(`ExcludeWatcher:: Added:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`); return { - close: () => log(`ExcludeWatcher:: Close:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`) + close: () => + log(`ExcludeWatcher:: Close:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`), }; } @@ -730,15 +861,19 @@ export function getWatchFactory(host: WatchFactoryHost, watchL flags: PollingInterval, options: WatchOptions | undefined, detailInfo1: X, - detailInfo2?: Y + detailInfo2?: Y, ): FileWatcher { - log(`FileWatcher:: Added:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`); + log(`FileWatcher:: Added:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`); const watcher = triggerInvokingFactory!.watchFile(file, cb, flags, options, detailInfo1, detailInfo2); return { close: () => { - log(`FileWatcher:: Close:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`); + log(`FileWatcher:: Close:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`); watcher.close(); - } + }, }; } @@ -748,9 +883,11 @@ export function getWatchFactory(host: WatchFactoryHost, watchL flags: WatchDirectoryFlags, options: WatchOptions | undefined, detailInfo1: X, - detailInfo2?: Y + detailInfo2?: Y, ): FileWatcher { - const watchInfo = `DirectoryWatcher:: Added:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`; + const watchInfo = `DirectoryWatcher:: Added:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`; log(watchInfo); const start = timestamp(); const watcher = triggerInvokingFactory!.watchDirectory(file, cb, flags, options, detailInfo1, detailInfo2); @@ -758,13 +895,15 @@ export function getWatchFactory(host: WatchFactoryHost, watchL log(`Elapsed:: ${elapsed}ms ${watchInfo}`); return { close: () => { - const watchInfo = `DirectoryWatcher:: Close:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`; + const watchInfo = `DirectoryWatcher:: Close:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`; log(watchInfo); const start = timestamp(); watcher.close(); const elapsed = timestamp() - start; log(`Elapsed:: ${elapsed}ms ${watchInfo}`); - } + }, }; } @@ -775,19 +914,41 @@ export function getWatchFactory(host: WatchFactoryHost, watchL flags: PollingInterval | WatchDirectoryFlags, options: WatchOptions | undefined, detailInfo1: X, - detailInfo2?: Y - ) => plainInvokeFactory[key].call(/*thisArgs*/ undefined, file, (...args: any[]) => { - const triggerredInfo = `${key === "watchFile" ? "FileWatcher" : "DirectoryWatcher"}:: Triggered with ${args[0]} ${args[1] !== undefined ? args[1] : ""}:: ${getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo)}`; - log(triggerredInfo); - const start = timestamp(); - cb.call(/*thisArg*/ undefined, ...args); - const elapsed = timestamp() - start; - log(`Elapsed:: ${elapsed}ms ${triggerredInfo}`); - }, flags, options, detailInfo1, detailInfo2); + detailInfo2?: Y, + ) => plainInvokeFactory[key].call( + /*thisArgs*/ undefined, + file, + (...args: any[]) => { + const triggerredInfo = `${key === "watchFile" ? "FileWatcher" : "DirectoryWatcher"}:: Triggered with ${ + args[0] + } ${args[1] !== undefined ? args[1] : ""}:: ${ + getWatchInfo(file, flags, options, detailInfo1, detailInfo2, getDetailWatchInfo) + }`; + log(triggerredInfo); + const start = timestamp(); + cb.call(/*thisArg*/ undefined, ...args); + const elapsed = timestamp() - start; + log(`Elapsed:: ${elapsed}ms ${triggerredInfo}`); + }, + flags, + options, + detailInfo1, + detailInfo2, + ); } - function getWatchInfo(file: string, flags: T, options: WatchOptions | undefined, detailInfo1: X, detailInfo2: Y | undefined, getDetailWatchInfo: GetDetailWatchInfo | undefined) { - return `WatchInfo: ${file} ${flags} ${JSON.stringify(options)} ${getDetailWatchInfo ? getDetailWatchInfo(detailInfo1, detailInfo2) : detailInfo2 === undefined ? detailInfo1 : `${detailInfo1} ${detailInfo2}`}`; + function getWatchInfo( + file: string, + flags: T, + options: WatchOptions | undefined, + detailInfo1: X, + detailInfo2: Y | undefined, + getDetailWatchInfo: GetDetailWatchInfo | undefined, + ) { + return `WatchInfo: ${file} ${flags} ${JSON.stringify(options)} ${ + getDetailWatchInfo ? getDetailWatchInfo(detailInfo1, detailInfo2) + : detailInfo2 === undefined ? detailInfo1 : `${detailInfo1} ${detailInfo2}` + }`; } } @@ -795,9 +956,9 @@ export function getWatchFactory(host: WatchFactoryHost, watchL export function getFallbackOptions(options: WatchOptions | undefined): WatchOptions { const fallbackPolling = options?.fallbackPolling; return { - watchFile: fallbackPolling !== undefined ? - fallbackPolling as unknown as WatchFileKind : - WatchFileKind.PriorityPollingInterval + watchFile: fallbackPolling !== undefined + ? fallbackPolling as unknown as WatchFileKind + : WatchFileKind.PriorityPollingInterval, }; } diff --git a/src/deprecatedCompat/5.0/identifierProperties.ts b/src/deprecatedCompat/5.0/identifierProperties.ts index fbbfc5ee55d15..2815b22775df3 100644 --- a/src/deprecatedCompat/5.0/identifierProperties.ts +++ b/src/deprecatedCompat/5.0/identifierProperties.ts @@ -5,7 +5,9 @@ import { identifierToKeywordKind, NodeFlags, } from "../_namespaces/ts"; -import { deprecate } from "../deprecate"; +import { + deprecate, +} from "../deprecate"; declare module "../../compiler/types" { export interface Identifier { @@ -29,8 +31,8 @@ addObjectAllocatorPatcher(objectAllocator => { since: "5.0", warnAfter: "5.1", errorAfter: "5.2", - message: "Use 'identifierToKeywordKind(identifier)' instead." - }) + message: "Use 'identifierToKeywordKind(identifier)' instead.", + }), }); } @@ -44,8 +46,8 @@ addObjectAllocatorPatcher(objectAllocator => { since: "5.0", warnAfter: "5.1", errorAfter: "5.2", - message: "Use '.parent' or the surrounding context to determine this instead." - }) + message: "Use '.parent' or the surrounding context to determine this instead.", + }), }); } }); diff --git a/src/deprecatedCompat/deprecate.ts b/src/deprecatedCompat/deprecate.ts index cc6b2f31c31ed..19247e8e31ca0 100644 --- a/src/deprecatedCompat/deprecate.ts +++ b/src/deprecatedCompat/deprecate.ts @@ -19,23 +19,40 @@ function getTypeScriptVersion() { return typeScriptVersion ?? (typeScriptVersion = new Version(version)); } -function formatDeprecationMessage(name: string, error: boolean | undefined, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { +function formatDeprecationMessage( + name: string, + error: boolean | undefined, + errorAfter: Version | undefined, + since: Version | undefined, + message: string | undefined, +) { let deprecationMessage = error ? "DeprecationError: " : "DeprecationWarning: "; deprecationMessage += `'${name}' `; deprecationMessage += since ? `has been deprecated since v${since}` : "is deprecated"; - deprecationMessage += error ? " and can no longer be used." : errorAfter ? ` and will no longer be usable after v${errorAfter}.` : "."; + deprecationMessage += error ? " and can no longer be used." + : errorAfter ? ` and will no longer be usable after v${errorAfter}.` : "."; deprecationMessage += message ? ` ${formatStringFromArgs(message, [name])}` : ""; return deprecationMessage; } -function createErrorDeprecation(name: string, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { +function createErrorDeprecation( + name: string, + errorAfter: Version | undefined, + since: Version | undefined, + message: string | undefined, +) { const deprecationMessage = formatDeprecationMessage(name, /*error*/ true, errorAfter, since, message); return () => { throw new TypeError(deprecationMessage); }; } -function createWarningDeprecation(name: string, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) { +function createWarningDeprecation( + name: string, + errorAfter: Version | undefined, + since: Version | undefined, + message: string | undefined, +) { let hasWrittenDeprecation = false; return () => { if (enableDeprecationWarnings && !hasWrittenDeprecation) { @@ -45,18 +62,19 @@ function createWarningDeprecation(name: string, errorAfter: Version | undefined, }; } -export function createDeprecation(name: string, options: DeprecationOptions & { error: true }): () => never; +export function createDeprecation(name: string, options: DeprecationOptions & { error: true; }): () => never; export function createDeprecation(name: string, options?: DeprecationOptions): () => void; export function createDeprecation(name: string, options: DeprecationOptions = {}) { - const version = typeof options.typeScriptVersion === "string" ? new Version(options.typeScriptVersion) : options.typeScriptVersion ?? getTypeScriptVersion(); + const version = typeof options.typeScriptVersion === "string" ? new Version(options.typeScriptVersion) + : options.typeScriptVersion ?? getTypeScriptVersion(); const errorAfter = typeof options.errorAfter === "string" ? new Version(options.errorAfter) : options.errorAfter; const warnAfter = typeof options.warnAfter === "string" ? new Version(options.warnAfter) : options.warnAfter; const since = typeof options.since === "string" ? new Version(options.since) : options.since ?? warnAfter; const error = options.error || errorAfter && version.compareTo(errorAfter) >= 0; const warn = !warnAfter || version.compareTo(warnAfter) >= 0; - return error ? createErrorDeprecation(name, errorAfter, since, options.message) : - warn ? createWarningDeprecation(name, errorAfter, since, options.message) : - noop; + return error ? createErrorDeprecation(name, errorAfter, since, options.message) + : warn ? createWarningDeprecation(name, errorAfter, since, options.message) + : noop; } function wrapFunction any>(deprecation: () => void, func: F): F { diff --git a/src/deprecatedCompat/deprecations.ts b/src/deprecatedCompat/deprecations.ts index 8682631b07830..5fae14cb7af1c 100644 --- a/src/deprecatedCompat/deprecations.ts +++ b/src/deprecatedCompat/deprecations.ts @@ -3,7 +3,9 @@ import { UnionToIntersection, Version, } from "./_namespaces/ts"; -import { deprecate } from "./deprecate"; +import { + deprecate, +} from "./deprecate"; /** @internal */ export interface DeprecationOptions { @@ -16,7 +18,6 @@ export interface DeprecationOptions { name?: string; } - // The following are deprecations for the public API. Deprecated exports are removed from the compiler itself // and compatible implementations are added here, along with an appropriate deprecation warning using // the `@deprecated` JSDoc tag as well as the `deprecate` API. @@ -51,7 +52,9 @@ export type OverloadKeys = Extract = Parameters<{ [P in OverloadKeys]: T[P]; }[OverloadKeys]>; +export type OverloadParameters = Parameters< + { [P in OverloadKeys]: T[P]; }[OverloadKeys] +>; // NOTE: the following doesn't work in TS 4.4 (the current LKG in main), so we have to use UnionToIntersection for now // type OverloadFunction any)[] = [], O = unknown> = @@ -69,7 +72,9 @@ export type OverloadFunction = UnionToIntersectio * * @internal */ -export type OverloadBinders = { [P in OverloadKeys]: (args: OverloadParameters) => boolean | undefined; }; +export type OverloadBinders = { + [P in OverloadKeys]: (args: OverloadParameters) => boolean | undefined; +}; /** * Defines deprecations for specific overloads by ordinal. @@ -79,7 +84,12 @@ export type OverloadBinders = { [P in OverloadKey export type OverloadDeprecations = { [P in OverloadKeys]?: DeprecationOptions; }; /** @internal */ -export function createOverload(name: string, overloads: T, binder: OverloadBinders, deprecations?: OverloadDeprecations) { +export function createOverload( + name: string, + overloads: T, + binder: OverloadBinders, + deprecations?: OverloadDeprecations, +) { Object.defineProperty(call, "name", { ...Object.getOwnPropertyDescriptor(call, "name"), value: name }); if (deprecations) { @@ -145,9 +155,9 @@ export function buildOverload(name: string): OverloadBuilder { bind: binder => ({ finish: () => createOverload(name, overloads, binder), deprecate: deprecations => ({ - finish: () => createOverload(name, overloads, binder, deprecations) - }) - }) - }) + finish: () => createOverload(name, overloads, binder, deprecations), + }), + }), + }), }; } diff --git a/src/executeCommandLine/executeCommandLine.ts b/src/executeCommandLine/executeCommandLine.ts index 660effc571d48..74bd1d506402e 100644 --- a/src/executeCommandLine/executeCommandLine.ts +++ b/src/executeCommandLine/executeCommandLine.ts @@ -149,11 +149,11 @@ function getCountKey(program: Program, file: SourceFile) { function updateReportDiagnostic( sys: System, existing: DiagnosticReporter, - options: CompilerOptions | BuildOptions + options: CompilerOptions | BuildOptions, ): DiagnosticReporter { - return shouldBePretty(sys, options) ? - createDiagnosticReporter(sys, /*pretty*/ true) : - existing; + return shouldBePretty(sys, options) + ? createDiagnosticReporter(sys, /*pretty*/ true) + : existing; } function defaultIsPretty(sys: System) { @@ -169,9 +169,9 @@ function shouldBePretty(sys: System, options: CompilerOptions | BuildOptions) { function getOptionsForHelp(commandLine: ParsedCommandLine) { // Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch") - return !!commandLine.options.all ? - sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) : - filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView); + return !!commandLine.options.all + ? sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) + : filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView); } function printVersion(sys: System) { @@ -185,7 +185,7 @@ function createColors(sys: System) { bold: (str: string) => str, blue: (str: string) => str, blueBackground: (str: string) => str, - brightWhite: (str: string) => str + brightWhite: (str: string) => str, }; } @@ -193,9 +193,11 @@ function createColors(sys: System) { return `\x1b[1m${str}\x1b[22m`; } - const isWindows = sys.getEnvironmentVariable("OS") && stringContains(sys.getEnvironmentVariable("OS").toLowerCase(), "windows"); + const isWindows = sys.getEnvironmentVariable("OS") + && stringContains(sys.getEnvironmentVariable("OS").toLowerCase(), "windows"); const isWindowsTerminal = sys.getEnvironmentVariable("WT_SESSION"); - const isVSCode = sys.getEnvironmentVariable("TERM_PROGRAM") && sys.getEnvironmentVariable("TERM_PROGRAM") === "vscode"; + const isVSCode = sys.getEnvironmentVariable("TERM_PROGRAM") + && sys.getEnvironmentVariable("TERM_PROGRAM") === "vscode"; function blue(str: string) { // Effectively Powershell and Command prompt users use cyan instead @@ -210,7 +212,8 @@ function createColors(sys: System) { // There are ~3 types of terminal color support: 16 colors, 256 and 16m colors // If there is richer color support, e.g. 256+ we can use extended ANSI codes which are not just generic 'blue' // but a 'lighter blue' which is closer to the blue in the TS logo. - const supportsRicherColors = sys.getEnvironmentVariable("COLORTERM") === "truecolor" || sys.getEnvironmentVariable("TERM") === "xterm-256color"; + const supportsRicherColors = sys.getEnvironmentVariable("COLORTERM") === "truecolor" + || sys.getEnvironmentVariable("TERM") === "xterm-256color"; function blueBackground(str: string) { if (supportsRicherColors) { return `\x1B[48;5;68m${str}\x1B[39;49m`; @@ -226,7 +229,7 @@ function createColors(sys: System) { bold, blue, brightWhite, - blueBackground + blueBackground, }; } @@ -234,7 +237,12 @@ function getDisplayNameTextOfOption(option: CommandLineOption) { return `--${option.name}${option.shortName ? `, -${option.shortName}` : ""}`; } -function generateOptionOutput(sys: System, option: CommandLineOption, rightAlignOfLeft: number, leftAlignOfRight: number) { +function generateOptionOutput( + sys: System, + option: CommandLineOption, + rightAlignOfLeft: number, + leftAlignOfRight: number, +) { interface ValueCandidate { // "one or more" or "any of" valueType: string; @@ -249,13 +257,12 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign // value type and possible value const valueCandidates = getValueCandidate(option); - const defaultValueDescription = - typeof option.defaultValueDescription === "object" - ? getDiagnosticText(option.defaultValueDescription) - : formatDefaultValue( - option.defaultValueDescription, - option.type === "list" || option.type === "listOrElement" ? option.element.type : option.type - ); + const defaultValueDescription = typeof option.defaultValueDescription === "object" + ? getDiagnosticText(option.defaultValueDescription) + : formatDefaultValue( + option.defaultValueDescription, + option.type === "list" || option.type === "listOrElement" ? option.element.type : option.type, + ); const terminalWidth = sys.getWidthOfTerminal?.() ?? 0; // Note: child_process might return `terminalWidth` as undefined. @@ -264,13 +271,43 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign if (option.description) { description = getDiagnosticText(option.description); } - text.push(...getPrettyOutput(name, description, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ true), sys.newLine); + text.push( + ...getPrettyOutput( + name, + description, + rightAlignOfLeft, + leftAlignOfRight, + terminalWidth, + /*colorLeft*/ true, + ), + sys.newLine, + ); if (showAdditionalInfoOutput(valueCandidates, option)) { if (valueCandidates) { - text.push(...getPrettyOutput(valueCandidates.valueType, valueCandidates.possibleValues, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ false), sys.newLine); + text.push( + ...getPrettyOutput( + valueCandidates.valueType, + valueCandidates.possibleValues, + rightAlignOfLeft, + leftAlignOfRight, + terminalWidth, + /*colorLeft*/ false, + ), + sys.newLine, + ); } if (defaultValueDescription) { - text.push(...getPrettyOutput(getDiagnosticText(Diagnostics.default_Colon), defaultValueDescription, rightAlignOfLeft, leftAlignOfRight, terminalWidth, /*colorLeft*/ false), sys.newLine); + text.push( + ...getPrettyOutput( + getDiagnosticText(Diagnostics.default_Colon), + defaultValueDescription, + rightAlignOfLeft, + leftAlignOfRight, + terminalWidth, + /*colorLeft*/ false, + ), + sys.newLine, + ); } } text.push(sys.newLine); @@ -300,14 +337,14 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign function formatDefaultValue( defaultValue: CommandLineOption["defaultValueDescription"], - type: CommandLineOption["type"] + type: CommandLineOption["type"], ) { return defaultValue !== undefined && typeof type === "object" // e.g. ScriptTarget.ES2015 -> "es6/es2015" ? arrayFrom(type.entries()) - .filter(([, value]) => value === defaultValue) - .map(([name]) => name) - .join("/") + .filter(([, value]) => value === defaultValue) + .map(([name]) => name) + .join("/") : String(defaultValue); } @@ -317,13 +354,23 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign const defaultValueDescription = option.defaultValueDescription; if (option.category === Diagnostics.Command_line_Options) return false; - if (contains(ignoreValues, valueCandidates?.possibleValues) && contains(ignoredDescriptions, defaultValueDescription)) { + if ( + contains(ignoreValues, valueCandidates?.possibleValues) + && contains(ignoredDescriptions, defaultValueDescription) + ) { return false; } return true; } - function getPrettyOutput(left: string, right: string, rightAlignOfLeft: number, leftAlignOfRight: number, terminalWidth: number, colorLeft: boolean) { + function getPrettyOutput( + left: string, + right: string, + rightAlignOfLeft: number, + leftAlignOfRight: number, + terminalWidth: number, + colorLeft: boolean, + ) { const res = []; let isFirstLine = true; let remainRight = right; @@ -361,7 +408,7 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign return { valueType: getValueType(option), - possibleValues: getPossibleValues(option) + possibleValues: getPossibleValues(option), }; function getValueType(option: CommandLineOption) { @@ -396,7 +443,7 @@ function generateOptionOutput(sys: System, option: CommandLineOption, rightAlign default: // Map // Group synonyms: es6/es2015 - const inverted: { [value: string]: string[] } = {}; + const inverted: { [value: string]: string[]; } = {}; option.type.forEach((value, name) => { (inverted[value] ||= []).push(name); }); @@ -434,7 +481,14 @@ function generateGroupOptionOutput(sys: System, optionsList: readonly CommandLin return lines; } -function generateSectionOptionsOutput(sys: System, sectionName: string, options: readonly CommandLineOption[], subCategory: boolean, beforeOptionsDescription?: string, afterOptionsDescription?: string) { +function generateSectionOptionsOutput( + sys: System, + sectionName: string, + options: readonly CommandLineOption[], + subCategory: boolean, + beforeOptionsDescription?: string, + afterOptionsDescription?: string, +) { let res: string[] = []; res.push(createColors(sys).bold(sectionName) + sys.newLine + sys.newLine); if (beforeOptionsDescription) { @@ -469,24 +523,56 @@ function generateSectionOptionsOutput(sys: System, sectionName: string, options: function printEasyHelp(sys: System, simpleOptions: readonly CommandLineOption[]) { const colors = createColors(sys); - let output: string[] = [...getHeader(sys,`${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)]; + let output: string[] = [ + ...getHeader( + sys, + `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${ + getDiagnosticText(Diagnostics.Version_0, version) + }`, + ), + ]; output.push(colors.bold(getDiagnosticText(Diagnostics.COMMON_COMMANDS)) + sys.newLine + sys.newLine); example("tsc", Diagnostics.Compiles_the_current_project_tsconfig_json_in_the_working_directory); - example("tsc app.ts util.ts", Diagnostics.Ignoring_tsconfig_json_compiles_the_specified_files_with_default_compiler_options); + example( + "tsc app.ts util.ts", + Diagnostics.Ignoring_tsconfig_json_compiles_the_specified_files_with_default_compiler_options, + ); example("tsc -b", Diagnostics.Build_a_composite_project_in_the_working_directory); example("tsc --init", Diagnostics.Creates_a_tsconfig_json_with_the_recommended_settings_in_the_working_directory); - example("tsc -p ./path/to/tsconfig.json", Diagnostics.Compiles_the_TypeScript_project_located_at_the_specified_path); - example("tsc --help --all", Diagnostics.An_expanded_version_of_this_information_showing_all_possible_compiler_options); + example( + "tsc -p ./path/to/tsconfig.json", + Diagnostics.Compiles_the_TypeScript_project_located_at_the_specified_path, + ); + example( + "tsc --help --all", + Diagnostics.An_expanded_version_of_this_information_showing_all_possible_compiler_options, + ); example(["tsc --noEmit", "tsc --target esnext"], Diagnostics.Compiles_the_current_project_with_additional_settings); - const cliCommands = simpleOptions.filter(opt => opt.isCommandLineOnly || opt.category === Diagnostics.Command_line_Options); + const cliCommands = simpleOptions.filter(opt => + opt.isCommandLineOnly || opt.category === Diagnostics.Command_line_Options + ); const configOpts = simpleOptions.filter(opt => !contains(cliCommands, opt)); output = [ ...output, - ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.COMMAND_LINE_FLAGS), cliCommands, /*subCategory*/ false, /*beforeOptionsDescription*/ undefined, /*afterOptionsDescription*/ undefined), - ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.COMMON_COMPILER_OPTIONS), configOpts, /*subCategory*/ false, /*beforeOptionsDescription*/ undefined, formatMessage(Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc")) + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.COMMAND_LINE_FLAGS), + cliCommands, + /*subCategory*/ false, + /*beforeOptionsDescription*/ undefined, + /*afterOptionsDescription*/ undefined, + ), + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.COMMON_COMPILER_OPTIONS), + configOpts, + /*subCategory*/ false, + /*beforeOptionsDescription*/ undefined, + formatMessage(Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc"), + ), ]; for (const line of output) { @@ -502,19 +588,86 @@ function printEasyHelp(sys: System, simpleOptions: readonly CommandLineOption[]) } } -function printAllHelp(sys: System, compilerOptions: readonly CommandLineOption[], buildOptions: readonly CommandLineOption[], watchOptions: readonly CommandLineOption[]) { - let output: string[] = [...getHeader(sys,`${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)]; - output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.ALL_COMPILER_OPTIONS), compilerOptions, /*subCategory*/ true, /*beforeOptionsDescription*/ undefined, formatMessage(Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc"))]; - output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.WATCH_OPTIONS), watchOptions, /*subCategory*/ false, getDiagnosticText(Diagnostics.Including_watch_w_will_start_watching_the_current_project_for_the_file_changes_Once_set_you_can_config_watch_mode_with_Colon))]; - output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), buildOptions, /*subCategory*/ false, formatMessage(Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))]; +function printAllHelp( + sys: System, + compilerOptions: readonly CommandLineOption[], + buildOptions: readonly CommandLineOption[], + watchOptions: readonly CommandLineOption[], +) { + let output: string[] = [ + ...getHeader( + sys, + `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${ + getDiagnosticText(Diagnostics.Version_0, version) + }`, + ), + ]; + output = [ + ...output, + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.ALL_COMPILER_OPTIONS), + compilerOptions, + /*subCategory*/ true, + /*beforeOptionsDescription*/ undefined, + formatMessage(Diagnostics.You_can_learn_about_all_of_the_compiler_options_at_0, "https://aka.ms/tsc"), + ), + ]; + output = [ + ...output, + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.WATCH_OPTIONS), + watchOptions, + /*subCategory*/ false, + getDiagnosticText( + Diagnostics + .Including_watch_w_will_start_watching_the_current_project_for_the_file_changes_Once_set_you_can_config_watch_mode_with_Colon, + ), + ), + ]; + output = [ + ...output, + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.BUILD_OPTIONS), + buildOptions, + /*subCategory*/ false, + formatMessage( + Diagnostics + .Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, + "https://aka.ms/tsc-composite-builds", + ), + ), + ]; for (const line of output) { sys.write(line); } } function printBuildHelp(sys: System, buildOptions: readonly CommandLineOption[]) { - let output: string[] = [...getHeader(sys,`${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${getDiagnosticText(Diagnostics.Version_0, version)}`)]; - output = [...output, ...generateSectionOptionsOutput(sys, getDiagnosticText(Diagnostics.BUILD_OPTIONS), buildOptions, /*subCategory*/ false, formatMessage(Diagnostics.Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, "https://aka.ms/tsc-composite-builds"))]; + let output: string[] = [ + ...getHeader( + sys, + `${getDiagnosticText(Diagnostics.tsc_Colon_The_TypeScript_Compiler)} - ${ + getDiagnosticText(Diagnostics.Version_0, version) + }`, + ), + ]; + output = [ + ...output, + ...generateSectionOptionsOutput( + sys, + getDiagnosticText(Diagnostics.BUILD_OPTIONS), + buildOptions, + /*subCategory*/ false, + formatMessage( + Diagnostics + .Using_build_b_will_make_tsc_behave_more_like_a_build_orchestrator_than_a_compiler_This_is_used_to_trigger_building_composite_projects_which_you_can_learn_more_about_at_0, + "https://aka.ms/tsc-composite-builds", + ), + ), + ]; for (const line of output) { sys.write(line); } @@ -592,13 +745,19 @@ function executeCommandLineWorker( } if (commandLine.options.watch && commandLine.options.listFilesOnly) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "listFilesOnly")); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "listFilesOnly"), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (commandLine.options.project) { if (commandLine.fileNames.length !== 0) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line)); + reportDiagnostic( + createCompilerDiagnostic( + Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line, + ), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } @@ -606,14 +765,24 @@ function executeCommandLineWorker( if (!fileOrDirectory /* current directory "." */ || sys.directoryExists(fileOrDirectory)) { configFileName = combinePaths(fileOrDirectory, "tsconfig.json"); if (!sys.fileExists(configFileName)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, commandLine.options.project)); + reportDiagnostic( + createCompilerDiagnostic( + Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_specified_directory_Colon_0, + commandLine.options.project, + ), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } } else { configFileName = fileOrDirectory; if (!sys.fileExists(configFileName)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_specified_path_does_not_exist_Colon_0, commandLine.options.project)); + reportDiagnostic( + createCompilerDiagnostic( + Diagnostics.The_specified_path_does_not_exist_Colon_0, + commandLine.options.project, + ), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } } @@ -625,7 +794,12 @@ function executeCommandLineWorker( if (commandLine.fileNames.length === 0 && !configFileName) { if (commandLine.options.showConfig) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_current_directory_Colon_0, normalizePath(sys.getCurrentDirectory()))); + reportDiagnostic( + createCompilerDiagnostic( + Diagnostics.Cannot_find_a_tsconfig_json_file_at_the_current_directory_Colon_0, + normalizePath(sys.getCurrentDirectory()), + ), + ); } else { printVersion(sys); @@ -637,17 +811,24 @@ function executeCommandLineWorker( const currentDirectory = sys.getCurrentDirectory(); const commandLineOptions = convertToOptionsWithAbsolutePaths( commandLine.options, - fileName => getNormalizedAbsolutePath(fileName, currentDirectory) + fileName => getNormalizedAbsolutePath(fileName, currentDirectory), ); if (configFileName) { const extendedConfigCache = new Map(); - const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions, extendedConfigCache, commandLine.watchOptions, sys, reportDiagnostic)!; // TODO: GH#18217 + const configParseResult = parseConfigFileWithSystem( + configFileName, + commandLineOptions, + extendedConfigCache, + commandLine.watchOptions, + sys, + reportDiagnostic, + )!; // TODO: GH#18217 if (commandLineOptions.showConfig) { if (configParseResult.errors.length !== 0) { reportDiagnostic = updateReportDiagnostic( sys, reportDiagnostic, - configParseResult.options + configParseResult.options, ); configParseResult.errors.forEach(reportDiagnostic); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); @@ -659,7 +840,7 @@ function executeCommandLineWorker( reportDiagnostic = updateReportDiagnostic( sys, reportDiagnostic, - configParseResult.options + configParseResult.options, ); if (isWatchSet(configParseResult.options)) { if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return; @@ -678,7 +859,7 @@ function executeCommandLineWorker( sys, cb, reportDiagnostic, - configParseResult + configParseResult, ); } else { @@ -686,20 +867,26 @@ function executeCommandLineWorker( sys, cb, reportDiagnostic, - configParseResult + configParseResult, ); } } else { if (commandLineOptions.showConfig) { // eslint-disable-next-line no-null/no-null - sys.write(JSON.stringify(convertToTSConfig(commandLine, combinePaths(currentDirectory, "tsconfig.json"), sys), null, 4) + sys.newLine); + sys.write( + JSON.stringify( + convertToTSConfig(commandLine, combinePaths(currentDirectory, "tsconfig.json"), sys), + null, + 4, + ) + sys.newLine, + ); return sys.exit(ExitStatus.Success); } reportDiagnostic = updateReportDiagnostic( sys, reportDiagnostic, - commandLineOptions + commandLineOptions, ); if (isWatchSet(commandLineOptions)) { if (reportWatchModeWithoutSysSupport(sys, reportDiagnostic)) return; @@ -717,7 +904,7 @@ function executeCommandLineWorker( sys, cb, reportDiagnostic, - { ...commandLine, options: commandLineOptions } + { ...commandLine, options: commandLineOptions }, ); } else { @@ -725,7 +912,7 @@ function executeCommandLineWorker( sys, cb, reportDiagnostic, - { ...commandLine, options: commandLineOptions } + { ...commandLine, options: commandLineOptions }, ); } } @@ -733,7 +920,8 @@ function executeCommandLineWorker( export function isBuild(commandLineArgs: readonly string[]) { if (commandLineArgs.length > 0 && commandLineArgs[0].charCodeAt(0) === CharacterCodes.minus) { - const firstOption = commandLineArgs[0].slice(commandLineArgs[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase(); + const firstOption = commandLineArgs[0].slice(commandLineArgs[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1) + .toLowerCase(); return firstOption === "build" || firstOption === "b"; } return false; @@ -748,14 +936,15 @@ export function executeCommandLine( if (isBuild(commandLineArgs)) { const { buildOptions, watchOptions, projects, errors } = parseBuildCommand(commandLineArgs.slice(1)); if (buildOptions.generateCpuProfile && system.enableCPUProfiler) { - system.enableCPUProfiler(buildOptions.generateCpuProfile, () => performBuild( - system, - cb, - buildOptions, - watchOptions, - projects, - errors - )); + system.enableCPUProfiler(buildOptions.generateCpuProfile, () => + performBuild( + system, + cb, + buildOptions, + watchOptions, + projects, + errors, + )); } else { return performBuild( @@ -764,18 +953,19 @@ export function executeCommandLine( buildOptions, watchOptions, projects, - errors + errors, ); } } const commandLine = parseCommandLine(commandLineArgs, path => system.readFile(path)); if (commandLine.options.generateCpuProfile && system.enableCPUProfiler) { - system.enableCPUProfiler(commandLine.options.generateCpuProfile, () => executeCommandLineWorker( - system, - cb, - commandLine, - )); + system.enableCPUProfiler(commandLine.options.generateCpuProfile, () => + executeCommandLineWorker( + system, + cb, + commandLine, + )); } else { return executeCommandLineWorker(system, cb, commandLine); @@ -784,7 +974,9 @@ export function executeCommandLine( function reportWatchModeWithoutSysSupport(sys: System, reportDiagnostic: DiagnosticReporter) { if (!sys.watchFile || !sys.watchDirectory) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch")); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), + ); sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); return true; } @@ -797,13 +989,13 @@ function performBuild( buildOptions: BuildOptions, watchOptions: WatchOptions | undefined, projects: string[], - errors: Diagnostic[] + errors: Diagnostic[], ) { // Update to pretty if host supports it const reportDiagnostic = updateReportDiagnostic( sys, createDiagnosticReporter(sys), - buildOptions + buildOptions, ); if (buildOptions.locale) { @@ -828,7 +1020,9 @@ function performBuild( } if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build")); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"), + ); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } @@ -839,7 +1033,7 @@ function performBuild( /*createProgram*/ undefined, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)), - createWatchStatusReporter(sys, buildOptions) + createWatchStatusReporter(sys, buildOptions), ); const solutionPerformance = enableSolutionPerformance(sys, buildOptions); updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance); @@ -847,10 +1041,12 @@ function performBuild( let reportBuildStatistics = false; buildHost.onWatchStatusChange = (d, newLine, options, errorCount) => { onWatchStatusChange?.(d, newLine, options, errorCount); - if (reportBuildStatistics && ( - d.code === Diagnostics.Found_0_errors_Watching_for_file_changes.code || - d.code === Diagnostics.Found_1_error_Watching_for_file_changes.code - )) { + if ( + reportBuildStatistics && ( + d.code === Diagnostics.Found_0_errors_Watching_for_file_changes.code + || d.code === Diagnostics.Found_1_error_Watching_for_file_changes.code + ) + ) { reportSolutionBuilderTimes(builder, solutionPerformance); } }; @@ -866,7 +1062,7 @@ function performBuild( /*createProgram*/ undefined, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)), - createReportErrorSummary(sys, buildOptions) + createReportErrorSummary(sys, buildOptions), ); const solutionPerformance = enableSolutionPerformance(sys, buildOptions); updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance); @@ -877,17 +1073,20 @@ function performBuild( return sys.exit(exitStatus); } -function createReportErrorSummary(sys: System, options: CompilerOptions | BuildOptions): ReportEmitErrorSummary | undefined { - return shouldBePretty(sys, options) ? - (errorCount, filesInError) => sys.write(getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)) : - undefined; +function createReportErrorSummary( + sys: System, + options: CompilerOptions | BuildOptions, +): ReportEmitErrorSummary | undefined { + return shouldBePretty(sys, options) + ? (errorCount, filesInError) => sys.write(getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)) + : undefined; } function performCompilation( sys: System, cb: ExecuteCommandLineCallbacks, reportDiagnostic: DiagnosticReporter, - config: ParsedCommandLine + config: ParsedCommandLine, ) { const { fileNames, options, projectReferences } = config; const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, sys); @@ -901,14 +1100,14 @@ function performCompilation( options, projectReferences, host, - configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config) + configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config), }; const program = createProgram(programOptions); const exitStatus = emitFilesAndReportErrorsAndGetExitStatus( program, reportDiagnostic, s => sys.write(s + sys.newLine), - createReportErrorSummary(sys, options) + createReportErrorSummary(sys, options), ); reportStatistics(sys, program, /*solutionPerformance*/ undefined); cb(program); @@ -919,7 +1118,7 @@ function performIncrementalCompilation( sys: System, cb: ExecuteCommandLineCallbacks, reportDiagnostic: DiagnosticReporter, - config: ParsedCommandLine + config: ParsedCommandLine, ) { const { options, fileNames, projectReferences } = config; enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false); @@ -936,7 +1135,7 @@ function performIncrementalCompilation( afterProgramEmitAndDiagnostics: builderProgram => { reportStatistics(sys, builderProgram.getProgram(), /*solutionPerformance*/ undefined); cb(builderProgram); - } + }, }); return sys.exit(exitStatus); } @@ -959,14 +1158,25 @@ function updateSolutionBuilderHost( }; } -function updateCreateProgram(sys: System, host: { createProgram: CreateProgram; }, isBuildMode: boolean) { +function updateCreateProgram( + sys: System, + host: { createProgram: CreateProgram; }, + isBuildMode: boolean, +) { const compileUsingBuilder = host.createProgram; host.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) => { Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram)); if (options !== undefined) { enableStatisticsAndTracing(sys, options, isBuildMode); } - return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences); + return compileUsingBuilder( + rootNames, + options, + host, + oldProgram, + configFileParsingDiagnostics, + projectReferences, + ); }; } @@ -1003,7 +1213,7 @@ function createWatchOfConfigFile( watchOptionsToExtend, system, reportDiagnostic, - reportWatchStatus: createWatchStatusReporter(system, configParseResult.options) + reportWatchStatus: createWatchStatusReporter(system, configParseResult.options), }); updateWatchCompilationHost(system, cb, watchCompilerHost); watchCompilerHost.configFileParsingResult = configParseResult; @@ -1025,7 +1235,7 @@ function createWatchOfFilesAndCompilerOptions( watchOptions, system, reportDiagnostic, - reportWatchStatus: createWatchStatusReporter(system, options) + reportWatchStatus: createWatchStatusReporter(system, options), }); updateWatchCompilationHost(system, cb, watchCompilerHost); return createWatchProgram(watchCompilerHost); @@ -1074,17 +1284,26 @@ function createSolutionPerfomrance(): SolutionPerformance { function reportSolutionBuilderTimes( builder: SolutionBuilder, - solutionPerformance: SolutionPerformance | undefined) { + solutionPerformance: SolutionPerformance | undefined, +) { if (!solutionPerformance) return; if (!performance.isEnabled()) { - sys.write(Diagnostics.Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found.message + "\n"); + sys.write( + Diagnostics + .Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found + .message + "\n", + ); return; } const statistics: Statistic[] = []; statistics.push( - { name: "Projects in scope", value: getBuildOrderFromAnyBuildOrder(builder.getBuildOrder()).length, type: StatisticType.count }, + { + name: "Projects in scope", + value: getBuildOrderFromAnyBuildOrder(builder.getBuildOrder()).length, + type: StatisticType.count, + }, ); reportSolutionBuilderCountStatistic("SolutionBuilder::Projects built"); reportSolutionBuilderCountStatistic("SolutionBuilder::Timestamps only updates"); @@ -1094,7 +1313,13 @@ function reportSolutionBuilderTimes( statistics.push(s); }); performance.forEachMeasure((name, duration) => { - if (isSolutionMarkOrMeasure(name)) statistics.push({ name: `${getNameFromSolutionBuilderMarkOrMeasure(name)} time`, value: duration, type: StatisticType.time }); + if (isSolutionMarkOrMeasure(name)) { + statistics.push({ + name: `${getNameFromSolutionBuilderMarkOrMeasure(name)} time`, + value: duration, + type: StatisticType.time, + }); + } }); performance.disable(); performance.enable(); @@ -1128,8 +1353,7 @@ function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOpt } if (canTrace(system, compilerOptions)) { - startTracing(isBuildMode ? "build" : "project", - compilerOptions.generateTrace!, compilerOptions.configFilePath); + startTracing(isBuildMode ? "build" : "project", compilerOptions.generateTrace!, compilerOptions.configFilePath); } } @@ -1141,7 +1365,11 @@ function isProgram(programOrConfig: Program | ParsedCommandLine): programOrConfi return !(programOrConfig as ParsedCommandLine).options; } -function reportStatistics(sys: System, programOrConfig: Program | ParsedCommandLine, solutionPerformance: SolutionPerformance | undefined) { +function reportStatistics( + sys: System, + programOrConfig: Program | ParsedCommandLine, + solutionPerformance: SolutionPerformance | undefined, +) { const program = isProgram(programOrConfig) ? programOrConfig : undefined; const config = isProgram(programOrConfig) ? undefined : programOrConfig; const compilerOptions = program ? program.getCompilerOptions() : config!.options; @@ -1173,7 +1401,10 @@ function reportStatistics(sys: System, programOrConfig: Program | ParsedCommandL reportCountStatistic("Instantiations", program.getInstantiationCount()); } if (memoryUsed >= 0) { - reportStatisticalValue({ name: "Memory used", value: memoryUsed, type: StatisticType.memory }, /*aggregate*/ true); + reportStatisticalValue( + { name: "Memory used", value: memoryUsed, type: StatisticType.memory }, + /*aggregate*/ true, + ); } const isPerformanceEnabled = performance.isEnabled(); @@ -1191,7 +1422,9 @@ function reportStatistics(sys: System, programOrConfig: Program | ParsedCommandL } if (isPerformanceEnabled) { performance.forEachMeasure((name, duration) => { - if (!isSolutionMarkOrMeasure(name)) reportTimeStatistic(`${name} time`, duration, /*aggregate*/ true); + if (!isSolutionMarkOrMeasure(name)) { + reportTimeStatistic(`${name} time`, duration, /*aggregate*/ true); + } }); } } @@ -1212,7 +1445,11 @@ function reportStatistics(sys: System, programOrConfig: Program | ParsedCommandL } reportAllStatistics(sys, statistics); if (!isPerformanceEnabled) { - sys.write(Diagnostics.Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found.message + "\n"); + sys.write( + Diagnostics + .Performance_timings_for_diagnostics_or_extendedDiagnostics_are_not_available_in_this_session_A_native_implementation_of_the_Web_Performance_API_could_not_be_found + .message + "\n", + ); } else { if (solutionPerformance) { @@ -1259,7 +1496,9 @@ function reportAllStatistics(sys: System, statistics: Statistic[]) { } for (const s of statistics) { - sys.write(padRight(s.name + ":", nameSize + 2) + padLeft(statisticValue(s).toString(), valueSize) + sys.newLine); + sys.write( + padRight(s.name + ":", nameSize + 2) + padLeft(statisticValue(s).toString(), valueSize) + sys.newLine, + ); } } @@ -1280,16 +1519,18 @@ function writeConfigFile( sys: System, reportDiagnostic: DiagnosticReporter, options: CompilerOptions, - fileNames: string[] + fileNames: string[], ) { const currentDirectory = sys.getCurrentDirectory(); const file = normalizePath(combinePaths(currentDirectory, "tsconfig.json")); if (sys.fileExists(file)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file)); + reportDiagnostic( + createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file), + ); } else { sys.writeFile(file, generateTSConfig(options, fileNames, sys.newLine)); - const output: string[] = [sys.newLine, ...getHeader(sys,"Created a new tsconfig.json with:")]; + const output: string[] = [sys.newLine, ...getHeader(sys, "Created a new tsconfig.json with:")]; output.push(getCompilerOptionsDiffValue(options, sys.newLine) + sys.newLine + sys.newLine); output.push(`You can learn more at https://aka.ms/tsconfig` + sys.newLine); for (const line of output) { diff --git a/src/harness/client.ts b/src/harness/client.ts index 76004edf58f10..a46df3e248272 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -102,14 +102,20 @@ export function extractMessage(message: string): string { Debug.assert(lines.length >= 2, "Malformed response: Expected 3 lines in the response."); const contentLengthText = lines[0]; - Debug.assert(contentLengthText.indexOf(contentLengthPrefix) === 0, "Malformed response: Response text did not contain content-length header."); + Debug.assert( + contentLengthText.indexOf(contentLengthPrefix) === 0, + "Malformed response: Response text did not contain content-length header.", + ); const contentLength = parseInt(contentLengthText.substring(contentLengthPrefix.length)); // Read the body const responseBody = lines[2]; // Verify content length - Debug.assert(responseBody.length + 1 === contentLength, "Malformed response: Content length did not match the response's body length."); + Debug.assert( + responseBody.length + 1 === contentLength, + "Malformed response: Content length did not match the response's body length.", + ); return responseBody; } @@ -149,7 +155,7 @@ export class SessionClient implements LanguageService { const lineOffset = computeLineAndCharacterOfPosition(this.getLineMap(fileName), position); return { line: lineOffset.line + 1, - offset: lineOffset.character + 1 + offset: lineOffset.character + 1, }; } @@ -162,7 +168,7 @@ export class SessionClient implements LanguageService { seq: this.sequence, type: "request", arguments: args, - command + command, }; this.sequence++; @@ -187,7 +193,10 @@ export class SessionClient implements LanguageService { } } catch (e) { - throw new Error("Malformed response: Failed to parse server response: " + lastMessage + ". \r\n Error details: " + e.message); + throw new Error( + "Malformed response: Failed to parse server response: " + lastMessage + ". \r\n Error details: " + + e.message, + ); } } @@ -196,7 +205,10 @@ export class SessionClient implements LanguageService { throw new Error("Error " + response.message); } - Debug.assert(response.request_seq === request.seq, "Malformed response: response sequence number did not match request sequence number."); + Debug.assert( + response.request_seq === request.seq, + "Malformed response: response sequence number did not match request sequence number.", + ); Debug.assert(expectEmptyBody || !!response.body, "Malformed response: Unexpected empty response body."); Debug.assert(!expectEmptyBody || !response.body, "Malformed response: Unexpected non-empty response body."); @@ -235,7 +247,12 @@ export class SessionClient implements LanguageService { this.processRequest(protocol.CommandTypes.Close, args); } - createChangeFileRequestArgs(fileName: string, start: number, end: number, insertString: string): protocol.ChangeRequestArgs { + createChangeFileRequestArgs( + fileName: string, + start: number, + end: number, + insertString: string, + ): protocol.ChangeRequestArgs { return { ...this.createFileLocationRequestArgsWithEndLineAndOffset(fileName, start, end), insertString }; } @@ -262,8 +279,9 @@ export class SessionClient implements LanguageService { kindModifiers: body.kindModifiers, textSpan: this.decodeSpan(body, fileName), displayParts: [{ kind: "text", text: body.displayString }], - documentation: typeof body.documentation === "string" ? [{ kind: "text", text: body.documentation }] : body.documentation, - tags: this.decodeLinkDisplayParts(body.tags) + documentation: typeof body.documentation === "string" ? [{ kind: "text", text: body.documentation }] + : body.documentation, + tags: this.decodeLinkDisplayParts(body.tags), }; } @@ -275,11 +293,15 @@ export class SessionClient implements LanguageService { return { configFileName: response.body!.configFileName, // TODO: GH#18217 - fileNames: response.body!.fileNames + fileNames: response.body!.fileNames, }; } - getCompletionsAtPosition(fileName: string, position: number, _preferences: UserPreferences | undefined): CompletionInfo { + getCompletionsAtPosition( + fileName: string, + position: number, + _preferences: UserPreferences | undefined, + ): CompletionInfo { // Not passing along 'preferences' because server should already have those from the 'configure' command const args: protocol.CompletionsRequestArgs = this.createFileLocationRequestArgs(fileName, position); @@ -292,19 +314,37 @@ export class SessionClient implements LanguageService { isNewIdentifierLocation: response.body!.isNewIdentifierLocation, entries: response.body!.entries.map(entry => { // TODO: GH#18217 if (entry.replacementSpan !== undefined) { - const res: CompletionEntry = { ...entry, data: entry.data as any, replacementSpan: this.decodeSpan(entry.replacementSpan, fileName) }; + const res: CompletionEntry = { + ...entry, + data: entry.data as any, + replacementSpan: this.decodeSpan(entry.replacementSpan, fileName), + }; return res; } - return entry as { name: string, kind: ScriptElementKind, kindModifiers: string, sortText: string }; // TODO: GH#18217 - }) + return entry as { name: string; kind: ScriptElementKind; kindModifiers: string; sortText: string; }; // TODO: GH#18217 + }), }; } - getCompletionEntryDetails(fileName: string, position: number, entryName: string, _options: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined, _preferences: UserPreferences | undefined, data: unknown): CompletionEntryDetails { - const args: protocol.CompletionDetailsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), entryNames: [{ name: entryName, source, data }] }; + getCompletionEntryDetails( + fileName: string, + position: number, + entryName: string, + _options: FormatCodeOptions | FormatCodeSettings | undefined, + source: string | undefined, + _preferences: UserPreferences | undefined, + data: unknown, + ): CompletionEntryDetails { + const args: protocol.CompletionDetailsRequestArgs = { + ...this.createFileLocationRequestArgs(fileName, position), + entryNames: [{ name: entryName, source, data }], + }; - const request = this.processRequest(protocol.CommandTypes.CompletionDetailsFull, args); + const request = this.processRequest( + protocol.CommandTypes.CompletionDetailsFull, + args, + ); const response = this.processResponse(request); Debug.assert(response.body.length === 1, "Unexpected length of completion details response body."); return response.body[0]; @@ -317,7 +357,7 @@ export class SessionClient implements LanguageService { getNavigateToItems(searchValue: string): NavigateToItem[] { const args: protocol.NavtoRequestArgs = { searchValue, - file: this.host.getScriptFileNames()[0] + file: this.host.getScriptFileNames()[0], }; const request = this.processRequest(protocol.CommandTypes.Navto, args); @@ -337,8 +377,11 @@ export class SessionClient implements LanguageService { } getFormattingEditsForRange(file: string, start: number, end: number, _options: FormatCodeOptions): TextChange[] { - const args: protocol.FormatRequestArgs = this.createFileLocationRequestArgsWithEndLineAndOffset(file, start, end); - + const args: protocol.FormatRequestArgs = this.createFileLocationRequestArgsWithEndLineAndOffset( + file, + start, + end, + ); // TODO: handle FormatCodeOptions const request = this.processRequest(protocol.CommandTypes.Format, args); @@ -348,11 +391,24 @@ export class SessionClient implements LanguageService { } getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[] { - return this.getFormattingEditsForRange(fileName, 0, this.host.getScriptSnapshot(fileName)!.getLength(), options); + return this.getFormattingEditsForRange( + fileName, + 0, + this.host.getScriptSnapshot(fileName)!.getLength(), + options, + ); } - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, _options: FormatCodeOptions): TextChange[] { - const args: protocol.FormatOnKeyRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), key }; + getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + _options: FormatCodeOptions, + ): TextChange[] { + const args: protocol.FormatOnKeyRequestArgs = { + ...this.createFileLocationRequestArgs(fileName, position), + key, + }; // TODO: handle FormatCodeOptions const request = this.processRequest(protocol.CommandTypes.Formatonkey, args); @@ -373,14 +429,17 @@ export class SessionClient implements LanguageService { fileName: entry.file, textSpan: this.decodeSpan(entry), kind: ScriptElementKind.unknown, - name: "" + name: "", })); } getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan { const args: protocol.FileLocationRequestArgs = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(protocol.CommandTypes.DefinitionAndBoundSpan, args); + const request = this.processRequest( + protocol.CommandTypes.DefinitionAndBoundSpan, + args, + ); const response = this.processResponse(request); const body = Debug.checkDefined(response.body); // TODO: GH#18217 @@ -394,7 +453,7 @@ export class SessionClient implements LanguageService { name: "", unverified: entry.unverified, })), - textSpan: this.decodeSpan(body.textSpan, request.arguments.file) + textSpan: this.decodeSpan(body.textSpan, request.arguments.file), }; } @@ -410,13 +469,16 @@ export class SessionClient implements LanguageService { fileName: entry.file, textSpan: this.decodeSpan(entry), kind: ScriptElementKind.unknown, - name: "" + name: "", })); } getSourceDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfo[] { const args: protocol.FileLocationRequestArgs = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(protocol.CommandTypes.FindSourceDefinition, args); + const request = this.processRequest( + protocol.CommandTypes.FindSourceDefinition, + args, + ); const response = this.processResponse(request); const body = Debug.checkDefined(response.body); // TODO: GH#18217 @@ -441,7 +503,7 @@ export class SessionClient implements LanguageService { fileName: entry.file, textSpan: this.decodeSpan(entry), kind: ScriptElementKind.unknown, - displayParts: [] + displayParts: [], })); } @@ -467,7 +529,9 @@ export class SessionClient implements LanguageService { } getFileReferences(fileName: string): ReferenceEntry[] { - const request = this.processRequest(protocol.CommandTypes.FileReferences, { file: fileName }); + const request = this.processRequest(protocol.CommandTypes.FileReferences, { + file: fileName, + }); const response = this.processResponse(request); return response.body!.refs.map(entry => ({ // TODO: GH#18217 @@ -495,14 +559,24 @@ export class SessionClient implements LanguageService { } private getDiagnostics(file: string, command: protocol.CommandTypes): DiagnosticWithLocation[] { - const request = this.processRequest(command, { file, includeLinePosition: true }); - const response = this.processResponse(request); + const request = this.processRequest< + | protocol.SyntacticDiagnosticsSyncRequest + | protocol.SemanticDiagnosticsSyncRequest + | protocol.SuggestionDiagnosticsSyncRequest + >(command, { file, includeLinePosition: true }); + const response = this.processResponse< + | protocol.SyntacticDiagnosticsSyncResponse + | protocol.SemanticDiagnosticsSyncResponse + | protocol.SuggestionDiagnosticsSyncResponse + >(request); const sourceText = getSnapshotText(this.host.getScriptSnapshot(file)!); const fakeSourceFile = { fileName: file, text: sourceText } as SourceFile; // Warning! This is a huge lie! return (response.body as protocol.DiagnosticWithLinePosition[]).map((entry): DiagnosticWithLocation => { - const category = firstDefined(Object.keys(DiagnosticCategory), id => - isString(id) && entry.category === id.toLowerCase() ? (DiagnosticCategory as any)[id] : undefined); + const category = firstDefined( + Object.keys(DiagnosticCategory), + id => isString(id) && entry.category === id.toLowerCase() ? (DiagnosticCategory as any)[id] : undefined, + ); return { file: fakeSourceFile, start: entry.start, @@ -520,9 +594,19 @@ export class SessionClient implements LanguageService { return notImplemented(); } - getRenameInfo(fileName: string, position: number, _preferences: UserPreferences, findInStrings?: boolean, findInComments?: boolean): RenameInfo { + getRenameInfo( + fileName: string, + position: number, + _preferences: UserPreferences, + findInStrings?: boolean, + findInComments?: boolean, + ): RenameInfo { // Not passing along 'options' because server should already have those from the 'configure' command - const args: protocol.RenameRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), findInStrings, findInComments }; + const args: protocol.RenameRequestArgs = { + ...this.createFileLocationRequestArgs(fileName, position), + findInStrings, + findInComments, + }; const request = this.processRequest(protocol.CommandTypes.Rename, args); const response = this.processResponse(request); @@ -534,10 +618,10 @@ export class SessionClient implements LanguageService { locations.push({ textSpan: this.decodeSpan({ start, end }, fileName), fileName, - ...(contextStart !== undefined ? - { contextSpan: this.decodeSpan({ start: contextStart, end: contextEnd! }, fileName) } : - undefined), - ...prefixSuffixText + ...(contextStart !== undefined + ? { contextSpan: this.decodeSpan({ start: contextStart, end: contextEnd! }, fileName) } + : undefined), + ...prefixSuffixText, }); } } @@ -570,33 +654,46 @@ export class SessionClient implements LanguageService { return notImplemented(); } - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, preferences: UserPreferences | boolean | undefined): RenameLocation[] { - if (!this.lastRenameEntry || - this.lastRenameEntry.inputs.fileName !== fileName || - this.lastRenameEntry.inputs.position !== position || - this.lastRenameEntry.inputs.findInStrings !== findInStrings || - this.lastRenameEntry.inputs.findInComments !== findInComments) { - const providePrefixAndSuffixTextForRename = typeof preferences === "boolean" ? preferences : preferences?.providePrefixAndSuffixTextForRename; + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + preferences: UserPreferences | boolean | undefined, + ): RenameLocation[] { + if ( + !this.lastRenameEntry + || this.lastRenameEntry.inputs.fileName !== fileName + || this.lastRenameEntry.inputs.position !== position + || this.lastRenameEntry.inputs.findInStrings !== findInStrings + || this.lastRenameEntry.inputs.findInComments !== findInComments + ) { + const providePrefixAndSuffixTextForRename = typeof preferences === "boolean" ? preferences + : preferences?.providePrefixAndSuffixTextForRename; const quotePreference = typeof preferences === "boolean" ? undefined : preferences?.quotePreference; if (providePrefixAndSuffixTextForRename !== undefined || quotePreference !== undefined) { // User preferences have to be set through the `Configure` command this.configure({ providePrefixAndSuffixTextForRename, quotePreference }); // Options argument is not used, so don't pass in options - this.getRenameInfo(fileName, position, /*preferences*/{}, findInStrings, findInComments); + this.getRenameInfo(fileName, position, /*preferences*/ {}, findInStrings, findInComments); // Restore previous user preferences if (this.preferences) { this.configure(this.preferences); } } else { - this.getRenameInfo(fileName, position, /*preferences*/{}, findInStrings, findInComments); + this.getRenameInfo(fileName, position, /*preferences*/ {}, findInStrings, findInComments); } } return this.lastRenameEntry!.locations; } - private decodeNavigationBarItems(items: protocol.NavigationBarItem[] | undefined, fileName: string, lineMap: number[]): NavigationBarItem[] { + private decodeNavigationBarItems( + items: protocol.NavigationBarItem[] | undefined, + fileName: string, + lineMap: number[], + ): NavigationBarItem[] { if (!items) { return []; } @@ -609,7 +706,7 @@ export class SessionClient implements LanguageService { childItems: this.decodeNavigationBarItems(item.childItems, fileName, lineMap), indent: item.indent, bolded: false, - grayed: false + grayed: false, })); } @@ -628,7 +725,7 @@ export class SessionClient implements LanguageService { kindModifiers: tree.kindModifiers, spans: tree.spans.map(span => this.decodeSpan(span, fileName, lineMap)), nameSpan: tree.nameSpan && this.decodeSpan(tree.nameSpan, fileName, lineMap), - childItems: map(tree.childItems, item => this.decodeNavigationTree(item, fileName, lineMap)) + childItems: map(tree.childItems, item => this.decodeNavigationTree(item, fileName, lineMap)), }; } @@ -640,9 +737,9 @@ export class SessionClient implements LanguageService { return this.decodeNavigationTree(response.body!, file, lineMap); // TODO: GH#18217 } - private decodeSpan(span: protocol.TextSpan & { file: string }): TextSpan; + private decodeSpan(span: protocol.TextSpan & { file: string; }): TextSpan; private decodeSpan(span: protocol.TextSpan, fileName: string, lineMap?: number[]): TextSpan; - private decodeSpan(span: protocol.TextSpan & { file: string }, fileName?: string, lineMap?: number[]): TextSpan { + private decodeSpan(span: protocol.TextSpan & { file: string; }, fileName?: string, lineMap?: number[]): TextSpan { if (span.start.line === 1 && span.start.offset === 1 && span.end.line === 1 && span.end.offset === 1) { return { start: 0, length: 0 }; } @@ -650,14 +747,17 @@ export class SessionClient implements LanguageService { lineMap = lineMap || this.getLineMap(fileName); return createTextSpanFromBounds( this.lineOffsetToPosition(fileName, span.start, lineMap), - this.lineOffsetToPosition(fileName, span.end, lineMap)); + this.lineOffsetToPosition(fileName, span.end, lineMap), + ); } private decodeLinkDisplayParts(tags: (protocol.JSDocTagInfo | JSDocTagInfo)[]): JSDocTagInfo[] { - return tags.map(tag => typeof tag.text === "string" ? { - ...tag, - text: [textPart(tag.text)] - } : (tag as JSDocTagInfo)); + return tags.map(tag => + typeof tag.text === "string" ? { + ...tag, + text: [textPart(tag.text)], + } : (tag as JSDocTagInfo) + ); } getNameOrDottedNameSpan(_fileName: string, _startPos: number, _endPos: number): TextSpan { @@ -678,31 +778,48 @@ export class SessionClient implements LanguageService { return undefined; } - const { items: encodedItems, applicableSpan: encodedApplicableSpan, selectedItemIndex, argumentIndex, argumentCount } = response.body; + const { + items: encodedItems, + applicableSpan: encodedApplicableSpan, + selectedItemIndex, + argumentIndex, + argumentCount, + } = response.body; const applicableSpan = encodedApplicableSpan as unknown as TextSpan; - const items = (encodedItems as (SignatureHelpItem | protocol.SignatureHelpItem)[]).map(item => ({ ...item, tags: this.decodeLinkDisplayParts(item.tags) })); + const items = (encodedItems as (SignatureHelpItem | protocol.SignatureHelpItem)[]).map(item => ({ + ...item, + tags: this.decodeLinkDisplayParts(item.tags), + })); return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount }; } getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] { - const args: protocol.DocumentHighlightsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), filesToSearch }; + const args: protocol.DocumentHighlightsRequestArgs = { + ...this.createFileLocationRequestArgs(fileName, position), + filesToSearch, + }; - const request = this.processRequest(protocol.CommandTypes.DocumentHighlights, args); + const request = this.processRequest( + protocol.CommandTypes.DocumentHighlights, + args, + ); const response = this.processResponse(request); return response.body!.map(item => ({ // TODO: GH#18217 fileName: item.file, highlightSpans: item.highlightSpans.map(span => ({ textSpan: this.decodeSpan(span, item.file), - kind: span.kind + kind: span.kind, })), })); } getOutliningSpans(file: string): OutliningSpan[] { - const request = this.processRequest(protocol.CommandTypes.GetOutliningSpans, { file }); + const request = this.processRequest(protocol.CommandTypes.GetOutliningSpans, { + file, + }); const response = this.processResponse(request); return response.body!.map(item => ({ @@ -710,7 +827,7 @@ export class SessionClient implements LanguageService { hintSpan: this.decodeSpan(item.hintSpan, file), bannerText: item.bannerText, autoCollapse: item.autoCollapse, - kind: item.kind + kind: item.kind, })); } @@ -718,7 +835,12 @@ export class SessionClient implements LanguageService { return notImplemented(); } - getDocCommentTemplateAtPosition(_fileName: string, _position: number, _options?: DocCommentTemplateOptions, _formatOptions?: FormatCodeSettings): TextInsertion { + getDocCommentTemplateAtPosition( + _fileName: string, + _position: number, + _options?: DocCommentTemplateOptions, + _formatOptions?: FormatCodeSettings, + ): TextInsertion { return notImplemented(); } @@ -738,14 +860,28 @@ export class SessionClient implements LanguageService { return notImplemented(); } - getCodeFixesAtPosition(file: string, start: number, end: number, errorCodes: readonly number[]): readonly CodeFixAction[] { + getCodeFixesAtPosition( + file: string, + start: number, + end: number, + errorCodes: readonly number[], + ): readonly CodeFixAction[] { const args: protocol.CodeFixRequestArgs = { ...this.createFileRangeRequestArgs(file, start, end), errorCodes }; const request = this.processRequest(protocol.CommandTypes.GetCodeFixes, args); const response = this.processResponse(request); - return response.body!.map(({ fixName, description, changes, commands, fixId, fixAllDescription }) => // TODO: GH#18217 - ({ fixName, description, changes: this.convertChanges(changes, file), commands: commands as CodeActionCommand[], fixId, fixAllDescription })); + return response.body!.map(( + { fixName, description, changes, commands, fixId, fixAllDescription }, + ) => // TODO: GH#18217 + ({ + fixName, + description, + changes: this.convertChanges(changes, file), + commands: commands as CodeActionCommand[], + fixId, + fixAllDescription, + })); } getCombinedCodeFix = notImplemented; @@ -770,15 +906,19 @@ export class SessionClient implements LanguageService { text, span: span && { start: this.lineOffsetToPosition(span.file, span.start), - length: this.lineOffsetToPosition(span.file, span.end) - this.lineOffsetToPosition(span.file, span.start), + length: this.lineOffsetToPosition(span.file, span.end) + - this.lineOffsetToPosition(span.file, span.start), }, - file: span && span.file + file: span && span.file, })), }); }); } - private createFileLocationOrRangeRequestArgs(positionOrRange: number | TextRange, fileName: string): protocol.FileLocationOrRangeRequestArgs { + private createFileLocationOrRangeRequestArgs( + positionOrRange: number | TextRange, + fileName: string, + ): protocol.FileLocationOrRangeRequestArgs { return typeof positionOrRange === "number" ? this.createFileLocationRequestArgs(fileName, positionOrRange) : this.createFileRangeRequestArgs(fileName, positionOrRange.pos, positionOrRange.end); @@ -795,7 +935,11 @@ export class SessionClient implements LanguageService { return { file, startLine, startOffset, endLine, endOffset }; } - private createFileLocationRequestArgsWithEndLineAndOffset(file: string, start: number, end: number): protocol.FileLocationRequestArgs & { endLine: number, endOffset: number } { + private createFileLocationRequestArgsWithEndLineAndOffset( + file: string, + start: number, + end: number, + ): protocol.FileLocationRequestArgs & { endLine: number; endOffset: number; } { const { line, offset } = this.positionToOneBasedLineOffset(file, start); const { line: endLine, offset: endOffset } = this.positionToOneBasedLineOffset(file, end); return { file, line, offset, endLine, endOffset }; @@ -807,15 +951,22 @@ export class SessionClient implements LanguageService { preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string, - includeInteractiveActions?: boolean): ApplicableRefactorInfo[] { + includeInteractiveActions?: boolean, + ): ApplicableRefactorInfo[] { if (preferences) { // Temporarily set preferences this.configure(preferences); } - const args: protocol.GetApplicableRefactorsRequestArgs = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName); + const args: protocol.GetApplicableRefactorsRequestArgs = this.createFileLocationOrRangeRequestArgs( + positionOrRange, + fileName, + ); args.triggerReason = triggerReason; args.kind = kind; args.includeInteractiveActions = includeInteractiveActions; - const request = this.processRequest(protocol.CommandTypes.GetApplicableRefactors, args); + const request = this.processRequest( + protocol.CommandTypes.GetApplicableRefactors, + args, + ); const response = this.processResponse(request); if (preferences) { // Restore preferences this.configure(this.preferences || {}); @@ -823,12 +974,18 @@ export class SessionClient implements LanguageService { return response.body!; // TODO: GH#18217 } - getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange): { newFileName: string; files: string[]; } { + getMoveToRefactoringFileSuggestions( + fileName: string, + positionOrRange: number | TextRange, + ): { newFileName: string; files: string[]; } { const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName); - const request = this.processRequest(protocol.CommandTypes.GetMoveToRefactoringFileSuggestions, args); + const request = this.processRequest( + protocol.CommandTypes.GetMoveToRefactoringFileSuggestions, + args, + ); const response = this.processResponse(request); - return { newFileName: response.body?.newFileName, files:response.body?.files }!; + return { newFileName: response.body?.newFileName, files: response.body?.files }!; } getEditsForRefactor( @@ -838,17 +995,23 @@ export class SessionClient implements LanguageService { refactorName: string, actionName: string, preferences: UserPreferences | undefined, - interactiveRefactorArguments?: InteractiveRefactorArguments): RefactorEditInfo { + interactiveRefactorArguments?: InteractiveRefactorArguments, + ): RefactorEditInfo { if (preferences) { // Temporarily set preferences this.configure(preferences); } - const args = - this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetEditsForRefactorRequestArgs; + const args = this.createFileLocationOrRangeRequestArgs( + positionOrRange, + fileName, + ) as protocol.GetEditsForRefactorRequestArgs; args.refactor = refactorName; args.action = actionName; args.interactiveRefactorArguments = interactiveRefactorArguments; - const request = this.processRequest(protocol.CommandTypes.GetEditsForRefactor, args); + const request = this.processRequest( + protocol.CommandTypes.GetEditsForRefactor, + args, + ); const response = this.processResponse(request); if (!response.body) { @@ -888,7 +1051,7 @@ export class SessionClient implements LanguageService { const fileName = edit.fileName; return { fileName, - textChanges: edit.textChanges.map(t => this.convertTextChangeToCodeEdit(t, fileName)) + textChanges: edit.textChanges.map(t => this.convertTextChangeToCodeEdit(t, fileName)), }; }); } @@ -896,14 +1059,14 @@ export class SessionClient implements LanguageService { private convertChanges(changes: protocol.FileCodeEdits[], fileName: string): FileTextChanges[] { return changes.map(change => ({ fileName: change.fileName, - textChanges: change.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, fileName)) + textChanges: change.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, fileName)), })); } convertTextChangeToCodeEdit(change: protocol.CodeEdit, fileName: string): TextChange { return { span: this.decodeSpan(change, fileName), - newText: change.newText ? change.newText : "" + newText: change.newText ? change.newText : "", }; } @@ -917,7 +1080,10 @@ export class SessionClient implements LanguageService { } configurePlugin(pluginName: string, configuration: any): void { - const request = this.processRequest("configurePlugin", { pluginName, configuration }); + const request = this.processRequest("configurePlugin", { + pluginName, + configuration, + }); this.processResponse(request, /*expectEmptyBody*/ true); } @@ -937,8 +1103,15 @@ export class SessionClient implements LanguageService { return notImplemented(); } - getEncodedSemanticClassifications(file: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications { - const request = this.processRequest(protocol.CommandTypes.EncodedSemanticClassificationsFull, { file, start: span.start, length: span.length, format }); + getEncodedSemanticClassifications( + file: string, + span: TextSpan, + format?: SemanticClassificationFormat, + ): Classifications { + const request = this.processRequest( + protocol.CommandTypes.EncodedSemanticClassificationsFull, + { file, start: span.start, length: span.length, format }, + ); const r = this.processResponse(request); return r.body!; } @@ -951,13 +1124,16 @@ export class SessionClient implements LanguageService { kindModifiers: item.kindModifiers, containerName: item.containerName, span: this.decodeSpan(item.span, item.file), - selectionSpan: this.decodeSpan(item.selectionSpan, item.file) + selectionSpan: this.decodeSpan(item.selectionSpan, item.file), }; } prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined { const args = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(protocol.CommandTypes.PrepareCallHierarchy, args); + const request = this.processRequest( + protocol.CommandTypes.PrepareCallHierarchy, + args, + ); const response = this.processResponse(request); return response.body && mapOneOrMany(response.body, item => this.convertCallHierarchyItem(item)); } @@ -965,27 +1141,36 @@ export class SessionClient implements LanguageService { private convertCallHierarchyIncomingCall(item: protocol.CallHierarchyIncomingCall): CallHierarchyIncomingCall { return { from: this.convertCallHierarchyItem(item.from), - fromSpans: item.fromSpans.map(span => this.decodeSpan(span, item.from.file)) + fromSpans: item.fromSpans.map(span => this.decodeSpan(span, item.from.file)), }; } provideCallHierarchyIncomingCalls(fileName: string, position: number) { const args = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(protocol.CommandTypes.ProvideCallHierarchyIncomingCalls, args); + const request = this.processRequest( + protocol.CommandTypes.ProvideCallHierarchyIncomingCalls, + args, + ); const response = this.processResponse(request); return response.body.map(item => this.convertCallHierarchyIncomingCall(item)); } - private convertCallHierarchyOutgoingCall(file: string, item: protocol.CallHierarchyOutgoingCall): CallHierarchyOutgoingCall { + private convertCallHierarchyOutgoingCall( + file: string, + item: protocol.CallHierarchyOutgoingCall, + ): CallHierarchyOutgoingCall { return { to: this.convertCallHierarchyItem(item.to), - fromSpans: item.fromSpans.map(span => this.decodeSpan(span, file)) + fromSpans: item.fromSpans.map(span => this.decodeSpan(span, file)), }; } provideCallHierarchyOutgoingCalls(fileName: string, position: number) { const args = this.createFileLocationRequestArgs(fileName, position); - const request = this.processRequest(protocol.CommandTypes.ProvideCallHierarchyOutgoingCalls, args); + const request = this.processRequest( + protocol.CommandTypes.ProvideCallHierarchyOutgoingCalls, + args, + ); const response = this.processResponse(request); return response.body.map(item => this.convertCallHierarchyOutgoingCall(fileName, item)); } @@ -1006,7 +1191,10 @@ export class SessionClient implements LanguageService { throw new Error("Program objects are not serializable through the server protocol."); } - updateIsDefinitionOfReferencedSymbols(_referencedSymbols: readonly ReferencedSymbol[], _knownSymbolSpans: Set): boolean { + updateIsDefinitionOfReferencedSymbols( + _referencedSymbols: readonly ReferencedSymbol[], + _knownSymbolSpans: Set, + ): boolean { return notImplemented(); } diff --git a/src/harness/collectionsImpl.ts b/src/harness/collectionsImpl.ts index cc43361489205..9c86d021546c3 100644 --- a/src/harness/collectionsImpl.ts +++ b/src/harness/collectionsImpl.ts @@ -44,9 +44,9 @@ export class SortedMap { return index >= 0 ? this._values[index] : undefined; } - public getEntry(key: K): [ K, V ] | undefined { + public getEntry(key: K): [K, V] | undefined { const index = ts.binarySearch(this._keys, key, ts.identity, this._comparer); - return index >= 0 ? [ this._keys[index], this._values[index] ] : undefined; + return index >= 0 ? [this._keys[index], this._values[index]] : undefined; } public set(key: K, value: V) { @@ -112,7 +112,7 @@ export class SortedMap { } } - public * keys() { + public *keys() { const keys = this._keys; const indices = this.getIterationOrder(); const version = this._version; @@ -134,7 +134,7 @@ export class SortedMap { } } - public * values() { + public *values() { const values = this._values; const indices = this.getIterationOrder(); const version = this._version; @@ -156,7 +156,7 @@ export class SortedMap { } } - public * entries() { + public *entries() { const keys = this._keys; const values = this._values; const indices = this.getIterationOrder(); @@ -230,7 +230,7 @@ function insertAt(array: T[], index: number, value: T): void { export class Metadata { private static readonly _undefinedValue = {}; private _parent: Metadata | undefined; - private _map: { [key: string]: any }; + private _map: { [key: string]: any; }; private _version = 0; private _size = -1; private _parentVersion: number | undefined; @@ -300,6 +300,7 @@ export class Metadata { } private static _unescapeKey(text: string) { - return (text.length >= 3 && text.charAt(0) === "_" && text.charAt(1) === "_" && text.charAt(2) === "_" ? text.slice(1) : text); + return (text.length >= 3 && text.charAt(0) === "_" && text.charAt(1) === "_" && text.charAt(2) === "_" + ? text.slice(1) : text); } } diff --git a/src/harness/compilerImpl.ts b/src/harness/compilerImpl.ts index f60a429fc567f..67c442dbe04d0 100644 --- a/src/harness/compilerImpl.ts +++ b/src/harness/compilerImpl.ts @@ -16,13 +16,18 @@ export interface Project { errors?: ts.Diagnostic[]; } -export function readProject(host: fakes.ParseConfigHost, project: string | undefined, existingOptions?: ts.CompilerOptions): Project | undefined { +export function readProject( + host: fakes.ParseConfigHost, + project: string | undefined, + existingOptions?: ts.CompilerOptions, +): Project | undefined { if (project) { project = vpath.isTsConfigFile(project) ? project : vpath.combine(project, "tsconfig.json"); } else { [project] = host.vfs.scanSync(".", "ancestors-or-self", { - accept: (path, stats) => stats.isFile() && host.vfs.stringComparer(vpath.basename(path), "tsconfig.json") === 0 + accept: (path, stats) => + stats.isFile() && host.vfs.stringComparer(vpath.basename(path), "tsconfig.json") === 0, }); } @@ -66,7 +71,13 @@ export class CompilationResult { private _inputs: documents.TextDocument[] = []; private _inputsAndOutputs: collections.SortedMap; - constructor(host: fakes.CompilerHost, options: ts.CompilerOptions, program: ts.Program | undefined, result: ts.EmitResult | undefined, diagnostics: readonly ts.Diagnostic[]) { + constructor( + host: fakes.CompilerHost, + options: ts.CompilerOptions, + program: ts.Program | undefined, + result: ts.EmitResult | undefined, + diagnostics: readonly ts.Diagnostic[], + ) { this.host = host; this.program = program; this.result = result; @@ -74,9 +85,18 @@ export class CompilationResult { this.options = program ? program.getCompilerOptions() : options; // collect outputs - const js = this.js = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); - const dts = this.dts = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); - const maps = this.maps = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); + const js = this.js = new collections.SortedMap({ + comparer: this.vfs.stringComparer, + sort: "insertion", + }); + const dts = this.dts = new collections.SortedMap({ + comparer: this.vfs.stringComparer, + sort: "insertion", + }); + const maps = this.maps = new collections.SortedMap({ + comparer: this.vfs.stringComparer, + sort: "insertion", + }); for (const document of this.host.outputs) { if (vpath.isJavaScript(document.file) || ts.fileExtensionIs(document.file, ts.Extension.Json)) { js.set(document.file, document); @@ -90,7 +110,10 @@ export class CompilationResult { } // correlate inputs and outputs - this._inputsAndOutputs = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); + this._inputsAndOutputs = new collections.SortedMap({ + comparer: this.vfs.stringComparer, + sort: "insertion", + }); if (program) { if (this.options.out || this.options.outFile) { const outFile = vpath.resolve(this.vfs.cwd(), this.options.outFile || this.options.out); @@ -109,7 +132,7 @@ export class CompilationResult { inputs, js: js.get(outFile), dts: dts.get(vpath.changeExtension(outFile, ".d.ts")), - map: maps.get(outFile + ".map") + map: maps.get(outFile + ".map"), }; if (outputs.js) this._inputsAndOutputs.set(outputs.js.file, outputs); @@ -130,8 +153,13 @@ export class CompilationResult { const outputs: CompilationOutput = { inputs: [input], js: js.get(this.getOutputPath(sourceFile.fileName, extname)), - dts: dts.get(this.getOutputPath(sourceFile.fileName, ts.getDeclarationEmitExtensionForPath(sourceFile.fileName))), - map: maps.get(this.getOutputPath(sourceFile.fileName, extname + ".map")) + dts: dts.get( + this.getOutputPath( + sourceFile.fileName, + ts.getDeclarationEmitExtensionForPath(sourceFile.fileName), + ), + ), + map: maps.get(this.getOutputPath(sourceFile.fileName, extname + ".map")), }; this._inputsAndOutputs.set(sourceFile.fileName, outputs); @@ -191,7 +219,12 @@ export class CompilationResult { public getSourceMapRecord(): string | undefined { const maps = this.result!.sourceMaps; if (maps && maps.length > 0) { - return Harness.SourceMapRecorder.getSourceMapRecord(maps, this.program!, ts.arrayFrom(this.js.values()).filter(d => !ts.fileExtensionIs(d.file, ts.Extension.Json)), ts.arrayFrom(this.dts.values())); + return Harness.SourceMapRecorder.getSourceMapRecord( + maps, + this.program!, + ts.arrayFrom(this.js.values()).filter(d => !ts.fileExtensionIs(d.file, ts.Extension.Json)), + ts.arrayFrom(this.dts.values()), + ); } } @@ -213,7 +246,9 @@ export class CompilationResult { } else { path = vpath.resolve(this.vfs.cwd(), path); - const outDir = ext === ".d.ts" || ext === ".d.mts" || ext === ".d.cts" || (ext.endsWith(".ts") || ts.stringContains(ext, ".d.")) ? this.options.declarationDir || this.options.outDir : this.options.outDir; + const outDir = ext === ".d.ts" || ext === ".d.mts" || ext === ".d.cts" + || (ext.endsWith(".ts") || ts.stringContains(ext, ".d.")) + ? this.options.declarationDir || this.options.outDir : this.options.outDir; if (outDir) { const common = this.commonSourceDirectory; if (common) { @@ -241,12 +276,23 @@ export class CompilationResult { } } -export function compileFiles(host: fakes.CompilerHost, rootFiles: string[] | undefined, compilerOptions: ts.CompilerOptions, typeScriptVersion?: string): CompilationResult { +export function compileFiles( + host: fakes.CompilerHost, + rootFiles: string[] | undefined, + compilerOptions: ts.CompilerOptions, + typeScriptVersion?: string, +): CompilationResult { if (compilerOptions.project || !rootFiles || rootFiles.length === 0) { const project = readProject(host.parseConfigHost, compilerOptions.project, compilerOptions); if (project) { if (project.errors && project.errors.length > 0) { - return new CompilationResult(host, compilerOptions, /*program*/ undefined, /*result*/ undefined, project.errors); + return new CompilationResult( + host, + compilerOptions, + /*program*/ undefined, + /*result*/ undefined, + project.errors, + ); } if (project.config) { rootFiles = project.config.fileNames; @@ -257,15 +303,25 @@ export function compileFiles(host: fakes.CompilerHost, rootFiles: string[] | und } // establish defaults (aligns with old harness) - if (compilerOptions.target === undefined && compilerOptions.module !== ts.ModuleKind.Node16 && compilerOptions.module !== ts.ModuleKind.NodeNext) compilerOptions.target = ts.ScriptTarget.ES3; + if ( + compilerOptions.target === undefined && compilerOptions.module !== ts.ModuleKind.Node16 + && compilerOptions.module !== ts.ModuleKind.NodeNext + ) compilerOptions.target = ts.ScriptTarget.ES3; if (compilerOptions.newLine === undefined) compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed; if (compilerOptions.skipDefaultLibCheck === undefined) compilerOptions.skipDefaultLibCheck = true; if (compilerOptions.noErrorTruncation === undefined) compilerOptions.noErrorTruncation = true; // pre-emit/post-emit error comparison requires declaration emit twice, which can be slow. If it's unlikely to flag any error consistency issues // and if the test is running `skipLibCheck` - an indicator that we want the tets to run quickly - skip the before/after error comparison, too - const skipErrorComparison = ts.length(rootFiles) >= 100 || (!!compilerOptions.skipLibCheck && !!compilerOptions.declaration); - const preProgram = !skipErrorComparison ? ts.createProgram({ rootNames: rootFiles || [], options: { ...compilerOptions, configFile: compilerOptions.configFile, traceResolution: false }, host, typeScriptVersion }) : undefined; + const skipErrorComparison = ts.length(rootFiles) >= 100 + || (!!compilerOptions.skipLibCheck && !!compilerOptions.declaration); + const preProgram = !skipErrorComparison + ? ts.createProgram({ + rootNames: rootFiles || [], + options: { ...compilerOptions, configFile: compilerOptions.configFile, traceResolution: false }, + host, + typeScriptVersion, + }) : undefined; const preErrors = preProgram && ts.getPreEmitDiagnostics(preProgram); const program = ts.createProgram({ rootNames: rootFiles || [], options: compilerOptions, host, typeScriptVersion }); @@ -273,22 +329,27 @@ export function compileFiles(host: fakes.CompilerHost, rootFiles: string[] | und const postErrors = ts.getPreEmitDiagnostics(program); const longerErrors = ts.length(preErrors) > postErrors.length ? preErrors : postErrors; const shorterErrors = longerErrors === preErrors ? postErrors : preErrors; - const errors = preErrors && (preErrors.length !== postErrors.length) ? [...shorterErrors!, + const errors = preErrors && (preErrors.length !== postErrors.length) ? [ + ...shorterErrors!, ts.addRelatedInfo( ts.createCompilerDiagnostic({ category: ts.DiagnosticCategory.Error, code: -1, key: "-1", - message: `Pre-emit (${preErrors.length}) and post-emit (${postErrors.length}) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here!` + message: + `Pre-emit (${preErrors.length}) and post-emit (${postErrors.length}) diagnostic counts do not match! This can indicate that a semantic _error_ was added by the emit resolver - such an error may not be reflected on the command line or in the editor, but may be captured in a baseline here!`, }), ts.createCompilerDiagnostic({ category: ts.DiagnosticCategory.Error, code: -1, key: "-1", - message: `The excess diagnostics are:` + message: `The excess diagnostics are:`, }), - ...ts.filter(longerErrors!, p => !ts.some(shorterErrors, p2 => ts.compareDiagnostics(p, p2) === ts.Comparison.EqualTo)) - ) + ...ts.filter( + longerErrors!, + p => !ts.some(shorterErrors, p2 => ts.compareDiagnostics(p, p2) === ts.Comparison.EqualTo), + ), + ), ] : postErrors; return new CompilationResult(host, compilerOptions, program, emitResult, errors); } diff --git a/src/harness/documentsUtil.ts b/src/harness/documentsUtil.ts index fa00ff2d06213..4a23ac5818069 100644 --- a/src/harness/documentsUtil.ts +++ b/src/harness/documentsUtil.ts @@ -27,7 +27,8 @@ export class TextDocument { file.unitName, file.content, file.fileOptions && Object.keys(file.fileOptions) - .reduce((meta, key) => meta.set(key, file.fileOptions[key]), new Map())); + .reduce((meta, key) => meta.set(key, file.fileOptions[key]), new Map()), + ); } public asTestFile() { @@ -35,7 +36,7 @@ export class TextDocument { unitName: this.file, content: this.text, fileOptions: ts.arrayFrom(this.meta) - .reduce((obj, [key, value]) => (obj[key] = value, obj), {} as Record) + .reduce((obj, [key, value]) => (obj[key] = value, obj), {} as Record), }); } } @@ -112,7 +113,14 @@ export class SourceMap { sourceColumn += segment[3]; } - const mapping: Mapping = { mappingIndex: mappings.length, emittedLine, emittedColumn, sourceIndex, sourceLine, sourceColumn }; + const mapping: Mapping = { + mappingIndex: mappings.length, + emittedLine, + emittedColumn, + sourceIndex, + sourceLine, + sourceColumn, + }; if (segment.length === 5) { nameIndex += segment[4]; mapping.nameIndex = nameIndex; @@ -120,11 +128,14 @@ export class SourceMap { mappings.push(mapping); - const mappingsForEmittedLine = this._emittedLineMappings[mapping.emittedLine] || (this._emittedLineMappings[mapping.emittedLine] = []); + const mappingsForEmittedLine = this._emittedLineMappings[mapping.emittedLine] + || (this._emittedLineMappings[mapping.emittedLine] = []); mappingsForEmittedLine.push(mapping); - const mappingsForSource = this._sourceLineMappings[mapping.sourceIndex] || (this._sourceLineMappings[mapping.sourceIndex] = []); - const mappingsForSourceLine = mappingsForSource[mapping.sourceLine] || (mappingsForSource[mapping.sourceLine] = []); + const mappingsForSource = this._sourceLineMappings[mapping.sourceIndex] + || (this._sourceLineMappings[mapping.sourceIndex] = []); + const mappingsForSourceLine = mappingsForSource[mapping.sourceLine] + || (mappingsForSource[mapping.sourceLine] = []); mappingsForSourceLine.push(mapping); } else if (match[2]) { diff --git a/src/harness/evaluatorImpl.ts b/src/harness/evaluatorImpl.ts index 00a4d80e90c73..257550766b094 100644 --- a/src/harness/evaluatorImpl.ts +++ b/src/harness/evaluatorImpl.ts @@ -33,23 +33,32 @@ for (const symbolName of symbolNames) { } } -export function evaluateTypeScript(source: string | { files: vfs.FileSet, rootFiles: string[], main: string }, options?: ts.CompilerOptions, globals?: Record) { - if (typeof source === "string") source = { files: { [sourceFile]: source }, rootFiles: [sourceFile], main: sourceFile }; +export function evaluateTypeScript( + source: string | { files: vfs.FileSet; rootFiles: string[]; main: string; }, + options?: ts.CompilerOptions, + globals?: Record, +) { + if (typeof source === "string") { + source = { files: { [sourceFile]: source }, rootFiles: [sourceFile], main: sourceFile }; + } const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { files: source.files }); const compilerOptions: ts.CompilerOptions = { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS, lib: ["lib.esnext.d.ts", "lib.dom.d.ts"], - ...options + ...options, }; const host = new fakes.CompilerHost(fs, compilerOptions); const result = compiler.compileFiles(host, source.rootFiles, compilerOptions); if (ts.some(result.diagnostics)) { - assert.ok(/*value*/ false, "Syntax error in evaluation source text:\n" + ts.formatDiagnostics(result.diagnostics, { - getCanonicalFileName: file => file, - getCurrentDirectory: () => "", - getNewLine: () => "\n" - })); + assert.ok( + /*value*/ false, + "Syntax error in evaluation source text:\n" + ts.formatDiagnostics(result.diagnostics, { + getCanonicalFileName: file => file, + getCurrentDirectory: () => "", + getNewLine: () => "\n", + }), + ); } const output = result.getOutput(source.main, "js")!; @@ -65,7 +74,11 @@ export function evaluateJavaScript(sourceText: string, globals?: Record): Loader { +function getLoader( + compilerOptions: ts.CompilerOptions, + fs: vfs.FileSystem, + globals: Record, +): Loader { const moduleKind = ts.getEmitModuleKind(compilerOptions); switch (moduleKind) { case ts.ModuleKind.UMD: @@ -186,10 +199,27 @@ class CommonJsLoader extends Loader { } const base = vpath.dirname(file); const localRequire = (id: string) => this.import(id, base); - const evaluateText = `(function (module, exports, require, __dirname, __filename, ${globalNames.join(", ")}) { ${text}\n})`; + const evaluateText = `(function (module, exports, require, __dirname, __filename, ${ + globalNames.join(", ") + }) { ${text}\n})`; // eslint-disable-next-line no-eval - const evaluateThunk = (void 0, eval)(evaluateText) as (module: any, exports: any, require: (id: string) => any, dirname: string, filename: string, ...globalArgs: any[]) => void; - evaluateThunk.call(this.globals, module, module.exports, localRequire, vpath.dirname(file), file, ...globalArgs); + const evaluateThunk = (void 0, eval)(evaluateText) as ( + module: any, + exports: any, + require: (id: string) => any, + dirname: string, + filename: string, + ...globalArgs: any[] + ) => void; + evaluateThunk.call( + this.globals, + module, + module.exports, + localRequire, + vpath.dirname(file), + file, + ...globalArgs, + ); } } @@ -234,7 +264,10 @@ interface SystemModuleContext { meta: any; } -type SystemModuleRegisterCallback = (exporter: SystemModuleExporter, context: SystemModuleContext) => SystemModuleDeclaration; +type SystemModuleRegisterCallback = ( + exporter: SystemModuleExporter, + context: SystemModuleContext, +) => SystemModuleDeclaration; type SystemModuleDependencySetter = (dependency: any) => void; interface SystemModuleDeclaration { @@ -256,7 +289,7 @@ class SystemLoader extends Loader { dependers: [], setters: [], hasExports: false, - state: SystemModuleState.Uninstantiated + state: SystemModuleState.Uninstantiated, }; } @@ -294,7 +327,7 @@ class SystemLoader extends Loader { } } const localSystem: SystemGlobal = { - register: (dependencies, declare) => this.instantiateModule(module, dependencies, declare) + register: (dependencies, declare) => this.instantiateModule(module, dependencies, declare), }; const evaluateText = `(function (System, ${globalNames.join(", ")}) { ${text}\n})`; try { @@ -308,7 +341,11 @@ class SystemLoader extends Loader { } } - private instantiateModule(module: SystemModule, dependencies: string[], registration?: SystemModuleRegisterCallback) { + private instantiateModule( + module: SystemModule, + dependencies: string[], + registration?: SystemModuleRegisterCallback, + ) { function exporter(name: string, value: T): T; function exporter(value: T): T; function exporter(...args: [string, T] | [T]) { @@ -330,10 +367,15 @@ class SystemLoader extends Loader { } const context: SystemModuleContext = { - import: (_id) => { throw new Error("Dynamic import not implemented."); }, + import: _id => { + throw new Error("Dynamic import not implemented."); + }, meta: { - url: ts.isUrl(module.file) ? module.file : `file:///${ts.normalizeSlashes(module.file).replace(/^\//, "").split("/").map(encodeURIComponent).join("/")}` - } + url: ts.isUrl(module.file) ? module.file + : `file:///${ + ts.normalizeSlashes(module.file).replace(/^\//, "").split("/").map(encodeURIComponent).join("/") + }`, + }, }; module.requestedDependencies = dependencies; @@ -512,9 +554,15 @@ type AmdDefineArgsUnnamedModuleNoDependencies = [declare: AmdModuleDeclaration]; type AmdDefineArgsUnnamedModule = [dependencies: string[], declare: AmdModuleDeclaration]; type AmdDefineArgsNamedModuleNoDependencies = [id: string, declare: AmdModuleDeclaration]; type AmdDefineArgsNamedModule = [id: string, dependencies: string[], declare: AmdModuleDeclaration]; -type AmdDefineArgs = AmdDefineArgsUnnamedModuleNoDependencies | AmdDefineArgsUnnamedModule | AmdDefineArgsNamedModuleNoDependencies | AmdDefineArgsNamedModule; - -function isAmdDefineArgsUnnamedModuleNoDependencies(args: AmdDefineArgs): args is AmdDefineArgsUnnamedModuleNoDependencies { +type AmdDefineArgs = + | AmdDefineArgsUnnamedModuleNoDependencies + | AmdDefineArgsUnnamedModule + | AmdDefineArgsNamedModuleNoDependencies + | AmdDefineArgsNamedModule; + +function isAmdDefineArgsUnnamedModuleNoDependencies( + args: AmdDefineArgs, +): args is AmdDefineArgsUnnamedModuleNoDependencies { return args.length === 1; } diff --git a/src/harness/fakesHosts.ts b/src/harness/fakesHosts.ts index 6155a2622b13f..bd14ef2d89f89 100644 --- a/src/harness/fakesHosts.ts +++ b/src/harness/fakesHosts.ts @@ -103,8 +103,24 @@ export class System implements ts.System { return result; } - public readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { - return ts.matchFiles(path, extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), depth, path => this.getAccessibleFileSystemEntries(path), path => this.realpath(path)); + public readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { + return ts.matchFiles( + path, + extensions, + exclude, + include, + this.useCaseSensitiveFileNames, + this.getCurrentDirectory(), + depth, + path => this.getAccessibleFileSystemEntries(path), + path => this.realpath(path), + ); } public getAccessibleFileSystemEntries(path: string): ts.FileSystemEntries { @@ -218,7 +234,13 @@ export class ParseConfigHost implements ts.ParseConfigHost { return this.sys.readFile(path); } - public readDirectory(path: string, extensions: string[], excludes: string[], includes: string[], depth: number): string[] { + public readDirectory( + path: string, + extensions: string[], + excludes: string[], + includes: string[], + depth: number, + ): string[] { return this.sys.readDirectory(path, extensions, excludes, includes, depth); } @@ -256,7 +278,10 @@ export class CompilerHost implements ts.CompilerHost { this.sys = sys; this.defaultLibLocation = sys.vfs.meta.get("defaultLibLocation") || ""; this._newLine = ts.getNewLineCharacter(options); - this._sourceFiles = new collections.SortedMap({ comparer: sys.vfs.stringComparer, sort: "insertion" }); + this._sourceFiles = new collections.SortedMap({ + comparer: sys.vfs.stringComparer, + sort: "insertion", + }); this._setParentNodes = setParentNodes; this._outputsMap = new collections.SortedMap(this.vfs.stringComparer); } @@ -309,7 +334,13 @@ export class CompilerHost implements ts.CompilerHost { return this.sys.getDirectories(path); } - public readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { + public readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { return this.sys.readDirectory(path, extensions, exclude, include, depth); } @@ -361,7 +392,8 @@ export class CompilerHost implements ts.CompilerHost { // reused across multiple tests. In that case, we cache the SourceFile we parse // so that it can be reused across multiple tests to avoid the cost of // repeatedly parsing the same file over and over (such as lib.d.ts). - const cacheKey = this.vfs.shadowRoot && `SourceFile[languageVersion=${languageVersion},setParentNodes=${this._setParentNodes}]`; + const cacheKey = this.vfs.shadowRoot + && `SourceFile[languageVersion=${languageVersion},setParentNodes=${this._setParentNodes}]`; if (cacheKey) { const meta = this.vfs.filemeta(canonicalFileName); const sourceFileFromMetadata = meta.get(cacheKey) as ts.SourceFile | undefined; @@ -371,7 +403,12 @@ export class CompilerHost implements ts.CompilerHost { } } - const parsed = ts.createSourceFile(fileName, content, languageVersion, this._setParentNodes || this.shouldAssertInvariants); + const parsed = ts.createSourceFile( + fileName, + content, + languageVersion, + this._setParentNodes || this.shouldAssertInvariants, + ); if (this.shouldAssertInvariants) { Utils.assertInvariants(parsed, /*parent*/ undefined); } @@ -385,10 +422,13 @@ export class CompilerHost implements ts.CompilerHost { let fs = this.vfs; while (fs.shadowRoot) { try { - const shadowRootStats = fs.shadowRoot.existsSync(canonicalFileName) ? fs.shadowRoot.statSync(canonicalFileName) : undefined!; // TODO: GH#18217 - if (shadowRootStats.dev !== stats.dev || - shadowRootStats.ino !== stats.ino || - shadowRootStats.mtimeMs !== stats.mtimeMs) { + const shadowRootStats = fs.shadowRoot.existsSync(canonicalFileName) + ? fs.shadowRoot.statSync(canonicalFileName) : undefined!; // TODO: GH#18217 + if ( + shadowRootStats.dev !== stats.dev + || shadowRootStats.ino !== stats.ino + || shadowRootStats.mtimeMs !== stats.mtimeMs + ) { break; } @@ -425,7 +465,7 @@ export interface ExpectedDiagnosticRelatedInformation extends ExpectedDiagnostic export enum DiagnosticKind { Error = "Error", - Status = "Status" + Status = "Status", } export interface ExpectedErrorDiagnostic extends ExpectedDiagnosticRelatedInformation { relatedInformation?: ExpectedDiagnosticRelatedInformation[]; @@ -465,7 +505,9 @@ function expectedDiagnosticMessageChainToText({ message, next }: ExpectedDiagnos return text; } -function expectedDiagnosticRelatedInformationToText({ location, ...diagnosticMessage }: ExpectedDiagnosticRelatedInformation) { +function expectedDiagnosticRelatedInformationToText( + { location, ...diagnosticMessage }: ExpectedDiagnosticRelatedInformation, +) { const text = expectedDiagnosticMessageChainToText(diagnosticMessage); if (location) { const { file, start, length } = location; @@ -474,7 +516,9 @@ function expectedDiagnosticRelatedInformationToText({ location, ...diagnosticMes return text; } -function expectedErrorDiagnosticToText({ relatedInformation, ...diagnosticRelatedInformation }: ExpectedErrorDiagnostic) { +function expectedErrorDiagnosticToText( + { relatedInformation, ...diagnosticRelatedInformation }: ExpectedErrorDiagnostic, +) { let text = `${DiagnosticKind.Error}!: ${expectedDiagnosticRelatedInformationToText(diagnosticRelatedInformation)}`; if (relatedInformation) { for (const kid of relatedInformation) { @@ -486,12 +530,12 @@ function expectedErrorDiagnosticToText({ relatedInformation, ...diagnosticRelate } function expectedDiagnosticToText(errorOrStatus: ExpectedDiagnostic) { - return ts.isArray(errorOrStatus) ? - `${DiagnosticKind.Status}!: ${expectedDiagnosticMessageToText(errorOrStatus)}` : - expectedErrorDiagnosticToText(errorOrStatus); + return ts.isArray(errorOrStatus) + ? `${DiagnosticKind.Status}!: ${expectedDiagnosticMessageToText(errorOrStatus)}` + : expectedErrorDiagnosticToText(errorOrStatus); } -function diagnosticMessageChainToText({ messageText, next}: ts.DiagnosticMessageChain, indent = 0) { +function diagnosticMessageChainToText({ messageText, next }: ts.DiagnosticMessageChain, indent = 0) { let text = indentedText(indent, messageText); if (next) { indent++; @@ -501,15 +545,17 @@ function diagnosticMessageChainToText({ messageText, next}: ts.DiagnosticMessage } function diagnosticRelatedInformationToText({ file, start, length, messageText }: ts.DiagnosticRelatedInformation) { - const text = typeof messageText === "string" ? - messageText : - diagnosticMessageChainToText(messageText); - return file ? - `${file.fileName}(${start}:${length}):: ${text}` : - text; + const text = typeof messageText === "string" + ? messageText + : diagnosticMessageChainToText(messageText); + return file + ? `${file.fileName}(${start}:${length}):: ${text}` + : text; } -function diagnosticToText({ kind, diagnostic: { relatedInformation, ...diagnosticRelatedInformation } }: SolutionBuilderDiagnostic) { +function diagnosticToText( + { kind, diagnostic: { relatedInformation, ...diagnosticRelatedInformation } }: SolutionBuilderDiagnostic, +) { let text = `${kind}!: ${diagnosticRelatedInformationToText(diagnosticRelatedInformation)}`; if (relatedInformation) { for (const kid of relatedInformation) { @@ -556,12 +602,23 @@ export function patchHostForBuildInfoWrite(sys: T, version: export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost { createProgram: ts.CreateProgram; - private constructor(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram) { + private constructor( + sys: System | vfs.FileSystem, + options?: ts.CompilerOptions, + setParentNodes?: boolean, + createProgram?: ts.CreateProgram, + ) { super(sys, options, setParentNodes); - this.createProgram = createProgram || ts.createEmitAndSemanticDiagnosticsBuilderProgram as unknown as ts.CreateProgram; + this.createProgram = createProgram + || ts.createEmitAndSemanticDiagnosticsBuilderProgram as unknown as ts.CreateProgram; } - static create(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram) { + static create( + sys: System | vfs.FileSystem, + options?: ts.CompilerOptions, + setParentNodes?: boolean, + createProgram?: ts.CreateProgram, + ) { const host = new SolutionBuilderHost(sys, options, setParentNodes, createProgram); patchHostForBuildInfoReadWrite(host.sys); return host; @@ -588,18 +645,26 @@ export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuil assertDiagnosticMessages(...expectedDiagnostics: ExpectedDiagnostic[]) { const actual = this.diagnostics.slice().map(diagnosticToText); const expected = expectedDiagnostics.map(expectedDiagnosticToText); - assert.deepEqual(actual, expected, `Diagnostic arrays did not match: + assert.deepEqual( + actual, + expected, + `Diagnostic arrays did not match: Actual: ${JSON.stringify(actual, /*replacer*/ undefined, " ")} -Expected: ${JSON.stringify(expected, /*replacer*/ undefined, " ")}`); +Expected: ${JSON.stringify(expected, /*replacer*/ undefined, " ")}`, + ); } assertErrors(...expectedDiagnostics: ExpectedErrorDiagnostic[]) { const actual = this.diagnostics.filter(d => d.kind === DiagnosticKind.Error).map(diagnosticToText); const expected = expectedDiagnostics.map(expectedDiagnosticToText); - assert.deepEqual(actual, expected, `Diagnostics arrays did not match: + assert.deepEqual( + actual, + expected, + `Diagnostics arrays did not match: Actual: ${JSON.stringify(actual, /*replacer*/ undefined, " ")} Expected: ${JSON.stringify(expected, /*replacer*/ undefined, " ")} -Actual All:: ${JSON.stringify(this.diagnostics.slice().map(diagnosticToText), /*replacer*/ undefined, " ")}`); +Actual All:: ${JSON.stringify(this.diagnostics.slice().map(diagnosticToText), /*replacer*/ undefined, " ")}`, + ); } printDiagnostics(header = "== Diagnostics ==") { @@ -614,4 +679,3 @@ Actual All:: ${JSON.stringify(this.diagnostics.slice().map(diagnosticToText), /* return this.sys.now(); } } - diff --git a/src/harness/findUpDir.ts b/src/harness/findUpDir.ts index 52f6d766668ca..bee3c14cce20e 100644 --- a/src/harness/findUpDir.ts +++ b/src/harness/findUpDir.ts @@ -1,4 +1,6 @@ -import { existsSync } from "fs"; +import { + existsSync, +} from "fs"; import { dirname, join, diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 634a80bdf0871..ea9d22d8b0ae8 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -12,7 +12,7 @@ export const enum FourSlashTestType { Native, Shims, ShimsWithPreprocess, - Server + Server, } // Represents a parsed source file with metadata @@ -86,17 +86,27 @@ export interface TextSpan { // Add cases into convertGlobalOptionsToCompilationsSettings function for the compiler to acknowledge such option from meta data const enum MetadataOptionNames { baselineFile = "baselinefile", - emitThisFile = "emitthisfile", // This flag is used for testing getEmitOutput feature. It allows test-cases to indicate what file to be output in multiple files project + emitThisFile = "emitthisfile", // This flag is used for testing getEmitOutput feature. It allows test-cases to indicate what file to be output in multiple files project fileName = "filename", - resolveReference = "resolvereference", // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file + resolveReference = "resolvereference", // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file symlink = "symlink", } // List of allowed metadata names -const fileMetadataNames = [MetadataOptionNames.fileName, MetadataOptionNames.emitThisFile, MetadataOptionNames.resolveReference, MetadataOptionNames.symlink]; - -function convertGlobalOptionsToCompilerOptions(globalOptions: Harness.TestCaseParser.CompilerSettings): ts.CompilerOptions { - const settings: ts.CompilerOptions = { target: ts.ScriptTarget.ES5, newLine: ts.NewLineKind.CarriageReturnLineFeed }; +const fileMetadataNames = [ + MetadataOptionNames.fileName, + MetadataOptionNames.emitThisFile, + MetadataOptionNames.resolveReference, + MetadataOptionNames.symlink, +]; + +function convertGlobalOptionsToCompilerOptions( + globalOptions: Harness.TestCaseParser.CompilerSettings, +): ts.CompilerOptions { + const settings: ts.CompilerOptions = { + target: ts.ScriptTarget.ES5, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }; Harness.Compiler.setCompilerOptionsFromHarnessSetting(globalOptions, settings); return settings; } @@ -105,7 +115,11 @@ function isMarker(x: Marker | Range): x is Marker { return (x as Marker).position !== undefined; } -function convertDocumentSpanToString(span: T, prefix?: string, ignoredProperties?: readonly string[]) { +function convertDocumentSpanToString( + span: T, + prefix?: string, + ignoredProperties?: readonly string[], +) { let text = prefix || ""; for (const p in span) { if (p === "textSpan" || p === "fileName" || p === "contextSpan") continue; @@ -186,7 +200,9 @@ export function verifyOperationIsCancelled(f: () => void) { throw new Error("Operation should be cancelled"); } -export function ignoreInterpolations(diagnostic: string | ts.DiagnosticMessage): FourSlashInterface.DiagnosticIgnoredInterpolations { +export function ignoreInterpolations( + diagnostic: string | ts.DiagnosticMessage, +): FourSlashInterface.DiagnosticIgnoredInterpolations { return { template: typeof diagnostic === "string" ? diagnostic : diagnostic.message }; } @@ -199,7 +215,7 @@ function createScriptSnapShot(sourceText: string): ts.IScriptSnapshot { const enum CallHierarchyItemDirection { Root, Incoming, - Outgoing + Outgoing, } export class TestState { @@ -224,7 +240,7 @@ export class TestState { public formatCodeSettings: ts.FormatCodeSettings; - private inputFiles = new Map(); // Map between inputFile's fileName and its content for easily looking up when resolving references + private inputFiles = new Map(); // Map between inputFile's fileName and its content for easily looking up when resolving references private static getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[] | undefined) { let result = ""; @@ -263,14 +279,26 @@ export class TestState { } } - private getLanguageServiceAdapter(testType: FourSlashTestType, cancellationToken: TestCancellationToken, compilationOptions: ts.CompilerOptions): Harness.LanguageService.LanguageServiceAdapter { + private getLanguageServiceAdapter( + testType: FourSlashTestType, + cancellationToken: TestCancellationToken, + compilationOptions: ts.CompilerOptions, + ): Harness.LanguageService.LanguageServiceAdapter { switch (testType) { case FourSlashTestType.Native: return new Harness.LanguageService.NativeLanguageServiceAdapter(cancellationToken, compilationOptions); case FourSlashTestType.Shims: - return new Harness.LanguageService.ShimLanguageServiceAdapter(/*preprocessToResolve*/ false, cancellationToken, compilationOptions); + return new Harness.LanguageService.ShimLanguageServiceAdapter( + /*preprocessToResolve*/ false, + cancellationToken, + compilationOptions, + ); case FourSlashTestType.ShimsWithPreprocess: - return new Harness.LanguageService.ShimLanguageServiceAdapter(/*preprocessToResolve*/ true, cancellationToken, compilationOptions); + return new Harness.LanguageService.ShimLanguageServiceAdapter( + /*preprocessToResolve*/ true, + cancellationToken, + compilationOptions, + ); case FourSlashTestType.Server: return new Harness.LanguageService.ServerLanguageServiceAdapter(cancellationToken, compilationOptions); default: @@ -278,7 +306,12 @@ export class TestState { } } - constructor(private originalInputFileName: string, private basePath: string, private testType: FourSlashTestType, public testData: FourSlashData) { + constructor( + private originalInputFileName: string, + private basePath: string, + private testType: FourSlashTestType, + public testData: FourSlashData, + ) { // Create a new Services Adapter this.cancellationToken = new TestCancellationToken(); let compilationOptions = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions); @@ -300,7 +333,11 @@ export class TestState { // Extend our existing compiler options so that we can also support tsconfig only options if (configJson.config.compilerOptions) { const baseDirectory = ts.normalizePath(ts.getDirectoryPath(file.fileName)); - const tsConfig = ts.convertCompilerOptionsFromJson(configJson.config.compilerOptions, baseDirectory, file.fileName); + const tsConfig = ts.convertCompilerOptionsFromJson( + configJson.config.compilerOptions, + baseDirectory, + file.fileName, + ); if (!tsConfig.errors || !tsConfig.errors.length) { compilationOptions = ts.extend(tsConfig.options, compilationOptions); @@ -314,7 +351,9 @@ export class TestState { } else if (startResolveFileRef) { // If entry point for resolving file references is already specified, report duplication error - throw new Error("There exists a Fourslash file which has resolveReference flag specified; remove duplicated resolveReference flag"); + throw new Error( + "There exists a Fourslash file which has resolveReference flag specified; remove duplicated resolveReference flag", + ); } } @@ -329,26 +368,48 @@ export class TestState { const fs = new vfs.FileSystem(/*ignoreCase*/ true, { cwd: baseDir, files }); const host = new fakes.ParseConfigHost(fs); const jsonSourceFile = ts.parseJsonText(configFileName, this.inputFiles.get(configFileName)!); - configParseResult = ts.parseJsonSourceFileConfigFileContent(jsonSourceFile, host, baseDir, compilationOptions, configFileName); + configParseResult = ts.parseJsonSourceFileConfigFileContent( + jsonSourceFile, + host, + baseDir, + compilationOptions, + configFileName, + ); compilationOptions = configParseResult.options; } if (compilationOptions.typeRoots) { - compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => ts.getNormalizedAbsolutePath(p, this.basePath)); + compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => + ts.getNormalizedAbsolutePath(p, this.basePath) + ); } - const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions); + const languageServiceAdapter = this.getLanguageServiceAdapter( + testType, + this.cancellationToken, + compilationOptions, + ); this.languageServiceAdapterHost = languageServiceAdapter.getHost(); this.languageService = memoWrap(languageServiceAdapter.getLanguageService(), this); // Wrap the LS to cache some expensive operations certain tests call repeatedly if (this.testType === FourSlashTestType.Server) { - this.assertTextConsistent = fileName => (languageServiceAdapter as Harness.LanguageService.ServerLanguageServiceAdapter).assertTextConsistent(fileName); + this.assertTextConsistent = fileName => + (languageServiceAdapter as Harness.LanguageService.ServerLanguageServiceAdapter).assertTextConsistent( + fileName, + ); } if (startResolveFileRef) { // Add the entry-point file itself into the languageServiceShimHost - this.languageServiceAdapterHost.addScript(startResolveFileRef.fileName, startResolveFileRef.content, /*isRootFile*/ true); + this.languageServiceAdapterHost.addScript( + startResolveFileRef.fileName, + startResolveFileRef.content, + /*isRootFile*/ true, + ); - const resolvedResult = languageServiceAdapter.getPreProcessedFileInfo(startResolveFileRef.fileName, startResolveFileRef.content); + const resolvedResult = languageServiceAdapter.getPreProcessedFileInfo( + startResolveFileRef.fileName, + startResolveFileRef.content, + ); const referencedFiles: ts.FileReference[] = resolvedResult.referencedFiles; const importedFiles: ts.FileReference[] = resolvedResult.importedFiles; @@ -370,8 +431,11 @@ export class TestState { // Check if no-default-lib flag is false and if so add default library if (!resolvedResult.isLibFile) { - this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName, - Harness.Compiler.getDefaultLibrarySourceFile()!.text, /*isRootFile*/ false); + this.languageServiceAdapterHost.addScript( + Harness.Compiler.defaultLibFileName, + Harness.Compiler.getDefaultLibrarySourceFile()!.text, + /*isRootFile*/ false, + ); compilationOptions.lib?.forEach(fileName => { const libFile = Harness.Compiler.getDefaultLibrarySourceFile(fileName); @@ -387,9 +451,10 @@ export class TestState { this.inputFiles.forEach((file, fileName) => { if (!Harness.isDefaultLibraryFile(fileName)) { // all files if config file not specified, otherwise root files from the config and typings cache files are root files - const isRootFile = !configParseResult || - ts.contains(configParseResult.fileNames, fileName) || - (ts.isDeclarationFileName(fileName) && ts.containsPath("/Library/Caches/typescript", fileName)); + const isRootFile = !configParseResult + || ts.contains(configParseResult.fileNames, fileName) + || (ts.isDeclarationFileName(fileName) + && ts.containsPath("/Library/Caches/typescript", fileName)); this.languageServiceAdapterHost.addScript(fileName, file, isRootFile); } }); @@ -446,17 +511,25 @@ export class TestState { continue; } const memo = Utils.memoize( - (_version: number, _active: string, _caret: number, _selectEnd: number, _marker: string | undefined, ...args: any[]) => (ls[key] as (...args: any[]) => any)(...args), - (...args) => args.map(a => a && typeof a === "object" ? JSON.stringify(a) : a).join("|,|") - ); - proxy[key] = (...args: any[]) => memo( - target.languageServiceAdapterHost.getScriptInfo(target.activeFile.fileName)!.version, - target.activeFile.fileName, - target.currentCaretPosition, - target.selectionEnd, - target.lastKnownMarker, - ...args + ( + _version: number, + _active: string, + _caret: number, + _selectEnd: number, + _marker: string | undefined, + ...args: any[] + ) => (ls[key] as (...args: any[]) => any)(...args), + (...args) => args.map(a => a && typeof a === "object" ? JSON.stringify(a) : a).join("|,|"), ); + proxy[key] = (...args: any[]) => + memo( + target.languageServiceAdapterHost.getScriptInfo(target.activeFile.fileName)!.version, + target.activeFile.fileName, + target.currentCaretPosition, + target.selectionEnd, + target.lastKnownMarker, + ...args, + ); } return proxy; } @@ -487,9 +560,9 @@ export class TestState { } private goToMarkerOrNameOrRange(markerOrRange: MarkerOrNameOrRange) { - return ts.isString(markerOrRange) || isMarker(markerOrRange) ? - this.goToMarker(markerOrRange) : - this.goToRangeStart(markerOrRange); + return ts.isString(markerOrRange) || isMarker(markerOrRange) + ? this.goToMarker(markerOrRange) + : this.goToRangeStart(markerOrRange); } public goToEachMarker(markers: readonly Marker[], action: (marker: Marker, index: number) => void) { @@ -520,7 +593,10 @@ export class TestState { public goToPosition(positionOrLineAndCharacter: number | ts.LineAndCharacter) { const pos = typeof positionOrLineAndCharacter === "number" ? positionOrLineAndCharacter - : this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, positionOrLineAndCharacter); + : this.languageServiceAdapterHost.lineAndCharacterToPosition( + this.activeFile.fileName, + positionOrLineAndCharacter, + ); this.currentCaretPosition = pos; this.selectionEnd = -1; } @@ -547,14 +623,20 @@ export class TestState { } public selectLine(index: number) { - const lineStart = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: index, character: 0 }); + const lineStart = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { + line: index, + character: 0, + }); const lineEnd = lineStart + this.getLineContent(index).length; this.selectRange({ fileName: this.activeFile.fileName, pos: lineStart, end: lineEnd }); } public moveCaretRight(count = 1) { this.currentCaretPosition += count; - this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length); + this.currentCaretPosition = Math.min( + this.currentCaretPosition, + this.getFileContent(this.activeFile.fileName).length, + ); this.selectionEnd = -1; } @@ -577,12 +659,20 @@ export class TestState { if (exists !== shouldExist) { this.printErrorLog(shouldExist, this.getAllDiagnostics()); - throw new Error(`${shouldExist ? "Expected" : "Did not expect"} failure between markers: '${startMarkerName}', '${endMarkerName}'`); + throw new Error( + `${ + shouldExist ? "Expected" : "Did not expect" + } failure between markers: '${startMarkerName}', '${endMarkerName}'`, + ); } } public verifyOrganizeImports(newContent: string, mode?: ts.OrganizeImportsMode, preferences?: ts.UserPreferences) { - const changes = this.languageService.organizeImports({ fileName: this.activeFile.fileName, type: "file", mode }, this.formatCodeSettings, preferences); + const changes = this.languageService.organizeImports( + { fileName: this.activeFile.fileName, type: "file", mode }, + this.formatCodeSettings, + preferences, + ); this.applyChanges(changes); this.verifyFileContent(this.activeFile.fileName, newContent); } @@ -592,7 +682,8 @@ export class TestState { } private messageAtLastKnownMarker(message: string) { - const locationDescription = this.lastKnownMarker !== undefined ? this.lastKnownMarker : this.getLineColStringAtPosition(this.currentCaretPosition); + const locationDescription = this.lastKnownMarker !== undefined ? this.lastKnownMarker + : this.getLineColStringAtPosition(this.currentCaretPosition); return `At marker '${locationDescription}': ${message}`; } @@ -624,7 +715,12 @@ export class TestState { public verifyErrorExistsAfterMarker(markerName: string, shouldExist: boolean, after: boolean) { const marker: Marker = this.getMarkerByName(markerName); - let predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number | undefined) => boolean; + let predicate: ( + errorMinChar: number, + errorLimChar: number, + startPos: number, + endPos: number | undefined, + ) => boolean; if (after) { predicate = (errorMinChar: number, errorLimChar: number, startPos: number) => @@ -644,9 +740,24 @@ export class TestState { } } - private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number | undefined) => boolean, startMarker: Marker, endMarker?: Marker): boolean { + private anyErrorInRange( + predicate: ( + errorMinChar: number, + errorLimChar: number, + startPos: number, + endPos: number | undefined, + ) => boolean, + startMarker: Marker, + endMarker?: Marker, + ): boolean { return this.getDiagnostics(startMarker.fileName).some(({ start, length }) => - predicate(start!, start! + length!, startMarker.position, endMarker === undefined ? undefined : endMarker.position)); // TODO: GH#18217 + predicate( + start!, + start! + length!, + startMarker.position, + endMarker === undefined ? undefined : endMarker.position, + ) + ); // TODO: GH#18217 } private printErrorLog(expectErrors: boolean, errors: readonly ts.Diagnostic[]): void { @@ -658,14 +769,18 @@ export class TestState { } for (const { start, length, messageText, file } of errors) { - Harness.IO.log(" " + this.formatRange(file, start!, length!) + // TODO: GH#18217 - ", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n"); + Harness.IO.log( + " " + this.formatRange(file, start!, length!) // TODO: GH#18217 + + ", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n", + ); } } private formatRange(file: ts.SourceFile | undefined, start: number, length: number) { if (file) { - return `from: ${this.formatLineAndCharacterOfPosition(file, start)}, to: ${this.formatLineAndCharacterOfPosition(file, start + length)}`; + return `from: ${this.formatLineAndCharacterOfPosition(file, start)}, to: ${ + this.formatLineAndCharacterOfPosition(file, start + length) + }`; } return "global"; } @@ -687,16 +802,21 @@ export class TestState { public verifyNoErrors() { ts.forEachKey(this.inputFiles, fileName => { - if (!ts.isAnySupportedFileExtension(fileName) + if ( + !ts.isAnySupportedFileExtension(fileName) || Harness.getConfigNameFromFileName(fileName) // Can't get a Program in Server tests - || this.testType !== FourSlashTestType.Server && !ts.getAllowJSCompilerOption(this.getProgram().getCompilerOptions()) && !ts.resolutionExtensionIsTSOrJson(ts.extensionFromPath(fileName)) - || ts.getBaseFileName(fileName) === "package.json") return; + || this.testType !== FourSlashTestType.Server + && !ts.getAllowJSCompilerOption(this.getProgram().getCompilerOptions()) + && !ts.resolutionExtensionIsTSOrJson(ts.extensionFromPath(fileName)) + || ts.getBaseFileName(fileName) === "package.json" + ) return; const errors = this.getDiagnostics(fileName).filter(e => e.category !== ts.DiagnosticCategory.Suggestion); if (errors.length) { this.printErrorLog(/*expectErrors*/ false, errors); const error = errors[0]; - const message = typeof error.messageText === "string" ? error.messageText : error.messageText.messageText; + const message = typeof error.messageText === "string" ? error.messageText + : error.messageText.messageText; this.raiseError(`Found an error: ${this.formatPosition(error.file!, error.start!)}: ${message}`); } }); @@ -707,10 +827,11 @@ export class TestState { const hasMatchingError = ts.some( this.getDiagnostics(range.fileName), ({ code, messageText, start, length }) => - code === code && - (!expectedMessage || expectedMessage === messageText) && - ts.isNumber(start) && ts.isNumber(length) && - ts.textSpansEqual(span, { start, length })); + code === code + && (!expectedMessage || expectedMessage === messageText) + && ts.isNumber(start) && ts.isNumber(length) + && ts.textSpansEqual(span, { start, length }), + ); if (!hasMatchingError) { this.raiseError(`No error with code ${code} found at provided range.`); @@ -723,7 +844,8 @@ export class TestState { if (actual !== expected) { this.printErrorLog(/*expectErrors*/ false, errors); - const errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + ")"; + const errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + + ")"; Harness.IO.log(errorMsg); this.raiseError(errorMsg); } @@ -749,13 +871,19 @@ export class TestState { return this.languageService.getDefinitionAndBoundSpan(this.activeFile.fileName, this.currentCaretPosition)!; } - private renderMarkers(markers: { text: string, fileName: string, position: number }[], useTerminalBoldSequence = true) { + private renderMarkers( + markers: { text: string; fileName: string; position: number; }[], + useTerminalBoldSequence = true, + ) { const filesToDisplay = ts.deduplicate(markers.map(m => m.fileName), ts.equateValues); return filesToDisplay.map(fileName => { - const markersToRender = markers.filter(m => m.fileName === fileName).sort((a, b) => b.position - a.position); + const markersToRender = markers.filter(m => m.fileName === fileName).sort((a, b) => + b.position - a.position + ); let fileContent = this.tryGetFileContent(fileName) || ""; for (const marker of markersToRender) { - fileContent = fileContent.slice(0, marker.position) + bold(`/*${marker.text}*/`) + fileContent.slice(marker.position); + fileContent = fileContent.slice(0, marker.position) + bold(`/*${marker.text}*/`) + + fileContent.slice(marker.position); } return `// @Filename: ${fileName}\n${fileContent}`; }).join("\n\n"); @@ -768,7 +896,11 @@ export class TestState { private baselineGoToDefs( markerName: string, markerOrRange: MarkerOrNameOrRange, - getDefs: () => readonly ts.DefinitionInfo[] | readonly ts.ImplementationLocation[] | ts.DefinitionInfoAndBoundSpan | undefined, + getDefs: () => + | readonly ts.DefinitionInfo[] + | readonly ts.ImplementationLocation[] + | ts.DefinitionInfoAndBoundSpan + | undefined, ) { this.goToMarkerOrNameOrRange(markerOrRange); const defs = getDefs(); @@ -783,20 +915,25 @@ export class TestState { markerInfo: { markerOrRange, markerName }, documentSpanId: defIdMap.size ? def => `defId: ${defIdMap.get(def)}` : undefined, skipDocumentSpanDetails: true, - additionalSpan: defs && !ts.isArray(defs) ? { fileName: this.activeFile.fileName, textSpan: defs.textSpan } : undefined, + additionalSpan: defs && !ts.isArray(defs) + ? { fileName: this.activeFile.fileName, textSpan: defs.textSpan } : undefined, }, ); if (definitions?.length) { baseline += "\n\n"; baseline += indentJsonBaseline( - "// === Details ===\n" + - JSON.stringify(definitions.map(def => ({ - defId: defIdMap.get(def), - ...def, - fileName: undefined, - textSpan: undefined, - contextSpan: undefined, - })), undefined, " ") + "// === Details ===\n" + + JSON.stringify( + definitions.map(def => ({ + defId: defIdMap.get(def), + ...def, + fileName: undefined, + textSpan: undefined, + contextSpan: undefined, + })), + undefined, + " ", + ), ); } return baseline; @@ -822,8 +959,13 @@ export class TestState { }); } - public baselineInlayHints(span: ts.TextSpan = { start: 0, length: this.activeFile.content.length }, preferences?: ts.UserPreferences): void{ - interface HasPosition { position: number; } + public baselineInlayHints( + span: ts.TextSpan = { start: 0, length: this.activeFile.content.length }, + preferences?: ts.UserPreferences, + ): void { + interface HasPosition { + position: number; + } const sortHints = (a: HasPosition, b: HasPosition) => { return a.position - b.position; }; @@ -833,7 +975,10 @@ export class TestState { const hints = this.languageService.provideInlayHints(fileName, span, preferences); const annotations = ts.map(hints.sort(sortHints), hint => { const span = { start: hint.position, length: hint.text.length }; - const { character, line } = this.languageServiceAdapterHost.positionToLineAndCharacter(fileName, span.start); + const { character, line } = this.languageServiceAdapterHost.positionToLineAndCharacter( + fileName, + span.start, + ); const underline = " ".repeat(character) + "^"; let annotation = this.getFileContent(fileName).split(/\r?\n/)[line]; annotation += "\n" + underline + "\n" + JSON.stringify(hint, undefined, " "); @@ -860,7 +1005,7 @@ export class TestState { return { andApplyCodeAction: () => { this.raiseError(`Cannot apply code action when multiple markers are specified.`); - } + }, }; } this.goToMarker(options.marker); @@ -870,27 +1015,43 @@ export class TestState { private verifyCompletionsWorker(options: FourSlashInterface.VerifyCompletionsOptions) { const preferences = options.preferences; - const actualCompletions = this.getCompletionListAtCaret({ ...preferences, triggerCharacter: options.triggerCharacter })!; + const actualCompletions = this.getCompletionListAtCaret({ + ...preferences, + triggerCharacter: options.triggerCharacter, + })!; if (!actualCompletions) { - if (ts.hasProperty(options, "exact") && (options.exact === undefined || ts.isArray(options.exact) && !options.exact.length)) { + if ( + ts.hasProperty(options, "exact") + && (options.exact === undefined || ts.isArray(options.exact) && !options.exact.length) + ) { return; } this.raiseError(`No completions at position '${this.currentCaretPosition}'.`); } if (actualCompletions.isNewIdentifierLocation !== (options.isNewIdentifierLocation || false)) { - this.raiseError(`Expected 'isNewIdentifierLocation' to be ${options.isNewIdentifierLocation || false}, got ${actualCompletions.isNewIdentifierLocation}`); + this.raiseError( + `Expected 'isNewIdentifierLocation' to be ${ + options.isNewIdentifierLocation || false + }, got ${actualCompletions.isNewIdentifierLocation}`, + ); } - if (ts.hasProperty(options, "isGlobalCompletion") && actualCompletions.isGlobalCompletion !== options.isGlobalCompletion) { - this.raiseError(`Expected 'isGlobalCompletion to be ${options.isGlobalCompletion}, got ${actualCompletions.isGlobalCompletion}`); + if ( + ts.hasProperty(options, "isGlobalCompletion") + && actualCompletions.isGlobalCompletion !== options.isGlobalCompletion + ) { + this.raiseError( + `Expected 'isGlobalCompletion to be ${options.isGlobalCompletion}, got ${actualCompletions.isGlobalCompletion}`, + ); } if (ts.hasProperty(options, "optionalReplacementSpan")) { assert.deepEqual( actualCompletions.optionalReplacementSpan && actualCompletions.optionalReplacementSpan, options.optionalReplacementSpan && ts.createTextSpanFromRange(options.optionalReplacementSpan), - "Expected 'optionalReplacementSpan' properties to match"); + "Expected 'optionalReplacementSpan' properties to match", + ); } const nameToEntries = new Map(); @@ -901,13 +1062,15 @@ export class TestState { nameToEntries.set(entry.name, [entry]); } else { - if (entries.some(e => - e.source === entry.source && - e.data?.exportName === entry.data?.exportName && - e.data?.fileName === entry.data?.fileName && - e.data?.moduleSpecifier === entry.data?.moduleSpecifier && - e.data?.ambientModuleName === entry.data?.ambientModuleName - )) { + if ( + entries.some(e => + e.source === entry.source + && e.data?.exportName === entry.data?.exportName + && e.data?.fileName === entry.data?.fileName + && e.data?.moduleSpecifier === entry.data?.moduleSpecifier + && e.data?.ambientModuleName === entry.data?.ambientModuleName + ) + ) { this.raiseError(`Duplicate completions for ${entry.name}`); } entries.push(entry); @@ -924,7 +1087,10 @@ export class TestState { } if (ts.hasProperty(options, "exact")) { - ts.Debug.assert(!ts.hasProperty(options, "includes") && !ts.hasProperty(options, "excludes") && !ts.hasProperty(options, "unsorted")); + ts.Debug.assert( + !ts.hasProperty(options, "includes") && !ts.hasProperty(options, "excludes") + && !ts.hasProperty(options, "unsorted"), + ); if (options.exact === undefined) throw this.raiseError("Expected no completions"); this.verifyCompletionsAreExactly(actualCompletions.entries, options.exact, options.marker); } @@ -934,7 +1100,9 @@ export class TestState { const name = typeof expectedEntry === "string" ? expectedEntry : expectedEntry.name; const found = nameToEntries.get(name); if (!found) throw this.raiseError(`Unsorted: completion '${name}' not found.`); - if (!found.length) throw this.raiseError(`Unsorted: no completions with name '${name}' remain unmatched.`); + if (!found.length) { + throw this.raiseError(`Unsorted: no completions with name '${name}' remain unmatched.`); + } this.verifyCompletionEntry(found.shift()!, expectedEntry); } if (actualCompletions.entries.length !== options.unsorted.length) { @@ -951,7 +1119,9 @@ export class TestState { const name = typeof include === "string" ? include : include.name; const found = nameToEntries.get(name); if (!found) throw this.raiseError(`Includes: completion '${name}' not found.`); - if (!found.length) throw this.raiseError(`Includes: no completions with name '${name}' remain unmatched.`); + if (!found.length) { + throw this.raiseError(`Includes: no completions with name '${name}' remain unmatched.`); + } this.verifyCompletionEntry(found.shift()!, include); } } @@ -967,22 +1137,32 @@ export class TestState { return { andApplyCodeAction: (options: { - name: string, - source: string, - description: string, - newFileContent?: string, - newRangeContent?: string, + name: string; + source: string; + description: string; + newFileContent?: string; + newRangeContent?: string; }) => { const { name, source, description, newFileContent, newRangeContent } = options; const data = nameAndSourceToData.get(`${options.name}|${options.source}`); if (data === false) { - this.raiseError(`Multiple completion entries found for '${options.name}' from '${options.source}'. This API cannot be used. Use 'verify.applyCodeActionFromCompletion' instead.`); + this.raiseError( + `Multiple completion entries found for '${options.name}' from '${options.source}'. This API cannot be used. Use 'verify.applyCodeActionFromCompletion' instead.`, + ); } if (data === undefined) { this.raiseError(`No completion entry found for '${options.name}' from '${options.source}'`); } - this.applyCodeActionFromCompletion(/*markerName*/ undefined, { name, source, data, description, newFileContent, newRangeContent, preferences }); - } + this.applyCodeActionFromCompletion(/*markerName*/ undefined, { + name, + source, + data, + description, + newFileContent, + newRangeContent, + preferences, + }); + }, }; } @@ -990,84 +1170,182 @@ export class TestState { expected = typeof expected === "string" ? { name: expected } : expected; if (actual.insertText !== expected.insertText) { - this.raiseError(`At entry ${actual.name}: Completion insert text did not match: ${showTextDiff(expected.insertText || "", actual.insertText || "")}`); + this.raiseError( + `At entry ${actual.name}: Completion insert text did not match: ${ + showTextDiff(expected.insertText || "", actual.insertText || "") + }`, + ); } - const convertedReplacementSpan = expected.replacementSpan && ts.createTextSpanFromRange(expected.replacementSpan); + const convertedReplacementSpan = expected.replacementSpan + && ts.createTextSpanFromRange(expected.replacementSpan); if (convertedReplacementSpan) { try { assert.deepEqual(actual.replacementSpan, convertedReplacementSpan); } catch { - this.raiseError(`At entry ${actual.name}: Expected completion replacementSpan to be ${stringify(convertedReplacementSpan)}, got ${stringify(actual.replacementSpan)}`); + this.raiseError( + `At entry ${actual.name}: Expected completion replacementSpan to be ${ + stringify(convertedReplacementSpan) + }, got ${stringify(actual.replacementSpan)}`, + ); } } else if (ts.hasProperty(expected, "replacementSpan")) { // Expected `replacementSpan` is explicitly set as `undefined`. - assert.equal(actual.replacementSpan, undefined, `At entry ${actual.name}: Expected 'replacementSpan' properties to match`); + assert.equal( + actual.replacementSpan, + undefined, + `At entry ${actual.name}: Expected 'replacementSpan' properties to match`, + ); } if (expected.kind !== undefined || expected.kindModifiers !== undefined) { - assert.equal(actual.kind, expected.kind, `At entry ${actual.name}: Expected 'kind' for ${actual.name} to match`); - assert.equal(actual.kindModifiers, expected.kindModifiers || "", `At entry ${actual.name}: Expected 'kindModifiers' for ${actual.name} to match`); + assert.equal( + actual.kind, + expected.kind, + `At entry ${actual.name}: Expected 'kind' for ${actual.name} to match`, + ); + assert.equal( + actual.kindModifiers, + expected.kindModifiers || "", + `At entry ${actual.name}: Expected 'kindModifiers' for ${actual.name} to match`, + ); } if (expected.isFromUncheckedFile !== undefined) { - assert.equal(actual.isFromUncheckedFile, expected.isFromUncheckedFile, `At entry ${actual.name}: Expected 'isFromUncheckedFile' properties to match`); + assert.equal( + actual.isFromUncheckedFile, + expected.isFromUncheckedFile, + `At entry ${actual.name}: Expected 'isFromUncheckedFile' properties to match`, + ); } if (expected.isPackageJsonImport !== undefined) { - assert.equal(actual.isPackageJsonImport, expected.isPackageJsonImport, `At entry ${actual.name}: Expected 'isPackageJsonImport' properties to match`); + assert.equal( + actual.isPackageJsonImport, + expected.isPackageJsonImport, + `At entry ${actual.name}: Expected 'isPackageJsonImport' properties to match`, + ); } assert.equal( actual.filterText, expected.filterText, - `At entry ${actual.name}: Completion 'filterText' not match: ${showTextDiff(expected.filterText || "", actual.filterText || "")}`); + `At entry ${actual.name}: Completion 'filterText' not match: ${ + showTextDiff(expected.filterText || "", actual.filterText || "") + }`, + ); assert.equal( actual.labelDetails?.description, expected.labelDetails?.description, - `At entry ${actual.name}: Completion 'labelDetails.description' did not match: ${showTextDiff(expected.labelDetails?.description || "", actual.labelDetails?.description || "")}`); + `At entry ${actual.name}: Completion 'labelDetails.description' did not match: ${ + showTextDiff(expected.labelDetails?.description || "", actual.labelDetails?.description || "") + }`, + ); assert.equal( actual.labelDetails?.detail, expected.labelDetails?.detail, - `At entry ${actual.name}: Completion 'labelDetails.detail' did not match: ${showTextDiff(expected.labelDetails?.detail || "", actual.labelDetails?.detail || "")}`); - assert.equal(actual.hasAction, expected.hasAction, `At entry ${actual.name}: Expected 'hasAction' properties to match`); - assert.equal(actual.isRecommended, expected.isRecommended, `At entry ${actual.name}: Expected 'isRecommended' properties to match'`); - assert.equal(actual.isSnippet, expected.isSnippet, `At entry ${actual.name}: Expected 'isSnippet' properties to match`); + `At entry ${actual.name}: Completion 'labelDetails.detail' did not match: ${ + showTextDiff(expected.labelDetails?.detail || "", actual.labelDetails?.detail || "") + }`, + ); + assert.equal( + actual.hasAction, + expected.hasAction, + `At entry ${actual.name}: Expected 'hasAction' properties to match`, + ); + assert.equal( + actual.isRecommended, + expected.isRecommended, + `At entry ${actual.name}: Expected 'isRecommended' properties to match'`, + ); + assert.equal( + actual.isSnippet, + expected.isSnippet, + `At entry ${actual.name}: Expected 'isSnippet' properties to match`, + ); assert.equal(actual.source, expected.source, `At entry ${actual.name}: Expected 'source' values to match`); - assert.equal(actual.sortText, expected.sortText || ts.Completions.SortText.LocationPriority, `At entry ${actual.name}: Expected 'sortText' properties to match`); + assert.equal( + actual.sortText, + expected.sortText || ts.Completions.SortText.LocationPriority, + `At entry ${actual.name}: Expected 'sortText' properties to match`, + ); if (expected.sourceDisplay && actual.sourceDisplay) { - assert.equal(ts.displayPartsToString(actual.sourceDisplay), expected.sourceDisplay, `At entry ${actual.name}: Expected 'sourceDisplay' properties to match`); + assert.equal( + ts.displayPartsToString(actual.sourceDisplay), + expected.sourceDisplay, + `At entry ${actual.name}: Expected 'sourceDisplay' properties to match`, + ); } if (expected.text !== undefined) { - const actualDetails = ts.Debug.checkDefined(this.getCompletionEntryDetails(actual.name, actual.source, actual.data), `No completion details available for name '${actual.name}' and source '${actual.source}'`); - assert.equal(ts.displayPartsToString(actualDetails.displayParts), expected.text, "Expected 'text' property to match 'displayParts' string"); - assert.equal(ts.displayPartsToString(actualDetails.documentation), expected.documentation || "", "Expected 'documentation' property to match 'documentation' display parts string"); + const actualDetails = ts.Debug.checkDefined( + this.getCompletionEntryDetails(actual.name, actual.source, actual.data), + `No completion details available for name '${actual.name}' and source '${actual.source}'`, + ); + assert.equal( + ts.displayPartsToString(actualDetails.displayParts), + expected.text, + "Expected 'text' property to match 'displayParts' string", + ); + assert.equal( + ts.displayPartsToString(actualDetails.documentation), + expected.documentation || "", + "Expected 'documentation' property to match 'documentation' display parts string", + ); // TODO: GH#23587 // assert.equal(actualDetails.kind, actual.kind); - assert.equal(actualDetails.kindModifiers, actual.kindModifiers, "Expected 'kindModifiers' properties to match"); - assert.equal(actualDetails.source && ts.displayPartsToString(actualDetails.source), expected.sourceDisplay, "Expected 'sourceDisplay' property to match 'source' display parts string"); + assert.equal( + actualDetails.kindModifiers, + actual.kindModifiers, + "Expected 'kindModifiers' properties to match", + ); + assert.equal( + actualDetails.source && ts.displayPartsToString(actualDetails.source), + expected.sourceDisplay, + "Expected 'sourceDisplay' property to match 'source' display parts string", + ); if (!actual.sourceDisplay) { - assert.equal(actualDetails.sourceDisplay && ts.displayPartsToString(actualDetails.sourceDisplay), expected.sourceDisplay, "Expected 'sourceDisplay' property to match 'sourceDisplay' display parts string"); + assert.equal( + actualDetails.sourceDisplay && ts.displayPartsToString(actualDetails.sourceDisplay), + expected.sourceDisplay, + "Expected 'sourceDisplay' property to match 'sourceDisplay' display parts string", + ); } assert.deepEqual(actualDetails.tags, expected.tags); } else { - assert(expected.documentation === undefined && expected.tags === undefined, "If specifying completion details, should specify 'text'"); + assert( + expected.documentation === undefined && expected.tags === undefined, + "If specifying completion details, should specify 'text'", + ); } } - private verifyCompletionsAreExactly(actual: readonly ts.CompletionEntry[], expected: ArrayOrSingle | FourSlashInterface.ExpectedExactCompletionsPlus, marker?: ArrayOrSingle) { + private verifyCompletionsAreExactly( + actual: readonly ts.CompletionEntry[], + expected: + | ArrayOrSingle + | FourSlashInterface.ExpectedExactCompletionsPlus, + marker?: ArrayOrSingle, + ) { if (!ts.isArray(expected)) { expected = [expected]; } // First pass: test that names are right. Then we'll test details. - assert.deepEqual(actual.map(a => a.name), expected.map(e => typeof e === "string" ? e : e.name), marker ? "At marker " + JSON.stringify(marker) : undefined); + assert.deepEqual( + actual.map(a => a.name), + expected.map(e => typeof e === "string" ? e : e.name), + marker ? "At marker " + JSON.stringify(marker) : undefined, + ); ts.zipWith(actual, expected, (completion, expectedCompletion, index) => { const name = typeof expectedCompletion === "string" ? expectedCompletion : expectedCompletion.name; if (completion.name !== name) { - this.raiseError(`${marker ? JSON.stringify(marker) : ""} Expected completion at index ${index} to be ${name}, got ${completion.name}`); + this.raiseError( + `${ + marker ? JSON.stringify(marker) : "" + } Expected completion at index ${index} to be ${name}, got ${completion.name}`, + ); } this.verifyCompletionEntry(completion, expectedCompletion); }); @@ -1079,7 +1357,8 @@ export class TestState { assert.deepEqual( plusArgument, expected.filter(entry => plusArgument.includes(entry)), - `At marker ${JSON.stringify(marker)}: Argument to '${plusFunctionName}' was incorrectly sorted.`); + `At marker ${JSON.stringify(marker)}: Argument to '${plusFunctionName}' was incorrectly sorted.`, + ); } } @@ -1148,7 +1427,10 @@ export class TestState { public symbolsInScope(range: Range): ts.Symbol[] { const node = this.goToAndGetNode(range); - return this.getChecker().getSymbolsInScope(node, ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace); + return this.getChecker().getSymbolsInScope( + node, + ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace, + ); } public setTypesRegistry(map: ts.MapLike): void { @@ -1189,7 +1471,8 @@ export class TestState { } if (command.rangeText !== undefined) { toArray(command.rangeText).forEach(text => - done = baselineArrayOrSingle(command, this.rangesByText().get(text)!, worker) || done); + done = baselineArrayOrSingle(command, this.rangesByText().get(text)!, worker) || done + ); } if (!done) { baselineArrayOrSingle(command, this.getRanges(), worker); @@ -1216,20 +1499,22 @@ export class TestState { case "goToDefinition": return baselineEachMarkerOrRange( command, - markerOrRange => this.baselineGoToDefs( - "/*GOTO DEF*/", - markerOrRange, - () => this.getGoToDefinitionAndBoundSpan(), - ), + markerOrRange => + this.baselineGoToDefs( + "/*GOTO DEF*/", + markerOrRange, + () => this.getGoToDefinitionAndBoundSpan(), + ), ); case "getDefinitionAtPosition": return baselineEachMarkerOrRange( command, - markerOrRange => this.baselineGoToDefs( - "/*GOTO DEF POS*/", - markerOrRange, - () => this.getGoToDefinition(), - ), + markerOrRange => + this.baselineGoToDefs( + "/*GOTO DEF POS*/", + markerOrRange, + () => this.getGoToDefinition(), + ), ); case "goToSourceDefinition": if (this.testType !== FourSlashTestType.Server) { @@ -1237,30 +1522,45 @@ export class TestState { } return baselineEachMarkerOrRange( command, - markerOrRange => this.baselineGoToDefs( - "/*GOTO SOURCE DEF*/", - markerOrRange, - () => (this.languageService as ts.server.SessionClient) - .getSourceDefinitionAndBoundSpan(this.activeFile.fileName, this.currentCaretPosition), - ), + markerOrRange => + this.baselineGoToDefs( + "/*GOTO SOURCE DEF*/", + markerOrRange, + () => + (this.languageService as ts.server.SessionClient) + .getSourceDefinitionAndBoundSpan( + this.activeFile.fileName, + this.currentCaretPosition, + ), + ), ); case "goToType": return baselineEachMarkerOrRange( command, - markerOrRange => this.baselineGoToDefs( - "/*GOTO TYPE*/", - markerOrRange, - () => this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition), - ), + markerOrRange => + this.baselineGoToDefs( + "/*GOTO TYPE*/", + markerOrRange, + () => + this.languageService.getTypeDefinitionAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ), + ), ); case "goToImplementation": return baselineEachMarkerOrRange( command, - markerOrRange => this.baselineGoToDefs( - "/*GOTO IMPL*/", - markerOrRange, - () => this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition), - ), + markerOrRange => + this.baselineGoToDefs( + "/*GOTO IMPL*/", + markerOrRange, + () => + this.languageService.getImplementationAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ), + ), ); case "documentHighlights": return baselineEachMarkerOrRange( @@ -1317,24 +1617,28 @@ export class TestState { if (references?.length) { baseline += "\n\n"; baseline += indentJsonBaseline( - "// === Definitions ===\n" + - this.getBaselineForDocumentSpansWithFileContents( - references.map(r => r.definition), - { - markerInfo, - documentSpanId: defIdMap.size ? def => `defId: ${defIdMap.get(def)}` : undefined, - skipDocumentSpanDetails: true, - skipDocumentContainingOnlyMarker: true, - } - ) + - "\n\n// === Details ===\n" + - JSON.stringify(references.map(r => ({ - defId: defIdMap.get(r.definition), - ...r.definition, - fileName: undefined, - textSpan: undefined, - contextSpan: undefined, - })), undefined, " ") + "// === Definitions ===\n" + + this.getBaselineForDocumentSpansWithFileContents( + references.map(r => r.definition), + { + markerInfo, + documentSpanId: defIdMap.size ? def => `defId: ${defIdMap.get(def)}` : undefined, + skipDocumentSpanDetails: true, + skipDocumentContainingOnlyMarker: true, + }, + ) + + "\n\n// === Details ===\n" + + JSON.stringify( + references.map(r => ({ + defId: defIdMap.get(r.definition), + ...r.definition, + fileName: undefined, + textSpan: undefined, + contextSpan: undefined, + })), + undefined, + " ", + ), ); } return baseline; @@ -1370,13 +1674,13 @@ export class TestState { skipDocumentContainingOnlyMarker, additionalSpan, } = options; - const marker: Marker | undefined = markerInfo !== undefined ? - ts.isString(markerInfo.markerOrRange) ? - this.getMarkerByName(markerInfo.markerOrRange) : - isMarker(markerInfo.markerOrRange) ? - markerInfo.markerOrRange : - { fileName: markerInfo.markerOrRange.fileName, position: markerInfo.markerOrRange.pos } : - undefined; + const marker: Marker | undefined = markerInfo !== undefined + ? ts.isString(markerInfo.markerOrRange) + ? this.getMarkerByName(markerInfo.markerOrRange) + : isMarker(markerInfo.markerOrRange) + ? markerInfo.markerOrRange + : { fileName: markerInfo.markerOrRange.fileName, position: markerInfo.markerOrRange.pos } + : undefined; const fileBaselines: string[] = []; let foundMarker = false; let foundAdditionalSpan = false; @@ -1399,10 +1703,12 @@ export class TestState { else { let baseline = `// === ${group[0].fileName} ===\n// Unavailable file content:\n`; for (const span of group) { - baseline += `// textSpan: ${JSON.stringify(span.textSpan)}${span.contextSpan ? `, contextSpan: ${JSON.stringify(span.contextSpan)}` : ""}`; - const text = !skipDocumentSpanDetails ? - convertDocumentSpanToString(span, documentSpanId?.(span)) : - documentSpanId?.(span); + baseline += `// textSpan: ${JSON.stringify(span.textSpan)}${ + span.contextSpan ? `, contextSpan: ${JSON.stringify(span.contextSpan)}` : "" + }`; + const text = !skipDocumentSpanDetails + ? convertDocumentSpanToString(span, documentSpanId?.(span)) + : documentSpanId?.(span); if (text) baseline += ` ${text}`; baseline += "\n"; } @@ -1466,7 +1772,9 @@ export class TestState { const detailSuffixes = new Map(); const details: Detail[] = []; let groupedSpanForAdditionalSpan: T | undefined; - if (fileName === marker?.fileName) details.push({ location: marker.position, locationMarker: markerInfo!.markerName }); + if (fileName === marker?.fileName) { + details.push({ location: marker.position, locationMarker: markerInfo!.markerName }); + } let canDetermineContextIdInline = true; for (const span of group) { const contextSpanIndex = details.length; @@ -1537,7 +1845,7 @@ export class TestState { }); } const lineStarts = ts.computeLineStarts(content); - let posLineInfo: { pos: number, line: number } | undefined; + let posLineInfo: { pos: number; line: number; } | undefined; // Our preferred way to write marker is // /*MARKER*/[| some text |] // [| some /*MARKER*/ text |] @@ -1549,10 +1857,16 @@ export class TestState { const { location, locationMarker, span, type } = detail; if (!span && deferredMarkerIndex === undefined) { // If this is marker position and its same as textEnd and/or contextEnd we want to write marker after those - for (let matchingEndPosIndex = index + 1; matchingEndPosIndex < sortedDetails.length; matchingEndPosIndex++) { + for ( + let matchingEndPosIndex = index + 1; + matchingEndPosIndex < sortedDetails.length; + matchingEndPosIndex++ + ) { // Defer after the location if its same as rangeEnd - if (sortedDetails[matchingEndPosIndex].location === location && - sortedDetails[matchingEndPosIndex].type!.endsWith("End")) { + if ( + sortedDetails[matchingEndPosIndex].location === location + && sortedDetails[matchingEndPosIndex].type!.endsWith("End") + ) { deferredMarkerIndex = matchingEndPosIndex; } // Dont defer further than already determined @@ -1570,9 +1884,9 @@ export class TestState { if (span) { switch (type) { case "textStart": - let text = !skipDocumentSpanDetails ? - convertDocumentSpanToString(span, documentSpanId?.(span), ignoredDocumentSpanProperties) : - documentSpanId?.(span); + let text = !skipDocumentSpanDetails + ? convertDocumentSpanToString(span, documentSpanId?.(span), ignoredDocumentSpanProperties) + : documentSpanId?.(span); if (span === groupedSpanForAdditionalSpan) { text = `textSpan: true` + (text ? `, ${text}` : ""); } @@ -1618,8 +1932,10 @@ export class TestState { if (!newContent && location === undefined) ts.Debug.fail("Unsupported"); if (type !== "textEnd" && type !== "contextEnd") { // Calculate pos to location number of lines - const posLine = posLineInfo?.pos === pos ? posLineInfo.line : ts.computeLineOfPosition(lineStarts, pos, posLineInfo?.line); - const locationLine = location !== undefined ? ts.computeLineOfPosition(lineStarts, location, posLine) : lineStarts.length - 1; + const posLine = posLineInfo?.pos === pos ? posLineInfo.line + : ts.computeLineOfPosition(lineStarts, pos, posLineInfo?.line); + const locationLine = location !== undefined ? ts.computeLineOfPosition(lineStarts, location, posLine) + : lineStarts.length - 1; if (location !== undefined) posLineInfo = { pos: location, line: locationLine }; let nLines = 0; if (newContent) nLines += TestState.nLinesContext + 1; @@ -1627,14 +1943,17 @@ export class TestState { // first nLinesContext and last nLinesContext if (locationLine - posLine > nLines) { if (newContent) { - readableContents = readableContents + "\n" + readableJsoncBaseline(newContent + content.slice(pos, lineStarts[posLine + TestState.nLinesContext]) + - `--- (line: ${isLibFile ? "--" : posLine + TestState.nLinesContext + 1}) skipped ---`); + readableContents = readableContents + "\n" + readableJsoncBaseline( + newContent + content.slice(pos, lineStarts[posLine + TestState.nLinesContext]) + + `--- (line: ${isLibFile ? "--" : posLine + TestState.nLinesContext + 1}) skipped ---`, + ); if (location !== undefined) readableContents += "\n"; newContent = ""; } if (location !== undefined) { - newContent += `--- (line: ${isLibFile ? "--" : locationLine - TestState.nLinesContext + 1}) skipped ---\n` + - content.slice(lineStarts[locationLine - TestState.nLinesContext + 1], location); + newContent += + `--- (line: ${isLibFile ? "--" : locationLine - TestState.nLinesContext + 1}) skipped ---\n` + + content.slice(lineStarts[locationLine - TestState.nLinesContext + 1], location); } return; } @@ -1646,7 +1965,11 @@ export class TestState { private assertObjectsEqual(fullActual: T, fullExpected: T, msgPrefix = ""): void { const recur = (actual: U, expected: U, path: string) => { const fail = (msg: string) => { - this.raiseError(`${msgPrefix} At ${path}: ${msg} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`); + this.raiseError( + `${msgPrefix} At ${path}: ${msg} ${ + displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual)) + }`, + ); }; if ((actual === undefined) !== (expected === undefined)) { @@ -1678,10 +2001,11 @@ export class TestState { if (fullActual === fullExpected) { return; } - this.raiseError(`${msgPrefix} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`); + this.raiseError( + `${msgPrefix} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`, + ); } recur(fullActual, fullExpected, ""); - } private configure(preferences: ts.UserPreferences) { @@ -1698,14 +2022,28 @@ export class TestState { this.activeFile.fileName, this.currentCaretPosition, options, - this.formatCodeSettings); + this.formatCodeSettings, + ); } - private getCompletionEntryDetails(entryName: string, source: string | undefined, data: ts.CompletionEntryData | undefined, preferences?: ts.UserPreferences): ts.CompletionEntryDetails | undefined { + private getCompletionEntryDetails( + entryName: string, + source: string | undefined, + data: ts.CompletionEntryData | undefined, + preferences?: ts.UserPreferences, + ): ts.CompletionEntryDetails | undefined { if (preferences) { this.configure(preferences); } - return this.languageService.getCompletionEntryDetails(this.activeFile.fileName, this.currentCaretPosition, entryName, this.formatCodeSettings, source, preferences, data); + return this.languageService.getCompletionEntryDetails( + this.activeFile.fileName, + this.currentCaretPosition, + entryName, + this.formatCodeSettings, + source, + preferences, + data, + ); } private findReferencesAtCaret() { @@ -1723,34 +2061,52 @@ export class TestState { } public getSuggestionDiagnostics(expected: readonly FourSlashInterface.Diagnostic[]): void { - this.testDiagnostics(expected, this.languageService.getSuggestionDiagnostics(this.activeFile.fileName), "suggestion"); + this.testDiagnostics( + expected, + this.languageService.getSuggestionDiagnostics(this.activeFile.fileName), + "suggestion", + ); } - private testDiagnostics(expected: readonly FourSlashInterface.Diagnostic[], diagnostics: readonly ts.Diagnostic[], category: string) { - assert.deepEqual(ts.realizeDiagnostics(diagnostics, "\n"), expected.map((e): ts.RealizedDiagnostic => { - const range = e.range || this.getRangesInFile()[0]; - if (!range) { - this.raiseError("Must provide a range for each expected diagnostic, or have one range in the fourslash source."); - } - return { - message: e.message, - category, - code: e.code, - ...ts.createTextSpanFromRange(range), - reportsUnnecessary: e.reportsUnnecessary, - reportsDeprecated: e.reportsDeprecated - }; - })); + private testDiagnostics( + expected: readonly FourSlashInterface.Diagnostic[], + diagnostics: readonly ts.Diagnostic[], + category: string, + ) { + assert.deepEqual( + ts.realizeDiagnostics(diagnostics, "\n"), + expected.map((e): ts.RealizedDiagnostic => { + const range = e.range || this.getRangesInFile()[0]; + if (!range) { + this.raiseError( + "Must provide a range for each expected diagnostic, or have one range in the fourslash source.", + ); + } + return { + message: e.message, + category, + code: e.code, + ...ts.createTextSpanFromRange(range), + reportsUnnecessary: e.reportsUnnecessary, + reportsDeprecated: e.reportsDeprecated, + }; + }), + ); } - public verifyQuickInfoAt(markerName: string | Range, expectedText: string, expectedDocumentation?: string, expectedTags?: {name: string; text: string;}[]) { + public verifyQuickInfoAt( + markerName: string | Range, + expectedText: string, + expectedDocumentation?: string, + expectedTags?: { name: string; text: string; }[], + ) { if (typeof markerName === "string") this.goToMarker(markerName); else this.goToRangeStart(markerName); this.verifyQuickInfoString(expectedText, expectedDocumentation, expectedTags); } - public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string] }) { + public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string]; }) { for (const name in namesAndTexts) { if (ts.hasProperty(namesAndTexts, name)) { const text = namesAndTexts[name]; @@ -1766,17 +2122,31 @@ export class TestState { } } - public verifyQuickInfoString(expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) { + public verifyQuickInfoString( + expectedText: string, + expectedDocumentation?: string, + expectedTags?: { name: string; text: string; }[], + ) { if (expectedDocumentation === "") { throw new Error("Use 'undefined' instead of empty string for `expectedDocumentation`"); } - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const actualQuickInfo = this.languageService.getQuickInfoAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); const actualQuickInfoText = ts.displayPartsToString(actualQuickInfo?.displayParts); const actualQuickInfoDocumentation = ts.displayPartsToString(actualQuickInfo?.documentation); - const actualQuickInfoTags = actualQuickInfo?.tags?.map(tag => ({ name: tag.name, text: ts.displayPartsToString(tag.text) })); + const actualQuickInfoTags = actualQuickInfo?.tags?.map(tag => ({ + name: tag.name, + text: ts.displayPartsToString(tag.text), + })); assert.equal(actualQuickInfoText, expectedText, this.messageAtLastKnownMarker("quick info text")); - assert.equal(actualQuickInfoDocumentation, expectedDocumentation || "", this.assertionMessageAtLastKnownMarker("quick info doc")); + assert.equal( + actualQuickInfoDocumentation, + expectedDocumentation || "", + this.assertionMessageAtLastKnownMarker("quick info doc"), + ); if (!expectedTags) { // Skip if `expectedTags` is not given } @@ -1786,23 +2156,48 @@ export class TestState { else { ts.zipWith(expectedTags, actualQuickInfoTags, (expectedTag, actualTag) => { assert.equal(expectedTag.name, actualTag.name); - assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name)); + assert.equal( + expectedTag.text, + actualTag.text, + this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name), + ); }); } } - public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: TextSpan, + public verifyQuickInfoDisplayParts( + kind: string, + kindModifiers: string, + textSpan: TextSpan, displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], - tags: ts.JSDocTagInfo[] | undefined + tags: ts.JSDocTagInfo[] | undefined, ) { - - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition)!; + const actualQuickInfo = this.languageService.getQuickInfoAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + )!; assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind")); - assert.equal(actualQuickInfo.kindModifiers, kindModifiers, this.messageAtLastKnownMarker("QuickInfo kindModifiers")); - assert.equal(JSON.stringify(actualQuickInfo.textSpan), JSON.stringify(textSpan), this.messageAtLastKnownMarker("QuickInfo textSpan")); - assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.displayParts), TestState.getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts")); - assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.documentation), TestState.getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation")); + assert.equal( + actualQuickInfo.kindModifiers, + kindModifiers, + this.messageAtLastKnownMarker("QuickInfo kindModifiers"), + ); + assert.equal( + JSON.stringify(actualQuickInfo.textSpan), + JSON.stringify(textSpan), + this.messageAtLastKnownMarker("QuickInfo textSpan"), + ); + assert.equal( + TestState.getDisplayPartsJson(actualQuickInfo.displayParts), + TestState.getDisplayPartsJson(displayParts), + this.messageAtLastKnownMarker("QuickInfo displayParts"), + ); + assert.equal( + TestState.getDisplayPartsJson(actualQuickInfo.documentation), + TestState.getDisplayPartsJson(documentation), + this.messageAtLastKnownMarker("QuickInfo documentation"), + ); if (!actualQuickInfo.tags || !tags) { assert.equal(actualQuickInfo.tags, tags, this.messageAtLastKnownMarker("QuickInfo tags")); } @@ -1810,22 +2205,26 @@ export class TestState { assert.equal(actualQuickInfo.tags.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags")); ts.zipWith(tags, actualQuickInfo.tags, (expectedTag, actualTag) => { assert.equal(expectedTag.name, actualTag.name); - assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name)); + assert.equal( + expectedTag.text, + actualTag.text, + this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name), + ); }); } } private baselineRenameWorker(markerOrRange: MarkerOrNameOrRange, options?: FourSlashInterface.RenameOptions) { - const { fileName, position } = ts.isString(markerOrRange) ? - this.getMarkerByName(markerOrRange) : - isMarker(markerOrRange) ? - markerOrRange : - { fileName: markerOrRange.fileName, position: markerOrRange.pos }; + const { fileName, position } = ts.isString(markerOrRange) + ? this.getMarkerByName(markerOrRange) + : isMarker(markerOrRange) + ? markerOrRange + : { fileName: markerOrRange.fileName, position: markerOrRange.pos }; const { findInStrings = false, findInComments = false, providePrefixAndSuffixTextForRename = true, - quotePreference = "double" + quotePreference = "double", } = options || {}; const locations = this.languageService.findRenameLocations( fileName, @@ -1839,12 +2238,13 @@ export class TestState { this.raiseError(`baselineRename failed. Could not rename at the provided position.`); } - const renameOptions = options ? - (options.findInStrings !== undefined ? `// @findInStrings: ${findInStrings}\n` : "") + - (options.findInComments !== undefined ? `// @findInComments: ${findInComments}\n` : "") + - (options.providePrefixAndSuffixTextForRename !== undefined ? `// @providePrefixAndSuffixTextForRename: ${providePrefixAndSuffixTextForRename}\n` : "") + - (options.quotePreference !== undefined ? `// @quotePreference: ${quotePreference}\n` : "") : - ""; + const renameOptions = options + ? (options.findInStrings !== undefined ? `// @findInStrings: ${findInStrings}\n` : "") + + (options.findInComments !== undefined ? `// @findInComments: ${findInComments}\n` : "") + + (options.providePrefixAndSuffixTextForRename !== undefined + ? `// @providePrefixAndSuffixTextForRename: ${providePrefixAndSuffixTextForRename}\n` : "") + + (options.quotePreference !== undefined ? `// @quotePreference: ${quotePreference}\n` : "") + : ""; return renameOptions + (renameOptions ? "\n" : "") + this.getBaselineForDocumentSpansWithFileContents( locations, @@ -1854,12 +2254,15 @@ export class TestState { startMarkerPrefix: span => span.prefixText ? `/*START PREFIX*/${span.prefixText}` : "", endMarkerSuffix: span => span.suffixText ? `${span.suffixText}/*END SUFFIX*/` : "", ignoredDocumentSpanProperties: ["prefixText", "suffixText"], - } + }, ); } public verifyQuickInfoExists(negative: boolean) { - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const actualQuickInfo = this.languageService.getQuickInfoAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); if (negative) { if (actualQuickInfo) { this.raiseError("verifyQuickInfoExists failed. Expected quick info NOT to exist"); @@ -1872,7 +2275,11 @@ export class TestState { } } - public verifySignatureHelpPresence(expectPresent: boolean, triggerReason: ts.SignatureHelpTriggerReason | undefined, markers: readonly (string | Marker)[]) { + public verifySignatureHelpPresence( + expectPresent: boolean, + triggerReason: ts.SignatureHelpTriggerReason | undefined, + markers: readonly (string | Marker)[], + ) { if (markers.length) { for (const marker of markers) { this.goToMarker(marker); @@ -1915,15 +2322,27 @@ export class TestState { // Argument index may exceed number of parameters const currentParameter = selectedItem.parameters[help.argumentIndex] as ts.SignatureHelpParameter | undefined; - assert.equal(help.items.length, options.overloadsCount || 1, this.assertionMessageAtLastKnownMarker("signature help overloads count")); + assert.equal( + help.items.length, + options.overloadsCount || 1, + this.assertionMessageAtLastKnownMarker("signature help overloads count"), + ); - assert.equal(ts.displayPartsToString(selectedItem.documentation), options.docComment || "", this.assertionMessageAtLastKnownMarker("current signature help doc comment")); + assert.equal( + ts.displayPartsToString(selectedItem.documentation), + options.docComment || "", + this.assertionMessageAtLastKnownMarker("current signature help doc comment"), + ); if (options.text !== undefined) { assert.equal( - ts.displayPartsToString(selectedItem.prefixDisplayParts) + - selectedItem.parameters.map(p => ts.displayPartsToString(p.displayParts)).join(ts.displayPartsToString(selectedItem.separatorDisplayParts)) + - ts.displayPartsToString(selectedItem.suffixDisplayParts), options.text); + ts.displayPartsToString(selectedItem.prefixDisplayParts) + + selectedItem.parameters.map(p => ts.displayPartsToString(p.displayParts)).join( + ts.displayPartsToString(selectedItem.separatorDisplayParts), + ) + + ts.displayPartsToString(selectedItem.suffixDisplayParts), + options.text, + ); } if (options.parameterName !== undefined) { assert.equal(currentParameter!.name, options.parameterName); @@ -1932,7 +2351,11 @@ export class TestState { assert.equal(ts.displayPartsToString(currentParameter!.displayParts), options.parameterSpan); } if (currentParameter) { - assert.equal(ts.displayPartsToString(currentParameter.documentation), options.parameterDocComment || "", this.assertionMessageAtLastKnownMarker("current parameter Help DocComment")); + assert.equal( + ts.displayPartsToString(currentParameter.documentation), + options.parameterDocComment || "", + this.assertionMessageAtLastKnownMarker("current parameter Help DocComment"), + ); } if (options.parameterCount !== undefined) { assert.equal(selectedItem.parameters.length, options.parameterCount); @@ -1944,10 +2367,18 @@ export class TestState { assert.equal(selectedItem.isVariadic, !!options.isVariadic); const actualTags = selectedItem.tags; - assert.equal(actualTags.length, (options.tags || ts.emptyArray).length, this.assertionMessageAtLastKnownMarker("signature help tags")); - ts.zipWith((options.tags || ts.emptyArray), actualTags, (expectedTag, actualTag) => { + assert.equal( + actualTags.length, + (options.tags || ts.emptyArray).length, + this.assertionMessageAtLastKnownMarker("signature help tags"), + ); + ts.zipWith(options.tags || ts.emptyArray, actualTags, (expectedTag, actualTag) => { assert.equal(actualTag.name, expectedTag.name); - assert.deepEqual(actualTag.text, expectedTag.text, this.assertionMessageAtLastKnownMarker("signature help tag " + actualTag.name)); + assert.deepEqual( + actualTag.text, + expectedTag.text, + this.assertionMessageAtLastKnownMarker("signature help tag " + actualTag.name), + ); }); const allKeys: readonly (keyof FourSlashInterface.VerifySignatureHelpOptions)[] = [ @@ -1963,7 +2394,7 @@ export class TestState { "isVariadic", "tags", "argumentCount", - "overrideSelectedItemIndex" + "overrideSelectedItemIndex", ]; for (const key in options) { if (!ts.contains(allKeys, key)) { @@ -1985,8 +2416,13 @@ export class TestState { kindModifiers: string | undefined, fileToRename: string | undefined, expectedRange: Range | undefined, - preferences: ts.UserPreferences | undefined): void { - const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, preferences || { allowRenameOfImportPath: true }); + preferences: ts.UserPreferences | undefined, + ): void { + const renameInfo = this.languageService.getRenameInfo( + this.activeFile.fileName, + this.currentCaretPosition, + preferences || { allowRenameOfImportPath: true }, + ); if (!renameInfo.canRename) { throw this.raiseError("Rename did not succeed"); } @@ -2004,16 +2440,24 @@ export class TestState { expectedRange = this.getRanges()[0]; } - if (renameInfo.triggerSpan.start !== expectedRange.pos || - ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end) { - this.raiseError("Expected triggerSpan [" + expectedRange.pos + "," + expectedRange.end + "). Got [" + - renameInfo.triggerSpan.start + "," + ts.textSpanEnd(renameInfo.triggerSpan) + ") instead."); + if ( + renameInfo.triggerSpan.start !== expectedRange.pos + || ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end + ) { + this.raiseError( + "Expected triggerSpan [" + expectedRange.pos + "," + expectedRange.end + "). Got [" + + renameInfo.triggerSpan.start + "," + ts.textSpanEnd(renameInfo.triggerSpan) + ") instead.", + ); } } public verifyRenameInfoFailed(message?: string, preferences?: ts.UserPreferences) { - const allowRenameOfImportPath = preferences?.allowRenameOfImportPath === undefined ? true : preferences.allowRenameOfImportPath; - const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, { ...preferences, allowRenameOfImportPath }); + const allowRenameOfImportPath = preferences?.allowRenameOfImportPath === undefined ? true + : preferences.allowRenameOfImportPath; + const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, { + ...preferences, + allowRenameOfImportPath, + }); if (renameInfo.canRename) { throw this.raiseError("Rename was expected to fail"); } @@ -2022,7 +2466,11 @@ export class TestState { private alignmentForExtraInfo = 50; - private spanLines(file: FourSlashFile, spanInfo: ts.TextSpan, { selection = false, fullLines = false, lineNumbers = false } = {}) { + private spanLines( + file: FourSlashFile, + spanInfo: ts.TextSpan, + { selection = false, fullLines = false, lineNumbers = false } = {}, + ) { if (selection) { fullLines = true; } @@ -2071,24 +2519,35 @@ export class TestState { contextLineMap = ts.computeLineStarts(contextString); contextStart = { line: 0, character: 0 }; contextEnd = { line: contextLineMap.length - 1, character: 0 }; - selectionStart = selection ? ts.computeLineAndCharacterOfPosition(contextLineMap, spanInfo.start - contextStartPos) : contextStart; - selectionEnd = selection ? ts.computeLineAndCharacterOfPosition(contextLineMap, ts.textSpanEnd(spanInfo) - contextStartPos) : contextEnd; + selectionStart = selection + ? ts.computeLineAndCharacterOfPosition(contextLineMap, spanInfo.start - contextStartPos) : contextStart; + selectionEnd = selection + ? ts.computeLineAndCharacterOfPosition(contextLineMap, ts.textSpanEnd(spanInfo) - contextStartPos) + : contextEnd; lineNumberPrefixLength = 0; } const output: string[] = []; for (let lineNumber = contextStart.line; lineNumber <= contextEnd.line; lineNumber++) { const spanLine = contextString.substring(contextLineMap[lineNumber], contextLineMap[lineNumber + 1]); - output.push(lineNumbers ? `${ts.padLeft(`${lineNumber + 1}: `, lineNumberPrefixLength)}${spanLine}` : spanLine); + output.push( + lineNumbers ? `${ts.padLeft(`${lineNumber + 1}: `, lineNumberPrefixLength)}${spanLine}` : spanLine, + ); if (selection) { if (lineNumber < selectionStart.line || lineNumber > selectionEnd.line) { continue; } - const isEmpty = selectionStart.line === selectionEnd.line && selectionStart.character === selectionEnd.character; + const isEmpty = selectionStart.line === selectionEnd.line + && selectionStart.character === selectionEnd.character; const selectionPadLength = lineNumber === selectionStart.line ? selectionStart.character : 0; const selectionPad = " ".repeat(selectionPadLength + lineNumberPrefixLength); - const selectionLength = isEmpty ? 0 : Math.max(lineNumber < selectionEnd.line ? spanLine.trimRight().length - selectionPadLength : selectionEnd.character - selectionPadLength, 1); + const selectionLength = isEmpty ? 0 + : Math.max( + lineNumber < selectionEnd.line ? spanLine.trimRight().length - selectionPadLength + : selectionEnd.character - selectionPadLength, + 1, + ); const selectionLine = isEmpty ? "<" : "^".repeat(selectionLength); output.push(`${selectionPad}${selectionLine}`); } @@ -2106,7 +2565,8 @@ export class TestState { } resultString += prefixString + spanLines[i]; } - resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start, file) + ") to (" + this.getLineColStringAtPosition(ts.textSpanEnd(spanInfo), file) + ")"; + resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start, file) + + ") to (" + this.getLineColStringAtPosition(ts.textSpanEnd(spanInfo), file) + ")"; } return resultString; @@ -2127,7 +2587,10 @@ export class TestState { if (previousSpanInfo) { resultString += currentLine; let thisLineMarker = ts.repeatString(" ", startColumn!) + ts.repeatString("~", length!); - thisLineMarker += ts.repeatString(" ", this.alignmentForExtraInfo - thisLineMarker.length - prefixString.length + 1); + thisLineMarker += ts.repeatString( + " ", + this.alignmentForExtraInfo - thisLineMarker.length - prefixString.length + 1, + ); resultString += thisLineMarker; resultString += "=> Pos: (" + (pos - length!) + " to " + (pos - 1) + ") "; resultString += " " + previousSpanInfo; @@ -2142,7 +2605,8 @@ export class TestState { if (resultString.length) { resultString += "\n--------------------------------"; } - currentLine = "\n" + nextLine.toString() + ts.repeatString(" ", 3 - nextLine.toString().length) + ">" + this.activeFile.content.substring(pos, fileLineMap[nextLine]) + "\n "; + currentLine = "\n" + nextLine.toString() + ts.repeatString(" ", 3 - nextLine.toString().length) + ">" + + this.activeFile.content.substring(pos, fileLineMap[nextLine]) + "\n "; startColumn = 0; length = 0; } @@ -2167,13 +2631,19 @@ export class TestState { } public baselineCurrentFileBreakpointLocations() { - const baselineFile = this.getBaselineFileNameForInternalFourslashFile().replace("breakpointValidation", "bpSpan"); - Harness.Baseline.runBaseline(baselineFile, this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)!)); + const baselineFile = this.getBaselineFileNameForInternalFourslashFile().replace( + "breakpointValidation", + "bpSpan", + ); + Harness.Baseline.runBaseline( + baselineFile, + this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)!), + ); } private getEmitFiles(): readonly FourSlashFile[] { // Find file to be emitted - const emitFiles: FourSlashFile[] = []; // List of FourSlashFile that has emitThisFile flag on + const emitFiles: FourSlashFile[] = []; // List of FourSlashFile that has emitThisFile flag on const allFourSlashFiles = this.testData.files; for (const file of allFourSlashFiles) { @@ -2192,7 +2662,10 @@ export class TestState { } public verifyGetEmitOutput(expectedOutputFiles: readonly string[]): void { - const outputFiles = ts.flatMap(this.getEmitFiles(), e => this.languageService.getEmitOutput(e.fileName).outputFiles); + const outputFiles = ts.flatMap( + this.getEmitFiles(), + e => this.languageService.getEmitOutput(e.fileName).outputFiles, + ); assert.deepEqual(outputFiles.map(f => f.name), expectedOutputFiles); @@ -2232,7 +2705,10 @@ export class TestState { resultString += Harness.IO.newLine(); } - Harness.Baseline.runBaseline(ts.Debug.checkDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]), resultString); + Harness.Baseline.runBaseline( + ts.Debug.checkDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]), + resultString, + ); } private flattenChainedMessage(diag: ts.DiagnosticMessageChain, indent = " ") { @@ -2254,7 +2730,8 @@ export class TestState { private getCompilerTestFiles() { return ts.map(this.testData.files, ({ content, fileName }) => ({ - content, unitName: fileName + content, + unitName: fileName, })); } @@ -2268,9 +2745,7 @@ export class TestState { } private getSyntacticDiagnosticBaselineText(files: Harness.Compiler.TestFile[]) { - const diagnostics = ts.flatMap(files, - file => this.languageService.getSyntacticDiagnostics(file.unitName) - ); + const diagnostics = ts.flatMap(files, file => this.languageService.getSyntacticDiagnostics(file.unitName)); const result = `Syntactic Diagnostics for file '${this.originalInputFileName}':` + Harness.IO.newLine() + Harness.Compiler.getErrorBaseline(files, diagnostics, /*pretty*/ false); @@ -2278,9 +2753,7 @@ export class TestState { } private getSemanticDiagnosticBaselineText(files: Harness.Compiler.TestFile[]) { - const diagnostics = ts.flatMap(files, - file => this.languageService.getSemanticDiagnostics(file.unitName) - ); + const diagnostics = ts.flatMap(files, file => this.languageService.getSemanticDiagnostics(file.unitName)); const result = `Semantic Diagnostics for file '${this.originalInputFileName}':` + Harness.IO.newLine() + Harness.Compiler.getErrorBaseline(files, diagnostics, /*pretty*/ false); @@ -2291,7 +2764,7 @@ export class TestState { const baselineFile = this.getBaselineFileNameForContainingTestFile(); const result = ts.arrayFrom(this.testData.markerPositions.entries(), ([name, marker]) => ({ marker: { ...marker, name }, - item: this.languageService.getQuickInfoAtPosition(marker.fileName, marker.position) + item: this.languageService.getQuickInfoAtPosition(marker.fileName, marker.position), })); const annotations = this.annotateContentWithTooltips( result, @@ -2300,8 +2773,11 @@ export class TestState { ({ displayParts, documentation, tags }) => [ ...(displayParts ? displayParts.map(p => p.text).join("").split("\n") : []), ...(documentation?.length ? documentation.map(p => p.text).join("").split("\n") : []), - ...(tags?.length ? tags.map(p => `@${p.name} ${p.text?.map(dp => dp.text).join("") ?? ""}`).join("\n").split("\n") : []) - ]); + ...(tags?.length + ? tags.map(p => `@${p.name} ${p.text?.map(dp => dp.text).join("") ?? ""}`).join("\n").split("\n") + : []), + ], + ); Harness.Baseline.runBaseline(baselineFile, annotations + "\n\n" + stringify(result)); } @@ -2309,14 +2785,21 @@ export class TestState { const baselineFile = this.getBaselineFileNameForContainingTestFile(); const result = ts.arrayFrom(this.testData.markerPositions.entries(), ([name, marker]) => ({ marker: { ...marker, name }, - item: this.languageService.getSignatureHelpItems(marker.fileName, marker.position, /*options*/ undefined) + item: this.languageService.getSignatureHelpItems(marker.fileName, marker.position, /*options*/ undefined), })); const annotations = this.annotateContentWithTooltips( result, "signature help", () => undefined, // use default: marker.position (item, previous) => { - const { documentation, tags, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters } = item.items[item.selectedItemIndex]; + const { + documentation, + tags, + prefixDisplayParts, + suffixDisplayParts, + separatorDisplayParts, + parameters, + } = item.items[item.selectedItemIndex]; const tooltip = []; let signature = ""; if (prefixDisplayParts.length) signature += prefixDisplayParts.map(p => p.text).join(""); @@ -2331,11 +2814,14 @@ export class TestState { if (previous?.applicableSpan.start !== item.applicableSpan.start) { if (documentation?.length) tooltip.push(...documentation.map(p => p.text).join("").split("\n")); if (tags?.length) { - tooltip.push(...tags.map(p => `@${p.name} ${p.text?.map(dp => dp.text).join("") ?? ""}`).join("\n").split("\n")); + tooltip.push( + ...tags.map(p => `@${p.name} ${p.text?.map(dp => dp.text).join("") ?? ""}`).join("\n") + .split("\n"), + ); } } return tooltip; - } + }, ); Harness.Baseline.runBaseline(baselineFile, annotations + "\n\n" + stringify(result)); } @@ -2351,19 +2837,22 @@ export class TestState { ...completions, entries: completions?.entries.map(entry => ({ ...entry, - ...this.getCompletionEntryDetails(entry.name, entry.source, entry.data, preferences) + ...this.getCompletionEntryDetails(entry.name, entry.source, entry.data, preferences), })), - } + }, }; }); const annotations = this.annotateContentWithTooltips( result, "completions", item => item.optionalReplacementSpan, - item => item.entries?.flatMap( - entry => entry.displayParts - ? entry.displayParts.map(p => p.text).join("").split("\n") - : [`(${entry.kindModifiers}${entry.kind}) ${entry.name}`]) + item => + item.entries?.flatMap( + entry => + entry.displayParts + ? entry.displayParts.map(p => p.text).join("").split("\n") + : [`(${entry.kindModifiers}${entry.kind}) ${entry.name}`], + ), ); for (const r of result) { for (const entry of r.item.entries ?? ts.emptyArray) { @@ -2381,36 +2870,43 @@ export class TestState { } } } - Harness.Baseline.runBaseline(baselineFile, annotations + "\n\n" + stringify(result, (key, value) => { - return key === "exportMapKey" - ? value.replace(/\|[0-9]+/g, "|*") - : value; - })); + Harness.Baseline.runBaseline( + baselineFile, + annotations + "\n\n" + stringify(result, (key, value) => { + return key === "exportMapKey" + ? value.replace(/\|[0-9]+/g, "|*") + : value; + }), + ); } - private annotateContentWithTooltips( + name: string; + kind: string; + kindModifiers?: string; + displayParts?: unknown; + }[]; + }, + >( items: ({ - marker: Marker & { name: string }, - item: T | undefined + marker: Marker & { name: string; }; + item: T | undefined; })[], opName: "completions" | "quickinfo" | "signature help", getSpan: (t: T) => ts.TextSpan | undefined, - getToolTipContents: (t: T, prev: T | undefined) => string[] | undefined): string { + getToolTipContents: (t: T, prev: T | undefined) => string[] | undefined, + ): string { const bar = "-".repeat(70); const sorted = items.slice(); // sort by file, then *backwards* by position in the file so I can insert multiple times on a line without counting sorted.sort((q1, q2) => q1.marker.fileName === q1.marker.fileName - ? (q1.marker.position > q2.marker.position ? -1 : 1) - : (q1.marker.fileName > q1.marker.fileName ? 1 : -1)); + ? (q1.marker.position > q2.marker.position ? -1 : 1) + : (q1.marker.fileName > q1.marker.fileName ? 1 : -1) + ); const files = new Map(); let previous: T | undefined; for (const { marker, item } of sorted) { @@ -2428,7 +2924,10 @@ export class TestState { files.set(marker.fileName, lines); previous = item; } - return Array.from(files.entries(), ([fileName, lines]) => `=== ${fileName} ===\n` + lines.map(l => "// " + l).join("\n")) + return Array.from( + files.entries(), + ([fileName, lines]) => `=== ${fileName} ===\n` + lines.map(l => "// " + l).join("\n"), + ) .join("\n\n"); } @@ -2438,8 +2937,13 @@ export class TestState { const markers = this.getMarkers(); const fileContent = this.activeFile.content; const text = markers.map(marker => { - const baselineContent = [fileContent.slice(0, marker.position) + "/**/" + fileContent.slice(marker.position) + n]; - let selectionRange: ts.SelectionRange | undefined = this.languageService.getSmartSelectionRange(this.activeFile.fileName, marker.position); + const baselineContent = [ + fileContent.slice(0, marker.position) + "/**/" + fileContent.slice(marker.position) + n, + ]; + let selectionRange: ts.SelectionRange | undefined = this.languageService.getSmartSelectionRange( + this.activeFile.fileName, + marker.position, + ); while (selectionRange) { const { textSpan } = selectionRange; let masked = ts.arrayFrom(fileContent).map((char, index) => { @@ -2450,7 +2954,8 @@ export class TestState { return ts.isLineBreak(charCode) ? char : " "; }).join(""); masked = masked.replace(/^\s*$\r?\n?/gm, ""); // Remove blank lines - const isRealCharacter = (char: string) => char !== "•" && char !== "↲" && !ts.isWhiteSpaceLike(char.charCodeAt(0)); + const isRealCharacter = (char: string) => + char !== "•" && char !== "↲" && !ts.isWhiteSpaceLike(char.charCodeAt(0)); const leadingWidth = ts.arrayFrom(masked).findIndex(isRealCharacter); const trailingWidth = ts.findLastIndex(ts.arrayFrom(masked), isRealCharacter); masked = masked.slice(0, leadingWidth) @@ -2466,7 +2971,9 @@ export class TestState { } public printBreakpointLocation(pos: number) { - Harness.IO.log("\n**Pos: " + pos + " " + this.spanInfoToString(this.getBreakpointStatementLocation(pos)!, " ")); + Harness.IO.log( + "\n**Pos: " + pos + " " + this.spanInfoToString(this.getBreakpointStatementLocation(pos)!, " "), + ); } public printBreakpointAtCurrentLocation() { @@ -2474,12 +2981,19 @@ export class TestState { } public printCurrentParameterHelp() { - const help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, /*options*/ undefined); + const help = this.languageService.getSignatureHelpItems( + this.activeFile.fileName, + this.currentCaretPosition, + /*options*/ undefined, + ); Harness.IO.log(stringify(help)); } public printCurrentQuickInfo() { - const quickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition)!; + const quickInfo = this.languageService.getQuickInfoAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + )!; Harness.IO.log("Quick Info: " + quickInfo.displayParts!.map(part => part.text).join("")); } @@ -2492,20 +3006,22 @@ export class TestState { if (errorList.length) { errorList.forEach(err => { Harness.IO.log( - "start: " + err.start + - ", length: " + err.length + - ", message: " + ts.flattenDiagnosticMessageText(err.messageText, Harness.IO.newLine())); + "start: " + err.start + + ", length: " + err.length + + ", message: " + ts.flattenDiagnosticMessageText(err.messageText, Harness.IO.newLine()), + ); }); } } public printCurrentFileState(showWhitespace: boolean, makeCaretVisible: boolean) { for (const file of this.testData.files) { - const active = (this.activeFile === file); + const active = this.activeFile === file; Harness.IO.log(`=== Script (${file.fileName}) ${(active ? "(active, cursor at |)" : "")} ===`); let content = this.getFileContent(file.fileName); if (active) { - content = content.substr(0, this.currentCaretPosition) + (makeCaretVisible ? "|" : "") + content.substr(this.currentCaretPosition); + content = content.substr(0, this.currentCaretPosition) + (makeCaretVisible ? "|" : "") + + content.substr(this.currentCaretPosition); } if (showWhitespace) { content = makeWhitespaceVisible(content); @@ -2520,18 +3036,20 @@ export class TestState { } private getBaselineFileNameForInternalFourslashFile(ext = ".baseline") { - return this.testData.globalOptions[MetadataOptionNames.baselineFile] || - ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ext); + return this.testData.globalOptions[MetadataOptionNames.baselineFile] + || ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ext); } private getBaselineFileNameForContainingTestFile(ext = ".baseline") { - return this.testData.globalOptions[MetadataOptionNames.baselineFile] || - ts.getBaseFileName(this.originalInputFileName).replace(ts.Extension.Ts, ext); + return this.testData.globalOptions[MetadataOptionNames.baselineFile] + || ts.getBaseFileName(this.originalInputFileName).replace(ts.Extension.Ts, ext); } - private getSignatureHelp({ triggerReason }: FourSlashInterface.VerifySignatureHelpOptions): ts.SignatureHelpItems | undefined { + private getSignatureHelp( + { triggerReason }: FourSlashInterface.VerifySignatureHelpOptions, + ): ts.SignatureHelpItems | undefined { return this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, { - triggerReason + triggerReason, }); } @@ -2552,8 +3070,14 @@ export class TestState { } const longestNameLength = max(entries, m => m.name.length); const longestKindLength = max(entries, m => m.kind.length); - entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0); - const membersString = entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers} ${m.isRecommended ? "recommended " : ""}${m.source === undefined ? "" : m.source}`).join("\n"); + entries.sort((m, n) => + m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0 + ); + const membersString = entries.map(m => + `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers} ${ + m.isRecommended ? "recommended " : "" + }${m.source === undefined ? "" : m.source}` + ).join("\n"); Harness.IO.log(membersString); } @@ -2576,7 +3100,12 @@ export class TestState { // Handle post-keystroke formatting if (this.enableFormatting) { - const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsAfterKeystroke( + this.activeFile.fileName, + offset, + ch, + this.formatCodeSettings, + ); if (edits.length) { offset += this.applyEdits(this.activeFile.fileName, edits); } @@ -2592,8 +3121,14 @@ export class TestState { } public deleteLineRange(startIndex: number, endIndexInclusive: number) { - const startPos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: startIndex, character: 0 }); - const endPos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: endIndexInclusive + 1, character: 0 }); + const startPos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { + line: startIndex, + character: 0, + }); + const endPos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { + line: endIndexInclusive + 1, + character: 0, + }); this.replace(startPos, endPos - startPos, ""); } @@ -2645,8 +3180,8 @@ export class TestState { this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset, { triggerReason: { kind: "characterTyped", - triggerCharacter: ch - } + triggerCharacter: ch, + }, }); } else if (prevChar === " " && /A-Za-z_/.test(ch)) { @@ -2661,7 +3196,12 @@ export class TestState { // Handle post-keystroke formatting if (this.enableFormatting) { - const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsAfterKeystroke( + this.activeFile.fileName, + offset, + ch, + this.formatCodeSettings, + ); if (edits.length) { offset += this.applyEdits(this.activeFile.fileName, edits); } @@ -2674,19 +3214,28 @@ export class TestState { // Enters text as if the user had pasted it public paste(text: string) { const start = this.currentCaretPosition; - this.editScriptAndUpdateMarkers(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition, text); + this.editScriptAndUpdateMarkers( + this.activeFile.fileName, + this.currentCaretPosition, + this.currentCaretPosition, + text, + ); this.checkPostEditInvariants(); const offset = this.currentCaretPosition += text.length; // Handle formatting if (this.enableFormatting) { - const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsForRange( + this.activeFile.fileName, + start, + offset, + this.formatCodeSettings, + ); if (edits.length) { this.applyEdits(this.activeFile.fileName, edits); } } - this.checkPostEditInvariants(); } @@ -2708,15 +3257,26 @@ export class TestState { const options: ts.CreateSourceFileOptions = { languageVersion: ts.ScriptTarget.Latest, impliedNodeFormat: ts.getImpliedNodeFormatForFile( - ts.toPath(this.activeFile.fileName, this.languageServiceAdapterHost.sys.getCurrentDirectory(), ts.hostGetCanonicalFileName(this.languageServiceAdapterHost)), + ts.toPath( + this.activeFile.fileName, + this.languageServiceAdapterHost.sys.getCurrentDirectory(), + ts.hostGetCanonicalFileName(this.languageServiceAdapterHost), + ), /*packageJsonInfoCache*/ undefined, this.languageServiceAdapterHost, - this.languageService.getProgram()?.getCompilerOptions() || {} + this.languageService.getProgram()?.getCompilerOptions() || {}, + ), + setExternalModuleIndicator: ts.getSetExternalModuleIndicator( + this.languageService.getProgram()?.getCompilerOptions() || {}, ), - setExternalModuleIndicator: ts.getSetExternalModuleIndicator(this.languageService.getProgram()?.getCompilerOptions() || {}), }; const referenceSourceFile = ts.createLanguageServiceSourceFile( - this.activeFile.fileName, createScriptSnapShot(content), options, /*version:*/ "0", /*setNodeParents*/ false); + this.activeFile.fileName, + createScriptSnapShot(content), + options, + /*version:*/ "0", + /*setNodeParents*/ false, + ); const referenceSyntaxDiagnostics = referenceSourceFile.parseDiagnostics; Utils.assertDiagnosticsEquals(incrementalSyntaxDiagnostics, referenceSyntaxDiagnostics); @@ -2765,17 +3325,30 @@ export class TestState { } public formatDocument() { - const edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsForDocument( + this.activeFile.fileName, + this.formatCodeSettings, + ); this.applyEdits(this.activeFile.fileName, edits); } public formatSelection(start: number, end: number) { - const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, end, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsForRange( + this.activeFile.fileName, + start, + end, + this.formatCodeSettings, + ); this.applyEdits(this.activeFile.fileName, edits); } public formatOnType(pos: number, key: string) { - const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, pos, key, this.formatCodeSettings); + const edits = this.languageService.getFormattingEditsAfterKeystroke( + this.activeFile.fileName, + pos, + key, + this.formatCodeSettings, + ); this.applyEdits(this.activeFile.fileName, edits); } @@ -2852,40 +3425,72 @@ export class TestState { public verifyCaretAtMarker(markerName = "") { const pos = this.getMarkerByName(markerName); if (pos.fileName !== this.activeFile.fileName) { - throw new Error(`verifyCaretAtMarker failed - expected to be in file "${pos.fileName}", but was in file "${this.activeFile.fileName}"`); + throw new Error( + `verifyCaretAtMarker failed - expected to be in file "${pos.fileName}", but was in file "${this.activeFile.fileName}"`, + ); } if (pos.position !== this.currentCaretPosition) { - throw new Error(`verifyCaretAtMarker failed - expected to be at marker "/*${markerName}*/, but was at position ${this.currentCaretPosition}(${this.getLineColStringAtPosition(this.currentCaretPosition)})`); + throw new Error( + `verifyCaretAtMarker failed - expected to be at marker "/*${markerName}*/, but was at position ${this.currentCaretPosition}(${ + this.getLineColStringAtPosition(this.currentCaretPosition) + })`, + ); } } - private getIndentation(fileName: string, position: number, indentStyle: ts.IndentStyle, baseIndentSize: number): number { + private getIndentation( + fileName: string, + position: number, + indentStyle: ts.IndentStyle, + baseIndentSize: number, + ): number { const formatOptions = ts.clone(this.formatCodeSettings); formatOptions.indentStyle = indentStyle; formatOptions.baseIndentSize = baseIndentSize; return this.languageService.getIndentationAtPosition(fileName, position, formatOptions); } - public verifyIndentationAtCurrentPosition(numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) { - const actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition, indentStyle, baseIndentSize); + public verifyIndentationAtCurrentPosition( + numberOfSpaces: number, + indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, + baseIndentSize = 0, + ) { + const actual = this.getIndentation( + this.activeFile.fileName, + this.currentCaretPosition, + indentStyle, + baseIndentSize, + ); const lineCol = this.getLineColStringAtPosition(this.currentCaretPosition); if (actual !== numberOfSpaces) { - this.raiseError(`verifyIndentationAtCurrentPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`); + this.raiseError( + `verifyIndentationAtCurrentPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`, + ); } } - public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) { + public verifyIndentationAtPosition( + fileName: string, + position: number, + numberOfSpaces: number, + indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, + baseIndentSize = 0, + ) { const actual = this.getIndentation(fileName, position, indentStyle, baseIndentSize); const lineCol = this.getLineColStringAtPosition(position); if (actual !== numberOfSpaces) { - this.raiseError(`verifyIndentationAtPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`); + this.raiseError( + `verifyIndentationAtPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`, + ); } } public verifyCurrentLineContent(text: string) { const actual = this.getCurrentLineContent(); if (actual !== text) { - throw new Error("verifyCurrentLineContent\n" + displayExpectedAndActualString(text, actual, /*quoted*/ true)); + throw new Error( + "verifyCurrentLineContent\n" + displayExpectedAndActualString(text, actual, /*quoted*/ true), + ); } } @@ -2908,21 +3513,34 @@ export class TestState { } public verifyTextAtCaretIs(text: string) { - const actual = this.getFileContent(this.activeFile.fileName).substring(this.currentCaretPosition, this.currentCaretPosition + text.length); + const actual = this.getFileContent(this.activeFile.fileName).substring( + this.currentCaretPosition, + this.currentCaretPosition + text.length, + ); if (actual !== text) { throw new Error("verifyTextAtCaretIs\n" + displayExpectedAndActualString(text, actual, /*quoted*/ true)); } } public verifyCurrentNameOrDottedNameSpanText(text: string) { - const span = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition); + const span = this.languageService.getNameOrDottedNameSpan( + this.activeFile.fileName, + this.currentCaretPosition, + this.currentCaretPosition, + ); if (!span) { - return this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + displayExpectedAndActualString("\"" + text + "\"", "undefined")); + return this.raiseError( + "verifyCurrentNameOrDottedNameSpanText\n" + + displayExpectedAndActualString('"' + text + '"', "undefined"), + ); } const actual = this.getFileContent(this.activeFile.fileName).substring(span.start, ts.textSpanEnd(span)); if (actual !== text) { - this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + displayExpectedAndActualString(text, actual, /*quoted*/ true)); + this.raiseError( + "verifyCurrentNameOrDottedNameSpanText\n" + + displayExpectedAndActualString(text, actual, /*quoted*/ true), + ); } } @@ -2933,15 +3551,15 @@ export class TestState { public baselineCurrentFileNameOrDottedNameSpans() { Harness.Baseline.runBaseline( this.testData.globalOptions[MetadataOptionNames.baselineFile], - this.baselineCurrentFileLocations(pos => this.getNameOrDottedNameSpan(pos)!)); + this.baselineCurrentFileLocations(pos => this.getNameOrDottedNameSpan(pos)!), + ); } public printNameOrDottedNameSpans(pos: number) { Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos)!, "**")); } - private classificationToIdentifier(classification: number){ - + private classificationToIdentifier(classification: number) { const tokenTypes: string[] = []; tokenTypes[ts.classifier.v2020.TokenType.class] = "class"; tokenTypes[ts.classifier.v2020.TokenType.enum] = "enum"; @@ -2964,7 +3582,6 @@ export class TestState { tokenModifiers[ts.classifier.v2020.TokenModifier.local] = "local"; tokenModifiers[ts.classifier.v2020.TokenModifier.defaultLibrary] = "defaultLibrary"; - function getTokenTypeFromClassification(tsClassification: number): number | undefined { if (tsClassification > ts.classifier.v2020.TokenEncodingConsts.modifierMask) { return (tsClassification >> ts.classifier.v2020.TokenEncodingConsts.typeOffset) - 1; @@ -2982,22 +3599,32 @@ export class TestState { return [tokenTypes[typeIdx], ...tokenModifiers.filter((_, i) => modSet & 1 << i)].join("."); } - private verifyClassifications(expected: { classificationType: string | number, text?: string; textSpan?: TextSpan }[], actual: (ts.ClassifiedSpan | ts.ClassifiedSpan2020)[] , sourceFileText: string) { + private verifyClassifications( + expected: { classificationType: string | number; text?: string; textSpan?: TextSpan; }[], + actual: (ts.ClassifiedSpan | ts.ClassifiedSpan2020)[], + sourceFileText: string, + ) { if (actual.length !== expected.length) { - this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length + - ", but was " + actual.length + - jsonMismatchString()); + this.raiseError( + "verifyClassifications failed - expected total classifications to be " + expected.length + + ", but was " + actual.length + + jsonMismatchString(), + ); } ts.zipWith(expected, actual, (expectedClassification, actualClassification) => { const expectedType = expectedClassification.classificationType; - const actualType = typeof actualClassification.classificationType === "number" ? this.classificationToIdentifier(actualClassification.classificationType) : actualClassification.classificationType; + const actualType = typeof actualClassification.classificationType === "number" + ? this.classificationToIdentifier(actualClassification.classificationType) + : actualClassification.classificationType; if (expectedType !== actualType) { - this.raiseError("verifyClassifications failed - expected classifications type to be " + - expectedType + ", but was " + - actualType + - jsonMismatchString()); + this.raiseError( + "verifyClassifications failed - expected classifications type to be " + + expectedType + ", but was " + + actualType + + jsonMismatchString(), + ); } const expectedSpan = expectedClassification.textSpan; @@ -3007,28 +3634,34 @@ export class TestState { const expectedLength = expectedSpan.end - expectedSpan.start; if (expectedSpan.start !== actualSpan.start || expectedLength !== actualSpan.length) { - this.raiseError("verifyClassifications failed - expected span of text to be " + - "{start=" + expectedSpan.start + ", length=" + expectedLength + "}, but was " + - "{start=" + actualSpan.start + ", length=" + actualSpan.length + "}" + - jsonMismatchString()); + this.raiseError( + "verifyClassifications failed - expected span of text to be " + + "{start=" + expectedSpan.start + ", length=" + expectedLength + "}, but was " + + "{start=" + actualSpan.start + ", length=" + actualSpan.length + "}" + + jsonMismatchString(), + ); } } const actualText = this.activeFile.content.substr(actualSpan.start, actualSpan.length); if (expectedClassification.text !== actualText) { - this.raiseError("verifyClassifications failed - expected classified text to be " + - expectedClassification.text + ", but was " + - actualText + - jsonMismatchString()); + this.raiseError( + "verifyClassifications failed - expected classified text to be " + + expectedClassification.text + ", but was " + + actualText + + jsonMismatchString(), + ); } }); function jsonMismatchString() { - const showActual = actual.map(({ classificationType, textSpan }) => - ({ classificationType, text: sourceFileText.slice(textSpan.start, textSpan.start + textSpan.length) })); - return Harness.IO.newLine() + - "expected: '" + Harness.IO.newLine() + stringify(expected) + "'" + Harness.IO.newLine() + - "actual: '" + Harness.IO.newLine() + stringify(showActual) + "'"; + const showActual = actual.map(({ classificationType, textSpan }) => ({ + classificationType, + text: sourceFileText.slice(textSpan.start, textSpan.start + textSpan.length), + })); + return Harness.IO.newLine() + + "expected: '" + Harness.IO.newLine() + stringify(expected) + "'" + Harness.IO.newLine() + + "actual: '" + Harness.IO.newLine() + stringify(showActual) + "'"; } } @@ -3036,21 +3669,24 @@ export class TestState { if (this.testType === FourSlashTestType.Server) { const actual = (this.languageService as ts.server.SessionClient).getProjectInfo( this.activeFile.fileName, - /*needFileNameList*/ true + /*needFileNameList*/ true, ); assert.equal( expected.join(","), actual.fileNames!.map(file => { return file.replace(this.basePath + "/", ""); - }).join(",") + }).join(","), ); } } public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty) { - const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, - ts.createTextSpan(0, this.activeFile.content.length), format); - const replacement = [`const c2 = classification("2020");`,`verify.semanticClassificationsAre("2020",`]; + const actual = this.languageService.getSemanticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + format, + ); + const replacement = [`const c2 = classification("2020");`, `verify.semanticClassificationsAre("2020",`]; for (const a of actual) { const identifier = this.classificationToIdentifier(a.classificationType as number); const text = this.activeFile.content.slice(a.textSpan.start, a.textSpan.start + a.textSpan.length); @@ -3058,7 +3694,9 @@ export class TestState { } replacement.push(");"); - throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); + throw new Error( + "You need to change the source code of fourslash test to use replaceWithSemanticClassifications", + ); // const fs = require("fs"); // const testfilePath = this.originalInputFileName.slice(1); @@ -3068,28 +3706,47 @@ export class TestState { } public verifyEncodedSyntacticClassificationsLength(expected: number) { - const actual = this.languageService.getEncodedSyntacticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length)); + const actual = this.languageService.getEncodedSyntacticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + ); if (actual.spans.length !== expected) { - this.raiseError(`encodedSyntacticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`); + this.raiseError( + `encodedSyntacticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`, + ); } } public verifyEncodedSemanticClassificationsLength(format: ts.SemanticClassificationFormat, expected: number) { - const actual = this.languageService.getEncodedSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format); + const actual = this.languageService.getEncodedSemanticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + format, + ); if (actual.spans.length !== expected) { - this.raiseError(`encodedSemanticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`); + this.raiseError( + `encodedSemanticClassificationsLength failed - expected total spans to be ${expected} got ${actual.spans.length}`, + ); } } - public verifySemanticClassifications(format: ts.SemanticClassificationFormat, expected: { classificationType: string | number; text?: string }[]) { - const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, - ts.createTextSpan(0, this.activeFile.content.length), format); + public verifySemanticClassifications( + format: ts.SemanticClassificationFormat, + expected: { classificationType: string | number; text?: string; }[], + ) { + const actual = this.languageService.getSemanticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + format, + ); this.verifyClassifications(expected, actual, this.activeFile.content); } - public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) { - const actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName, - ts.createTextSpan(0, this.activeFile.content.length)); + public verifySyntacticClassifications(expected: { classificationType: string; text: string; }[]) { + const actual = this.languageService.getSyntacticClassifications( + this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), + ); this.verifyClassifications(expected, actual, this.activeFile.content); } @@ -3102,7 +3759,7 @@ export class TestState { } private printOutliningSpansInline(spans: ts.OutliningSpan[]) { - const allSpanInsets = [] as { text: string, pos: number }[]; + const allSpanInsets = [] as { text: string; pos: number; }[]; let annotated = this.activeFile.content; ts.forEach(spans, span => { allSpanInsets.push({ text: "[|", pos: span.textSpan.start }); @@ -3111,7 +3768,7 @@ export class TestState { const reverseSpans = allSpanInsets.sort((l, r) => r.pos - l.pos); ts.forEach(reverseSpans, span => { - annotated = annotated.slice(0, span.pos) + span.text + annotated.slice(span.pos); + annotated = annotated.slice(0, span.pos) + span.text + annotated.slice(span.pos); }); Harness.IO.log(`\nMockup:\n${annotated}`); } @@ -3121,15 +3778,30 @@ export class TestState { const filterActual = ts.filter(actual, f => kind === undefined ? true : f.kind === kind); if (filterActual.length !== spans.length) { - this.raiseError(`verifyOutliningSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}\n\nFound Spans:\n\n${this.printOutliningSpansInline(actual)}`); + this.raiseError( + `verifyOutliningSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}\n\nFound Spans:\n\n${ + this.printOutliningSpansInline(actual) + }`, + ); } ts.zipWith(spans, filterActual, (expectedSpan, actualSpan, i) => { - if (expectedSpan.pos !== actualSpan.textSpan.start || expectedSpan.end !== ts.textSpanEnd(actualSpan.textSpan)) { - return this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.textSpan.start},${ts.textSpanEnd(actualSpan.textSpan)})`); + if ( + expectedSpan.pos !== actualSpan.textSpan.start + || expectedSpan.end !== ts.textSpanEnd(actualSpan.textSpan) + ) { + return this.raiseError( + `verifyOutliningSpans failed - span ${(i + + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.textSpan.start},${ + ts.textSpanEnd(actualSpan.textSpan) + })`, + ); } if (kind !== undefined && actualSpan.kind !== kind) { - return this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected kind: ('${kind}'), actual: ('${actualSpan.kind}')`); + return this.raiseError( + `verifyOutliningSpans failed - span ${(i + + 1)} expected kind: ('${kind}'), actual: ('${actualSpan.kind}')`, + ); } }); } @@ -3138,29 +3810,50 @@ export class TestState { const actual = this.languageService.getOutliningSpans(this.activeFile.fileName); if (actual.length !== spans.length) { - this.raiseError(`verifyOutliningHintSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}`); + this.raiseError( + `verifyOutliningHintSpans failed - expected total spans to be ${spans.length}, but was ${actual.length}`, + ); } ts.zipWith(spans, actual, (expectedSpan, actualSpan, i) => { - if (expectedSpan.pos !== actualSpan.hintSpan.start || expectedSpan.end !== ts.textSpanEnd(actualSpan.hintSpan)) { - return this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.hintSpan.start},${ts.textSpanEnd(actualSpan.hintSpan)})`); + if ( + expectedSpan.pos !== actualSpan.hintSpan.start + || expectedSpan.end !== ts.textSpanEnd(actualSpan.hintSpan) + ) { + return this.raiseError( + `verifyOutliningSpans failed - span ${(i + + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.hintSpan.start},${ + ts.textSpanEnd(actualSpan.hintSpan) + })`, + ); } }); } public verifyTodoComments(descriptors: string[], spans: Range[]) { - const actual = this.languageService.getTodoComments(this.activeFile.fileName, - descriptors.map(d => ({ text: d, priority: 0 }))); + const actual = this.languageService.getTodoComments( + this.activeFile.fileName, + descriptors.map(d => ({ text: d, priority: 0 })), + ); if (actual.length !== spans.length) { - this.raiseError(`verifyTodoComments failed - expected total spans to be ${spans.length}, but was ${actual.length}`); + this.raiseError( + `verifyTodoComments failed - expected total spans to be ${spans.length}, but was ${actual.length}`, + ); } ts.zipWith(spans, actual, (expectedSpan, actualComment, i) => { const actualCommentSpan = ts.createTextSpan(actualComment.position, actualComment.message.length); - if (expectedSpan.pos !== actualCommentSpan.start || expectedSpan.end !== ts.textSpanEnd(actualCommentSpan)) { - this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualCommentSpan.start},${ts.textSpanEnd(actualCommentSpan)})`); + if ( + expectedSpan.pos !== actualCommentSpan.start || expectedSpan.end !== ts.textSpanEnd(actualCommentSpan) + ) { + this.raiseError( + `verifyOutliningSpans failed - span ${(i + + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualCommentSpan.start},${ + ts.textSpanEnd(actualCommentSpan) + })`, + ); } }); } @@ -3176,20 +3869,29 @@ export class TestState { const fixes = this.getCodeFixes(fileName, errorCode); if (index === undefined) { if (!(fixes && fixes.length === 1)) { - this.raiseError(`Should find exactly one codefix, but ${fixes ? fixes.length : "none"} found. ${fixes ? fixes.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`); + this.raiseError( + `Should find exactly one codefix, but ${fixes ? fixes.length : "none"} found. ${ + fixes ? fixes.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" + }`, + ); } index = 0; } else { if (!(fixes && fixes.length >= index + 1)) { - this.raiseError(`Should find at least ${index + 1} codefix(es), but ${fixes ? fixes.length : "none"} found.`); + this.raiseError( + `Should find at least ${index + 1} codefix(es), but ${fixes ? fixes.length : "none"} found.`, + ); } } this.applyChanges(fixes[index].changes); } - public applyCodeActionFromCompletion(markerName: string | undefined, options: FourSlashInterface.VerifyCompletionActionOptions) { + public applyCodeActionFromCompletion( + markerName: string | undefined, + options: FourSlashInterface.VerifyCompletionActionOptions, + ) { if (markerName !== undefined) { this.goToMarker(markerName); } @@ -3199,9 +3901,13 @@ export class TestState { const completions = this.getCompletionListAtCaret(options.preferences)?.entries; const matchingName = completions?.filter(e => e.name === options.name); const detailMessage = matchingName?.length - ? `\n Found ${matchingName.length} with name '${options.name}' from source(s) ${matchingName.map(e => `'${e.source}'`).join(", ")}.` + ? `\n Found ${matchingName.length} with name '${options.name}' from source(s) ${ + matchingName.map(e => `'${e.source}'`).join(", ") + }.` : ` (In fact, there were no completions with name '${options.name}' at all.)`; - return this.raiseError(`No completions were found for the given name, source/data, and preferences.` + detailMessage); + return this.raiseError( + `No completions were found for the given name, source/data, and preferences.` + detailMessage, + ); } const codeActions = details.codeActions; if (codeActions?.length !== 1) { @@ -3232,7 +3938,9 @@ export class TestState { private verifyTextMatches(actualText: string, includeWhitespace: boolean, expectedText: string) { const removeWhitespace = (s: string): string => includeWhitespace ? s : this.removeWhitespace(s); if (removeWhitespace(actualText) !== removeWhitespace(expectedText)) { - this.raiseError(`Actual range text doesn't match expected text.\n${showTextDiff(expectedText, actualText)}`); + this.raiseError( + `Actual range text doesn't match expected text.\n${showTextDiff(expectedText, actualText)}`, + ); } } @@ -3241,18 +3949,40 @@ export class TestState { * (ie: [|...|]) in the file after applying the codefix sole codefix * in the source file. */ - public verifyRangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number) { + public verifyRangeAfterCodeFix( + expectedText: string, + includeWhiteSpace?: boolean, + errorCode?: number, + index?: number, + ) { this.getAndApplyCodeActions(errorCode, index); this.verifyRangeIs(expectedText, includeWhiteSpace); } - public verifyCodeFixAll({ fixId, fixAllDescription, newFileContent, commands: expectedCommands }: FourSlashInterface.VerifyCodeFixAllOptions): void { + public verifyCodeFixAll( + { fixId, fixAllDescription, newFileContent, commands: expectedCommands }: + FourSlashInterface.VerifyCodeFixAllOptions, + ): void { const fixWithId = ts.find(this.getCodeFixes(this.activeFile.fileName), a => a.fixId === fixId); - ts.Debug.assert(fixWithId !== undefined, "No available code fix has the expected id. Fix All is not available if there is only one potentially fixable diagnostic present.", () => - `Expected '${fixId}'. Available actions:\n${ts.mapDefined(this.getCodeFixes(this.activeFile.fileName), a => `${a.fixName} (${a.fixId || "no fix id"})`).join("\n")}`); + ts.Debug.assert( + fixWithId !== undefined, + "No available code fix has the expected id. Fix All is not available if there is only one potentially fixable diagnostic present.", + () => + `Expected '${fixId}'. Available actions:\n${ + ts.mapDefined( + this.getCodeFixes(this.activeFile.fileName), + a => `${a.fixName} (${a.fixId || "no fix id"})`, + ).join("\n") + }`, + ); ts.Debug.assertEqual(fixWithId.fixAllDescription, fixAllDescription); - const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.emptyOptions); + const { changes, commands } = this.languageService.getCombinedCodeFix( + { type: "file", fileName: this.activeFile.fileName }, + fixId, + this.formatCodeSettings, + ts.emptyOptions, + ); assert.deepEqual(commands, expectedCommands); this.verifyNewContent({ newFileContent }, changes); } @@ -3263,13 +3993,19 @@ export class TestState { let index = options.index; if (index === undefined) { if (!(actions && actions.length === 1)) { - this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`); + this.raiseError( + `Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${ + actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" + }`, + ); } index = 0; } else { if (!(actions && actions.length >= index + 1)) { - this.raiseError(`Should find at least ${index + 1} codefix(es), but ${actions ? actions.length : "none"} found.`); + this.raiseError( + `Should find at least ${index + 1} codefix(es), but ${actions ? actions.length : "none"} found.`, + ); } } @@ -3298,13 +4034,22 @@ export class TestState { } } - private verifyNewContent({ newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, changes: readonly ts.FileTextChanges[]): void { + private verifyNewContent( + { newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, + changes: readonly ts.FileTextChanges[], + ): void { if (newRangeContent !== undefined) { assert(newFileContent === undefined); - assert(changes.length === 1, "Affected 0 or more than 1 file, must use 'newFileContent' instead of 'newRangeContent'"); + assert( + changes.length === 1, + "Affected 0 or more than 1 file, must use 'newFileContent' instead of 'newRangeContent'", + ); const change = ts.first(changes); assert(change.fileName = this.activeFile.fileName); - const newText = ts.textChanges.applyChanges(this.getFileContent(this.activeFile.fileName), change.textChanges); + const newText = ts.textChanges.applyChanges( + this.getFileContent(this.activeFile.fileName), + change.textChanges, + ); const newRange = updateTextRangeForTextChanges(this.getOnlyRange(), change.textChanges); const actualText = newText.slice(newRange.pos, newRange.end); this.verifyTextMatches(actualText, /*includeWhitespace*/ true, newRangeContent); @@ -3318,7 +4063,8 @@ export class TestState { ts.Debug.fail(`Did not expect a change in ${change.fileName}`); } const oldText = this.tryGetFileContent(change.fileName); - const newContent = change.isNewFile ? ts.first(change.textChanges).newText : ts.textChanges.applyChanges(oldText!, change.textChanges); + const newContent = change.isNewFile ? ts.first(change.textChanges).newText + : ts.textChanges.applyChanges(oldText!, change.textChanges); this.verifyTextMatches(newContent, /*includeWhitespace*/ true, expectedNewContent); } for (const newFileName in newFileContent) { @@ -3327,7 +4073,10 @@ export class TestState { } } - private verifyNewContentAfterChange({ newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, changedFiles: readonly string[]) { + private verifyNewContentAfterChange( + { newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, + changedFiles: readonly string[], + ) { const assertedChangedFiles = !newFileContent || typeof newFileContent === "string" ? [this.activeFile.fileName] : ts.getOwnKeys(newFileContent); @@ -3353,7 +4102,12 @@ export class TestState { * Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found. * @param fileName Path to file where error should be retrieved from. */ - private getCodeFixes(fileName: string, errorCode?: number, preferences: ts.UserPreferences = ts.emptyOptions, position?: number): readonly ts.CodeFixAction[] { + private getCodeFixes( + fileName: string, + errorCode?: number, + preferences: ts.UserPreferences = ts.emptyOptions, + position?: number, + ): readonly ts.CodeFixAction[] { if (this.testType === FourSlashTestType.Server) { this.configure(preferences); } @@ -3361,7 +4115,7 @@ export class TestState { const diagnosticsForCodeFix = this.getDiagnostics(fileName, /*includeSuggestions*/ true).map(diagnostic => ({ start: diagnostic.start, length: diagnostic.length, - code: diagnostic.code + code: diagnostic.code, })); return ts.flatMap(ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties), diagnostic => { @@ -3374,7 +4128,14 @@ export class TestState { return; } } - return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start!, diagnostic.start! + diagnostic.length!, [diagnostic.code], this.formatCodeSettings, preferences); + return this.languageService.getCodeFixesAtPosition( + fileName, + diagnostic.start!, + diagnostic.start! + diagnostic.length!, + [diagnostic.code], + this.formatCodeSettings, + preferences, + ); }); } @@ -3384,7 +4145,11 @@ export class TestState { } } - public verifyImportFixAtPosition(expectedTextArray: string[], errorCode: number | undefined, preferences: ts.UserPreferences | undefined) { + public verifyImportFixAtPosition( + expectedTextArray: string[], + errorCode: number | undefined, + preferences: ts.UserPreferences | undefined, + ) { const { fileName } = this.activeFile; const ranges = this.getRanges().filter(r => r.fileName === fileName); if (ranges.length > 1) { @@ -3396,7 +4161,9 @@ export class TestState { this.configure(preferences); } - const codeFixes = this.getCodeFixes(fileName, errorCode, preferences).filter(f => f.fixName === ts.codefix.importFixName); + const codeFixes = this.getCodeFixes(fileName, errorCode, preferences).filter(f => + f.fixName === ts.codefix.importFixName + ); if (codeFixes.length === 0) { if (expectedTextArray.length !== 0) { @@ -3423,7 +4190,11 @@ export class TestState { this.editScriptAndUpdateMarkers(fileName, span.start, span.start + insertedText.length, deletedText); } if (expectedTextArray.length !== actualTextArray.length) { - this.raiseError(`Expected ${expectedTextArray.length} import fixes, got ${actualTextArray.length}:\n\n${actualTextArray.join("\n\n" + "-".repeat(20) + "\n\n")}`); + this.raiseError( + `Expected ${expectedTextArray.length} import fixes, got ${actualTextArray.length}:\n\n${ + actualTextArray.join("\n\n" + "-".repeat(20) + "\n\n") + }`, + ); } ts.zipWith(expectedTextArray, actualTextArray, (expected, actual, index) => { if (expected !== actual) { @@ -3432,7 +4203,11 @@ export class TestState { }); } - public verifyImportFixModuleSpecifiers(markerName: string, moduleSpecifiers: string[], preferences?: ts.UserPreferences) { + public verifyImportFixModuleSpecifiers( + markerName: string, + moduleSpecifiers: string[], + preferences?: ts.UserPreferences, + ) { const marker = this.getMarkerByName(markerName); const codeFixes = this.getCodeFixes(marker.fileName, ts.Diagnostics.Cannot_find_name_0.code, { includeCompletionsForModuleExports: true, @@ -3452,32 +4227,44 @@ export class TestState { public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined, options?: ts.DocCommentTemplateOptions) { const name = "verifyDocCommentTemplate"; - const actual = this.languageService.getDocCommentTemplateAtPosition(this.activeFile.fileName, this.currentCaretPosition, options || { generateReturnInDocTemplate: true }, this.formatCodeSettings)!; + const actual = this.languageService.getDocCommentTemplateAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + options || { generateReturnInDocTemplate: true }, + this.formatCodeSettings, + )!; if (expected === undefined) { if (actual) { - this.raiseError(`${name} failed - expected no template but got {newText: "${actual.newText}", caretOffset: ${actual.caretOffset}}`); + this.raiseError( + `${name} failed - expected no template but got {newText: "${actual.newText}", caretOffset: ${actual.caretOffset}}`, + ); } return; } else { if (actual === undefined) { - this.raiseError(`${name} failed - expected the template {newText: "${expected.newText}", caretOffset: "${expected.caretOffset}"} but got nothing instead`); + this.raiseError( + `${name} failed - expected the template {newText: "${expected.newText}", caretOffset: "${expected.caretOffset}"} but got nothing instead`, + ); } if (actual.newText !== expected.newText) { - this.raiseError(`${name} failed for expected insertion.\n${showTextDiff(expected.newText, actual.newText)}`); + this.raiseError( + `${name} failed for expected insertion.\n${showTextDiff(expected.newText, actual.newText)}`, + ); } if (actual.caretOffset !== expected.caretOffset) { - this.raiseError(`${name} failed - expected caretOffset: ${expected.caretOffset}\nactual caretOffset:${actual.caretOffset}`); + this.raiseError( + `${name} failed - expected caretOffset: ${expected.caretOffset}\nactual caretOffset:${actual.caretOffset}`, + ); } } } public verifyBraceCompletionAtPosition(negative: boolean, openingBrace: string) { - const openBraceMap = new Map(Object.entries({ "(": ts.CharacterCodes.openParen, "{": ts.CharacterCodes.openBrace, @@ -3485,7 +4272,7 @@ export class TestState { "'": ts.CharacterCodes.singleQuote, '"': ts.CharacterCodes.doubleQuote, "`": ts.CharacterCodes.backtick, - "<": ts.CharacterCodes.lessThan + "<": ts.CharacterCodes.lessThan, })); const charCode = openBraceMap.get(openingBrace); @@ -3496,7 +4283,11 @@ export class TestState { const position = this.currentCaretPosition; - const validBraceCompletion = this.languageService.isValidBraceCompletionAtPosition(this.activeFile.fileName, position, charCode); + const validBraceCompletion = this.languageService.isValidBraceCompletionAtPosition( + this.activeFile.fileName, + position, + charCode, + ); if (!negative && !validBraceCompletion) { this.raiseError(`${position} is not a valid brace completion position for ${openingBrace}`); @@ -3514,7 +4305,7 @@ export class TestState { includeCompletionsWithInsertText: true, allowIncompleteCompletions: true, includeCompletionsWithSnippetText: true, - ...preferences + ...preferences, }; this.goToMarker(marker); @@ -3522,25 +4313,52 @@ export class TestState { const fileName = this.activeFile.fileName; const ext = ts.getAnyExtensionFromPath(fileName).slice(1); const lang = ["mts", "cts"].includes(ext) ? "ts" : ext; - let baselineText = codeFence(this.renderMarkers([{ text: "|", fileName: marker.fileName, position: marker.position }], /*useTerminalBoldSequence*/ false), lang) + "\n\n"; + let baselineText = codeFence( + this.renderMarkers( + [{ text: "|", fileName: marker.fileName, position: marker.position }], + /*useTerminalBoldSequence*/ false, + ), + lang, + ) + "\n\n"; const completions = this.getCompletionListAtCaret(completionPreferences)!; - const autoImportCompletions = completions.entries.filter(c => c.hasAction && c.source && c.sortText === ts.Completions.SortText.AutoImportSuggestions); + const autoImportCompletions = completions.entries.filter(c => + c.hasAction && c.source && c.sortText === ts.Completions.SortText.AutoImportSuggestions + ); if (autoImportCompletions.length) { - baselineText += `## From completions\n\n${autoImportCompletions.map(c => `- \`${c.name}\` from \`"${c.source}"\``).join("\n")}\n\n`; + baselineText += `## From completions\n\n${ + autoImportCompletions.map(c => `- \`${c.name}\` from \`"${c.source}"\``).join("\n") + }\n\n`; autoImportCompletions.forEach(c => { const details = this.getCompletionEntryDetails(c.name, c.source, c.data, completionPreferences); - assert(details?.codeActions, `Entry '${c.name}' from "${c.source}" returned no code actions from completion details request`); - assert(details.codeActions.length === 1, `Entry '${c.name}' from "${c.source}" returned more than one code action`); - assert(details.codeActions[0].changes.length === 1, `Entry '${c.name}' from "${c.source}" returned a code action changing more than one file`); - assert(details.codeActions[0].changes[0].fileName === this.activeFile.fileName, `Entry '${c.name}' from "${c.source}" returned a code action changing a different file`); + assert( + details?.codeActions, + `Entry '${c.name}' from "${c.source}" returned no code actions from completion details request`, + ); + assert( + details.codeActions.length === 1, + `Entry '${c.name}' from "${c.source}" returned more than one code action`, + ); + assert( + details.codeActions[0].changes.length === 1, + `Entry '${c.name}' from "${c.source}" returned a code action changing more than one file`, + ); + assert( + details.codeActions[0].changes[0].fileName === this.activeFile.fileName, + `Entry '${c.name}' from "${c.source}" returned a code action changing a different file`, + ); const changes = details.codeActions[0].changes[0].textChanges; - const completionChange: ts.TextChange = { newText: c.insertText || c.name, span: c.replacementSpan || completions.optionalReplacementSpan || { start: marker.position, length: 0 } }; + const completionChange: ts.TextChange = { + newText: c.insertText || c.name, + span: c.replacementSpan || completions.optionalReplacementSpan + || { start: marker.position, length: 0 }, + }; const sortedChanges = [...changes, completionChange].sort((a, b) => a.span.start - b.span.start); let newFileContent = this.activeFile.content; for (let i = sortedChanges.length - 1; i >= 0; i--) { - newFileContent = newFileContent.substring(0, sortedChanges[i].span.start) + sortedChanges[i].newText + newFileContent.substring(sortedChanges[i].span.start + sortedChanges[i].span.length); + newFileContent = newFileContent.substring(0, sortedChanges[i].span.start) + sortedChanges[i].newText + + newFileContent.substring(sortedChanges[i].span.start + sortedChanges[i].span.length); } baselineText += codeFence(newFileContent, lang) + "\n\n"; }); @@ -3555,7 +4373,10 @@ export class TestState { baselineText += `## From codefixes\n\n`; for (const fullNameForCodeFix of fullNamesForCodeFix) { - this.applyEdits(fileName, [{ span: { start: 0, length: this.getFileContent(fileName).length }, newText: originalContent }]); + this.applyEdits(fileName, [{ + span: { start: 0, length: this.getFileContent(fileName).length }, + newText: originalContent, + }]); this.applyEdits(fileName, [{ span: ts.createTextSpanFromRange(range), newText: fullNameForCodeFix }]); baselineText += `### When marker text is \`${fullNameForCodeFix}\`\n\n`; @@ -3579,18 +4400,24 @@ export class TestState { Harness.Baseline.runBaseline(baselineFile, baselineText); } - public verifyJsxClosingTag(map: { [markerName: string]: ts.JsxClosingTagInfo | undefined }): void { + public verifyJsxClosingTag(map: { [markerName: string]: ts.JsxClosingTagInfo | undefined; }): void { for (const markerName in map) { this.goToMarker(markerName); - const actual = this.languageService.getJsxClosingTagAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const actual = this.languageService.getJsxClosingTagAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); assert.deepEqual(actual, map[markerName], markerName); } } - public verifyLinkedEditingRange(map: { [markerName: string]: ts.LinkedEditingInfo | undefined }): void { + public verifyLinkedEditingRange(map: { [markerName: string]: ts.LinkedEditingInfo | undefined; }): void { for (const markerName in map) { this.goToMarker(markerName); - const actual = this.languageService.getLinkedEditingRangeAtPosition(this.activeFile.fileName, this.currentCaretPosition); + const actual = this.languageService.getLinkedEditingRangeAtPosition( + this.activeFile.fileName, + this.currentCaretPosition, + ); assert.deepEqual(actual, map[markerName], markerName); } } @@ -3609,13 +4436,17 @@ export class TestState { Harness.Baseline.runBaseline(baselineFile, baselineContent); - function getLinkedEditingBaselineWorker(activeFile: FourSlashFile, offset: number, languageService: ts.LanguageService) { + function getLinkedEditingBaselineWorker( + activeFile: FourSlashFile, + offset: number, + languageService: ts.LanguageService, + ) { const fileName = activeFile.fileName; let baselineContent = `=== ${fileName} ===\n`; // get linkedEdit at every position in the file, then group positions by their linkedEdit const linkedEditsInFile = new Map(); - for(let pos = 0; pos < activeFile.content.length; pos++) { + for (let pos = 0; pos < activeFile.content.length; pos++) { const linkedEditAtPosition = languageService.getLinkedEditingRangeAtPosition(fileName, pos); if (!linkedEditAtPosition) continue; @@ -3626,10 +4457,13 @@ export class TestState { const linkedEditsByRange = [...linkedEditsInFile.entries()].sort((a, b) => a[1][0] - b[1][0]); if (linkedEditsByRange.length === 0) { - return { baselineContent: baselineContent + activeFile.content + `\n\n--No linked edits found--`, offset }; + return { + baselineContent: baselineContent + activeFile.content + `\n\n--No linked edits found--`, + offset, + }; } - let inlineLinkedEditBaselines: { start: number, end: number, index: number }[] = []; + let inlineLinkedEditBaselines: { start: number; end: number; index: number; }[] = []; let linkedEditInfoBaseline = ""; for (const edit of linkedEditsByRange) { const [linkedEdit, positions] = edit; @@ -3637,11 +4471,19 @@ export class TestState { for (let j = 0; j < positions.length - 1; j++) { // for each distinct range in the list of positions, add an entry to the list of places that need to be annotated in the baseline if (positions[j] + 1 !== positions[j + 1]) { - inlineLinkedEditBaselines.push({ start: positions[rangeStart], end: positions[j], index: offset }); + inlineLinkedEditBaselines.push({ + start: positions[rangeStart], + end: positions[j], + index: offset, + }); rangeStart = j + 1; } } - inlineLinkedEditBaselines.push({ start: positions[rangeStart], end: positions[positions.length - 1], index: offset }); + inlineLinkedEditBaselines.push({ + start: positions[rangeStart], + end: positions[positions.length - 1], + index: offset, + }); // add the LinkedEditInfo with its index to the baseline linkedEditInfoBaseline += `\n\n=== ${offset} ===\n` + linkedEdit; @@ -3654,7 +4496,8 @@ export class TestState { for (let i = 0; i < inlineLinkedEditBaselines.length; i++) { const e = inlineLinkedEditBaselines[i]; const sliceEnd = inlineLinkedEditBaselines[i + 1]?.start; - baselineContent += `[|/*${e.index}*/` + fileText.slice(e.start, e.end) + `|]` + fileText.slice(e.end, sliceEnd); + baselineContent += `[|/*${e.index}*/` + fileText.slice(e.start, e.end) + `|]` + + fileText.slice(e.end, sliceEnd); } baselineContent += linkedEditInfoBaseline; @@ -3666,7 +4509,9 @@ export class TestState { const actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition); if (actual.length !== 2) { - this.raiseError(`verifyMatchingBracePosition failed - expected result to contain 2 spans, but it had ${actual.length}`); + this.raiseError( + `verifyMatchingBracePosition failed - expected result to contain 2 spans, but it had ${actual.length}`, + ); } let actualMatchPosition = -1; @@ -3677,11 +4522,17 @@ export class TestState { actualMatchPosition = actual[0].start; } else { - this.raiseError(`verifyMatchingBracePosition failed - could not find the brace position: ${bracePosition} in the returned list: (${actual[0].start},${ts.textSpanEnd(actual[0])}) and (${actual[1].start},${ts.textSpanEnd(actual[1])})`); + this.raiseError( + `verifyMatchingBracePosition failed - could not find the brace position: ${bracePosition} in the returned list: (${ + actual[0].start + },${ts.textSpanEnd(actual[0])}) and (${actual[1].start},${ts.textSpanEnd(actual[1])})`, + ); } if (actualMatchPosition !== expectedMatchPosition) { - this.raiseError(`verifyMatchingBracePosition failed - expected: ${actualMatchPosition}, actual: ${expectedMatchPosition}`); + this.raiseError( + `verifyMatchingBracePosition failed - expected: ${actualMatchPosition}, actual: ${expectedMatchPosition}`, + ); } } @@ -3698,7 +4549,11 @@ export class TestState { const position = this.currentCaretPosition; const fileName = this.activeFile.fileName; const actual = !!this.languageService.getSpanOfEnclosingComment(fileName, position, /*onlyMultiLine*/ false); - const actualOnlyMultiLine = !!this.languageService.getSpanOfEnclosingComment(fileName, position, /*onlyMultiLine*/ true); + const actualOnlyMultiLine = !!this.languageService.getSpanOfEnclosingComment( + fileName, + position, + /*onlyMultiLine*/ true, + ); if (expected !== actual || onlyMultiLineDiverges === (actual === actualOnlyMultiLine)) { this.raiseError(`verifySpanOfEnclosingComment failed: position: '${position}' @@ -3713,31 +4568,51 @@ export class TestState { public verifyNavigateTo(options: readonly FourSlashInterface.VerifyNavigateToOptions[]): void { for (const { pattern, expected, fileName } of options) { const items = this.languageService.getNavigateToItems(pattern, /*maxResultCount*/ undefined, fileName); - this.assertObjectsEqual(items, expected.map((e): ts.NavigateToItem => ({ - name: e.name, - kind: e.kind, - kindModifiers: e.kindModifiers || "", - matchKind: e.matchKind || "exact", - isCaseSensitive: e.isCaseSensitive === undefined ? true : e.isCaseSensitive, - fileName: e.range.fileName, - textSpan: ts.createTextSpanFromRange(e.range), - containerName: e.containerName || "", - containerKind: e.containerKind || ts.ScriptElementKind.unknown, - }))); + this.assertObjectsEqual( + items, + expected.map((e): ts.NavigateToItem => ({ + name: e.name, + kind: e.kind, + kindModifiers: e.kindModifiers || "", + matchKind: e.matchKind || "exact", + isCaseSensitive: e.isCaseSensitive === undefined ? true : e.isCaseSensitive, + fileName: e.range.fileName, + textSpan: ts.createTextSpanFromRange(e.range), + containerName: e.containerName || "", + containerKind: e.containerKind || ts.ScriptElementKind.unknown, + })), + ); } } - public verifyNavigationBar(json: any, options: { checkSpans?: boolean } | undefined) { - this.verifyNavigationTreeOrBar(json, this.languageService.getNavigationBarItems(this.activeFile.fileName), "Bar", options); + public verifyNavigationBar(json: any, options: { checkSpans?: boolean; } | undefined) { + this.verifyNavigationTreeOrBar( + json, + this.languageService.getNavigationBarItems(this.activeFile.fileName), + "Bar", + options, + ); } - public verifyNavigationTree(json: any, options: { checkSpans?: boolean } | undefined) { - this.verifyNavigationTreeOrBar(json, this.languageService.getNavigationTree(this.activeFile.fileName), "Tree", options); + public verifyNavigationTree(json: any, options: { checkSpans?: boolean; } | undefined) { + this.verifyNavigationTreeOrBar( + json, + this.languageService.getNavigationTree(this.activeFile.fileName), + "Tree", + options, + ); } - private verifyNavigationTreeOrBar(json: any, tree: any, name: "Tree" | "Bar", options: { checkSpans?: boolean } | undefined) { + private verifyNavigationTreeOrBar( + json: any, + tree: any, + name: "Tree" | "Bar", + options: { checkSpans?: boolean; } | undefined, + ) { if (JSON.stringify(tree, replacer) !== JSON.stringify(json)) { - this.raiseError(`verifyNavigation${name} failed - \n${showTextDiff(stringify(json), stringify(tree, replacer))}`); + this.raiseError( + `verifyNavigation${name} failed - \n${showTextDiff(stringify(json), stringify(tree, replacer))}`, + ); } function replacer(key: string, value: any) { @@ -3762,7 +4637,9 @@ export class TestState { const items = this.languageService.getNavigateToItems(searchValue); Harness.IO.log(`NavigationItems list (${items.length} items)`); for (const item of items) { - Harness.IO.log(`name: ${item.name}, kind: ${item.kind}, parentName: ${item.containerName}, fileName: ${item.fileName}`); + Harness.IO.log( + `name: ${item.name}, kind: ${item.kind}, parentName: ${item.containerName}, fileName: ${item.fileName}`, + ); } } @@ -3770,31 +4647,49 @@ export class TestState { const items = this.languageService.getNavigationBarItems(this.activeFile.fileName); Harness.IO.log(`Navigation bar (${items.length} items)`); for (const item of items) { - Harness.IO.log(`${ts.repeatString(" ", item.indent)}name: ${item.text}, kind: ${item.kind}, childItems: ${item.childItems.map(child => child.text)}`); + Harness.IO.log( + `${ts.repeatString(" ", item.indent)}name: ${item.text}, kind: ${item.kind}, childItems: ${ + item.childItems.map(child => child.text) + }`, + ); } } private getDocumentHighlightsAtCurrentPosition(fileNamesToSearch: readonly string[]) { const filesToSearch = fileNamesToSearch.map(name => ts.combinePaths(this.basePath, name)); - return this.languageService.getDocumentHighlights(this.activeFile.fileName, this.currentCaretPosition, filesToSearch); + return this.languageService.getDocumentHighlights( + this.activeFile.fileName, + this.currentCaretPosition, + filesToSearch, + ); } - private baselineGetDocumentHighlights(markerOrRange: MarkerOrNameOrRange, options: FourSlashInterface.VerifyDocumentHighlightsOptions | undefined) { + private baselineGetDocumentHighlights( + markerOrRange: MarkerOrNameOrRange, + options: FourSlashInterface.VerifyDocumentHighlightsOptions | undefined, + ) { this.goToMarkerOrNameOrRange(markerOrRange); - const highlights = this.getDocumentHighlightsAtCurrentPosition(ts.map(options?.filesToSearch, ts.normalizePath) || [this.activeFile.fileName]); + const highlights = this.getDocumentHighlightsAtCurrentPosition( + ts.map(options?.filesToSearch, ts.normalizePath) || [this.activeFile.fileName], + ); // Write input files - const filesToSearch = options ? "// filesToSearch:\n" + - options.filesToSearch.map(f => "// " + f).join("\n") + "\n\n" : - ""; + const filesToSearch = options ? "// filesToSearch:\n" + + options.filesToSearch.map(f => "// " + f).join("\n") + "\n\n" + : ""; const baselineContent = this.getBaselineForGroupedDocumentSpansWithFileContents( - highlights?.map(h => h.highlightSpans.map(s => s.fileName ? s as ts.DocumentSpan : { ...s, fileName: h.fileName })) || ts.emptyArray, + highlights?.map(h => + h.highlightSpans.map(s => s.fileName ? s as ts.DocumentSpan : { ...s, fileName: h.fileName }) + ) || ts.emptyArray, { markerInfo: { markerOrRange, markerName: "/*HIGHLIGHTS*/" } }, ); return filesToSearch + baselineContent; } - public verifyCodeFixAvailable(negative: boolean, expected: FourSlashInterface.VerifyCodeFixAvailableOptions[] | string | undefined): void { + public verifyCodeFixAvailable( + negative: boolean, + expected: FourSlashInterface.VerifyCodeFixAvailableOptions[] | string | undefined, + ): void { const codeFixes = this.getCodeFixes(this.activeFile.fileName); if (negative) { if (typeof expected === "undefined") { @@ -3806,14 +4701,20 @@ export class TestState { } } else { - assert(typeof expected === "undefined" || typeof expected === "string", "With a negated assertion, 'expected' must be undefined or a string value of a codefix name."); + assert( + typeof expected === "undefined" || typeof expected === "string", + "With a negated assertion, 'expected' must be undefined or a string value of a codefix name.", + ); } } else if (typeof expected === "string") { this.assertObjectsEqual(codeFixes.map(fix => fix.fixName), [expected]); } else { - const actuals = codeFixes.map((fix): FourSlashInterface.VerifyCodeFixAvailableOptions => ({ description: fix.description, commands: fix.commands })); + const actuals = codeFixes.map((fix): FourSlashInterface.VerifyCodeFixAvailableOptions => ({ + description: fix.description, + commands: fix.commands, + })); this.assertObjectsEqual(actuals, negative ? ts.emptyArray : expected); } } @@ -3830,10 +4731,14 @@ export class TestState { } this.raiseError( - `Expected to find a fix with the name '${fixName}', but none exists.` + - availableFixes.length - ? ` Available fixes: ${availableFixes.map(fix => `${fix.fixName} (${fix.fixId ? "with" : "without"} fix-all)`).join(", ")}` - : "" + `Expected to find a fix with the name '${fixName}', but none exists.` + + availableFixes.length + ? ` Available fixes: ${ + availableFixes.map(fix => `${fix.fixName} (${fix.fixId ? "with" : "without"} fix-all)`).join( + ", ", + ) + }` + : "", ); } } @@ -3841,21 +4746,31 @@ export class TestState { public verifyApplicableRefactorAvailableAtMarker(negative: boolean, markerName: string) { const isAvailable = this.getApplicableRefactors(this.getMarkerByName(markerName)).length > 0; if (negative && isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableAtMarker failed - expected no refactor at marker ${markerName} but found some.`); + this.raiseError( + `verifyApplicableRefactorAvailableAtMarker failed - expected no refactor at marker ${markerName} but found some.`, + ); } if (!negative && !isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableAtMarker failed - expected a refactor at marker ${markerName} but found none.`); + this.raiseError( + `verifyApplicableRefactorAvailableAtMarker failed - expected a refactor at marker ${markerName} but found none.`, + ); } } private getSelection(): ts.TextRange { return { pos: this.currentCaretPosition, - end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd + end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd, }; } - public verifyRefactorAvailable(negative: boolean, triggerReason: ts.RefactorTriggerReason, name: string, actionName?: string, actionDescription?: string) { + public verifyRefactorAvailable( + negative: boolean, + triggerReason: ts.RefactorTriggerReason, + name: string, + actionName?: string, + actionDescription?: string, + ) { let refactors = this.getApplicableRefactorsAtSelection(triggerReason); refactors = refactors.filter(r => r.name === name); @@ -3873,15 +4788,23 @@ export class TestState { if (negative) { if (isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found: ${refactors.map(r => r.name).join(", ")}`); + this.raiseError( + `verifyApplicableRefactorAvailableForRange failed - expected no refactor but found: ${ + refactors.map(r => r.name).join(", ") + }`, + ); } } else { if (!isAvailable) { - this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`); + this.raiseError( + `verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`, + ); } if (refactors.length > 1) { - this.raiseError(`${refactors.length} available refactors both have name ${name} and action ${actionName}`); + this.raiseError( + `${refactors.length} available refactors both have name ${name} and action ${actionName}`, + ); } } } @@ -3911,23 +4834,48 @@ export class TestState { } } - public applyRefactor({ refactorName, actionName, actionDescription, newContent: newContentWithRenameMarker, triggerReason }: FourSlashInterface.ApplyRefactorOptions) { + public applyRefactor( + { refactorName, actionName, actionDescription, newContent: newContentWithRenameMarker, triggerReason }: + FourSlashInterface.ApplyRefactorOptions, + ) { const range = this.getSelection(); const refactors = this.getApplicableRefactorsAtSelection(triggerReason); const refactorsWithName = refactors.filter(r => r.name === refactorName); if (refactorsWithName.length === 0) { - this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.\nAvailable refactors: ${refactors.map(r => r.name)}`); + this.raiseError( + `The expected refactor: ${refactorName} is not available at the marker location.\nAvailable refactors: ${ + refactors.map(r => r.name) + }`, + ); } - const action = ts.firstDefined(refactorsWithName, refactor => refactor.actions.find(a => a.name === actionName)); + const action = ts.firstDefined( + refactorsWithName, + refactor => refactor.actions.find(a => a.name === actionName), + ); if (!action) { - throw this.raiseError(`The expected action: ${actionName} is not included in: ${ts.flatMap(refactorsWithName, r => r.actions.map(a => a.name))}`); + throw this.raiseError( + `The expected action: ${actionName} is not included in: ${ + ts.flatMap(refactorsWithName, r => r.actions.map(a => a.name)) + }`, + ); } if (action.description !== actionDescription) { - this.raiseError(`Expected action description to be ${JSON.stringify(actionDescription)}, got: ${JSON.stringify(action.description)}`); + this.raiseError( + `Expected action description to be ${JSON.stringify(actionDescription)}, got: ${ + JSON.stringify(action.description) + }`, + ); } - const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName, ts.emptyOptions)!; + const editInfo = this.languageService.getEditsForRefactor( + this.activeFile.fileName, + this.formatCodeSettings, + range, + refactorName, + actionName, + ts.emptyOptions, + )!; for (const edit of editInfo.edits) { this.applyEdits(edit.fileName, edit.textChanges); } @@ -3935,7 +4883,8 @@ export class TestState { let renameFilename: string | undefined; let renamePosition: number | undefined; - const newFileContents = typeof newContentWithRenameMarker === "string" ? { [this.activeFile.fileName]: newContentWithRenameMarker } : newContentWithRenameMarker; + const newFileContents = typeof newContentWithRenameMarker === "string" + ? { [this.activeFile.fileName]: newContentWithRenameMarker } : newContentWithRenameMarker; for (const fileName in newFileContents) { const { renamePosition: rp, newContent } = TestState.parseNewContent(newFileContents[fileName]); if (renamePosition === undefined) { @@ -3946,7 +4895,6 @@ export class TestState { ts.Debug.assert(rp === undefined); } this.verifyFileContent(fileName, newContent); - } if (renamePosition === undefined) { @@ -3962,13 +4910,16 @@ export class TestState { } } - private static parseNewContent(newContentWithRenameMarker: string): { readonly renamePosition: number | undefined, readonly newContent: string } { + private static parseNewContent( + newContentWithRenameMarker: string, + ): { readonly renamePosition: number | undefined; readonly newContent: string; } { const renamePosition = newContentWithRenameMarker.indexOf("/*RENAME*/"); if (renamePosition === -1) { return { renamePosition: undefined, newContent: newContentWithRenameMarker }; } else { - const newContent = newContentWithRenameMarker.slice(0, renamePosition) + newContentWithRenameMarker.slice(renamePosition + "/*RENAME*/".length); + const newContent = newContentWithRenameMarker.slice(0, renamePosition) + + newContentWithRenameMarker.slice(renamePosition + "/*RENAME*/".length); return { renamePosition, newContent }; } } @@ -3986,30 +4937,67 @@ export class TestState { } public moveToNewFile(options: FourSlashInterface.MoveToNewFileOptions): void { - assert(this.getRanges().length === 1, "Must have exactly one fourslash range (source enclosed between '[|' and '|]' delimiters) in the source file"); + assert( + this.getRanges().length === 1, + "Must have exactly one fourslash range (source enclosed between '[|' and '|]' delimiters) in the source file", + ); const range = this.getRanges()[0]; - const refactor = ts.find(this.getApplicableRefactors(range, { allowTextChangesInNewFiles: true }), r => r.name === "Move to a new file")!; + const refactor = ts.find( + this.getApplicableRefactors(range, { allowTextChangesInNewFiles: true }), + r => r.name === "Move to a new file", + )!; assert(refactor.actions.length === 1); const action = ts.first(refactor.actions); assert(action.name === "Move to a new file" && action.description === "Move to a new file"); - const editInfo = this.languageService.getEditsForRefactor(range.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions)!; + const editInfo = this.languageService.getEditsForRefactor( + range.fileName, + this.formatCodeSettings, + range, + refactor.name, + action.name, + options.preferences || ts.emptyOptions, + )!; this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits); } public moveToFile(options: FourSlashInterface.MoveToFileOptions): void { - assert(this.getRanges().length === 1, "Must have exactly one fourslash range (source enclosed between '[|' and '|]' delimiters) in the source file"); + assert( + this.getRanges().length === 1, + "Must have exactly one fourslash range (source enclosed between '[|' and '|]' delimiters) in the source file", + ); const range = this.getRanges()[0]; - const refactor = ts.find(this.getApplicableRefactors(range, { allowTextChangesInNewFiles: true }, /*triggerReason*/ undefined, /*kind*/ undefined, /*includeInteractiveActions*/ true), r => r.name === "Move to file")!; + const refactor = ts.find( + this.getApplicableRefactors( + range, + { allowTextChangesInNewFiles: true }, + /*triggerReason*/ undefined, + /*kind*/ undefined, + /*includeInteractiveActions*/ true, + ), + r => r.name === "Move to file", + )!; assert(refactor.actions.length === 1); const action = ts.first(refactor.actions); assert(action.name === "Move to file" && action.description === "Move to file"); - const editInfo = this.languageService.getEditsForRefactor(range.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions, options.interactiveRefactorArguments)!; + const editInfo = this.languageService.getEditsForRefactor( + range.fileName, + this.formatCodeSettings, + range, + refactor.name, + action.name, + options.preferences || ts.emptyOptions, + options.interactiveRefactorArguments, + )!; this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits); } - private testNewFileContents(edits: readonly ts.FileTextChanges[], newFileContents: { [fileName: string]: string }, description: string): void { + private testNewFileContents( + edits: readonly ts.FileTextChanges[], + newFileContents: { [fileName: string]: string; }, + description: string, + ): void { for (const { fileName, textChanges } of edits) { const newContent = newFileContents[fileName]; if (newContent === undefined) { @@ -4042,19 +5030,33 @@ export class TestState { expectedContent: string, refactorNameToApply: string, actionName: string, - formattingOptions?: ts.FormatCodeSettings) { - + formattingOptions?: ts.FormatCodeSettings, + ) { formattingOptions = formattingOptions || this.formatCodeSettings; const marker = this.getMarkerByName(markerName); - const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, marker.position, ts.emptyOptions); - const applicableRefactorToApply = ts.find(applicableRefactors, refactor => refactor.name === refactorNameToApply); + const applicableRefactors = this.languageService.getApplicableRefactors( + this.activeFile.fileName, + marker.position, + ts.emptyOptions, + ); + const applicableRefactorToApply = ts.find( + applicableRefactors, + refactor => refactor.name === refactorNameToApply, + ); if (!applicableRefactorToApply) { this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`); } - const editInfo = this.languageService.getEditsForRefactor(marker.fileName, formattingOptions, marker.position, refactorNameToApply, actionName, ts.emptyOptions)!; + const editInfo = this.languageService.getEditsForRefactor( + marker.fileName, + formattingOptions, + marker.position, + refactorNameToApply, + actionName, + ts.emptyOptions, + )!; for (const edit of editInfo.edits) { this.applyEdits(edit.fileName, edit.textChanges); @@ -4062,7 +5064,9 @@ export class TestState { const actualContent = this.getFileContent(marker.fileName); if (actualContent !== expectedContent) { - this.raiseError(`verifyFileAfterApplyingRefactors failed:\n${showTextDiff(expectedContent, actualContent)}`); + this.raiseError( + `verifyFileAfterApplyingRefactors failed:\n${showTextDiff(expectedContent, actualContent)}`, + ); } } @@ -4071,12 +5075,19 @@ export class TestState { Harness.IO.log(stringify(codeFixes)); } - private formatCallHierarchyItemSpan(file: FourSlashFile, span: ts.TextSpan, prefix: string, trailingPrefix = prefix) { + private formatCallHierarchyItemSpan( + file: FourSlashFile, + span: ts.TextSpan, + prefix: string, + trailingPrefix = prefix, + ) { const startLc = this.languageServiceAdapterHost.positionToLineAndCharacter(file.fileName, span.start); const endLc = this.languageServiceAdapterHost.positionToLineAndCharacter(file.fileName, ts.textSpanEnd(span)); const lines = this.spanLines(file, span, { fullLines: true, lineNumbers: true, selection: true }); let text = ""; - text += `${prefix}╭ ${file.fileName}:${startLc.line + 1}:${startLc.character + 1}-${endLc.line + 1}:${endLc.character + 1}\n`; + text += `${prefix}╭ ${file.fileName}:${startLc.line + 1}:${startLc.character + 1}-${endLc.line + 1}:${ + endLc.character + 1 + }\n`; for (const line of lines) { text += `${prefix}│ ${line.trimRight()}\n`; } @@ -4084,28 +5095,55 @@ export class TestState { return text; } - private formatCallHierarchyItemSpans(file: FourSlashFile, spans: ts.TextSpan[], prefix: string, trailingPrefix = prefix) { + private formatCallHierarchyItemSpans( + file: FourSlashFile, + spans: ts.TextSpan[], + prefix: string, + trailingPrefix = prefix, + ) { let text = ""; for (let i = 0; i < spans.length; i++) { - text += this.formatCallHierarchyItemSpan(file, spans[i], prefix, i < spans.length - 1 ? prefix : trailingPrefix); + text += this.formatCallHierarchyItemSpan( + file, + spans[i], + prefix, + i < spans.length - 1 ? prefix : trailingPrefix, + ); } return text; } - private formatCallHierarchyItem(file: FourSlashFile, callHierarchyItem: ts.CallHierarchyItem, direction: CallHierarchyItemDirection, seen: Map, prefix: string, trailingPrefix: string = prefix) { + private formatCallHierarchyItem( + file: FourSlashFile, + callHierarchyItem: ts.CallHierarchyItem, + direction: CallHierarchyItemDirection, + seen: Map, + prefix: string, + trailingPrefix: string = prefix, + ) { const key = `${callHierarchyItem.file}|${JSON.stringify(callHierarchyItem.span)}|${direction}`; const alreadySeen = seen.has(key); seen.set(key, true); - const incomingCalls = - direction === CallHierarchyItemDirection.Outgoing ? { result: "skip" } as const : - alreadySeen ? { result: "seen" } as const : - { result: "show", values: this.languageService.provideCallHierarchyIncomingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const; - - const outgoingCalls = - direction === CallHierarchyItemDirection.Incoming ? { result: "skip" } as const : - alreadySeen ? { result: "seen" } as const : - { result: "show", values: this.languageService.provideCallHierarchyOutgoingCalls(callHierarchyItem.file, callHierarchyItem.selectionSpan.start) } as const; + const incomingCalls = direction === CallHierarchyItemDirection.Outgoing ? { result: "skip" } as const + : alreadySeen ? { result: "seen" } as const + : { + result: "show", + values: this.languageService.provideCallHierarchyIncomingCalls( + callHierarchyItem.file, + callHierarchyItem.selectionSpan.start, + ), + } as const; + + const outgoingCalls = direction === CallHierarchyItemDirection.Incoming ? { result: "skip" } as const + : alreadySeen ? { result: "seen" } as const + : { + result: "show", + values: this.languageService.provideCallHierarchyOutgoingCalls( + callHierarchyItem.file, + callHierarchyItem.selectionSpan.start, + ), + } as const; let text = ""; text += `${prefix}╭ name: ${callHierarchyItem.name}\n`; @@ -4117,9 +5155,13 @@ export class TestState { text += `${prefix}├ span:\n`; text += this.formatCallHierarchyItemSpan(file, callHierarchyItem.span, `${prefix}│ `); text += `${prefix}├ selectionSpan:\n`; - text += this.formatCallHierarchyItemSpan(file, callHierarchyItem.selectionSpan, `${prefix}│ `, - incomingCalls.result !== "skip" || outgoingCalls.result !== "skip" ? `${prefix}│ ` : - `${trailingPrefix}╰ `); + text += this.formatCallHierarchyItemSpan( + file, + callHierarchyItem.selectionSpan, + `${prefix}│ `, + incomingCalls.result !== "skip" || outgoingCalls.result !== "skip" ? `${prefix}│ ` + : `${trailingPrefix}╰ `, + ); if (incomingCalls.result === "seen") { if (outgoingCalls.result === "skip") { @@ -4144,12 +5186,22 @@ export class TestState { const incomingCall = incomingCalls.values[i]; const file = this.findFile(incomingCall.from.file); text += `${prefix}│ ╭ from:\n`; - text += this.formatCallHierarchyItem(file, incomingCall.from, CallHierarchyItemDirection.Incoming, seen, `${prefix}│ │ `); + text += this.formatCallHierarchyItem( + file, + incomingCall.from, + CallHierarchyItemDirection.Incoming, + seen, + `${prefix}│ │ `, + ); text += `${prefix}│ ├ fromSpans:\n`; - text += this.formatCallHierarchyItemSpans(file, incomingCall.fromSpans, `${prefix}│ │ `, - i < incomingCalls.values.length - 1 ? `${prefix}│ ╰ ` : - outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` : - `${trailingPrefix}╰ ╰ `); + text += this.formatCallHierarchyItemSpans( + file, + incomingCall.fromSpans, + `${prefix}│ │ `, + i < incomingCalls.values.length - 1 ? `${prefix}│ ╰ ` + : outgoingCalls.result !== "skip" ? `${prefix}│ ╰ ` + : `${trailingPrefix}╰ ╰ `, + ); } } } @@ -4166,11 +5218,21 @@ export class TestState { for (let i = 0; i < outgoingCalls.values.length; i++) { const outgoingCall = outgoingCalls.values[i]; text += `${prefix}│ ╭ to:\n`; - text += this.formatCallHierarchyItem(this.findFile(outgoingCall.to.file), outgoingCall.to, CallHierarchyItemDirection.Outgoing, seen, `${prefix}│ │ `); + text += this.formatCallHierarchyItem( + this.findFile(outgoingCall.to.file), + outgoingCall.to, + CallHierarchyItemDirection.Outgoing, + seen, + `${prefix}│ │ `, + ); text += `${prefix}│ ├ fromSpans:\n`; - text += this.formatCallHierarchyItemSpans(file, outgoingCall.fromSpans, `${prefix}│ │ `, - i < outgoingCalls.values.length - 1 ? `${prefix}│ ╰ ` : - `${trailingPrefix}╰ ╰ `); + text += this.formatCallHierarchyItemSpans( + file, + outgoingCall.fromSpans, + `${prefix}│ │ `, + i < outgoingCalls.values.length - 1 ? `${prefix}│ ╰ ` + : `${trailingPrefix}╰ ╰ `, + ); } } } @@ -4181,21 +5243,35 @@ export class TestState { let text = ""; if (callHierarchyItem) { const file = this.findFile(callHierarchyItem.file); - text += this.formatCallHierarchyItem(file, callHierarchyItem, CallHierarchyItemDirection.Root, new Map(), ""); + text += this.formatCallHierarchyItem( + file, + callHierarchyItem, + CallHierarchyItemDirection.Root, + new Map(), + "", + ); } return text; } public baselineCallHierarchy() { const baselineFile = this.getBaselineFileNameForContainingTestFile(".callHierarchy.txt"); - const callHierarchyItem = this.languageService.prepareCallHierarchy(this.activeFile.fileName, this.currentCaretPosition); - const text = callHierarchyItem ? ts.mapOneOrMany(callHierarchyItem, item => this.formatCallHierarchy(item), result => result.join("")) : "none"; + const callHierarchyItem = this.languageService.prepareCallHierarchy( + this.activeFile.fileName, + this.currentCaretPosition, + ); + const text = callHierarchyItem + ? ts.mapOneOrMany(callHierarchyItem, item => this.formatCallHierarchy(item), result => result.join("")) + : "none"; Harness.Baseline.runBaseline(baselineFile, text); } private getLineContent(index: number) { const text = this.getFileContent(this.activeFile.fileName); - const pos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { line: index, character: 0 }); + const pos = this.languageServiceAdapterHost.lineAndCharacterToPosition(this.activeFile.fileName, { + line: index, + character: 0, + }); let startPos = pos, endPos = pos; while (startPos > 0) { @@ -4222,17 +5298,21 @@ export class TestState { // Get the text of the entire line the caret is currently at private getCurrentLineContent() { - return this.getLineContent(this.languageServiceAdapterHost.positionToLineAndCharacter( - this.activeFile.fileName, - this.currentCaretPosition, - ).line); + return this.getLineContent( + this.languageServiceAdapterHost.positionToLineAndCharacter( + this.activeFile.fileName, + this.currentCaretPosition, + ).line, + ); } private findFile(indexOrName: string | number): FourSlashFile { if (typeof indexOrName === "number") { const index = indexOrName; if (index >= this.testData.files.length) { - throw new Error(`File index (${index}) in openFile was out of range. There are only ${this.testData.files.length} files in this test.`); + throw new Error( + `File index (${index}) in openFile was out of range. There are only ${this.testData.files.length} files in this test.`, + ); } else { return this.testData.files[index]; @@ -4241,7 +5321,11 @@ export class TestState { else if (ts.isString(indexOrName)) { const { file, availableNames } = this.tryFindFileWorker(indexOrName); if (!file) { - throw new Error(`No test file named "${indexOrName}" exists. Available file names are: ${availableNames.join(", ")}`); + throw new Error( + `No test file named "${indexOrName}" exists. Available file names are: ${ + availableNames.join(", ") + }`, + ); } return file; } @@ -4250,7 +5334,9 @@ export class TestState { } } - private tryFindFileWorker(name: string): { readonly file: FourSlashFile | undefined; readonly availableNames: readonly string[]; } { + private tryFindFileWorker( + name: string, + ): { readonly file: FourSlashFile | undefined; readonly availableNames: readonly string[]; } { name = ts.normalizePath(name); // names are stored in the compiler with this relative path, this allows people to use goTo.file on just the fileName name = name.indexOf("/") === -1 ? (this.basePath + "/" + name) : name; @@ -4280,7 +5366,11 @@ export class TestState { public getMarkerByName(markerName: string) { const markerPos = this.testData.markerPositions.get(markerName); if (markerPos === undefined) { - throw new Error(`Unknown marker "${markerName}" Available markers: ${this.getMarkerNames().map(m => "\"" + m + "\"").join(", ")}`); + throw new Error( + `Unknown marker "${markerName}" Available markers: ${ + this.getMarkerNames().map(m => '"' + m + '"').join(", ") + }`, + ); } else { return markerPos; @@ -4295,9 +5385,16 @@ export class TestState { this.cancellationToken.resetCancelled(); } - public getEditsForFileRename({ oldPath, newPath, newFileContents, preferences }: FourSlashInterface.GetEditsForFileRenameOptions): void { - const test = (fileContents: { readonly [fileName: string]: string }, description: string): void => { - const changes = this.languageService.getEditsForFileRename(oldPath, newPath, this.formatCodeSettings, preferences); + public getEditsForFileRename( + { oldPath, newPath, newFileContents, preferences }: FourSlashInterface.GetEditsForFileRenameOptions, + ): void { + const test = (fileContents: { readonly [fileName: string]: string; }, description: string): void => { + const changes = this.languageService.getEditsForFileRename( + oldPath, + newPath, + this.formatCodeSettings, + preferences, + ); this.testNewFileContents(changes, fileContents, description); }; @@ -4307,18 +5404,60 @@ export class TestState { this.languageServiceAdapterHost.renameFileOrDirectory(oldPath, newPath); this.languageService.cleanupSemanticCache(); - const pathUpdater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false), /*sourceMapper*/ undefined); + const pathUpdater = ts.getPathUpdater( + oldPath, + newPath, + ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false), + /*sourceMapper*/ undefined, + ); test(renameKeys(newFileContents, key => pathUpdater(key) || key), "with file moved"); } - private getApplicableRefactorsAtSelection(triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string, preferences = ts.emptyOptions) { - return this.getApplicableRefactorsWorker(this.getSelection(), this.activeFile.fileName, preferences, triggerReason, kind); - } - private getApplicableRefactors(rangeOrMarker: Range | Marker, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string, includeInteractiveActions?: boolean): readonly ts.ApplicableRefactorInfo[] { - return this.getApplicableRefactorsWorker("position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, rangeOrMarker.fileName, preferences, triggerReason, kind, includeInteractiveActions); // eslint-disable-line local/no-in-operator + private getApplicableRefactorsAtSelection( + triggerReason: ts.RefactorTriggerReason = "implicit", + kind?: string, + preferences = ts.emptyOptions, + ) { + return this.getApplicableRefactorsWorker( + this.getSelection(), + this.activeFile.fileName, + preferences, + triggerReason, + kind, + ); } - private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason, kind?: string, includeInteractiveActions?: boolean): readonly ts.ApplicableRefactorInfo[] { - return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences, triggerReason, kind, includeInteractiveActions) || ts.emptyArray; + private getApplicableRefactors( + rangeOrMarker: Range | Marker, + preferences = ts.emptyOptions, + triggerReason: ts.RefactorTriggerReason = "implicit", + kind?: string, + includeInteractiveActions?: boolean, + ): readonly ts.ApplicableRefactorInfo[] { + return this.getApplicableRefactorsWorker( + "position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, + rangeOrMarker.fileName, + preferences, + triggerReason, + kind, + includeInteractiveActions, + ); // eslint-disable-line local/no-in-operator + } + private getApplicableRefactorsWorker( + positionOrRange: number | ts.TextRange, + fileName: string, + preferences = ts.emptyOptions, + triggerReason: ts.RefactorTriggerReason, + kind?: string, + includeInteractiveActions?: boolean, + ): readonly ts.ApplicableRefactorInfo[] { + return this.languageService.getApplicableRefactors( + fileName, + positionOrRange, + preferences, + triggerReason, + kind, + includeInteractiveActions, + ) || ts.emptyArray; } public configurePlugin(pluginName: string, configuration: any): void { @@ -4375,9 +5514,13 @@ export class TestState { } } -function updateTextRangeForTextChanges({ pos, end }: ts.TextRange, textChanges: readonly ts.TextChange[]): ts.TextRange { +function updateTextRangeForTextChanges( + { pos, end }: ts.TextRange, + textChanges: readonly ts.TextChange[], +): ts.TextRange { forEachTextChange(textChanges, change => { - const update = (p: number): number => updatePosition(p, change.span.start, ts.textSpanEnd(change.span), change.newText); + const update = (p: number): number => + updatePosition(p, change.span.start, ts.textSpanEnd(change.span), change.newText); pos = update(pos); end = update(end); }); @@ -4402,11 +5545,14 @@ function forEachTextChange(changes: readonly ts.TextChange[], cb: (change: ts.Te function updatePosition(position: number, editStart: number, editEnd: number, { length }: string): number { // If inside the edit, return -1 to mark as invalid - return position <= editStart ? position : position < editEnd ? -1 : position + length - + (editEnd - editStart); + return position <= editStart ? position : position < editEnd ? -1 : position + length - +(editEnd - editStart); } -function renameKeys(obj: { readonly [key: string]: T }, renameKey: (key: string) => string): { readonly [key: string]: T } { - const res: { [key: string]: T } = {}; +function renameKeys( + obj: { readonly [key: string]: T; }, + renameKey: (key: string) => string, +): { readonly [key: string]: T; } { + const res: { [key: string]: T; } = {}; for (const key in obj) { res[renameKey(key)] = obj[key]; } @@ -4418,7 +5564,12 @@ export function runFourSlashTest(basePath: string, testType: FourSlashTestType, runFourSlashTestContent(basePath, testType, content, fileName); } -export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): void { +export function runFourSlashTestContent( + basePath: string, + testType: FourSlashTestType, + content: string, + fileName: string, +): void { // Give file paths an absolute path for the virtual file system const absoluteBasePath = ts.combinePaths(Harness.virtualFileSystemRoot, basePath); const absoluteFileName = ts.combinePaths(Harness.virtualFileSystemRoot, fileName); @@ -4427,7 +5578,11 @@ export function runFourSlashTestContent(basePath: string, testType: FourSlashTes const testData = parseTestData(absoluteBasePath, content, absoluteFileName); const state = new TestState(absoluteFileName, absoluteBasePath, testType, testData); const actualFileName = Harness.IO.resolvePath(fileName) || absoluteFileName; - const output = ts.transpileModule(content, { reportDiagnostics: true, fileName: actualFileName, compilerOptions: { target: ts.ScriptTarget.ES2015, inlineSourceMap: true, inlineSources: true } }); + const output = ts.transpileModule(content, { + reportDiagnostics: true, + fileName: actualFileName, + compilerOptions: { target: ts.ScriptTarget.ES2015, inlineSourceMap: true, inlineSources: true }, + }); if (output.diagnostics!.length > 0) { throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`); } @@ -4437,11 +5592,14 @@ export function runFourSlashTestContent(basePath: string, testType: FourSlashTes function runCode(code: string, state: TestState, fileName: string): void { // Compile and execute the test 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})`; + 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 + resetRetrieveHandlers(): void; }; // Provide the content of the current test to 'source-map-support' so that it can give us the correct source positions @@ -4456,9 +5614,9 @@ function runCode(code: string, state: TestState, fileName: string): void { sourceMapSupportModule?.install({ retrieveFile: path => { - return path === generatedFile ? wrappedCode : - undefined!; - } + return path === generatedFile ? wrappedCode + : undefined!; + }, }); try { @@ -4472,7 +5630,21 @@ function runCode(code: string, state: TestState, fileName: string): void { const cancellation = new FourSlashInterface.Cancellation(state); // eslint-disable-next-line no-eval const f = (0, eval)(wrappedCode); - f(ts, test, goTo, config, verify, edit, debug, format, cancellation, FourSlashInterface.classification, FourSlashInterface.Completion, verifyOperationIsCancelled, ignoreInterpolations); + f( + ts, + test, + goTo, + config, + verify, + edit, + debug, + format, + cancellation, + FourSlashInterface.classification, + FourSlashInterface.Completion, + verifyOperationIsCancelled, + ignoreInterpolations, + ); } catch (err) { // ensure 'source-map-support' is triggered while we still have the handler attached by accessing `error.stack`. @@ -4520,7 +5692,7 @@ function parseTestData(basePath: string, contents: string, fileName: string): Fo let currentFileContent: string | undefined; let currentFileName = fileName; let currentFileSymlinks: string[] | undefined; - let currentFileOptions: { [s: string]: string } = {}; + let currentFileOptions: { [s: string]: string; } = {}; function nextFile() { if (currentFileContent === undefined) return; @@ -4614,7 +5786,7 @@ function parseTestData(basePath: string, contents: string, fileName: string): Fo globalOptions, files, symlinks, - ranges + ranges, }; } @@ -4626,7 +5798,7 @@ function getNonFileNameOptionInFileList(files: FourSlashFile[]): string | undefi return ts.forEach(files, f => getNonFileNameOptionInObject(f.fileOptions)); } -function getNonFileNameOptionInObject(optionObject: { [s: string]: string }): string | undefined { +function getNonFileNameOptionInObject(optionObject: { [s: string]: string; }): string | undefined { for (const option in optionObject) { switch (option) { case MetadataOptionNames.fileName: @@ -4643,7 +5815,7 @@ function getNonFileNameOptionInObject(optionObject: { [s: string]: string }): st const enum State { none, inSlashStarMarker, - inObjectMarker + inObjectMarker, } function reportError(fileName: string, line: number, col: number, message: string): never { @@ -4651,11 +5823,17 @@ function reportError(fileName: string, line: number, col: number, message: strin throw new Error(errorMessage); } -function recordObjectMarker(fileName: string, location: LocationInformation, text: string, markerMap: Map, markers: Marker[]): Marker | undefined { +function recordObjectMarker( + fileName: string, + location: LocationInformation, + text: string, + markerMap: Map, + markers: Marker[], +): Marker | undefined { let markerValue; try { // Attempt to parse the marker value as JSON - markerValue = JSON.parse("{ " + text + " }") as { name?: unknown }; + markerValue = JSON.parse("{ " + text + " }") as { name?: unknown; }; } catch (e) { reportError(fileName, location.sourceLine, location.sourceColumn, "Unable to parse marker text " + e.message); @@ -4668,7 +5846,7 @@ function recordObjectMarker(fileName: string, location: LocationInformation, tex const marker: Marker = { fileName, position: location.position, - data: markerValue + data: markerValue, }; // Object markers can be anonymous @@ -4681,10 +5859,16 @@ function recordObjectMarker(fileName: string, location: LocationInformation, tex return marker; } -function recordMarker(fileName: string, location: LocationInformation, name: string, markerMap: Map, markers: Marker[]): Marker | undefined { +function recordMarker( + fileName: string, + location: LocationInformation, + name: string, + markerMap: Map, + markers: Marker[], +): Marker | undefined { const marker: Marker = { fileName, - position: location.position + position: location.position, }; // Verify markers for uniqueness @@ -4699,7 +5883,13 @@ function recordMarker(fileName: string, location: LocationInformation, name: str } } -function parseFileContent(content: string, fileName: string, markerMap: Map, markers: Marker[], ranges: Range[]): FourSlashFile { +function parseFileContent( + content: string, + fileName: string, + markerMap: Map, + markers: Marker[], + ranges: Range[], +): FourSlashFile { content = chompLeadingSpace(content); // Any slash-star comment with a character not in this string is not a marker. @@ -4731,7 +5921,11 @@ function parseFileContent(content: string, fileName: string, markerMap: Map { - output = output + content.substr(lastNormalCharPosition, lastSafeCharIndex === undefined ? undefined : lastSafeCharIndex - lastNormalCharPosition); + output = output + + content.substr( + lastNormalCharPosition, + lastSafeCharIndex === undefined ? undefined : lastSafeCharIndex - lastNormalCharPosition, + ); }; if (content.length > 0) { @@ -4764,7 +5958,7 @@ function parseFileContent(content: string, fileName: string, markerMap: Map 0) { openRanges[openRanges.length - 1].marker = marker; @@ -4935,9 +6135,11 @@ function stripWhitespace(s: string): string { function displayExpectedAndActualString(expected: string, actual: string, quoted = false) { const expectMsg = "\x1b[1mExpected\x1b[0m\x1b[31m"; const actualMsg = "\x1b[1mActual\x1b[0m\x1b[31m"; - const expectedString = quoted ? "\"" + expected + "\"" : expected; - const actualString = quoted ? "\"" + actual + "\"" : actual; - return `\n${expectMsg}:\n${expectedString}\n\n${actualMsg}:\n${highlightDifferenceBetweenStrings(expected, actualString)}`; + const expectedString = quoted ? '"' + expected + '"' : expected; + const actualString = quoted ? '"' + actual + '"' : actual; + return `\n${expectMsg}:\n${expectedString}\n\n${actualMsg}:\n${ + highlightDifferenceBetweenStrings(expected, actualString) + }`; } function templateToRegExp(template: string) { @@ -4945,7 +6147,7 @@ function templateToRegExp(template: string) { } function rangesOfDiffBetweenTwoStrings(source: string, target: string) { - const ranges = [] as { start: number; length: number }[]; + const ranges = [] as { start: number; length: number; }[]; const addToIndex = (index: number) => { const closestIndex = ranges[ranges.length - 1]; @@ -4954,9 +6156,9 @@ function rangesOfDiffBetweenTwoStrings(source: string, target: string) { if (doesAddToIndex) { closestIndex.length = closestIndex.length + 1; } - else { - ranges.push({ start: index - 1, length: 1 }); - } + else { + ranges.push({ start: index - 1, length: 1 }); + } } else { ranges.push({ start: index - 1, length: 1 }); @@ -4983,7 +6185,7 @@ function highlightDifferenceBetweenStrings(source: string, target: string) { const before = emTarget.slice(0, range.start + 1 + additionalOffset); const between = emTarget.slice( range.start + 1 + additionalOffset, - range.start + range.length + 1 + additionalOffset + range.start + range.length + 1 + additionalOffset, ); const after = emTarget.slice(range.start + range.length + 1 + additionalOffset, emTarget.length); emTarget = before + lhs + between + rhs + after; @@ -4999,7 +6201,10 @@ function getRangeOfIdentifierTouchingPosition(content: string, position: number) const scanner = ts.createScanner(ts.ScriptTarget.Latest, /*skipTrivia*/ true, ts.LanguageVariant.Standard, content); while (scanner.scan() !== ts.SyntaxKind.EndOfFileToken) { const tokenFullStart = scanner.getTokenFullStart(); - if (scanner.getToken() === ts.SyntaxKind.Identifier && tokenFullStart <= position && scanner.getTokenEnd() >= position) { + if ( + scanner.getToken() === ts.SyntaxKind.Identifier && tokenFullStart <= position + && scanner.getTokenEnd() >= position + ) { return { pos: tokenFullStart, end: scanner.getTokenEnd() }; } if (tokenFullStart > position) { diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index a97341d5eeecb..81ac862dccb19 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -75,12 +75,14 @@ export class GoTo { public eachMarker(markers: readonly string[], action: (marker: FourSlash.Marker, index: number) => void): void; public eachMarker(action: (marker: FourSlash.Marker, index: number) => void): void; - public eachMarker(a: readonly string[] | ((marker: FourSlash.Marker, index: number) => void), b?: (marker: FourSlash.Marker, index: number) => void): void { + public eachMarker( + a: readonly string[] | ((marker: FourSlash.Marker, index: number) => void), + b?: (marker: FourSlash.Marker, index: number) => void, + ): void { const markers = typeof a === "function" ? this.state.getMarkers() : a.map(m => this.state.getMarkerByName(m)); this.state.goToEachMarker(markers, typeof a === "function" ? a : b!); } - public rangeStart(range: FourSlash.Range) { this.state.goToRangeStart(range); } @@ -141,11 +143,17 @@ export class VerifyNegatable { this.state.verifySignatureHelpPresence(/*expectPresent*/ false, /*triggerReason*/ undefined, markers); } - public noSignatureHelpForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void { + public noSignatureHelpForTriggerReason( + reason: ts.SignatureHelpTriggerReason, + ...markers: (string | FourSlash.Marker)[] + ): void { this.state.verifySignatureHelpPresence(/*expectPresent*/ false, reason, markers); } - public signatureHelpPresentForTriggerReason(reason: ts.SignatureHelpTriggerReason, ...markers: (string | FourSlash.Marker)[]): void { + public signatureHelpPresentForTriggerReason( + reason: ts.SignatureHelpTriggerReason, + ...markers: (string | FourSlash.Marker)[] + ): void { this.state.verifySignatureHelpPresence(/*expectPresent*/ true, reason, markers); } @@ -173,11 +181,11 @@ export class VerifyNegatable { this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace); } - public jsxClosingTag(map: { [markerName: string]: ts.JsxClosingTagInfo | undefined }): void { + public jsxClosingTag(map: { [markerName: string]: ts.JsxClosingTagInfo | undefined; }): void { this.state.verifyJsxClosingTag(map); } - public linkedEditing(map: { [markerName: string]: ts.LinkedEditingInfo | undefined }): void { + public linkedEditing(map: { [markerName: string]: ts.LinkedEditingInfo | undefined; }): void { this.state.verifyLinkedEditingRange(map); } @@ -217,7 +225,11 @@ export class VerifyNegatable { this.state.verifyRefactorAvailable(this.negative, "implicit", name, actionName, actionDescription); } - public refactorAvailableForTriggerReason(triggerReason: ts.RefactorTriggerReason, name: string, actionName?: string) { + public refactorAvailableForTriggerReason( + triggerReason: ts.RefactorTriggerReason, + name: string, + actionName?: string, + ) { this.state.verifyRefactorAvailable(this.negative, triggerReason, name, actionName); } @@ -265,15 +277,24 @@ export class Verify extends VerifyNegatable { this.state.baselineInlayHints(span, preference); } - public quickInfoIs(expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) { + public quickInfoIs( + expectedText: string, + expectedDocumentation?: string, + expectedTags?: { name: string; text: string; }[], + ) { this.state.verifyQuickInfoString(expectedText, expectedDocumentation, expectedTags); } - public quickInfoAt(markerName: string | FourSlash.Range, expectedText: string, expectedDocumentation?: string, expectedTags?: { name: string; text: string; }[]) { + public quickInfoAt( + markerName: string | FourSlash.Range, + expectedText: string, + expectedDocumentation?: string, + expectedTags?: { name: string; text: string; }[], + ) { this.state.verifyQuickInfoAt(markerName, expectedText, expectedDocumentation, expectedTags); } - public quickInfos(namesAndTexts: { [name: string]: string }) { + public quickInfos(namesAndTexts: { [name: string]: string; }) { this.state.verifyQuickInfos(namesAndTexts); } @@ -285,7 +306,13 @@ export class Verify extends VerifyNegatable { this.state.verifyIndentationAtCurrentPosition(numberOfSpaces); } - public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) { + public indentationAtPositionIs( + fileName: string, + position: number, + numberOfSpaces: number, + indentStyle = ts.IndentStyle.Smart, + baseIndentSize = 0, + ) { this.state.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle, baseIndentSize); } @@ -390,11 +417,17 @@ export class Verify extends VerifyNegatable { this.state.verifyBaselineCommands({ type: "goToImplementation", rangeText }); } - public baselineDocumentHighlights(markerOrRange?: ArrayOrSingle, options?: VerifyDocumentHighlightsOptions) { + public baselineDocumentHighlights( + markerOrRange?: ArrayOrSingle, + options?: VerifyDocumentHighlightsOptions, + ) { this.state.verifyBaselineCommands({ type: "documentHighlights", markerOrRange, options }); } - public baselineDocumentHighlightsAtRangesWithText(rangeText?: ArrayOrSingle, options?: VerifyDocumentHighlightsOptions) { + public baselineDocumentHighlightsAtRangesWithText( + rangeText?: ArrayOrSingle, + options?: VerifyDocumentHighlightsOptions, + ) { this.state.verifyBaselineCommands({ type: "documentHighlights", rangeText, options }); } @@ -474,9 +507,17 @@ export class Verify extends VerifyNegatable { this.state.verifyNoMatchingBracePosition(bracePosition); } - public docCommentTemplateAt(marker: string | FourSlash.Marker, expectedOffset: number, expectedText: string, options?: ts.DocCommentTemplateOptions) { + public docCommentTemplateAt( + marker: string | FourSlash.Marker, + expectedOffset: number, + expectedText: string, + options?: ts.DocCommentTemplateOptions, + ) { this.state.goToMarker(marker); - this.state.verifyDocCommentTemplate({ newText: expectedText.replace(/\r?\n/g, ts.testFormatSettings.newLineCharacter!), caretOffset: expectedOffset }, options); + this.state.verifyDocCommentTemplate({ + newText: expectedText.replace(/\r?\n/g, ts.testFormatSettings.newLineCharacter!), + caretOffset: expectedOffset, + }, options); } public noDocCommentTemplateAt(marker: string | FourSlash.Marker) { @@ -484,7 +525,12 @@ export class Verify extends VerifyNegatable { this.state.verifyDocCommentTemplate(/*expected*/ undefined); } - public rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void { + public rangeAfterCodeFix( + expectedText: string, + includeWhiteSpace?: boolean, + errorCode?: number, + index?: number, + ): void { this.state.verifyRangeAfterCodeFix(expectedText, includeWhiteSpace, errorCode, index); } @@ -492,8 +538,20 @@ export class Verify extends VerifyNegatable { this.state.verifyCodeFixAll(options); } - public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: ts.FormatCodeSettings): void { - this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, actionName, formattingOptions); + public fileAfterApplyingRefactorAtMarker( + markerName: string, + expectedContent: string, + refactorNameToApply: string, + actionName: string, + formattingOptions?: ts.FormatCodeSettings, + ): void { + this.state.verifyFileAfterApplyingRefactorAtMarker( + markerName, + expectedContent, + refactorNameToApply, + actionName, + formattingOptions, + ); } public rangeIs(expectedText: string, includeWhiteSpace?: boolean): void { @@ -508,7 +566,11 @@ export class Verify extends VerifyNegatable { this.state.applyCodeActionFromCompletion(markerName, options); } - public importFixAtPosition(expectedTextArray: string[], errorCode?: number, preferences?: ts.UserPreferences): void { + public importFixAtPosition( + expectedTextArray: string[], + errorCode?: number, + preferences?: ts.UserPreferences, + ): void { this.state.verifyImportFixAtPosition(expectedTextArray, errorCode, preferences); } @@ -520,11 +582,11 @@ export class Verify extends VerifyNegatable { this.state.baselineAutoImports(marker, fullNamesForCodeFix, options); } - public navigationBar(json: any, options?: { checkSpans?: boolean }) { + public navigationBar(json: any, options?: { checkSpans?: boolean; }) { this.state.verifyNavigationBar(json, options); } - public navigationTree(json: any, options?: { checkSpans?: boolean }) { + public navigationTree(json: any, options?: { checkSpans?: boolean; }) { this.state.verifyNavigationTree(json, options); } @@ -535,7 +597,7 @@ export class Verify extends VerifyNegatable { /** * This method *requires* a contiguous, complete, and ordered stream of classifications for a file. */ - public syntacticClassificationsAre(...classifications: { classificationType: string; text: string }[]) { + public syntacticClassificationsAre(...classifications: { classificationType: string; text: string; }[]) { this.state.verifySyntacticClassifications(classifications); } @@ -565,8 +627,17 @@ export class Verify extends VerifyNegatable { kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range, - preferences?: ts.UserPreferences) { - this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange, preferences); + preferences?: ts.UserPreferences, + ) { + this.state.verifyRenameInfoSucceeded( + displayName, + fullDisplayName, + kind, + kindModifiers, + fileToRename, + expectedRange, + preferences, + ); } public renameInfoFailed(message?: string, preferences?: ts.UserPreferences) { @@ -581,8 +652,14 @@ export class Verify extends VerifyNegatable { this.state.verifyBaselineCommands({ type: "findRenameLocations", rangeText, options }); } - public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: FourSlash.TextSpan, - displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[]) { + public verifyQuickInfoDisplayParts( + kind: string, + kindModifiers: string, + textSpan: FourSlash.TextSpan, + displayParts: ts.SymbolDisplayPart[], + documentation: ts.SymbolDisplayPart[], + tags: ts.JSDocTagInfo[], + ) { this.state.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation, tags); } @@ -783,7 +860,10 @@ export class Format { } public selection(startMarker: string, endMarker: string) { - this.state.formatSelection(this.state.getMarkerByName(startMarker).position, this.state.getMarkerByName(endMarker).position); + this.state.formatSelection( + this.state.getMarkerByName(startMarker).position, + this.state.getMarkerByName(endMarker).position, + ); } public onType(posMarker: string, key: string) { @@ -824,17 +904,16 @@ interface ModernClassification { type Classification = OlderClassification | ModernClassification; export function classification(format: ts.SemanticClassificationFormat) { - function semanticToken(identifier: string, text: string, _position: number): Classification { return { classificationType: identifier, - text - }; + text, + }; } if (format === ts.SemanticClassificationFormat.TwentyTwenty) { return { - semanticToken + semanticToken, }; } @@ -932,7 +1011,11 @@ export function classification(format: ts.SemanticClassificationFormat) { return getClassification(ts.ClassificationTypeNames.jsxAttributeStringLiteralValue, text, position); } - function getClassification(classificationType: ts.ClassificationTypeNames, text: string, position?: number): Classification { + function getClassification( + classificationType: ts.ClassificationTypeNames, + text: string, + position?: number, + ): Classification { const textSpan = position === undefined ? undefined : { start: position, end: position + text.length }; return { classificationType, text, textSpan }; } @@ -961,7 +1044,7 @@ export function classification(format: ts.SemanticClassificationFormat) { jsxAttribute, jsxText, jsxAttributeStringLiteralValue, - getClassification + getClassification, }; } @@ -1000,7 +1083,7 @@ export namespace Completion { name, kind: "function", kindModifiers: "declare", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }); const deprecatedFunctionEntry = (name: string): ExpectedCompletionEntryObject => ({ name, @@ -1012,24 +1095,24 @@ export namespace Completion { name, kind: "var", kindModifiers: "declare", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }); const moduleEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "module", kindModifiers: "declare", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }); const keywordEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "keyword", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }); const methodEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "method", kindModifiers: "declare", - sortText: SortText.LocationPriority + sortText: SortText.LocationPriority, }); const deprecatedMethodEntry = (name: string): ExpectedCompletionEntryObject => ({ name, @@ -1041,19 +1124,19 @@ export namespace Completion { name, kind: "property", kindModifiers: "declare", - sortText: SortText.LocationPriority + sortText: SortText.LocationPriority, }); const interfaceEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "interface", kindModifiers: "declare", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }); const typeEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "type", kindModifiers: "declare", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }); const res: ExpectedCompletionEntryObject[] = []; @@ -1061,11 +1144,13 @@ export namespace Completion { res.push({ name: ts.Debug.checkDefined(ts.tokenToString(i)), kind: "keyword", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }); } export const keywordsWithUndefined: readonly ExpectedCompletionEntryObject[] = res; - export const keywords: readonly ExpectedCompletionEntryObject[] = keywordsWithUndefined.filter(k => k.name !== "undefined"); + export const keywords: readonly ExpectedCompletionEntryObject[] = keywordsWithUndefined.filter(k => + k.name !== "undefined" + ); export const typeKeywords: readonly ExpectedCompletionEntryObject[] = [ "any", @@ -1104,7 +1189,10 @@ export namespace Completion { providedByHarness: readonly ExpectedCompletionEntry[], providedByTest: readonly ExpectedCompletionEntry[], ): ExpectedExactCompletionsPlus { - return Object.assign(sorted([...providedByHarness, ...providedByTest]), { plusFunctionName: functionName, plusArgument: providedByTest }); + return Object.assign(sorted([...providedByHarness, ...providedByTest]), { + plusFunctionName: functionName, + plusArgument: providedByTest, + }); } export function typeKeywordsPlus(plus: readonly ExpectedCompletionEntry[]) { @@ -1234,21 +1322,22 @@ export namespace Completion { export const globalThisEntry: ExpectedCompletionEntry = { name: "globalThis", kind: "module", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }; export const globalTypes = globalTypesPlus([]); export function globalTypesPlus(plus: readonly ExpectedCompletionEntry[]) { return combineExpectedCompletionEntries( "globalTypesPlus", [globalThisEntry, ...globalTypeDecls, ...typeKeywords], - plus + plus, ); } - export const typeAssertionKeywords: readonly ExpectedCompletionEntry[] = - globalTypesPlus([keywordEntry("const")]); + export const typeAssertionKeywords: readonly ExpectedCompletionEntry[] = globalTypesPlus([keywordEntry("const")]); - function getInJsKeywords(keywords: readonly ExpectedCompletionEntryObject[]): readonly ExpectedCompletionEntryObject[] { + function getInJsKeywords( + keywords: readonly ExpectedCompletionEntryObject[], + ): readonly ExpectedCompletionEntryObject[] { return keywords.filter(keyword => { switch (keyword.name) { case "enum": @@ -1303,12 +1392,17 @@ export namespace Completion { export const classElementInJsKeywords = getInJsKeywords(classElementKeywords); - export const constructorParameterKeywords: readonly ExpectedCompletionEntryObject[] = - ["override", "private", "protected", "public", "readonly"].map((name): ExpectedCompletionEntryObject => ({ - name, - kind: "keyword", - sortText: SortText.GlobalsOrKeywords - })); + export const constructorParameterKeywords: readonly ExpectedCompletionEntryObject[] = [ + "override", + "private", + "protected", + "public", + "readonly", + ].map((name): ExpectedCompletionEntryObject => ({ + name, + kind: "keyword", + sortText: SortText.GlobalsOrKeywords, + })); export const functionMembers: readonly ExpectedCompletionEntryObject[] = [ methodEntry("apply"), @@ -1548,29 +1642,37 @@ export namespace Completion { export const undefinedVarEntry: ExpectedCompletionEntryObject = { name: "undefined", kind: "var", - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }; // TODO: many of these are inappropriate to always provide - export const globalsInsideFunction = (plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean }): readonly ExpectedCompletionEntry[] => [ - { name: "arguments", kind: "local var" }, - ...plus, - globalThisEntry, - ...options?.noLib ? [] : globalsVars, - undefinedVarEntry, - ...globalKeywordsInsideFunction, - ].sort(compareExpectedCompletionEntries); + export const globalsInsideFunction = ( + plus: readonly ExpectedCompletionEntry[], + options?: { noLib?: boolean; }, + ): readonly ExpectedCompletionEntry[] => + [ + { name: "arguments", kind: "local var" }, + ...plus, + globalThisEntry, + ...options?.noLib ? [] : globalsVars, + undefinedVarEntry, + ...globalKeywordsInsideFunction, + ].sort(compareExpectedCompletionEntries); const globalInJsKeywordsInsideFunction = getInJsKeywords(globalKeywordsInsideFunction); // TODO: many of these are inappropriate to always provide - export const globalsInJsInsideFunction = (plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean }): readonly ExpectedCompletionEntry[] => [ - { name: "arguments", kind: "local var" }, - globalThisEntry, - ...options?.noLib ? [] : globalsVars, - ...plus, - undefinedVarEntry, - ...globalInJsKeywordsInsideFunction, - ].sort(compareExpectedCompletionEntries); + export const globalsInJsInsideFunction = ( + plus: readonly ExpectedCompletionEntry[], + options?: { noLib?: boolean; }, + ): readonly ExpectedCompletionEntry[] => + [ + { name: "arguments", kind: "local var" }, + globalThisEntry, + ...options?.noLib ? [] : globalsVars, + ...plus, + undefinedVarEntry, + ...globalInJsKeywordsInsideFunction, + ].sort(compareExpectedCompletionEntries); // TODO: many of these are inappropriate to always provide export const globalKeywords: readonly ExpectedCompletionEntryObject[] = [ @@ -1697,17 +1799,17 @@ export namespace Completion { globalThisEntry, ...globalsVars, undefinedVarEntry, - ...globalKeywords + ...globalKeywords, ].sort(compareExpectedCompletionEntries); export const globalsInJs: readonly ExpectedCompletionEntryObject[] = [ globalThisEntry, ...globalsVars, undefinedVarEntry, - ...globalInJsKeywords + ...globalInJsKeywords, ].sort(compareExpectedCompletionEntries); - export function globalsPlus(plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean }) { + export function globalsPlus(plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean; }) { return combineExpectedCompletionEntries("globalsPlus", [ globalThisEntry, ...options?.noLib ? [] : globalsVars, @@ -1716,7 +1818,7 @@ export namespace Completion { ], plus); } - export function globalsInJsPlus(plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean }) { + export function globalsInJsPlus(plus: readonly ExpectedCompletionEntry[], options?: { noLib?: boolean; }) { return combineExpectedCompletionEntries("globalsInJsPlus", [ globalThisEntry, ...options?.noLib ? [] : globalsVars, @@ -1731,7 +1833,7 @@ export interface ReferenceGroup { ranges: FourSlash.Range[]; } -export type ReferenceGroupDefinition = string | { text: string, range: FourSlash.Range }; +export type ReferenceGroupDefinition = string | { text: string; range: FourSlash.Range; }; export interface ApplyRefactorOptions { refactorName: string; @@ -1769,8 +1871,8 @@ export interface ExpectedCompletionEntryLabelDetails { } export type ExpectedExactCompletionsPlus = readonly ExpectedCompletionEntry[] & { - plusFunctionName: string, - plusArgument: readonly ExpectedCompletionEntry[] + plusFunctionName: string; + plusArgument: readonly ExpectedCompletionEntry[]; }; export interface VerifyCompletionsOptions { @@ -1846,7 +1948,7 @@ export interface VerifyDocumentHighlightsOptions { filesToSearch: readonly string[]; } -export type NewFileContent = string | { readonly [filename: string]: string }; +export type NewFileContent = string | { readonly [filename: string]: string; }; export interface NewContentOptions { // Exactly one of these should be defined. @@ -1900,17 +2002,17 @@ export interface Diagnostic { export interface GetEditsForFileRenameOptions { readonly oldPath: string; readonly newPath: string; - readonly newFileContents: { readonly [fileName: string]: string }; + readonly newFileContents: { readonly [fileName: string]: string; }; readonly preferences?: ts.UserPreferences; } export interface MoveToNewFileOptions { - readonly newFileContents: { readonly [fileName: string]: string }; + readonly newFileContents: { readonly [fileName: string]: string; }; readonly preferences?: ts.UserPreferences; } export interface MoveToFileOptions { - readonly newFileContents: { readonly [fileName: string]: string }; + readonly newFileContents: { readonly [fileName: string]: string; }; readonly interactiveRefactorArguments: ts.InteractiveRefactorArguments; readonly preferences?: ts.UserPreferences; } @@ -1922,9 +2024,13 @@ export type RenameLocationsOptions = readonly RenameLocationOptions[] | { readonly providePrefixAndSuffixTextForRename?: boolean; }; export interface DiagnosticIgnoredInterpolations { - template: string + template: string; } -export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range, readonly prefixText?: string, readonly suffixText?: string }; +export type RenameLocationOptions = FourSlash.Range | { + readonly range: FourSlash.Range; + readonly prefixText?: string; + readonly suffixText?: string; +}; export interface RenameOptions { readonly findInStrings?: boolean; readonly findInComments?: boolean; @@ -1932,7 +2038,13 @@ export interface RenameOptions { readonly quotePreference?: "auto" | "double" | "single"; } export type BaselineCommandWithMarkerOrRange = { - type: "findAllReferences" | "goToDefinition" | "getDefinitionAtPosition" | "goToSourceDefinition" | "goToType" | "goToImplementation"; + type: + | "findAllReferences" + | "goToDefinition" + | "getDefinitionAtPosition" + | "goToSourceDefinition" + | "goToType" + | "goToImplementation"; markerOrRange?: ArrayOrSingle; rangeText?: ArrayOrSingle; } | { diff --git a/src/harness/harnessGlobals.ts b/src/harness/harnessGlobals.ts index 9de9537181f49..a83bff41287ba 100644 --- a/src/harness/harnessGlobals.ts +++ b/src/harness/harnessGlobals.ts @@ -27,7 +27,7 @@ globalThis.assert = chai.assert; assertDeepImpl(a, b, msg); function arrayExtraKeysObject(a: readonly unknown[]): object { - const obj: { [key: string]: unknown } = {}; + const obj: { [key: string]: unknown; } = {}; for (const key in a) { if (Number.isNaN(Number(key))) { obj[key] = a[key]; diff --git a/src/harness/harnessIO.ts b/src/harness/harnessIO.ts index d727cd82e928d..4543212092780 100644 --- a/src/harness/harnessIO.ts +++ b/src/harness/harnessIO.ts @@ -26,18 +26,24 @@ export interface IO { directoryExists(path: string): boolean; deleteFile(fileName: string): void; enumerateTestFiles(runner: RunnerBase): (string | FileBasedTest)[]; - listFiles(path: string, filter?: RegExp, options?: { recursive?: boolean }): string[]; + listFiles(path: string, filter?: RegExp, options?: { recursive?: boolean; }): string[]; log(text: string): void; args(): string[]; getExecutingFilePath(): string; getWorkspaceRoot(): string; exit(exitCode?: number): void; - readDirectory(path: string, extension?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): readonly string[]; + readDirectory( + path: string, + extension?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): readonly string[]; getAccessibleFileSystemEntries(dirname: string): ts.FileSystemEntries; tryEnableSourceMapsForHost?(): void; getEnvironmentVariable?(name: string): string; getMemoryUsage?(): number | undefined; - joinPath(...components: string[]): string + joinPath(...components: string[]): string; } export let IO: IO; @@ -84,7 +90,7 @@ function createNodeIO(): IO { return runner.getTestFiles(); } - function listFiles(path: string, spec: RegExp, options: { recursive?: boolean } = {}) { + function listFiles(path: string, spec: RegExp, options: { recursive?: boolean; } = {}) { function filesInFolder(folder: string): string[] { let paths: string[] = []; @@ -108,7 +114,9 @@ function createNodeIO(): IO { function getAccessibleFileSystemEntries(dirname: string): ts.FileSystemEntries { try { - const entries: string[] = fs.readdirSync(dirname || ".").sort(ts.sys.useCaseSensitiveFileNames ? ts.compareStringsCaseSensitive : ts.compareStringsCaseInsensitive); + const entries: string[] = fs.readdirSync(dirname || ".").sort( + ts.sys.useCaseSensitiveFileNames ? ts.compareStringsCaseSensitive : ts.compareStringsCaseInsensitive, + ); const files: string[] = []; const directories: string[] = []; for (const entry of entries) { @@ -169,12 +177,13 @@ function createNodeIO(): IO { getExecutingFilePath: () => ts.sys.getExecutingFilePath(), getWorkspaceRoot: () => workspaceRoot, exit: exitCode => ts.sys.exit(exitCode), - readDirectory: (path, extension, exclude, include, depth) => ts.sys.readDirectory(path, extension, exclude, include, depth), + readDirectory: (path, extension, exclude, include, depth) => + ts.sys.readDirectory(path, extension, exclude, include, depth), getAccessibleFileSystemEntries, tryEnableSourceMapsForHost: () => ts.sys.tryEnableSourceMapsForHost && ts.sys.tryEnableSourceMapsForHost(), getMemoryUsage: () => ts.sys.getMemoryUsage && ts.sys.getMemoryUsage(), getEnvironmentVariable: name => ts.sys.getEnvironmentVariable(name), - joinPath + joinPath, }; } @@ -220,12 +229,12 @@ export namespace Compiler { public Write(str: string) { // out of memory usage concerns avoid using + or += if we're going to do any manipulation of this string later - this.currentLine = [(this.currentLine || ""), str].join(""); + this.currentLine = [this.currentLine || "", str].join(""); } public WriteLine(str: string) { // out of memory usage concerns avoid using + or += if we're going to do any manipulation of this string later - this.lines.push([(this.currentLine || ""), str].join("")); + this.lines.push([this.currentLine || "", str].join("")); this.currentLine = undefined!; } @@ -243,12 +252,18 @@ export namespace Compiler { export function createSourceFileAndAssertInvariants( fileName: string, sourceText: string, - languageVersion: ts.ScriptTarget) { + languageVersion: ts.ScriptTarget, + ) { // We'll only assert invariants outside of light mode. const shouldAssertInvariants = !lightMode; // Only set the parent nodes if we're asserting invariants. We don't need them otherwise. - const result = ts.createSourceFile(fileName, sourceText, languageVersion, /*setParentNodes:*/ shouldAssertInvariants); + const result = ts.createSourceFile( + fileName, + sourceText, + languageVersion, + /*setParentNodes:*/ shouldAssertInvariants, + ); if (shouldAssertInvariants) { Utils.assertInvariants(result, /*parent:*/ undefined); @@ -270,13 +285,24 @@ export namespace Compiler { if (!libFileNameSourceFileMap) { libFileNameSourceFileMap = new Map(Object.entries({ - [defaultLibFileName]: createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.es5.d.ts")!, /*languageVersion*/ ts.ScriptTarget.Latest) + [defaultLibFileName]: createSourceFileAndAssertInvariants( + defaultLibFileName, + IO.readFile(libFolder + "lib.es5.d.ts")!, + /*languageVersion*/ ts.ScriptTarget.Latest, + ), })); } let sourceFile = libFileNameSourceFileMap.get(fileName); if (!sourceFile) { - libFileNameSourceFileMap.set(fileName, sourceFile = createSourceFileAndAssertInvariants(fileName, IO.readFile(libFolder + fileName)!, ts.ScriptTarget.Latest)); + libFileNameSourceFileMap.set( + fileName, + sourceFile = createSourceFileAndAssertInvariants( + fileName, + IO.readFile(libFolder + fileName)!, + ts.ScriptTarget.Latest, + ), + ); } return sourceFile; } @@ -343,7 +369,10 @@ export namespace Compiler { return optionsIndex.get(name.toLowerCase()); } - export function setCompilerOptionsFromHarnessSetting(settings: TestCaseParser.CompilerSettings, options: ts.CompilerOptions & HarnessOptions): void { + export function setCompilerOptionsFromHarnessSetting( + settings: TestCaseParser.CompilerSettings, + options: ts.CompilerOptions & HarnessOptions, + ): void { for (const name in settings) { if (ts.hasProperty(settings, name)) { const value = settings[name]; @@ -403,13 +432,15 @@ export namespace Compiler { compilerOptions: ts.CompilerOptions | undefined, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file currentDirectory: string | undefined, - symlinks?: vfs.FileSet + symlinks?: vfs.FileSet, ): compiler.CompilationResult { - const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false }; + const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) + : { noResolve: false }; options.target = ts.getEmitScriptTarget(options); options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed; options.noErrorTruncation = true; - options.skipDefaultLibCheck = typeof options.skipDefaultLibCheck === "undefined" ? true : options.skipDefaultLibCheck; + options.skipDefaultLibCheck = typeof options.skipDefaultLibCheck === "undefined" ? true + : options.skipDefaultLibCheck; if (typeof currentDirectory === "undefined") { currentDirectory = vfs.srcFolder; @@ -425,10 +456,13 @@ export namespace Compiler { } } - const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined ? options.useCaseSensitiveFileNames : true; + const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined + ? options.useCaseSensitiveFileNames : true; // When a tsconfig is present, root names passed to createProgram should already be absolute const programFileNames = inputFiles - .map(file => options.configFile ? ts.getNormalizedAbsolutePath(file.unitName, currentDirectory) : file.unitName) + .map(file => + options.configFile ? ts.getNormalizedAbsolutePath(file.unitName, currentDirectory) : file.unitName + ) .filter(fileName => !ts.fileExtensionIs(fileName, ts.Extension.Json)); // Files from built\local that are requested by test "@includeBuiltFiles" to be in the context. @@ -450,7 +484,10 @@ export namespace Compiler { fs.apply(symlinks); } - ts.assign(options, ts.convertToOptionsWithAbsolutePaths(options, path => ts.getNormalizedAbsolutePath(path, currentDirectory))); + ts.assign( + options, + ts.convertToOptionsWithAbsolutePaths(options, path => ts.getNormalizedAbsolutePath(path, currentDirectory)), + ); const host = new fakes.CompilerHost(fs, options); const result = compiler.compileFiles(host, programFileNames, options, typeScriptVersion); result.symlinks = symlinks; @@ -465,14 +502,15 @@ export namespace Compiler { currentDirectory: string; } - export function prepareDeclarationCompilationContext(inputFiles: readonly TestFile[], + export function prepareDeclarationCompilationContext( + inputFiles: readonly TestFile[], otherFiles: readonly TestFile[], result: compiler.CompilationResult, harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions, options: ts.CompilerOptions, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory: string | undefined): DeclarationCompilationContext | undefined { - + currentDirectory: string | undefined, + ): DeclarationCompilationContext | undefined { if (options.declaration && result.diagnostics.length === 0) { if (options.emitDeclarationOnly) { if (result.js.size > 0 || result.dts.size === 0) { @@ -480,7 +518,9 @@ export namespace Compiler { } } else if (result.dts.size !== result.getNumberOfJsFiles(/*includeJson*/ false)) { - throw new Error("There were no errors and declFiles generated did not match number of js files generated"); + throw new Error( + "There were no errors and declFiles generated did not match number of js files generated", + ); } } @@ -491,19 +531,28 @@ export namespace Compiler { if (options.declaration && result.diagnostics.length === 0 && result.dts.size > 0) { ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles)); ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles)); - return { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory: currentDirectory || harnessSettings.currentDirectory }; + return { + declInputFiles, + declOtherFiles, + harnessSettings, + options, + currentDirectory: currentDirectory || harnessSettings.currentDirectory, + }; } function addDtsFile(file: TestFile, dtsFiles: TestFile[]) { if (vpath.isDeclaration(file.unitName) || vpath.isJson(file.unitName)) { dtsFiles.push(file); } - else if (vpath.isTypeScript(file.unitName) || (vpath.isJavaScript(file.unitName) && ts.getAllowJSCompilerOption(options))) { + else if ( + vpath.isTypeScript(file.unitName) + || (vpath.isJavaScript(file.unitName) && ts.getAllowJSCompilerOption(options)) + ) { const declFile = findResultCodeFile(file.unitName); if (declFile && !findUnit(declFile.file, declInputFiles) && !findUnit(declFile.file, declOtherFiles)) { dtsFiles.push({ unitName: declFile.file, - content: Utils.removeByteOrderMark(declFile.text) + content: Utils.removeByteOrderMark(declFile.text), }); } } @@ -530,7 +579,8 @@ export namespace Compiler { sourceFileName = outFile; } - const dTsFileName = ts.removeFileExtension(sourceFileName) + ts.getDeclarationEmitExtensionForPath(sourceFileName); + const dTsFileName = ts.removeFileExtension(sourceFileName) + + ts.getDeclarationEmitExtensionForPath(sourceFileName); return result.dts.get(dTsFileName); } @@ -539,12 +589,22 @@ export namespace Compiler { } } - export function compileDeclarationFiles(context: DeclarationCompilationContext | undefined, symlinks: vfs.FileSet | undefined) { + export function compileDeclarationFiles( + context: DeclarationCompilationContext | undefined, + symlinks: vfs.FileSet | undefined, + ) { if (!context) { return; } const { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory } = context; - const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory, symlinks); + const output = compileFiles( + declInputFiles, + declOtherFiles, + harnessSettings, + options, + currentDirectory, + symlinks, + ); return { declInputFiles, declOtherFiles, declResult: output }; } @@ -553,7 +613,11 @@ export namespace Compiler { return (pretty ? ts.formatDiagnosticsWithColorAndContext : ts.formatDiagnostics)(diagnostics, host); } - export function getErrorBaseline(inputFiles: readonly TestFile[], diagnostics: readonly ts.Diagnostic[], pretty?: boolean) { + export function getErrorBaseline( + inputFiles: readonly TestFile[], + diagnostics: readonly ts.Diagnostic[], + pretty?: boolean, + ) { let outputLines = ""; const gen = iterateErrorBaseline(inputFiles, diagnostics, { pretty }); for (const value of gen) { @@ -561,14 +625,25 @@ export namespace Compiler { outputLines += content; } if (pretty) { - outputLines += Utils.removeTestPathPrefixes(ts.getErrorSummaryText(ts.getErrorCountForSummary(diagnostics), ts.getFilesInErrorForSummary(diagnostics), IO.newLine(), { getCurrentDirectory: () => "" })); + outputLines += Utils.removeTestPathPrefixes( + ts.getErrorSummaryText( + ts.getErrorCountForSummary(diagnostics), + ts.getFilesInErrorForSummary(diagnostics), + IO.newLine(), + { getCurrentDirectory: () => "" }, + ), + ); } return outputLines; } export const diagnosticSummaryMarker = "__diagnosticSummary"; export const globalErrorsMarker = "__globalErrors"; - export function *iterateErrorBaseline(inputFiles: readonly TestFile[], diagnostics: readonly ts.Diagnostic[], options?: { pretty?: boolean, caseSensitive?: boolean, currentDirectory?: string }): IterableIterator<[string, string, number]> { + export function* iterateErrorBaseline( + inputFiles: readonly TestFile[], + diagnostics: readonly ts.Diagnostic[], + options?: { pretty?: boolean; caseSensitive?: boolean; currentDirectory?: string; }, + ): IterableIterator<[string, string, number]> { diagnostics = ts.sort(diagnostics, ts.compareDiagnostics); let outputLines = ""; // Count up all errors that were found in files other than lib.d.ts so we don't miss any @@ -588,7 +663,9 @@ export namespace Compiler { const formatDiagnsoticHost = { getCurrentDirectory: () => options && options.currentDirectory ? options.currentDirectory : "", getNewLine: () => IO.newLine(), - getCanonicalFileName: ts.createGetCanonicalFileName(options && options.caseSensitive !== undefined ? options.caseSensitive : true), + getCanonicalFileName: ts.createGetCanonicalFileName( + options && options.caseSensitive !== undefined ? options.caseSensitive : true, + ), }; function outputErrorText(error: ts.Diagnostic) { @@ -601,15 +678,20 @@ export namespace Compiler { .map(s => "!!! " + ts.diagnosticCategoryName(error) + " TS" + error.code + ": " + s); if (error.relatedInformation) { for (const info of error.relatedInformation) { - let location = info.file ? " " + ts.formatLocation(info.file, info.start!, formatDiagnsoticHost, ts.identity) : ""; + let location = info.file + ? " " + ts.formatLocation(info.file, info.start!, formatDiagnsoticHost, ts.identity) : ""; location = Utils.removeTestPathPrefixes(location); if (location && isDefaultLibraryFile(info.file!.fileName)) { location = location.replace(/(lib(?:.*)\.d\.ts):\d+:\d+/i, "$1:--:--"); } - errLines.push(`!!! related TS${info.code}${location}: ${ts.flattenDiagnosticMessageText(info.messageText, IO.newLine())}`); + errLines.push( + `!!! related TS${info.code}${location}: ${ + ts.flattenDiagnosticMessageText(info.messageText, IO.newLine()) + }`, + ); } } - errLines.forEach(e => outputLines += (newLine() + e)); + errLines.forEach(e => outputLines += newLine() + e); errorsReported++; // do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics @@ -618,7 +700,9 @@ export namespace Compiler { // Similarly for tsconfig, which may be in the input files and contain errors. // 'totalErrorsReportedInNonLibraryNonTsconfigFiles + numLibraryDiagnostics + numTsconfigDiagnostics, diagnostics.length - if (!error.file || !isDefaultLibraryFile(error.file.fileName) && !vpath.isTsConfigFile(error.file.fileName)) { + if ( + !error.file || !isDefaultLibraryFile(error.file.fileName) && !vpath.isTsConfigFile(error.file.fileName) + ) { totalErrorsReportedInNonLibraryNonTsconfigFiles++; } } @@ -642,12 +726,18 @@ export namespace Compiler { // Filter down to the errors in the file const fileErrors = diagnostics.filter((e): e is ts.DiagnosticWithLocation => { const errFn = e.file; - return !!errFn && ts.comparePaths(Utils.removeTestPathPrefixes(errFn.fileName), Utils.removeTestPathPrefixes(inputFile.unitName), options && options.currentDirectory || "", !(options && options.caseSensitive)) === ts.Comparison.EqualTo; + return !!errFn + && ts.comparePaths( + Utils.removeTestPathPrefixes(errFn.fileName), + Utils.removeTestPathPrefixes(inputFile.unitName), + options && options.currentDirectory || "", + !(options && options.caseSensitive), + ) === ts.Comparison.EqualTo; }); - // Header - outputLines += (newLine() + "==== " + Utils.removeTestPathPrefixes(inputFile.unitName) + " (" + fileErrors.length + " errors) ===="); + outputLines += newLine() + "==== " + Utils.removeTestPathPrefixes(inputFile.unitName) + " (" + + fileErrors.length + " errors) ===="; // Make sure we emit something for every error let markedErrorCount = 0; @@ -676,7 +766,7 @@ export namespace Compiler { nextLineStart = lineStarts[lineIndex + 1]; } // Emit this line from the original file - outputLines += (newLine() + " " + line); + outputLines += newLine() + " " + line; fileErrors.forEach(errDiagnostic => { const err = errDiagnostic as ts.TextSpan; // TODO: GH#18217 // Does any error start or continue on to this line? Emit squiggles @@ -689,7 +779,8 @@ export namespace Compiler { // Calculate the start of the squiggle const squiggleStart = Math.max(0, relativeOffset); // TODO/REVIEW: this doesn't work quite right in the browser if a multi file test has files whose names are just the right length relative to one another - outputLines += (newLine() + " " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~")); + outputLines += newLine() + " " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"); // If the error ended here, or we're at the end of the file, emit its message if ((lineIndex === lines.length - 1) || nextLineStart > end) { @@ -718,7 +809,8 @@ export namespace Compiler { } const numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => { - return !!diagnostic.file && (isDefaultLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName)); + return !!diagnostic.file + && (isDefaultLibraryFile(diagnostic.file.fileName) || isBuiltFile(diagnostic.file.fileName)); }); const numTsconfigDiagnostics = ts.countWhere(diagnostics, diagnostic => { @@ -726,15 +818,36 @@ export namespace Compiler { }); // Verify we didn't miss any errors in total - assert.equal(totalErrorsReportedInNonLibraryNonTsconfigFiles + numLibraryDiagnostics + numTsconfigDiagnostics, diagnostics.length, "total number of errors"); + assert.equal( + totalErrorsReportedInNonLibraryNonTsconfigFiles + numLibraryDiagnostics + numTsconfigDiagnostics, + diagnostics.length, + "total number of errors", + ); } - export function doErrorBaseline(baselinePath: string, inputFiles: readonly TestFile[], errors: readonly ts.Diagnostic[], pretty?: boolean) { - Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), - !errors || (errors.length === 0) ? null : getErrorBaseline(inputFiles, errors, pretty)); // eslint-disable-line no-null/no-null + export function doErrorBaseline( + baselinePath: string, + inputFiles: readonly TestFile[], + errors: readonly ts.Diagnostic[], + pretty?: boolean, + ) { + Baseline.runBaseline( + baselinePath.replace(/\.tsx?$/, ".errors.txt"), + !errors || (errors.length === 0) ? null : getErrorBaseline(inputFiles, errors, pretty), + ); // eslint-disable-line no-null/no-null } - export function doTypeAndSymbolBaseline(baselinePath: string, header: string, program: ts.Program, allFiles: {unitName: string, content: string}[], opts?: Baseline.BaselineOptions, multifile?: boolean, skipTypeBaselines?: boolean, skipSymbolBaselines?: boolean, hasErrorBaseline?: boolean) { + export function doTypeAndSymbolBaseline( + baselinePath: string, + header: string, + program: ts.Program, + allFiles: { unitName: string; content: string; }[], + opts?: Baseline.BaselineOptions, + multifile?: boolean, + skipTypeBaselines?: boolean, + skipSymbolBaselines?: boolean, + hasErrorBaseline?: boolean, + ) { // The full walker simulates the types that you would get from doing a full // compile. The pull walker simulates the types you get when you just do // a type query for a random node (like how the LS would do it). Most of the @@ -788,16 +901,23 @@ export namespace Compiler { // When calling this function from rwc-runner, the baselinePath will have no extension. // As rwc test- file is stored in json which ".json" will get stripped off. // When calling this function from compiler-runner, the baselinePath will then has either ".ts" or ".tsx" extension - const outputFileName = ts.endsWith(baselinePath, ts.Extension.Ts) || ts.endsWith(baselinePath, ts.Extension.Tsx) ? - baselinePath.replace(/\.tsx?/, "") : baselinePath; + const outputFileName = + ts.endsWith(baselinePath, ts.Extension.Ts) || ts.endsWith(baselinePath, ts.Extension.Tsx) + ? baselinePath.replace(/\.tsx?/, "") : baselinePath; if (!multifile) { - const fullBaseLine = generateBaseLine(isSymbolBaseLine, isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines); + const fullBaseLine = generateBaseLine( + isSymbolBaseLine, + isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines, + ); Baseline.runBaseline(outputFileName + fullExtension, fullBaseLine, opts); } else { Baseline.runMultifileBaseline(outputFileName, fullExtension, () => { - return iterateBaseLine(isSymbolBaseLine, isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines); + return iterateBaseLine( + isSymbolBaseLine, + isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines, + ); }, opts); } } @@ -812,7 +932,10 @@ export namespace Compiler { return result ? (`//// [${header}] ////\r\n\r\n` + result) : null; // eslint-disable-line no-null/no-null } - function *iterateBaseLine(isSymbolBaseline: boolean, skipBaseline?: boolean): IterableIterator<[string, string]> { + function* iterateBaseLine( + isSymbolBaseline: boolean, + skipBaseline?: boolean, + ): IterableIterator<[string, string]> { if (skipBaseline) { return; } @@ -822,7 +945,8 @@ export namespace Compiler { const { unitName } = file; let typeLines = "=== " + unitName + " ===\r\n"; const codeLines = ts.flatMap(file.content.split(/\r?\n/g), e => e.split(/[\r\u2028\u2029]/g)); - const gen: IterableIterator = isSymbolBaseline ? fullWalker.getSymbols(unitName) : fullWalker.getTypes(unitName); + const gen: IterableIterator = isSymbolBaseline ? fullWalker.getSymbols(unitName) + : fullWalker.getTypes(unitName); let lastIndexWritten: number | undefined; for (const result of gen) { if (isSymbolBaseline && !result.symbol) { @@ -832,7 +956,11 @@ export namespace Compiler { typeLines += codeLines.slice(0, result.line + 1).join("\r\n") + "\r\n"; } else if (result.line !== lastIndexWritten) { - if (!((lastIndexWritten + 1 < codeLines.length) && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) || codeLines[lastIndexWritten + 1].trim() === ""))) { + if ( + !((lastIndexWritten + 1 < codeLines.length) + && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) + || codeLines[lastIndexWritten + 1].trim() === "")) + ) { typeLines += "\r\n"; } typeLines += codeLines.slice(lastIndexWritten + 1, result.line + 1).join("\r\n") + "\r\n"; @@ -845,7 +973,11 @@ export namespace Compiler { lastIndexWritten ??= -1; if (lastIndexWritten + 1 < codeLines.length) { - if (!((lastIndexWritten + 1 < codeLines.length) && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) || codeLines[lastIndexWritten + 1].trim() === ""))) { + if ( + !((lastIndexWritten + 1 < codeLines.length) + && (codeLines[lastIndexWritten + 1].match(/^\s*[{|}]\s*$/) + || codeLines[lastIndexWritten + 1].trim() === "")) + ) { typeLines += "\r\n"; } typeLines += codeLines.slice(lastIndexWritten + 1).join("\r\n"); @@ -856,7 +988,12 @@ export namespace Compiler { } } - export function doSourcemapBaseline(baselinePath: string, options: ts.CompilerOptions, result: compiler.CompilationResult, harnessSettings: TestCaseParser.CompilerSettings) { + export function doSourcemapBaseline( + baselinePath: string, + options: ts.CompilerOptions, + result: compiler.CompilationResult, + harnessSettings: TestCaseParser.CompilerSettings, + ) { const declMaps = ts.getAreDeclarationMapsEnabled(options); if (options.inlineSourceMap) { if (result.maps.size > 0 && !declMaps) { @@ -865,7 +1002,11 @@ export namespace Compiler { return; } else if (options.sourceMap || declMaps) { - if (result.maps.size !== ((options.sourceMap ? result.getNumberOfJsFiles(/*includeJson*/ false) : 0) + (declMaps ? result.getNumberOfJsFiles(/*includeJson*/ true) : 0))) { + if ( + result.maps.size + !== ((options.sourceMap ? result.getNumberOfJsFiles(/*includeJson*/ false) : 0) + + (declMaps ? result.getNumberOfJsFiles(/*includeJson*/ true) : 0)) + ) { throw new Error("Number of sourcemap files should be same as js files."); } @@ -898,12 +1039,27 @@ export namespace Compiler { const anyUnfoundSources = ts.contains(sourceTDs, /*value*/ undefined); if (anyUnfoundSources) return ""; - const hash = "#base64," + ts.map([outputJSFile.text, sourcemap].concat(sourceTDs.map(td => td!.text)), (s) => ts.convertToBase64(decodeURIComponent(encodeURIComponent(s)))).join(","); + const hash = "#base64," + + ts.map( + [outputJSFile.text, sourcemap].concat(sourceTDs.map(td => td!.text)), + s => ts.convertToBase64(decodeURIComponent(encodeURIComponent(s))), + ).join(","); return "\n//// https://sokra.github.io/source-map-visualization" + hash + "\n"; } - export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: compiler.CompilationResult, tsConfigFiles: readonly TestFile[], toBeCompiled: readonly TestFile[], otherFiles: readonly TestFile[], harnessSettings: TestCaseParser.CompilerSettings) { - if (!options.noEmit && !options.emitDeclarationOnly && result.js.size === 0 && result.diagnostics.length === 0) { + export function doJsEmitBaseline( + baselinePath: string, + header: string, + options: ts.CompilerOptions, + result: compiler.CompilationResult, + tsConfigFiles: readonly TestFile[], + toBeCompiled: readonly TestFile[], + otherFiles: readonly TestFile[], + harnessSettings: TestCaseParser.CompilerSettings, + ) { + if ( + !options.noEmit && !options.emitDeclarationOnly && result.js.size === 0 && result.diagnostics.length === 0 + ) { throw new Error("Expected at least one js file to be emitted or at least one error to be created."); } @@ -923,7 +1079,13 @@ export namespace Compiler { jsCode += "\r\n"; } if (!result.diagnostics.length && !ts.endsWith(file.file, ts.Extension.Json)) { - const fileParseResult = ts.createSourceFile(file.file, file.text, ts.getEmitScriptTarget(options), /*setParentNodes*/ false, ts.endsWith(file.file, "x") ? ts.ScriptKind.JSX : ts.ScriptKind.JS); + const fileParseResult = ts.createSourceFile( + file.file, + file.text, + ts.getEmitScriptTarget(options), + /*setParentNodes*/ false, + ts.endsWith(file.file, "x") ? ts.ScriptKind.JSX : ts.ScriptKind.JS, + ); if (ts.length(fileParseResult.parseDiagnostics)) { jsCode += getErrorBaseline([file.asTestFile()], fileParseResult.parseDiagnostics); return; @@ -940,22 +1102,37 @@ export namespace Compiler { } const declFileContext = prepareDeclarationCompilationContext( - toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined + toBeCompiled, + otherFiles, + result, + harnessSettings, + options, + /*currentDirectory*/ undefined, ); const declFileCompilationResult = compileDeclarationFiles(declFileContext, result.symlinks); if (declFileCompilationResult && declFileCompilationResult.declResult.diagnostics.length) { jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n"; jsCode += "\r\n\r\n"; - jsCode += getErrorBaseline(tsConfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.diagnostics); + jsCode += getErrorBaseline( + tsConfigFiles.concat( + declFileCompilationResult.declInputFiles, + declFileCompilationResult.declOtherFiles, + ), + declFileCompilationResult.declResult.diagnostics, + ); } // eslint-disable-next-line no-null/no-null - Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ts.Extension.Js), jsCode.length > 0 ? tsCode + "\r\n\r\n" + jsCode : null); + Baseline.runBaseline( + baselinePath.replace(/\.tsx?/, ts.Extension.Js), + jsCode.length > 0 ? tsCode + "\r\n\r\n" + jsCode : null, + ); } function fileOutput(file: documents.TextDocument, harnessSettings: TestCaseParser.CompilerSettings): string { - const fileName = harnessSettings.fullEmitPaths ? Utils.removeTestPathPrefixes(file.file) : ts.getBaseFileName(file.file); + const fileName = harnessSettings.fullEmitPaths ? Utils.removeTestPathPrefixes(file.file) + : ts.getBaseFileName(file.file); return "//// [" + fileName + "]\r\n" + Utils.removeTestPathPrefixes(file.text); } @@ -982,7 +1159,10 @@ export namespace Compiler { const dupeCase = new Map(); // Yield them for (const outputFile of files) { - yield [checkDuplicatedFileName(outputFile.file, dupeCase), "/*====== " + outputFile.file + " ======*/\r\n" + Utils.removeByteOrderMark(outputFile.text)]; + yield [ + checkDuplicatedFileName(outputFile.file, dupeCase), + "/*====== " + outputFile.file + " ======*/\r\n" + Utils.removeByteOrderMark(outputFile.text), + ]; } function cleanName(fn: string) { @@ -1006,7 +1186,11 @@ export namespace Compiler { } export function sanitizeTestFilePath(name: string) { - const path = ts.toPath(ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), "", Utils.canonicalizeForHarness); + const path = ts.toPath( + ts.normalizeSlashes(name.replace(/[\^<>:"|?*%]/g, "_")).replace(/\.\.\//g, "__dotdot/"), + "", + Utils.canonicalizeForHarness, + ); if (ts.startsWith(path, "/")) { return path.substring(1); } @@ -1048,7 +1232,7 @@ function splitVaryBySettingValue(text: string, varyBy: string): string[] | undef return undefined; } - const variations: { key: string, value?: string | number }[] = []; + const variations: { key: string; value?: string | number; }[] = []; const values = getVaryByStarSettingValues(varyBy); // add (and deduplicate) all included entries @@ -1072,7 +1256,9 @@ function splitVaryBySettingValue(text: string, varyBy: string): string[] | undef for (const exclude of excludes) { const value = values?.get(exclude); let index: number; - while ((index = ts.findIndex(variations, v => v.key === exclude || value !== undefined && v.value === value)) >= 0) { + while ( + (index = ts.findIndex(variations, v => v.key === exclude || value !== undefined && v.value === value)) >= 0 + ) { ts.orderedRemoveItemAt(variations, index); } } @@ -1084,7 +1270,12 @@ function splitVaryBySettingValue(text: string, varyBy: string): string[] | undef return ts.map(variations, v => v.key); } -function computeFileBasedTestConfigurationVariations(configurations: FileBasedTestConfiguration[], variationState: FileBasedTestConfiguration, varyByEntries: [string, string[]][], offset: number) { +function computeFileBasedTestConfigurationVariations( + configurations: FileBasedTestConfiguration[], + variationState: FileBasedTestConfiguration, + varyByEntries: [string, string[]][], + offset: number, +) { if (offset >= varyByEntries.length) { // make a copy of the current variation state configurations.push({ ...variationState }); @@ -1102,7 +1293,10 @@ function computeFileBasedTestConfigurationVariations(configurations: FileBasedTe let booleanVaryByStarSettingValues: Map | undefined; function getVaryByStarSettingValues(varyBy: string): ReadonlyMap | undefined { - const option = ts.forEach(ts.optionDeclarations, decl => ts.equateStringsCaseInsensitive(decl.name, varyBy) ? decl : undefined); + const option = ts.forEach( + ts.optionDeclarations, + decl => ts.equateStringsCaseInsensitive(decl.name, varyBy) ? decl : undefined, + ); if (option) { if (typeof option.type === "object") { return option.type; @@ -1110,7 +1304,7 @@ function getVaryByStarSettingValues(varyBy: string): ReadonlyMap 25) throw new Error(`Provided test options exceeded the maximum number of variations: ${varyBy.map(v => `'@${v}'`).join(", ")}`); + if (variationCount > 25) { + throw new Error( + `Provided test options exceeded the maximum number of variations: ${ + varyBy.map(v => `'@${v}'`).join(", ") + }`, + ); + } varyByEntries.push([varyByKey, entries]); } } @@ -1173,8 +1376,8 @@ export namespace TestCaseParser { } // Regex for parsing options in the format "@Alpha: Value of any sort" - const optionRegex = /^[/]{2}\s*@(\w+)\s*:\s*([^\r\n]*)/gm; // multiple matches on multiple lines - const linkRegex = /^[/]{2}\s*@link\s*:\s*([^\r\n]*)\s*->\s*([^\r\n]*)/gm; // multiple matches on multiple lines + const optionRegex = /^[/]{2}\s*@(\w+)\s*:\s*([^\r\n]*)/gm; // multiple matches on multiple lines + const linkRegex = /^[/]{2}\s*@link\s*:\s*([^\r\n]*)\s*->\s*([^\r\n]*)/gm; // multiple matches on multiple lines export function parseSymlinkFromTest(line: string, symlinks: vfs.FileSet | undefined, absoluteRootDir?: string) { const linkMetaData = linkRegex.exec(line); @@ -1182,7 +1385,9 @@ export namespace TestCaseParser { if (!linkMetaData) return undefined; if (!symlinks) symlinks = {}; - symlinks[ts.getNormalizedAbsolutePath(linkMetaData[2].trim(), absoluteRootDir)] = new vfs.Symlink(ts.getNormalizedAbsolutePath(linkMetaData[1].trim(), absoluteRootDir)); + symlinks[ts.getNormalizedAbsolutePath(linkMetaData[2].trim(), absoluteRootDir)] = new vfs.Symlink( + ts.getNormalizedAbsolutePath(linkMetaData[1].trim(), absoluteRootDir), + ); return symlinks; } @@ -1206,7 +1411,11 @@ export namespace TestCaseParser { } /** Given a test file containing // @FileName directives, return an array of named units of code to be added to an existing compiler instance */ - export function makeUnitsFromTest(code: string, fileName: string, settings = extractCompilerSettings(code)): TestCaseContent { + export function makeUnitsFromTest( + code: string, + fileName: string, + settings = extractCompilerSettings(code), + ): TestCaseContent { // List of all the subfiles we've parsed out const testUnitData: TestUnitData[] = []; @@ -1242,7 +1451,7 @@ export namespace TestCaseParser { name: currentFileName, fileOptions: currentFileOptions, originalFilePath: fileName, - references: refs + references: refs, }; testUnitData.push(newTestFile); @@ -1280,7 +1489,7 @@ export namespace TestCaseParser { name: currentFileName, fileOptions: currentFileOptions, originalFilePath: fileName, - references: refs + references: refs, }; testUnitData.push(newTestFile2); @@ -1288,31 +1497,44 @@ export namespace TestCaseParser { const parseConfigHost: ts.ParseConfigHost = { useCaseSensitiveFileNames: false, readDirectory: (directory, extensions, excludes, includes, depth) => { - return ts.matchFiles(directory, extensions, excludes, includes, /*useCaseSensitiveFileNames*/ false, "", depth, dir => { - const files: string[] = []; - const directories = new Set(); - for (const unit of testUnitData) { - const fileName = ts.getNormalizedAbsolutePath(unit.name, vfs.srcFolder); - if (fileName.toLowerCase().startsWith(dir.toLowerCase())) { - let path = fileName.substring(dir.length); - if (path.startsWith("/")) { - path = path.substring(1); - } - if (path.includes("/")) { - const directoryName = path.substring(0, path.indexOf("/")); - directories.add(directoryName); - } - else { - files.push(path); + return ts.matchFiles( + directory, + extensions, + excludes, + includes, + /*useCaseSensitiveFileNames*/ false, + "", + depth, + dir => { + const files: string[] = []; + const directories = new Set(); + for (const unit of testUnitData) { + const fileName = ts.getNormalizedAbsolutePath(unit.name, vfs.srcFolder); + if (fileName.toLowerCase().startsWith(dir.toLowerCase())) { + let path = fileName.substring(dir.length); + if (path.startsWith("/")) { + path = path.substring(1); + } + if (path.includes("/")) { + const directoryName = path.substring(0, path.indexOf("/")); + directories.add(directoryName); + } + else { + files.push(path); + } } } - } - return { files, directories: ts.arrayFrom(directories) }; - - }, ts.identity); + return { files, directories: ts.arrayFrom(directories) }; + }, + ts.identity, + ); }, fileExists: fileName => testUnitData.some(data => data.name.toLowerCase() === fileName.toLowerCase()), - readFile: (name) => ts.forEach(testUnitData, data => data.name.toLowerCase() === name.toLowerCase() ? data.content : undefined) + readFile: name => + ts.forEach( + testUnitData, + data => data.name.toLowerCase() === name.toLowerCase() ? data.content : undefined, + ), }; // check if project has tsconfig.json in the list of files @@ -1325,7 +1547,13 @@ export namespace TestCaseParser { assert.isTrue(configJson.endOfFileToken !== undefined); const configFileName = ts.getNormalizedAbsolutePath(data.name, vfs.srcFolder); const configDir = ts.getDirectoryPath(configFileName); - tsConfig = ts.parseJsonSourceFileConfigFileContent(configJson, parseConfigHost, configDir, /*existingOptions*/ undefined, configFileName); + tsConfig = ts.parseJsonSourceFileConfigFileContent( + configJson, + parseConfigHost, + configDir, + /*existingOptions*/ undefined, + configFileName, + ); tsConfigFileUnitData = data; // delete entry from the list @@ -1375,7 +1603,7 @@ export namespace Baseline { } } - const fileCache: { [idx: string]: boolean } = {}; + const fileCache: { [idx: string]: boolean; } = {}; function compareToBaseline(actual: string | null, relativeFileName: string, opts: BaselineOptions | undefined) { // actual is now either undefined (the generator had an error), null (no file requested), @@ -1400,7 +1628,13 @@ export namespace Baseline { return { expected, actual }; } - function writeComparison(expected: string, actual: string, relativeFileName: string, actualFileName: string, opts?: BaselineOptions) { + function writeComparison( + expected: string, + actual: string, + relativeFileName: string, + actualFileName: string, + opts?: BaselineOptions, + ) { // For now this is written using TypeScript, because sys is not available when running old test cases. // But we need to move to sys once we have // Creates the directory including its parent if not already present @@ -1437,12 +1671,21 @@ export namespace Baseline { const errorMessage = getBaselineFileChangedErrorMessage(relativeFileName); if (!!require && opts && opts.PrintDiff) { const Diff = require("diff"); - const patch = Diff.createTwoFilesPatch("Expected", "Actual", expected, actual, "The current baseline", "The new version"); + const patch = Diff.createTwoFilesPatch( + "Expected", + "Actual", + expected, + actual, + "The current baseline", + "The new version", + ); throw new Error(`${errorMessage}${ts.ForegroundColorEscapeSequences.Grey}\n\n${patch}`); } else { if (!IO.fileExists(expected)) { - throw new Error(`New baseline created at ${IO.joinPath("tests", "baselines","local", relativeFileName)}`); + throw new Error( + `New baseline created at ${IO.joinPath("tests", "baselines", "local", relativeFileName)}`, + ); } else { throw new Error(errorMessage); @@ -1458,13 +1701,19 @@ export namespace Baseline { export function runBaseline(relativeFileName: string, actual: string | null, opts?: BaselineOptions): void { const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder); if (actual === undefined) { - throw new Error("The generated content was \"undefined\". Return \"null\" if no baselining is required.\""); + throw new Error('The generated content was "undefined". Return "null" if no baselining is required."'); } const comparison = compareToBaseline(actual, relativeFileName, opts); writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName, opts); } - export function runMultifileBaseline(relativeFileBase: string, extension: string, generateContent: () => IterableIterator<[string, string, number]> | IterableIterator<[string, string]> | null, opts?: BaselineOptions, referencedExtensions?: string[]): void { + export function runMultifileBaseline( + relativeFileBase: string, + extension: string, + generateContent: () => IterableIterator<[string, string, number]> | IterableIterator<[string, string]> | null, + opts?: BaselineOptions, + referencedExtensions?: string[], + ): void { const gen = generateContent(); const writtenFiles = new Map(); const errors: Error[] = []; @@ -1489,7 +1738,11 @@ export namespace Baseline { const referenceDir = referencePath(relativeFileBase, opts && opts.Baselinefolder, opts && opts.Subfolder); let existing = IO.readDirectory(referenceDir, referencedExtensions || [extension]); - if (extension === ".ts" || referencedExtensions && referencedExtensions.indexOf(".ts") > -1 && referencedExtensions.indexOf(".d.ts") === -1) { + if ( + extension === ".ts" + || referencedExtensions && referencedExtensions.indexOf(".ts") > -1 + && referencedExtensions.indexOf(".d.ts") === -1 + ) { // special-case and filter .d.ts out of .ts results existing = existing.filter(f => !ts.endsWith(f, ".d.ts")); } @@ -1509,14 +1762,23 @@ export namespace Baseline { if (errors.length || missing.length) { let errorMsg = ""; if (errors.length) { - errorMsg += `The baseline for ${relativeFileBase} in ${errors.length} files has changed:${"\n " + errors.slice(0, 5).map(e => e.message).join("\n ") + (errors.length > 5 ? "\n" + ` and ${errors.length - 5} more` : "")}`; + errorMsg += `The baseline for ${relativeFileBase} in ${errors.length} files has changed:${ + "\n " + errors.slice(0, 5).map(e => e.message).join("\n ") + + (errors.length > 5 ? "\n" + ` and ${errors.length - 5} more` : "") + }`; } if (errors.length && missing.length) { errorMsg += "\n"; } if (missing.length) { const writtenFilesArray = ts.arrayFrom(writtenFiles.keys()); - errorMsg += `Baseline missing ${missing.length} files:${"\n " + missing.slice(0, 5).join("\n ") + (missing.length > 5 ? "\n" + ` and ${missing.length - 5} more` : "") + "\n"}Written ${writtenFiles.size} files:${"\n " + writtenFilesArray.slice(0, 5).join("\n ") + (writtenFilesArray.length > 5 ? "\n" + ` and ${writtenFilesArray.length - 5} more` : "")}`; + errorMsg += `Baseline missing ${missing.length} files:${ + "\n " + missing.slice(0, 5).join("\n ") + + (missing.length > 5 ? "\n" + ` and ${missing.length - 5} more` : "") + "\n" + }Written ${writtenFiles.size} files:${ + "\n " + writtenFilesArray.slice(0, 5).join("\n ") + + (writtenFilesArray.length > 5 ? "\n" + ` and ${writtenFilesArray.length - 5} more` : "") + }`; } throw new Error(errorMsg); } @@ -1530,8 +1792,8 @@ export function isDefaultLibraryFile(filePath: string): boolean { } export function isBuiltFile(filePath: string): boolean { - return filePath.indexOf(libFolder) === 0 || - filePath.indexOf(vpath.addTrailingSeparator(vfs.builtFolder)) === 0; + return filePath.indexOf(libFolder) === 0 + || filePath.indexOf(vpath.addTrailingSeparator(vfs.builtFolder)) === 0; } export function getDefaultLibraryFile(filePath: string, io: IO): Compiler.TestFile { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index e059aad96f1f5..a93526a169cc7 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -6,10 +6,14 @@ import { virtualFileSystemRoot, } from "./_namespaces/Harness"; import * as ts from "./_namespaces/ts"; -import { getNewLineCharacter } from "./_namespaces/ts"; +import { + getNewLineCharacter, +} from "./_namespaces/ts"; import * as vfs from "./_namespaces/vfs"; import * as vpath from "./_namespaces/vpath"; -import { incrementalVerifier } from "./incrementalUtils"; +import { + incrementalVerifier, +} from "./incrementalUtils"; export function makeDefaultProxy(info: ts.server.PluginCreateInfo): ts.LanguageService { const proxy = Object.create(/*o*/ null); // eslint-disable-line no-null/no-null @@ -59,7 +63,9 @@ export class ScriptInfo { this.editRanges.push({ length: this.content.length, textChangeRange: ts.createTextChangeRange( - ts.createTextSpanFromBounds(start, end), newText.length) + ts.createTextSpanFromBounds(start, end), + newText.length, + ), }); // Update version # @@ -141,8 +147,10 @@ export abstract class LanguageServiceAdapterHost { public typesRegistry: Map | undefined; private scriptInfos: collections.SortedMap; - constructor(protected cancellationToken = DefaultHostCancellationToken.instance, - protected settings = ts.getDefaultCompilerOptions()) { + constructor( + protected cancellationToken = DefaultHostCancellationToken.instance, + protected settings = ts.getDefaultCompilerOptions(), + ) { this.scriptInfos = new collections.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }); } @@ -211,7 +219,12 @@ export abstract class LanguageServiceAdapterHost { this.vfs.mkdirpSync(ts.getDirectoryPath(newPath)); this.vfs.renameSync(oldPath, newPath); - const updater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(this.useCaseSensitiveFileNames()), /*sourceMapper*/ undefined); + const updater = ts.getPathUpdater( + oldPath, + newPath, + ts.createGetCanonicalFileName(this.useCaseSensitiveFileNames()), + /*sourceMapper*/ undefined, + ); this.scriptInfos.forEach((scriptInfo, key) => { const newFileName = updater(key); if (newFileName !== undefined) { @@ -234,7 +247,7 @@ export abstract class LanguageServiceAdapterHost { throw new Error("No script with name '" + fileName + "'"); } - public openFile(_fileName: string, _content?: string, _scriptKindName?: string): void { /*overridden*/ } + public openFile(_fileName: string, _content?: string, _scriptKindName?: string): void {/*overridden*/} /** * @param line 0 based index @@ -249,7 +262,11 @@ export abstract class LanguageServiceAdapterHost { public lineAndCharacterToPosition(fileName: string, lineAndCharacter: ts.LineAndCharacter): number { const script: ScriptInfo = this.getScriptInfo(fileName)!; assert.isOk(script); - return ts.computePositionOfLineAndCharacter(script.getLineMap(), lineAndCharacter.line, lineAndCharacter.character); + return ts.computePositionOfLineAndCharacter( + script.getLineMap(), + lineAndCharacter.line, + lineAndCharacter.character, + ); } useCaseSensitiveFileNames() { @@ -258,7 +275,9 @@ export abstract class LanguageServiceAdapterHost { } /// Native adapter -class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost, LanguageServiceAdapterHost { +class NativeLanguageServiceHost extends LanguageServiceAdapterHost + implements ts.LanguageServiceHost, LanguageServiceAdapterHost +{ isKnownTypesPackageName(name: string): boolean { return !!this.typesRegistry && this.typesRegistry.has(name); } @@ -269,17 +288,25 @@ class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts installPackage = ts.notImplemented; - getCompilationSettings() { return this.settings; } + getCompilationSettings() { + return this.settings; + } - getCancellationToken() { return this.cancellationToken; } + getCancellationToken() { + return this.cancellationToken; + } getDirectories(path: string): string[] { return this.sys.getDirectories(path); } - getCurrentDirectory(): string { return virtualFileSystemRoot; } + getCurrentDirectory(): string { + return virtualFileSystemRoot; + } - getDefaultLibFileName(): string { return Compiler.defaultLibFileName; } + getDefaultLibFileName(): string { + return Compiler.defaultLibFileName; + } getScriptFileNames(): string[] { return this.getFilenames().filter(ts.isAnySupportedFileExtension); @@ -290,7 +317,9 @@ class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts return script ? new ScriptSnapshot(script) : undefined; } - getScriptKind(): ts.ScriptKind { return ts.ScriptKind.Unknown; } + getScriptKind(): ts.ScriptKind { + return ts.ScriptKind.Unknown; + } getScriptVersion(fileName: string): string { const script = this.getScriptInfo(fileName); @@ -305,7 +334,13 @@ class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts return this.sys.fileExists(fileName); } - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { return this.sys.readDirectory(path, extensions, exclude, include, depth); } @@ -331,20 +366,34 @@ export class NativeLanguageServiceAdapter implements LanguageServiceAdapter { constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { this.host = new NativeLanguageServiceHost(cancellationToken, options); } - getHost(): LanguageServiceAdapterHost { return this.host; } - getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); } - getClassifier(): ts.Classifier { return ts.createClassifier(); } - getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /*readImportFiles*/ true, ts.hasJSFileExtension(fileName)); } + getHost(): LanguageServiceAdapterHost { + return this.host; + } + getLanguageService(): ts.LanguageService { + return ts.createLanguageService(this.host); + } + getClassifier(): ts.Classifier { + return ts.createClassifier(); + } + getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { + return ts.preProcessFile(fileContents, /*readImportFiles*/ true, ts.hasJSFileExtension(fileName)); + } } /// Shim adapter -class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceShimHost, ts.CoreServicesShimHost { +class ShimLanguageServiceHost extends LanguageServiceAdapterHost + implements ts.LanguageServiceShimHost, ts.CoreServicesShimHost +{ private nativeHost: NativeLanguageServiceHost; public getModuleResolutionsForFile: ((fileName: string) => string) | undefined; public getTypeReferenceDirectiveResolutionsForFile: ((fileName: string) => string) | undefined; - constructor(preprocessToResolve: boolean, cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { + constructor( + preprocessToResolve: boolean, + cancellationToken?: ts.HostCancellationToken, + options?: ts.CompilerOptions, + ) { super(cancellationToken, options); this.nativeHost = new NativeLanguageServiceHost(cancellationToken, options); @@ -356,30 +405,41 @@ class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.L const scriptInfo = this.getScriptInfo(fileName); return scriptInfo && scriptInfo.content; }, - useCaseSensitiveFileNames: this.useCaseSensitiveFileNames() + useCaseSensitiveFileNames: this.useCaseSensitiveFileNames(), }; - this.getModuleResolutionsForFile = (fileName) => { + this.getModuleResolutionsForFile = fileName => { const scriptInfo = this.getScriptInfo(fileName)!; const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ true); const imports: ts.MapLike = {}; for (const module of preprocessInfo.importedFiles) { - const resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost); + const resolutionInfo = ts.resolveModuleName( + module.fileName, + fileName, + compilerOptions, + moduleResolutionHost, + ); if (resolutionInfo.resolvedModule) { imports[module.fileName] = resolutionInfo.resolvedModule.resolvedFileName; } } return JSON.stringify(imports); }; - this.getTypeReferenceDirectiveResolutionsForFile = (fileName) => { + this.getTypeReferenceDirectiveResolutionsForFile = fileName => { const scriptInfo = this.getScriptInfo(fileName); if (scriptInfo) { const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ false); const resolutions: ts.MapLike = {}; const settings = this.nativeHost.getCompilationSettings(); for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) { - const resolutionInfo = ts.resolveTypeReferenceDirective(typeReferenceDirective.fileName, fileName, settings, moduleResolutionHost); + const resolutionInfo = ts.resolveTypeReferenceDirective( + typeReferenceDirective.fileName, + fileName, + settings, + moduleResolutionHost, + ); if (resolutionInfo.resolvedTypeReferenceDirective!.resolvedFileName) { - resolutions[typeReferenceDirective.fileName] = resolutionInfo.resolvedTypeReferenceDirective!; + resolutions[typeReferenceDirective.fileName] = resolutionInfo + .resolvedTypeReferenceDirective!; } } return JSON.stringify(resolutions); @@ -391,37 +451,73 @@ class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.L } } - override getFilenames(): string[] { return this.nativeHost.getFilenames(); } - override getScriptInfo(fileName: string): ScriptInfo | undefined { return this.nativeHost.getScriptInfo(fileName); } - override addScript(fileName: string, content: string, isRootFile: boolean): void { this.nativeHost.addScript(fileName, content, isRootFile); } - override editScript(fileName: string, start: number, end: number, newText: string): void { this.nativeHost.editScript(fileName, start, end, newText); } - override positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter { return this.nativeHost.positionToLineAndCharacter(fileName, position); } + override getFilenames(): string[] { + return this.nativeHost.getFilenames(); + } + override getScriptInfo(fileName: string): ScriptInfo | undefined { + return this.nativeHost.getScriptInfo(fileName); + } + override addScript(fileName: string, content: string, isRootFile: boolean): void { + this.nativeHost.addScript(fileName, content, isRootFile); + } + override editScript(fileName: string, start: number, end: number, newText: string): void { + this.nativeHost.editScript(fileName, start, end, newText); + } + override positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter { + return this.nativeHost.positionToLineAndCharacter(fileName, position); + } - getCompilationSettings(): string { return JSON.stringify(this.nativeHost.getCompilationSettings()); } - getCancellationToken(): ts.HostCancellationToken { return this.nativeHost.getCancellationToken(); } - getCurrentDirectory(): string { return this.nativeHost.getCurrentDirectory(); } - getDirectories(path: string): string { return JSON.stringify(this.nativeHost.getDirectories(path)); } - getDefaultLibFileName(): string { return this.nativeHost.getDefaultLibFileName(); } - getScriptFileNames(): string { return JSON.stringify(this.nativeHost.getScriptFileNames()); } + getCompilationSettings(): string { + return JSON.stringify(this.nativeHost.getCompilationSettings()); + } + getCancellationToken(): ts.HostCancellationToken { + return this.nativeHost.getCancellationToken(); + } + getCurrentDirectory(): string { + return this.nativeHost.getCurrentDirectory(); + } + getDirectories(path: string): string { + return JSON.stringify(this.nativeHost.getDirectories(path)); + } + getDefaultLibFileName(): string { + return this.nativeHost.getDefaultLibFileName(); + } + getScriptFileNames(): string { + return JSON.stringify(this.nativeHost.getScriptFileNames()); + } getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim { const nativeScriptSnapshot = this.nativeHost.getScriptSnapshot(fileName)!; // TODO: GH#18217 return nativeScriptSnapshot && new ScriptSnapshotProxy(nativeScriptSnapshot); } - getScriptKind(): ts.ScriptKind { return this.nativeHost.getScriptKind(); } - getScriptVersion(fileName: string): string { return this.nativeHost.getScriptVersion(fileName); } - getLocalizedDiagnosticMessages(): string { return JSON.stringify({}); } + getScriptKind(): ts.ScriptKind { + return this.nativeHost.getScriptKind(); + } + getScriptVersion(fileName: string): string { + return this.nativeHost.getScriptVersion(fileName); + } + getLocalizedDiagnosticMessages(): string { + return JSON.stringify({}); + } readDirectory = ts.notImplemented; readDirectoryNames = ts.notImplemented; readFileNames = ts.notImplemented; - override fileExists(fileName: string) { return this.getScriptInfo(fileName) !== undefined; } + override fileExists(fileName: string) { + return this.getScriptInfo(fileName) !== undefined; + } override readFile(fileName: string) { const snapshot = this.nativeHost.getScriptSnapshot(fileName); return snapshot && ts.getSnapshotText(snapshot); } - log(s: string): void { this.nativeHost.log(s); } - trace(s: string): void { this.nativeHost.trace(s); } - error(s: string): void { this.nativeHost.error(s); } + log(s: string): void { + this.nativeHost.log(s); + } + trace(s: string): void { + this.nativeHost.trace(s); + } + error(s: string): void { + this.nativeHost.error(s); + } override directoryExists(): boolean { // for tests pessimistically assume that directory always exists return true; @@ -431,10 +527,18 @@ class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.L class ClassifierShimProxy implements ts.Classifier { constructor(private shim: ts.ClassifierShim) { } - getEncodedLexicalClassifications(_text: string, _lexState: ts.EndOfLineState, _classifyKeywordsInGenerics?: boolean): ts.Classifications { + getEncodedLexicalClassifications( + _text: string, + _lexState: ts.EndOfLineState, + _classifyKeywordsInGenerics?: boolean, + ): ts.Classifications { return ts.notImplemented(); } - getClassificationsForLine(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.ClassificationResult { + getClassificationsForLine( + text: string, + lexState: ts.EndOfLineState, + classifyKeywordsInGenerics?: boolean, + ): ts.ClassificationResult { const result = this.shim.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics).split("\n"); const entries: ts.ClassificationInfo[] = []; let i = 0; @@ -443,7 +547,7 @@ class ClassifierShimProxy implements ts.Classifier { for (; i < result.length - 1; i += 2) { const t = entries[i / 2] = { length: parseInt(result[i]), - classification: parseInt(result[i + 1]) + classification: parseInt(result[i + 1]), }; assert.isTrue(t.length > 0, "Result length should be greater than 0, got :" + t.length); @@ -451,11 +555,16 @@ class ClassifierShimProxy implements ts.Classifier { } const finalLexState = parseInt(result[result.length - 1]); - assert.equal(position, text.length, "Expected cumulative length of all entries to match the length of the source. expected: " + text.length + ", but got: " + position); + assert.equal( + position, + text.length, + "Expected cumulative length of all entries to match the length of the source. expected: " + text.length + + ", but got: " + position, + ); return { finalLexState, - entries + entries, }; } } @@ -492,21 +601,56 @@ class LanguageServiceShimProxy implements ts.LanguageService { getSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] { return unwrapJSONCallResult(this.shim.getSyntacticClassifications(fileName, span.start, span.length)); } - getSemanticClassifications(fileName: string, span: ts.TextSpan, format?: ts.SemanticClassificationFormat): ts.ClassifiedSpan[] { + getSemanticClassifications( + fileName: string, + span: ts.TextSpan, + format?: ts.SemanticClassificationFormat, + ): ts.ClassifiedSpan[] { return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length, format)); } getEncodedSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications { return unwrapJSONCallResult(this.shim.getEncodedSyntacticClassifications(fileName, span.start, span.length)); } - getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan, format?: ts.SemanticClassificationFormat): ts.Classifications { + getEncodedSemanticClassifications( + fileName: string, + span: ts.TextSpan, + format?: ts.SemanticClassificationFormat, + ): ts.Classifications { const responseFormat = format || ts.SemanticClassificationFormat.Original; - return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length, responseFormat)); - } - getCompletionsAtPosition(fileName: string, position: number, preferences: ts.UserPreferences | undefined, formattingSettings: ts.FormatCodeSettings | undefined): ts.CompletionInfo { - return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position, preferences, formattingSettings)); - } - getCompletionEntryDetails(fileName: string, position: number, entryName: string, formatOptions: ts.FormatCodeOptions | undefined, source: string | undefined, preferences: ts.UserPreferences | undefined, data: ts.CompletionEntryData | undefined): ts.CompletionEntryDetails { - return unwrapJSONCallResult(this.shim.getCompletionEntryDetails(fileName, position, entryName, JSON.stringify(formatOptions), source, preferences, data)); + return unwrapJSONCallResult( + this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length, responseFormat), + ); + } + getCompletionsAtPosition( + fileName: string, + position: number, + preferences: ts.UserPreferences | undefined, + formattingSettings: ts.FormatCodeSettings | undefined, + ): ts.CompletionInfo { + return unwrapJSONCallResult( + this.shim.getCompletionsAtPosition(fileName, position, preferences, formattingSettings), + ); + } + getCompletionEntryDetails( + fileName: string, + position: number, + entryName: string, + formatOptions: ts.FormatCodeOptions | undefined, + source: string | undefined, + preferences: ts.UserPreferences | undefined, + data: ts.CompletionEntryData | undefined, + ): ts.CompletionEntryDetails { + return unwrapJSONCallResult( + this.shim.getCompletionEntryDetails( + fileName, + position, + entryName, + JSON.stringify(formatOptions), + source, + preferences, + data, + ), + ); } getCompletionEntrySymbol(): ts.Symbol { throw new Error("getCompletionEntrySymbol not implemented across the shim layer."); @@ -520,7 +664,11 @@ class LanguageServiceShimProxy implements ts.LanguageService { getBreakpointStatementAtPosition(fileName: string, position: number): ts.TextSpan { return unwrapJSONCallResult(this.shim.getBreakpointStatementAtPosition(fileName, position)); } - getSignatureHelpItems(fileName: string, position: number, options: ts.SignatureHelpItemsOptions | undefined): ts.SignatureHelpItems { + getSignatureHelpItems( + fileName: string, + position: number, + options: ts.SignatureHelpItemsOptions | undefined, + ): ts.SignatureHelpItems { return unwrapJSONCallResult(this.shim.getSignatureHelpItems(fileName, position, options)); } getRenameInfo(fileName: string, position: number, preferences: ts.UserPreferences): ts.RenameInfo { @@ -529,8 +677,16 @@ class LanguageServiceShimProxy implements ts.LanguageService { getSmartSelectionRange(fileName: string, position: number): ts.SelectionRange { return unwrapJSONCallResult(this.shim.getSmartSelectionRange(fileName, position)); } - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, preferences?: ts.UserPreferences | boolean): ts.RenameLocation[] { - return unwrapJSONCallResult(this.shim.findRenameLocations(fileName, position, findInStrings, findInComments, preferences)); + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + preferences?: ts.UserPreferences | boolean, + ): ts.RenameLocation[] { + return unwrapJSONCallResult( + this.shim.findRenameLocations(fileName, position, findInStrings, findInComments, preferences), + ); } getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position)); @@ -577,17 +733,38 @@ class LanguageServiceShimProxy implements ts.LanguageService { getIndentationAtPosition(fileName: string, position: number, options: ts.EditorOptions): number { return unwrapJSONCallResult(this.shim.getIndentationAtPosition(fileName, position, JSON.stringify(options))); } - getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): ts.TextChange[] { - return unwrapJSONCallResult(this.shim.getFormattingEditsForRange(fileName, start, end, JSON.stringify(options))); + getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: ts.FormatCodeOptions, + ): ts.TextChange[] { + return unwrapJSONCallResult( + this.shim.getFormattingEditsForRange(fileName, start, end, JSON.stringify(options)), + ); } getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): ts.TextChange[] { return unwrapJSONCallResult(this.shim.getFormattingEditsForDocument(fileName, JSON.stringify(options))); } - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: ts.FormatCodeOptions): ts.TextChange[] { - return unwrapJSONCallResult(this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options))); - } - getDocCommentTemplateAtPosition(fileName: string, position: number, options?: ts.DocCommentTemplateOptions, formatOptions?: ts.FormatCodeSettings): ts.TextInsertion { - return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position, options, formatOptions)); + getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: ts.FormatCodeOptions, + ): ts.TextChange[] { + return unwrapJSONCallResult( + this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options)), + ); + } + getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: ts.DocCommentTemplateOptions, + formatOptions?: ts.FormatCodeSettings, + ): ts.TextInsertion { + return unwrapJSONCallResult( + this.shim.getDocCommentTemplateAtPosition(fileName, position, options, formatOptions), + ); } isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean { return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPosition(fileName, position, openingBrace)); @@ -618,10 +795,13 @@ class LanguageServiceShimProxy implements ts.LanguageService { getApplicableRefactors(): ts.ApplicableRefactorInfo[] { throw new Error("Not supported on the shim."); } - getMoveToRefactoringFileSuggestions(): { newFileName: string, files: string[] } { + getMoveToRefactoringFileSuggestions(): { newFileName: string; files: string[]; } { throw new Error("Not supported on the shim."); } - organizeImports(_args: ts.OrganizeImportsArgs, _formatOptions: ts.FormatCodeSettings): readonly ts.FileTextChanges[] { + organizeImports( + _args: ts.OrganizeImportsArgs, + _formatOptions: ts.FormatCodeSettings, + ): readonly ts.FileTextChanges[] { throw new Error("Not supported on the shim."); } getEditsForFileRename(): readonly ts.FileTextChanges[] { @@ -651,7 +831,10 @@ class LanguageServiceShimProxy implements ts.LanguageService { getAutoImportProvider(): ts.Program | undefined { throw new Error("Program can not be marshaled across the shim layer."); } - updateIsDefinitionOfReferencedSymbols(_referencedSymbols: readonly ts.ReferencedSymbol[], _knownSymbolSpans: Set): boolean { + updateIsDefinitionOfReferencedSymbols( + _referencedSymbols: readonly ts.ReferencedSymbol[], + _knownSymbolSpans: Set, + ): boolean { return ts.notImplemented(); } getNonBoundSourceFile(): ts.SourceFile { @@ -678,19 +861,31 @@ class LanguageServiceShimProxy implements ts.LanguageService { uncommentSelection(fileName: string, textRange: ts.TextRange): ts.TextChange[] { return unwrapJSONCallResult(this.shim.uncommentSelection(fileName, textRange)); } - dispose(): void { this.shim.dispose({}); } + dispose(): void { + this.shim.dispose({}); + } } export class ShimLanguageServiceAdapter implements LanguageServiceAdapter { private host: ShimLanguageServiceHost; private factory: ts.TypeScriptServicesFactory; - constructor(preprocessToResolve: boolean, cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { + constructor( + preprocessToResolve: boolean, + cancellationToken?: ts.HostCancellationToken, + options?: ts.CompilerOptions, + ) { this.host = new ShimLanguageServiceHost(preprocessToResolve, cancellationToken, options); this.factory = new ts.TypeScriptServicesFactory(); } - getHost() { return this.host; } - getLanguageService(): ts.LanguageService { return new LanguageServiceShimProxy(this.factory.createLanguageServiceShim(this.host)); } - getClassifier(): ts.Classifier { return new ClassifierShimProxy(this.factory.createClassifierShim(this.host)); } + getHost() { + return this.host; + } + getLanguageService(): ts.LanguageService { + return new LanguageServiceShimProxy(this.factory.createLanguageServiceShim(this.host)); + } + getClassifier(): ts.Classifier { + return new ClassifierShimProxy(this.factory.createClassifierShim(this.host)); + } getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { const coreServicesShim = this.factory.createCoreServicesShim(this.host); const shimResult: { @@ -698,7 +893,9 @@ export class ShimLanguageServiceAdapter implements LanguageServiceAdapter { typeReferenceDirectives: ts.ShimsFileReference[]; importedFiles: ts.ShimsFileReference[]; isLibFile: boolean; - } = unwrapJSONCallResult(coreServicesShim.getPreProcessedFileInfo(fileName, ts.ScriptSnapshot.fromString(fileContents))); + } = unwrapJSONCallResult( + coreServicesShim.getPreProcessedFileInfo(fileName, ts.ScriptSnapshot.fromString(fileContents)), + ); const convertResult: ts.PreProcessedFileInfo = { referencedFiles: [], @@ -706,14 +903,14 @@ export class ShimLanguageServiceAdapter implements LanguageServiceAdapter { ambientExternalModules: [], isLibFile: shimResult.isLibFile, typeReferenceDirectives: [], - libReferenceDirectives: [] + libReferenceDirectives: [], }; ts.forEach(shimResult.referencedFiles, refFile => { convertResult.referencedFiles.push({ fileName: refFile.path, pos: refFile.position, - end: refFile.position + refFile.length + end: refFile.position + refFile.length, }); }); @@ -721,7 +918,7 @@ export class ShimLanguageServiceAdapter implements LanguageServiceAdapter { convertResult.importedFiles.push({ fileName: importedFile.path, pos: importedFile.position, - end: importedFile.position + importedFile.length + end: importedFile.position + importedFile.length, }); }); @@ -729,7 +926,7 @@ export class ShimLanguageServiceAdapter implements LanguageServiceAdapter { convertResult.importedFiles.push({ fileName: typeRefDirective.path, pos: typeRefDirective.position, - end: typeRefDirective.position + typeRefDirective.length + end: typeRefDirective.position + typeRefDirective.length, }); }); return convertResult; @@ -829,7 +1026,13 @@ class SessionServerHost implements ts.server.ServerHost, ts.server.Logger { return ts.sys.getEnvironmentVariable(name); } - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { return this.host.readDirectory(path, extensions, exclude, include, depth); } @@ -863,8 +1066,12 @@ class SessionServerHost implements ts.server.ServerHost, ts.server.Logger { return false; } - startGroup() { throw ts.notImplemented(); } - endGroup() { throw ts.notImplemented(); } + startGroup() { + throw ts.notImplemented(); + } + endGroup() { + throw ts.notImplemented(); + } perftrc(message: string): void { return this.host.log(message); @@ -912,9 +1119,9 @@ class SessionServerHost implements ts.server.ServerHost, ts.server.Logger { }; return proxy; - } + }, }), - error: undefined + error: undefined, }; // Throws during initialization @@ -923,9 +1130,9 @@ class SessionServerHost implements ts.server.ServerHost, ts.server.Logger { module: () => ({ create() { throw new Error("I am not a well-behaved plugin"); - } + }, }), - error: undefined + error: undefined, }; // Adds another diagnostic @@ -936,21 +1143,27 @@ class SessionServerHost implements ts.server.ServerHost, ts.server.Logger { const proxy = makeDefaultProxy(info); proxy.getSemanticDiagnostics = filename => { const prev = info.languageService.getSemanticDiagnostics(filename); - const sourceFile: ts.SourceFile = info.project.getSourceFile(ts.toPath(filename, /*basePath*/ undefined, ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames)))!; + const sourceFile: ts.SourceFile = info.project.getSourceFile( + ts.toPath( + filename, + /*basePath*/ undefined, + ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames), + ), + )!; prev.push({ category: ts.DiagnosticCategory.Warning, file: sourceFile, code: 9999, length: 3, messageText: `Plugin diagnostic`, - start: 0 + start: 0, }); return prev; }; return proxy; - } + }, }), - error: undefined + error: undefined, }; // Accepts configurations @@ -963,14 +1176,20 @@ class SessionServerHost implements ts.server.ServerHost, ts.server.Logger { const proxy = makeDefaultProxy(info); proxy.getSemanticDiagnostics = filename => { const prev = info.languageService.getSemanticDiagnostics(filename); - const sourceFile: ts.SourceFile = info.project.getSourceFile(ts.toPath(filename, /*basePath*/ undefined, ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames)))!; + const sourceFile: ts.SourceFile = info.project.getSourceFile( + ts.toPath( + filename, + /*basePath*/ undefined, + ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames), + ), + )!; prev.push({ category: ts.DiagnosticCategory.Error, file: sourceFile, code: 9999, length: 3, messageText: customMessage, - start: 0 + start: 0, }); return prev; }; @@ -978,15 +1197,15 @@ class SessionServerHost implements ts.server.ServerHost, ts.server.Logger { }, onConfigurationChanged(config: any) { customMessage = config.message; - } + }, }), - error: undefined + error: undefined, }; default: return { module: undefined, - error: new Error("Could not resolve module") + error: new Error("Could not resolve module"), }; } } @@ -994,7 +1213,10 @@ class SessionServerHost implements ts.server.ServerHost, ts.server.Logger { class FourslashSession extends ts.server.Session { getText(fileName: string) { - return ts.getSnapshotText(this.projectService.getDefaultProjectForFile(ts.server.toNormalizedPath(fileName), /*ensureProject*/ true)!.getScriptSnapshot(fileName)!); + return ts.getSnapshotText( + this.projectService.getDefaultProjectForFile(ts.server.toNormalizedPath(fileName), /*ensureProject*/ true)! + .getScriptSnapshot(fileName)!, + ); } } @@ -1015,7 +1237,10 @@ export class ServerLanguageServiceAdapter implements LanguageServiceAdapter { cancellationToken: ts.server.nullCancellationToken, useSingleInferredProject: false, useInferredProjectPerProjectRoot: false, - typingsInstaller: { ...ts.server.nullTypingsInstaller, globalTypingsCacheLocation: "/Library/Caches/typescript" }, + typingsInstaller: { + ...ts.server.nullTypingsInstaller, + globalTypingsCacheLocation: "/Library/Caches/typescript", + }, byteLength: Buffer.byteLength, hrtime: process.hrtime, logger: serverHost, @@ -1024,7 +1249,6 @@ export class ServerLanguageServiceAdapter implements LanguageServiceAdapter { }; this.server = new FourslashSession(opts); - // Fake the connection between the client and the server serverHost.writeMessage = client.onMessage.bind(client); clientHost.writeMessage = this.server.onMessage.bind(this.server); @@ -1037,23 +1261,34 @@ export class ServerLanguageServiceAdapter implements LanguageServiceAdapter { this.client = client; this.host = clientHost; } - getHost() { return this.host; } - getLanguageService(): ts.LanguageService { return this.client; } - getClassifier(): ts.Classifier { throw new Error("getClassifier is not available using the server interface."); } - getPreProcessedFileInfo(): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); } + getHost() { + return this.host; + } + getLanguageService(): ts.LanguageService { + return this.client; + } + getClassifier(): ts.Classifier { + throw new Error("getClassifier is not available using the server interface."); + } + getPreProcessedFileInfo(): ts.PreProcessedFileInfo { + throw new Error("getPreProcessedFileInfo is not available using the server interface."); + } assertTextConsistent(fileName: string) { const serverText = this.server.getText(fileName); const clientText = this.host.readFile(fileName); - ts.Debug.assert(serverText === clientText, [ - "Server and client text are inconsistent.", - "", - "\x1b[1mServer\x1b[0m\x1b[31m:", - serverText, - "", - "\x1b[1mClient\x1b[0m\x1b[31m:", - clientText, - "", - "This probably means something is wrong with the fourslash infrastructure, not with the test." - ].join(ts.sys.newLine)); + ts.Debug.assert( + serverText === clientText, + [ + "Server and client text are inconsistent.", + "", + "\x1b[1mServer\x1b[0m\x1b[31m:", + serverText, + "", + "\x1b[1mClient\x1b[0m\x1b[31m:", + clientText, + "", + "This probably means something is wrong with the fourslash infrastructure, not with the test.", + ].join(ts.sys.newLine), + ); } } diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts index beee8048030a8..b51e608380bed 100644 --- a/src/harness/harnessUtils.ts +++ b/src/harness/harnessUtils.ts @@ -91,23 +91,21 @@ export function assertInvariants(node: ts.Node | undefined, parent: ts.Node | un // Make sure each of the children is in order. let currentPos = 0; - ts.forEachChild(node, - child => { - assert.isFalse(child.pos < currentPos, "child.pos < currentPos"); - currentPos = child.end; - }, - array => { - assert.isFalse(array.pos < node.pos, "array.pos < node.pos"); - assert.isFalse(array.end > node.end, "array.end > node.end"); - assert.isFalse(array.pos < currentPos, "array.pos < currentPos"); - - for (const item of array) { - assert.isFalse(item.pos < currentPos, "array[i].pos < currentPos"); - currentPos = item.end; - } + ts.forEachChild(node, child => { + assert.isFalse(child.pos < currentPos, "child.pos < currentPos"); + currentPos = child.end; + }, array => { + assert.isFalse(array.pos < node.pos, "array.pos < node.pos"); + assert.isFalse(array.end > node.end, "array.end > node.end"); + assert.isFalse(array.pos < currentPos, "array.pos < currentPos"); - currentPos = array.end; - }); + for (const item of array) { + assert.isFalse(item.pos < currentPos, "array[i].pos < currentPos"); + currentPos = item.end; + } + + currentPos = array.end; + }); const childNodesAndArrays: any[] = []; ts.forEachChild(node, child => { @@ -117,29 +115,34 @@ export function assertInvariants(node: ts.Node | undefined, parent: ts.Node | un }); for (const childName in node) { - if (childName === "parent" || - childName === "nextContainer" || - childName === "modifiers" || - childName === "externalModuleIndicator" || - childName === "original" || + if ( + childName === "parent" + || childName === "nextContainer" + || childName === "modifiers" + || childName === "externalModuleIndicator" + || childName === "original" // for now ignore jsdoc comments - childName === "jsDocComment" || - childName === "checkJsDirective" || - childName === "commonJsModuleIndicator" || + || childName === "jsDocComment" + || childName === "checkJsDirective" + || childName === "commonJsModuleIndicator" // ignore nodes added only to report grammar errors - childName === "illegalInitializer" || - childName === "illegalDecorators" || - childName === "illegalModifiers" || - childName === "illegalQuestionToken" || - childName === "illegalExclamationToken" || - childName === "illegalTypeParameters" || - childName === "illegalType") { + || childName === "illegalInitializer" + || childName === "illegalDecorators" + || childName === "illegalModifiers" + || childName === "illegalQuestionToken" + || childName === "illegalExclamationToken" + || childName === "illegalTypeParameters" + || childName === "illegalType" + ) { continue; } const child = (node as any)[childName]; if (isNodeOrArray(child)) { - assert.isFalse(childNodesAndArrays.indexOf(child) < 0, - "Missing child when forEach'ing over node: " + ts.Debug.formatSyntaxKind(node.kind) + "-" + childName); + assert.isFalse( + childNodesAndArrays.indexOf(child) < 0, + "Missing child when forEach'ing over node: " + ts.Debug.formatSyntaxKind(node.kind) + "-" + + childName, + ); } } } @@ -160,7 +163,7 @@ function convertDiagnostic(diagnostic: ts.Diagnostic) { length: diagnostic.length, messageText: ts.flattenDiagnosticMessageText(diagnostic.messageText, Harness.IO.newLine()), category: ts.diagnosticCategoryName(diagnostic, /*lowerCase*/ false), - code: diagnostic.code + code: diagnostic.code, }; } @@ -184,7 +187,11 @@ export function sourceFileToJSON(file: ts.Node): string { o.containsParseError = true; } - for (const propertyName of Object.getOwnPropertyNames(n) as readonly (keyof ts.SourceFile | keyof ts.Identifier | keyof ts.StringLiteral)[]) { + for ( + const propertyName of Object.getOwnPropertyNames( + n, + ) as readonly (keyof ts.SourceFile | keyof ts.Identifier | keyof ts.StringLiteral)[] + ) { switch (propertyName) { case "parent": case "symbol": @@ -232,7 +239,11 @@ export function sourceFileToJSON(file: ts.Node): string { case "nextContainer": if ((n as ts.HasLocals).nextContainer) { - o[propertyName] = { kind: (n as ts.HasLocals).nextContainer!.kind, pos: (n as ts.HasLocals).nextContainer!.pos, end: (n as ts.HasLocals).nextContainer!.end }; + o[propertyName] = { + kind: (n as ts.HasLocals).nextContainer!.kind, + pos: (n as ts.HasLocals).nextContainer!.pos, + end: (n as ts.HasLocals).nextContainer!.end, + }; } break; @@ -270,7 +281,9 @@ export function assertDiagnosticsEquals(array1: readonly ts.Diagnostic[], array2 assert.equal(d1.length, d2.length, "d1.length !== d2.length"); assert.equal( ts.flattenDiagnosticMessageText(d1.messageText, Harness.IO.newLine()), - ts.flattenDiagnosticMessageText(d2.messageText, Harness.IO.newLine()), "d1.messageText !== d2.messageText"); + ts.flattenDiagnosticMessageText(d2.messageText, Harness.IO.newLine()), + "d1.messageText !== d2.messageText", + ); assert.equal(d1.category, d2.category, "d1.category !== d2.category"); assert.equal(d1.code, d2.code, "d1.code !== d2.code"); } @@ -290,21 +303,23 @@ export function assertStructuralEquals(node1: ts.Node, node2: ts.Node) { // call this on both nodes to ensure all propagated flags have been set (and thus can be // compared). assert.equal(ts.containsParseError(node1), ts.containsParseError(node2)); - assert.equal(node1.flags & ~ts.NodeFlags.ReachabilityAndEmitFlags, node2.flags & ~ts.NodeFlags.ReachabilityAndEmitFlags, "node1.flags !== node2.flags"); - - ts.forEachChild(node1, - child1 => { - const childName = findChildName(node1, child1); - const child2: ts.Node = (node2 as any)[childName]; - - assertStructuralEquals(child1, child2); - }, - array1 => { - const childName = findChildName(node1, array1); - const array2: ts.NodeArray = (node2 as any)[childName]; - - assertArrayStructuralEquals(array1, array2); - }); + assert.equal( + node1.flags & ~ts.NodeFlags.ReachabilityAndEmitFlags, + node2.flags & ~ts.NodeFlags.ReachabilityAndEmitFlags, + "node1.flags !== node2.flags", + ); + + ts.forEachChild(node1, child1 => { + const childName = findChildName(node1, child1); + const child2: ts.Node = (node2 as any)[childName]; + + assertStructuralEquals(child1, child2); + }, array1 => { + const childName = findChildName(node1, array1); + const array2: ts.NodeArray = (node2 as any)[childName]; + + assertArrayStructuralEquals(array1, array2); + }); } function assertArrayStructuralEquals(array1: ts.NodeArray, array2: ts.NodeArray) { @@ -344,9 +359,11 @@ export function filterStack(error: Error, stackTraceLimit = Infinity) { let harnessFrameCount = 0; for (let line of lines) { if (isStackFrame(line)) { - if (frameCount >= stackTraceLimit + if ( + frameCount >= stackTraceLimit || isMocha(line) - || isNode(line)) { + || isNode(line) + ) { continue; } diff --git a/src/harness/incrementalUtils.ts b/src/harness/incrementalUtils.ts index b1f517b2fd89f..17acbcbf0da3a 100644 --- a/src/harness/incrementalUtils.ts +++ b/src/harness/incrementalUtils.ts @@ -6,17 +6,26 @@ export function reportDocumentRegistryStats(documentRegistry: ts.DocumentRegistr str.push(` Key:: ${key}`); bucketEntries.forEach((entry, path) => { if (ts.isDocumentRegistryEntry(entry)) { - str.push(` ${path}: ${ts.Debug.formatScriptKind(entry.sourceFile.scriptKind)} ${entry.languageServiceRefCount}`); + str.push( + ` ${path}: ${ + ts.Debug.formatScriptKind(entry.sourceFile.scriptKind) + } ${entry.languageServiceRefCount}`, + ); } else { - entry.forEach((real, kind) => str.push(` ${path}: ${ts.Debug.formatScriptKind(kind)} ${real.languageServiceRefCount}`)); + entry.forEach((real, kind) => + str.push(` ${path}: ${ts.Debug.formatScriptKind(kind)} ${real.languageServiceRefCount}`) + ); } }); }); return str; } -type DocumentRegistryExpectedStats = Map>>; +type DocumentRegistryExpectedStats = Map< + ts.DocumentRegistryBucketKeyWithMode, + Map> +>; function verifyDocumentRegistryStats( documentRegistry: ts.DocumentRegistry, stats: DocumentRegistryExpectedStats, @@ -27,42 +36,61 @@ function verifyDocumentRegistryStats( const expected = statsByPath?.get(path); if (ts.isDocumentRegistryEntry(entry)) { ts.Debug.assert( - expected?.size === 1 && expected.has(entry.sourceFile.scriptKind) && expected.get(entry.sourceFile.scriptKind) === entry.languageServiceRefCount, - `Document registry has unexpected language service ref count for ${key} ${path} ${ts.Debug.formatScriptKind(entry.sourceFile.scriptKind)} ${entry.languageServiceRefCount}`, + expected?.size === 1 && expected.has(entry.sourceFile.scriptKind) + && expected.get(entry.sourceFile.scriptKind) === entry.languageServiceRefCount, + `Document registry has unexpected language service ref count for ${key} ${path} ${ + ts.Debug.formatScriptKind(entry.sourceFile.scriptKind) + } ${entry.languageServiceRefCount}`, reportStats, ); } else { - entry.forEach((real, kind) => ts.Debug.assert( - real.languageServiceRefCount === expected?.get(kind), - `Document registry has unexpected language service ref count for ${key} ${path} ${ts.Debug.formatScriptKind(kind)} ${real.languageServiceRefCount}`, - reportStats, - )); - expected?.forEach((value, kind) => ts.Debug.assert( - entry.has(kind), - `Document registry expected language service ref count for ${key} ${path} ${ts.Debug.formatScriptKind(kind)} ${value}`, - reportStats, - )); + entry.forEach((real, kind) => + ts.Debug.assert( + real.languageServiceRefCount === expected?.get(kind), + `Document registry has unexpected language service ref count for ${key} ${path} ${ + ts.Debug.formatScriptKind(kind) + } ${real.languageServiceRefCount}`, + reportStats, + ) + ); + expected?.forEach((value, kind) => + ts.Debug.assert( + entry.has(kind), + `Document registry expected language service ref count for ${key} ${path} ${ + ts.Debug.formatScriptKind(kind) + } ${value}`, + reportStats, + ) + ); } }); - statsByPath?.forEach((_value, path) => ts.Debug.assert( - bucketEntries.has(path), - `Document registry does not contain entry for ${key}, ${path}`, - reportStats, - )); + statsByPath?.forEach((_value, path) => + ts.Debug.assert( + bucketEntries.has(path), + `Document registry does not contain entry for ${key}, ${path}`, + reportStats, + ) + ); }); - stats.forEach((_value, key) => ts.Debug.assert( - documentRegistry.getBuckets().has(key), - `Document registry does not contain entry for key: ${key}`, - reportStats, - )); + stats.forEach((_value, key) => + ts.Debug.assert( + documentRegistry.getBuckets().has(key), + `Document registry does not contain entry for key: ${key}`, + reportStats, + ) + ); function reportStats() { const str: string[] = ["", "Actual::", ...reportDocumentRegistryStats(documentRegistry)]; str.push("Expected::"); stats?.forEach((statsByPath, key) => { str.push(` Key:: ${key}`); - statsByPath.forEach((entry, path) => entry.forEach((refCount, kind) => str.push(` ${path}: ${ts.Debug.formatScriptKind(kind)} ${refCount}`))); + statsByPath.forEach((entry, path) => + entry.forEach((refCount, kind) => + str.push(` ${path}: ${ts.Debug.formatScriptKind(kind)} ${refCount}`) + ) + ); }); return str.join("\n"); } @@ -97,4 +125,4 @@ function verifyDocumentRegistry(service: ts.server.ProjectService) { export function incrementalVerifier(service: ts.server.ProjectService) { service.verifyDocumentRegistry = () => verifyDocumentRegistry(service); -} \ No newline at end of file +} diff --git a/src/harness/runnerbase.ts b/src/harness/runnerbase.ts index 41f4ca2469f44..a8053bc6cb911 100644 --- a/src/harness/runnerbase.ts +++ b/src/harness/runnerbase.ts @@ -29,8 +29,11 @@ export abstract class RunnerBase { this.tests.push(fileName); } - public enumerateFiles(folder: string, regex?: RegExp, options?: { recursive: boolean }): string[] { - return ts.map(IO.listFiles(userSpecifiedRoot + folder, regex, { recursive: (options ? options.recursive : false) }), ts.normalizeSlashes); + public enumerateFiles(folder: string, regex?: RegExp, options?: { recursive: boolean; }): string[] { + return ts.map( + IO.listFiles(userSpecifiedRoot + folder, regex, { recursive: (options ? options.recursive : false) }), + ts.normalizeSlashes, + ); } abstract kind(): TestRunnerKind; diff --git a/src/harness/sourceMapRecorder.ts b/src/harness/sourceMapRecorder.ts index 00852dbc1ccd2..8c9d61d70e4ae 100644 --- a/src/harness/sourceMapRecorder.ts +++ b/src/harness/sourceMapRecorder.ts @@ -1,5 +1,7 @@ import * as documents from "./_namespaces/documents"; -import { Compiler } from "./_namespaces/Harness"; +import { + Compiler, +} from "./_namespaces/Harness"; import * as ts from "./_namespaces/ts"; import * as Utils from "./_namespaces/Utils"; @@ -56,7 +58,11 @@ namespace SourceMapSpanWriter { let nextJsLineToWrite: number; let spanMarkerContinues: boolean; - export function initializeSourceMapSpanWriter(sourceMapRecordWriter: Compiler.WriterAggregator, sourceMap: ts.RawSourceMap, currentJsFile: documents.TextDocument) { + export function initializeSourceMapSpanWriter( + sourceMapRecordWriter: Compiler.WriterAggregator, + sourceMap: ts.RawSourceMap, + currentJsFile: documents.TextDocument, + ) { sourceMapRecorder = sourceMapRecordWriter; sourceMapSources = sourceMap.sources; sourceMapNames = sourceMap.names; @@ -84,7 +90,8 @@ namespace SourceMapSpanWriter { function getSourceMapSpanString(mapEntry: ts.Mapping, getAbsentNameIndex?: boolean) { let mapString = "Emitted(" + (mapEntry.generatedLine + 1) + ", " + (mapEntry.generatedCharacter + 1) + ")"; if (ts.isSourceMapping(mapEntry)) { - mapString += " Source(" + (mapEntry.sourceLine + 1) + ", " + (mapEntry.sourceCharacter + 1) + ") + SourceIndex(" + mapEntry.sourceIndex + ")"; + mapString += " Source(" + (mapEntry.sourceLine + 1) + ", " + (mapEntry.sourceCharacter + 1) + + ") + SourceIndex(" + mapEntry.sourceIndex + ")"; if (mapEntry.nameIndex! >= 0 && mapEntry.nameIndex! < sourceMapNames!.length) { mapString += " name (" + sourceMapNames![mapEntry.nameIndex!] + ")"; } @@ -104,15 +111,26 @@ namespace SourceMapSpanWriter { let decodeErrors: string[] | undefined; if (typeof decodeResult.error === "string" || !ts.sameMapping(decodeResult.sourceMapSpan, sourceMapSpan)) { if (decodeResult.error) { - decodeErrors = ["!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error]; + decodeErrors = [ + "!!^^ !!^^ There was decoding error in the sourcemap at this location: " + decodeResult.error, + ]; } else { - decodeErrors = ["!!^^ !!^^ The decoded span from sourcemap's mapping entry does not match what was encoded for this span:"]; + decodeErrors = [ + "!!^^ !!^^ The decoded span from sourcemap's mapping entry does not match what was encoded for this span:", + ]; } - decodeErrors.push("!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + " Span encoded by the emitter:" + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true)); + decodeErrors.push( + "!!^^ !!^^ Decoded span from sourcemap's mappings entry: " + + getSourceMapSpanString(decodeResult.sourceMapSpan, /*getAbsentNameIndex*/ true) + + " Span encoded by the emitter:" + + getSourceMapSpanString(sourceMapSpan, /*getAbsentNameIndex*/ true), + ); } - if (spansOnSingleLine.length && spansOnSingleLine[0].sourceMapSpan.generatedLine !== sourceMapSpan.generatedLine) { + if ( + spansOnSingleLine.length && spansOnSingleLine[0].sourceMapSpan.generatedLine !== sourceMapSpan.generatedLine + ) { // On different line from the one that we have been recording till now, writeRecordedSpans(); spansOnSingleLine = []; @@ -122,7 +140,10 @@ namespace SourceMapSpanWriter { export function recordNewSourceFileSpan(sourceMapSpan: ts.Mapping, newSourceFileCode: string) { let continuesLine = false; - if (spansOnSingleLine.length > 0 && spansOnSingleLine[0].sourceMapSpan.generatedCharacter === sourceMapSpan.generatedLine) { + if ( + spansOnSingleLine.length > 0 + && spansOnSingleLine[0].sourceMapSpan.generatedCharacter === sourceMapSpan.generatedLine + ) { writeRecordedSpans(); spansOnSingleLine = []; nextJsLineToWrite--; // walk back one line to reprint the line @@ -133,7 +154,11 @@ namespace SourceMapSpanWriter { assert.isTrue(spansOnSingleLine.length === 1); sourceMapRecorder.WriteLine("-------------------------------------------------------------------"); - sourceMapRecorder.WriteLine("emittedFile:" + jsFile.file + (continuesLine ? ` (${sourceMapSpan.generatedLine + 1}, ${sourceMapSpan.generatedCharacter + 1})` : "")); + sourceMapRecorder.WriteLine( + "emittedFile:" + jsFile.file + + (continuesLine ? ` (${sourceMapSpan.generatedLine + 1}, ${sourceMapSpan.generatedCharacter + 1})` + : ""), + ); sourceMapRecorder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex!]); sourceMapRecorder.WriteLine("-------------------------------------------------------------------"); @@ -147,9 +172,12 @@ namespace SourceMapSpanWriter { writeRecordedSpans(); if (!SourceMapDecoder.hasCompletedDecoding()) { - sourceMapRecorder.WriteLine("!!!! **** There are more source map entries in the sourceMap's mapping than what was encoded"); - sourceMapRecorder.WriteLine("!!!! **** Remaining decoded string: " + SourceMapDecoder.getRemainingDecodeString()); - + sourceMapRecorder.WriteLine( + "!!!! **** There are more source map entries in the sourceMap's mapping than what was encoded", + ); + sourceMapRecorder.WriteLine( + "!!!! **** Remaining decoded string: " + SourceMapDecoder.getRemainingDecodeString(), + ); } // write remaining js lines @@ -204,7 +232,12 @@ namespace SourceMapSpanWriter { } } - function writeSourceMapMarker(currentSpan: SourceMapSpanWithDecodeErrors, index: number, endColumn = currentSpan.sourceMapSpan.generatedCharacter, endContinues = false) { + function writeSourceMapMarker( + currentSpan: SourceMapSpanWithDecodeErrors, + index: number, + endColumn = currentSpan.sourceMapSpan.generatedCharacter, + endContinues = false, + ) { const markerId = getMarkerId(index); markerIds.push(markerId); @@ -221,7 +254,8 @@ namespace SourceMapSpanWriter { } function writeSourceMapSourceText(currentSpan: SourceMapSpanWithDecodeErrors, index: number) { - const sourcePos = tsLineMap[currentSpan.sourceMapSpan.sourceLine!] + (currentSpan.sourceMapSpan.sourceCharacter!); + const sourcePos = tsLineMap[currentSpan.sourceMapSpan.sourceLine!] + + (currentSpan.sourceMapSpan.sourceCharacter!); let sourceText = ""; if (prevWrittenSourcePos < sourcePos) { // Position that goes forward, get text @@ -264,7 +298,12 @@ namespace SourceMapSpanWriter { const jsFileText = getTextOfLine(currentJsLine + 1, jsLineMap, jsFile.text); if (prevEmittedCol < jsFileText.length - 1) { // There is remaining text on this line that will be part of next source span so write marker that continues - writeSourceMapMarker(/*currentSpan*/ undefined!, spansOnSingleLine.length, /*endColumn*/ jsFileText.length - 1, /*endContinues*/ true); // TODO: GH#18217 + writeSourceMapMarker( + /*currentSpan*/ undefined!, + spansOnSingleLine.length, + /*endColumn*/ jsFileText.length - 1, + /*endContinues*/ true, + ); // TODO: GH#18217 } // Emit Source text @@ -278,7 +317,12 @@ namespace SourceMapSpanWriter { } } -export function getSourceMapRecord(sourceMapDataList: readonly ts.SourceMapEmitResult[], program: ts.Program, jsFiles: readonly documents.TextDocument[], declarationFiles: readonly documents.TextDocument[]) { +export function getSourceMapRecord( + sourceMapDataList: readonly ts.SourceMapEmitResult[], + program: ts.Program, + jsFiles: readonly documents.TextDocument[], + declarationFiles: readonly documents.TextDocument[], +) { const sourceMapRecorder = new Compiler.WriterAggregator(); for (let i = 0; i < sourceMapDataList.length; i++) { @@ -332,9 +376,12 @@ export function getSourceMapRecordWithSystem(sys: ts.System, sourceMapFile: stri const sourceMap = ts.tryParseRawSourceMap(sys.readFile(sourceMapFile, "utf8")!); if (sourceMap) { const mapDirectory = ts.getDirectoryPath(sourceMapFile); - const sourceRoot = sourceMap.sourceRoot ? ts.getNormalizedAbsolutePath(sourceMap.sourceRoot, mapDirectory) : mapDirectory; + const sourceRoot = sourceMap.sourceRoot ? ts.getNormalizedAbsolutePath(sourceMap.sourceRoot, mapDirectory) + : mapDirectory; const generatedAbsoluteFilePath = ts.getNormalizedAbsolutePath(sourceMap.file, mapDirectory); - const sourceFileAbsolutePaths = sourceMap.sources.map(source => ts.getNormalizedAbsolutePath(source, sourceRoot)); + const sourceFileAbsolutePaths = sourceMap.sources.map(source => + ts.getNormalizedAbsolutePath(source, sourceRoot) + ); const currentFile = getFile(generatedAbsoluteFilePath); SourceMapSpanWriter.initializeSourceMapSpanWriter(sourceMapRecorder, sourceMap, currentFile); diff --git a/src/harness/typeWriter.ts b/src/harness/typeWriter.ts index 3d3602b32decd..40ee7b7406fb8 100644 --- a/src/harness/typeWriter.ts +++ b/src/harness/typeWriter.ts @@ -75,7 +75,9 @@ export class TypeWriterWalker { } private isImportStatementName(node: ts.Node) { - if (ts.isImportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) return true; + if (ts.isImportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) { + return true; + } if (ts.isImportClause(node.parent) && node.parent.name === node) return true; if (ts.isImportEqualsDeclaration(node.parent) && node.parent.name === node) return true; return false; @@ -83,7 +85,9 @@ export class TypeWriterWalker { private isExportStatementName(node: ts.Node) { if (ts.isExportAssignment(node.parent) && node.parent.expression === node) return true; - if (ts.isExportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) return true; + if (ts.isExportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) { + return true; + } return false; } @@ -102,13 +106,18 @@ export class TypeWriterWalker { if (!isSymbolWalk) { // Don't try to get the type of something that's already a type. // Exception for `T` in `type T = something` because that may evaluate to some interesting type. - if (ts.isPartOfTypeNode(node) || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) && !(ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node)) { + if ( + ts.isPartOfTypeNode(node) + || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) + && !(ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node) + ) { return undefined; } // Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions // let type = this.checker.getTypeAtLocation(node); - let type = ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) ? this.checker.getTypeAtLocation(node.parent) : undefined; + let type = ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) + ? this.checker.getTypeAtLocation(node.parent) : undefined; if (!type || type.flags & ts.TypeFlags.Any) type = this.checker.getTypeAtLocation(node); // Distinguish `errorType`s from `any`s; but only if the file has no errors. // Additionally, @@ -123,31 +132,45 @@ export class TypeWriterWalker { // return `error`s via `getTypeAtLocation` // But this is generally expected, so we don't call those out, either let typeString: string; - if (!this.hadErrorBaseline && - type.flags & ts.TypeFlags.Any && - !ts.isBindingElement(node.parent) && - !ts.isPropertyAccessOrQualifiedName(node.parent) && - !ts.isLabelName(node) && - !(ts.isModuleDeclaration(node.parent) && ts.isGlobalScopeAugmentation(node.parent)) && - !ts.isMetaProperty(node.parent) && - !this.isImportStatementName(node) && - !this.isExportStatementName(node) && - !this.isIntrinsicJsxTag(node)) { + if ( + !this.hadErrorBaseline + && type.flags & ts.TypeFlags.Any + && !ts.isBindingElement(node.parent) + && !ts.isPropertyAccessOrQualifiedName(node.parent) + && !ts.isLabelName(node) + && !(ts.isModuleDeclaration(node.parent) && ts.isGlobalScopeAugmentation(node.parent)) + && !ts.isMetaProperty(node.parent) + && !this.isImportStatementName(node) + && !this.isExportStatementName(node) + && !this.isIntrinsicJsxTag(node) + ) { typeString = (type as ts.IntrinsicType).intrinsicName; } else { - typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType); - if (ts.isIdentifier(node) && ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node && typeString === ts.idText(node)) { + typeString = this.checker.typeToString( + type, + node.parent, + ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType, + ); + if ( + ts.isIdentifier(node) && ts.isTypeAliasDeclaration(node.parent) && node.parent.name === node + && typeString === ts.idText(node) + ) { // for a complex type alias `type T = ...`, showing "T : T" isn't very helpful for type tests. When the type produced is the same as // the name of the type alias, recreate the type string without reusing the alias name - typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType | ts.TypeFormatFlags.InTypeAlias); + typeString = this.checker.typeToString( + type, + node.parent, + ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType + | ts.TypeFormatFlags.InTypeAlias, + ); } } return { line: lineAndCharacter.line, syntaxKind: node.kind, sourceText, - type: typeString + type: typeString, }; } const symbol = this.checker.getSymbolAtLocation(node); @@ -172,7 +195,9 @@ export class TypeWriterWalker { const declLineAndCharacter = declSourceFile.getLineAndCharacterOfPosition(declaration.pos); const fileName = ts.getBaseFileName(declSourceFile.fileName); const isLibFile = /lib(.*)\.d\.ts/i.test(fileName); - const declText = `Decl(${ fileName }, ${ isLibFile ? "--" : declLineAndCharacter.line }, ${ isLibFile ? "--" : declLineAndCharacter.character })`; + const declText = `Decl(${fileName}, ${isLibFile ? "--" : declLineAndCharacter.line}, ${ + isLibFile ? "--" : declLineAndCharacter.character + })`; symbolString += declText; (declaration as any).__symbolTestOutputCache = declText; } @@ -182,7 +207,7 @@ export class TypeWriterWalker { line: lineAndCharacter.line, syntaxKind: node.kind, sourceText, - symbol: symbolString + symbol: symbolString, }; } } diff --git a/src/harness/util.ts b/src/harness/util.ts index 607e527459173..81c250e2789d1 100644 --- a/src/harness/util.ts +++ b/src/harness/util.ts @@ -6,19 +6,30 @@ import * as ts from "./_namespaces/ts"; const testPathPrefixRegExp = /(?:(file:\/{3})|\/)\.(ts|lib|src)\//g; export function removeTestPathPrefixes(text: string, retainTrailingDirectorySeparator?: boolean): string { - return text !== undefined ? text.replace(testPathPrefixRegExp, (_, scheme) => scheme || (retainTrailingDirectorySeparator ? "/" : "")) : undefined!; // TODO: GH#18217 + return text !== undefined + ? text.replace(testPathPrefixRegExp, (_, scheme) => scheme || (retainTrailingDirectorySeparator ? "/" : "")) + : undefined!; // TODO: GH#18217 } -function createDiagnosticMessageReplacer string[]>(diagnosticMessage: ts.DiagnosticMessage, replacer: R) { +function createDiagnosticMessageReplacer string[]>( + diagnosticMessage: ts.DiagnosticMessage, + replacer: R, +) { const messageParts = diagnosticMessage.message.split(/{\d+}/g); const regExp = new RegExp(`^(?:${messageParts.map(ts.regExpEscape).join("(.*?)")})$`); type Args = R extends (messageArgs: string[], ...args: infer A) => string[] ? A : []; - return (text: string, ...args: Args) => text.replace(regExp, (_, ...fixedArgs) => ts.formatStringFromArgs(diagnosticMessage.message, replacer(fixedArgs, ...args))); + return (text: string, ...args: Args) => + text.replace( + regExp, + (_, ...fixedArgs) => ts.formatStringFromArgs(diagnosticMessage.message, replacer(fixedArgs, ...args)), + ); } const replaceTypesVersionsMessage = createDiagnosticMessageReplacer( - ts.Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, - ([entry, , moduleName], compilerVersion) => [entry, compilerVersion, moduleName]); + ts.Diagnostics + .package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, + ([entry, , moduleName], compilerVersion) => [entry, compilerVersion, moduleName], +); export function sanitizeTraceResolutionLogEntry(text: string) { return text && replaceTypesVersionsMessage(text, "3.1.0-dev"); @@ -107,9 +118,9 @@ export function theory(name: string, cb: (...args: T) => void, } function formatTheoryDatum(value: any) { - return typeof value === "function" ? value.name || "" : - value === undefined ? "undefined" : - JSON.stringify(value); + return typeof value === "function" ? value.name || "" + : value === undefined ? "undefined" + : JSON.stringify(value); } export interface Deferred { diff --git a/src/harness/vfsUtil.ts b/src/harness/vfsUtil.ts index 6968b34914d81..91a4c83d74be6 100644 --- a/src/harness/vfsUtil.ts +++ b/src/harness/vfsUtil.ts @@ -25,14 +25,14 @@ export const testLibFolder = "/.lib"; export const srcFolder = "/.src"; // file type -const S_IFMT = 0o170000; // file type -const S_IFSOCK = 0o140000; // socket -const S_IFLNK = 0o120000; // symbolic link -const S_IFREG = 0o100000; // regular file -const S_IFBLK = 0o060000; // block device -const S_IFDIR = 0o040000; // directory -const S_IFCHR = 0o020000; // character device -const S_IFIFO = 0o010000; // FIFO +const S_IFMT = 0o170000; // file type +const S_IFSOCK = 0o140000; // socket +const S_IFLNK = 0o120000; // symbolic link +const S_IFREG = 0o100000; // regular file +const S_IFBLK = 0o060000; // block device +const S_IFDIR = 0o040000; // directory +const S_IFCHR = 0o020000; // character device +const S_IFIFO = 0o010000; // FIFO let devCount = 0; // A monotonically increasing count of device ids let inoCount = 0; // A monotonically increasing count of inodes @@ -155,7 +155,9 @@ export class FileSystem { */ public shadow(ignoreCase = this.ignoreCase) { if (!this.isReadonly) throw new Error("Cannot shadow a mutable file system."); - if (ignoreCase && !this.ignoreCase) throw new Error("Cannot create a case-insensitive file system from a case-sensitive one."); + if (ignoreCase && !this.ignoreCase) { + throw new Error("Cannot create a case-insensitive file system from a case-sensitive one."); + } const fs = new FileSystem(ignoreCase, { time: this._time }); fs._shadowRoot = this; fs._cwd = this._cwd; @@ -455,7 +457,6 @@ export class FileSystem { return this._stat(this._walk(this._resolve(path), /*noFollow*/ true)); } - private _stat(entry: WalkResult) { const node = entry.node; if (!node) throw createIOError(`ENOENT`, entry.realpath); @@ -577,11 +578,17 @@ export class FileSystem { public renameSync(oldpath: string, newpath: string) { if (this.isReadonly) throw createIOError("EROFS"); - const { parent: oldParent, links: oldParentLinks, node, basename: oldBasename } = this._walk(this._resolve(oldpath), /*noFollow*/ true); + const { parent: oldParent, links: oldParentLinks, node, basename: oldBasename } = this._walk( + this._resolve(oldpath), + /*noFollow*/ true, + ); if (!oldParent) throw createIOError("EPERM"); if (!node) throw createIOError("ENOENT"); - const { parent: newParent, links: newParentLinks, node: existingNode, basename: newBasename } = this._walk(this._resolve(newpath), /*noFollow*/ true); + const { parent: newParent, links: newParentLinks, node: existingNode, basename: newBasename } = this._walk( + this._resolve(newpath), + /*noFollow*/ true, + ); if (!newParent) throw createIOError("EPERM"); const time = this.time(); @@ -590,7 +597,9 @@ export class FileSystem { if (!isDirectory(existingNode)) throw createIOError("ENOTDIR"); // if both old and new arguments point to the same directory, just pass. So we could rename /src/a/1 to /src/A/1 in Win. // if not and the directory pointed by the new path is not empty, throw an error. - if (this.stringComparer(oldpath, newpath) !== 0 && this._getLinks(existingNode).size > 0) throw createIOError("ENOTEMPTY"); + if (this.stringComparer(oldpath, newpath) !== 0 && this._getLinks(existingNode).size > 0) { + throw createIOError("ENOTEMPTY"); + } } else { if (isDirectory(existingNode)) throw createIOError("EISDIR"); @@ -682,7 +691,8 @@ export class FileSystem { if (isDirectory(node)) throw createIOError("EISDIR"); if (!isFile(node)) throw createIOError("EBADF"); - node.buffer = Buffer.isBuffer(data) ? data.slice() : ts.sys.bufferFrom!("" + data, encoding || "utf8") as Buffer; + node.buffer = Buffer.isBuffer(data) ? data.slice() + : ts.sys.bufferFrom!("" + data, encoding || "utf8") as Buffer; node.size = node.buffer.byteLength; node.mtimeMs = time; node.ctimeMs = time; @@ -695,9 +705,9 @@ export class FileSystem { public diff(base?: FileSystem | undefined, options: DiffOptions = {}) { if (!base && !options.baseIsNotShadowRoot) base = this.shadowRoot; const differences: FileSet = {}; - const hasDifferences = base ? - FileSystem.rootDiff(differences, this, base, options) : - FileSystem.trackCreatedInodes(differences, this, this._getRootLinks()); + const hasDifferences = base + ? FileSystem.rootDiff(differences, this, base, options) + : FileSystem.trackCreatedInodes(differences, this, this._getRootLinks()); return hasDifferences ? differences : undefined; } @@ -706,12 +716,19 @@ export class FileSystem { */ public static diff(changed: FileSystem, base: FileSystem, options: DiffOptions = {}) { const differences: FileSet = {}; - return FileSystem.rootDiff(differences, changed, base, options) ? - differences : - undefined; - } - - private static diffWorker(container: FileSet, changed: FileSystem, changedLinks: ReadonlyMap | undefined, base: FileSystem, baseLinks: ReadonlyMap | undefined, options: DiffOptions) { + return FileSystem.rootDiff(differences, changed, base, options) + ? differences + : undefined; + } + + private static diffWorker( + container: FileSet, + changed: FileSystem, + changedLinks: ReadonlyMap | undefined, + base: FileSystem, + baseLinks: ReadonlyMap | undefined, + options: DiffOptions, + ) { if (changedLinks && !baseLinks) return FileSystem.trackCreatedInodes(container, changed, changedLinks); if (baseLinks && !changedLinks) return FileSystem.trackDeletedInodes(container, baseLinks); if (changedLinks && baseLinks) { @@ -728,16 +745,22 @@ export class FileSystem { const baseNode = baseLinks.get(basename); if (baseNode) { if (isDirectory(changedNode) && isDirectory(baseNode)) { - return hasChanges = FileSystem.directoryDiff(container, basename, changed, changedNode, base, baseNode, options) || hasChanges; + return hasChanges = + FileSystem.directoryDiff(container, basename, changed, changedNode, base, baseNode, options) + || hasChanges; } if (isFile(changedNode) && isFile(baseNode)) { - return hasChanges = FileSystem.fileDiff(container, basename, changed, changedNode, base, baseNode, options) || hasChanges; + return hasChanges = + FileSystem.fileDiff(container, basename, changed, changedNode, base, baseNode, options) + || hasChanges; } if (isSymlink(changedNode) && isSymlink(baseNode)) { - return hasChanges = FileSystem.symlinkDiff(container, basename, changedNode, baseNode) || hasChanges; + return hasChanges = FileSystem.symlinkDiff(container, basename, changedNode, baseNode) + || hasChanges; } } - return hasChanges = FileSystem.trackCreatedInode(container, basename, changed, changedNode) || hasChanges; + return hasChanges = FileSystem.trackCreatedInode(container, basename, changed, changedNode) + || hasChanges; }); return hasChanges; } @@ -757,7 +780,15 @@ export class FileSystem { return FileSystem.diffWorker(container, changed, changed._getRootLinks(), base, base._getRootLinks(), options); } - private static directoryDiff(container: FileSet, basename: string, changed: FileSystem, changedNode: DirectoryInode, base: FileSystem, baseNode: DirectoryInode, options: DiffOptions) { + private static directoryDiff( + container: FileSet, + basename: string, + changed: FileSystem, + changedNode: DirectoryInode, + base: FileSystem, + baseNode: DirectoryInode, + options: DiffOptions, + ) { while (!changedNode.links && changedNode.shadowRoot) changedNode = changedNode.shadowRoot; while (!baseNode.links && baseNode.shadowRoot) baseNode = baseNode.shadowRoot; @@ -768,13 +799,24 @@ export class FileSystem { if (isEmptyNonShadowedDirectory(changedNode) && isEmptyNonShadowedDirectory(baseNode)) return false; // no difference if both nodes are unpopulated and point to the same mounted file system - if (!changedNode.links && !baseNode.links && - changedNode.resolver && changedNode.source !== undefined && - baseNode.resolver === changedNode.resolver && baseNode.source === changedNode.source) return false; + if ( + !changedNode.links && !baseNode.links + && changedNode.resolver && changedNode.source !== undefined + && baseNode.resolver === changedNode.resolver && baseNode.source === changedNode.source + ) return false; // no difference if both nodes have identical children const children: FileSet = {}; - if (!FileSystem.diffWorker(children, changed, changed._getLinks(changedNode), base, base._getLinks(baseNode), options)) { + if ( + !FileSystem.diffWorker( + children, + changed, + changed._getLinks(changedNode), + base, + base._getLinks(baseNode), + options, + ) + ) { return false; } @@ -782,7 +824,15 @@ export class FileSystem { return true; } - private static fileDiff(container: FileSet, basename: string, changed: FileSystem, changedNode: FileInode, base: FileSystem, baseNode: FileInode, options: DiffOptions) { + private static fileDiff( + container: FileSet, + basename: string, + changed: FileSystem, + changedNode: FileInode, + base: FileSystem, + baseNode: FileInode, + options: DiffOptions, + ) { while (!changedNode.buffer && changedNode.shadowRoot) changedNode = changedNode.shadowRoot; while (!baseNode.buffer && baseNode.shadowRoot) baseNode = baseNode.shadowRoot; @@ -793,9 +843,11 @@ export class FileSystem { if (isEmptyNonShadowedFile(changedNode) && isEmptyNonShadowedFile(baseNode)) return false; // no difference if both nodes are unpopulated and point to the same mounted file system - if (!changedNode.buffer && !baseNode.buffer && - changedNode.resolver && changedNode.source !== undefined && - baseNode.resolver === changedNode.resolver && baseNode.source === changedNode.source) return false; + if ( + !changedNode.buffer && !baseNode.buffer + && changedNode.resolver && changedNode.source !== undefined + && baseNode.resolver === changedNode.resolver && baseNode.source === changedNode.source + ) return false; const changedBuffer = changed._getBuffer(changedNode); const baseBuffer = base._getBuffer(baseNode); @@ -818,7 +870,12 @@ export class FileSystem { return true; } - private static symlinkDiff(container: FileSet, basename: string, changedNode: SymlinkInode, baseNode: SymlinkInode) { + private static symlinkDiff( + container: FileSet, + basename: string, + changedNode: SymlinkInode, + baseNode: SymlinkInode, + ) { // no difference if the nodes are the same reference if (changedNode.symlink === baseNode.symlink) return false; container[basename] = new Symlink(changedNode.symlink); @@ -840,7 +897,11 @@ export class FileSystem { return true; } - private static trackCreatedInodes(container: FileSet, changed: FileSystem, changedLinks: ReadonlyMap) { + private static trackCreatedInodes( + container: FileSet, + changed: FileSystem, + changedLinks: ReadonlyMap, + ) { // no difference if links are empty if (!changedLinks.size) return false; @@ -871,11 +932,17 @@ export class FileSystem { mtimeMs: time, ctimeMs: time, birthtimeMs: time, - nlink: 0 + nlink: 0, }; } - private _addLink(parent: DirectoryInode | undefined, links: collections.SortedMap, name: string, node: Inode, time = this.time()) { + private _addLink( + parent: DirectoryInode | undefined, + links: collections.SortedMap, + name: string, + node: Inode, + time = this.time(), + ) { links.set(name, node); node.nlink++; node.ctimeMs = time; @@ -883,14 +950,29 @@ export class FileSystem { if (!parent && !this._cwd) this._cwd = name; } - private _removeLink(parent: DirectoryInode | undefined, links: collections.SortedMap, name: string, node: Inode, time = this.time()) { + private _removeLink( + parent: DirectoryInode | undefined, + links: collections.SortedMap, + name: string, + node: Inode, + time = this.time(), + ) { links.delete(name); node.nlink--; node.ctimeMs = time; if (parent) parent.mtimeMs = time; } - private _replaceLink(oldParent: DirectoryInode, oldLinks: collections.SortedMap, oldName: string, newParent: DirectoryInode, newLinks: collections.SortedMap, newName: string, node: Inode, time: number) { + private _replaceLink( + oldParent: DirectoryInode, + oldLinks: collections.SortedMap, + oldName: string, + newParent: DirectoryInode, + newLinks: collections.SortedMap, + newName: string, + node: Inode, + time: number, + ) { if (oldParent !== newParent) { this._removeLink(oldParent, oldLinks, oldName, node, time); this._addLink(newParent, newLinks, newName, node, time); @@ -964,7 +1046,7 @@ export class FileSystem { ctimeMs: root.ctimeMs, birthtimeMs: root.birthtimeMs, nlink: root.nlink, - shadowRoot: root + shadowRoot: root, }; if (isSymlink(root)) (shadow as SymlinkInode).symlink = root.symlink; @@ -1016,9 +1098,21 @@ export class FileSystem { * * @link http://man7.org/linux/man-pages/man7/path_resolution.7.html */ - private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "retry" | "throw"): WalkResult; - private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw"): WalkResult | undefined; - private _walk(path: string, noFollow?: boolean, onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw"): WalkResult | undefined { + private _walk( + path: string, + noFollow?: boolean, + onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "retry" | "throw", + ): WalkResult; + private _walk( + path: string, + noFollow?: boolean, + onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw", + ): WalkResult | undefined; + private _walk( + path: string, + noFollow?: boolean, + onError?: (error: NodeJS.ErrnoException, fragment: WalkResult) => "stop" | "retry" | "throw", + ): WalkResult | undefined { let links = this._getRootLinks(); let parent: DirectoryInode | undefined; let components = vpath.parse(path); @@ -1081,7 +1175,10 @@ export class FileSystem { */ private _resolve(path: string) { return this._cwd - ? vpath.resolve(this._cwd, vpath.validate(path, vpath.ValidationFlags.RelativeOrAbsolute | vpath.ValidationFlags.AllowWildcard)) + ? vpath.resolve( + this._cwd, + vpath.validate(path, vpath.ValidationFlags.RelativeOrAbsolute | vpath.ValidationFlags.AllowWildcard), + ) : vpath.validate(path, vpath.ValidationFlags.Absolute | vpath.ValidationFlags.AllowWildcard); } @@ -1218,7 +1315,7 @@ export function createResolver(host: FileSystemResolverHost): FileSystemResolver }, readFileSync(path: string): Buffer { return ts.sys.bufferFrom!(host.readFile(path)!, "utf8") as Buffer; // TODO: GH#18217 - } + }, }; } @@ -1231,7 +1328,11 @@ export function createResolver(host: FileSystemResolverHost): FileSystemResolver * * Unless overridden, `/.src` will be the current working directory for the virtual file system. */ -export function createFromFileSystem(host: FileSystemResolverHost, ignoreCase: boolean, { documents, files, cwd, time, meta }: FileSystemCreateOptions = {}) { +export function createFromFileSystem( + host: FileSystemResolverHost, + ignoreCase: boolean, + { documents, files, cwd, time, meta }: FileSystemCreateOptions = {}, +) { const fs = getBuiltLocal(host, ignoreCase).shadow(); if (meta) { for (const key of Object.keys(meta)) { @@ -1287,8 +1388,34 @@ export class Stats { public birthtime: Date; constructor(); - constructor(dev: number, ino: number, mode: number, nlink: number, rdev: number, size: number, blksize: number, blocks: number, atimeMs: number, mtimeMs: number, ctimeMs: number, birthtimeMs: number); - constructor(dev = 0, ino = 0, mode = 0, nlink = 0, rdev = 0, size = 0, blksize = 0, blocks = 0, atimeMs = 0, mtimeMs = 0, ctimeMs = 0, birthtimeMs = 0) { + constructor( + dev: number, + ino: number, + mode: number, + nlink: number, + rdev: number, + size: number, + blksize: number, + blocks: number, + atimeMs: number, + mtimeMs: number, + ctimeMs: number, + birthtimeMs: number, + ); + constructor( + dev = 0, + ino = 0, + mode = 0, + nlink = 0, + rdev = 0, + size = 0, + blksize = 0, + blocks = 0, + atimeMs = 0, + mtimeMs = 0, + ctimeMs = 0, + birthtimeMs = 0, + ) { this.dev = dev; this.ino = ino; this.mode = mode; @@ -1309,13 +1436,27 @@ export class Stats { this.birthtime = new Date(this.birthtimeMs); } - public isFile() { return (this.mode & S_IFMT) === S_IFREG; } - public isDirectory() { return (this.mode & S_IFMT) === S_IFDIR; } - public isSymbolicLink() { return (this.mode & S_IFMT) === S_IFLNK; } - public isBlockDevice() { return (this.mode & S_IFMT) === S_IFBLK; } - public isCharacterDevice() { return (this.mode & S_IFMT) === S_IFCHR; } - public isFIFO() { return (this.mode & S_IFMT) === S_IFIFO; } - public isSocket() { return (this.mode & S_IFMT) === S_IFSOCK; } + public isFile() { + return (this.mode & S_IFMT) === S_IFREG; + } + public isDirectory() { + return (this.mode & S_IFMT) === S_IFDIR; + } + public isSymbolicLink() { + return (this.mode & S_IFMT) === S_IFLNK; + } + public isBlockDevice() { + return (this.mode & S_IFMT) === S_IFBLK; + } + public isCharacterDevice() { + return (this.mode & S_IFMT) === S_IFCHR; + } + public isFIFO() { + return (this.mode & S_IFMT) === S_IFIFO; + } + public isSocket() { + return (this.mode & S_IFMT) === S_IFSOCK; + } } export const IOErrorMessages = Object.freeze({ @@ -1330,7 +1471,7 @@ export const IOErrorMessages = Object.freeze({ EINVAL: "invalid value", ENOTEMPTY: "directory not empty", EPERM: "operation not permitted", - EROFS: "file system is read-only" + EROFS: "file system is read-only", }); export function createIOError(code: keyof typeof IOErrorMessages, details = "") { @@ -1354,7 +1495,7 @@ export type FileLike = File | Buffer | string; export class Directory { public readonly files: FileSet; public readonly meta: Record | undefined; - constructor(files: FileSet, { meta }: { meta?: Record } = {}) { + constructor(files: FileSet, { meta }: { meta?: Record; } = {}) { this.files = files; this.meta = meta; } @@ -1365,7 +1506,7 @@ export class File { public readonly data: Buffer | string; public readonly encoding: string | undefined; public readonly meta: Record | undefined; - constructor(data: Buffer | string, { meta, encoding }: { encoding?: string, meta?: Record } = {}) { + constructor(data: Buffer | string, { meta, encoding }: { encoding?: string; meta?: Record; } = {}) { this.data = data; this.encoding = encoding; this.meta = meta; @@ -1373,13 +1514,13 @@ export class File { } export class SameFileContentFile extends File { - constructor(data: Buffer | string, metaAndEncoding?: { encoding?: string, meta?: Record }) { + constructor(data: Buffer | string, metaAndEncoding?: { encoding?: string; meta?: Record; }) { super(data, metaAndEncoding); } } export class SameFileWithModifiedTime extends File { - constructor(data: Buffer | string, metaAndEncoding?: { encoding?: string, meta?: Record }) { + constructor(data: Buffer | string, metaAndEncoding?: { encoding?: string; meta?: Record; }) { super(data, metaAndEncoding); } } @@ -1406,7 +1547,7 @@ export class Unlink { export class Symlink { public readonly symlink: string; public readonly meta: Record | undefined; - constructor(symlink: string, { meta }: { meta?: Record } = {}) { + constructor(symlink: string, { meta }: { meta?: Record; } = {}) { this.symlink = symlink; this.meta = meta; } @@ -1417,7 +1558,7 @@ export class Mount { public readonly source: string; public readonly resolver: FileSystemResolver; public readonly meta: Record | undefined; - constructor(source: string, resolver: FileSystemResolver, { meta }: { meta?: Record } = {}) { + constructor(source: string, resolver: FileSystemResolver, { meta }: { meta?: Record; } = {}) { this.source = source; this.resolver = resolver; this.meta = meta; @@ -1519,10 +1660,10 @@ function getBuiltLocal(host: FileSystemResolverHost, ignoreCase: boolean): FileS [builtFolder]: new Mount(vpath.resolve(host.getWorkspaceRoot(), "built/local"), resolver), [testLibFolder]: new Mount(vpath.resolve(host.getWorkspaceRoot(), "tests/lib"), resolver), [projectsFolder]: new Mount(vpath.resolve(host.getWorkspaceRoot(), "tests/projects"), resolver), - [srcFolder]: {} + [srcFolder]: {}, }, cwd: srcFolder, - meta: { defaultLibLocation: builtFolder } + meta: { defaultLibLocation: builtFolder }, }); builtLocalCI.makeReadonly(); } @@ -1536,15 +1677,17 @@ function getBuiltLocal(host: FileSystemResolverHost, ignoreCase: boolean): FileS /* eslint-disable no-null/no-null */ function normalizeFileSetEntry(value: FileSet[string]) { - if (value === undefined || - value === null || - value instanceof Directory || - value instanceof File || - value instanceof Link || - value instanceof Symlink || - value instanceof Mount || - value instanceof Rmdir || - value instanceof Unlink) { + if ( + value === undefined + || value === null + || value instanceof Directory + || value instanceof File + || value instanceof Link + || value instanceof Symlink + || value instanceof Mount + || value instanceof Rmdir + || value instanceof Unlink + ) { return value; } return typeof value === "string" || Buffer.isBuffer(value) ? new File(value) : new Directory(value); diff --git a/src/harness/vpathUtil.ts b/src/harness/vpathUtil.ts index 0e84144cf0958..aff65f8967adc 100644 --- a/src/harness/vpathUtil.ts +++ b/src/harness/vpathUtil.ts @@ -54,10 +54,12 @@ export const enum ValidationFlags { Root = RequireRoot | AllowRoot | AllowTrailingSeparator, /** Path must be a absolute */ - Absolute = RequireRoot | AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator | AllowNavigation, + Absolute = RequireRoot | AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator + | AllowNavigation, /** Path may be relative or absolute */ - RelativeOrAbsolute = AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator | AllowNavigation, + RelativeOrAbsolute = AllowRoot | AllowDirname | AllowBasename | AllowExtname | AllowTrailingSeparator + | AllowNavigation, /** Path may only be a filename */ Basename = RequireBasename | AllowExtname, @@ -69,8 +71,10 @@ function validateComponents(components: string[], flags: ValidationFlags, hasTra const hasBasename = components.length > 1; const hasExtname = hasBasename && extRegExp.test(components[components.length - 1]); const invalidComponentRegExp = flags & ValidationFlags.AllowNavigation - ? flags & ValidationFlags.AllowWildcard ? invalidNavigableComponentWithWildcardsRegExp : invalidNavigableComponentRegExp - : flags & ValidationFlags.AllowWildcard ? invalidNonNavigableComponentWithWildcardsRegExp : invalidNonNavigableComponentRegExp; + ? flags & ValidationFlags.AllowWildcard ? invalidNavigableComponentWithWildcardsRegExp + : invalidNavigableComponentRegExp + : flags & ValidationFlags.AllowWildcard ? invalidNonNavigableComponentWithWildcardsRegExp + : invalidNonNavigableComponentRegExp; // Validate required components if (flags & ValidationFlags.RequireRoot && !hasRoot) return false; diff --git a/src/jsTyping/jsTyping.ts b/src/jsTyping/jsTyping.ts index 1983107b35548..d1692fce33cb1 100644 --- a/src/jsTyping/jsTyping.ts +++ b/src/jsTyping/jsTyping.ts @@ -35,7 +35,13 @@ export interface TypingResolutionHost { directoryExists(path: string): boolean; fileExists(fileName: string): boolean; readFile(path: string, encoding?: string): string | undefined; - readDirectory(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[] | undefined, depth?: number): string[]; + readDirectory( + rootDir: string, + extensions: readonly string[], + excludes: readonly string[] | undefined, + includes: readonly string[] | undefined, + depth?: number, + ): string[]; } interface PackageJson { @@ -56,7 +62,10 @@ export interface CachedTyping { /** @internal */ export function isTypingUpToDate(cachedTyping: CachedTyping, availableTypingVersions: MapLike) { - const availableVersion = new Version(getProperty(availableTypingVersions, `ts${versionMajorMinor}`) || getProperty(availableTypingVersions, "latest")!); + const availableVersion = new Version( + getProperty(availableTypingVersions, `ts${versionMajorMinor}`) + || getProperty(availableTypingVersions, "latest")!, + ); return availableVersion.compareTo(cachedTyping.version) <= 0; } @@ -107,7 +116,7 @@ const unprefixedNodeCoreModuleList = [ "vm", "wasi", "worker_threads", - "zlib" + "zlib", ]; /** @internal */ @@ -167,9 +176,8 @@ export function discoverTypings( typeAcquisition: TypeAcquisition, unresolvedImports: readonly string[], typesRegistry: ReadonlyMap>, - compilerOptions: CompilerOptions): - { cachedTypingPaths: string[], newTypingNames: string[], filesToWatch: string[] } { - + compilerOptions: CompilerOptions, +): { cachedTypingPaths: string[]; newTypingNames: string[]; filesToWatch: string[]; } { if (!typeAcquisition || !typeAcquisition.enable) { return { cachedTypingPaths: [], newTypingNames: [], filesToWatch: [] }; } @@ -194,13 +202,13 @@ export function discoverTypings( if (!compilerOptions.types) { const possibleSearchDirs = new Set(fileNames.map(getDirectoryPath)); possibleSearchDirs.add(projectRootPath); - possibleSearchDirs.forEach((searchDir) => { + possibleSearchDirs.forEach(searchDir => { getTypingNames(searchDir, "bower.json", "bower_components", filesToWatch); getTypingNames(searchDir, "package.json", "node_modules", filesToWatch); }); } - if(!typeAcquisition.disableFilenameBasedTypeAcquisition) { + if (!typeAcquisition.disableFilenameBasedTypeAcquisition) { getTypingNamesFromSourceFileNames(fileNames); } // add typings for unresolved imports @@ -208,13 +216,17 @@ export function discoverTypings( const module = deduplicate( unresolvedImports.map(nonRelativeModuleNameForTypingCache), equateStringsCaseSensitive, - compareStringsCaseSensitive); + compareStringsCaseSensitive, + ); addInferredTypings(module, "Inferred typings from unresolved imports"); } // Add the cached typing locations for inferred typings that are already installed packageNameToTypingLocation.forEach((typing, name) => { const registryEntry = typesRegistry.get(name); - if (inferredTypings.has(name) && inferredTypings.get(name) === undefined && registryEntry !== undefined && isTypingUpToDate(typing, registryEntry)) { + if ( + inferredTypings.has(name) && inferredTypings.get(name) === undefined && registryEntry !== undefined + && isTypingUpToDate(typing, registryEntry) + ) { inferredTypings.set(name, typing.typingLocation); } }); @@ -257,7 +269,12 @@ export function discoverTypings( * @param modulesDirName is the directory name for modules (node_modules or bower_components). Should be lowercase! * @param filesToWatch are the files to watch for changes. We will push things into this array. */ - function getTypingNames(projectRootPath: string, manifestName: string, modulesDirName: string, filesToWatch: string[]): void { + function getTypingNames( + projectRootPath: string, + manifestName: string, + modulesDirName: string, + filesToWatch: string[], + ): void { // First, we check the manifests themselves. They're not // _required_, but they allow us to do some filtering when dealing // with big flat dep directories. @@ -267,7 +284,12 @@ export function discoverTypings( if (host.fileExists(manifestPath)) { filesToWatch.push(manifestPath); manifest = readConfigFile(manifestPath, path => host.readFile(path)).config; - manifestTypingNames = flatMap([manifest.dependencies, manifest.devDependencies, manifest.optionalDependencies, manifest.peerDependencies], getOwnKeys); + manifestTypingNames = flatMap([ + manifest.dependencies, + manifest.devDependencies, + manifest.optionalDependencies, + manifest.peerDependencies, + ], getOwnKeys); addInferredTypings(manifestTypingNames, `Typing names in '${manifestPath}' dependencies`); } @@ -300,7 +322,13 @@ export function discoverTypings( // This is #1 described above. ? manifestTypingNames.map(typingName => combinePaths(packagesFolderPath, typingName, manifestName)) // And #2. Depth = 3 because scoped packages look like `node_modules/@foo/bar/package.json` - : host.readDirectory(packagesFolderPath, [Extension.Json], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 3) + : host.readDirectory( + packagesFolderPath, + [Extension.Json], + /*excludes*/ undefined, + /*includes*/ undefined, + /*depth*/ 3, + ) .filter(manifestPath => { if (getBaseFileName(manifestPath) !== manifestName) { return false; @@ -312,11 +340,17 @@ export function discoverTypings( // packages. So that needs this dance here. const pathComponents = getPathComponents(normalizePath(manifestPath)); const isScoped = pathComponents[pathComponents.length - 3][0] === "@"; - return isScoped && toFileNameLowerCase(pathComponents[pathComponents.length - 4]) === modulesDirName || // `node_modules/@foo/bar` - !isScoped && toFileNameLowerCase(pathComponents[pathComponents.length - 3]) === modulesDirName; // `node_modules/foo` + return isScoped + && toFileNameLowerCase(pathComponents[pathComponents.length - 4]) === modulesDirName // `node_modules/@foo/bar` + || !isScoped + && toFileNameLowerCase(pathComponents[pathComponents.length - 3]) === modulesDirName; // `node_modules/foo` }); - if (log) log(`Searching for typing names in ${packagesFolderPath}; all files: ${JSON.stringify(dependencyManifestNames)}`); + if (log) { + log(`Searching for typing names in ${packagesFolderPath}; all files: ${ + JSON.stringify(dependencyManifestNames) + }`); + } // Once we have the names of things to look up, we iterate over // and either collect their included typings, or add them to the @@ -383,7 +417,7 @@ export const enum NameValidationResult { NameTooLong, NameStartsWithDot, NameStartsWithUnderscore, - NameContainsNonURISafeCharacters + NameContainsNonURISafeCharacters, } const maxPackageNameLength = 214; @@ -445,12 +479,17 @@ function validatePackageNameWorker(packageName: string, supportScopedPackage: bo /** @internal */ export function renderPackageNameValidationFailure(result: PackageNameValidationResult, typing: string): string { - return typeof result === "object" ? - renderPackageNameValidationFailureWorker(typing, result.result, result.name, result.isScopeName) : - renderPackageNameValidationFailureWorker(typing, result, typing, /*isScopeName*/ false); + return typeof result === "object" + ? renderPackageNameValidationFailureWorker(typing, result.result, result.name, result.isScopeName) + : renderPackageNameValidationFailureWorker(typing, result, typing, /*isScopeName*/ false); } -function renderPackageNameValidationFailureWorker(typing: string, result: NameValidationResult, name: string, isScopeName: boolean): string { +function renderPackageNameValidationFailureWorker( + typing: string, + result: NameValidationResult, + name: string, + isScopeName: boolean, +): string { const kind = isScopeName ? "Scope" : "Package"; switch (result) { case NameValidationResult.EmptyName: diff --git a/src/jsTyping/shared.ts b/src/jsTyping/shared.ts index 5ae0e09354c75..c0c4c0c1f5145 100644 --- a/src/jsTyping/shared.ts +++ b/src/jsTyping/shared.ts @@ -64,5 +64,7 @@ export function findArgument(argumentName: string): string | undefined { export function nowString() { // E.g. "12:34:56.789" const d = new Date(); - return `${padLeft(d.getHours().toString(), 2, "0")}:${padLeft(d.getMinutes().toString(), 2, "0")}:${padLeft(d.getSeconds().toString(), 2, "0")}.${padLeft(d.getMilliseconds().toString(), 3, "0")}`; + return `${padLeft(d.getHours().toString(), 2, "0")}:${padLeft(d.getMinutes().toString(), 2, "0")}:${ + padLeft(d.getSeconds().toString(), 2, "0") + }.${padLeft(d.getMilliseconds().toString(), 3, "0")}`; } diff --git a/src/jsTyping/types.ts b/src/jsTyping/types.ts index a9991a2f086c7..b428ba1f9f408 100644 --- a/src/jsTyping/types.ts +++ b/src/jsTyping/types.ts @@ -18,7 +18,15 @@ import { } from "./_namespaces/ts.server"; export interface TypingInstallerResponse { - readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed | ActionWatchTypingLocations; + readonly kind: + | ActionSet + | ActionInvalidate + | EventTypesRegistry + | ActionPackageInstalled + | EventBeginInstallTypes + | EventEndInstallTypes + | EventInitializationFailed + | ActionWatchTypingLocations; } export interface TypingInstallerRequestWithProjectName { @@ -117,4 +125,11 @@ export interface WatchTypingLocations extends ProjectResponse { } /** @internal */ -export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InstallTypes | InitializationFailedResponse | WatchTypingLocations; +export type TypingInstallerResponseUnion = + | SetTypings + | InvalidateCachedTypings + | TypesRegistryResponse + | PackageInstalledResponse + | InstallTypes + | InitializationFailedResponse + | WatchTypingLocations; diff --git a/src/lib/decorators.d.ts b/src/lib/decorators.d.ts index 977fa5fc5deb0..e0815367dfbe8 100644 --- a/src/lib/decorators.d.ts +++ b/src/lib/decorators.d.ts @@ -6,21 +6,19 @@ type ClassMemberDecoratorContext = | ClassGetterDecoratorContext | ClassSetterDecoratorContext | ClassFieldDecoratorContext - | ClassAccessorDecoratorContext - ; + | ClassAccessorDecoratorContext; /** * The decorator context types provided to any decorator. */ type DecoratorContext = | ClassDecoratorContext - | ClassMemberDecoratorContext - ; + | ClassMemberDecoratorContext; type DecoratorMetadataObject = Record & object; -type DecoratorMetadata = - typeof globalThis extends { Symbol: { readonly metadata: symbol } } ? DecoratorMetadataObject : DecoratorMetadataObject | undefined; +type DecoratorMetadata = typeof globalThis extends { Symbol: { readonly metadata: symbol; }; } ? DecoratorMetadataObject + : DecoratorMetadataObject | undefined; /** * Context provided to a class decorator. diff --git a/src/lib/decorators.legacy.d.ts b/src/lib/decorators.legacy.d.ts index 2207e50bbda2d..79d794d0f3970 100644 --- a/src/lib/decorators.legacy.d.ts +++ b/src/lib/decorators.legacy.d.ts @@ -1,4 +1,12 @@ declare type ClassDecorator = (target: TFunction) => TFunction | void; declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void; -declare type MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor) => TypedPropertyDescriptor | void; -declare type ParameterDecorator = (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) => void; +declare type MethodDecorator = ( + target: Object, + propertyKey: string | symbol, + descriptor: TypedPropertyDescriptor, +) => TypedPropertyDescriptor | void; +declare type ParameterDecorator = ( + target: Object, + propertyKey: string | symbol | undefined, + parameterIndex: number, +) => void; diff --git a/src/lib/dom.iterable.d.ts b/src/lib/dom.iterable.d.ts index 2c968671a1a42..8ffbcd4811b55 100644 --- a/src/lib/dom.iterable.d.ts +++ b/src/lib/dom.iterable.d.ts @@ -41,12 +41,10 @@ interface NodeList { */ values(): IterableIterator; - [Symbol.iterator](): IterableIterator; } interface NodeListOf { - /** * Returns an array of key, value pairs for every entry in the list */ diff --git a/src/lib/es2015.collection.d.ts b/src/lib/es2015.collection.d.ts index 122e30666ab27..e88f0d4c3b405 100644 --- a/src/lib/es2015.collection.d.ts +++ b/src/lib/es2015.collection.d.ts @@ -1,5 +1,4 @@ interface Map { - clear(): void; /** * @returns true if an element in the Map existed and has been removed, or false if the element does not exist. @@ -29,7 +28,7 @@ interface Map { } interface MapConstructor { - new(): Map; + new (): Map; new (entries?: readonly (readonly [K, V])[] | null): Map; readonly prototype: Map; } diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index 3b1c76c5afc3c..0195237d95a41 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -329,7 +329,10 @@ interface ReadonlyArray { * @param thisArg If provided, it will be used as the this value for each invocation of * predicate. If it is not provided, undefined is used instead. */ - find(predicate: (value: T, index: number, obj: readonly T[]) => value is S, thisArg?: any): S | undefined; + find( + predicate: (value: T, index: number, obj: readonly T[]) => value is S, + thisArg?: any, + ): S | undefined; find(predicate: (value: T, index: number, obj: readonly T[]) => unknown, thisArg?: any): T | undefined; /** @@ -535,5 +538,5 @@ interface StringConstructor { * @param template A well-formed template string call site representation. * @param substitutions A set of substitution values. */ - raw(template: { raw: readonly string[] | ArrayLike}, ...substitutions: any[]): string; + raw(template: { raw: readonly string[] | ArrayLike; }, ...substitutions: any[]): string; } diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index c7b7afa72119d..d28b8381eec86 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -137,11 +137,11 @@ interface ReadonlyMap { } interface MapConstructor { - new(): Map; + new (): Map; new (iterable?: Iterable | null): Map; } -interface WeakMap { } +interface WeakMap {} interface WeakMapConstructor { new (iterable: Iterable): WeakMap; @@ -189,13 +189,13 @@ interface SetConstructor { new (iterable?: Iterable | null): Set; } -interface WeakSet { } +interface WeakSet {} interface WeakSetConstructor { new (iterable: Iterable): WeakSet; } -interface Promise { } +interface Promise {} interface PromiseConstructor { /** @@ -297,7 +297,6 @@ interface Uint8ClampedArray { interface Uint8ClampedArrayConstructor { new (elements: Iterable): Uint8ClampedArray; - /** * Creates an array from an array-like or iterable object. * @param arrayLike An array-like or iterable object to convert to an array. diff --git a/src/lib/es2015.promise.d.ts b/src/lib/es2015.promise.d.ts index 68b476d8c2fc6..3636347d1f1f8 100644 --- a/src/lib/es2015.promise.d.ts +++ b/src/lib/es2015.promise.d.ts @@ -10,7 +10,9 @@ interface PromiseConstructor { * a resolve callback used to resolve the promise with a value or the result of another promise, * and a reject callback used to reject the promise with a provided reason or error. */ - new (executor: (resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => void): Promise; + new ( + executor: (resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => void, + ): Promise; /** * Creates a Promise that is resolved with an array of results when all of the provided Promises @@ -18,7 +20,7 @@ interface PromiseConstructor { * @param values An array of Promises. * @returns A new Promise. */ - all(values: T): Promise<{ -readonly [P in keyof T]: Awaited }>; + all(values: T): Promise<{ -readonly [P in keyof T]: Awaited; }>; // see: lib.es2015.iterable.d.ts // all(values: Iterable>): Promise[]>; diff --git a/src/lib/es2015.reflect.d.ts b/src/lib/es2015.reflect.d.ts index 4f4ddc404f02f..a3f74bbfeeb64 100644 --- a/src/lib/es2015.reflect.d.ts +++ b/src/lib/es2015.reflect.d.ts @@ -34,7 +34,11 @@ declare namespace Reflect { * @param propertyKey The property name. * @param attributes Descriptor for the property. It can be for a data property or an accessor property. */ - function defineProperty(target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor & ThisType): boolean; + function defineProperty( + target: object, + propertyKey: PropertyKey, + attributes: PropertyDescriptor & ThisType, + ): boolean; /** * Removes a property from an object, equivalent to `delete target[propertyKey]`, diff --git a/src/lib/es2015.symbol.d.ts b/src/lib/es2015.symbol.d.ts index 5ef7ff4bb0ee4..9ede0239fafbe 100644 --- a/src/lib/es2015.symbol.d.ts +++ b/src/lib/es2015.symbol.d.ts @@ -25,4 +25,4 @@ interface SymbolConstructor { keyFor(sym: symbol): string | undefined; } -declare var Symbol: SymbolConstructor; \ No newline at end of file +declare var Symbol: SymbolConstructor; diff --git a/src/lib/es2015.symbol.wellknown.d.ts b/src/lib/es2015.symbol.wellknown.d.ts index cf6ccef52b89f..ab18c1f5ddf45 100644 --- a/src/lib/es2015.symbol.wellknown.d.ts +++ b/src/lib/es2015.symbol.wellknown.d.ts @@ -227,14 +227,22 @@ interface String { * @param searchValue An object that supports searching for and replacing matches within a string. * @param replaceValue The replacement text. */ - replace(searchValue: { [Symbol.replace](string: string, replaceValue: string): string; }, replaceValue: string): string; + replace( + searchValue: { [Symbol.replace](string: string, replaceValue: string): string; }, + replaceValue: string, + ): string; /** * Replaces text in a string, using an object that supports replacement within a string. * @param searchValue A object can search for and replace matches within a string. * @param replacer A function that returns the replacement text. */ - replace(searchValue: { [Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string; }, replacer: (substring: string, ...args: any[]) => string): string; + replace( + searchValue: { + [Symbol.replace](string: string, replacer: (substring: string, ...args: any[]) => string): string; + }, + replacer: (substring: string, ...args: any[]) => string, + ): string; /** * Finds the first substring match in a regular expression search. diff --git a/src/lib/es2016.array.include.d.ts b/src/lib/es2016.array.include.d.ts index 1012c18407b0b..00ce45267012a 100644 --- a/src/lib/es2016.array.include.d.ts +++ b/src/lib/es2016.array.include.d.ts @@ -95,4 +95,4 @@ interface Float64Array { * @param fromIndex The position in this array at which to begin searching for searchElement. */ includes(searchElement: number, fromIndex?: number): boolean; -} \ No newline at end of file +} diff --git a/src/lib/es2016.d.ts b/src/lib/es2016.d.ts index fc1aab7798cac..b87f4c2c4f3a1 100644 --- a/src/lib/es2016.d.ts +++ b/src/lib/es2016.d.ts @@ -1,2 +1,2 @@ /// -/// \ No newline at end of file +/// diff --git a/src/lib/es2016.full.d.ts b/src/lib/es2016.full.d.ts index 0f1fd4349daa4..5dda8cc35e785 100644 --- a/src/lib/es2016.full.d.ts +++ b/src/lib/es2016.full.d.ts @@ -2,4 +2,4 @@ /// /// /// -/// \ No newline at end of file +/// diff --git a/src/lib/es2017.date.d.ts b/src/lib/es2017.date.d.ts index 0d3434964b64c..ebd08ea50fb2c 100644 --- a/src/lib/es2017.date.d.ts +++ b/src/lib/es2017.date.d.ts @@ -9,5 +9,13 @@ interface DateConstructor { * @param seconds Must be supplied if milliseconds is supplied. A number from 0 to 59 that specifies the seconds. * @param ms A number from 0 to 999 that specifies the milliseconds. */ - UTC(year: number, monthIndex?: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number; + UTC( + year: number, + monthIndex?: number, + date?: number, + hours?: number, + minutes?: number, + seconds?: number, + ms?: number, + ): number; } diff --git a/src/lib/es2017.full.d.ts b/src/lib/es2017.full.d.ts index 82c358f31e18e..ab03ea04d4844 100644 --- a/src/lib/es2017.full.d.ts +++ b/src/lib/es2017.full.d.ts @@ -2,4 +2,4 @@ /// /// /// -/// \ No newline at end of file +/// diff --git a/src/lib/es2017.intl.d.ts b/src/lib/es2017.intl.d.ts index 2f9efc15fbbae..3ec15630c3e4a 100644 --- a/src/lib/es2017.intl.d.ts +++ b/src/lib/es2017.intl.d.ts @@ -1,17 +1,16 @@ declare namespace Intl { - interface DateTimeFormatPartTypesRegistry { - day: any - dayPeriod: any - era: any - hour: any - literal: any - minute: any - month: any - second: any - timeZoneName: any - weekday: any - year: any + day: any; + dayPeriod: any; + era: any; + hour: any; + literal: any; + minute: any; + month: any; + second: any; + timeZoneName: any; + weekday: any; + year: any; } type DateTimeFormatPartTypes = keyof DateTimeFormatPartTypesRegistry; diff --git a/src/lib/es2017.object.d.ts b/src/lib/es2017.object.d.ts index b3ace85bef182..43e234a3c4dd2 100644 --- a/src/lib/es2017.object.d.ts +++ b/src/lib/es2017.object.d.ts @@ -3,7 +3,7 @@ interface ObjectConstructor { * Returns an array of values of the enumerable 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: { [s: string]: T } | ArrayLike): T[]; + values(o: { [s: string]: T; } | ArrayLike): T[]; /** * Returns an array of values of the enumerable properties of an object @@ -15,7 +15,7 @@ interface ObjectConstructor { * Returns an array of key/values of the enumerable 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: { [s: string]: T } | ArrayLike): [string, T][]; + entries(o: { [s: string]: T; } | ArrayLike): [string, T][]; /** * Returns an array of key/values of the enumerable properties of an object @@ -27,5 +27,7 @@ interface ObjectConstructor { * Returns an object containing all own property descriptors 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. */ - getOwnPropertyDescriptors(o: T): {[P in keyof T]: TypedPropertyDescriptor} & { [x: string]: PropertyDescriptor }; + getOwnPropertyDescriptors( + o: T, + ): { [P in keyof T]: TypedPropertyDescriptor; } & { [x: string]: PropertyDescriptor; }; } diff --git a/src/lib/es2017.sharedmemory.d.ts b/src/lib/es2017.sharedmemory.d.ts index 0d93ba914e09e..77b88af98a408 100644 --- a/src/lib/es2017.sharedmemory.d.ts +++ b/src/lib/es2017.sharedmemory.d.ts @@ -31,28 +31,45 @@ interface Atomics { * Until this atomic operation completes, any other read or write operation against the array * will block. */ - add(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + add( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Stores the bitwise AND of a value with the value at the given position in the array, * returning the original value. Until this atomic operation completes, any other read or * write operation against the array will block. */ - and(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + and( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Replaces the value at the given position in the array if the original value equals the given * expected value, returning the original value. Until this atomic operation completes, any * other read or write operation against the array will block. */ - compareExchange(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, expectedValue: number, replacementValue: number): number; + compareExchange( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + expectedValue: number, + replacementValue: number, + ): number; /** * Replaces the value at the given position in the array, returning the original value. Until * this atomic operation completes, any other read or write operation against the array will * block. */ - exchange(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + exchange( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Returns a value indicating whether high-performance algorithms can use atomic operations @@ -65,27 +82,42 @@ interface Atomics { * Returns the value at the given position in the array. Until this atomic operation completes, * any other read or write operation against the array will block. */ - load(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number): number; + load( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + ): number; /** * Stores the bitwise OR of a value with the value at the given position in the array, * returning the original value. Until this atomic operation completes, any other read or write * operation against the array will block. */ - or(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + or( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Stores a value at the given position in the array, returning the new value. Until this * atomic operation completes, any other read or write operation against the array will block. */ - store(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + store( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * Subtracts a value from the value at the given position in the array, returning the original * value. Until this atomic operation completes, any other read or write operation against the * array will block. */ - sub(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + sub( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; /** * If the value at the given position in the array is equal to the provided value, the current @@ -109,7 +141,11 @@ interface Atomics { * returning the original value. Until this atomic operation completes, any other read or write * operation against the array will block. */ - xor(typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, index: number, value: number): number; + xor( + typedArray: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array, + index: number, + value: number, + ): number; readonly [Symbol.toStringTag]: "Atomics"; } diff --git a/src/lib/es2018.asynciterable.d.ts b/src/lib/es2018.asynciterable.d.ts index c19b8d34cd538..0fe799e21055e 100644 --- a/src/lib/es2018.asynciterable.d.ts +++ b/src/lib/es2018.asynciterable.d.ts @@ -22,4 +22,4 @@ interface AsyncIterable { interface AsyncIterableIterator extends AsyncIterator { [Symbol.asyncIterator](): AsyncIterableIterator; -} \ No newline at end of file +} diff --git a/src/lib/es2018.full.d.ts b/src/lib/es2018.full.d.ts index 0f38d44ca5e6c..e887270b82a2d 100644 --- a/src/lib/es2018.full.d.ts +++ b/src/lib/es2018.full.d.ts @@ -2,4 +2,4 @@ /// /// /// -/// \ No newline at end of file +/// diff --git a/src/lib/es2018.intl.d.ts b/src/lib/es2018.intl.d.ts index 849e064de5dea..345fef902dc23 100644 --- a/src/lib/es2018.intl.d.ts +++ b/src/lib/es2018.intl.d.ts @@ -1,5 +1,4 @@ declare namespace Intl { - // http://cldr.unicode.org/index/cldr-spec/plural-rules#TOC-Determining-Plural-Categories type LDMLPluralRule = "zero" | "one" | "two" | "few" | "many" | "other"; type PluralRuleType = "cardinal" | "ordinal"; @@ -34,12 +33,33 @@ declare namespace Intl { new (locales?: string | string[], options?: PluralRulesOptions): PluralRules; (locales?: string | string[], options?: PluralRulesOptions): PluralRules; - supportedLocalesOf(locales: string | string[], options?: { localeMatcher?: "lookup" | "best fit" }): string[]; + supportedLocalesOf(locales: string | string[], options?: { localeMatcher?: "lookup" | "best fit"; }): string[]; }; // We can only have one definition for 'type' in TypeScript, and so you can learn where the keys come from here: - type ES2018NumberFormatPartType = "literal" | "nan" | "infinity" | "percent" | "integer" | "group" | "decimal" | "fraction" | "plusSign" | "minusSign" | "percentSign" | "currency" | "code" | "symbol" | "name"; - type ES2020NumberFormatPartType = "compact" | "exponentInteger" | "exponentMinusSign" | "exponentSeparator" | "unit" | "unknown"; + type ES2018NumberFormatPartType = + | "literal" + | "nan" + | "infinity" + | "percent" + | "integer" + | "group" + | "decimal" + | "fraction" + | "plusSign" + | "minusSign" + | "percentSign" + | "currency" + | "code" + | "symbol" + | "name"; + type ES2020NumberFormatPartType = + | "compact" + | "exponentInteger" + | "exponentMinusSign" + | "exponentSeparator" + | "unit" + | "unknown"; type NumberFormatPartTypes = ES2018NumberFormatPartType | ES2020NumberFormatPartType; interface NumberFormatPart { diff --git a/src/lib/es2018.promise.d.ts b/src/lib/es2018.promise.d.ts index 28f903870b67c..070c4972f1141 100644 --- a/src/lib/es2018.promise.d.ts +++ b/src/lib/es2018.promise.d.ts @@ -8,5 +8,5 @@ interface Promise { * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). * @returns A Promise for the completion of the callback. */ - finally(onfinally?: (() => void) | undefined | null): Promise + finally(onfinally?: (() => void) | undefined | null): Promise; } diff --git a/src/lib/es2018.regexp.d.ts b/src/lib/es2018.regexp.d.ts index 2067b4846d791..3f142e8cf2131 100644 --- a/src/lib/es2018.regexp.d.ts +++ b/src/lib/es2018.regexp.d.ts @@ -1,13 +1,13 @@ interface RegExpMatchArray { groups?: { - [key: string]: string - } + [key: string]: string; + }; } interface RegExpExecArray { groups?: { - [key: string]: string - } + [key: string]: string; + }; } interface RegExp { @@ -16,4 +16,4 @@ interface RegExp { * Default is false. Read-only. */ readonly dotAll: boolean; -} \ No newline at end of file +} diff --git a/src/lib/es2019.array.d.ts b/src/lib/es2019.array.d.ts index 5181677c5f973..a36c63bbb8aee 100644 --- a/src/lib/es2019.array.d.ts +++ b/src/lib/es2019.array.d.ts @@ -1,12 +1,11 @@ type FlatArray = { - "done": Arr, - "recur": Arr extends ReadonlyArray + done: Arr; + recur: Arr extends ReadonlyArray ? FlatArray - : Arr + : Arr; }[Depth extends -1 ? "done" : "recur"]; interface ReadonlyArray { - /** * Calls a defined callback function on each element of an array. Then, flattens the result into * a new array. @@ -17,11 +16,10 @@ interface ReadonlyArray { * @param thisArg An object to which the this keyword can refer in the callback function. If * thisArg is omitted, undefined is used as the this value. */ - flatMap ( + flatMap( callback: (this: This, value: T, index: number, array: T[]) => U | ReadonlyArray, - thisArg?: This - ): U[] - + thisArg?: This, + ): U[]; /** * Returns a new array with all sub-array elements concatenated into it recursively up to the @@ -31,12 +29,11 @@ interface ReadonlyArray { */ flat( this: A, - depth?: D - ): FlatArray[] - } + depth?: D, + ): FlatArray[]; +} interface Array { - /** * Calls a defined callback function on each element of an array. Then, flattens the result into * a new array. @@ -47,10 +44,10 @@ interface Array { * @param thisArg An object to which the this keyword can refer in the callback function. If * thisArg is omitted, undefined is used as the this value. */ - flatMap ( + flatMap( callback: (this: This, value: T, index: number, array: T[]) => U | ReadonlyArray, - thisArg?: This - ): U[] + thisArg?: This, + ): U[]; /** * Returns a new array with all sub-array elements concatenated into it recursively up to the @@ -60,6 +57,6 @@ interface Array { */ flat( this: A, - depth?: D - ): FlatArray[] + depth?: D, + ): FlatArray[]; } diff --git a/src/lib/es2019.intl.d.ts b/src/lib/es2019.intl.d.ts index 32993edc4d8cd..c7b62bcf8bded 100644 --- a/src/lib/es2019.intl.d.ts +++ b/src/lib/es2019.intl.d.ts @@ -1,5 +1,5 @@ declare namespace Intl { interface DateTimeFormatPartTypesRegistry { - unknown: any + unknown: any; } } diff --git a/src/lib/es2019.object.d.ts b/src/lib/es2019.object.d.ts index e3518b7b9d689..ed8e9777f01e2 100644 --- a/src/lib/es2019.object.d.ts +++ b/src/lib/es2019.object.d.ts @@ -5,7 +5,7 @@ interface ObjectConstructor { * Returns an object created by key-value entries for properties and methods * @param entries An iterable object that contains key-value entries for properties and methods. */ - fromEntries(entries: Iterable): { [k: string]: T }; + fromEntries(entries: Iterable): { [k: string]: T; }; /** * Returns an object created by key-value entries for properties and methods diff --git a/src/lib/es2020.bigint.d.ts b/src/lib/es2020.bigint.d.ts index e13da87bc71c7..2851cb7994329 100644 --- a/src/lib/es2020.bigint.d.ts +++ b/src/lib/es2020.bigint.d.ts @@ -45,27 +45,132 @@ interface BigIntToLocaleStringOptions { /** * The minimum number of integer digits to use. Possible values are from 1 to 21; the default is 1. */ - minimumIntegerDigits?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21; + minimumIntegerDigits?: + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21; /** * The minimum number of fraction digits to use. Possible values are from 0 to 20; the default for plain number and percent formatting is 0; the default for currency formatting is the number of minor unit digits provided by the {@link http://www.currency-iso.org/en/home/tables/table-a1.html ISO 4217 currency codes list} (2 if the list doesn't provide that information). */ - minimumFractionDigits?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; + minimumFractionDigits?: + | 0 + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20; /** * The maximum number of fraction digits to use. Possible values are from 0 to 20; the default for plain number formatting is the larger of minimumFractionDigits and 3; the default for currency formatting is the larger of minimumFractionDigits and the number of minor unit digits provided by the {@link http://www.currency-iso.org/en/home/tables/table-a1.html ISO 4217 currency codes list} (2 if the list doesn't provide that information); the default for percent formatting is the larger of minimumFractionDigits and 0. */ - maximumFractionDigits?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20; + maximumFractionDigits?: + | 0 + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20; /** * The minimum number of significant digits to use. Possible values are from 1 to 21; the default is 1. */ - minimumSignificantDigits?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21; + minimumSignificantDigits?: + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21; /** * The maximum number of significant digits to use. Possible values are from 1 to 21; the default is 21. */ - maximumSignificantDigits?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21; + maximumSignificantDigits?: + | 1 + | 2 + | 3 + | 4 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 18 + | 19 + | 20 + | 21; /** * The formatting that should be displayed for the number, the defaults is "standard" @@ -271,7 +376,9 @@ interface BigInt64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint): bigint; + reduce( + callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint, + ): bigint; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -283,7 +390,10 @@ interface BigInt64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -295,7 +405,9 @@ interface BigInt64Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint): bigint; + reduceRight( + callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigInt64Array) => bigint, + ): bigint; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -307,7 +419,10 @@ interface BigInt64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigInt64Array) => U, + initialValue: U, + ): U; /** Reverses the elements in the array. */ reverse(): this; @@ -371,9 +486,9 @@ interface BigInt64Array { interface BigInt64ArrayConstructor { readonly prototype: BigInt64Array; - new(length?: number): BigInt64Array; - new(array: Iterable): BigInt64Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): BigInt64Array; + new (length?: number): BigInt64Array; + new (array: Iterable): BigInt64Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): BigInt64Array; /** The size in bytes of each element in the array. */ readonly BYTES_PER_ELEMENT: number; @@ -465,7 +580,10 @@ interface BigUint64Array { * @param thisArg If provided, it will be used as the this value for each invocation of * predicate. If it is not provided, undefined is used instead. */ - find(predicate: (value: bigint, index: number, array: BigUint64Array) => boolean, thisArg?: any): bigint | undefined; + find( + predicate: (value: bigint, index: number, array: BigUint64Array) => boolean, + thisArg?: any, + ): bigint | undefined; /** * Returns the index of the first element in the array where predicate is true, and -1 @@ -543,7 +661,14 @@ interface BigUint64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigUint64Array) => bigint): bigint; + reduce( + callbackfn: ( + previousValue: bigint, + currentValue: bigint, + currentIndex: number, + array: BigUint64Array, + ) => bigint, + ): bigint; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -555,7 +680,10 @@ interface BigUint64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -567,7 +695,14 @@ interface BigUint64Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: bigint, currentValue: bigint, currentIndex: number, array: BigUint64Array) => bigint): bigint; + reduceRight( + callbackfn: ( + previousValue: bigint, + currentValue: bigint, + currentIndex: number, + array: BigUint64Array, + ) => bigint, + ): bigint; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -579,7 +714,10 @@ interface BigUint64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: bigint, currentIndex: number, array: BigUint64Array) => U, + initialValue: U, + ): U; /** Reverses the elements in the array. */ reverse(): this; @@ -643,9 +781,9 @@ interface BigUint64Array { interface BigUint64ArrayConstructor { readonly prototype: BigUint64Array; - new(length?: number): BigUint64Array; - new(array: Iterable): BigUint64Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): BigUint64Array; + new (length?: number): BigUint64Array; + new (array: Iterable): BigUint64Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): BigUint64Array; /** The size in bytes of each element in the array. */ readonly BYTES_PER_ELEMENT: number; @@ -702,7 +840,7 @@ interface DataView { setBigUint64(byteOffset: number, value: bigint, littleEndian?: boolean): void; } -declare namespace Intl{ +declare namespace Intl { interface NumberFormat { format(value: number | bigint): string; resolvedOptions(): ResolvedNumberFormatOptions; diff --git a/src/lib/es2020.date.d.ts b/src/lib/es2020.date.d.ts index 07af7065f7391..f85966ec7f9ae 100644 --- a/src/lib/es2020.date.d.ts +++ b/src/lib/es2020.date.d.ts @@ -21,4 +21,4 @@ interface Date { * @param options An object that contains one or more properties that specify comparison options. */ toLocaleTimeString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string; -} \ No newline at end of file +} diff --git a/src/lib/es2020.intl.d.ts b/src/lib/es2020.intl.d.ts index 37486e296307d..a82f062b61781 100644 --- a/src/lib/es2020.intl.d.ts +++ b/src/lib/es2020.intl.d.ts @@ -1,6 +1,5 @@ /// declare namespace Intl { - /** * [Unicode BCP 47 Locale Identifiers](https://unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers) definition. * @@ -40,7 +39,7 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/formatToParts#Using_formatToParts). */ - type RelativeTimeFormatUnitSingular = + type RelativeTimeFormatUnitSingular = | "year" | "quarter" | "month" @@ -83,7 +82,11 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locales_argument). */ - type LocalesArgument = UnicodeBCP47LocaleIdentifier | Locale | readonly (UnicodeBCP47LocaleIdentifier | Locale)[] | undefined; + type LocalesArgument = + | UnicodeBCP47LocaleIdentifier + | Locale + | readonly (UnicodeBCP47LocaleIdentifier | Locale)[] + | undefined; /** * An object with some or all of properties of `options` parameter @@ -122,14 +125,14 @@ declare namespace Intl { */ type RelativeTimeFormatPart = | { - type: "literal"; - value: string; - } + type: "literal"; + value: string; + } | { - type: Exclude; - value: string; - unit: RelativeTimeFormatUnitSingular; - }; + type: Exclude; + value: string; + unit: RelativeTimeFormatUnitSingular; + }; interface RelativeTimeFormat { /** @@ -200,7 +203,7 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat). */ - new( + new ( locales?: UnicodeBCP47LocaleIdentifier | UnicodeBCP47LocaleIdentifier[], options?: RelativeTimeFormatOptions, ): RelativeTimeFormat; @@ -392,7 +395,7 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/DisplayNames). */ - new(locales: LocalesArgument, options: DisplayNamesOptions): DisplayNames; + new (locales: LocalesArgument, options: DisplayNamesOptions): DisplayNames; /** * Returns an array containing those of the provided locales that are supported in display names without having to fall back to the runtime's default locale. @@ -407,7 +410,9 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames/supportedLocalesOf). */ - supportedLocalesOf(locales?: LocalesArgument, options?: { localeMatcher?: RelativeTimeFormatLocaleMatcher }): BCP47LanguageTag[]; + supportedLocalesOf( + locales?: LocalesArgument, + options?: { localeMatcher?: RelativeTimeFormatLocaleMatcher; }, + ): BCP47LanguageTag[]; }; - } diff --git a/src/lib/es2020.promise.d.ts b/src/lib/es2020.promise.d.ts index a1b408ff8f6a9..47018b45db8e1 100644 --- a/src/lib/es2020.promise.d.ts +++ b/src/lib/es2020.promise.d.ts @@ -17,7 +17,9 @@ interface PromiseConstructor { * @param values An array of Promises. * @returns A new Promise. */ - allSettled(values: T): Promise<{ -readonly [P in keyof T]: PromiseSettledResult> }>; + allSettled( + values: T, + ): Promise<{ -readonly [P in keyof T]: PromiseSettledResult>; }>; /** * Creates a Promise that is resolved with an array of results when all diff --git a/src/lib/es2020.sharedmemory.d.ts b/src/lib/es2020.sharedmemory.d.ts index e8403c18ba82b..5c0680f41f492 100644 --- a/src/lib/es2020.sharedmemory.d.ts +++ b/src/lib/es2020.sharedmemory.d.ts @@ -18,7 +18,12 @@ interface Atomics { * expected value, returning the original value. Until this atomic operation completes, any * other read or write operation against the array will block. */ - compareExchange(typedArray: BigInt64Array | BigUint64Array, index: number, expectedValue: bigint, replacementValue: bigint): bigint; + compareExchange( + typedArray: BigInt64Array | BigUint64Array, + index: number, + expectedValue: bigint, + replacementValue: bigint, + ): bigint; /** * Replaces the value at the given position in the array, returning the original value. Until diff --git a/src/lib/es2021.intl.d.ts b/src/lib/es2021.intl.d.ts index b6e3dbf156ff6..f0c4b96797862 100644 --- a/src/lib/es2021.intl.d.ts +++ b/src/lib/es2021.intl.d.ts @@ -1,8 +1,7 @@ declare namespace Intl { - interface DateTimeFormatPartTypesRegistry { - fractionalSecond: any - } + fractionalSecond: any; + } interface DateTimeFormatOptions { formatMatcher?: "basic" | "best fit" | "best fit" | undefined; @@ -13,12 +12,15 @@ declare namespace Intl { } interface DateTimeRangeFormatPart extends DateTimeFormatPart { - source: "startRange" | "endRange" | "shared" + source: "startRange" | "endRange" | "shared"; } interface DateTimeFormat { formatRange(startDate: Date | number | bigint, endDate: Date | number | bigint): string; - formatRangeToParts(startDate: Date | number | bigint, endDate: Date | number | bigint): DateTimeRangeFormatPart[]; + formatRangeToParts( + startDate: Date | number | bigint, + endDate: Date | number | bigint, + ): DateTimeRangeFormatPart[]; } interface ResolvedDateTimeFormatOptions { @@ -96,7 +98,7 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/formatToParts). */ - formatToParts(list: Iterable): { type: "element" | "literal", value: string; }[]; + formatToParts(list: Iterable): { type: "element" | "literal"; value: string; }[]; /** * Returns a new object with properties reflecting the locale and style @@ -126,7 +128,7 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat). */ - new(locales?: BCP47LanguageTag | BCP47LanguageTag[], options?: ListFormatOptions): ListFormat; + new (locales?: BCP47LanguageTag | BCP47LanguageTag[], options?: ListFormatOptions): ListFormat; /** * Returns an array containing those of the provided locales that are @@ -144,6 +146,9 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/supportedLocalesOf). */ - supportedLocalesOf(locales: BCP47LanguageTag | BCP47LanguageTag[], options?: Pick): BCP47LanguageTag[]; + supportedLocalesOf( + locales: BCP47LanguageTag | BCP47LanguageTag[], + options?: Pick, + ): BCP47LanguageTag[]; }; } diff --git a/src/lib/es2021.promise.d.ts b/src/lib/es2021.promise.d.ts index ef9fdeda98389..cb001ed63e92b 100644 --- a/src/lib/es2021.promise.d.ts +++ b/src/lib/es2021.promise.d.ts @@ -1,9 +1,9 @@ interface AggregateError extends Error { - errors: any[] + errors: any[]; } interface AggregateErrorConstructor { - new(errors: Iterable, message?: string): AggregateError; + new (errors: Iterable, message?: string): AggregateError; (errors: Iterable, message?: string): AggregateError; readonly prototype: AggregateError; } @@ -26,5 +26,5 @@ interface PromiseConstructor { * @param values An array or iterable of Promises. * @returns A new Promise. */ - any(values: Iterable>): Promise> + any(values: Iterable>): Promise>; } diff --git a/src/lib/es2021.weakref.d.ts b/src/lib/es2021.weakref.d.ts index b8aac14ae51f9..dd6f4a37056f3 100644 --- a/src/lib/es2021.weakref.d.ts +++ b/src/lib/es2021.weakref.d.ts @@ -17,7 +17,7 @@ interface WeakRefConstructor { * In es2023 the value can be either a symbol or an object, in previous versions only object is permissible. * @param target The target value for the WeakRef instance. */ - new(target: T): WeakRef; + new (target: T): WeakRef; } declare var WeakRef: WeakRefConstructor; @@ -52,7 +52,7 @@ interface FinalizationRegistryConstructor { * Creates a finalization registry with an associated cleanup callback * @param cleanupCallback The callback to call after a value in the registry has been reclaimed. */ - new(cleanupCallback: (heldValue: T) => void): FinalizationRegistry; + new (cleanupCallback: (heldValue: T) => void): FinalizationRegistry; } declare var FinalizationRegistry: FinalizationRegistryConstructor; diff --git a/src/lib/es2022.error.d.ts b/src/lib/es2022.error.d.ts index 5f9bae491f42e..c4d956136bc1f 100644 --- a/src/lib/es2022.error.d.ts +++ b/src/lib/es2022.error.d.ts @@ -45,11 +45,11 @@ interface AggregateErrorConstructor { new ( errors: Iterable, message?: string, - options?: ErrorOptions + options?: ErrorOptions, ): AggregateError; ( errors: Iterable, message?: string, - options?: ErrorOptions + options?: ErrorOptions, ): AggregateError; } diff --git a/src/lib/es2022.intl.d.ts b/src/lib/es2022.intl.d.ts index 987b621559777..57af89a100803 100644 --- a/src/lib/es2022.intl.d.ts +++ b/src/lib/es2022.intl.d.ts @@ -1,5 +1,4 @@ declare namespace Intl { - /** * An object with some or all properties of the `Intl.Segmenter` constructor `options` parameter. * @@ -72,7 +71,7 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter). */ - new(locales?: BCP47LanguageTag | BCP47LanguageTag[], options?: SegmenterOptions): Segmenter; + new (locales?: BCP47LanguageTag | BCP47LanguageTag[], options?: SegmenterOptions): Segmenter; /** * Returns an array containing those of the provided locales that are supported without having to fall back to the runtime's default locale. @@ -86,7 +85,10 @@ declare namespace Intl { * * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter/supportedLocalesOf) */ - supportedLocalesOf(locales: BCP47LanguageTag | BCP47LanguageTag[], options?: Pick): BCP47LanguageTag[]; + supportedLocalesOf( + locales: BCP47LanguageTag | BCP47LanguageTag[], + options?: Pick, + ): BCP47LanguageTag[]; }; /** @@ -96,5 +98,7 @@ declare namespace Intl { * @param key A string indicating the category of values to return. * @returns A sorted array of the supported values. */ - function supportedValuesOf(key: "calendar" | "collation" | "currency" | "numberingSystem" | "timeZone" | "unit"): string[]; + function supportedValuesOf( + key: "calendar" | "collation" | "currency" | "numberingSystem" | "timeZone" | "unit", + ): string[]; } diff --git a/src/lib/es2022.sharedmemory.d.ts b/src/lib/es2022.sharedmemory.d.ts index fe6c26d02cf79..9944ce2a97598 100644 --- a/src/lib/es2022.sharedmemory.d.ts +++ b/src/lib/es2022.sharedmemory.d.ts @@ -7,7 +7,12 @@ interface Atomics { * @param value The expected value to test. * @param [timeout] The expected value to test. */ - waitAsync(typedArray: Int32Array, index: number, value: number, timeout?: number): { async: false, value: "not-equal" | "timed-out" } | { async: true, value: Promise<"ok" | "timed-out"> }; + waitAsync( + typedArray: Int32Array, + index: number, + value: number, + timeout?: number, + ): { async: false; value: "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "timed-out">; }; /** * A non-blocking, asynchronous version of wait which is usable on the main thread. @@ -17,5 +22,10 @@ interface Atomics { * @param value The expected value to test. * @param [timeout] The expected value to test. */ - waitAsync(typedArray: BigInt64Array, index: number, value: bigint, timeout?: number): { async: false, value: "not-equal" | "timed-out" } | { async: true, value: Promise<"ok" | "timed-out"> }; + waitAsync( + typedArray: BigInt64Array, + index: number, + value: bigint, + timeout?: number, + ): { async: false; value: "not-equal" | "timed-out"; } | { async: true; value: Promise<"ok" | "timed-out">; }; } diff --git a/src/lib/es2023.array.d.ts b/src/lib/es2023.array.d.ts index a5cc73ae0f963..8ccbca44bb8c3 100644 --- a/src/lib/es2023.array.d.ts +++ b/src/lib/es2023.array.d.ts @@ -79,11 +79,11 @@ interface ReadonlyArray { */ findLast( predicate: (value: T, index: number, array: readonly T[]) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: (value: T, index: number, array: readonly T[]) => unknown, - thisArg?: any + thisArg?: any, ): T | undefined; /** @@ -97,7 +97,7 @@ interface ReadonlyArray { */ findLastIndex( predicate: (value: T, index: number, array: readonly T[]) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -159,13 +159,13 @@ interface Int8Array { predicate: ( value: number, index: number, - array: Int8Array + array: Int8Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: (value: number, index: number, array: Int8Array) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -179,7 +179,7 @@ interface Int8Array { */ findLastIndex( predicate: (value: number, index: number, array: Int8Array) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -223,13 +223,13 @@ interface Uint8Array { predicate: ( value: number, index: number, - array: Uint8Array + array: Uint8Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: (value: number, index: number, array: Uint8Array) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -243,7 +243,7 @@ interface Uint8Array { */ findLastIndex( predicate: (value: number, index: number, array: Uint8Array) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -287,17 +287,17 @@ interface Uint8ClampedArray { predicate: ( value: number, index: number, - array: Uint8ClampedArray + array: Uint8ClampedArray, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: ( value: number, index: number, - array: Uint8ClampedArray + array: Uint8ClampedArray, ) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -313,9 +313,9 @@ interface Uint8ClampedArray { predicate: ( value: number, index: number, - array: Uint8ClampedArray + array: Uint8ClampedArray, ) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -359,13 +359,13 @@ interface Int16Array { predicate: ( value: number, index: number, - array: Int16Array + array: Int16Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: (value: number, index: number, array: Int16Array) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -379,7 +379,7 @@ interface Int16Array { */ findLastIndex( predicate: (value: number, index: number, array: Int16Array) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -423,17 +423,17 @@ interface Uint16Array { predicate: ( value: number, index: number, - array: Uint16Array + array: Uint16Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: ( value: number, index: number, - array: Uint16Array + array: Uint16Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -449,9 +449,9 @@ interface Uint16Array { predicate: ( value: number, index: number, - array: Uint16Array + array: Uint16Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -495,13 +495,13 @@ interface Int32Array { predicate: ( value: number, index: number, - array: Int32Array + array: Int32Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: (value: number, index: number, array: Int32Array) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -515,7 +515,7 @@ interface Int32Array { */ findLastIndex( predicate: (value: number, index: number, array: Int32Array) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -559,17 +559,17 @@ interface Uint32Array { predicate: ( value: number, index: number, - array: Uint32Array + array: Uint32Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: ( value: number, index: number, - array: Uint32Array + array: Uint32Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -585,9 +585,9 @@ interface Uint32Array { predicate: ( value: number, index: number, - array: Uint32Array + array: Uint32Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -631,17 +631,17 @@ interface Float32Array { predicate: ( value: number, index: number, - array: Float32Array + array: Float32Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: ( value: number, index: number, - array: Float32Array + array: Float32Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -657,9 +657,9 @@ interface Float32Array { predicate: ( value: number, index: number, - array: Float32Array + array: Float32Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -703,17 +703,17 @@ interface Float64Array { predicate: ( value: number, index: number, - array: Float64Array + array: Float64Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: ( value: number, index: number, - array: Float64Array + array: Float64Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number | undefined; /** @@ -729,9 +729,9 @@ interface Float64Array { predicate: ( value: number, index: number, - array: Float64Array + array: Float64Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -775,17 +775,17 @@ interface BigInt64Array { predicate: ( value: bigint, index: number, - array: BigInt64Array + array: BigInt64Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: ( value: bigint, index: number, - array: BigInt64Array + array: BigInt64Array, ) => unknown, - thisArg?: any + thisArg?: any, ): bigint | undefined; /** @@ -801,9 +801,9 @@ interface BigInt64Array { predicate: ( value: bigint, index: number, - array: BigInt64Array + array: BigInt64Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number; /** @@ -847,17 +847,17 @@ interface BigUint64Array { predicate: ( value: bigint, index: number, - array: BigUint64Array + array: BigUint64Array, ) => value is S, - thisArg?: any + thisArg?: any, ): S | undefined; findLast( predicate: ( value: bigint, index: number, - array: BigUint64Array + array: BigUint64Array, ) => unknown, - thisArg?: any + thisArg?: any, ): bigint | undefined; /** @@ -873,9 +873,9 @@ interface BigUint64Array { predicate: ( value: bigint, index: number, - array: BigUint64Array + array: BigUint64Array, ) => unknown, - thisArg?: any + thisArg?: any, ): number; /** diff --git a/src/lib/es2023.collection.d.ts b/src/lib/es2023.collection.d.ts index 77545a0a415c3..affc6effa40d0 100644 --- a/src/lib/es2023.collection.d.ts +++ b/src/lib/es2023.collection.d.ts @@ -1,3 +1,3 @@ -interface WeakKeyTypes { - symbol: symbol; -} +interface WeakKeyTypes { + symbol: symbol; +} diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index a187e3c04a0f3..8269eb4d9ca6f 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -135,7 +135,7 @@ interface Object { } interface ObjectConstructor { - new(value?: any): Object; + new (value?: any): Object; (): any; (value: any): any; @@ -207,7 +207,10 @@ interface ObjectConstructor { * Prevents the modification of existing property attributes and values, and prevents the addition of new properties. * @param o Object on which to lock the attributes. */ - freeze(o: T): Readonly; + freeze< + T extends { [idx: string]: U | null | undefined | object; }, + U extends string | bigint | number | boolean | symbol, + >(o: T): Readonly; /** * Prevents the modification of existing property attributes and values, and prevents the addition of new properties. @@ -293,7 +296,7 @@ interface FunctionConstructor { * Creates a new function. * @param args A list of arguments the function accepts. */ - new(...args: string[]): Function; + new (...args: string[]): Function; (...args: string[]): Function; readonly prototype: Function; } @@ -308,7 +311,9 @@ type ThisParameterType = T extends (this: infer U, ...args: never) => any ? U /** * Removes the 'this' parameter from a function type. */ -type OmitThisParameter = unknown extends ThisParameterType ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T; +type OmitThisParameter = unknown extends ThisParameterType ? T + : T extends (...args: infer A) => infer R ? (...args: A) => R + : T; interface CallableFunction extends Function { /** @@ -344,7 +349,11 @@ interface CallableFunction extends Function { * @param thisArg The object to be used as the this object. * @param args Arguments to bind to the parameters of the function. */ - bind(this: (this: T, ...args: [...A, ...B]) => R, thisArg: T, ...args: A): (...args: B) => R; + bind( + this: (this: T, ...args: [...A, ...B]) => R, + thisArg: T, + ...args: A + ): (...args: B) => R; } interface NewableFunction extends Function { @@ -380,7 +389,11 @@ interface NewableFunction extends Function { * @param thisArg The object to be used as the this object. * @param args Arguments to bind to the parameters of the function. */ - bind
(this: new (...args: [...A, ...B]) => R, thisArg: any, ...args: A): new (...args: B) => R; + bind( + this: new (...args: [...A, ...B]) => R, + thisArg: any, + ...args: A + ): new (...args: B) => R; } interface IArguments { @@ -514,7 +527,7 @@ interface String { } interface StringConstructor { - new(value?: any): String; + new (value?: any): String; (value?: any): string; readonly prototype: String; fromCharCode(...codes: number[]): string; @@ -531,7 +544,7 @@ interface Boolean { } interface BooleanConstructor { - new(value?: any): Boolean; + new (value?: any): Boolean; (value?: T): boolean; readonly prototype: Boolean; } @@ -568,7 +581,7 @@ interface Number { } interface NumberConstructor { - new(value?: any): Number; + new (value?: any): Number; (value?: any): number; readonly prototype: Number; @@ -896,8 +909,8 @@ interface Date { } interface DateConstructor { - new(): Date; - new(value: number | string): Date; + new (): Date; + new (value: number | string): Date; /** * Creates a new Date. * @param year The full year designation is required for cross-century date accuracy. If year is between 0 and 99 is used, then year is assumed to be 1900 + year. @@ -908,7 +921,15 @@ interface DateConstructor { * @param seconds Must be supplied if milliseconds is supplied. A number from 0 to 59 that specifies the seconds. * @param ms A number from 0 to 999 that specifies the milliseconds. */ - new(year: number, monthIndex: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date; + new ( + year: number, + monthIndex: number, + date?: number, + hours?: number, + minutes?: number, + seconds?: number, + ms?: number, + ): Date; (): string; readonly prototype: Date; /** @@ -926,7 +947,15 @@ interface DateConstructor { * @param seconds Must be supplied if milliseconds is supplied. A number from 0 to 59 that specifies the seconds. * @param ms A number from 0 to 999 that specifies the milliseconds. */ - UTC(year: number, monthIndex: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number; + UTC( + year: number, + monthIndex: number, + date?: number, + hours?: number, + minutes?: number, + seconds?: number, + ms?: number, + ): number; /** Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC). */ now(): number; } @@ -996,49 +1025,49 @@ interface RegExp { } interface RegExpConstructor { - new(pattern: RegExp | string): RegExp; - new(pattern: string, flags?: string): RegExp; + new (pattern: RegExp | string): RegExp; + new (pattern: string, flags?: string): RegExp; (pattern: RegExp | string): RegExp; (pattern: string, flags?: string): RegExp; - readonly prototype: RegExp; + readonly "prototype": RegExp; // Non-standard extensions /** @deprecated A legacy feature for browser compatibility */ - $1: string; + "$1": string; /** @deprecated A legacy feature for browser compatibility */ - $2: string; + "$2": string; /** @deprecated A legacy feature for browser compatibility */ - $3: string; + "$3": string; /** @deprecated A legacy feature for browser compatibility */ - $4: string; + "$4": string; /** @deprecated A legacy feature for browser compatibility */ - $5: string; + "$5": string; /** @deprecated A legacy feature for browser compatibility */ - $6: string; + "$6": string; /** @deprecated A legacy feature for browser compatibility */ - $7: string; + "$7": string; /** @deprecated A legacy feature for browser compatibility */ - $8: string; + "$8": string; /** @deprecated A legacy feature for browser compatibility */ - $9: string; + "$9": string; /** @deprecated A legacy feature for browser compatibility */ - input: string; + "input": string; /** @deprecated A legacy feature for browser compatibility */ - $_: string; + "$_": string; /** @deprecated A legacy feature for browser compatibility */ - lastMatch: string; + "lastMatch": string; /** @deprecated A legacy feature for browser compatibility */ "$&": string; /** @deprecated A legacy feature for browser compatibility */ - lastParen: string; + "lastParen": string; /** @deprecated A legacy feature for browser compatibility */ "$+": string; /** @deprecated A legacy feature for browser compatibility */ - leftContext: string; + "leftContext": string; /** @deprecated A legacy feature for browser compatibility */ "$`": string; /** @deprecated A legacy feature for browser compatibility */ - rightContext: string; + "rightContext": string; /** @deprecated A legacy feature for browser compatibility */ "$'": string; } @@ -1052,7 +1081,7 @@ interface Error { } interface ErrorConstructor { - new(message?: string): Error; + new (message?: string): Error; (message?: string): Error; readonly prototype: Error; } @@ -1063,7 +1092,7 @@ interface EvalError extends Error { } interface EvalErrorConstructor extends ErrorConstructor { - new(message?: string): EvalError; + new (message?: string): EvalError; (message?: string): EvalError; readonly prototype: EvalError; } @@ -1074,7 +1103,7 @@ interface RangeError extends Error { } interface RangeErrorConstructor extends ErrorConstructor { - new(message?: string): RangeError; + new (message?: string): RangeError; (message?: string): RangeError; readonly prototype: RangeError; } @@ -1085,7 +1114,7 @@ interface ReferenceError extends Error { } interface ReferenceErrorConstructor extends ErrorConstructor { - new(message?: string): ReferenceError; + new (message?: string): ReferenceError; (message?: string): ReferenceError; readonly prototype: ReferenceError; } @@ -1096,7 +1125,7 @@ interface SyntaxError extends Error { } interface SyntaxErrorConstructor extends ErrorConstructor { - new(message?: string): SyntaxError; + new (message?: string): SyntaxError; (message?: string): SyntaxError; readonly prototype: SyntaxError; } @@ -1107,7 +1136,7 @@ interface TypeError extends Error { } interface TypeErrorConstructor extends ErrorConstructor { - new(message?: string): TypeError; + new (message?: string): TypeError; (message?: string): TypeError; readonly prototype: TypeError; } @@ -1118,7 +1147,7 @@ interface URIError extends Error { } interface URIErrorConstructor extends ErrorConstructor { - new(message?: string): URIError; + new (message?: string): URIError; (message?: string): URIError; readonly prototype: URIError; } @@ -1154,7 +1183,6 @@ interface JSON { */ declare var JSON: JSON; - ///////////////////////////// /// ECMAScript Array API (specially handled by compiler) ///////////////////////////// @@ -1213,7 +1241,10 @@ interface ReadonlyArray { * @param thisArg An object to which the this keyword can refer in the predicate function. * If thisArg is omitted, undefined is used as the this value. */ - every(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): this is readonly S[]; + every( + predicate: (value: T, index: number, array: readonly T[]) => value is S, + thisArg?: any, + ): this is readonly S[]; /** * Determines whether all the members of an array satisfy the specified test. * @param predicate A function that accepts up to three arguments. The every method calls @@ -1262,26 +1293,38 @@ interface ReadonlyArray { * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T; - reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T; + reduce( + callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, + initialValue: T, + ): T; /** * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T): T; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, initialValue: T): T; + reduceRight( + callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: readonly T[]) => T, + initialValue: T, + ): T; /** * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: readonly T[]) => U, + initialValue: U, + ): U; readonly [n: number]: T; } @@ -1459,26 +1502,35 @@ interface Array { * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; - reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; + reduceRight( + callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, + initialValue: T, + ): T; /** * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, + initialValue: U, + ): U; [n: number]: T; } interface ArrayConstructor { - new(arrayLength?: number): any[]; + new (arrayLength?: number): any[]; new (arrayLength: number): T[]; new (...items: T[]): T[]; (arrayLength?: number): any[]; @@ -1499,7 +1551,9 @@ interface TypedPropertyDescriptor { set?: (value: T) => void; } -declare type PromiseConstructorLike = new (executor: (resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => void) => PromiseLike; +declare type PromiseConstructorLike = new ( + executor: (resolve: (value: T | PromiseLike) => void, reject: (reason?: any) => void) => void, +) => PromiseLike; interface PromiseLike { /** @@ -1508,7 +1562,10 @@ interface PromiseLike { * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of which ever callback is executed. */ - then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; + then( + onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null, + ): PromiseLike; } /** @@ -1521,26 +1578,30 @@ interface Promise { * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of which ever callback is executed. */ - then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + then( + onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null, + ): Promise; /** * Attaches a callback for only the rejection of the Promise. * @param onrejected The callback to execute when the Promise is rejected. * @returns A Promise for the completion of the callback. */ - catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; + catch( + onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null, + ): Promise; } /** * Recursively unwraps the "awaited type" of a type. Non-promise "thenables" should resolve to `never`. This emulates the behavior of `await`. */ -type Awaited = - T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode - T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped - F extends ((value: infer V, ...args: infer _) => any) ? // if the argument to `then` is callable, extracts the first argument - Awaited : // recursively unwrap the value - never : // the argument to `then` was not callable - T; // non-object or non-thenable +type Awaited = T extends null | undefined ? T // special case for `null | undefined` when not in `--strictNullChecks` mode + : T extends object & { then(onfulfilled: infer F, ...args: infer _): any; } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + ? F extends ((value: infer V, ...args: infer _) => any) // if the argument to `then` is callable, extracts the first argument + ? Awaited // recursively unwrap the value + : never // the argument to `then` was not callable + : T; // non-object or non-thenable interface ArrayLike { readonly length: number; @@ -1610,7 +1671,8 @@ type Parameters any> = T extends (...args: infer P) /** * Obtain the parameters of a constructor function type in a tuple */ -type ConstructorParameters any> = T extends abstract new (...args: infer P) => any ? P : never; +type ConstructorParameters any> = T extends + abstract new (...args: infer P) => any ? P : never; /** * Obtain the return type of a function type @@ -1620,7 +1682,8 @@ type ReturnType any> = T extends (...args: any) => i /** * Obtain the return type of a constructor function type */ -type InstanceType any> = T extends abstract new (...args: any) => infer R ? R : any; +type InstanceType any> = T extends abstract new (...args: any) => infer R ? R + : any; /** * Convert string literal type to uppercase @@ -1645,7 +1708,7 @@ type Uncapitalize = intrinsic; /** * Marker for contextual 'this' type */ -interface ThisType { } +interface ThisType {} /** * Stores types to be used with WeakSet, WeakMap, WeakRef, and FinalizationRegistry @@ -1684,7 +1747,7 @@ type ArrayBufferLike = ArrayBufferTypes[keyof ArrayBufferTypes]; interface ArrayBufferConstructor { readonly prototype: ArrayBuffer; - new(byteLength: number): ArrayBuffer; + new (byteLength: number): ArrayBuffer; isView(arg: any): arg is ArrayBufferView; } declare var ArrayBuffer: ArrayBufferConstructor; @@ -1836,7 +1899,7 @@ interface DataView { interface DataViewConstructor { readonly prototype: DataView; - new(buffer: ArrayBufferLike & { BYTES_PER_ELEMENT?: never }, byteOffset?: number, byteLength?: number): DataView; + new (buffer: ArrayBufferLike & { BYTES_PER_ELEMENT?: never; }, byteOffset?: number, byteLength?: number): DataView; } declare var DataView: DataViewConstructor; @@ -1984,8 +2047,13 @@ interface Int8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -1997,7 +2065,10 @@ interface Int8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int8Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int8Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2009,8 +2080,13 @@ interface Int8Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int8Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2022,7 +2098,10 @@ interface Int8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int8Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int8Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -2089,9 +2168,9 @@ interface Int8Array { } interface Int8ArrayConstructor { readonly prototype: Int8Array; - new(length: number): Int8Array; - new(array: ArrayLike | ArrayBufferLike): Int8Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int8Array; + new (length: number): Int8Array; + new (array: ArrayLike | ArrayBufferLike): Int8Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int8Array; /** * The size in bytes of each element in the array. @@ -2117,8 +2196,6 @@ interface Int8ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => number, thisArg?: any): Int8Array; - - } declare var Int8Array: Int8ArrayConstructor; @@ -2266,8 +2343,13 @@ interface Uint8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -2279,7 +2361,10 @@ interface Uint8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2291,8 +2376,13 @@ interface Uint8Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2304,7 +2394,10 @@ interface Uint8Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -2372,9 +2465,9 @@ interface Uint8Array { interface Uint8ArrayConstructor { readonly prototype: Uint8Array; - new(length: number): Uint8Array; - new(array: ArrayLike | ArrayBufferLike): Uint8Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8Array; + new (length: number): Uint8Array; + new (array: ArrayLike | ArrayBufferLike): Uint8Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8Array; /** * The size in bytes of each element in the array. @@ -2400,7 +2493,6 @@ interface Uint8ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => number, thisArg?: any): Uint8Array; - } declare var Uint8Array: Uint8ArrayConstructor; @@ -2467,7 +2559,10 @@ interface Uint8ClampedArray { * @param thisArg An object to which the this keyword can refer in the predicate function. * If thisArg is omitted, undefined is used as the this value. */ - filter(predicate: (value: number, index: number, array: Uint8ClampedArray) => any, thisArg?: any): Uint8ClampedArray; + filter( + predicate: (value: number, index: number, array: Uint8ClampedArray) => any, + thisArg?: any, + ): Uint8ClampedArray; /** * Returns the value of the first element in the array where predicate is true, and undefined @@ -2478,7 +2573,10 @@ interface Uint8ClampedArray { * @param thisArg If provided, it will be used as the this value for each invocation of * predicate. If it is not provided, undefined is used instead. */ - find(predicate: (value: number, index: number, obj: Uint8ClampedArray) => boolean, thisArg?: any): number | undefined; + find( + predicate: (value: number, index: number, obj: Uint8ClampedArray) => boolean, + thisArg?: any, + ): number | undefined; /** * Returns the index of the first element in the array where predicate is true, and -1 @@ -2536,7 +2634,10 @@ interface Uint8ClampedArray { * @param thisArg An object to which the this keyword can refer in the callbackfn function. * If thisArg is omitted, undefined is used as the this value. */ - map(callbackfn: (value: number, index: number, array: Uint8ClampedArray) => number, thisArg?: any): Uint8ClampedArray; + map( + callbackfn: (value: number, index: number, array: Uint8ClampedArray) => number, + thisArg?: any, + ): Uint8ClampedArray; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -2548,8 +2649,23 @@ interface Uint8ClampedArray { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => number, initialValue: number): number; + reduce( + callbackfn: ( + previousValue: number, + currentValue: number, + currentIndex: number, + array: Uint8ClampedArray, + ) => number, + ): number; + reduce( + callbackfn: ( + previousValue: number, + currentValue: number, + currentIndex: number, + array: Uint8ClampedArray, + ) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -2561,7 +2677,10 @@ interface Uint8ClampedArray { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2573,8 +2692,23 @@ interface Uint8ClampedArray { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => number, initialValue: number): number; + reduceRight( + callbackfn: ( + previousValue: number, + currentValue: number, + currentIndex: number, + array: Uint8ClampedArray, + ) => number, + ): number; + reduceRight( + callbackfn: ( + previousValue: number, + currentValue: number, + currentIndex: number, + array: Uint8ClampedArray, + ) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2586,7 +2720,10 @@ interface Uint8ClampedArray { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint8ClampedArray) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -2654,9 +2791,9 @@ interface Uint8ClampedArray { interface Uint8ClampedArrayConstructor { readonly prototype: Uint8ClampedArray; - new(length: number): Uint8ClampedArray; - new(array: ArrayLike | ArrayBufferLike): Uint8ClampedArray; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8ClampedArray; + new (length: number): Uint8ClampedArray; + new (array: ArrayLike | ArrayBufferLike): Uint8ClampedArray; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint8ClampedArray; /** * The size in bytes of each element in the array. @@ -2828,8 +2965,13 @@ interface Int16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -2841,7 +2983,10 @@ interface Int16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int16Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int16Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2853,8 +2998,13 @@ interface Int16Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int16Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -2866,7 +3016,10 @@ interface Int16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int16Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int16Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -2934,9 +3087,9 @@ interface Int16Array { interface Int16ArrayConstructor { readonly prototype: Int16Array; - new(length: number): Int16Array; - new(array: ArrayLike | ArrayBufferLike): Int16Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int16Array; + new (length: number): Int16Array; + new (array: ArrayLike | ArrayBufferLike): Int16Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int16Array; /** * The size in bytes of each element in the array. @@ -2962,8 +3115,6 @@ interface Int16ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => number, thisArg?: any): Int16Array; - - } declare var Int16Array: Int16ArrayConstructor; @@ -3111,8 +3262,13 @@ interface Uint16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -3124,7 +3280,10 @@ interface Uint16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint16Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint16Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3136,8 +3295,13 @@ interface Uint16Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint16Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3149,7 +3313,10 @@ interface Uint16Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint16Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint16Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -3217,9 +3384,9 @@ interface Uint16Array { interface Uint16ArrayConstructor { readonly prototype: Uint16Array; - new(length: number): Uint16Array; - new(array: ArrayLike | ArrayBufferLike): Uint16Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint16Array; + new (length: number): Uint16Array; + new (array: ArrayLike | ArrayBufferLike): Uint16Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint16Array; /** * The size in bytes of each element in the array. @@ -3245,8 +3412,6 @@ interface Uint16ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => number, thisArg?: any): Uint16Array; - - } declare var Uint16Array: Uint16ArrayConstructor; /** @@ -3393,8 +3558,13 @@ interface Int32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -3406,7 +3576,10 @@ interface Int32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int32Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int32Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3418,8 +3591,13 @@ interface Int32Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Int32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3431,7 +3609,10 @@ interface Int32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int32Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Int32Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -3499,9 +3680,9 @@ interface Int32Array { interface Int32ArrayConstructor { readonly prototype: Int32Array; - new(length: number): Int32Array; - new(array: ArrayLike | ArrayBufferLike): Int32Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int32Array; + new (length: number): Int32Array; + new (array: ArrayLike | ArrayBufferLike): Int32Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Int32Array; /** * The size in bytes of each element in the array. @@ -3527,7 +3708,6 @@ interface Int32ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => number, thisArg?: any): Int32Array; - } declare var Int32Array: Int32ArrayConstructor; @@ -3674,8 +3854,13 @@ interface Uint32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -3687,7 +3872,10 @@ interface Uint32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint32Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint32Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3699,8 +3887,13 @@ interface Uint32Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Uint32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3712,7 +3905,10 @@ interface Uint32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint32Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Uint32Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -3780,9 +3976,9 @@ interface Uint32Array { interface Uint32ArrayConstructor { readonly prototype: Uint32Array; - new(length: number): Uint32Array; - new(array: ArrayLike | ArrayBufferLike): Uint32Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint32Array; + new (length: number): Uint32Array; + new (array: ArrayLike | ArrayBufferLike): Uint32Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Uint32Array; /** * The size in bytes of each element in the array. @@ -3808,7 +4004,6 @@ interface Uint32ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => number, thisArg?: any): Uint32Array; - } declare var Uint32Array: Uint32ArrayConstructor; @@ -3956,8 +4151,13 @@ interface Float32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -3969,7 +4169,10 @@ interface Float32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float32Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float32Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3981,8 +4184,13 @@ interface Float32Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float32Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -3994,7 +4202,10 @@ interface Float32Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float32Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float32Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -4062,9 +4273,9 @@ interface Float32Array { interface Float32ArrayConstructor { readonly prototype: Float32Array; - new(length: number): Float32Array; - new(array: ArrayLike | ArrayBufferLike): Float32Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Float32Array; + new (length: number): Float32Array; + new (array: ArrayLike | ArrayBufferLike): Float32Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Float32Array; /** * The size in bytes of each element in the array. @@ -4090,8 +4301,6 @@ interface Float32ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => number, thisArg?: any): Float32Array; - - } declare var Float32Array: Float32ArrayConstructor; @@ -4239,8 +4448,13 @@ interface Float64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number): number; - reduce(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, initialValue: number): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, + ): number; + reduce( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array. The return value of @@ -4252,7 +4466,10 @@ interface Float64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduce(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float64Array) => U, initialValue: U): U; + reduce( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float64Array) => U, + initialValue: U, + ): U; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -4264,8 +4481,13 @@ interface Float64Array { * the accumulation. The first call to the callbackfn function provides this value as an * argument instead of an array value. */ - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number): number; - reduceRight(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, initialValue: number): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, + ): number; + reduceRight( + callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: Float64Array) => number, + initialValue: number, + ): number; /** * Calls the specified callback function for all the elements in an array, in descending order. @@ -4277,7 +4499,10 @@ interface Float64Array { * the accumulation. The first call to the callbackfn function provides this value as an argument * instead of an array value. */ - reduceRight(callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float64Array) => U, initialValue: U): U; + reduceRight( + callbackfn: (previousValue: U, currentValue: number, currentIndex: number, array: Float64Array) => U, + initialValue: U, + ): U; /** * Reverses the elements in an Array. @@ -4345,9 +4570,9 @@ interface Float64Array { interface Float64ArrayConstructor { readonly prototype: Float64Array; - new(length: number): Float64Array; - new(array: ArrayLike | ArrayBufferLike): Float64Array; - new(buffer: ArrayBufferLike, byteOffset?: number, length?: number): Float64Array; + new (length: number): Float64Array; + new (array: ArrayLike | ArrayBufferLike): Float64Array; + new (buffer: ArrayBufferLike, byteOffset?: number, length?: number): Float64Array; /** * The size in bytes of each element in the array. @@ -4373,7 +4598,6 @@ interface Float64ArrayConstructor { * @param thisArg Value of 'this' used to invoke the mapfn. */ from(arrayLike: ArrayLike, mapfn: (v: T, k: number) => number, thisArg?: any): Float64Array; - } declare var Float64Array: Float64ArrayConstructor; @@ -4388,7 +4612,25 @@ declare namespace Intl { numeric?: boolean | undefined; caseFirst?: "upper" | "lower" | "false" | undefined; sensitivity?: "base" | "accent" | "case" | "variant" | undefined; - collation?: "big5han" | "compat" | "dict" | "direct" | "ducet" | "emoji" | "eor" | "gb2312" | "phonebk" | "phonetic" | "pinyin" | "reformed" | "searchjl" | "stroke" | "trad" | "unihan" | "zhuyin" | undefined; + collation?: + | "big5han" + | "compat" + | "dict" + | "direct" + | "ducet" + | "emoji" + | "eor" + | "gb2312" + | "phonebk" + | "phonetic" + | "pinyin" + | "reformed" + | "searchjl" + | "stroke" + | "trad" + | "unihan" + | "zhuyin" + | undefined; ignorePunctuation?: boolean | undefined; } @@ -4407,7 +4649,7 @@ declare namespace Intl { resolvedOptions(): ResolvedCollatorOptions; } var Collator: { - new(locales?: string | string[], options?: CollatorOptions): Collator; + new (locales?: string | string[], options?: CollatorOptions): Collator; (locales?: string | string[], options?: CollatorOptions): Collator; supportedLocalesOf(locales: string | string[], options?: CollatorOptions): string[]; }; @@ -4443,7 +4685,7 @@ declare namespace Intl { resolvedOptions(): ResolvedNumberFormatOptions; } var NumberFormat: { - new(locales?: string | string[], options?: NumberFormatOptions): NumberFormat; + new (locales?: string | string[], options?: NumberFormatOptions): NumberFormat; (locales?: string | string[], options?: NumberFormatOptions): NumberFormat; supportedLocalesOf(locales: string | string[], options?: NumberFormatOptions): string[]; readonly prototype: NumberFormat; @@ -4487,7 +4729,7 @@ declare namespace Intl { resolvedOptions(): ResolvedDateTimeFormatOptions; } var DateTimeFormat: { - new(locales?: string | string[], options?: DateTimeFormatOptions): DateTimeFormat; + new (locales?: string | string[], options?: DateTimeFormatOptions): DateTimeFormat; (locales?: string | string[], options?: DateTimeFormatOptions): DateTimeFormat; supportedLocalesOf(locales: string | string[], options?: DateTimeFormatOptions): string[]; readonly prototype: DateTimeFormat; diff --git a/src/lib/esnext.decorators.d.ts b/src/lib/esnext.decorators.d.ts index d5e6cb910daa0..38738fcf29335 100644 --- a/src/lib/esnext.decorators.d.ts +++ b/src/lib/esnext.decorators.d.ts @@ -1,10 +1,10 @@ -/// -/// - -interface SymbolConstructor { - readonly metadata: unique symbol; -} - -interface Function { - [Symbol.metadata]: DecoratorMetadata | null; -} +/// +/// + +interface SymbolConstructor { + readonly metadata: unique symbol; +} + +interface Function { + [Symbol.metadata]: DecoratorMetadata | null; +} diff --git a/src/lib/esnext.disposable.d.ts b/src/lib/esnext.disposable.d.ts index 318b7395ac28a..4d91a6e98a300 100644 --- a/src/lib/esnext.disposable.d.ts +++ b/src/lib/esnext.disposable.d.ts @@ -70,18 +70,18 @@ interface DisposableStack { * constructor() { * // stack will be disposed when exiting constructor for any reason * using stack = new DisposableStack(); - * + * * // get first resource * this.#res1 = stack.use(getResource1()); - * + * * // get second resource. If this fails, both `stack` and `#res1` will be disposed. * this.#res2 = stack.use(getResource2()); - * + * * // all operations succeeded, move resources out of `stack` so that they aren't disposed * // when constructor exits * this.#disposables = stack.move(); * } - * + * * [Symbol.dispose]() { * this.#disposables.dispose(); * } @@ -94,7 +94,7 @@ interface DisposableStack { } interface DisposableStackConstructor { - new(): DisposableStack; + new (): DisposableStack; readonly prototype: DisposableStack; } declare var DisposableStack: DisposableStackConstructor; @@ -137,18 +137,18 @@ interface AsyncDisposableStack { * constructor() { * // stack will be disposed when exiting constructor for any reason * using stack = new DisposableStack(); - * + * * // get first resource * this.#res1 = stack.use(getResource1()); - * + * * // get second resource. If this fails, both `stack` and `#res1` will be disposed. * this.#res2 = stack.use(getResource2()); - * + * * // all operations succeeded, move resources out of `stack` so that they aren't disposed * // when constructor exits * this.#disposables = stack.move(); * } - * + * * [Symbol.dispose]() { * this.#disposables.dispose(); * } @@ -161,7 +161,7 @@ interface AsyncDisposableStack { } interface AsyncDisposableStackConstructor { - new(): AsyncDisposableStack; + new (): AsyncDisposableStack; readonly prototype: AsyncDisposableStack; } declare var AsyncDisposableStack: AsyncDisposableStackConstructor; diff --git a/src/lib/esnext.full.d.ts b/src/lib/esnext.full.d.ts index 2a8029d3a80fa..70fc982b908bc 100644 --- a/src/lib/esnext.full.d.ts +++ b/src/lib/esnext.full.d.ts @@ -2,4 +2,4 @@ /// /// /// -/// \ No newline at end of file +/// diff --git a/src/lib/esnext.intl.d.ts b/src/lib/esnext.intl.d.ts index 3c5a0bd4df9a3..b6d59cfa0d9fc 100644 --- a/src/lib/esnext.intl.d.ts +++ b/src/lib/esnext.intl.d.ts @@ -1,10 +1,10 @@ declare namespace Intl { - interface NumberRangeFormatPart extends NumberFormatPart { - source: "startRange" | "endRange" | "shared" - } + interface NumberRangeFormatPart extends NumberFormatPart { + source: "startRange" | "endRange" | "shared"; + } - interface NumberFormat { - formatRange(start: number | bigint, end: number | bigint): string; - formatRangeToParts(start: number | bigint, end: number | bigint): NumberRangeFormatPart[]; - } + interface NumberFormat { + formatRange(start: number | bigint, end: number | bigint): string; + formatRangeToParts(start: number | bigint, end: number | bigint): NumberRangeFormatPart[]; + } } diff --git a/src/lib/scripthost.d.ts b/src/lib/scripthost.d.ts index c3ac4a7e6560f..704399103b3b5 100644 --- a/src/lib/scripthost.d.ts +++ b/src/lib/scripthost.d.ts @@ -1,10 +1,7 @@ - - ///////////////////////////// /// Windows Script Host APIS ///////////////////////////// - interface ActiveXObject { new (s: string): any; } @@ -244,7 +241,7 @@ interface Enumerator { interface EnumeratorConstructor { new (safearray: SafeArray): Enumerator; - new (collection: { Item(index: any): T }): Enumerator; + new (collection: { Item(index: any): T; }): Enumerator; new (collection: any): Enumerator; } diff --git a/src/lib/webworker.importscripts.d.ts b/src/lib/webworker.importscripts.d.ts index 1c4c4f4e953da..8144ff3387a46 100644 --- a/src/lib/webworker.importscripts.d.ts +++ b/src/lib/webworker.importscripts.d.ts @@ -1,4 +1,3 @@ - ///////////////////////////// /// WorkerGlobalScope APIs ///////////////////////////// diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 354198918b5e8..92f5aa396a569 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -216,12 +216,12 @@ export interface LargeFileReferencedEvent { export interface ConfigFileDiagEvent { eventName: typeof ConfigFileDiagEvent; - data: { triggerFile: string, configFileName: string, diagnostics: readonly Diagnostic[] }; + data: { triggerFile: string; configFileName: string; diagnostics: readonly Diagnostic[]; }; } export interface ProjectLanguageServiceStateEvent { eventName: typeof ProjectLanguageServiceStateEvent; - data: { project: Project, languageServiceEnabled: boolean }; + data: { project: Project; languageServiceEnabled: boolean; }; } /** This will be converted to the payload of a protocol.TelemetryEvent in session.defaultEventHandler. */ @@ -320,7 +320,7 @@ export interface OpenFileInfo { } export type ProjectServiceEvent = - LargeFileReferencedEvent + | LargeFileReferencedEvent | ProjectsUpdatedInBackgroundEvent | ProjectLoadingStartEvent | ProjectLoadingFinishEvent @@ -335,10 +335,12 @@ export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void; export type PerformanceEventHandler = (event: PerformanceEvent) => void; export interface SafeList { - [name: string]: { match: RegExp, exclude?: (string | number)[][], types?: string[] }; + [name: string]: { match: RegExp; exclude?: (string | number)[][]; types?: string[]; }; } -function prepareConvertersForEnumLikeCompilerOptions(commandLineOptions: CommandLineOption[]): Map> { +function prepareConvertersForEnumLikeCompilerOptions( + commandLineOptions: CommandLineOption[], +): Map> { const map = new Map>(); for (const option of commandLineOptions) { if (typeof option.type === "object") { @@ -358,12 +360,12 @@ const watchOptionsConverters = prepareConvertersForEnumLikeCompilerOptions(optio const indentStyle = new Map(Object.entries({ none: IndentStyle.None, block: IndentStyle.Block, - smart: IndentStyle.Smart + smart: IndentStyle.Smart, })); export interface TypesMapFile { typesMap: SafeList; - simpleMap: { [libName: string]: string }; + simpleMap: { [libName: string]: string; }; } /** @@ -388,30 +390,30 @@ const defaultTypeSafeList: SafeList = { "jquery": { // jquery files can have names like "jquery-1.10.2.min.js" (or "jquery.intellisense.js") match: /jquery(-[\d.]+)?(\.intellisense)?(\.min)?\.js$/i, - types: ["jquery"] + types: ["jquery"], }, "WinJS": { // e.g. c:/temp/UWApp1/lib/winjs-4.0.1/js/base.js - match: /^(.*\/winjs-[.\d]+)\/js\/base\.js$/i, // If the winjs/base.js file is found.. - exclude: [["^", 1, "/.*"]], // ..then exclude all files under the winjs folder - types: ["winjs"] // And fetch the @types package for WinJS + match: /^(.*\/winjs-[.\d]+)\/js\/base\.js$/i, // If the winjs/base.js file is found.. + exclude: [["^", 1, "/.*"]], // ..then exclude all files under the winjs folder + types: ["winjs"], // And fetch the @types package for WinJS }, "Kendo": { // e.g. /Kendo3/wwwroot/lib/kendo/kendo.all.min.js match: /^(.*\/kendo(-ui)?)\/kendo\.all(\.min)?\.js$/i, exclude: [["^", 1, "/.*"]], - types: ["kendo-ui"] + types: ["kendo-ui"], }, "Office Nuget": { // e.g. /scripts/Office/1/excel-15.debug.js match: /^(.*\/office\/1)\/excel-\d+\.debug\.js$/i, // Office NuGet package is installed under a "1/office" folder - exclude: [["^", 1, "/.*"]], // Exclude that whole folder if the file indicated above is found in it - types: ["office"] // @types package to fetch instead + exclude: [["^", 1, "/.*"]], // Exclude that whole folder if the file indicated above is found in it + types: ["office"], // @types package to fetch instead }, "References": { match: /^(.*\/_references\.js)$/i, - exclude: [["^", 1, "$"]] - } + exclude: [["^", 1, "$"]], + }, }; export function convertFormatOptions(protocolOptions: protocol.FormatCodeSettings): FormatCodeSettings { @@ -422,7 +424,9 @@ export function convertFormatOptions(protocolOptions: protocol.FormatCodeSetting return protocolOptions as any; } -export function convertCompilerOptions(protocolOptions: protocol.ExternalProjectCompilerOptions): CompilerOptions & protocol.CompileOnSaveMixin { +export function convertCompilerOptions( + protocolOptions: protocol.ExternalProjectCompilerOptions, +): CompilerOptions & protocol.CompileOnSaveMixin { compilerOptionConverters.forEach((mappedValues, id) => { const propertyValue = protocolOptions[id]; if (isString(propertyValue)) { @@ -432,23 +436,28 @@ export function convertCompilerOptions(protocolOptions: protocol.ExternalProject return protocolOptions as any; } -export function convertWatchOptions(protocolOptions: protocol.ExternalProjectCompilerOptions, currentDirectory?: string): WatchOptionsAndErrors | undefined { +export function convertWatchOptions( + protocolOptions: protocol.ExternalProjectCompilerOptions, + currentDirectory?: string, +): WatchOptionsAndErrors | undefined { let watchOptions: WatchOptions | undefined; let errors: Diagnostic[] | undefined; optionsForWatch.forEach(option => { const propertyValue = protocolOptions[option.name]; if (propertyValue === undefined) return; const mappedValues = watchOptionsConverters.get(option.name); - (watchOptions || (watchOptions = {}))[option.name] = mappedValues ? - isString(propertyValue) ? mappedValues.get(propertyValue.toLowerCase()) : propertyValue : - convertJsonOption(option, propertyValue, currentDirectory || "", errors || (errors = [])); + (watchOptions || (watchOptions = {}))[option.name] = mappedValues + ? isString(propertyValue) ? mappedValues.get(propertyValue.toLowerCase()) : propertyValue + : convertJsonOption(option, propertyValue, currentDirectory || "", errors || (errors = [])); }); return watchOptions && { watchOptions, errors }; } -export function convertTypeAcquisition(protocolOptions: protocol.InferredProjectCompilerOptions): TypeAcquisition | undefined { +export function convertTypeAcquisition( + protocolOptions: protocol.InferredProjectCompilerOptions, +): TypeAcquisition | undefined { let result: TypeAcquisition | undefined; - typeAcquisitionDeclarations.forEach((option) => { + typeAcquisitionDeclarations.forEach(option => { const propertyValue = protocolOptions[option.name]; if (propertyValue === undefined) return; (result || (result = {}))[option.name] = propertyValue; @@ -522,7 +531,8 @@ const fileNamePropertyReader: FilePropertyReader = { } return result!; // TODO: GH#18217 }, - hasMixedContent: (fileName, extraFileExtensions) => some(extraFileExtensions, ext => ext.isMixedContent && fileExtensionIs(fileName, ext.extension)), + hasMixedContent: (fileName, extraFileExtensions) => + some(extraFileExtensions, ext => ext.isMixedContent && fileExtensionIs(fileName, ext.extension)), }; const externalFilePropertyReader: FilePropertyReader = { @@ -593,7 +603,10 @@ export interface ProjectServiceOptions { /** @internal */ incrementalVerifier?: (service: ProjectService) => void; } -interface OriginalFileInfo { fileName: NormalizedPath; path: Path; } +interface OriginalFileInfo { + fileName: NormalizedPath; + path: Path; +} interface AncestorConfigFileInfo { /** config file name */ fileName: string; @@ -604,11 +617,15 @@ interface AncestorConfigFileInfo { type OpenScriptInfoOrClosedFileInfo = ScriptInfo | OriginalFileInfo; type OpenScriptInfoOrClosedOrConfigFileInfo = OpenScriptInfoOrClosedFileInfo | AncestorConfigFileInfo; -function isOpenScriptInfo(infoOrFileNameOrConfig: OpenScriptInfoOrClosedOrConfigFileInfo): infoOrFileNameOrConfig is ScriptInfo { +function isOpenScriptInfo( + infoOrFileNameOrConfig: OpenScriptInfoOrClosedOrConfigFileInfo, +): infoOrFileNameOrConfig is ScriptInfo { return !!(infoOrFileNameOrConfig as ScriptInfo).containingProjects; } -function isAncestorConfigFileInfo(infoOrFileNameOrConfig: OpenScriptInfoOrClosedOrConfigFileInfo): infoOrFileNameOrConfig is AncestorConfigFileInfo { +function isAncestorConfigFileInfo( + infoOrFileNameOrConfig: OpenScriptInfoOrClosedOrConfigFileInfo, +): infoOrFileNameOrConfig is AncestorConfigFileInfo { return !!(infoOrFileNameOrConfig as AncestorConfigFileInfo).configFileInfo; } @@ -623,7 +640,7 @@ export enum ProjectReferenceProjectLoadKind { /** Find existing project or create one for the project reference */ FindCreate, /** Find existing project or create and load it for the project reference */ - FindCreateLoad + FindCreateLoad, } /** @internal */ @@ -639,14 +656,14 @@ export function forEachResolvedProjectReferenceProject( fileName: string | undefined, cb: (child: ConfiguredProject) => T | undefined, projectReferenceProjectLoadKind: ProjectReferenceProjectLoadKind, - reason: string + reason: string, ): T | undefined; export function forEachResolvedProjectReferenceProject( project: ConfiguredProject, fileName: string | undefined, cb: (child: ConfiguredProject) => T | undefined, projectReferenceProjectLoadKind: ProjectReferenceProjectLoadKind, - reason?: string + reason?: string, ): T | undefined { const resolvedRefs = project.getCurrentProgram()?.getResolvedProjectReferences(); if (!resolvedRefs) return undefined; @@ -669,7 +686,7 @@ export function forEachResolvedProjectReferenceProject( (ref, loadKind) => possibleDefaultRef === ref ? callback(ref, loadKind) : undefined, projectReferenceProjectLoadKind, project.projectService, - seenResolvedRefs + seenResolvedRefs, ); if (result) return result; // Cleanup seenResolvedRefs @@ -683,19 +700,19 @@ export function forEachResolvedProjectReferenceProject( (ref, loadKind) => possibleDefaultRef !== ref ? callback(ref, loadKind) : undefined, projectReferenceProjectLoadKind, project.projectService, - seenResolvedRefs + seenResolvedRefs, ); function callback(ref: ResolvedProjectReference, loadKind: ProjectReferenceProjectLoadKind) { const configFileName = toNormalizedPath(ref.sourceFile.fileName); const child = project.projectService.findConfiguredProjectByProjectName(configFileName) || ( - loadKind === ProjectReferenceProjectLoadKind.Find ? - undefined : - loadKind === ProjectReferenceProjectLoadKind.FindCreate ? - project.projectService.createConfiguredProject(configFileName) : - loadKind === ProjectReferenceProjectLoadKind.FindCreateLoad ? - project.projectService.createAndLoadConfiguredProject(configFileName, reason!) : - Debug.assertNever(loadKind) + loadKind === ProjectReferenceProjectLoadKind.Find + ? undefined + : loadKind === ProjectReferenceProjectLoadKind.FindCreate + ? project.projectService.createConfiguredProject(configFileName) + : loadKind === ProjectReferenceProjectLoadKind.FindCreateLoad + ? project.projectService.createAndLoadConfiguredProject(configFileName, reason!) + : Debug.assertNever(loadKind) ); return child && cb(child); @@ -710,7 +727,8 @@ function forEachResolvedProjectReferenceProjectWorker( projectService: ProjectService, seenResolvedRefs: Map | undefined, ): T | undefined { - const loadKind = parentOptions.disableReferencedProjectLoad ? ProjectReferenceProjectLoadKind.Find : projectReferenceProjectLoadKind; + const loadKind = parentOptions.disableReferencedProjectLoad ? ProjectReferenceProjectLoadKind.Find + : projectReferenceProjectLoadKind; return forEach(resolvedProjectReferences, ref => { if (!ref) return undefined; @@ -726,35 +744,43 @@ function forEachResolvedProjectReferenceProjectWorker( } (seenResolvedRefs || (seenResolvedRefs = new Map())).set(canonicalPath, loadKind); - return ref.references && forEachResolvedProjectReferenceProjectWorker(ref.references, ref.commandLine.options, cb, loadKind, projectService, seenResolvedRefs); + return ref.references + && forEachResolvedProjectReferenceProjectWorker( + ref.references, + ref.commandLine.options, + cb, + loadKind, + projectService, + seenResolvedRefs, + ); }); } function forEachPotentialProjectReference( project: ConfiguredProject, - cb: (potentialProjectReference: NormalizedPath) => T | undefined + cb: (potentialProjectReference: NormalizedPath) => T | undefined, ): T | undefined { - return project.potentialProjectReferences && - forEachKey(project.potentialProjectReferences, cb); + return project.potentialProjectReferences + && forEachKey(project.potentialProjectReferences, cb); } function forEachAnyProjectReferenceKind( project: ConfiguredProject, cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, cbProjectRef: (projectReference: ProjectReference) => T | undefined, - cbPotentialProjectRef: (potentialProjectReference: NormalizedPath) => T | undefined + cbPotentialProjectRef: (potentialProjectReference: NormalizedPath) => T | undefined, ): T | undefined { - return project.getCurrentProgram() ? - project.forEachResolvedProjectReference(cb) : - project.isInitialLoadPending() ? - forEachPotentialProjectReference(project, cbPotentialProjectRef) : - forEach(project.getProjectReferences(), cbProjectRef); + return project.getCurrentProgram() + ? project.forEachResolvedProjectReference(cb) + : project.isInitialLoadPending() + ? forEachPotentialProjectReference(project, cbPotentialProjectRef) + : forEach(project.getProjectReferences(), cbProjectRef); } function callbackRefProject( project: ConfiguredProject, cb: (refProj: ConfiguredProject) => T | undefined, - refPath: P | undefined + refPath: P | undefined, ) { const refProject = refPath && project.projectService.configuredProjects.get(refPath); return refProject && cb(refProject); @@ -762,13 +788,13 @@ function callbackRefProject( function forEachReferencedProject( project: ConfiguredProject, - cb: (refProj: ConfiguredProject) => T | undefined + cb: (refProj: ConfiguredProject) => T | undefined, ): T | undefined { return forEachAnyProjectReferenceKind( project, resolvedRef => callbackRefProject(project, cb, resolvedRef.sourceFile.path), projectRef => callbackRefProject(project, cb, project.toPath(resolveProjectReferencePath(projectRef))), - potentialProjectRef => callbackRefProject(project, cb, potentialProjectRef) + potentialProjectRef => callbackRefProject(project, cb, potentialProjectRef), ); } @@ -780,7 +806,9 @@ interface NodeModulesWatcher extends FileWatcher { } function getDetailWatchInfo(watchType: WatchType, project: Project | NormalizedPath | undefined) { - return `${isString(project) ? `Config: ${project} ` : project ? `Project: ${project.getProjectName()} ` : ""}WatchType: ${watchType}`; + return `${ + isString(project) ? `Config: ${project} ` : project ? `Project: ${project.getProjectName()} ` : "" + }WatchType: ${watchType}`; } function isScriptInfoWatchedFromNodeModules(info: ScriptInfo) { @@ -793,8 +821,8 @@ function isScriptInfoWatchedFromNodeModules(info: ScriptInfo) { * @internal */ export function projectContainsInfoDirectly(project: Project, info: ScriptInfo) { - return project.containsScriptInfo(info) && - !project.isSourceOfProjectReferenceRedirect(info.path); + return project.containsScriptInfo(info) + && !project.isSourceOfProjectReferenceRedirect(info.path); } /** @internal */ @@ -830,7 +858,7 @@ export interface WatchOptionsAndErrors { } /** @internal */ -export interface ParsedConfig{ +export interface ParsedConfig { cachedDirectoryStructureHost: CachedDirectoryStructureHost; /** * The map contains @@ -853,7 +881,6 @@ function createProjectNameFactoryWithCounter(nameFactory: (counter: number) => s } export class ProjectService { - /** @internal */ readonly typingsCache: TypingsCache; @@ -933,7 +960,6 @@ export class ProjectService { * - Or it is present if we have configured project open with config file at that location * In this case the exists property is always true * - * * @internal */ readonly configFileExistenceInfoCache = new Map(); @@ -977,7 +1003,10 @@ export class ProjectService { readonly watchFactory: WatchFactory; /** @internal */ - private readonly sharedExtendedConfigFileWatchers = new Map>(); + private readonly sharedExtendedConfigFileWatchers = new Map< + Path, + SharedExtendedConfigFileWatcher + >(); /** @internal */ private readonly extendedConfigCache = new Map(); @@ -1010,7 +1039,8 @@ export class ProjectService { this.globalPlugins = opts.globalPlugins || emptyArray; this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray; this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads; - this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(getDirectoryPath(this.getExecutingFilePath()), "typesMap.json") : opts.typesMapLocation; + this.typesMapLocation = (opts.typesMapLocation === undefined) + ? combinePaths(getDirectoryPath(this.getExecutingFilePath()), "typesMap.json") : opts.typesMapLocation; this.session = opts.session; if (opts.serverMode !== undefined) { @@ -1048,17 +1078,21 @@ export class ProjectService { extraFileExtensions: [], }; - this.documentRegistry = createDocumentRegistryInternal(this.host.useCaseSensitiveFileNames, this.currentDirectory, this); - const watchLogLevel = this.logger.hasLevel(LogLevel.verbose) ? WatchLogLevel.Verbose : - this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None; + this.documentRegistry = createDocumentRegistryInternal( + this.host.useCaseSensitiveFileNames, + this.currentDirectory, + this, + ); + const watchLogLevel = this.logger.hasLevel(LogLevel.verbose) ? WatchLogLevel.Verbose + : this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None; const log: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => this.logger.info(s)) : noop; this.packageJsonCache = createPackageJsonCache(this); - this.watchFactory = this.serverMode !== LanguageServiceMode.Semantic ? - { + this.watchFactory = this.serverMode !== LanguageServiceMode.Semantic + ? { watchFile: returnNoopFileWatcher, watchDirectory: returnNoopFileWatcher, - } : - getWatchFactory(this.host, watchLogLevel, log, getDetailWatchInfo); + } + : getWatchFactory(this.host, watchLogLevel, log, getDetailWatchInfo); opts.incrementalVerifier?.(this); } @@ -1085,7 +1119,8 @@ export class ProjectService { /** @internal */ getDocument(key: DocumentRegistryBucketKeyWithMode, path: Path): SourceFile | undefined { const info = this.getScriptInfoForPath(path); - return info && info.cacheSourceFile && info.cacheSourceFile.key === key ? info.cacheSourceFile.sourceFile : undefined; + return info && info.cacheSourceFile && info.cacheSourceFile.key === key ? info.cacheSourceFile.sourceFile + : undefined; } /** @internal */ @@ -1105,7 +1140,7 @@ export class ProjectService { } const event: ProjectLanguageServiceStateEvent = { eventName: ProjectLanguageServiceStateEvent, - data: { project, languageServiceEnabled } + data: { project, languageServiceEnabled }, }; this.eventHandler(event); } @@ -1139,8 +1174,12 @@ export class ProjectService { updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse): void; /** @internal */ - updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse | BeginInstallTypes | EndInstallTypes): void; // eslint-disable-line @typescript-eslint/unified-signatures - updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse | BeginInstallTypes | EndInstallTypes): void { + updateTypingsForProject( + response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse | BeginInstallTypes | EndInstallTypes, + ): void; // eslint-disable-line @typescript-eslint/unified-signatures + updateTypingsForProject( + response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse | BeginInstallTypes | EndInstallTypes, + ): void { const project = this.findProject(response.projectName); if (!project) { return; @@ -1148,11 +1187,23 @@ 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( + this.typingsCache.updateTypingsForProject( + response.projectName, + 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); + this.typingsCache.enqueueInstallTypingsForProject( + project, + project.lastCachedUnresolvedImportsList, + /*forceRefresh*/ true, + ); return; } } @@ -1209,8 +1260,8 @@ export class ProjectService { const event: ProjectsUpdatedInBackgroundEvent = { eventName: ProjectsUpdatedInBackgroundEvent, data: { - openFiles: arrayFrom(this.openFiles.keys(), path => this.getScriptInfoForPath(path as Path)!.fileName) - } + openFiles: arrayFrom(this.openFiles.keys(), path => this.getScriptInfoForPath(path as Path)!.fileName), + }, }; this.eventHandler(event); } @@ -1223,7 +1274,7 @@ export class ProjectService { const event: LargeFileReferencedEvent = { eventName: LargeFileReferencedEvent, - data: { file, fileSize, maxFileSize } + data: { file, fileSize, maxFileSize }, }; this.eventHandler(event); } @@ -1236,7 +1287,7 @@ export class ProjectService { project.sendLoadingProjectFinish = true; const event: ProjectLoadingStartEvent = { eventName: ProjectLoadingStartEvent, - data: { project, reason } + data: { project, reason }, }; this.eventHandler(event); } @@ -1250,7 +1301,7 @@ export class ProjectService { project.sendLoadingProjectFinish = false; const event: ProjectLoadingFinishEvent = { eventName: ProjectLoadingFinishEvent, - data: { project } + data: { project }, }; this.eventHandler(event); } @@ -1279,8 +1330,14 @@ export class ProjectService { } } - setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.InferredProjectCompilerOptions, projectRootPath?: string): void { - Debug.assert(projectRootPath === undefined || this.useInferredProjectPerProjectRoot, "Setting compiler options per project root path is only supported when useInferredProjectPerProjectRoot is enabled"); + setCompilerOptionsForInferredProjects( + projectCompilerOptions: protocol.InferredProjectCompilerOptions, + projectRootPath?: string, + ): void { + Debug.assert( + projectRootPath === undefined || this.useInferredProjectPerProjectRoot, + "Setting compiler options per project root path is only supported when useInferredProjectPerProjectRoot is enabled", + ); const compilerOptions = convertCompilerOptions(projectCompilerOptions); const watchOptions = convertWatchOptions(projectCompilerOptions, projectRootPath); @@ -1310,9 +1367,12 @@ export class ProjectService { // root path // - Inferred projects with a projectRootPath, if the new options apply to that // project root path. - if (canonicalProjectRootPath ? - project.projectRootPath === canonicalProjectRootPath : - !project.projectRootPath || !this.compilerOptionsForInferredProjectsPerProjectRoot.has(project.projectRootPath)) { + if ( + canonicalProjectRootPath + ? project.projectRootPath === canonicalProjectRootPath + : !project.projectRootPath + || !this.compilerOptionsForInferredProjectsPerProjectRoot.has(project.projectRootPath) + ) { project.setCompilerOptions(compilerOptions); project.setTypeAcquisition(typeAcquisition); project.setWatchOptions(watchOptions?.watchOptions); @@ -1333,7 +1393,8 @@ export class ProjectService { if (isInferredProjectName(projectName)) { return findProjectByName(projectName, this.inferredProjects); } - return this.findExternalProjectByProjectName(projectName) || this.findConfiguredProjectByProjectName(toNormalizedPath(projectName)); + return this.findExternalProjectByProjectName(projectName) + || this.findConfiguredProjectByProjectName(toNormalizedPath(projectName)); } /** @internal */ @@ -1358,21 +1419,27 @@ export class ProjectService { /** @internal */ tryGetDefaultProjectForFile(fileNameOrScriptInfo: NormalizedPath | ScriptInfo): Project | undefined { - const scriptInfo = isString(fileNameOrScriptInfo) ? this.getScriptInfoForNormalizedPath(fileNameOrScriptInfo) : fileNameOrScriptInfo; + const scriptInfo = isString(fileNameOrScriptInfo) ? this.getScriptInfoForNormalizedPath(fileNameOrScriptInfo) + : fileNameOrScriptInfo; return scriptInfo && !scriptInfo.isOrphan() ? scriptInfo.getDefaultProject() : undefined; } /** @internal */ ensureDefaultProjectForFile(fileNameOrScriptInfo: NormalizedPath | ScriptInfo): Project { - return this.tryGetDefaultProjectForFile(fileNameOrScriptInfo) || this.doEnsureDefaultProjectForFile(fileNameOrScriptInfo); + return this.tryGetDefaultProjectForFile(fileNameOrScriptInfo) + || this.doEnsureDefaultProjectForFile(fileNameOrScriptInfo); } private doEnsureDefaultProjectForFile(fileNameOrScriptInfo: NormalizedPath | ScriptInfo): Project { this.ensureProjectStructuresUptoDate(); - const scriptInfo = isString(fileNameOrScriptInfo) ? this.getScriptInfoForNormalizedPath(fileNameOrScriptInfo) : fileNameOrScriptInfo; - return scriptInfo ? - scriptInfo.getDefaultProject() : - (this.logErrorForScriptInfoNotFound(isString(fileNameOrScriptInfo) ? fileNameOrScriptInfo : fileNameOrScriptInfo.fileName), Errors.ThrowNoProject()); + const scriptInfo = isString(fileNameOrScriptInfo) ? this.getScriptInfoForNormalizedPath(fileNameOrScriptInfo) + : fileNameOrScriptInfo; + return scriptInfo + ? scriptInfo.getDefaultProject() + : (this.logErrorForScriptInfoNotFound( + isString(fileNameOrScriptInfo) ? fileNameOrScriptInfo : fileNameOrScriptInfo.fileName, + ), + Errors.ThrowNoProject()); } getScriptInfoEnsuringProjectsUptoDate(uncheckedFileName: string) { @@ -1495,36 +1562,49 @@ export class ProjectService { * * @internal */ - private watchWildcardDirectory(directory: Path, flags: WatchDirectoryFlags, configFileName: NormalizedPath, config: ParsedConfig) { + private watchWildcardDirectory( + directory: Path, + flags: WatchDirectoryFlags, + configFileName: NormalizedPath, + config: ParsedConfig, + ) { return this.watchFactory.watchDirectory( directory, fileOrDirectory => { const fileOrDirectoryPath = this.toPath(fileOrDirectory); - const fsResult = config.cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath); - if (getBaseFileName(fileOrDirectoryPath) === "package.json" && !isInsideNodeModules(fileOrDirectoryPath) && - (fsResult && fsResult.fileExists || !fsResult && this.host.fileExists(fileOrDirectoryPath)) + const fsResult = config.cachedDirectoryStructureHost.addOrDeleteFileOrDirectory( + fileOrDirectory, + fileOrDirectoryPath, + ); + if ( + getBaseFileName(fileOrDirectoryPath) === "package.json" && !isInsideNodeModules(fileOrDirectoryPath) + && (fsResult && fsResult.fileExists || !fsResult && this.host.fileExists(fileOrDirectoryPath)) ) { this.logger.info(`Config: ${configFileName} Detected new package.json: ${fileOrDirectory}`); this.onAddPackageJson(fileOrDirectoryPath); } const configuredProjectForConfig = this.findConfiguredProjectByProjectName(configFileName); - if (isIgnoredFileFromWildCardWatching({ - watchedDirPath: directory, - fileOrDirectory, - fileOrDirectoryPath, - configFileName, - extraFileExtensions: this.hostConfiguration.extraFileExtensions, - currentDirectory: this.currentDirectory, - options: config.parsedCommandLine!.options, - program: configuredProjectForConfig?.getCurrentProgram() || config.parsedCommandLine!.fileNames, - useCaseSensitiveFileNames: this.host.useCaseSensitiveFileNames, - writeLog: s => this.logger.info(s), - toPath: s => this.toPath(s) - })) return; + if ( + isIgnoredFileFromWildCardWatching({ + watchedDirPath: directory, + fileOrDirectory, + fileOrDirectoryPath, + configFileName, + extraFileExtensions: this.hostConfiguration.extraFileExtensions, + currentDirectory: this.currentDirectory, + options: config.parsedCommandLine!.options, + program: configuredProjectForConfig?.getCurrentProgram() || config.parsedCommandLine!.fileNames, + useCaseSensitiveFileNames: this.host.useCaseSensitiveFileNames, + writeLog: s => this.logger.info(s), + toPath: s => this.toPath(s), + }) + ) return; // Reload is pending, do the reload - if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) config.reloadLevel = ConfigFileProgramReloadLevel.Partial; + if (config.reloadLevel !== ConfigFileProgramReloadLevel.Full) { + config.reloadLevel = ConfigFileProgramReloadLevel.Partial; + } config.projects.forEach((watchWildcardDirectories, projectCanonicalPath) => { if (!watchWildcardDirectories) return; const project = this.getConfiguredProjectByCanonicalConfigFilePath(projectCanonicalPath); @@ -1532,14 +1612,19 @@ export class ProjectService { // Load root file names for configured project with the config file name // But only schedule update if project references this config file - const reloadLevel = configuredProjectForConfig === project ? ConfigFileProgramReloadLevel.Partial : ConfigFileProgramReloadLevel.None; + const reloadLevel = configuredProjectForConfig === project ? ConfigFileProgramReloadLevel.Partial + : ConfigFileProgramReloadLevel.None; if (project.pendingReload !== undefined && project.pendingReload > reloadLevel) return; // don't trigger callback on open, existing files if (this.openFiles.has(fileOrDirectoryPath)) { const info = Debug.checkDefined(this.getScriptInfoForPath(fileOrDirectoryPath)); if (info.isAttached(project)) { - const loadLevelToSet = Math.max(reloadLevel, project.openFileWatchTriggered.get(fileOrDirectoryPath) || ConfigFileProgramReloadLevel.None) as ConfigFileProgramReloadLevel; + const loadLevelToSet = Math.max( + reloadLevel, + project.openFileWatchTriggered.get(fileOrDirectoryPath) + || ConfigFileProgramReloadLevel.None, + ) as ConfigFileProgramReloadLevel; project.openFileWatchTriggered.set(fileOrDirectoryPath, loadLevelToSet); } else { @@ -1556,12 +1641,15 @@ export class ProjectService { flags, this.getWatchOptionsFromProjectWatchOptions(config.parsedCommandLine!.watchOptions), WatchType.WildcardDirectory, - configFileName + configFileName, ); } /** @internal */ - private delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalConfigFilePath: NormalizedPath, reloadReason: string) { + private delayUpdateProjectsFromParsedConfigOnConfigFileChange( + canonicalConfigFilePath: NormalizedPath, + reloadReason: string, + ) { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (!configFileExistenceInfo?.config) return false; let scheduledAnyProjectUpdate = false; @@ -1582,7 +1670,9 @@ export class ProjectService { } else { // Change in referenced project config file - project.resolutionCache.removeResolutionsFromProjectReferenceRedirects(this.toPath(canonicalConfigFilePath)); + project.resolutionCache.removeResolutionsFromProjectReferenceRedirects( + this.toPath(canonicalConfigFilePath), + ); this.delayUpdateProjectGraph(project); } }); @@ -1599,9 +1689,9 @@ export class ProjectService { configFileExistenceInfo.exists = false; // Remove the configured project for this config file - const project = configFileExistenceInfo.config?.projects.has(canonicalConfigFilePath) ? - this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath) : - undefined; + const project = configFileExistenceInfo.config?.projects.has(canonicalConfigFilePath) + ? this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath) + : undefined; if (project) this.removeProject(project); } else { @@ -1610,7 +1700,10 @@ export class ProjectService { } // Update projects watching config - this.delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalConfigFilePath, "Change in config file detected"); + this.delayUpdateProjectsFromParsedConfigOnConfigFileChange( + canonicalConfigFilePath, + "Change in config file detected", + ); // Reload the configured projects for the open files in the map as they are affected by this config file // If the configured project was deleted, we want to reload projects for all the open files including files @@ -1622,38 +1715,49 @@ export class ProjectService { configFileExistenceInfo.openFilesImpactedByConfigFile, /*clearSemanticCache*/ false, /*delayReload*/ true, - eventKind !== FileWatcherEventKind.Deleted ? - identity : // Reload open files if they are root of inferred project - returnTrue, // Reload all the open files impacted by config file - "Change in config file detected" + eventKind !== FileWatcherEventKind.Deleted + ? identity // Reload open files if they are root of inferred project + : returnTrue, // Reload all the open files impacted by config file + "Change in config file detected", ); this.delayEnsureProjectForOpenFiles(); } private removeProject(project: Project) { this.logger.info("`remove Project::"); - project.print(/*writeProjectFileNames*/ true, /*writeFileExplaination*/ true, /*writeFileVersionAndText*/ false); + project.print( + /*writeProjectFileNames*/ true, + /*writeFileExplaination*/ true, + /*writeFileVersionAndText*/ false, + ); project.close(); if (Debug.shouldAssert(AssertionLevel.Normal)) { - this.filenameToScriptInfo.forEach(info => Debug.assert( - !info.isAttached(project), - "Found script Info still attached to project", - () => `${project.projectName}: ScriptInfos still attached: ${JSON.stringify( - arrayFrom( - mapDefinedIterator( - this.filenameToScriptInfo.values(), - info => info.isAttached(project) ? - { - fileName: info.fileName, - projects: info.containingProjects.map(p => p.projectName), - hasMixedContent: info.hasMixedContent - } : undefined - ) - ), - /*replacer*/ undefined, - " " - )}`)); + this.filenameToScriptInfo.forEach(info => + Debug.assert( + !info.isAttached(project), + "Found script Info still attached to project", + () => + `${project.projectName}: ScriptInfos still attached: ${ + JSON.stringify( + arrayFrom( + mapDefinedIterator( + this.filenameToScriptInfo.values(), + info => + info.isAttached(project) + ? { + fileName: info.fileName, + projects: info.containingProjects.map(p => p.projectName), + hasMixedContent: info.hasMixedContent, + } : undefined, + ), + ), + /*replacer*/ undefined, + " ", + ) + }`, + ) + ); } // Remove the project from pending project updates this.pendingProjectUpdates.delete(project.getProjectName()); @@ -1677,21 +1781,21 @@ export class ProjectService { assignOrphanScriptInfoToInferredProject(info: ScriptInfo, projectRootPath: NormalizedPath | undefined) { Debug.assert(info.isOrphan()); - const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(info, projectRootPath) || - this.getOrCreateSingleInferredProjectIfEnabled() || - this.getOrCreateSingleInferredWithoutProjectRoot( - info.isDynamic ? - projectRootPath || this.currentDirectory : - getDirectoryPath( - isRootedDiskPath(info.fileName) ? - info.fileName : - getNormalizedAbsolutePath( + const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(info, projectRootPath) + || this.getOrCreateSingleInferredProjectIfEnabled() + || this.getOrCreateSingleInferredWithoutProjectRoot( + info.isDynamic + ? projectRootPath || this.currentDirectory + : getDirectoryPath( + isRootedDiskPath(info.fileName) + ? info.fileName + : getNormalizedAbsolutePath( info.fileName, - projectRootPath ? - this.getNormalizedAbsolutePath(projectRootPath) : - this.currentDirectory - ) - ) + projectRootPath + ? this.getNormalizedAbsolutePath(projectRootPath) + : this.currentDirectory, + ), + ), ); project.addRoot(info); @@ -1719,7 +1823,10 @@ export class ProjectService { // instead of scanning all open files const roots = inferredProject.getRootScriptInfos(); Debug.assert(roots.length === 1 || !!inferredProject.projectRootPath); - if (roots.length === 1 && forEach(roots[0].containingProjects, p => p !== roots[0].containingProjects[0] && !p.isOrphan())) { + if ( + roots.length === 1 + && forEach(roots[0].containingProjects, p => p !== roots[0].containingProjects[0] && !p.isOrphan()) + ) { inferredProject.removeFile(roots[0], /*fileExists*/ true, /*detachFromProject*/ true); } } @@ -1828,7 +1935,11 @@ export class ProjectService { } } - private configFileExists(configFileName: NormalizedPath, canonicalConfigFilePath: NormalizedPath, info: OpenScriptInfoOrClosedOrConfigFileInfo) { + private configFileExists( + configFileName: NormalizedPath, + canonicalConfigFilePath: NormalizedPath, + info: OpenScriptInfoOrClosedOrConfigFileInfo, + ) { let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (configFileExistenceInfo) { // By default the info would get impacted by presence of config file since its in the detection path @@ -1860,7 +1971,11 @@ export class ProjectService { } /** @internal */ - private createConfigFileWatcherForParsedConfig(configFileName: NormalizedPath, canonicalConfigFilePath: NormalizedPath, forProject: ConfiguredProject) { + private createConfigFileWatcherForParsedConfig( + configFileName: NormalizedPath, + canonicalConfigFilePath: NormalizedPath, + forProject: ConfiguredProject, + ) { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath)!; // When watching config file for parsed config, remove the noopFileWatcher that can be created for open files impacted by config file and watch for real if (!configFileExistenceInfo.watcher || configFileExistenceInfo.watcher === noopConfigFileWatcher) { @@ -1868,9 +1983,11 @@ export class ProjectService { configFileName, (_fileName, eventKind) => this.onConfigFileChanged(canonicalConfigFilePath, eventKind), PollingInterval.High, - this.getWatchOptionsFromProjectWatchOptions(configFileExistenceInfo?.config?.parsedCommandLine?.watchOptions), + this.getWatchOptionsFromProjectWatchOptions( + configFileExistenceInfo?.config?.parsedCommandLine?.watchOptions, + ), WatchType.ConfigFile, - forProject + forProject, ); } // Watching config file for project, update the map @@ -1882,8 +1999,8 @@ export class ProjectService { * Returns true if the configFileExistenceInfo is needed/impacted by open files that are root of inferred project */ private configFileExistenceImpactsRootOfInferredProject(configFileExistenceInfo: ConfigFileExistenceInfo) { - return configFileExistenceInfo.openFilesImpactedByConfigFile && - forEachEntry(configFileExistenceInfo.openFilesImpactedByConfigFile, identity); + return configFileExistenceInfo.openFilesImpactedByConfigFile + && forEachEntry(configFileExistenceInfo.openFilesImpactedByConfigFile, identity); } /** @internal */ @@ -1929,9 +2046,11 @@ export class ProjectService { private closeConfigFileWatcherOnReleaseOfOpenFile(configFileExistenceInfo: ConfigFileExistenceInfo) { // Close the config file watcher if there are no more open files that are root of inferred project // or if there are no projects that need to watch this config file existence info - if (configFileExistenceInfo.watcher && - !configFileExistenceInfo.config && - !this.configFileExistenceImpactsRootOfInferredProject(configFileExistenceInfo)) { + if ( + configFileExistenceInfo.watcher + && !configFileExistenceInfo.config + && !this.configFileExistenceImpactsRootOfInferredProject(configFileExistenceInfo) + ) { configFileExistenceInfo.watcher.close(); configFileExistenceInfo.watcher = undefined; } @@ -1945,7 +2064,9 @@ export class ProjectService { this.forEachConfigFileLocation(info, canonicalConfigFilePath => { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (configFileExistenceInfo) { - const infoIsRootOfInferredProject = configFileExistenceInfo.openFilesImpactedByConfigFile?.get(info.path); + const infoIsRootOfInferredProject = configFileExistenceInfo.openFilesImpactedByConfigFile?.get( + info.path, + ); // Delete the info from map, since this file is no more open configFileExistenceInfo.openFilesImpactedByConfigFile?.delete(info.path); @@ -1961,8 +2082,10 @@ export class ProjectService { // If there are no open files that are impacted by configFileExistenceInfo after closing this script info // and there is are no projects that need the config file existence or parsed config, // remove the cached existence info - if (!configFileExistenceInfo.openFilesImpactedByConfigFile?.size && - !configFileExistenceInfo.config) { + if ( + !configFileExistenceInfo.openFilesImpactedByConfigFile?.size + && !configFileExistenceInfo.config + ) { Debug.assert(!configFileExistenceInfo.watcher); this.configFileExistenceInfoCache.delete(canonicalConfigFilePath); } @@ -1989,15 +2112,16 @@ export class ProjectService { (configFileExistenceInfo.openFilesImpactedByConfigFile ||= new Map()).set(info.path, true); // If there is no configured project for this config file, add the file watcher - configFileExistenceInfo.watcher ||= canWatchDirectoryOrFile(getPathComponents(getDirectoryPath(canonicalConfigFilePath) as Path)) ? - this.watchFactory.watchFile( - configFileName, - (_filename, eventKind) => this.onConfigFileChanged(canonicalConfigFilePath, eventKind), - PollingInterval.High, - this.hostConfiguration.watchOptions, - WatchType.ConfigFileForInferredRoot - ) : - noopConfigFileWatcher; + configFileExistenceInfo.watcher ||= + canWatchDirectoryOrFile(getPathComponents(getDirectoryPath(canonicalConfigFilePath) as Path)) + ? this.watchFactory.watchFile( + configFileName, + (_filename, eventKind) => this.onConfigFileChanged(canonicalConfigFilePath, eventKind), + PollingInterval.High, + this.hostConfiguration.watchOptions, + WatchType.ConfigFileForInferredRoot, + ) + : noopConfigFileWatcher; }); } @@ -2029,7 +2153,10 @@ export class ProjectService { * The server must start searching from the directory containing * the newly opened file. */ - private forEachConfigFileLocation(info: OpenScriptInfoOrClosedOrConfigFileInfo, action: (canonicalConfigFilePath: NormalizedPath, configFileName: NormalizedPath) => boolean | void) { + private forEachConfigFileLocation( + info: OpenScriptInfoOrClosedOrConfigFileInfo, + action: (canonicalConfigFilePath: NormalizedPath, configFileName: NormalizedPath) => boolean | void, + ) { if (this.serverMode !== LanguageServiceMode.Semantic) { return undefined; } @@ -2040,7 +2167,8 @@ export class ProjectService { if (scriptInfo.isDynamic) return undefined; let searchPath = asNormalizedPath(getDirectoryPath(info.fileName)); - const isSearchPathInProjectRoot = () => containsPath(projectRootPath!, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames); + const isSearchPathInProjectRoot = () => + containsPath(projectRootPath!, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames); // If projectRootPath doesn't contain info.path, then do normal search for config file const anySearchPathOk = !projectRootPath || !isSearchPathInProjectRoot(); @@ -2048,9 +2176,16 @@ export class ProjectService { let searchInDirectory = !isAncestorConfigFileInfo(info); do { if (searchInDirectory) { - const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName); + const canonicalSearchPath = normalizedPathToPath( + searchPath, + this.currentDirectory, + this.toCanonicalFileName, + ); const tsconfigFileName = asNormalizedPath(combinePaths(searchPath, "tsconfig.json")); - let result = action(combinePaths(canonicalSearchPath, "tsconfig.json") as NormalizedPath, tsconfigFileName); + let result = action( + combinePaths(canonicalSearchPath, "tsconfig.json") as NormalizedPath, + tsconfigFileName, + ); if (result) return tsconfigFileName; const jsconfigFileName = asNormalizedPath(combinePaths(searchPath, "jsconfig.json")); @@ -2069,7 +2204,8 @@ export class ProjectService { if (parentPath === searchPath) break; searchPath = parentPath; searchInDirectory = true; - } while (anySearchPathOk || isSearchPathInProjectRoot()); + } + while (anySearchPathOk || isSearchPathInProjectRoot()); return undefined; } @@ -2078,12 +2214,12 @@ export class ProjectService { findDefaultConfiguredProject(info: ScriptInfo) { if (!info.isScriptOpen()) return undefined; const configFileName = this.getConfigFileNameForFile(info); - const project = configFileName && - this.findConfiguredProjectByProjectName(configFileName); + const project = configFileName + && this.findConfiguredProjectByProjectName(configFileName); - return project && projectContainsInfoDirectly(project, info) ? - project : - project?.getDefaultChildProjectFromProjectWithReferences(info); + return project && projectContainsInfoDirectly(project, info) + ? project + : project?.getDefaultChildProjectFromProjectWithReferences(info); } /** @@ -2103,8 +2239,11 @@ export class ProjectService { if (result !== undefined) return result || undefined; } this.logger.info(`Search path: ${getDirectoryPath(info.fileName)}`); - const configFileName = this.forEachConfigFileLocation(info, (canonicalConfigFilePath, configFileName) => - this.configFileExists(configFileName, canonicalConfigFilePath, info)); + const configFileName = this.forEachConfigFileLocation( + info, + (canonicalConfigFilePath, configFileName) => + this.configFileExists(configFileName, canonicalConfigFilePath, info), + ); if (configFileName) { this.logger.info(`For info: ${info.fileName} :: Config file name: ${configFileName}`); } @@ -2145,7 +2284,9 @@ export class ProjectService { return this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath); } - private getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath: string): ConfiguredProject | undefined { + private getConfiguredProjectByCanonicalConfigFilePath( + canonicalConfigFilePath: string, + ): ConfiguredProject | undefined { return this.configuredProjects.get(canonicalConfigFilePath); } @@ -2154,14 +2295,19 @@ export class ProjectService { } /** Get a filename if the language service exceeds the maximum allowed program size; otherwise returns undefined. */ - private getFilenameForExceededTotalSizeLimitForNonTsFiles(name: string, options: CompilerOptions | undefined, fileNames: T[], propertyReader: FilePropertyReader): string | undefined { + private getFilenameForExceededTotalSizeLimitForNonTsFiles( + name: string, + options: CompilerOptions | undefined, + fileNames: T[], + propertyReader: FilePropertyReader, + ): string | undefined { if (options && options.disableSizeLimit || !this.host.getFileSize) { return; } let availableSpace = maxProgramSizeForNonTsFiles; this.projectToSizeMap.set(name, 0); - this.projectToSizeMap.forEach(val => (availableSpace -= (val || 0))); + this.projectToSizeMap.forEach(val => (availableSpace -= val || 0)); let totalNonTsFileSize = 0; @@ -2179,7 +2325,11 @@ export class ProjectService { .map(name => ({ name, size: this.host.getFileSize!(name) })) .sort((a, b) => b.size - a.size) .slice(0, 5); - this.logger.info(`Non TS file size exceeded limit (${totalNonTsFileSize}). Largest files: ${top5LargestFiles.map(file => `${file.name}:${file.size}`).join(", ")}`); + this.logger.info( + `Non TS file size exceeded limit (${totalNonTsFileSize}). Largest files: ${ + top5LargestFiles.map(file => `${file.name}:${file.size}`).join(", ") + }`, + ); // Keep the size as zero since it's disabled return fileName; } @@ -2187,7 +2337,13 @@ export class ProjectService { this.projectToSizeMap.set(name, totalNonTsFileSize); } - private createExternalProject(projectFileName: string, files: protocol.ExternalFile[], options: protocol.ExternalProjectCompilerOptions, typeAcquisition: TypeAcquisition, excludedFiles: NormalizedPath[]) { + private createExternalProject( + projectFileName: string, + files: protocol.ExternalFile[], + options: protocol.ExternalProjectCompilerOptions, + typeAcquisition: TypeAcquisition, + excludedFiles: NormalizedPath[], + ) { const compilerOptions = convertCompilerOptions(options); const watchOptionsAndErrors = convertWatchOptions(options, getDirectoryPath(normalizeSlashes(projectFileName))); const project = new ExternalProject( @@ -2195,10 +2351,15 @@ export class ProjectService { this, this.documentRegistry, compilerOptions, - /*lastFileExceededProgramSize*/ this.getFilenameForExceededTotalSizeLimitForNonTsFiles(projectFileName, compilerOptions, files, externalFilePropertyReader), + /*lastFileExceededProgramSize*/ this.getFilenameForExceededTotalSizeLimitForNonTsFiles( + projectFileName, + compilerOptions, + files, + externalFilePropertyReader, + ), options.compileOnSave === undefined ? true : options.compileOnSave, /*projectFilePath*/ undefined, - watchOptionsAndErrors?.watchOptions + watchOptionsAndErrors?.watchOptions, ); project.setProjectErrors(watchOptionsAndErrors?.errors); project.excludedFiles = excludedFiles; @@ -2257,7 +2418,12 @@ export class ProjectService { } } - private addFilesToNonInferredProject(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader, typeAcquisition: TypeAcquisition): void { + private addFilesToNonInferredProject( + project: ConfiguredProject | ExternalProject, + files: T[], + propertyReader: FilePropertyReader, + typeAcquisition: TypeAcquisition, + ): void { this.updateNonInferredProjectFiles(project, files, propertyReader); project.setTypeAcquisition(typeAcquisition); } @@ -2278,9 +2444,13 @@ export class ProjectService { } if (!configFileExistenceInfo.config) { configFileExistenceInfo.config = { - cachedDirectoryStructureHost: createCachedDirectoryStructureHost(this.host, this.host.getCurrentDirectory(), this.host.useCaseSensitiveFileNames)!, + cachedDirectoryStructureHost: createCachedDirectoryStructureHost( + this.host, + this.host.getCurrentDirectory(), + this.host.useCaseSensitiveFileNames, + )!, projects: new Map(), - reloadLevel: ConfigFileProgramReloadLevel.Full + reloadLevel: ConfigFileProgramReloadLevel.Full, }; } @@ -2289,7 +2459,8 @@ export class ProjectService { canonicalConfigFilePath, this, this.documentRegistry, - configFileExistenceInfo.config.cachedDirectoryStructureHost); + configFileExistenceInfo.config.cachedDirectoryStructureHost, + ); this.configuredProjects.set(canonicalConfigFilePath, project); this.createConfigFileWatcherForParsedConfig(configFileName, canonicalConfigFilePath, project); return project; @@ -2323,7 +2494,9 @@ export class ProjectService { * @internal */ private loadConfiguredProject(project: ConfiguredProject, reason: string) { - tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { configFilePath: project.canonicalConfigFilePath }); + tracing?.push(tracing.Phase.Session, "loadConfiguredProject", { + configFilePath: project.canonicalConfigFilePath, + }); this.sendProjectLoadingStartEvent(project, reason); // Read updated contents from disk @@ -2332,7 +2505,7 @@ export class ProjectService { configFilename, project.canonicalConfigFilePath, this.configFileExistenceInfoCache.get(project.canonicalConfigFilePath)!, - project + project, ); const parsedCommandLine = configFileExistenceInfo.config!.parsedCommandLine!; Debug.assert(!!parsedCommandLine.fileNames); @@ -2344,17 +2517,23 @@ export class ProjectService { configHasExtendsProperty: parsedCommandLine.raw.extends !== undefined, configHasFilesProperty: parsedCommandLine.raw.files !== undefined, configHasIncludeProperty: parsedCommandLine.raw.include !== undefined, - configHasExcludeProperty: parsedCommandLine.raw.exclude !== undefined + configHasExcludeProperty: parsedCommandLine.raw.exclude !== undefined, }; } project.canConfigFileJsonReportNoInputFiles = canJsonReportNoInputFiles(parsedCommandLine.raw); project.setProjectErrors(parsedCommandLine.options.configFile!.parseDiagnostics); project.updateReferences(parsedCommandLine.projectReferences); - const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, compilerOptions, parsedCommandLine.fileNames, fileNamePropertyReader); + const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles( + project.canonicalConfigFilePath, + compilerOptions, + parsedCommandLine.fileNames, + fileNamePropertyReader, + ); if (lastFileExceededProgramSize) { project.disableLanguageService(lastFileExceededProgramSize); this.configFileExistenceInfoCache.forEach((_configFileExistenceInfo, canonicalConfigFilePath) => - this.stopWatchingWildCards(canonicalConfigFilePath, project)); + this.stopWatchingWildCards(canonicalConfigFilePath, project) + ); } else { project.setCompilerOptions(compilerOptions); @@ -2364,12 +2543,25 @@ export class ProjectService { } project.enablePluginsWithOptions(compilerOptions); const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles()); - this.updateRootAndOptionsOfNonInferredProject(project, filesToAdd, fileNamePropertyReader, compilerOptions, parsedCommandLine.typeAcquisition!, parsedCommandLine.compileOnSave, parsedCommandLine.watchOptions); + this.updateRootAndOptionsOfNonInferredProject( + project, + filesToAdd, + fileNamePropertyReader, + compilerOptions, + parsedCommandLine.typeAcquisition!, + parsedCommandLine.compileOnSave, + parsedCommandLine.watchOptions, + ); tracing?.pop(); } /** @internal */ - ensureParsedConfigUptoDate(configFilename: NormalizedPath, canonicalConfigFilePath: NormalizedPath, configFileExistenceInfo: ConfigFileExistenceInfo, forProject: ConfiguredProject): ConfigFileExistenceInfo { + ensureParsedConfigUptoDate( + configFilename: NormalizedPath, + canonicalConfigFilePath: NormalizedPath, + configFileExistenceInfo: ConfigFileExistenceInfo, + forProject: ConfiguredProject, + ): ConfigFileExistenceInfo { if (configFileExistenceInfo.config) { if (!configFileExistenceInfo.config.reloadLevel) return configFileExistenceInfo; if (configFileExistenceInfo.config.reloadLevel === ConfigFileProgramReloadLevel.Partial) { @@ -2379,12 +2571,19 @@ export class ProjectService { } // Parse the config file and ensure its cached - const cachedDirectoryStructureHost = configFileExistenceInfo.config?.cachedDirectoryStructureHost || - createCachedDirectoryStructureHost(this.host, this.host.getCurrentDirectory(), this.host.useCaseSensitiveFileNames)!; + const cachedDirectoryStructureHost = configFileExistenceInfo.config?.cachedDirectoryStructureHost + || createCachedDirectoryStructureHost( + this.host, + this.host.getCurrentDirectory(), + this.host.useCaseSensitiveFileNames, + )!; // Read updated contents from disk const configFileContent = tryReadFile(configFilename, fileName => this.host.readFile(fileName)); - const configFile = parseJsonText(configFilename, isString(configFileContent) ? configFileContent : "") as TsConfigSourceFile; + const configFile = parseJsonText( + configFilename, + isString(configFileContent) ? configFileContent : "", + ) as TsConfigSourceFile; const configFileErrors = configFile.parseDiagnostics as Diagnostic[]; if (!isString(configFileContent)) configFileErrors.push(configFileContent); const parsedCommandLine = parseJsonSourceFileConfigFileContent( @@ -2393,7 +2592,7 @@ export class ProjectService { getDirectoryPath(configFilename), /*existingOptions*/ {}, configFilename, - /*resolutionStack*/[], + /*resolutionStack*/ [], this.hostConfiguration.extraFileExtensions, this.extendedConfigCache, ); @@ -2402,12 +2601,18 @@ export class ProjectService { configFileErrors.push(...parsedCommandLine.errors); } - this.logger.info(`Config: ${configFilename} : ${JSON.stringify({ - rootNames: parsedCommandLine.fileNames, - options: parsedCommandLine.options, - watchOptions: parsedCommandLine.watchOptions, - projectReferences: parsedCommandLine.projectReferences - }, /*replacer*/ undefined, " ")}`); + this.logger.info(`Config: ${configFilename} : ${ + JSON.stringify( + { + rootNames: parsedCommandLine.fileNames, + options: parsedCommandLine.options, + watchOptions: parsedCommandLine.watchOptions, + projectReferences: parsedCommandLine.projectReferences, + }, + /*replacer*/ undefined, + " ", + ) + }`); const oldCommandLine = configFileExistenceInfo.config?.parsedCommandLine; if (!configFileExistenceInfo.config) { @@ -2420,12 +2625,14 @@ export class ProjectService { } // If watch options different than older options when setting for the first time, update the config file watcher - if (!oldCommandLine && !isJsonEqual( - // Old options - this.getWatchOptionsFromProjectWatchOptions(/*projectOptions*/ undefined), - // New options - this.getWatchOptionsFromProjectWatchOptions(parsedCommandLine.watchOptions) - )) { + if ( + !oldCommandLine && !isJsonEqual( + // Old options + this.getWatchOptionsFromProjectWatchOptions(/*projectOptions*/ undefined), + // New options + this.getWatchOptionsFromProjectWatchOptions(parsedCommandLine.watchOptions), + ) + ) { // Reset the config file watcher configFileExistenceInfo.watcher?.close(); configFileExistenceInfo.watcher = undefined; @@ -2438,30 +2645,43 @@ export class ProjectService { canonicalConfigFilePath, parsedCommandLine.options, this.sharedExtendedConfigFileWatchers, - (extendedConfigFileName, extendedConfigFilePath) => this.watchFactory.watchFile( - extendedConfigFileName, - () => { - // Update extended config cache - cleanExtendedConfigCache(this.extendedConfigCache, extendedConfigFilePath, fileName => this.toPath(fileName)); - // Update projects - let ensureProjectsForOpenFiles = false; - this.sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects.forEach(canonicalPath => { - ensureProjectsForOpenFiles = this.delayUpdateProjectsFromParsedConfigOnConfigFileChange(canonicalPath, `Change in extended config file ${extendedConfigFileName} detected`) || ensureProjectsForOpenFiles; - }); - if (ensureProjectsForOpenFiles) this.delayEnsureProjectForOpenFiles(); - }, - PollingInterval.High, - this.hostConfiguration.watchOptions, - WatchType.ExtendedConfigFile, - configFilename - ), + (extendedConfigFileName, extendedConfigFilePath) => + this.watchFactory.watchFile( + extendedConfigFileName, + () => { + // Update extended config cache + cleanExtendedConfigCache(this.extendedConfigCache, extendedConfigFilePath, fileName => + this.toPath(fileName)); + // Update projects + let ensureProjectsForOpenFiles = false; + this.sharedExtendedConfigFileWatchers.get(extendedConfigFilePath)?.projects.forEach( + canonicalPath => { + ensureProjectsForOpenFiles = this.delayUpdateProjectsFromParsedConfigOnConfigFileChange( + canonicalPath, + `Change in extended config file ${extendedConfigFileName} detected`, + ) || ensureProjectsForOpenFiles; + }, + ); + if (ensureProjectsForOpenFiles) { + this.delayEnsureProjectForOpenFiles(); + } + }, + PollingInterval.High, + this.hostConfiguration.watchOptions, + WatchType.ExtendedConfigFile, + configFilename, + ), fileName => this.toPath(fileName), ); return configFileExistenceInfo; } /** @internal */ - watchWildcards(configFileName: NormalizedPath, { exists, config }: ConfigFileExistenceInfo, forProject: ConfiguredProject) { + watchWildcards( + configFileName: NormalizedPath, + { exists, config }: ConfigFileExistenceInfo, + forProject: ConfiguredProject, + ) { config!.projects.set(forProject.canonicalConfigFilePath, true); if (exists) { if (config!.watchedDirectories && !config!.watchedDirectoriesStale) return; @@ -2484,8 +2704,10 @@ export class ProjectService { /** @internal */ stopWatchingWildCards(canonicalConfigFilePath: NormalizedPath, forProject: ConfiguredProject) { const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath)!; - if (!configFileExistenceInfo.config || - !configFileExistenceInfo.config.projects.get(forProject.canonicalConfigFilePath)) { + if ( + !configFileExistenceInfo.config + || !configFileExistenceInfo.config.projects.get(forProject.canonicalConfigFilePath) + ) { return; } @@ -2532,7 +2754,7 @@ export class ProjectService { project.currentDirectory, scriptKind, hasMixedContent, - project.directoryStructureHost + project.directoryStructureHost, )); path = scriptInfo.path; const existingValue = projectRootFilesMap.get(path); @@ -2573,7 +2795,15 @@ export class ProjectService { project.markAsDirty(); } - private updateRootAndOptionsOfNonInferredProject(project: ExternalProject | ConfiguredProject, newUncheckedFiles: T[], propertyReader: FilePropertyReader, newOptions: CompilerOptions, newTypeAcquisition: TypeAcquisition, compileOnSave: boolean | undefined, watchOptions: WatchOptions | undefined) { + private updateRootAndOptionsOfNonInferredProject( + project: ExternalProject | ConfiguredProject, + newUncheckedFiles: T[], + propertyReader: FilePropertyReader, + newOptions: CompilerOptions, + newTypeAcquisition: TypeAcquisition, + compileOnSave: boolean | undefined, + watchOptions: WatchOptions | undefined, + ) { project.setCompilerOptions(newOptions); project.setWatchOptions(watchOptions); // VS only set the CompileOnSaveEnabled option in the request if the option was changed recently @@ -2590,9 +2820,16 @@ export class ProjectService { * @internal */ reloadFileNamesOfConfiguredProject(project: ConfiguredProject) { - const fileNames = this.reloadFileNamesOfParsedConfig(project.getConfigFilePath(), this.configFileExistenceInfoCache.get(project.canonicalConfigFilePath)!.config!); + const fileNames = this.reloadFileNamesOfParsedConfig( + project.getConfigFilePath(), + this.configFileExistenceInfoCache.get(project.canonicalConfigFilePath)!.config!, + ); project.updateErrorOnNoInputFiles(fileNames); - this.updateNonInferredProjectFiles(project, fileNames.concat(project.getExternalFiles()), fileNamePropertyReader); + this.updateNonInferredProjectFiles( + project, + fileNames.concat(project.getExternalFiles()), + fileNamePropertyReader, + ); return project.updateGraph(); } @@ -2606,7 +2843,7 @@ export class ProjectService { getDirectoryPath(configFileName), config.parsedCommandLine!.options, config.cachedDirectoryStructureHost, - this.hostConfiguration.extraFileExtensions + this.hostConfiguration.extraFileExtensions, ); config.parsedCommandLine = { ...config.parsedCommandLine!, fileNames }; return fileNames; @@ -2622,7 +2859,12 @@ export class ProjectService { * * @internal */ - reloadConfiguredProject(project: ConfiguredProject, reason: string, isInitialLoad: boolean, clearSemanticCache: boolean) { + reloadConfiguredProject( + project: ConfiguredProject, + reason: string, + isInitialLoad: boolean, + clearSemanticCache: boolean, + ) { // At this point, there is no reason to not have configFile in the host const host = project.getCachedDirectoryStructureHost(); if (clearSemanticCache) this.clearSemanticCache(project); @@ -2654,16 +2896,23 @@ export class ProjectService { const diagnostics = project.getLanguageService().getCompilerOptionsDiagnostics(); diagnostics.push(...project.getAllProjectErrors()); - this.eventHandler({ - eventName: ConfigFileDiagEvent, - data: { configFileName: project.getConfigFilePath(), diagnostics, triggerFile } - } satisfies ConfigFileDiagEvent); + this.eventHandler( + { + eventName: ConfigFileDiagEvent, + data: { configFileName: project.getConfigFilePath(), diagnostics, triggerFile }, + } satisfies ConfigFileDiagEvent, + ); } - private getOrCreateInferredProjectForProjectRootPathIfEnabled(info: ScriptInfo, projectRootPath: NormalizedPath | undefined): InferredProject | undefined { - if (!this.useInferredProjectPerProjectRoot || + private getOrCreateInferredProjectForProjectRootPathIfEnabled( + info: ScriptInfo, + projectRootPath: NormalizedPath | undefined, + ): InferredProject | undefined { + if ( + !this.useInferredProjectPerProjectRoot // Its a dynamic info opened without project root - (info.isDynamic && projectRootPath === undefined)) { + || (info.isDynamic && projectRootPath === undefined) + ) { return undefined; } @@ -2685,7 +2934,14 @@ export class ProjectService { // ignore single inferred projects (handled elsewhere) if (!project.projectRootPath) continue; // ignore inferred projects that don't contain the root's path - if (!containsPath(project.projectRootPath, info.path, this.host.getCurrentDirectory(), !this.host.useCaseSensitiveFileNames)) continue; + if ( + !containsPath( + project.projectRootPath, + info.path, + this.host.getCurrentDirectory(), + !this.host.useCaseSensitiveFileNames, + ) + ) continue; // ignore inferred projects that are higher up in the project root. // TODO(rbuckton): Should we add the file as a root to these as well? if (bestMatch && bestMatch.projectRootPath!.length > project.projectRootPath.length) continue; @@ -2721,9 +2977,11 @@ export class ProjectService { const expectedCurrentDirectory = this.toCanonicalFileName(this.getNormalizedAbsolutePath(currentDirectory)); // Reuse the project with same current directory but no roots for (const inferredProject of this.inferredProjects) { - if (!inferredProject.projectRootPath && - inferredProject.isOrphan() && - inferredProject.canonicalCurrentDirectory === expectedCurrentDirectory) { + if ( + !inferredProject.projectRootPath + && inferredProject.isOrphan() + && inferredProject.canonicalCurrentDirectory === expectedCurrentDirectory + ) { return inferredProject; } } @@ -2731,8 +2989,14 @@ export class ProjectService { return this.createInferredProject(currentDirectory); } - private createInferredProject(currentDirectory: string, isSingleInferredProject?: boolean, projectRootPath?: NormalizedPath): InferredProject { - const compilerOptions = projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) || this.compilerOptionsForInferredProjects!; // TODO: GH#18217 + private createInferredProject( + currentDirectory: string, + isSingleInferredProject?: boolean, + projectRootPath?: NormalizedPath, + ): InferredProject { + const compilerOptions = + projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) + || this.compilerOptionsForInferredProjects!; // TODO: GH#18217 let watchOptionsAndErrors: WatchOptionsAndErrors | false | undefined; let typeAcquisition: TypeAcquisition | undefined; if (projectRootPath) { @@ -2746,7 +3010,15 @@ export class ProjectService { typeAcquisition = this.typeAcquisitionForInferredProjects; } watchOptionsAndErrors = watchOptionsAndErrors || undefined; - const project = new InferredProject(this, this.documentRegistry, compilerOptions, watchOptionsAndErrors?.watchOptions, projectRootPath, currentDirectory, typeAcquisition); + const project = new InferredProject( + this, + this.documentRegistry, + compilerOptions, + watchOptionsAndErrors?.watchOptions, + projectRootPath, + currentDirectory, + typeAcquisition, + ); project.setProjectErrors(watchOptionsAndErrors?.errors); if (isSingleInferredProject) { this.inferredProjects.unshift(project); @@ -2758,10 +3030,17 @@ export class ProjectService { } /** @internal */ - getOrCreateScriptInfoNotOpenedByClient(uncheckedFileName: string, currentDirectory: string, hostToQueryFileExistsOn: DirectoryStructureHost) { + getOrCreateScriptInfoNotOpenedByClient( + uncheckedFileName: string, + currentDirectory: string, + hostToQueryFileExistsOn: DirectoryStructureHost, + ) { return this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath( - toNormalizedPath(uncheckedFileName), currentDirectory, /*scriptKind*/ undefined, - /*hasMixedContent*/ undefined, hostToQueryFileExistsOn + toNormalizedPath(uncheckedFileName), + currentDirectory, + /*scriptKind*/ undefined, + /*hasMixedContent*/ undefined, + hostToQueryFileExistsOn, ); } @@ -2780,8 +3059,14 @@ export class ProjectService { /** @internal */ logErrorForScriptInfoNotFound(fileName: string): void { - const names = arrayFrom(this.filenameToScriptInfo.entries(), ([path, scriptInfo]) => ({ path, fileName: scriptInfo.fileName })); - this.logger.msg(`Could not find file ${JSON.stringify(fileName)}.\nAll files are: ${JSON.stringify(names)}`, Msg.Err); + const names = arrayFrom( + this.filenameToScriptInfo.entries(), + ([path, scriptInfo]) => ({ path, fileName: scriptInfo.fileName }), + ); + this.logger.msg( + `Could not find file ${JSON.stringify(fileName)}.\nAll files are: ${JSON.stringify(names)}`, + Msg.Err, + ); } /** @@ -2806,15 +3091,22 @@ export class ProjectService { if (toAddInfo !== info) { for (const project of toAddInfo.containingProjects) { // Add the projects only if they can use symLink targets and not already in the list - if (project.languageServiceEnabled && - !project.isOrphan() && - !project.getCompilerOptions().preserveSymlinks && - !info.isAttached(project)) { + if ( + project.languageServiceEnabled + && !project.isOrphan() + && !project.getCompilerOptions().preserveSymlinks + && !info.isAttached(project) + ) { if (!projects) { projects = createMultiMap(); projects.add(toAddInfo.path, project); } - else if (!forEachEntry(projects, (projs, path) => path === toAddInfo.path ? false : contains(projs, project))) { + else if ( + !forEachEntry( + projects, + (projs, path) => path === toAddInfo.path ? false : contains(projs, project), + ) + ) { projects.add(toAddInfo.path, project); } } @@ -2827,9 +3119,11 @@ export class ProjectService { Debug.assert(!info.fileWatcher); // do not watch files with mixed content - server doesn't know how to interpret it // do not watch files in the global cache location - if (!info.isDynamicOrHasMixedContent() && - (!this.globalCacheLocationDirectoryPath || - !startsWith(info.path, this.globalCacheLocationDirectoryPath))) { + if ( + !info.isDynamicOrHasMixedContent() + && (!this.globalCacheLocationDirectoryPath + || !startsWith(info.path, this.globalCacheLocationDirectoryPath)) + ) { const indexOfNodeModules = info.path.indexOf("/node_modules/"); if (!this.host.getModifiedTime || indexOfNodeModules === -1) { info.fileWatcher = this.watchFactory.watchFile( @@ -2837,12 +3131,14 @@ export class ProjectService { (_fileName, eventKind) => this.onSourceFileChanged(info, eventKind), PollingInterval.Medium, this.hostConfiguration.watchOptions, - WatchType.ClosedScriptInfo + WatchType.ClosedScriptInfo, ); } else { info.mTime = this.getModifiedTime(info); - info.fileWatcher = this.watchClosedScriptInfoInNodeModules(info.path.substr(0, indexOfNodeModules) as Path); + info.fileWatcher = this.watchClosedScriptInfoInNodeModules( + info.path.substr(0, indexOfNodeModules) as Path, + ); } } } @@ -2857,9 +3153,11 @@ export class ProjectService { // Clear module specifier cache for any projects whose cache was affected by // dependency package.jsons in this node_modules directory const basename = getBaseFileName(fileOrDirectoryPath); - if (result.affectedModuleSpecifierCacheProjects?.size && ( - basename === "package.json" || basename === "node_modules" - )) { + if ( + result.affectedModuleSpecifierCacheProjects?.size && ( + basename === "package.json" || basename === "node_modules" + ) + ) { result.affectedModuleSpecifierCacheProjects.forEach(projectName => { this.findProject(projectName)?.getModuleSpecifierCache()?.clear(); }); @@ -2886,7 +3184,7 @@ export class ProjectService { }, WatchDirectoryFlags.Recursive, this.hostConfiguration.watchOptions, - WatchType.NodeModules + WatchType.NodeModules, ); const result: NodeModulesWatcher = { refreshScriptInfoRefCount: 0, @@ -2957,9 +3255,23 @@ export class ProjectService { } } - private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined) { + private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath( + fileName: NormalizedPath, + currentDirectory: string, + scriptKind: ScriptKind | undefined, + hasMixedContent: boolean | undefined, + hostToQueryFileExistsOn: DirectoryStructureHost | undefined, + ) { if (isRootedDiskPath(fileName) || isDynamicFileName(fileName)) { - return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn); + return this.getOrCreateScriptInfoWorker( + fileName, + currentDirectory, + /*openedByClient*/ false, + /*fileContent*/ undefined, + scriptKind, + hasMixedContent, + hostToQueryFileExistsOn, + ); } // This is non rooted path with different current directory than project service current directory @@ -2974,28 +3286,111 @@ export class ProjectService { return undefined; } - private getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined) { - return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent); + private getOrCreateScriptInfoOpenedByClientForNormalizedPath( + fileName: NormalizedPath, + currentDirectory: string, + fileContent: string | undefined, + scriptKind: ScriptKind | undefined, + hasMixedContent: boolean | undefined, + ) { + return this.getOrCreateScriptInfoWorker( + fileName, + currentDirectory, + /*openedByClient*/ true, + fileContent, + scriptKind, + hasMixedContent, + ); } - getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }) { - return this.getOrCreateScriptInfoWorker(fileName, this.currentDirectory, openedByClient, fileContent, scriptKind, hasMixedContent, hostToQueryFileExistsOn); + getOrCreateScriptInfoForNormalizedPath( + fileName: NormalizedPath, + openedByClient: boolean, + fileContent?: string, + scriptKind?: ScriptKind, + hasMixedContent?: boolean, + hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }, + ) { + return this.getOrCreateScriptInfoWorker( + fileName, + this.currentDirectory, + openedByClient, + fileContent, + scriptKind, + hasMixedContent, + hostToQueryFileExistsOn, + ); } - private getOrCreateScriptInfoWorker(fileName: NormalizedPath, currentDirectory: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }) { - Debug.assert(fileContent === undefined || openedByClient, "ScriptInfo needs to be opened by client to be able to set its user defined content"); + private getOrCreateScriptInfoWorker( + fileName: NormalizedPath, + currentDirectory: string, + openedByClient: boolean, + fileContent?: string, + scriptKind?: ScriptKind, + hasMixedContent?: boolean, + hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }, + ) { + Debug.assert( + fileContent === undefined || openedByClient, + "ScriptInfo needs to be opened by client to be able to set its user defined content", + ); const path = normalizedPathToPath(fileName, currentDirectory, this.toCanonicalFileName); let info = this.getScriptInfoForPath(path); if (!info) { const isDynamic = isDynamicFileName(fileName); - Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`); - Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`); - Debug.assert(!isDynamic || this.currentDirectory === currentDirectory || this.useInferredProjectPerProjectRoot, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.`); + Debug.assert( + isRootedDiskPath(fileName) || isDynamic || openedByClient, + "", + () => + `${ + JSON.stringify({ + fileName, + currentDirectory, + hostCurrentDirectory: this.currentDirectory, + openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()), + }) + }\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`, + ); + Debug.assert( + !isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory + || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), + "", + () => + `${ + JSON.stringify({ + fileName, + currentDirectory, + hostCurrentDirectory: this.currentDirectory, + openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()), + }) + }\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`, + ); + Debug.assert( + !isDynamic || this.currentDirectory === currentDirectory || this.useInferredProjectPerProjectRoot, + "", + () => + `${ + JSON.stringify({ + fileName, + currentDirectory, + hostCurrentDirectory: this.currentDirectory, + openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()), + }) + }\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.`, + ); // If the file is not opened by client and the file doesnot exist on the disk, return if (!openedByClient && !isDynamic && !(hostToQueryFileExistsOn || this.host).fileExists(fileName)) { return; } - info = new ScriptInfo(this.host, fileName, scriptKind!, !!hasMixedContent, path, this.filenameToScriptInfoVersion.get(path)); // TODO: GH#18217 + info = new ScriptInfo( + this.host, + fileName, + scriptKind!, + !!hasMixedContent, + path, + this.filenameToScriptInfoVersion.get(path), + ); // TODO: GH#18217 this.filenameToScriptInfo.set(info.path, info); this.filenameToScriptInfoVersion.delete(info.path); if (!openedByClient) { @@ -3022,8 +3417,11 @@ export class ProjectService { * This gets the script info for the normalized path. If the path is not rooted disk path then the open script info with project root context is preferred */ getScriptInfoForNormalizedPath(fileName: NormalizedPath) { - return !isRootedDiskPath(fileName) && this.openFilesWithNonRootedDiskPath.get(this.toCanonicalFileName(fileName)) || - this.getScriptInfoForPath(normalizedPathToPath(fileName, this.currentDirectory, this.toCanonicalFileName)); + return !isRootedDiskPath(fileName) + && this.openFilesWithNonRootedDiskPath.get(this.toCanonicalFileName(fileName)) + || this.getScriptInfoForPath( + normalizedPathToPath(fileName, this.currentDirectory, this.toCanonicalFileName), + ); } getScriptInfoForPath(fileName: Path) { @@ -3031,9 +3429,17 @@ export class ProjectService { } /** @internal */ - getDocumentPositionMapper(project: Project, generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined { + getDocumentPositionMapper( + project: Project, + generatedFileName: string, + sourceFileName?: string, + ): DocumentPositionMapper | undefined { // Since declaration info and map file watches arent updating project's directory structure host (which can cache file structure) use host - const declarationInfo = this.getOrCreateScriptInfoNotOpenedByClient(generatedFileName, project.currentDirectory, this.host); + const declarationInfo = this.getOrCreateScriptInfoNotOpenedByClient( + generatedFileName, + project.currentDirectory, + this.host, + ); if (!declarationInfo) { if (sourceFileName) { // Project contains source file and it generates the generated file name @@ -3050,14 +3456,23 @@ export class ProjectService { if (sourceMapFileInfo) { sourceMapFileInfo.getSnapshot(); if (sourceMapFileInfo.documentPositionMapper !== undefined) { - sourceMapFileInfo.sourceInfos = this.addSourceInfoToSourceMap(sourceFileName, project, sourceMapFileInfo.sourceInfos); - return sourceMapFileInfo.documentPositionMapper ? sourceMapFileInfo.documentPositionMapper : undefined; + sourceMapFileInfo.sourceInfos = this.addSourceInfoToSourceMap( + sourceFileName, + project, + sourceMapFileInfo.sourceInfos, + ); + return sourceMapFileInfo.documentPositionMapper ? sourceMapFileInfo.documentPositionMapper + : undefined; } } declarationInfo.sourceMapFilePath = undefined; } else if (declarationInfo.sourceMapFilePath) { - declarationInfo.sourceMapFilePath.sourceInfos = this.addSourceInfoToSourceMap(sourceFileName, project, declarationInfo.sourceMapFilePath.sourceInfos); + declarationInfo.sourceMapFilePath.sourceInfos = this.addSourceInfoToSourceMap( + sourceFileName, + project, + declarationInfo.sourceMapFilePath.sourceInfos, + ); return undefined; } else if (declarationInfo.sourceMapFilePath !== undefined) { @@ -3070,7 +3485,11 @@ export class ProjectService { let mapFileNameFromDeclarationInfo: string | undefined; let readMapFile: ReadMapFile | undefined = (mapFileName, mapFileNameFromDts) => { - const mapInfo = this.getOrCreateScriptInfoNotOpenedByClient(mapFileName, project.currentDirectory, this.host); + const mapInfo = this.getOrCreateScriptInfoNotOpenedByClient( + mapFileName, + project.currentDirectory, + this.host, + ); if (!mapInfo) { mapFileNameFromDeclarationInfo = mapFileNameFromDts; return undefined; @@ -3082,27 +3501,35 @@ export class ProjectService { }; const projectName = project.projectName; const documentPositionMapper = getDocumentPositionMapper( - { getCanonicalFileName: this.toCanonicalFileName, log: s => this.logger.info(s), getSourceFileLike: f => this.getSourceFileLike(f, projectName, declarationInfo) }, + { + getCanonicalFileName: this.toCanonicalFileName, + log: s => this.logger.info(s), + getSourceFileLike: f => this.getSourceFileLike(f, projectName, declarationInfo), + }, declarationInfo.fileName, declarationInfo.textStorage.getLineInfo(), - readMapFile + readMapFile, ); readMapFile = undefined; // Remove ref to project if (sourceMapFileInfo) { declarationInfo.sourceMapFilePath = sourceMapFileInfo.path; sourceMapFileInfo.declarationInfoPath = declarationInfo.path; sourceMapFileInfo.documentPositionMapper = documentPositionMapper || false; - sourceMapFileInfo.sourceInfos = this.addSourceInfoToSourceMap(sourceFileName, project, sourceMapFileInfo.sourceInfos); + sourceMapFileInfo.sourceInfos = this.addSourceInfoToSourceMap( + sourceFileName, + project, + sourceMapFileInfo.sourceInfos, + ); } else if (mapFileNameFromDeclarationInfo) { declarationInfo.sourceMapFilePath = { watcher: this.addMissingSourceMapFile( - project.currentDirectory === this.currentDirectory ? - mapFileNameFromDeclarationInfo : - getNormalizedAbsolutePath(mapFileNameFromDeclarationInfo, project.currentDirectory), - declarationInfo.path + project.currentDirectory === this.currentDirectory + ? mapFileNameFromDeclarationInfo + : getNormalizedAbsolutePath(mapFileNameFromDeclarationInfo, project.currentDirectory), + declarationInfo.path, ), - sourceInfos: this.addSourceInfoToSourceMap(sourceFileName, project) + sourceInfos: this.addSourceInfoToSourceMap(sourceFileName, project), }; } else { @@ -3114,7 +3541,11 @@ export class ProjectService { private addSourceInfoToSourceMap(sourceFileName: string | undefined, project: Project, sourceInfos?: Set) { if (sourceFileName) { // Attach as source - const sourceInfo = this.getOrCreateScriptInfoNotOpenedByClient(sourceFileName, project.currentDirectory, project.directoryStructureHost)!; + const sourceInfo = this.getOrCreateScriptInfoNotOpenedByClient( + sourceFileName, + project.currentDirectory, + project.directoryStructureHost, + )!; (sourceInfos || (sourceInfos = new Set())).add(sourceInfo.path); } return sourceInfos; @@ -3125,7 +3556,9 @@ export class ProjectService { mapFileName, () => { const declarationInfo = this.getScriptInfoForPath(declarationInfoPath); - if (declarationInfo && declarationInfo.sourceMapFilePath && !isString(declarationInfo.sourceMapFilePath)) { + if ( + declarationInfo && declarationInfo.sourceMapFilePath && !isString(declarationInfo.sourceMapFilePath) + ) { // Update declaration and source projects this.delayUpdateProjectGraphs(declarationInfo.containingProjects, /*clearSourceMapperCache*/ true); this.delayUpdateSourceInfoProjects(declarationInfo.sourceMapFilePath.sourceInfos); @@ -3140,8 +3573,13 @@ export class ProjectService { } /** @internal */ - getSourceFileLike(fileName: string, projectNameOrProject: string | Project, declarationInfo?: ScriptInfo): SourceFileLike | undefined { - const project = (projectNameOrProject as Project).projectName ? projectNameOrProject as Project : this.findProject(projectNameOrProject as string); + getSourceFileLike( + fileName: string, + projectNameOrProject: string | Project, + declarationInfo?: ScriptInfo, + ): SourceFileLike | undefined { + const project = (projectNameOrProject as Project).projectName ? projectNameOrProject as Project + : this.findProject(projectNameOrProject as string); if (project) { const path = project.toPath(fileName); const sourceFile = project.getSourceFile(path); @@ -3149,7 +3587,11 @@ export class ProjectService { } // Need to look for other files. - const info = this.getOrCreateScriptInfoNotOpenedByClient(fileName, (project || this).currentDirectory, project ? project.directoryStructureHost : this.host); + const info = this.getOrCreateScriptInfoNotOpenedByClient( + fileName, + (project || this).currentDirectory, + project ? project.directoryStructureHost : this.host, + ); if (!info) return undefined; // Attach as source @@ -3174,7 +3616,8 @@ export class ProjectService { const lineOffset = info.positionToLineOffset(pos); return { line: lineOffset.line - 1, character: lineOffset.offset - 1 }; }, - getPositionOfLineAndCharacter: (line, character, allowEdits) => info.lineOffsetToPosition(line + 1, character + 1, allowEdits) + getPositionOfLineAndCharacter: (line, character, allowEdits) => + info.lineOffsetToPosition(line + 1, character + 1, allowEdits), }; } return info.sourceFileLike; @@ -3199,7 +3642,10 @@ export class ProjectService { this.logger.info(`Host information ${args.hostInfo}`); } if (args.formatOptions) { - this.hostConfiguration.formatCodeOptions = { ...this.hostConfiguration.formatCodeOptions, ...convertFormatOptions(args.formatOptions) }; + this.hostConfiguration.formatCodeOptions = { + ...this.hostConfiguration.formatCodeOptions, + ...convertFormatOptions(args.formatOptions), + }; this.logger.info("Format host information updated"); } if (args.preferences) { @@ -3209,12 +3655,17 @@ export class ProjectService { } = this.hostConfiguration.preferences; this.hostConfiguration.preferences = { ...this.hostConfiguration.preferences, ...args.preferences }; - if (lazyConfiguredProjectsFromExternalProject && !this.hostConfiguration.preferences.lazyConfiguredProjectsFromExternalProject) { + if ( + lazyConfiguredProjectsFromExternalProject + && !this.hostConfiguration.preferences.lazyConfiguredProjectsFromExternalProject + ) { // Load configured projects for external projects that are pending reload this.configuredProjects.forEach(project => { - if (project.hasExternalProjectRef() && - project.pendingReload === ConfigFileProgramReloadLevel.Full && - !this.pendingProjectUpdates.has(project.getProjectName())) { + if ( + project.hasExternalProjectRef() + && project.pendingReload === ConfigFileProgramReloadLevel.Full + && !this.pendingProjectUpdates.has(project.getProjectName()) + ) { project.updateGraph(); } }); @@ -3233,7 +3684,11 @@ export class ProjectService { if (args.watchOptions) { this.hostConfiguration.watchOptions = convertWatchOptions(args.watchOptions)?.watchOptions; - this.logger.info(`Host watch options changed to ${JSON.stringify(this.hostConfiguration.watchOptions)}, it will be take effect for next watches.`); + this.logger.info( + `Host watch options changed to ${ + JSON.stringify(this.hostConfiguration.watchOptions) + }, it will be take effect for next watches.`, + ); } } } @@ -3245,9 +3700,9 @@ export class ProjectService { /** @internal */ private getWatchOptionsFromProjectWatchOptions(projectOptions: WatchOptions | undefined) { - return projectOptions && this.hostConfiguration.watchOptions ? - { ...this.hostConfiguration.watchOptions, ...projectOptions } : - projectOptions || this.hostConfiguration.watchOptions; + return projectOptions && this.hostConfiguration.watchOptions + ? { ...this.hostConfiguration.watchOptions, ...projectOptions } + : projectOptions || this.hostConfiguration.watchOptions; } closeLog() { @@ -3270,7 +3725,10 @@ export class ProjectService { if (this.openFiles.has(info.path)) return; // Skip open files if (!info.fileWatcher) return; // not watched file // Handle as if file is changed or deleted - this.onSourceFileChanged(info, this.host.fileExists(info.fileName) ? FileWatcherEventKind.Changed : FileWatcherEventKind.Deleted); + this.onSourceFileChanged( + info, + this.host.fileExists(info.fileName) ? FileWatcherEventKind.Changed : FileWatcherEventKind.Deleted, + ); }); // Cancel all project updates since we will be updating them now this.pendingProjectUpdates.forEach((_project, projectName) => { @@ -3286,7 +3744,13 @@ export class ProjectService { }); // Reload Projects - this.reloadConfiguredProjectForFiles(this.openFiles as Map, /*clearSemanticCache*/ true, /*delayReload*/ false, returnTrue, "User requested reload projects"); + this.reloadConfiguredProjectForFiles( + this.openFiles as Map, + /*clearSemanticCache*/ true, + /*delayReload*/ false, + returnTrue, + "User requested reload projects", + ); this.externalProjects.forEach(project => { this.clearSemanticCache(project); project.updateGraph(); @@ -3302,7 +3766,13 @@ export class ProjectService { * If there is no existing project it just opens the configured project for the config file * reloadForInfo provides a way to filter out files to reload configured project for */ - private reloadConfiguredProjectForFiles(openFiles: Map | undefined, clearSemanticCache: boolean, delayReload: boolean, shouldReloadProjectFor: (openFileValue: T) => boolean, reason: string) { + private reloadConfiguredProjectForFiles( + openFiles: Map | undefined, + clearSemanticCache: boolean, + delayReload: boolean, + shouldReloadProjectFor: (openFileValue: T) => boolean, + reason: string, + ) { const updatedProjects = new Map(); const reloadChildProject = (child: ConfiguredProject) => { if (!updatedProjects.has(child.canonicalConfigFilePath)) { @@ -3327,7 +3797,8 @@ export class ProjectService { // otherwise we create a new one. const configFileName = this.getConfigFileNameForFile(info); if (configFileName) { - const project = this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName); + const project = this.findConfiguredProjectByProjectName(configFileName) + || this.createConfiguredProject(configFileName); if (!updatedProjects.has(project.canonicalConfigFilePath)) { updatedProjects.set(project.canonicalConfigFilePath, true); if (delayReload) { @@ -3348,7 +3819,7 @@ export class ProjectService { reloadChildProject(child); return projectContainsInfoDirectly(child, info); }, - ProjectReferenceProjectLoadKind.FindCreate + ProjectReferenceProjectLoadKind.FindCreate, ); if (referencedProject) { // Reload the project's tree that is already present @@ -3356,7 +3827,7 @@ export class ProjectService { project, /*fileName*/ undefined, reloadChildProject, - ProjectReferenceProjectLoadKind.Find + ProjectReferenceProjectLoadKind.Find, ); } } @@ -3387,10 +3858,12 @@ export class ProjectService { Debug.assert(info.containingProjects.length > 0); const firstProject = info.containingProjects[0]; - if (!firstProject.isOrphan() && - isInferredProject(firstProject) && - firstProject.isRoot(info) && - forEach(info.containingProjects, p => p !== firstProject && !p.isOrphan())) { + if ( + !firstProject.isOrphan() + && isInferredProject(firstProject) + && firstProject.isRoot(info) + && forEach(info.containingProjects, p => p !== firstProject && !p.isOrphan()) + ) { firstProject.removeFile(info, /*fileExists*/ true, /*detachFromProject*/ true); } } @@ -3429,23 +3902,40 @@ export class ProjectService { * @param filename is absolute pathname * @param fileContent is a known version of the file content that is more up to date than the one on disk */ - openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: string): OpenConfiguredProjectResult { - return this.openClientFileWithNormalizedPath(toNormalizedPath(fileName), fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath ? toNormalizedPath(projectRootPath) : undefined); + openClientFile( + fileName: string, + fileContent?: string, + scriptKind?: ScriptKind, + projectRootPath?: string, + ): OpenConfiguredProjectResult { + return this.openClientFileWithNormalizedPath( + toNormalizedPath(fileName), + fileContent, + scriptKind, + /*hasMixedContent*/ false, + projectRootPath ? toNormalizedPath(projectRootPath) : undefined, + ); } /** @internal */ - getOriginalLocationEnsuringConfiguredProject(project: Project, location: DocumentPosition): DocumentPosition | undefined { + getOriginalLocationEnsuringConfiguredProject( + project: Project, + location: DocumentPosition, + ): DocumentPosition | undefined { const isSourceOfProjectReferenceRedirect = project.isSourceOfProjectReferenceRedirect(location.fileName); - const originalLocation = isSourceOfProjectReferenceRedirect ? - location : - project.getSourceMapper().tryGetSourcePosition(location); + const originalLocation = isSourceOfProjectReferenceRedirect + ? location + : project.getSourceMapper().tryGetSourcePosition(location); if (!originalLocation) return undefined; const { fileName } = originalLocation; const scriptInfo = this.getScriptInfo(fileName); if (!scriptInfo && !this.host.fileExists(fileName)) return undefined; - const originalFileInfo: OriginalFileInfo = { fileName: toNormalizedPath(fileName), path: this.toPath(fileName) }; + const originalFileInfo: OriginalFileInfo = { + fileName: toNormalizedPath(fileName), + path: this.toPath(fileName), + }; const configFileName = this.getConfigFileNameForFile(originalFileInfo); if (!configFileName) return undefined; @@ -3466,7 +3956,12 @@ export class ProjectService { : location; } - configuredProject = this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}`); + configuredProject = this.createAndLoadConfiguredProject( + configFileName, + `Creating project for original file: ${originalFileInfo.fileName}${ + location !== originalLocation ? " for location: " + location.fileName : "" + }`, + ); } updateProjectIfDirty(configuredProject); @@ -3485,7 +3980,9 @@ export class ProjectService { return projectContainsOriginalInfo(child) ? child : undefined; }, ProjectReferenceProjectLoadKind.FindCreateLoad, - `Creating project referenced in solution ${configuredProject.projectName} to find possible configured project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}` + `Creating project referenced in solution ${configuredProject.projectName} to find possible configured project for original file: ${originalFileInfo.fileName}${ + location !== originalLocation ? " for location: " + location.fileName : "" + }`, ); if (!configuredProject) return undefined; if (configuredProject === project) return originalLocation; @@ -3526,8 +4023,20 @@ export class ProjectService { }); } - private getOrCreateOpenScriptInfo(fileName: NormalizedPath, fileContent: string | undefined, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, projectRootPath: NormalizedPath | undefined) { - const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent)!; // TODO: GH#18217 + private getOrCreateOpenScriptInfo( + fileName: NormalizedPath, + fileContent: string | undefined, + scriptKind: ScriptKind | undefined, + hasMixedContent: boolean | undefined, + projectRootPath: NormalizedPath | undefined, + ) { + const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath( + fileName, + projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, + fileContent, + scriptKind, + hasMixedContent, + )!; // TODO: GH#18217 this.openFiles.set(info.path, projectRootPath); return info; } @@ -3535,7 +4044,9 @@ export class ProjectService { private assignProjectToOpenedScriptInfo(info: ScriptInfo): AssignProjectResult { let configFileName: NormalizedPath | undefined; let configFileErrors: readonly Diagnostic[] | undefined; - let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info); + let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo( + info, + ); let retainProjects: ConfiguredProject[] | ConfiguredProject | undefined; let projectForConfigFileDiag: ConfiguredProject | undefined; let defaultConfigProjectIsCreated = false; @@ -3544,7 +4055,10 @@ export class ProjectService { if (configFileName) { project = this.findConfiguredProjectByProjectName(configFileName); if (!project) { - project = this.createLoadAndUpdateConfiguredProject(configFileName, `Creating possible configured project for ${info.fileName} to open`); + project = this.createLoadAndUpdateConfiguredProject( + configFileName, + `Creating possible configured project for ${info.fileName} to open`, + ); defaultConfigProjectIsCreated = true; } else { @@ -3583,7 +4097,7 @@ export class ProjectService { } }, ProjectReferenceProjectLoadKind.FindCreateLoad, - `Creating project referenced in solution ${project.projectName} to find possible configured project for ${info.fileName} to open` + `Creating project referenced in solution ${project.projectName} to find possible configured project for ${info.fileName} to open`, ); } @@ -3638,10 +4152,11 @@ export class ProjectService { // Create configured project till project root while (true) { // Skip if project is not composite - if (!project.isInitialLoadPending() && - ( - !project.getCompilerOptions().composite || - project.getCompilerOptions().disableSolutionSearching + if ( + !project.isInitialLoadPending() + && ( + !project.getCompilerOptions().composite + || project.getCompilerOptions().disableSolutionSearching ) ) return; @@ -3649,13 +4164,16 @@ export class ProjectService { const configFileName = this.getConfigFileNameForFile({ fileName: project.getConfigFilePath(), path: info.path, - configFileInfo: true + configFileInfo: true, }); if (!configFileName) return; // find or delay load the project - const ancestor = this.findConfiguredProjectByProjectName(configFileName) || - this.createConfiguredProjectWithDelayLoad(configFileName, `Creating project possibly referencing default composite project ${project.getProjectName()} of open file ${info.fileName}`); + const ancestor = this.findConfiguredProjectByProjectName(configFileName) + || this.createConfiguredProjectWithDelayLoad( + configFileName, + `Creating project possibly referencing default composite project ${project.getProjectName()} of open file ${info.fileName}`, + ); if (ancestor.isInitialLoadPending()) { // Set a potential project reference ancestor.setPotentialProjectReference(project.canonicalConfigFilePath); @@ -3668,7 +4186,7 @@ export class ProjectService { loadAncestorProjectTree(forProjects?: ReadonlyCollection) { forProjects = forProjects || mapDefinedEntries( this.configuredProjects, - (key, project) => !project.isInitialLoadPending() ? [key, true] : undefined + (key, project) => !project.isInitialLoadPending() ? [key, true] : undefined, ); const seenProjects = new Set(); @@ -3683,7 +4201,11 @@ export class ProjectService { } } - private ensureProjectChildren(project: ConfiguredProject, forProjects: ReadonlyCollection, seenProjects: Set) { + private ensureProjectChildren( + project: ConfiguredProject, + forProjects: ReadonlyCollection, + seenProjects: Set, + ) { if (!tryAddToSet(seenProjects, project.canonicalConfigFilePath)) return; // If this project disables child load ignore it @@ -3694,13 +4216,19 @@ export class ProjectService { for (const child of children) { if (!child) continue; - const referencedProject = forEachResolvedProjectReference(child.references, ref => forProjects.has(ref.sourceFile.path) ? ref : undefined); + const referencedProject = forEachResolvedProjectReference( + child.references, + ref => forProjects.has(ref.sourceFile.path) ? ref : undefined, + ); if (!referencedProject) continue; // Load this project, const configFileName = toNormalizedPath(child.sourceFile.fileName); - const childProject = project.projectService.findConfiguredProjectByProjectName(configFileName) || - project.projectService.createAndLoadConfiguredProject(configFileName, `Creating project referenced by : ${project.projectName} as it references project ${referencedProject.sourceFile.fileName}`); + const childProject = project.projectService.findConfiguredProjectByProjectName(configFileName) + || project.projectService.createAndLoadConfiguredProject( + configFileName, + `Creating project referenced by : ${project.projectName} as it references project ${referencedProject.sourceFile.fileName}`, + ); updateProjectIfDirty(childProject); // Ensure children for this project @@ -3708,7 +4236,9 @@ export class ProjectService { } } - private cleanupAfterOpeningFile(toRetainConfigProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined) { + private cleanupAfterOpeningFile( + toRetainConfigProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined, + ) { // This was postponed from closeOpenFile to after opening next file, // so that we can reuse the project if we need to right away this.removeOrphanConfiguredProjects(toRetainConfigProjects); @@ -3728,8 +4258,20 @@ export class ProjectService { this.removeOrphanScriptInfos(); } - openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult { - const info = this.getOrCreateOpenScriptInfo(fileName, fileContent, scriptKind, hasMixedContent, projectRootPath); + openClientFileWithNormalizedPath( + fileName: NormalizedPath, + fileContent?: string, + scriptKind?: ScriptKind, + hasMixedContent?: boolean, + projectRootPath?: NormalizedPath, + ): OpenConfiguredProjectResult { + const info = this.getOrCreateOpenScriptInfo( + fileName, + fileContent, + scriptKind, + hasMixedContent, + projectRootPath, + ); const { retainProjects, ...result } = this.assignProjectToOpenedScriptInfo(info); this.cleanupAfterOpeningFile(retainProjects); this.telemetryOnOpenFile(info); @@ -3737,7 +4279,9 @@ export class ProjectService { return result; } - private removeOrphanConfiguredProjects(toRetainConfiguredProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined) { + private removeOrphanConfiguredProjects( + toRetainConfiguredProjects: readonly ConfiguredProject[] | ConfiguredProject | undefined, + ) { const toRemoveConfiguredProjects = new Map(this.configuredProjects); const markOriginalProjectsAsUsed = (project: Project) => { if (!project.isOrphan() && project.originalConfiguredProjects) { @@ -3745,7 +4289,7 @@ export class ProjectService { (_value, configuredProjectPath) => { const project = this.getConfiguredProjectByCanonicalConfigFilePath(configuredProjectPath); return project && retainConfiguredProject(project); - } + }, ); } }; @@ -3770,7 +4314,7 @@ export class ProjectService { // If the configured project for project reference has more than zero references, keep it alive forEachReferencedProject( project, - ref => isRetained(ref) && retainConfiguredProject(project) + ref => isRetained(ref) && retainConfiguredProject(project), ); } }); @@ -3808,10 +4352,12 @@ export class ProjectService { sourceInfos = info.sourceMapFilePath.sourceInfos; } if (!sourceInfos) return; - if (!forEachKey(sourceInfos, path => { - const info = this.getScriptInfoForPath(path); - return !!info && (info.isScriptOpen() || !info.isOrphan()); - })) { + if ( + !forEachKey(sourceInfos, path => { + const info = this.getScriptInfoForPath(path); + return !!info && (info.isScriptOpen() || !info.isOrphan()); + }) + ) { return; } } @@ -3844,7 +4390,10 @@ export class ProjectService { } private telemetryOnOpenFile(scriptInfo: ScriptInfo): void { - if (this.serverMode !== LanguageServiceMode.Semantic || !this.eventHandler || !scriptInfo.isJavaScript() || !addToSeen(this.allJsFilesForOpenFileTelemetry, scriptInfo.path)) { + if ( + this.serverMode !== LanguageServiceMode.Semantic || !this.eventHandler || !scriptInfo.isJavaScript() + || !addToSeen(this.allJsFilesForOpenFileTelemetry, scriptInfo.path) + ) { return; } @@ -3878,25 +4427,39 @@ export class ProjectService { lastKnownProjectVersions: protocol.ProjectVersionInfo[], currentProjects: Iterable, includeProjectReferenceRedirectInfo: boolean | undefined, - result: ProjectFilesWithTSDiagnostics[] - ): void { + result: ProjectFilesWithTSDiagnostics[], + ): void { for (const proj of currentProjects) { const knownProject = find(lastKnownProjectVersions, p => p.projectName === proj.getProjectName()); - result.push(proj.getChangesSinceVersion(knownProject && knownProject.version, includeProjectReferenceRedirectInfo)); + result.push( + proj.getChangesSinceVersion(knownProject && knownProject.version, includeProjectReferenceRedirectInfo), + ); } } /** @internal */ - synchronizeProjectList(knownProjects: protocol.ProjectVersionInfo[], includeProjectReferenceRedirectInfo?: boolean): ProjectFilesWithTSDiagnostics[] { + synchronizeProjectList( + knownProjects: protocol.ProjectVersionInfo[], + includeProjectReferenceRedirectInfo?: boolean, + ): ProjectFilesWithTSDiagnostics[] { const files: ProjectFilesWithTSDiagnostics[] = []; this.collectChanges(knownProjects, this.externalProjects, includeProjectReferenceRedirectInfo, files); - this.collectChanges(knownProjects, this.configuredProjects.values(), includeProjectReferenceRedirectInfo, files); + this.collectChanges( + knownProjects, + this.configuredProjects.values(), + includeProjectReferenceRedirectInfo, + files, + ); this.collectChanges(knownProjects, this.inferredProjects, includeProjectReferenceRedirectInfo, files); return files; } /** @internal */ - applyChangesInOpenFiles(openFiles: Iterable | undefined, changedFiles?: Iterable, closedFiles?: string[]): void { + applyChangesInOpenFiles( + openFiles: Iterable | undefined, + changedFiles?: Iterable, + closedFiles?: string[], + ): void { let openScriptInfos: ScriptInfo[] | undefined; let assignOrphanScriptInfosToInferredProject = false; if (openFiles) { @@ -3907,7 +4470,7 @@ export class ProjectService { file.content, tryConvertScriptKindName(file.scriptKind!), file.hasMixedContent, - file.projectRootPath ? toNormalizedPath(file.projectRootPath) : undefined + file.projectRootPath ? toNormalizedPath(file.projectRootPath) : undefined, ); (openScriptInfos || (openScriptInfos = [])).push(info); } @@ -3925,14 +4488,19 @@ export class ProjectService { if (closedFiles) { for (const file of closedFiles) { // Close files, but dont assign projects to orphan open script infos, that part comes later - assignOrphanScriptInfosToInferredProject = this.closeClientFile(file, /*skipAssignOrphanScriptInfosToInferredProject*/ true) || assignOrphanScriptInfosToInferredProject; + assignOrphanScriptInfosToInferredProject = + this.closeClientFile(file, /*skipAssignOrphanScriptInfosToInferredProject*/ true) + || assignOrphanScriptInfosToInferredProject; } } // All the script infos now exist, so ok to go update projects for open files let retainProjects: readonly ConfiguredProject[] | undefined; if (openScriptInfos) { - retainProjects = flatMap(openScriptInfos, info => this.assignProjectToOpenedScriptInfo(info).retainProjects); + retainProjects = flatMap( + openScriptInfos, + info => this.assignProjectToOpenedScriptInfo(info).retainProjects, + ); } // While closing files there could be open files that needed assigning new inferred projects, do it now @@ -4058,7 +4626,9 @@ export class ProjectService { if (typeof groupNumberOrString === "number") { if (!isString(groups[groupNumberOrString])) { // Specification was wrong - exclude nothing! - this.logger.info(`Incorrect RegExp specification in safelist rule ${name} - not enough groups`); + this.logger.info( + `Incorrect RegExp specification in safelist rule ${name} - not enough groups`, + ); // * can't appear in a filename; escape it because it's feeding into a RegExp return "\\*"; } @@ -4099,7 +4669,11 @@ export class ProjectService { const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName); const typeName = this.legacySafelist.get(cleanedTypingName); if (typeName !== undefined) { - this.logger.info(`Excluded '${normalizedNames[i]}' because it matched ${cleanedTypingName} from the legacy safelist`); + this.logger.info( + `Excluded '${ + normalizedNames[i] + }' because it matched ${cleanedTypingName} from the legacy safelist`, + ); excludedFiles.push(normalizedNames[i]); // *exclude* it from the project... exclude = true; @@ -4162,7 +4736,12 @@ export class ProjectService { if (!tsConfigFiles) { const compilerOptions = convertCompilerOptions(proj.options); const watchOptionsAndErrors = convertWatchOptions(proj.options, externalProject.getCurrentDirectory()); - const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(proj.projectFileName, compilerOptions, proj.rootFiles, externalFilePropertyReader); + const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles( + proj.projectFileName, + compilerOptions, + proj.rootFiles, + externalFilePropertyReader, + ); if (lastFileExceededProgramSize) { externalProject.disableLanguageService(lastFileExceededProgramSize); } @@ -4172,7 +4751,15 @@ export class ProjectService { externalProject.setProjectErrors(watchOptionsAndErrors?.errors); // external project already exists and not config files were added - update the project and return; // The graph update here isnt postponed since any file open operation needs all updated external projects - this.updateRootAndOptionsOfNonInferredProject(externalProject, proj.rootFiles, externalFilePropertyReader, compilerOptions, proj.typeAcquisition, proj.options.compileOnSave, watchOptionsAndErrors?.watchOptions); + this.updateRootAndOptionsOfNonInferredProject( + externalProject, + proj.rootFiles, + externalFilePropertyReader, + compilerOptions, + proj.typeAcquisition, + proj.options.compileOnSave, + watchOptionsAndErrors?.watchOptions, + ); externalProject.updateGraph(); return; } @@ -4221,9 +4808,15 @@ export class ProjectService { let project = this.findConfiguredProjectByProjectName(tsconfigFile); if (!project) { // errors are stored in the project, do not need to update the graph - project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject ? - this.createConfiguredProjectWithDelayLoad(tsconfigFile, `Creating configured project in external project: ${proj.projectFileName}`) : - this.createLoadAndUpdateConfiguredProject(tsconfigFile, `Creating configured project in external project: ${proj.projectFileName}`); + project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject + ? this.createConfiguredProjectWithDelayLoad( + tsconfigFile, + `Creating configured project in external project: ${proj.projectFileName}`, + ) + : this.createLoadAndUpdateConfiguredProject( + tsconfigFile, + `Creating configured project in external project: ${proj.projectFileName}`, + ); } if (project && !contains(exisingConfigFiles, tsconfigFile)) { // keep project alive even if no documents are opened - its lifetime is bound to the lifetime of containing external project @@ -4236,7 +4829,13 @@ export class ProjectService { // Create external project and update its graph, do not delay update since // any file open operation needs all updated external projects this.externalProjectToConfiguredProjectMap.delete(proj.projectFileName); - const project = this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition, excludedFiles); + const project = this.createExternalProject( + proj.projectFileName, + rootFiles, + proj.options, + proj.typeAcquisition, + excludedFiles, + ); project.updateGraph(); } } @@ -4257,13 +4856,19 @@ export class ProjectService { */ requestEnablePlugin(project: Project, pluginConfigEntry: PluginImport, searchPaths: string[]) { if (!this.host.importPlugin && !this.host.require) { - this.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded"); + this.logger.info( + "Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded", + ); return; } this.logger.info(`Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`); if (!pluginConfigEntry.name || parsePackageName(pluginConfigEntry.name).rest) { - this.logger.info(`Skipped loading plugin ${pluginConfigEntry.name || JSON.stringify(pluginConfigEntry)} because only package name is allowed plugin name`); + this.logger.info( + `Skipped loading plugin ${ + pluginConfigEntry.name || JSON.stringify(pluginConfigEntry) + } because only package name is allowed plugin name`, + ); return; } @@ -4283,19 +4888,25 @@ export class ProjectService { } // Otherwise, load the plugin using `require` - this.endEnablePlugin(project, Project.importServicePluginSync( - pluginConfigEntry, - searchPaths, - this.host, - s => this.logger.info(s), - )); + this.endEnablePlugin( + project, + Project.importServicePluginSync( + pluginConfigEntry, + searchPaths, + this.host, + s => this.logger.info(s), + ), + ); } /** * Performs the remaining steps of enabling a plugin after its module has been instantiated. * @internal */ - private endEnablePlugin(project: Project, { pluginConfigEntry, resolvedModule, errorLogs }: BeginEnablePluginResult) { + private endEnablePlugin( + project: Project, + { pluginConfigEntry, resolvedModule, errorLogs }: BeginEnablePluginResult, + ) { if (resolvedModule) { const configurationOverride = this.currentPluginConfigOverrides?.get(pluginConfigEntry.name); if (configurationOverride) { @@ -4371,14 +4982,19 @@ export class ProjectService { // Process all pending plugins, partitioned by project. This way a project with few plugins doesn't need to wait // on a project with many plugins. - await Promise.all(map(pendingPlugins, ([project, promises]) => this.enableRequestedPluginsForProjectAsync(project, promises))); + await Promise.all( + map(pendingPlugins, ([project, promises]) => this.enableRequestedPluginsForProjectAsync(project, promises)), + ); // Clear the pending operation and notify the client that projects have been updated. this.currentPluginEnablementPromise = undefined; this.sendProjectsUpdatedInBackgroundEvent(); } - private async enableRequestedPluginsForProjectAsync(project: Project, promises: Promise[]) { + private async enableRequestedPluginsForProjectAsync( + project: Project, + promises: Promise[], + ) { // Await all pending plugin imports. This ensures all requested plugin modules are fully loaded // prior to patching the language service, and that any promise rejections are observed. const results = await Promise.all(promises); @@ -4397,7 +5013,9 @@ export class ProjectService { configurePlugin(args: protocol.ConfigurePluginRequestArguments) { // For any projects that already have the plugin loaded, configure the plugin - this.forEachEnabledProject(project => project.onPluginConfigurationChanged(args.pluginName, args.configuration)); + this.forEachEnabledProject(project => + project.onPluginConfigurationChanged(args.pluginName, args.configuration) + ); // Also save the current configuration to pass on to any projects that are yet to be loaded. // If a plugin is configured twice, only the latest configuration will be remembered. @@ -4437,8 +5055,10 @@ export class ProjectService { getNearestAncestorDirectoryWithPackageJson(fileName: string): string | undefined { return forEachAncestorDirectory(fileName, directory => { switch (this.packageJsonCache.directoryHasPackageJson(this.toPath(directory))) { - case Ternary.True: return directory; - case Ternary.False: return undefined; + case Ternary.True: + return directory; + case Ternary.False: + return undefined; case Ternary.Maybe: return this.host.fileExists(combinePaths(directory, "package.json")) ? directory @@ -4452,28 +5072,31 @@ export class ProjectService { const watchers = this.packageJsonFilesMap || (this.packageJsonFilesMap = new Map()); if (!watchers.has(path)) { this.invalidateProjectPackageJson(path); - watchers.set(path, this.watchFactory.watchFile( + watchers.set( path, - (fileName, eventKind) => { - const path = this.toPath(fileName); - switch (eventKind) { - case FileWatcherEventKind.Created: - return Debug.fail(); - case FileWatcherEventKind.Changed: - this.packageJsonCache.addOrUpdate(path); - this.invalidateProjectPackageJson(path); - break; - case FileWatcherEventKind.Deleted: - this.packageJsonCache.delete(path); - this.invalidateProjectPackageJson(path); - watchers.get(path)!.close(); - watchers.delete(path); - } - }, - PollingInterval.Low, - this.hostConfiguration.watchOptions, - WatchType.PackageJson, - )); + this.watchFactory.watchFile( + path, + (fileName, eventKind) => { + const path = this.toPath(fileName); + switch (eventKind) { + case FileWatcherEventKind.Created: + return Debug.fail(); + case FileWatcherEventKind.Changed: + this.packageJsonCache.addOrUpdate(path); + this.invalidateProjectPackageJson(path); + break; + case FileWatcherEventKind.Deleted: + this.packageJsonCache.delete(path); + this.invalidateProjectPackageJson(path); + watchers.get(path)!.close(); + watchers.delete(path); + } + }, + PollingInterval.Low, + this.hostConfiguration.watchOptions, + WatchType.PackageJson, + ), + ); } } @@ -4486,9 +5109,12 @@ export class ProjectService { /** @internal */ includePackageJsonAutoImports(): PackageJsonAutoImportPreference { switch (this.hostConfiguration.preferences.includePackageJsonAutoImports) { - case "on": return PackageJsonAutoImportPreference.On; - case "off": return PackageJsonAutoImportPreference.Off; - default: return PackageJsonAutoImportPreference.Auto; + case "on": + return PackageJsonAutoImportPreference.On; + case "off": + return PackageJsonAutoImportPreference.Off; + default: + return PackageJsonAutoImportPreference.Auto; } } @@ -4524,7 +5150,7 @@ function createIncompleteCompletionsCache(): IncompleteCompletionsCache { }, clear() { info = undefined; - } + }, }; } diff --git a/src/server/moduleSpecifierCache.ts b/src/server/moduleSpecifierCache.ts index 2f2142a5bb0fe..cdec3252de15e 100644 --- a/src/server/moduleSpecifierCache.ts +++ b/src/server/moduleSpecifierCache.ts @@ -26,7 +26,10 @@ export function createModuleSpecifierCache(host: ModuleSpecifierResolutionCacheH return cache.get(toFileName); }, set(fromFileName, toFileName, preferences, options, modulePaths, moduleSpecifiers) { - ensureCache(fromFileName, preferences, options).set(toFileName, createInfo(modulePaths, moduleSpecifiers, /*isBlockedByPackageJsonDependencies*/ false)); + ensureCache(fromFileName, preferences, options).set( + toFileName, + createInfo(modulePaths, moduleSpecifiers, /*isBlockedByPackageJsonDependencies*/ false), + ); // If any module specifiers were generated based off paths in node_modules, // a package.json file in that package was read and is an input to the cached. @@ -37,7 +40,10 @@ export function createModuleSpecifierCache(host: ModuleSpecifierResolutionCacheH for (const p of modulePaths) { if (p.isInNodeModules) { // No trailing slash - const nodeModulesPath = p.path.substring(0, p.path.indexOf(nodeModulesPathPart) + nodeModulesPathPart.length - 1); + const nodeModulesPath = p.path.substring( + 0, + p.path.indexOf(nodeModulesPathPart) + nodeModulesPathPart.length - 1, + ); if (!containedNodeModulesWatchers?.has(nodeModulesPath)) { (containedNodeModulesWatchers ||= new Map()).set( nodeModulesPath, @@ -55,17 +61,37 @@ export function createModuleSpecifierCache(host: ModuleSpecifierResolutionCacheH info.modulePaths = modulePaths; } else { - cache.set(toFileName, createInfo(modulePaths, /*moduleSpecifiers*/ undefined, /*isBlockedByPackageJsonDependencies*/ undefined)); + cache.set( + toFileName, + createInfo( + modulePaths, + /*moduleSpecifiers*/ undefined, + /*isBlockedByPackageJsonDependencies*/ undefined, + ), + ); } }, - setBlockedByPackageJsonDependencies(fromFileName, toFileName, preferences, options, isBlockedByPackageJsonDependencies) { + setBlockedByPackageJsonDependencies( + fromFileName, + toFileName, + preferences, + options, + isBlockedByPackageJsonDependencies, + ) { const cache = ensureCache(fromFileName, preferences, options); const info = cache.get(toFileName); if (info) { info.isBlockedByPackageJsonDependencies = isBlockedByPackageJsonDependencies; } else { - cache.set(toFileName, createInfo(/*modulePaths*/ undefined, /*moduleSpecifiers*/ undefined, isBlockedByPackageJsonDependencies)); + cache.set( + toFileName, + createInfo( + /*modulePaths*/ undefined, + /*moduleSpecifiers*/ undefined, + isBlockedByPackageJsonDependencies, + ), + ); } }, clear() { @@ -76,7 +102,7 @@ export function createModuleSpecifierCache(host: ModuleSpecifierResolutionCacheH }, count() { return cache ? cache.size : 0; - } + }, }; if (Debug.isDebugging) { Object.defineProperty(result, "__cache", { get: () => cache }); diff --git a/src/server/packageJsonCache.ts b/src/server/packageJsonCache.ts index d1c12c65d9bfb..b1d7251695cd1 100644 --- a/src/server/packageJsonCache.ts +++ b/src/server/packageJsonCache.ts @@ -9,7 +9,9 @@ import { Ternary, tryFileExists, } from "./_namespaces/ts"; -import { ProjectService } from "./_namespaces/ts.server"; +import { + ProjectService, +} from "./_namespaces/ts.server"; /** @internal */ export interface PackageJsonCache { @@ -61,8 +63,8 @@ export function createPackageJsonCache(host: ProjectService): PackageJsonCache { } function directoryHasPackageJson(directory: Path) { - return packageJsons.has(combinePaths(directory, "package.json")) ? Ternary.True : - directoriesWithoutPackageJson.has(directory) ? Ternary.False : - Ternary.Maybe; + return packageJsons.has(combinePaths(directory, "package.json")) ? Ternary.True + : directoriesWithoutPackageJson.has(directory) ? Ternary.False + : Ternary.Maybe; } } diff --git a/src/server/project.ts b/src/server/project.ts index 1c9e985c83c50..e8ddd4c01b187 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -169,12 +169,18 @@ export type Mutable = { -readonly [K in keyof T]: T[K]; }; /** @internal */ export function countEachFileTypes(infos: ScriptInfo[], includeSizes = false): FileStats { const result: Mutable = { - js: 0, jsSize: 0, - jsx: 0, jsxSize: 0, - ts: 0, tsSize: 0, - tsx: 0, tsxSize: 0, - dts: 0, dtsSize: 0, - deferred: 0, deferredSize: 0, + js: 0, + jsSize: 0, + jsx: 0, + jsxSize: 0, + ts: 0, + tsSize: 0, + tsx: 0, + tsxSize: 0, + dts: 0, + dtsSize: 0, + deferred: 0, + deferredSize: 0, }; for (const info of infos) { const fileSize = includeSizes ? info.textStorage.getTelemetryFileSize() : 0; @@ -227,7 +233,10 @@ export function allFilesAreJsOrDts(project: Project): boolean { /** @internal */ export function hasNoTypeScriptSource(fileNames: string[]): boolean { - return !fileNames.some(fileName => (fileExtensionIs(fileName, Extension.Ts) && !isDeclarationFileName(fileName)) || fileExtensionIs(fileName, Extension.Tsx)); + return !fileNames.some(fileName => + (fileExtensionIs(fileName, Extension.Ts) && !isDeclarationFileName(fileName)) + || fileExtensionIs(fileName, Extension.Tsx) + ); } /** @internal */ @@ -255,7 +264,7 @@ export interface PluginModuleWithName { module: PluginModule; } -export type PluginModuleFactory = (mod: { typescript: typeof ts }) => PluginModule; +export type PluginModuleFactory = (mod: { typescript: typeof ts; }) => PluginModule; /** @internal */ export interface PluginImportResult { @@ -295,12 +304,11 @@ export interface EmitResult { const enum TypingWatcherType { FileWatcher = "FileWatcher", - DirectoryWatcher = "DirectoryWatcher" + DirectoryWatcher = "DirectoryWatcher", } type TypingWatchers = Map & { isInvoked?: boolean; }; - export abstract class Project implements LanguageServiceHost, ModuleResolutionHost { private rootFiles: ScriptInfo[] = []; private rootFilesMap = new Map(); @@ -416,7 +424,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return hasOneOrMoreJsAndNoTsFiles(this); } - public static resolveModule(moduleName: string, initialDir: string, host: ServerHost, log: (message: string) => void): {} | undefined { + public static resolveModule( + moduleName: string, + initialDir: string, + host: ServerHost, + log: (message: string) => void, + ): {} | undefined { return Project.importServicePluginSync({ name: moduleName }, [initialDir], host, log).resolvedModule; } @@ -469,7 +482,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo break; } const err = result.error.stack || result.error.message || JSON.stringify(result.error); - (errorLogs ??= []).push(`Failed to dynamically import module '${pluginConfigEntry.name}' from ${resolvedPath}: ${err}`); + (errorLogs ??= []).push( + `Failed to dynamically import module '${pluginConfigEntry.name}' from ${resolvedPath}: ${err}`, + ); } return { pluginConfigEntry, resolvedModule, errorLogs }; } @@ -520,13 +535,19 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory); this.getCanonicalFileName = this.projectService.toCanonicalFileName; - this.cancellationToken = new ThrottledCancellationToken(this.projectService.cancellationToken, this.projectService.throttleWaitMilliseconds); + this.cancellationToken = new ThrottledCancellationToken( + this.projectService.cancellationToken, + this.projectService.throttleWaitMilliseconds, + ); if (!this.compilerOptions) { this.compilerOptions = getDefaultCompilerOptions(); this.compilerOptions.allowNonTsExtensions = true; this.compilerOptions.allowJs = true; } - else if (hasExplicitListOfFiles || getAllowJSCompilerOption(this.compilerOptions) || this.projectService.hasDeferredExtension()) { + else if ( + hasExplicitListOfFiles || getAllowJSCompilerOption(this.compilerOptions) + || this.projectService.hasDeferredExtension() + ) { // If files are listed explicitly or allowJs is specified, allow all extensions this.compilerOptions.allowNonTsExtensions = true; } @@ -563,7 +584,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.resolutionCache = createResolutionCache( this, this.currentDirectory, - /*logChangesWhenResolvingModule*/ true + /*logChangesWhenResolvingModule*/ true, ); this.languageService = createLanguageService(this, this.documentRegistry, this.projectService.serverMode); if (lastFileExceededProgramSize) { @@ -579,7 +600,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return this.typingsCache.isKnownTypesPackageName(name); } installPackage(options: InstallPackageOptions): Promise { - return this.typingsCache.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) }); + return this.typingsCache.installPackage({ + ...options, + projectName: this.projectName, + projectRootPath: this.toPath(this.currentDirectory), + }); } /** @internal */ @@ -599,7 +624,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo if (this.program && !this.symlinks.hasProcessedResolutions()) { this.symlinks.setSymlinksFromResolutions( this.program.getSourceFiles(), - this.program.getAutomaticTypeDirectiveResolutions()); + this.program.getAutomaticTypeDirectiveResolutions(), + ); } return this.symlinks; } @@ -643,7 +669,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } private getOrCreateScriptInfoAndAttachToProject(fileName: string) { - const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost); + const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient( + fileName, + this.currentDirectory, + this.directoryStructureHost, + ); if (scriptInfo) { const existingValue = this.rootFilesMap.get(scriptInfo.path); if (existingValue && existingValue.info !== scriptInfo) { @@ -664,7 +694,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo getScriptVersion(filename: string) { // Don't attach to the project if version is asked - const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient(filename, this.currentDirectory, this.directoryStructureHost); + const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient( + filename, + this.currentDirectory, + this.directoryStructureHost, + ); return (info && info.getLatestVersion())!; // TODO: GH#18217 } @@ -692,7 +726,13 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return this.projectService.host.useCaseSensitiveFileNames; } - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { return this.directoryStructureHost.readDirectory!(path, extensions, exclude, include, depth); } @@ -712,8 +752,22 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - resolveModuleNameLiterals(moduleLiterals: readonly StringLiteralLike[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile, reusedNames: readonly StringLiteralLike[] | undefined): readonly ResolvedModuleWithFailedLookupLocations[] { - return this.resolutionCache.resolveModuleNameLiterals(moduleLiterals, containingFile, redirectedReference, options, containingSourceFile, reusedNames); + resolveModuleNameLiterals( + moduleLiterals: readonly StringLiteralLike[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingSourceFile: SourceFile, + reusedNames: readonly StringLiteralLike[] | undefined, + ): readonly ResolvedModuleWithFailedLookupLocations[] { + return this.resolutionCache.resolveModuleNameLiterals( + moduleLiterals, + containingFile, + redirectedReference, + options, + containingSourceFile, + reusedNames, + ); } getModuleResolutionCache(): ModuleResolutionCache | undefined { @@ -721,7 +775,14 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - resolveTypeReferenceDirectiveReferences(typeDirectiveReferences: readonly T[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile | undefined, reusedNames: readonly T[] | undefined): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { + resolveTypeReferenceDirectiveReferences( + typeDirectiveReferences: readonly T[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingSourceFile: SourceFile | undefined, + reusedNames: readonly T[] | undefined, + ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { return this.resolutionCache.resolveTypeReferenceDirectiveReferences( typeDirectiveReferences, containingFile, @@ -733,7 +794,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - resolveLibrary(libraryName: string, resolveFrom: string, options: CompilerOptions, libFileName: string): ResolvedModuleWithFailedLookupLocations { + resolveLibrary( + libraryName: string, + resolveFrom: string, + options: CompilerOptions, + libFileName: string, + ): ResolvedModuleWithFailedLookupLocations { return this.resolutionCache.resolveLibrary(libraryName, resolveFrom, options, libFileName); } @@ -763,7 +829,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo flags, this.projectService.getWatchOptions(this), WatchType.FailedLookupLocations, - this + this, ); } @@ -775,7 +841,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo PollingInterval.High, this.projectService.getWatchOptions(this), WatchType.AffectingFileLocation, - this + this, ); } @@ -786,17 +852,23 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** @internal */ scheduleInvalidateResolutionsOfFailedLookupLocations() { - this.projectService.throttledOperations.schedule(`${this.getProjectName()}FailedLookupInvalidation`, /*delay*/ 1000, () => { - if (this.resolutionCache.invalidateResolutionsOfFailedLookupLocations()) { - this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this); - } - }); + this.projectService.throttledOperations.schedule( + `${this.getProjectName()}FailedLookupInvalidation`, + /*delay*/ 1000, + () => { + if (this.resolutionCache.invalidateResolutionsOfFailedLookupLocations()) { + this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this); + } + }, + ); } /** @internal */ invalidateResolutionsOfFailedLookupLocations() { - if (this.clearInvalidateResolutionOfFailedLookupTimer() && - this.resolutionCache.invalidateResolutionsOfFailedLookupLocations()) { + if ( + this.clearInvalidateResolutionOfFailedLookupTimer() + && this.resolutionCache.invalidateResolutionsOfFailedLookupLocations() + ) { this.markAsDirty(); this.projectService.delayEnsureProjectForOpenFiles(); } @@ -815,7 +887,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo flags, this.projectService.getWatchOptions(this), WatchType.TypeRoots, - this + this, ); } @@ -831,7 +903,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** @internal */ getGlobalCache() { - return this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation : undefined; + return this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation + : undefined; } /** @internal */ @@ -908,9 +981,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** @internal */ shouldEmitFile(scriptInfo: ScriptInfo | undefined) { - return scriptInfo && - !scriptInfo.isDynamicOrHasMixedContent() && - !this.program!.isSourceOfProjectReferenceRedirect(scriptInfo.path); + return scriptInfo + && !scriptInfo.isDynamicOrHasMixedContent() + && !this.program!.isSourceOfProjectReferenceRedirect(scriptInfo.path); } getCompileOnSaveAffectedFileList(scriptInfo: ScriptInfo): string[] { @@ -918,7 +991,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return []; } updateProjectIfDirty(this); - this.builderState = BuilderState.create(this.program!, this.builderState, /*disableUseFileVersionAsSignature*/ true); + this.builderState = BuilderState.create( + this.program!, + this.builderState, + /*disableUseFileVersionAsSignature*/ true, + ); return mapDefined( BuilderState.getFilesAffectedBy( this.builderState, @@ -927,14 +1004,19 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.cancellationToken, this.projectService.host, ), - sourceFile => this.shouldEmitFile(this.projectService.getScriptInfoForPath(sourceFile.path)) ? sourceFile.fileName : undefined + sourceFile => + this.shouldEmitFile(this.projectService.getScriptInfoForPath(sourceFile.path)) ? sourceFile.fileName + : undefined, ); } /** * Returns true if emit was conducted */ - emitFile(scriptInfo: ScriptInfo, writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => void): EmitResult { + emitFile( + scriptInfo: ScriptInfo, + writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => void, + ): EmitResult { if (!this.languageServiceEnabled || !this.shouldEmitFile(scriptInfo)) { return { emitSkipped: true, diagnostics: emptyArray }; } @@ -950,9 +1032,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const dtsFiles = outputFiles.filter(f => isDeclarationFileName(f.name)); if (dtsFiles.length === 1) { const sourceFile = this.program!.getSourceFile(scriptInfo.fileName)!; - const signature = this.projectService.host.createHash ? - this.projectService.host.createHash(dtsFiles[0].text) : - generateDjb2Hash(dtsFiles[0].text); + const signature = this.projectService.host.createHash + ? this.projectService.host.createHash(dtsFiles[0].text) + : generateDjb2Hash(dtsFiles[0].text); BuilderState.updateSignatureOfFile(this.builderState, signature, sourceFile.resolvedPath); } } @@ -978,7 +1060,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.detachScriptInfoIfNotRoot(f.fileName); } this.program.forEachResolvedProjectReference(ref => - this.detachScriptInfoFromProject(ref.sourceFile.fileName)); + this.detachScriptInfoFromProject(ref.sourceFile.fileName) + ); this.program = undefined; } } @@ -1135,7 +1218,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } return map(this.program!.getSourceFiles(), sourceFile => { const scriptInfo = this.projectService.getScriptInfoForPath(sourceFile.resolvedPath); - Debug.assert(!!scriptInfo, "getScriptInfo", () => `scriptInfo for a file '${sourceFile.fileName}' Path: '${sourceFile.path}' / '${sourceFile.resolvedPath}' is missing.`); + Debug.assert( + !!scriptInfo, + "getScriptInfo", + () => + `scriptInfo for a file '${sourceFile.fileName}' Path: '${sourceFile.path}' / '${sourceFile.resolvedPath}' is missing.`, + ); return scriptInfo; }); } @@ -1185,7 +1273,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo getFileNamesWithRedirectInfo(includeProjectReferenceRedirectInfo: boolean) { return this.getFileNames().map((fileName): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName, - isSourceOfProjectReferenceRedirect: includeProjectReferenceRedirectInfo && this.isSourceOfProjectReferenceRedirect(fileName) + isSourceOfProjectReferenceRedirect: includeProjectReferenceRedirectInfo + && this.isSourceOfProjectReferenceRedirect(fileName), })); } @@ -1321,7 +1410,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo * @returns: true if set of files in the project stays the same and false - otherwise. */ updateGraph(): boolean { - tracing?.push(tracing.Phase.Session, "updateGraph", { name: this.projectName, kind: ProjectKind[this.projectKind] }); + tracing?.push(tracing.Phase.Session, "updateGraph", { + name: this.projectName, + kind: ProjectKind[this.projectKind], + }); perfLogger?.logStartUpdateGraph(); this.resolutionCache.startRecordingFilesWithChangedResolutions(); @@ -1330,7 +1422,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.hasAddedorRemovedFiles = false; this.hasAddedOrRemovedSymlinks = false; - const changedFiles: readonly Path[] = this.resolutionCache.finishRecordingFilesWithChangedResolutions() || emptyArray; + const changedFiles: readonly Path[] = this.resolutionCache.finishRecordingFilesWithChangedResolutions() + || emptyArray; for (const file of changedFiles) { // delete cached information for changed files @@ -1347,10 +1440,17 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo // (can reuse cached imports for files that were not changed) // 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch if (hasNewProgram || changedFiles.length) { - this.lastCachedUnresolvedImportsList = getUnresolvedImports(this.program!, this.cachedUnresolvedImportsPerFile); + this.lastCachedUnresolvedImportsList = getUnresolvedImports( + this.program!, + this.cachedUnresolvedImportsPerFile, + ); } - this.projectService.typingsCache.enqueueInstallTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasAddedorRemovedFiles); + this.projectService.typingsCache.enqueueInstallTypingsForProject( + this, + this.lastCachedUnresolvedImportsList, + hasAddedorRemovedFiles, + ); } else { this.lastCachedUnresolvedImportsList = undefined; @@ -1375,14 +1475,21 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** @internal */ updateTypingFiles(typingFiles: SortedReadonlyArray) { - if (enumerateInsertsAndDeletes(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()), - /*inserted*/ noop, - removed => this.detachScriptInfoFromProject(removed) - )) { + if ( + enumerateInsertsAndDeletes( + typingFiles, + this.typingFiles, + getStringComparer(!this.useCaseSensitiveFileNames()), + /*inserted*/ noop, + removed => this.detachScriptInfoFromProject(removed), + ) + ) { // If typing files changed, then only schedule project update this.typingFiles = typingFiles; // Invalidate files with unresolved imports - this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile); + this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports( + this.cachedUnresolvedImportsPerFile, + ); this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this); } } @@ -1421,30 +1528,46 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const canonicalPath = this.toPath(path); toRemove.delete(canonicalPath); if (!this.typingWatchers!.has(canonicalPath)) { - this.typingWatchers!.set(canonicalPath, typingsWatcherType === TypingWatcherType.FileWatcher ? - this.projectService.watchFactory.watchFile( - path, - () => !this.typingWatchers!.isInvoked ? - this.onTypingInstallerWatchInvoke() : - this.writeLog(`TypingWatchers already invoked`), - PollingInterval.High, - this.projectService.getWatchOptions(this), - WatchType.TypingInstallerLocationFile, - this, - ) : - this.projectService.watchFactory.watchDirectory( - path, - f => { - if (this.typingWatchers!.isInvoked) return this.writeLog(`TypingWatchers already invoked`); - if (!fileExtensionIs(f, Extension.Json)) return this.writeLog(`Ignoring files that are not *.json`); - if (comparePaths(f, combinePaths(this.projectService.typingsInstaller.globalTypingsCacheLocation!, "package.json"), !this.useCaseSensitiveFileNames())) return this.writeLog(`Ignoring package.json change at global typings location`); - this.onTypingInstallerWatchInvoke(); - }, - WatchDirectoryFlags.Recursive, - this.projectService.getWatchOptions(this), - WatchType.TypingInstallerLocationDirectory, - this, - ) + this.typingWatchers!.set( + canonicalPath, + typingsWatcherType === TypingWatcherType.FileWatcher + ? this.projectService.watchFactory.watchFile( + path, + () => + !this.typingWatchers!.isInvoked + ? this.onTypingInstallerWatchInvoke() + : this.writeLog(`TypingWatchers already invoked`), + PollingInterval.High, + this.projectService.getWatchOptions(this), + WatchType.TypingInstallerLocationFile, + this, + ) + : this.projectService.watchFactory.watchDirectory( + path, + f => { + if (this.typingWatchers!.isInvoked) { + return this.writeLog(`TypingWatchers already invoked`); + } + if (!fileExtensionIs(f, Extension.Json)) { + return this.writeLog(`Ignoring files that are not *.json`); + } + if ( + comparePaths( + f, + combinePaths( + this.projectService.typingsInstaller.globalTypingsCacheLocation!, + "package.json", + ), + !this.useCaseSensitiveFileNames(), + ) + ) return this.writeLog(`Ignoring package.json change at global typings location`); + this.onTypingInstallerWatchInvoke(); + }, + WatchDirectoryFlags.Recursive, + this.projectService.getWatchOptions(this), + WatchType.TypingInstallerLocationDirectory, + this, + ), ); } }; @@ -1473,8 +1596,18 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } // path in global cache, watch global cache - if (containsPath(this.projectService.typingsInstaller.globalTypingsCacheLocation!, file, this.currentDirectory, !this.useCaseSensitiveFileNames())) { - createProjectWatcher(this.projectService.typingsInstaller.globalTypingsCacheLocation!, TypingWatcherType.DirectoryWatcher); + if ( + containsPath( + this.projectService.typingsInstaller.globalTypingsCacheLocation!, + file, + this.currentDirectory, + !this.useCaseSensitiveFileNames(), + ) + ) { + createProjectWatcher( + this.projectService.typingsInstaller.globalTypingsCacheLocation!, + TypingWatcherType.DirectoryWatcher, + ); continue; } @@ -1505,7 +1638,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo Debug.assert(!this.isClosed(), "Called update graph worker of closed project"); this.writeLog(`Starting updateGraphWorker: Project: ${this.getProjectName()}`); const start = timestamp(); - const { hasInvalidatedResolutions, hasInvalidatedLibResolutions } = this.resolutionCache.createHasInvalidatedResolutions(returnFalse, returnFalse); + const { hasInvalidatedResolutions, hasInvalidatedLibResolutions } = this.resolutionCache + .createHasInvalidatedResolutions(returnFalse, returnFalse); this.hasInvalidatedResolutions = hasInvalidatedResolutions; this.hasInvalidatedLibResolutions = hasInvalidatedLibResolutions; this.resolutionCache.startCachingPerDirectoryResolution(); @@ -1521,7 +1655,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo // - oldProgram is not set - this is a first time updateGraph is called // - newProgram is different from the old program and structure of the old program was not reused. let hasNewProgram = false; - if (this.program && (!oldProgram || (this.program !== oldProgram && this.program.structureIsReused !== StructureIsReused.Completely))) { + if ( + this.program + && (!oldProgram + || (this.program !== oldProgram && this.program.structureIsReused !== StructureIsReused.Completely)) + ) { hasNewProgram = true; if (oldProgram) { for (const f of oldProgram.getSourceFiles()) { @@ -1545,17 +1683,19 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.program, this.missingFilesMap || (this.missingFilesMap = new Map()), // Watch the missing files - missingFilePath => this.addMissingFileWatcher(missingFilePath) + missingFilePath => this.addMissingFileWatcher(missingFilePath), ); if (this.generatedFilesMap) { const outPath = outFile(this.compilerOptions); if (isGeneratedFileWatcher(this.generatedFilesMap)) { // --out - if (!outPath || !this.isValidGeneratedFileWatcher( - removeFileExtension(outPath) + Extension.Dts, - this.generatedFilesMap, - )) { + if ( + !outPath || !this.isValidGeneratedFileWatcher( + removeFileExtension(outPath) + Extension.Dts, + this.generatedFilesMap, + ) + ) { this.clearGeneratedFileWatch(); } } @@ -1567,12 +1707,20 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo else { this.generatedFilesMap.forEach((watcher, source) => { const sourceFile = this.program!.getSourceFileByPath(source); - if (!sourceFile || - sourceFile.resolvedPath !== source || - !this.isValidGeneratedFileWatcher( - getDeclarationEmitOutputFilePathWorker(sourceFile.fileName, this.compilerOptions, this.currentDirectory, this.program!.getCommonSourceDirectory(), this.getCanonicalFileName), - watcher - )) { + if ( + !sourceFile + || sourceFile.resolvedPath !== source + || !this.isValidGeneratedFileWatcher( + getDeclarationEmitOutputFilePathWorker( + sourceFile.fileName, + this.compilerOptions, + this.currentDirectory, + this.program!.getCommonSourceDirectory(), + this.getCanonicalFileName, + ), + watcher, + ) + ) { closeFileWatcherOf(watcher); (this.generatedFilesMap as Map).delete(source); } @@ -1600,7 +1748,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.exportMapCache!.clear(); return true; } - return this.exportMapCache!.onFileChanged(oldSourceFile, sourceFile, !!this.getTypeAcquisition().enable); + return this.exportMapCache!.onFileChanged( + oldSourceFile, + sourceFile, + !!this.getTypeAcquisition().enable, + ); }); } } @@ -1608,7 +1760,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.changedFilesForExportMapCache.clear(); } - if (this.hasAddedOrRemovedSymlinks || this.program && !this.program.structureIsReused && this.getCompilerOptions().preserveSymlinks) { + if ( + this.hasAddedOrRemovedSymlinks + || this.program && !this.program.structureIsReused && this.getCompilerOptions().preserveSymlinks + ) { // With --preserveSymlinks, we may not determine that a file is a symlink, so we never set `hasAddedOrRemovedSymlinks` this.symlinks = undefined; this.moduleSpecifierCache.clear(); @@ -1616,29 +1771,48 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const oldExternalFiles = this.externalFiles || emptyArray as SortedReadonlyArray; this.externalFiles = this.getExternalFiles(); - enumerateInsertsAndDeletes(this.externalFiles, oldExternalFiles, getStringComparer(!this.useCaseSensitiveFileNames()), - // Ensure a ScriptInfo is created for new external files. This is performed indirectly + enumerateInsertsAndDeletes( + this.externalFiles, + oldExternalFiles, + getStringComparer(!this.useCaseSensitiveFileNames()), // Ensure a ScriptInfo is created for new external files. This is performed indirectly // by the host for files in the program when the program is retrieved above but // the program doesn't contain external files so this must be done explicitly. inserted => { - const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost); + const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient( + inserted, + this.currentDirectory, + this.directoryStructureHost, + ); scriptInfo?.attachToProject(this); }, - removed => this.detachScriptInfoFromProject(removed) + removed => this.detachScriptInfoFromProject(removed), ); const elapsed = timestamp() - start; this.sendPerformanceEvent("UpdateGraph", elapsed); - this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasNewProgram}${this.program ? ` structureIsReused:: ${(ts as any).StructureIsReused[this.program.structureIsReused]}` : ""} Elapsed: ${elapsed}ms`); + this.writeLog( + `Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasNewProgram}${ + this.program ? ` structureIsReused:: ${(ts as any).StructureIsReused[this.program.structureIsReused]}` + : "" + } Elapsed: ${elapsed}ms`, + ); if (this.projectService.logger.isTestLogger) { if (this.program !== oldProgram) { - this.print(/*writeProjectFileNames*/ true, this.hasAddedorRemovedFiles, /*writeFileVersionAndText*/ true); + this.print( + /*writeProjectFileNames*/ true, + this.hasAddedorRemovedFiles, + /*writeFileVersionAndText*/ true, + ); } else { this.writeLog(`Same program as before`); } } else if (this.hasAddedorRemovedFiles) { - this.print(/*writeProjectFileNames*/ true, /*writeFileExplaination*/ true, /*writeFileVersionAndText*/ false); + this.print( + /*writeProjectFileNames*/ true, + /*writeFileExplaination*/ true, + /*writeFileVersionAndText*/ false, + ); } else if (this.program !== oldProgram) { this.writeLog(`Different program with same set of files`); @@ -1666,7 +1840,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo private addMissingFileWatcher(missingFilePath: Path): FileWatcher { if (isConfiguredProject(this)) { // If this file is referenced config file, we are already watching it, no need to watch again - const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(missingFilePath as string as NormalizedPath); + const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get( + missingFilePath as string as NormalizedPath, + ); if (configFileExistenceInfo?.config?.projects.has(this.canonicalConfigFilePath)) return noopFileWatcher; } const fileWatcher = this.projectService.watchFactory.watchFile( @@ -1687,7 +1863,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo PollingInterval.Medium, this.projectService.getWatchOptions(this), WatchType.MissingFile, - this + this, ); return fileWatcher; } @@ -1709,7 +1885,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const path = this.toPath(sourceFile); if (this.generatedFilesMap) { if (isGeneratedFileWatcher(this.generatedFilesMap)) { - Debug.fail(`${this.projectName} Expected to not have --out watcher for generated file with options: ${JSON.stringify(this.compilerOptions)}`); + Debug.fail( + `${this.projectName} Expected to not have --out watcher for generated file with options: ${ + JSON.stringify(this.compilerOptions) + }`, + ); return; } if (this.generatedFilesMap.has(path)) return; @@ -1733,8 +1913,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo PollingInterval.High, this.projectService.getWatchOptions(this), WatchType.MissingGeneratedFile, - this - ) + this, + ), }; } @@ -1767,18 +1947,28 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } filesToString(writeProjectFileNames: boolean) { - return this.filesToStringWorker(writeProjectFileNames, /*writeFileExplaination*/ true, /*writeFileVersionAndText*/ false); + return this.filesToStringWorker( + writeProjectFileNames, + /*writeFileExplaination*/ true, + /*writeFileVersionAndText*/ false, + ); } /** @internal */ - private filesToStringWorker(writeProjectFileNames: boolean, writeFileExplaination: boolean, writeFileVersionAndText: boolean) { + private filesToStringWorker( + writeProjectFileNames: boolean, + writeFileExplaination: boolean, + writeFileVersionAndText: boolean, + ) { if (this.isInitialLoadPending()) return "\tFiles (0) InitialLoadPending\n"; if (!this.program) return "\tFiles (0) NoProgram\n"; const sourceFiles = this.program.getSourceFiles(); let strBuilder = `\tFiles (${sourceFiles.length})\n`; if (writeProjectFileNames) { for (const file of sourceFiles) { - strBuilder += `\t${file.fileName}${writeFileVersionAndText?` ${file.version} ${JSON.stringify(file.text)}` : ""}\n`; + strBuilder += `\t${file.fileName}${ + writeFileVersionAndText ? ` ${file.version} ${JSON.stringify(file.text)}` : "" + }\n`; } if (writeFileExplaination) { strBuilder += "\n\n"; @@ -1798,7 +1988,11 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo )); this.writeLog("-----------------------------------------------"); if (this.autoImportProviderHost) { - this.autoImportProviderHost.print(/*writeProjectFileNames*/ false, /*writeFileExplaination*/ false, /*writeFileVersionAndText*/ false); + this.autoImportProviderHost.print( + /*writeProjectFileNames*/ false, + /*writeFileExplaination*/ false, + /*writeFileVersionAndText*/ false, + ); } } @@ -1841,14 +2035,22 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - getChangesSinceVersion(lastKnownVersion?: number, includeProjectReferenceRedirectInfo?: boolean): ProjectFilesWithTSDiagnostics { - const includeProjectReferenceRedirectInfoIfRequested = - includeProjectReferenceRedirectInfo - ? (files: Map) => arrayFrom(files.entries(), ([fileName, isSourceOfProjectReferenceRedirect]): protocol.FileWithProjectReferenceRedirectInfo => ({ - fileName, - isSourceOfProjectReferenceRedirect - })) - : (files: Map) => arrayFrom(files.keys()); + getChangesSinceVersion( + lastKnownVersion?: number, + includeProjectReferenceRedirectInfo?: boolean, + ): ProjectFilesWithTSDiagnostics { + const includeProjectReferenceRedirectInfoIfRequested = includeProjectReferenceRedirectInfo + ? (files: Map) => + arrayFrom( + files.entries(), + ( + [fileName, isSourceOfProjectReferenceRedirect], + ): protocol.FileWithProjectReferenceRedirectInfo => ({ + fileName, + isSourceOfProjectReferenceRedirect, + }), + ) + : (files: Map) => arrayFrom(files.keys()); // Update the graph only if initial configured project load is not pending if (!this.isInitialLoadPending()) { @@ -1861,7 +2063,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo isInferred: isInferredProject(this), options: this.getCompilationSettings(), languageServiceDisabled: !this.languageServiceEnabled, - lastFileExceededProgramSize: this.lastFileExceededProgramSize + lastFileExceededProgramSize: this.lastFileExceededProgramSize, }; const updatedFileNames = this.updatedFileNames; this.updatedFileNames = undefined; @@ -1875,12 +2077,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const lastReportedFileNames = this.lastReportedFileNames; const externalFiles = this.getExternalFiles().map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName: toNormalizedPath(f), - isSourceOfProjectReferenceRedirect: false + isSourceOfProjectReferenceRedirect: false, })); const currentFiles = arrayToMap( this.getFileNamesWithRedirectInfo(!!includeProjectReferenceRedirectInfo).concat(externalFiles), info => info.fileName, - info => info.isSourceOfProjectReferenceRedirect + info => info.isSourceOfProjectReferenceRedirect, ); const added: Map = new Map(); @@ -1893,10 +2095,13 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo if (!lastReportedFileNames.has(fileName)) { added.set(fileName, isSourceOfProjectReferenceRedirect); } - else if (includeProjectReferenceRedirectInfo && isSourceOfProjectReferenceRedirect !== lastReportedFileNames.get(fileName)) { + else if ( + includeProjectReferenceRedirectInfo + && isSourceOfProjectReferenceRedirect !== lastReportedFileNames.get(fileName) + ) { updatedRedirects.push({ fileName, - isSourceOfProjectReferenceRedirect + isSourceOfProjectReferenceRedirect, }); } }); @@ -1915,12 +2120,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo updated: includeProjectReferenceRedirectInfo ? updated.map((fileName): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName, - isSourceOfProjectReferenceRedirect: this.isSourceOfProjectReferenceRedirect(fileName) + isSourceOfProjectReferenceRedirect: this.isSourceOfProjectReferenceRedirect(fileName), })) : updated, - updatedRedirects: includeProjectReferenceRedirectInfo ? updatedRedirects : undefined + updatedRedirects: includeProjectReferenceRedirectInfo ? updatedRedirects : undefined, }, - projectErrors: this.getGlobalProjectErrors() + projectErrors: this.getGlobalProjectErrors(), }; } else { @@ -1928,19 +2133,19 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const projectFileNames = this.getFileNamesWithRedirectInfo(!!includeProjectReferenceRedirectInfo); const externalFiles = this.getExternalFiles().map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName: toNormalizedPath(f), - isSourceOfProjectReferenceRedirect: false + isSourceOfProjectReferenceRedirect: false, })); const allFiles = projectFileNames.concat(externalFiles); this.lastReportedFileNames = arrayToMap( allFiles, info => info.fileName, - info => info.isSourceOfProjectReferenceRedirect + info => info.isSourceOfProjectReferenceRedirect, ); this.lastReportedVersion = this.projectProgramVersion; return { info, files: includeProjectReferenceRedirectInfo ? allFiles : allFiles.map(f => f.fileName), - projectErrors: this.getGlobalProjectErrors() + projectErrors: this.getGlobalProjectErrors(), }; } } @@ -1971,7 +2176,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const host = this.projectService.host; if (!host.require && !host.importPlugin) { - this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded"); + this.projectService.logger.info( + "Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded", + ); return; } @@ -1999,7 +2206,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo enableProxy(pluginModuleFactory: PluginModuleFactory, configEntry: PluginImport) { try { if (typeof pluginModuleFactory !== "function") { - this.projectService.logger.info(`Skipped loading plugin ${configEntry.name} because it did not expose a proper factory function`); + this.projectService.logger.info( + `Skipped loading plugin ${configEntry.name} because it did not expose a proper factory function`, + ); return; } @@ -2009,7 +2218,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo languageService: this.languageService, languageServiceHost: this, serverHost: this.projectService.host, - session: this.projectService.session + session: this.projectService.session, }; const pluginModule = pluginModuleFactory({ typescript: ts }); @@ -2017,7 +2226,9 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo for (const k of Object.keys(this.languageService)) { // eslint-disable-next-line local/no-in-operator if (!(k in newLS)) { - this.projectService.logger.info(`Plugin activation warning: Missing proxied method ${k} in created LS. Patching.`); + this.projectService.logger.info( + `Plugin activation warning: Missing proxied method ${k} in created LS. Patching.`, + ); (newLS as any)[k] = (this.languageService as any)[k]; } } @@ -2057,7 +2268,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** @internal */ getPackageJsonsForAutoImport(rootDir?: string): readonly ProjectPackageJsonInfo[] { - const packageJsons = this.getPackageJsonsVisibleToFile(combinePaths(this.currentDirectory, inferredTypesContainingFile), rootDir); + const packageJsons = this.getPackageJsonsVisibleToFile( + combinePaths(this.currentDirectory, inferredTypesContainingFile), + rootDir, + ); this.packageJsonsForAutoImport = new Set(packageJsons.map(p => p.fileName)); return packageJsons; } @@ -2084,10 +2298,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo /** @internal */ includePackageJsonAutoImports(): PackageJsonAutoImportPreference { - if (this.projectService.includePackageJsonAutoImports() === PackageJsonAutoImportPreference.Off || - !this.languageServiceEnabled || - isInsideNodeModules(this.currentDirectory) || - !this.isDefaultProjectForOpenFiles()) { + if ( + this.projectService.includePackageJsonAutoImports() === PackageJsonAutoImportPreference.Off + || !this.languageServiceEnabled + || isInsideNodeModules(this.currentDirectory) + || !this.isDefaultProjectForOpenFiles() + ) { return PackageJsonAutoImportPreference.Off; } return this.projectService.includePackageJsonAutoImports(); @@ -2134,7 +2350,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo if (dependencySelection) { tracing?.push(tracing.Phase.Session, "getPackageJsonAutoImportProvider"); const start = timestamp(); - this.autoImportProviderHost = AutoImportProviderProject.create(dependencySelection, this, this.getHostForAutoImportProvider(), this.documentRegistry); + this.autoImportProviderHost = AutoImportProviderProject.create( + dependencySelection, + this, + this.getHostForAutoImportProvider(), + this.documentRegistry, + ); if (this.autoImportProviderHost) { updateProjectIfDirty(this.autoImportProviderHost); this.sendPerformanceEvent("CreatePackageJsonAutoImportProvider", timestamp() - start); @@ -2149,7 +2370,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo private isDefaultProjectForOpenFiles(): boolean { return !!forEachEntry( this.projectService.openFiles, - (_, fileName) => this.projectService.tryGetDefaultProjectForFile(toNormalizedPath(fileName)) === this); + (_, fileName) => this.projectService.tryGetDefaultProjectForFile(toNormalizedPath(fileName)) === this, + ); } /** @internal */ @@ -2166,7 +2388,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo getNoDtsResolutionProject(rootFileNames: readonly string[]): Project { Debug.assert(this.projectService.serverMode === LanguageServiceMode.Semantic); if (!this.noDtsResolutionProject) { - this.noDtsResolutionProject = new AuxiliaryProject(this.projectService, this.documentRegistry, this.getCompilerOptionsForNoDtsResolutionProject(), this.currentDirectory); + this.noDtsResolutionProject = new AuxiliaryProject( + this.projectService, + this.documentRegistry, + this.getCompilerOptionsForNoDtsResolutionProject(), + this.currentDirectory, + ); } enumerateInsertsAndDeletes( @@ -2177,7 +2404,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient( pathToAdd, this.currentDirectory, - this.noDtsResolutionProject!.directoryStructureHost); + this.noDtsResolutionProject!.directoryStructureHost, + ); if (info) { this.noDtsResolutionProject!.addRoot(info, pathToAdd); } @@ -2211,24 +2439,38 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } } -function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: Map): SortedReadonlyArray { +function getUnresolvedImports( + program: Program, + cachedUnresolvedImportsPerFile: Map, +): SortedReadonlyArray { const sourceFiles = program.getSourceFiles(); tracing?.push(tracing.Phase.Session, "getUnresolvedImports", { count: sourceFiles.length }); const ambientModules = program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName())); - const result = sortAndDeduplicate(flatMap(sourceFiles, sourceFile => - extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile))); + const result = sortAndDeduplicate( + flatMap( + sourceFiles, + sourceFile => + extractUnresolvedImportsFromSourceFile(sourceFile, ambientModules, cachedUnresolvedImportsPerFile), + ), + ); tracing?.pop(); return result; } -function extractUnresolvedImportsFromSourceFile(file: SourceFile, ambientModules: readonly string[], cachedUnresolvedImportsPerFile: Map): readonly string[] { +function extractUnresolvedImportsFromSourceFile( + file: SourceFile, + ambientModules: readonly string[], + cachedUnresolvedImportsPerFile: Map, +): readonly string[] { return getOrUpdate(cachedUnresolvedImportsPerFile, file.path, () => { if (!file.resolvedModules) return emptyArray; let unresolvedImports: string[] | undefined; file.resolvedModules.forEach(({ resolvedModule }, name) => { // pick unresolved non-relative names - if ((!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) && - !isExternalModuleNameRelative(name) && - !ambientModules.some(m => m === name)) { + if ( + (!resolvedModule || !resolutionExtensionIsTSOrJson(resolvedModule.extension)) + && !isExternalModuleNameRelative(name) + && !ambientModules.some(m => m === name) + ) { unresolvedImports = append(unresolvedImports, parsePackageName(name).packageName); } }); @@ -2284,8 +2526,10 @@ export class InferredProject extends Project { watchOptions: WatchOptions | undefined, projectRootPath: NormalizedPath | undefined, currentDirectory: string, - typeAcquisition: TypeAcquisition | undefined) { - super(projectService.newInferredProjectName(), + typeAcquisition: TypeAcquisition | undefined, + ) { + super( + projectService.newInferredProjectName(), ProjectKind.Inferred, projectService, documentRegistry, @@ -2296,7 +2540,8 @@ export class InferredProject extends Project { /*compileOnSaveEnabled*/ false, watchOptions, projectService.host, - currentDirectory); + currentDirectory, + ); this.typeAcquisition = typeAcquisition; this.projectRootPath = projectRootPath && projectService.toCanonicalFileName(projectRootPath); if (!projectRootPath && !projectService.useSingleInferredProject) { @@ -2337,12 +2582,15 @@ export class InferredProject extends Project { // - when useSingleInferredProject is not set and projectRootPath is not set, // we can guarantee that this will be the only root // - other wise it has single root if it has single root script info - return (!this.projectRootPath && !this.projectService.useSingleInferredProject) || - this.getRootScriptInfos().length === 1; + return (!this.projectRootPath && !this.projectService.useSingleInferredProject) + || this.getRootScriptInfos().length === 1; } override close() { - forEach(this.getRootScriptInfos(), info => this.projectService.stopWatchingConfigFilesForInferredProjectRoot(info)); + forEach( + this.getRootScriptInfos(), + info => this.projectService.stopWatchingConfigFilesForInferredProjectRoot(info), + ); super.close(); } @@ -2350,15 +2598,21 @@ export class InferredProject extends Project { return this.typeAcquisition || { enable: allRootFilesAreJsOrDts(this), include: ts.emptyArray, - exclude: ts.emptyArray + exclude: ts.emptyArray, }; } } /** @internal */ export class AuxiliaryProject extends Project { - constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, currentDirectory: string) { - super(projectService.newAuxiliaryProjectName(), + constructor( + projectService: ProjectService, + documentRegistry: DocumentRegistry, + compilerOptions: CompilerOptions, + currentDirectory: string, + ) { + super( + projectService.newAuxiliaryProjectName(), ProjectKind.Auxiliary, projectService, documentRegistry, @@ -2368,7 +2622,8 @@ export class AuxiliaryProject extends Project { /*compileOnSaveEnabled*/ false, /*watchOptions*/ undefined, projectService.host, - currentDirectory); + currentDirectory, + ); } override isOrphan(): boolean { @@ -2386,7 +2641,12 @@ export class AutoImportProviderProject extends Project { private static readonly maxDependencies = 10; /** @internal */ - static getRootFileNames(dependencySelection: PackageJsonAutoImportPreference, hostProject: Project, host: GetPackageJsonEntrypointsHost, compilerOptions: CompilerOptions): string[] { + static getRootFileNames( + dependencySelection: PackageJsonAutoImportPreference, + hostProject: Project, + host: GetPackageJsonEntrypointsHost, + compilerOptions: CompilerOptions, + ): string[] { if (!dependencySelection) { return ts.emptyArray; } @@ -2400,7 +2660,9 @@ export class AutoImportProviderProject extends Project { let dependencyNames: Set | undefined; let rootNames: string[] | undefined; const rootFileName = combinePaths(hostProject.currentDirectory, inferredTypesContainingFile); - const packageJsons = hostProject.getPackageJsonsForAutoImport(combinePaths(hostProject.currentDirectory, rootFileName)); + const packageJsons = hostProject.getPackageJsonsForAutoImport( + combinePaths(hostProject.currentDirectory, rootFileName), + ); for (const packageJson of packageJsons) { packageJson.dependencies?.forEach((_, dependenyName) => addDependency(dependenyName)); packageJson.peerDependencies?.forEach((_, dependencyName) => addDependency(dependencyName)); @@ -2411,8 +2673,13 @@ export class AutoImportProviderProject extends Project { const symlinkCache = hostProject.getSymlinkCache(); for (const name of arrayFrom(dependencyNames.keys())) { // Avoid creating a large project that would significantly slow down time to editor interactivity - if (dependencySelection === PackageJsonAutoImportPreference.Auto && dependenciesAdded > this.maxDependencies) { - hostProject.log(`AutoImportProviderProject: attempted to add more than ${this.maxDependencies} dependencies. Aborting.`); + if ( + dependencySelection === PackageJsonAutoImportPreference.Auto + && dependenciesAdded > this.maxDependencies + ) { + hostProject.log( + `AutoImportProviderProject: attempted to add more than ${this.maxDependencies} dependencies. Aborting.`, + ); return ts.emptyArray; } @@ -2425,7 +2692,8 @@ export class AutoImportProviderProject extends Project { hostProject.currentDirectory, compilerOptions, host, - program.getModuleResolutionCache()); + program.getModuleResolutionCache(), + ); if (packageJson) { const entrypoints = getRootNamesFromPackageJson(packageJson, program, symlinkCache); if (entrypoints) { @@ -2437,22 +2705,30 @@ export class AutoImportProviderProject extends Project { // 2. Try to load from the @types package in the tree and in the global // typings cache location, if enabled. - const done = forEach([hostProject.currentDirectory, hostProject.getGlobalTypingsCacheLocation()], directory => { - if (directory) { - const typesPackageJson = resolvePackageNameToPackageJson( - `@types/${name}`, - directory, - compilerOptions, - host, - program.getModuleResolutionCache()); - if (typesPackageJson) { - const entrypoints = getRootNamesFromPackageJson(typesPackageJson, program, symlinkCache); - rootNames = concatenate(rootNames, entrypoints); - dependenciesAdded += entrypoints?.length ? 1 : 0; - return true; + const done = forEach( + [hostProject.currentDirectory, hostProject.getGlobalTypingsCacheLocation()], + directory => { + if (directory) { + const typesPackageJson = resolvePackageNameToPackageJson( + `@types/${name}`, + directory, + compilerOptions, + host, + program.getModuleResolutionCache(), + ); + if (typesPackageJson) { + const entrypoints = getRootNamesFromPackageJson( + typesPackageJson, + program, + symlinkCache, + ); + rootNames = concatenate(rootNames, entrypoints); + dependenciesAdded += entrypoints?.length ? 1 : 0; + return true; + } } - } - }); + }, + ); if (done) continue; @@ -2460,7 +2736,12 @@ export class AutoImportProviderProject extends Project { // allow processing JS from node_modules, go back to the implementation // package and load the JS. if (packageJson && compilerOptions.allowJs && compilerOptions.maxNodeModuleJsDepth) { - const entrypoints = getRootNamesFromPackageJson(packageJson, program, symlinkCache, /*resolveJs*/ true); + const entrypoints = getRootNamesFromPackageJson( + packageJson, + program, + symlinkCache, + /*resolveJs*/ true, + ); rootNames = concatenate(rootNames, entrypoints); dependenciesAdded += entrypoints?.length ? 1 : 0; } @@ -2468,7 +2749,11 @@ export class AutoImportProviderProject extends Project { } if (rootNames?.length) { - hostProject.log(`AutoImportProviderProject: found ${rootNames.length} root files in ${dependenciesAdded} dependencies in ${timestamp() - start} ms`); + hostProject.log( + `AutoImportProviderProject: found ${rootNames.length} root files in ${dependenciesAdded} dependencies in ${ + timestamp() - start + } ms`, + ); } return rootNames || ts.emptyArray; @@ -2478,13 +2763,19 @@ export class AutoImportProviderProject extends Project { } } - function getRootNamesFromPackageJson(packageJson: PackageJsonInfo, program: Program, symlinkCache: SymlinkCache, resolveJs?: boolean) { + function getRootNamesFromPackageJson( + packageJson: PackageJsonInfo, + program: Program, + symlinkCache: SymlinkCache, + resolveJs?: boolean, + ) { const entrypoints = getEntrypointsFromPackageJsonInfo( packageJson, compilerOptions, host, program.getModuleResolutionCache(), - resolveJs); + resolveJs, + ); if (entrypoints) { const real = host.realpath?.(packageJson.packageDirectory); const isSymlink = real && real !== packageJson.packageDirectory; @@ -2496,7 +2787,8 @@ export class AutoImportProviderProject extends Project { } return mapDefined(entrypoints, entrypoint => { - const resolvedFileName = isSymlink ? entrypoint.replace(packageJson.packageDirectory, real) : entrypoint; + const resolvedFileName = isSymlink ? entrypoint.replace(packageJson.packageDirectory, real) + : entrypoint; if (!program.getSourceFile(resolvedFileName) && !(isSymlink && program.getSourceFile(entrypoint))) { return resolvedFileName; } @@ -2516,7 +2808,12 @@ export class AutoImportProviderProject extends Project { }; /** @internal */ - static create(dependencySelection: PackageJsonAutoImportPreference, hostProject: Project, host: GetPackageJsonEntrypointsHost, documentRegistry: DocumentRegistry): AutoImportProviderProject | undefined { + static create( + dependencySelection: PackageJsonAutoImportPreference, + hostProject: Project, + host: GetPackageJsonEntrypointsHost, + documentRegistry: DocumentRegistry, + ): AutoImportProviderProject | undefined { if (dependencySelection === PackageJsonAutoImportPreference.Off) { return undefined; } @@ -2543,7 +2840,8 @@ export class AutoImportProviderProject extends Project { documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, ) { - super(hostProject.projectService.newAutoImportProviderProjectName(), + super( + hostProject.projectService.newAutoImportProviderProjectName(), ProjectKind.AutoImportProvider, hostProject.projectService, documentRegistry, @@ -2553,10 +2851,14 @@ export class AutoImportProviderProject extends Project { /*compileOnSaveEnabled*/ false, hostProject.getWatchOptions(), hostProject.projectService.host, - hostProject.currentDirectory); + hostProject.currentDirectory, + ); this.rootFileNames = initialRootNames; - this.useSourceOfProjectReferenceRedirect = maybeBind(this.hostProject, this.hostProject.useSourceOfProjectReferenceRedirect); + this.useSourceOfProjectReferenceRedirect = maybeBind( + this.hostProject, + this.hostProject.useSourceOfProjectReferenceRedirect, + ); this.getParsedCommandLine = maybeBind(this.hostProject, this.hostProject.getParsedCommandLine); } @@ -2576,7 +2878,8 @@ export class AutoImportProviderProject extends Project { this.hostProject.includePackageJsonAutoImports(), this.hostProject, this.hostProject.getHostForAutoImportProvider(), - this.getCompilationSettings()); + this.getCompilationSettings(), + ); } this.projectService.setFileNamesOfAutoImportProviderProject(this, rootFileNames); @@ -2609,7 +2912,9 @@ export class AutoImportProviderProject extends Project { } override getLanguageService(): never { - throw new Error("AutoImportProviderProject language service should never be used. To get the program, use `project.getCurrentProgram()`."); + throw new Error( + "AutoImportProviderProject language service should never be used. To get the program, use `project.getCurrentProgram()`.", + ); } /** @internal */ @@ -2623,7 +2928,9 @@ export class AutoImportProviderProject extends Project { } override getHostForAutoImportProvider(): never { - throw new Error("AutoImportProviderProject cannot provide its own host; use `hostProject.getModuleResolutionHostForAutomImportProvider()` instead."); + throw new Error( + "AutoImportProviderProject cannot provide its own host; use `hostProject.getModuleResolutionHostForAutomImportProvider()` instead.", + ); } override getProjectReferences() { @@ -2692,12 +2999,15 @@ export class ConfiguredProject extends Project { private compilerHost?: CompilerHost; /** @internal */ - constructor(configFileName: NormalizedPath, + constructor( + configFileName: NormalizedPath, readonly canonicalConfigFilePath: NormalizedPath, projectService: ProjectService, documentRegistry: DocumentRegistry, - cachedDirectoryStructureHost: CachedDirectoryStructureHost) { - super(configFileName, + cachedDirectoryStructureHost: CachedDirectoryStructureHost, + ) { + super( + configFileName, ProjectKind.Configured, projectService, documentRegistry, @@ -2707,7 +3017,7 @@ export class ConfiguredProject extends Project { /*compileOnSaveEnabled*/ false, /*watchOptions*/ undefined, cachedDirectoryStructureHost, - getDirectoryPath(configFileName) + getDirectoryPath(configFileName), ); } @@ -2733,10 +3043,18 @@ export class ConfiguredProject extends Project { // Ensure the config file existience info is cached let configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(canonicalConfigFilePath); if (!configFileExistenceInfo) { - this.projectService.configFileExistenceInfoCache.set(canonicalConfigFilePath, configFileExistenceInfo = { exists: this.projectService.host.fileExists(configFileName) }); + this.projectService.configFileExistenceInfoCache.set( + canonicalConfigFilePath, + configFileExistenceInfo = { exists: this.projectService.host.fileExists(configFileName) }, + ); } // Ensure we have upto date parsed command line - this.projectService.ensureParsedConfigUptoDate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, this); + this.projectService.ensureParsedConfigUptoDate( + configFileName, + canonicalConfigFilePath, + configFileExistenceInfo, + this, + ); // Watch wild cards if LS is enabled if (this.languageServiceEnabled && this.projectService.serverMode === LanguageServiceMode.Semantic) { this.projectService.watchWildcards(configFileName, configFileExistenceInfo, this); @@ -2746,7 +3064,9 @@ export class ConfiguredProject extends Project { /** @internal */ onReleaseParsedCommandLine(fileName: string) { - this.releaseParsedConfig(asNormalizedPath(this.projectService.toCanonicalFileName(asNormalizedPath(normalizePath(fileName))))); + this.releaseParsedConfig( + asNormalizedPath(this.projectService.toCanonicalFileName(asNormalizedPath(normalizePath(fileName)))), + ); } /** @internal */ @@ -2818,7 +3138,7 @@ export class ConfiguredProject extends Project { /** @internal */ forEachResolvedProjectReference( - cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined + cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, ): T | undefined { return this.getCurrentProgram()?.forEachResolvedProjectReference(cb); } @@ -2829,7 +3149,9 @@ export class ConfiguredProject extends Project { if (!options.plugins?.length && !this.projectService.globalPlugins.length) return; const host = this.projectService.host; if (!host.require && !host.importPlugin) { - this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded"); + this.projectService.logger.info( + "Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded", + ); return; } @@ -2870,7 +3192,8 @@ export class ConfiguredProject extends Project { override close() { this.projectService.configFileExistenceInfoCache.forEach((_configFileExistenceInfo, canonicalConfigFilePath) => - this.releaseParsedConfig(canonicalConfigFilePath)); + this.releaseParsedConfig(canonicalConfigFilePath) + ); this.projectErrors = undefined; this.openFileWatchTriggered.clear(); this.compilerHost = undefined; @@ -2889,8 +3212,8 @@ export class ConfiguredProject extends Project { /** @internal */ isSolution() { - return this.getRootFilesMap().size === 0 && - !this.canConfigFileJsonReportNoInputFiles; + return this.getRootFilesMap().size === 0 + && !this.canConfigFileJsonReportNoInputFiles; } /** @@ -2902,10 +3225,11 @@ export class ConfiguredProject extends Project { return forEachResolvedProjectReferenceProject( this, info.path, - child => projectContainsInfoDirectly(child, info) ? - child : - undefined, - ProjectReferenceProjectLoadKind.Find + child => + projectContainsInfoDirectly(child, info) + ? child + : undefined, + ProjectReferenceProjectLoadKind.Find, ); } @@ -2924,7 +3248,9 @@ export class ConfiguredProject extends Project { return false; } - const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(this.canonicalConfigFilePath)!; + const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get( + this.canonicalConfigFilePath, + )!; if (this.projectService.hasPendingProjectUpdate(this)) { // If there is pending update for this project, // we dont know if this project would be needed by any of the open files impacted by this config file @@ -2936,18 +3262,18 @@ export class ConfiguredProject extends Project { // We know exact set of open files that get impacted by this configured project as the files in the project // The project is referenced only if open files impacted by this project are present in this project return !!configFileExistenceInfo.openFilesImpactedByConfigFile && forEachEntry( - configFileExistenceInfo.openFilesImpactedByConfigFile, - (_value, infoPath) => { - const info = this.projectService.getScriptInfoForPath(infoPath)!; - return this.containsScriptInfo(info) || - !!forEachResolvedProjectReferenceProject( - this, - info.path, - child => child.containsScriptInfo(info), - ProjectReferenceProjectLoadKind.Find - ); - } - ) || false; + configFileExistenceInfo.openFilesImpactedByConfigFile, + (_value, infoPath) => { + const info = this.projectService.getScriptInfoForPath(infoPath)!; + return this.containsScriptInfo(info) + || !!forEachResolvedProjectReferenceProject( + this, + info.path, + child => child.containsScriptInfo(info), + ProjectReferenceProjectLoadKind.Find, + ); + }, + ) || false; } /** @internal */ @@ -2961,7 +3287,13 @@ export class ConfiguredProject extends Project { /** @internal */ updateErrorOnNoInputFiles(fileNames: string[]) { - updateErrorForNoInputFiles(fileNames, this.getConfigFilePath(), this.getCompilerOptions().configFile!.configFileSpecs!, this.projectErrors!, this.canConfigFileJsonReportNoInputFiles); + updateErrorForNoInputFiles( + fileNames, + this.getConfigFilePath(), + this.getCompilerOptions().configFile!.configFileSpecs!, + this.projectErrors!, + this.canConfigFileJsonReportNoInputFiles, + ); } } @@ -2972,15 +3304,18 @@ export class ConfiguredProject extends Project { export class ExternalProject extends Project { excludedFiles: readonly NormalizedPath[] = []; /** @internal */ - constructor(public externalProjectName: string, + constructor( + public externalProjectName: string, projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, lastFileExceededProgramSize: string | undefined, public override compileOnSaveEnabled: boolean, projectFilePath?: string, - watchOptions?: WatchOptions) { - super(externalProjectName, + watchOptions?: WatchOptions, + ) { + super( + externalProjectName, ProjectKind.External, projectService, documentRegistry, @@ -2990,7 +3325,8 @@ export class ExternalProject extends Project { compileOnSaveEnabled, watchOptions, projectService.host, - getDirectoryPath(projectFilePath || normalizeSlashes(externalProjectName))); + getDirectoryPath(projectFilePath || normalizeSlashes(externalProjectName)), + ); this.enableGlobalPlugins(this.getCompilerOptions()); } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 50fbe3deb139f..1b0624497ef6c 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -172,7 +172,7 @@ export const enum CommandTypes { PrepareCallHierarchy = "prepareCallHierarchy", ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls", ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls", - ProvideInlayHints = "provideInlayHints" + ProvideInlayHints = "provideInlayHints", } /** @@ -295,8 +295,8 @@ export interface FileRequestArgs { file: string; /* - * Optional name of project that contains file - */ + * Optional name of project that contains file + */ projectFileName?: string; } @@ -707,7 +707,6 @@ export type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & { interactiveRefactorArguments?: InteractiveRefactorArguments; }; - export interface GetEditsForRefactorResponse extends Response { body?: RefactorEditInfo; } @@ -792,7 +791,7 @@ export interface ApplyCodeActionCommandRequest extends Request { } // All we need is the `success` and `message` fields of Response. -export interface ApplyCodeActionCommandResponse extends Response { } +export interface ApplyCodeActionCommandResponse extends Response {} export interface FileRangeRequestArgs extends FileRequestArgs { /** @@ -935,12 +934,12 @@ export interface EncodedSemanticClassificationsRequestArgs extends FileRequestAr * Optional parameter for the semantic highlighting response, if absent it * defaults to "original". */ - format?: "original" | "2020" + format?: "original" | "2020"; } /** The response for a EncodedSemanticClassificationsRequest */ export interface EncodedSemanticClassificationsResponse extends Response { - body?: EncodedSemanticClassificationsResponseBody + body?: EncodedSemanticClassificationsResponseBody; } /** @@ -1136,7 +1135,7 @@ export interface JsxClosingTagRequest extends FileLocationRequest { readonly arguments: JsxClosingTagRequestArgs; } -export interface JsxClosingTagRequestArgs extends FileLocationRequestArgs { } +export interface JsxClosingTagRequestArgs extends FileLocationRequestArgs {} export interface JsxClosingTagResponse extends Response { readonly body: TextInsertion; @@ -1578,12 +1577,10 @@ export interface ChangedOpenFile { changes: TextChange[]; } - /** * Information found in a configure request. */ export interface ConfigureRequestArguments { - /** * Information about the host, for example 'Emacs 24.4' or * 'Sublime Text version 3075' @@ -2491,7 +2488,6 @@ export interface CompletionDetailsResponse extends Response { * Signature help information for a single parameter */ export interface SignatureHelpParameter { - /** * The parameter's name */ @@ -2517,7 +2513,6 @@ export interface SignatureHelpParameter { * Represents a single signature to show in signature help. */ export interface SignatureHelpItem { - /** * Whether the signature accepts a variable number of arguments. */ @@ -2558,7 +2553,6 @@ export interface SignatureHelpItem { * Signature help items found in the response of a signature help request. */ export interface SignatureHelpItems { - /** * The signature help items. */ @@ -3026,7 +3020,7 @@ export interface LargeFileReferencedEventBody { /** @internal */ export type AnyEvent = - RequestCompletedEvent + | RequestCompletedEvent | DiagnosticEvent | ConfigFileDiagnosticEvent | ProjectLanguageServiceStateEvent @@ -3388,7 +3382,7 @@ export interface NavTreeResponse extends Response { export interface CallHierarchyItem { name: string; kind: ScriptElementKind; - kindModifiers?: string + kindModifiers?: string; file: string; span: TextSpan; selectionSpan: TextSpan; @@ -3537,7 +3531,7 @@ export interface UserPreferences { readonly includeInlayParameterNameHints?: "none" | "literals" | "all"; readonly includeInlayParameterNameHintsWhenArgumentMatchesName?: boolean; - readonly includeInlayFunctionParameterTypeHints?: boolean, + readonly includeInlayFunctionParameterTypeHints?: boolean; readonly includeInlayVariableTypeHints?: boolean; readonly includeInlayVariableTypeHintsWhenTypeMatchesName?: boolean; readonly includeInlayPropertyDeclarationTypeHints?: boolean; @@ -3695,7 +3689,7 @@ export const enum ModuleKind { System = "System", ES6 = "ES6", ES2015 = "ES2015", - ESNext = "ESNext" + ESNext = "ESNext", } export const enum ModuleResolutionKind { @@ -3720,7 +3714,7 @@ export const enum ScriptTarget { ES2020 = "ES2020", ES2021 = "ES2021", ES2022 = "ES2022", - ESNext = "ESNext" + ESNext = "ESNext", } export const enum ClassificationType { diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 114e3f33d3518..ff7736776b1a7 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -175,9 +175,9 @@ export class TextStorage { * returns true if text changed */ public reloadWithFileText(tempFileName?: string) { - const { text: newText, fileSize } = tempFileName || !this.info.isDynamicOrHasMixedContent() ? - this.getFileTextAndSize(tempFileName) : - { text: "", fileSize: undefined }; + const { text: newText, fileSize } = tempFileName || !this.info.isDynamicOrHasMixedContent() + ? this.getFileTextAndSize(tempFileName) + : { text: "", fileSize: undefined }; const reloaded = this.reload(newText); this.fileSize = fileSize; // NB: after reload since reload clears it this.ownFileText = !tempFileName || tempFileName === this.info.fileName; @@ -189,9 +189,9 @@ export class TextStorage { * returns true when scheduling reload */ public scheduleReloadIfNeeded() { - return !this.pendingReloadFromDisk && !this.ownFileText ? - this.pendingReloadFromDisk = true : - false; + return !this.pendingReloadFromDisk && !this.ownFileText + ? this.pendingReloadFromDisk = true + : false; } public delayReloadFromFileIntoText() { @@ -209,27 +209,27 @@ export class TextStorage { return !!this.fileSize ? this.fileSize : !!this.text // Check text before svc because its length is cheaper - ? this.text.length // Could be wrong if this.pendingReloadFromDisk - : !!this.svc - ? this.svc.getSnapshot().getLength() // Could be wrong if this.pendingReloadFromDisk - : this.getSnapshot().getLength(); // Should be strictly correct + ? this.text.length // Could be wrong if this.pendingReloadFromDisk + : !!this.svc + ? this.svc.getSnapshot().getLength() // Could be wrong if this.pendingReloadFromDisk + : this.getSnapshot().getLength(); // Should be strictly correct } public getSnapshot(): IScriptSnapshot { - return this.tryUseScriptVersionCache()?.getSnapshot() || - (this.textSnapshot ??= ScriptSnapshot.fromString(Debug.checkDefined(this.text))); + return this.tryUseScriptVersionCache()?.getSnapshot() + || (this.textSnapshot ??= ScriptSnapshot.fromString(Debug.checkDefined(this.text))); } public getAbsolutePositionAndLineText(oneBasedLine: number): AbsolutePositionAndLineText { const svc = this.tryUseScriptVersionCache(); if (svc) return svc.getAbsolutePositionAndLineText(oneBasedLine); const lineMap = this.getLineMap(); - return oneBasedLine <= lineMap.length ? - { + return oneBasedLine <= lineMap.length + ? { absolutePosition: lineMap[oneBasedLine - 1], lineText: this.text!.substring(lineMap[oneBasedLine - 1], lineMap[oneBasedLine]), - } : - { + } + : { absolutePosition: this.text!.length, lineText: undefined, }; @@ -252,9 +252,9 @@ export class TextStorage { */ lineOffsetToPosition(line: number, offset: number, allowEdits?: true): number { const svc = this.tryUseScriptVersionCache(); - return svc ? - svc.lineOffsetToPosition(line, offset) : - computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1, this.text, allowEdits); + return svc + ? svc.lineOffsetToPosition(line, offset) + : computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1, this.text, allowEdits); } positionToLineOffset(position: number): protocol.Location { @@ -264,7 +264,7 @@ export class TextStorage { return { line: line + 1, offset: character + 1 }; } - private getFileTextAndSize(tempFileName?: string): { text: string, fileSize?: number } { + private getFileTextAndSize(tempFileName?: string): { text: string; fileSize?: number; } { let text: string; const fileName = tempFileName || this.info.fileName; const getText = () => text === undefined ? (text = this.host.readFile(fileName) || "") : text; @@ -274,7 +274,9 @@ export class TextStorage { if (fileSize > maxFileSize) { Debug.assert(!!this.info.containingProjects.length); const service = this.info.containingProjects[0].projectService; - service.logger.info(`Skipped loading contents of large file ${fileName} for info ${this.info.fileName}: fileSize: ${fileSize}`); + service.logger.info( + `Skipped loading contents of large file ${fileName} for info ${this.info.fileName}: fileSize: ${fileSize}`, + ); this.info.containingProjects[0].projectService.sendLargeFileReferencedEvent(fileName, fileSize); return { text: "", fileSize }; } @@ -313,7 +315,10 @@ export class TextStorage { private getOrLoadText() { if (this.text === undefined || this.pendingReloadFromDisk) { - Debug.assert(!this.svc || this.pendingReloadFromDisk, "ScriptVersionCache should not be set when reloading from disk"); + Debug.assert( + !this.svc || this.pendingReloadFromDisk, + "ScriptVersionCache should not be set when reloading from disk", + ); this.reloadWithFileText(); } return this.text!; @@ -329,7 +334,7 @@ export class TextStorage { if (svc) { return { getLineCount: () => svc.getLineCount(), - getLineText: line => svc.getAbsolutePositionAndLineText(line + 1).lineText! + getLineText: line => svc.getAbsolutePositionAndLineText(line + 1).lineText!, }; } const lineMap = this.getLineMap(); @@ -338,10 +343,10 @@ export class TextStorage { } export function isDynamicFileName(fileName: NormalizedPath) { - return fileName[0] === "^" || - ((stringContains(fileName, "walkThroughSnippet:/") || stringContains(fileName, "untitled:/")) && - getBaseFileName(fileName)[0] === "^") || - (stringContains(fileName, ":^") && !stringContains(fileName, directorySeparator)); + return fileName[0] === "^" + || ((stringContains(fileName, "walkThroughSnippet:/") || stringContains(fileName, "untitled:/")) + && getBaseFileName(fileName)[0] === "^") + || (stringContains(fileName, ":^") && !stringContains(fileName, directorySeparator)); } /** @internal */ @@ -405,7 +410,8 @@ export class ScriptInfo { readonly scriptKind: ScriptKind, public readonly hasMixedContent: boolean, readonly path: Path, - initialVersion?: number) { + initialVersion?: number, + ) { this.isDynamic = isDynamicFileName(fileName); this.textStorage = new TextStorage(host, this, initialVersion); @@ -428,8 +434,10 @@ export class ScriptInfo { public open(newText: string | undefined) { this.textStorage.isOpen = true; - if (newText !== undefined && - this.textStorage.reload(newText)) { + if ( + newText !== undefined + && this.textStorage.reload(newText) + ) { // reload new contents only if the existing contents changed this.markContainingProjectsAsDirty(); } @@ -479,8 +487,12 @@ export class ScriptInfo { return this.realpath && this.realpath !== this.path; } - getFormatCodeSettings(): FormatCodeSettings | undefined { return this.formatSettings; } - getPreferences(): protocol.UserPreferences | undefined { return this.preferences; } + getFormatCodeSettings(): FormatCodeSettings | undefined { + return this.formatSettings; + } + getPreferences(): protocol.UserPreferences | undefined { + return this.preferences; + } attachToProject(project: Project): boolean { const isNew = !this.isAttached(project); @@ -497,10 +509,14 @@ export class ScriptInfo { isAttached(project: Project) { // unrolled for common cases switch (this.containingProjects.length) { - case 0: return false; - case 1: return this.containingProjects[0] === project; - case 2: return this.containingProjects[0] === project || this.containingProjects[1] === project; - default: return contains(this.containingProjects, project); + case 0: + return false; + case 1: + return this.containingProjects[0] === project; + case 2: + return this.containingProjects[0] === project || this.containingProjects[1] === project; + default: + return contains(this.containingProjects, project); } } @@ -536,7 +552,11 @@ export class ScriptInfo { detachAllProjects() { for (const p of this.containingProjects) { if (isConfiguredProject(p)) { - p.getCachedDirectoryStructureHost().addOrDeleteFile(this.fileName, this.path, FileWatcherEventKind.Deleted); + p.getCachedDirectoryStructureHost().addOrDeleteFile( + this.fileName, + this.path, + FileWatcherEventKind.Deleted, + ); } const existingRoot = p.getRootFilesMap().get(this.path); // detach is unnecessary since we'll clean the list of containing projects anyways @@ -575,12 +595,17 @@ export class ScriptInfo { if (!project.isSourceOfProjectReferenceRedirect(this.fileName)) { // If we havent found default configuredProject and // its not the last one, find it and use that one if there - if (defaultConfiguredProject === undefined && - index !== this.containingProjects.length - 1) { - defaultConfiguredProject = project.projectService.findDefaultConfiguredProject(this) || false; + if ( + defaultConfiguredProject === undefined + && index !== this.containingProjects.length - 1 + ) { + defaultConfiguredProject = project.projectService.findDefaultConfiguredProject(this) + || false; } if (defaultConfiguredProject === project) return project; - if (!firstNonSourceOfProjectReferenceRedirect) firstNonSourceOfProjectReferenceRedirect = project; + if (!firstNonSourceOfProjectReferenceRedirect) { + firstNonSourceOfProjectReferenceRedirect = project; + } } if (!firstConfiguredProject) firstConfiguredProject = project; } @@ -591,11 +616,13 @@ export class ScriptInfo { firstInferredProject = project; } } - return ensurePrimaryProjectKind(defaultConfiguredProject || - firstNonSourceOfProjectReferenceRedirect || - firstConfiguredProject || - firstExternalProject || - firstInferredProject); + return ensurePrimaryProjectKind( + defaultConfiguredProject + || firstNonSourceOfProjectReferenceRedirect + || firstConfiguredProject + || firstExternalProject + || firstInferredProject, + ); } } @@ -668,7 +695,8 @@ export class ScriptInfo { isContainedByBackgroundProject() { return some( this.containingProjects, - p => p.projectKind === ProjectKind.AutoImportProvider || p.projectKind === ProjectKind.Auxiliary); + p => p.projectKind === ProjectKind.AutoImportProvider || p.projectKind === ProjectKind.Auxiliary, + ); } /** @@ -715,7 +743,10 @@ export class ScriptInfo { * reported as the default project for a ScriptInfo. */ function ensurePrimaryProjectKind(project: Project | undefined) { - if (!project || project.projectKind === ProjectKind.AutoImportProvider || project.projectKind === ProjectKind.Auxiliary) { + if ( + !project || project.projectKind === ProjectKind.AutoImportProvider + || project.projectKind === ProjectKind.Auxiliary + ) { return Errors.ThrowNoProject(); } return project; diff --git a/src/server/scriptVersionCache.ts b/src/server/scriptVersionCache.ts index af5faff067112..111f3f3c1148e 100644 --- a/src/server/scriptVersionCache.ts +++ b/src/server/scriptVersionCache.ts @@ -37,7 +37,7 @@ export const enum CharRangeSection { Entire, Mid, End, - PostEnd + PostEnd, } /** @internal */ @@ -45,15 +45,27 @@ export interface LineIndexWalker { goSubtree: boolean; done: boolean; leaf(relativeStart: number, relativeLength: number, lineCollection: LineLeaf): void; - pre?(relativeStart: number, relativeLength: number, lineCollection: LineCollection, - parent: LineNode, nodeType: CharRangeSection): void; - post?(relativeStart: number, relativeLength: number, lineCollection: LineCollection, - parent: LineNode, nodeType: CharRangeSection): void; + pre?( + relativeStart: number, + relativeLength: number, + lineCollection: LineCollection, + parent: LineNode, + nodeType: CharRangeSection, + ): void; + post?( + relativeStart: number, + relativeLength: number, + lineCollection: LineCollection, + parent: LineNode, + nodeType: CharRangeSection, + ): void; } class EditWalker implements LineIndexWalker { goSubtree = true; - get done() { return false; } + get done() { + return false; + } readonly lineIndex = new LineIndex(); // path to start of range @@ -164,7 +176,13 @@ class EditWalker implements LineIndexWalker { this.stack.pop(); } - pre(_relativeStart: number, _relativeLength: number, lineCollection: LineCollection, _parent: LineCollection, nodeType: CharRangeSection): void { + pre( + _relativeStart: number, + _relativeLength: number, + lineCollection: LineCollection, + _parent: LineCollection, + nodeType: CharRangeSection, + ): void { // currentNode corresponds to parent, but in the new tree const currentNode = this.stack[this.stack.length - 1]; @@ -261,8 +279,10 @@ class TextChange { } getTextChangeRange() { - return createTextChangeRange(createTextSpan(this.pos, this.deleteLen), - this.insertedText ? this.insertedText.length : 0); + return createTextChangeRange( + createTextSpan(this.pos, this.deleteLen), + this.insertedText ? this.insertedText.length : 0, + ); } } @@ -292,14 +312,18 @@ export class ScriptVersionCache { // REVIEW: can optimize by coalescing simple edits edit(pos: number, deleteLen: number, insertedText?: string) { this.changes.push(new TextChange(pos, deleteLen, insertedText)); - if (this.changes.length > ScriptVersionCache.changeNumberThreshold || - deleteLen > ScriptVersionCache.changeLengthThreshold || - insertedText && insertedText.length > ScriptVersionCache.changeLengthThreshold) { + if ( + this.changes.length > ScriptVersionCache.changeNumberThreshold + || deleteLen > ScriptVersionCache.changeLengthThreshold + || insertedText && insertedText.length > ScriptVersionCache.changeLengthThreshold + ) { this.getSnapshot(); } } - getSnapshot(): IScriptSnapshot { return this._getSnapshot(); } + getSnapshot(): IScriptSnapshot { + return this._getSnapshot(); + } private _getSnapshot(): LineIndexSnapshot { let snap = this.versions[this.currentVersionToIndex()]; @@ -340,7 +364,8 @@ export class ScriptVersionCache { lineToTextSpan(line: number): TextSpan { const index = this._getSnapshot().index; const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1); - const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition; + const len = lineText !== undefined ? lineText.length + : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition; return createTextSpan(absolutePosition, len); } @@ -380,7 +405,12 @@ export class ScriptVersionCache { } class LineIndexSnapshot implements IScriptSnapshot { - constructor(readonly version: number, readonly cache: ScriptVersionCache, readonly index: LineIndex, readonly changesSincePreviousVersion: readonly TextChange[] = emptyArray) { + constructor( + readonly version: number, + readonly cache: ScriptVersionCache, + readonly index: LineIndex, + readonly changesSincePreviousVersion: readonly TextChange[] = emptyArray, + ) { } getText(rangeStart: number, rangeEnd: number) { @@ -418,7 +448,7 @@ export class LineIndex { return { line: oneBasedLine, offset: zeroBasedColumn + 1 }; } - private positionToColumnAndLineText(position: number): { zeroBasedColumn: number, lineText: string | undefined } { + private positionToColumnAndLineText(position: number): { zeroBasedColumn: number; lineText: string | undefined; } { return this.root.charOffsetToLineInfo(1, position); } @@ -462,7 +492,7 @@ export class LineIndex { done: false, leaf: (relativeStart: number, relativeLength: number, ll: LineLeaf) => { accum = accum.concat(ll.text.substring(relativeStart, relativeStart + relativeLength)); - } + }, }); } return accum; @@ -483,7 +513,7 @@ export class LineIndex { if (!f(ll, relativeStart, relativeLength)) { this.done = true; } - } + }, }; this.walk(rangeStart, rangeEnd - rangeStart, walkFns); return !walkFns.done; @@ -603,7 +633,13 @@ export class LineNode implements LineCollection { } } - private execWalk(rangeStart: number, rangeLength: number, walkFns: LineIndexWalker, childIndex: number, nodeType: CharRangeSection) { + private execWalk( + rangeStart: number, + rangeLength: number, + walkFns: LineIndexWalker, + childIndex: number, + nodeType: CharRangeSection, + ) { if (walkFns.pre) { walkFns.pre(rangeStart, rangeLength, this.children[childIndex], this, nodeType); } @@ -619,7 +655,13 @@ export class LineNode implements LineCollection { return walkFns.done; } - private skipChild(relativeStart: number, relativeLength: number, childIndex: number, walkFns: LineIndexWalker, nodeType: CharRangeSection) { + private skipChild( + relativeStart: number, + relativeLength: number, + childIndex: number, + walkFns: LineIndexWalker, + nodeType: CharRangeSection, + ) { if (walkFns.pre && (!walkFns.done)) { walkFns.pre(relativeStart, relativeLength, this.children[childIndex], this, nodeType); walkFns.goSubtree = true; @@ -646,7 +688,15 @@ export class LineNode implements LineCollection { } else { // Case II: start and end of range in different subtrees (possibly with subtrees in the middle) - if (this.execWalk(adjustedStart, childCharCount - adjustedStart, walkFns, childIndex, CharRangeSection.Start)) { + if ( + this.execWalk( + adjustedStart, + childCharCount - adjustedStart, + walkFns, + childIndex, + CharRangeSection.Start, + ) + ) { return; } let adjustedLength = rangeLength - (childCharCount - adjustedStart); @@ -680,7 +730,10 @@ export class LineNode implements LineCollection { // Input position is relative to the start of this node. // Output line number is absolute. - charOffsetToLineInfo(lineNumberAccumulator: number, relativePosition: number): { oneBasedLine: number, zeroBasedColumn: number, lineText: string | undefined } { + charOffsetToLineInfo( + lineNumberAccumulator: number, + relativePosition: number, + ): { oneBasedLine: number; zeroBasedColumn: number; lineText: string | undefined; } { if (this.children.length === 0) { // Root node might have no children if this is an empty document. return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: undefined }; @@ -689,7 +742,11 @@ export class LineNode implements LineCollection { for (const child of this.children) { if (child.charCount() > relativePosition) { if (child.isLeaf()) { - return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: child.text }; + return { + oneBasedLine: lineNumberAccumulator, + zeroBasedColumn: relativePosition, + lineText: child.text, + }; } else { return (child as LineNode).charOffsetToLineInfo(lineNumberAccumulator, relativePosition); @@ -715,11 +772,15 @@ export class LineNode implements LineCollection { * Output line number is relative to the child. * positionAccumulator will be an absolute position once relativeLineNumber reaches 0. */ - lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } { + lineNumberToInfo( + relativeOneBasedLine: number, + positionAccumulator: number, + ): { position: number; leaf: LineLeaf | undefined; } { for (const child of this.children) { const childLineCount = child.lineCount(); if (childLineCount >= relativeOneBasedLine) { - return child.isLeaf() ? { position: positionAccumulator, leaf: child } : (child as LineNode).lineNumberToInfo(relativeOneBasedLine, positionAccumulator); + return child.isLeaf() ? { position: positionAccumulator, leaf: child } + : (child as LineNode).lineNumberToInfo(relativeOneBasedLine, positionAccumulator); } else { relativeOneBasedLine -= childLineCount; diff --git a/src/server/session.ts b/src/server/session.ts index ed3872c8f4038..96f2e42069cd0 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -193,7 +193,7 @@ export interface ServerCancellationToken extends HostCancellationToken { export const nullCancellationToken: ServerCancellationToken = { isCancellationRequested: () => false, setRequest: () => void 0, - resetRequest: () => void 0 + resetRequest: () => void 0, }; function hrTimeToMilliseconds(time: [number, number]): number { @@ -216,15 +216,16 @@ function isDeclarationFileInJSOnlyNonConfiguredProject(project: Project, file: N // We still want to check .js files in a JS-only inferred or external project (e.g. if the // file has '// @ts-check'). - if ((isInferredProject(project) || isExternalProject(project)) && - project.isJsOnlyProject()) { + if ( + (isInferredProject(project) || isExternalProject(project)) + && project.isJsOnlyProject() + ) { const scriptInfo = project.getScriptInfoForNormalizedPath(file); return scriptInfo && !scriptInfo.isJavaScript(); } return false; } - function dtsChangeCanAffectEmit(compilationSettings: CompilerOptions) { return getEmitDeclarations(compilationSettings) || !!compilationSettings.emitDecoratorMetadata; } @@ -249,18 +250,18 @@ function formatRelatedInformation(info: DiagnosticRelatedInformation): protocol. return { message: flattenDiagnosticMessageText(info.messageText, "\n"), category: diagnosticCategoryName(info), - code: info.code + code: info.code, }; } return { span: { start: convertToLocation(getLineAndCharacterOfPosition(info.file, info.start!)), end: convertToLocation(getLineAndCharacterOfPosition(info.file, info.start! + info.length!)), // TODO: GH#18217 - file: info.file.fileName + file: info.file.fileName, }, message: flattenDiagnosticMessageText(info.messageText, "\n"), category: diagnosticCategoryName(info), - code: info.code + code: info.code, }; } @@ -273,7 +274,10 @@ export function formatDiagnosticToProtocol(diag: Diagnostic, includeFileName: tr /** @internal */ export function formatDiagnosticToProtocol(diag: Diagnostic, includeFileName: false): protocol.Diagnostic; /** @internal */ -export function formatDiagnosticToProtocol(diag: Diagnostic, includeFileName: boolean): protocol.Diagnostic | protocol.DiagnosticWithFileName { +export function formatDiagnosticToProtocol( + diag: Diagnostic, + includeFileName: boolean, +): protocol.Diagnostic | protocol.DiagnosticWithFileName { const start = (diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start!)))!; // TODO: GH#18217 const end = (diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start! + diag.length!)))!; // TODO: GH#18217 const text = flattenDiagnosticMessageText(diag.messageText, "\n"); @@ -314,7 +318,12 @@ export type CommandNames = protocol.CommandTypes; /** @deprecated use ts.server.protocol.CommandTypes */ export const CommandNames = (protocol as any).CommandTypes; -export function formatMessage(msg: T, logger: Logger, byteLength: (s: string, encoding: BufferEncoding) => number, newLine: string): string { +export function formatMessage( + msg: T, + logger: Logger, + byteLength: (s: string, encoding: BufferEncoding) => number, + newLine: string, +): string { const verboseLogging = logger.hasLevel(LogLevel.verbose); const json = JSON.stringify(msg); @@ -355,7 +364,7 @@ class MultistepOperation implements NextStep { private timerHandle: any; private immediateId: number | undefined; - constructor(private readonly operationHost: MultistepOperationHost) { } + constructor(private readonly operationHost: MultistepOperationHost) {} public startNew(action: (next: NextStep) => void) { this.complete(); @@ -375,19 +384,27 @@ class MultistepOperation implements NextStep { public immediate(actionType: string, action: () => void) { const requestId = this.requestId!; Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "immediate: incorrect request id"); - this.setImmediateId(this.operationHost.getServerHost().setImmediate(() => { - this.immediateId = undefined; - this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action)); - }, actionType)); + this.setImmediateId( + this.operationHost.getServerHost().setImmediate(() => { + this.immediateId = undefined; + this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action)); + }, actionType), + ); } public delay(actionType: string, ms: number, action: () => void) { const requestId = this.requestId!; Debug.assert(requestId === this.operationHost.getCurrentRequestId(), "delay: incorrect request id"); - this.setTimerHandle(this.operationHost.getServerHost().setTimeout(() => { - this.timerHandle = undefined; - this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action)); - }, ms, actionType)); + this.setTimerHandle( + this.operationHost.getServerHost().setTimeout( + () => { + this.timerHandle = undefined; + this.operationHost.executeWithRequestId(requestId, () => this.executeAction(action)); + }, + ms, + actionType, + ), + ); } private executeAction(action: (next: NextStep) => void) { @@ -413,7 +430,10 @@ class MultistepOperation implements NextStep { tracing?.instant(tracing.Phase.Session, "stepCanceled", { seq: this.requestId }); } else { - tracing?.instant(tracing.Phase.Session, "stepError", { seq: this.requestId, message: (e as Error).message }); + tracing?.instant(tracing.Phase.Session, "stepError", { + seq: this.requestId, + message: (e as Error).message, + }); this.operationHost.logError(e, `delayed processing of request ${this.requestId}`); } } @@ -453,7 +473,7 @@ export function toEvent(eventName: string, body: object): protocol.Event { seq: 0, type: "event", event: eventName, - body + body, }; } @@ -471,7 +491,10 @@ function combineProjectOutput( projects: Projects, action: (project: Project, value: T) => readonly U[] | U | undefined, ): U[] { - const outputs = flatMapToMutable(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue)); + const outputs = flatMapToMutable( + isArray(projects) ? projects : projects.projects, + project => action(project, defaultValue), + ); if (!isArray(projects) && projects.symLinkedProjects) { projects.symLinkedProjects.forEach((projects, path) => { const value = getValue(path); @@ -487,7 +510,7 @@ interface ProjectNavigateToItems { } function createDocumentSpanSet(): Set { - return createSet(({textSpan}) => textSpan.start + 100003 * textSpan.length, documentSpansEqual); + return createSet(({ textSpan }) => textSpan.start + 100003 * textSpan.length, documentSpansEqual); } function getRenameLocationsWorker( @@ -496,14 +519,21 @@ function getRenameLocationsWorker( initialLocation: DocumentPosition, findInStrings: boolean, findInComments: boolean, - preferences: protocol.UserPreferences + preferences: protocol.UserPreferences, ): readonly RenameLocation[] { const perProjectResults = getPerProjectReferences( projects, defaultProject, initialLocation, /*isForRename*/ true, - (project, position) => project.getLanguageService().findRenameLocations(position.fileName, position.pos, findInStrings, findInComments, preferences), + (project, position) => + project.getLanguageService().findRenameLocations( + position.fileName, + position.pos, + findInStrings, + findInComments, + preferences, + ), (renameLocation, cb) => cb(documentSpanLocation(renameLocation)), ); @@ -528,8 +558,17 @@ function getRenameLocationsWorker( return results; } -function getDefinitionLocation(defaultProject: Project, initialLocation: DocumentPosition, isForRename: boolean): DocumentPosition | undefined { - const infos = defaultProject.getLanguageService().getDefinitionAtPosition(initialLocation.fileName, initialLocation.pos, /*searchOtherFilesOnly*/ false, /*stopAtAlias*/ isForRename); +function getDefinitionLocation( + defaultProject: Project, + initialLocation: DocumentPosition, + isForRename: boolean, +): DocumentPosition | undefined { + const infos = defaultProject.getLanguageService().getDefinitionAtPosition( + initialLocation.fileName, + initialLocation.pos, + /*searchOtherFilesOnly*/ false, + /*stopAtAlias*/ isForRename, + ); const info = infos && firstOrUndefined(infos); // Note that the value of `isLocal` may depend on whether or not the checker has run on the containing file // (implying that FAR cascading behavior may depend on request order) @@ -548,7 +587,9 @@ function getReferencesWorker( initialLocation, /*isForRename*/ false, (project, position) => { - logger.info(`Finding references to ${position.fileName} position ${position.pos} in project ${project.getProjectName()}`); + logger.info( + `Finding references to ${position.fileName} position ${position.pos} in project ${project.getProjectName()}`, + ); return project.getLanguageService().findReferences(position.fileName, position.pos); }, (referencedSymbol, cb) => { @@ -597,7 +638,10 @@ function getReferencesWorker( let progress = false; perProjectResults.forEach((referencedSymbols, project) => { if (updatedProjects.has(project)) return; - const updated = project.getLanguageService().updateIsDefinitionOfReferencedSymbols(referencedSymbols, knownSymbolSpans); + const updated = project.getLanguageService().updateIsDefinitionOfReferencedSymbols( + referencedSymbols, + knownSymbolSpans, + ); if (updated) { updatedProjects.add(project); progress = true; @@ -627,14 +671,17 @@ function getReferencesWorker( // dropped later when we check for defs with ref-count 0. perProjectResults.forEach((projectResults, project) => { for (const referencedSymbol of projectResults) { - const mappedDefinitionFile = getMappedLocationForProject(documentSpanLocation(referencedSymbol.definition), project); - const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? - referencedSymbol.definition : - { + const mappedDefinitionFile = getMappedLocationForProject( + documentSpanLocation(referencedSymbol.definition), + project, + ); + const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined + ? referencedSymbol.definition + : { ...referencedSymbol.definition, textSpan: createTextSpan(mappedDefinitionFile.pos, referencedSymbol.definition.textSpan.length), // Why would the length be the same in the original? fileName: mappedDefinitionFile.fileName, - contextSpan: getMappedContextSpanForProject(referencedSymbol.definition, project) + contextSpan: getMappedContextSpanForProject(referencedSymbol.definition, project), }; let symbolToAddTo = find(results, o => documentSpansEqual(o.definition, definition)); @@ -660,7 +707,11 @@ interface ProjectAndLocation { readonly location: DocumentPosition; } -function forEachProjectInProjects(projects: Projects, path: string | undefined, cb: (project: Project, path: string | undefined) => void): void { +function forEachProjectInProjects( + projects: Projects, + path: string | undefined, + cb: (project: Project, path: string | undefined) => void, +): void { for (const project of isArray(projects) ? projects : projects.projects) { cb(project, path); } @@ -713,12 +764,16 @@ function getPerProjectReferences( const defaultDefinition = getDefinitionLocation(defaultProject, initialLocation, isForRename); // Don't call these unless !!defaultDefinition - const getGeneratedDefinition = memoize(() => defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) ? - defaultDefinition : - defaultProject.getLanguageService().getSourceMapper().tryGetGeneratedPosition(defaultDefinition!)); - const getSourceDefinition = memoize(() => defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) ? - defaultDefinition : - defaultProject.getLanguageService().getSourceMapper().tryGetSourcePosition(defaultDefinition!)); + const getGeneratedDefinition = memoize(() => + defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) + ? defaultDefinition + : defaultProject.getLanguageService().getSourceMapper().tryGetGeneratedPosition(defaultDefinition!) + ); + const getSourceDefinition = memoize(() => + defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) + ? defaultDefinition + : defaultProject.getLanguageService().getSourceMapper().tryGetSourcePosition(defaultDefinition!) + ); // The keys of resultsMap allow us to check which projects have already been searched, but we also // maintain a set of strings because that's what `loadAncestorProjectTree` wants. @@ -755,7 +810,12 @@ function getPerProjectReferences( projectService.forEachEnabledProject(project => { if (cancellationToken.isCancellationRequested()) return; // There's no mechanism for skipping the remaining projects if (resultsMap.has(project)) return; // Can loop forever without this (enqueue here, dequeue above, repeat) - const location = mapDefinitionInProject(defaultDefinition, project, getGeneratedDefinition, getSourceDefinition); + const location = mapDefinitionInProject( + defaultDefinition, + project, + getGeneratedDefinition, + getSourceDefinition, + ); if (location) { queue.enqueue({ project, location }); } @@ -794,7 +854,10 @@ function getPerProjectReferences( symlinkedProjectsMap.forEach((symlinkedProjects, symlinkedPath) => { for (const symlinkedProject of symlinkedProjects) { if (!symlinkedProject.isOrphan() && !resultsMap.has(symlinkedProject)) { // Optimization: don't enqueue if will be discarded - queue.enqueue({ project: symlinkedProject, location: { fileName: symlinkedPath as string, pos: originalLocation.pos } }); + queue.enqueue({ + project: symlinkedProject, + location: { fileName: symlinkedPath as string, pos: originalLocation.pos }, + }); } } }); @@ -810,17 +873,22 @@ function mapDefinitionInProject( definition: DocumentPosition, project: Project, getGeneratedDefinition: () => DocumentPosition | undefined, - getSourceDefinition: () => DocumentPosition | undefined + getSourceDefinition: () => DocumentPosition | undefined, ): DocumentPosition | undefined { // If the definition is actually from the project, definition is correct as is - if (project.containsFile(toNormalizedPath(definition.fileName)) && - !isLocationProjectReferenceRedirect(project, definition)) { + if ( + project.containsFile(toNormalizedPath(definition.fileName)) + && !isLocationProjectReferenceRedirect(project, definition) + ) { return definition; } const generatedDefinition = getGeneratedDefinition(); - if (generatedDefinition && project.containsFile(toNormalizedPath(generatedDefinition.fileName))) return generatedDefinition; + if (generatedDefinition && project.containsFile(toNormalizedPath(generatedDefinition.fileName))) { + return generatedDefinition; + } const sourceDefinition = getSourceDefinition(); - return sourceDefinition && project.containsFile(toNormalizedPath(sourceDefinition.fileName)) ? sourceDefinition : undefined; + return sourceDefinition && project.containsFile(toNormalizedPath(sourceDefinition.fileName)) ? sourceDefinition + : undefined; } function isLocationProjectReferenceRedirect(project: Project, location: DocumentPosition | undefined) { @@ -834,9 +902,9 @@ function isLocationProjectReferenceRedirect(project: Project, location: Document // This happens when rootFile in project is one of the file from referenced project // Thus root is attached but program doesnt have the actual .ts file but .d.ts // If this is not the file we were actually looking, return rest of the toDo - return !!sourceFile && - sourceFile.resolvedPath !== sourceFile.path && - sourceFile.resolvedPath !== project.toPath(location.fileName); + return !!sourceFile + && sourceFile.resolvedPath !== sourceFile.path + && sourceFile.resolvedPath !== project.toPath(location.fileName); } function getProjectKey(project: Project) { @@ -848,15 +916,27 @@ function documentSpanLocation({ fileName, textSpan }: DocumentSpan): DocumentPos } function getMappedLocationForProject(location: DocumentPosition, project: Project): DocumentPosition | undefined { - return getMappedLocation(location, project.getSourceMapper(), p => project.projectService.fileExists(p as NormalizedPath)); + return getMappedLocation( + location, + project.getSourceMapper(), + p => project.projectService.fileExists(p as NormalizedPath), + ); } function getMappedDocumentSpanForProject(documentSpan: DocumentSpan, project: Project): DocumentSpan | undefined { - return getMappedDocumentSpan(documentSpan, project.getSourceMapper(), p => project.projectService.fileExists(p as NormalizedPath)); + return getMappedDocumentSpan( + documentSpan, + project.getSourceMapper(), + p => project.projectService.fileExists(p as NormalizedPath), + ); } function getMappedContextSpanForProject(documentSpan: DocumentSpan, project: Project): TextSpan | undefined { - return getMappedContextSpan(documentSpan, project.getSourceMapper(), p => project.projectService.fileExists(p as NormalizedPath)); + return getMappedContextSpan( + documentSpan, + project.getSourceMapper(), + p => project.projectService.fileExists(p as NormalizedPath), + ); } const invalidPartialSemanticModeCommands: readonly protocol.CommandTypes[] = [ @@ -993,7 +1073,7 @@ export class Session implements EventSender { getServerHost: () => this.host, logError: (err, cmd) => this.logError(err, cmd), sendRequestCompletedEvent: requestId => this.sendRequestCompletedEvent(requestId), - isCancellationRequested: () => this.cancellationToken.isCancellationRequested() + isCancellationRequested: () => this.cancellationToken.isCancellationRequested(), }; this.errorCheck = new MultistepOperation(multistepOperationHost); const settings: ProjectServiceOptions = { @@ -1025,7 +1105,9 @@ export class Session implements EventSender { case LanguageServiceMode.PartialSemantic: invalidPartialSemanticModeCommands.forEach(commandName => this.handlers.set(commandName, request => { - throw new Error(`Request: ${request.command} not allowed in LanguageServiceMode.PartialSemantic`); + throw new Error( + `Request: ${request.command} not allowed in LanguageServiceMode.PartialSemantic`, + ); }) ); break; @@ -1073,30 +1155,40 @@ export class Session implements EventSender { const { project, reason } = event.data; this.event( { projectName: project.getProjectName(), reason }, - ProjectLoadingStartEvent); + ProjectLoadingStartEvent, + ); break; case ProjectLoadingFinishEvent: const { project: finishProject } = event.data; - this.event({ projectName: finishProject.getProjectName() }, ProjectLoadingFinishEvent); + this.event( + { projectName: finishProject.getProjectName() }, + ProjectLoadingFinishEvent, + ); break; case LargeFileReferencedEvent: const { file, fileSize, maxFileSize } = event.data; - this.event({ file, fileSize, maxFileSize }, LargeFileReferencedEvent); + this.event( + { file, fileSize, maxFileSize }, + LargeFileReferencedEvent, + ); break; case ConfigFileDiagEvent: const { triggerFile, configFileName: configFile, diagnostics } = event.data; - const bakedDiags = map(diagnostics, diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ true)); + const bakedDiags = map( + diagnostics, + diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ true), + ); this.event({ triggerFile, configFile, - diagnostics: bakedDiags + diagnostics: bakedDiags, }, ConfigFileDiagEvent); break; case ProjectLanguageServiceStateEvent: { const eventName: protocol.ProjectLanguageServiceStateEventName = ProjectLanguageServiceStateEvent; this.event({ projectName: event.data.project.getProjectName(), - languageServiceEnabled: event.data.languageServiceEnabled + languageServiceEnabled: event.data.languageServiceEnabled, }, eventName); break; } @@ -1121,7 +1213,7 @@ export class Session implements EventSender { // Send project changed event this.event({ - openFiles + openFiles, }, ProjectsUpdatedInBackgroundEvent); } } @@ -1130,7 +1222,11 @@ export class Session implements EventSender { this.logErrorWorker(err, cmd); } - private logErrorWorker(err: Error & PossibleProgramFileInfo, cmd: string, fileRequest?: protocol.FileRequestArgs): void { + private logErrorWorker( + err: Error & PossibleProgramFileInfo, + cmd: string, + fileRequest?: protocol.FileRequestArgs, + ): void { let msg = "Exception on executing command " + cmd; if (err.message) { msg += ":\n" + indent(err.message); @@ -1149,10 +1245,9 @@ export class Session implements EventSender { msg += `\n\nFile text of ${fileRequest.file}:${indent(text)}\n`; } } - catch { } // eslint-disable-line no-empty + catch {} // eslint-disable-line no-empty } - if (err.ProgramFiles) { msg += `\n\nProgram files: ${JSON.stringify(err.ProgramFiles)}\n`; msg += `\n\nProjects::\n`; @@ -1200,7 +1295,7 @@ export class Session implements EventSender { command: cmdName, request_seq: reqSeq, success, - performanceData: this.performanceData + performanceData: this.performanceData, }; if (success) { @@ -1212,7 +1307,7 @@ export class Session implements EventSender { } else if (typeof info === "object") { if ((info as WithMetadata<{}>).metadata) { - const { metadata: infoMetadata, ...body } = (info as WithMetadata<{}>); + const { metadata: infoMetadata, ...body } = info as WithMetadata<{}>; res.body = body; metadata = infoMetadata; } @@ -1235,7 +1330,10 @@ export class Session implements EventSender { } private semanticCheck(file: NormalizedPath, project: Project) { - tracing?.push(tracing.Phase.Session, "semanticCheck", { file, configFilePath: (project as ConfiguredProject).canonicalConfigFilePath }); // undefined is fine if the cast fails + 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 : project.getLanguageService().getSemanticDiagnostics(file).filter(d => !!d.file); @@ -1244,20 +1342,44 @@ export class Session implements EventSender { } private syntacticCheck(file: NormalizedPath, project: Project) { - 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"); + 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", + ); tracing?.pop(); } private suggestionCheck(file: NormalizedPath, project: Project) { - 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"); + 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", + ); tracing?.pop(); } - private sendDiagnosticsEvent(file: NormalizedPath, project: Project, diagnostics: readonly Diagnostic[], kind: protocol.DiagnosticEventKind): void { + private sendDiagnosticsEvent( + file: NormalizedPath, + project: Project, + diagnostics: readonly Diagnostic[], + kind: protocol.DiagnosticEventKind, + ): void { try { - this.event({ file, diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)) }, kind); + this.event({ + file, + diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)), + }, kind); } catch (err) { this.logError(err, kind); @@ -1265,7 +1387,12 @@ export class Session implements EventSender { } /** It is the caller's responsibility to verify that `!this.suppressDiagnosticEvents`. */ - private updateErrorCheck(next: NextStep, checkList: readonly string[] | readonly PendingErrorCheck[], ms: number, requireOpen = true) { + private updateErrorCheck( + next: NextStep, + checkList: readonly string[] | readonly PendingErrorCheck[], + ms: number, + requireOpen = true, + ) { Debug.assert(!this.suppressDiagnosticEvents); // Caller's responsibility const seq = this.changeSeq; @@ -1362,7 +1489,8 @@ export class Session implements EventSender { private getEncodedSemanticClassifications(args: protocol.EncodedSemanticClassificationsRequestArgs) { const { file, project } = this.getFileAndProject(args); - const format = args.format === "2020" ? SemanticClassificationFormat.TwentyTwenty : SemanticClassificationFormat.Original; + const format = args.format === "2020" ? SemanticClassificationFormat.TwentyTwenty + : SemanticClassificationFormat.Original; return project.getLanguageService().getEncodedSemanticClassifications(file, args, format); } @@ -1370,13 +1498,15 @@ export class Session implements EventSender { return projectFileName === undefined ? undefined : this.projectService.findProject(projectFileName); } - private getConfigFileAndProject(args: protocol.FileRequestArgs): { configFile: NormalizedPath | undefined, project: Project | undefined } { + private getConfigFileAndProject( + args: protocol.FileRequestArgs, + ): { configFile: NormalizedPath | undefined; project: Project | undefined; } { const project = this.getProject(args.projectFileName); const file = toNormalizedPath(args.file); return { configFile: project && project.hasConfigFile(file) ? file : undefined, - project + project, }; } @@ -1385,17 +1515,19 @@ export class Session implements EventSender { const optionsErrors = project.getLanguageService().getCompilerOptionsDiagnostics(); const diagnosticsForConfigFile = filter( concatenate(projectErrors, optionsErrors), - diagnostic => !!diagnostic.file && diagnostic.file.fileName === configFile + diagnostic => !!diagnostic.file && diagnostic.file.fileName === configFile, ); - return includeLinePosition ? - this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnosticsForConfigFile) : - map( + return includeLinePosition + ? this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnosticsForConfigFile) + : map( diagnosticsForConfigFile, - diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ false) + diagnostic => formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ false), ); } - private convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics: readonly Diagnostic[]): protocol.DiagnosticWithLinePosition[] { + private convertToDiagnosticsWithLinePositionFromDiagnosticFile( + diagnostics: readonly Diagnostic[], + ): protocol.DiagnosticWithLinePosition[] { return diagnostics.map(d => ({ message: flattenDiagnosticMessageText(d.messageText, this.host.newLine), start: d.start!, // TODO: GH#18217 @@ -1407,7 +1539,7 @@ export class Session implements EventSender { endLocation: (d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start! + d.length!)))!, // TODO: GH#18217 reportsUnnecessary: d.reportsUnnecessary, reportsDeprecated: d.reportsDeprecated, - relatedInformation: map(d.relatedInformation, formatRelatedInformation) + relatedInformation: map(d.relatedInformation, formatRelatedInformation), })); } @@ -1419,30 +1551,38 @@ export class Session implements EventSender { return this.convertToDiagnosticsWithLinePosition( filter( project.getLanguageService().getCompilerOptionsDiagnostics(), - diagnostic => !diagnostic.file + diagnostic => !diagnostic.file, ), - /*scriptInfo*/ undefined + /*scriptInfo*/ undefined, ); } - private convertToDiagnosticsWithLinePosition(diagnostics: readonly Diagnostic[], scriptInfo: ScriptInfo | undefined): protocol.DiagnosticWithLinePosition[] { - return diagnostics.map(d => ({ - message: flattenDiagnosticMessageText(d.messageText, this.host.newLine), - start: d.start, - length: d.length, - category: diagnosticCategoryName(d), - code: d.code, - source: d.source, - startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start!), // TODO: GH#18217 - endLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start! + d.length!), - reportsUnnecessary: d.reportsUnnecessary, - reportsDeprecated: d.reportsDeprecated, - relatedInformation: map(d.relatedInformation, formatRelatedInformation), - }) as protocol.DiagnosticWithLinePosition); + private convertToDiagnosticsWithLinePosition( + diagnostics: readonly Diagnostic[], + scriptInfo: ScriptInfo | undefined, + ): protocol.DiagnosticWithLinePosition[] { + return diagnostics.map(d => + ({ + message: flattenDiagnosticMessageText(d.messageText, this.host.newLine), + start: d.start, + length: d.length, + category: diagnosticCategoryName(d), + code: d.code, + source: d.source, + startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start!), // TODO: GH#18217 + endLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start! + d.length!), + reportsUnnecessary: d.reportsUnnecessary, + reportsDeprecated: d.reportsDeprecated, + relatedInformation: map(d.relatedInformation, formatRelatedInformation), + }) as protocol.DiagnosticWithLinePosition + ); } private getDiagnosticsWorker( - args: protocol.FileRequestArgs, isSemantic: boolean, selector: (project: Project, file: string) => readonly Diagnostic[], includeLinePosition: boolean + args: protocol.FileRequestArgs, + isSemantic: boolean, + selector: (project: Project, file: string) => readonly Diagnostic[], + includeLinePosition: boolean, ): readonly protocol.DiagnosticWithLinePosition[] | readonly protocol.Diagnostic[] { const { project, file } = this.getFileAndProject(args); if (isSemantic && isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) { @@ -1455,14 +1595,24 @@ export class Session implements EventSender { : diagnostics.map(d => formatDiag(file, project, d)); } - private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): readonly protocol.FileSpanWithContext[] | readonly DefinitionInfo[] { + private getDefinition( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.FileSpanWithContext[] | readonly DefinitionInfo[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - const definitions = this.mapDefinitionInfoLocations(project.getLanguageService().getDefinitionAtPosition(file, position) || emptyArray, project); - return simplifiedResult ? this.mapDefinitionInfo(definitions, project) : definitions.map(Session.mapToOriginalLocation); + const definitions = this.mapDefinitionInfoLocations( + project.getLanguageService().getDefinitionAtPosition(file, position) || emptyArray, + project, + ); + return simplifiedResult ? this.mapDefinitionInfo(definitions, project) + : definitions.map(Session.mapToOriginalLocation); } - private mapDefinitionInfoLocations(definitions: readonly DefinitionInfo[], project: Project): readonly DefinitionInfo[] { + private mapDefinitionInfoLocations( + definitions: readonly DefinitionInfo[], + project: Project, + ): readonly DefinitionInfo[] { return definitions.map((info): DefinitionInfo => { const newDocumentSpan = getMappedDocumentSpanForProject(info, project); return !newDocumentSpan ? info : { @@ -1477,7 +1627,10 @@ export class Session implements EventSender { }); } - private getDefinitionAndBoundSpan(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.DefinitionInfoAndBoundSpan | DefinitionInfoAndBoundSpan { + private getDefinitionAndBoundSpan( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): protocol.DefinitionInfoAndBoundSpan | DefinitionInfoAndBoundSpan { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); const scriptInfo = Debug.checkDefined(project.getScriptInfo(file)); @@ -1487,7 +1640,7 @@ export class Session implements EventSender { if (!unmappedDefinitionAndBoundSpan || !unmappedDefinitionAndBoundSpan.definitions) { return { definitions: emptyArray, - textSpan: undefined! // TODO: GH#18217 + textSpan: undefined!, // TODO: GH#18217 }; } @@ -1497,7 +1650,7 @@ export class Session implements EventSender { if (simplifiedResult) { return { definitions: this.mapDefinitionInfo(definitions, project), - textSpan: toProtocolTextSpan(textSpan, scriptInfo) + textSpan: toProtocolTextSpan(textSpan, scriptInfo), }; } @@ -1511,22 +1664,35 @@ export class Session implements EventSender { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); const unmappedDefinitions = project.getLanguageService().getDefinitionAtPosition(file, position); - let definitions: readonly DefinitionInfo[] = this.mapDefinitionInfoLocations(unmappedDefinitions || emptyArray, project).slice(); + let definitions: readonly DefinitionInfo[] = this.mapDefinitionInfoLocations( + unmappedDefinitions || emptyArray, + project, + ).slice(); const needsJsResolution = this.projectService.serverMode === LanguageServiceMode.Semantic && ( - !some(definitions, d => toNormalizedPath(d.fileName) !== file && !d.isAmbient) || - some(definitions, d => !!d.failedAliasResolution)); + !some(definitions, d => toNormalizedPath(d.fileName) !== file && !d.isAmbient) + || some(definitions, d => !!d.failedAliasResolution) + ); if (needsJsResolution) { const definitionSet = createSet(d => d.textSpan.start, documentSpansEqual); definitions?.forEach(d => definitionSet.add(d)); const noDtsProject = project.getNoDtsResolutionProject([file]); const ls = noDtsProject.getLanguageService(); - const jsDefinitions = ls.getDefinitionAtPosition(file, position, /*searchOtherFilesOnly*/ true, /*stopAtAlias*/ false) + const jsDefinitions = ls.getDefinitionAtPosition( + file, + position, + /*searchOtherFilesOnly*/ true, + /*stopAtAlias*/ false, + ) ?.filter(d => toNormalizedPath(d.fileName) !== file); if (some(jsDefinitions)) { for (const jsDefinition of jsDefinitions) { if (jsDefinition.unverified) { - const refined = tryRefineDefinition(jsDefinition, project.getLanguageService().getProgram()!, ls.getProgram()!); + const refined = tryRefineDefinition( + jsDefinition, + project.getLanguageService().getProgram()!, + ls.getProgram()!, + ); if (some(refined)) { for (const def of refined) { definitionSet.add(def); @@ -1539,8 +1705,15 @@ export class Session implements EventSender { } else { const ambientCandidates = definitions.filter(d => toNormalizedPath(d.fileName) !== file && d.isAmbient); - for (const candidate of some(ambientCandidates) ? ambientCandidates : getAmbientCandidatesByClimbingAccessChain()) { - const fileNameToSearch = findImplementationFileFromDtsFileName(candidate.fileName, file, noDtsProject); + for ( + const candidate of some(ambientCandidates) ? ambientCandidates + : getAmbientCandidatesByClimbingAccessChain() + ) { + const fileNameToSearch = findImplementationFileFromDtsFileName( + candidate.fileName, + file, + noDtsProject, + ); if (!fileNameToSearch || !ensureRoot(noDtsProject, fileNameToSearch)) { continue; } @@ -1557,14 +1730,24 @@ export class Session implements EventSender { definitions = definitions.filter(d => !d.isAmbient && !d.failedAliasResolution); return this.mapDefinitionInfo(definitions, project); - function findImplementationFileFromDtsFileName(fileName: string, resolveFromFile: string, auxiliaryProject: Project) { + function findImplementationFileFromDtsFileName( + fileName: string, + resolveFromFile: string, + auxiliaryProject: Project, + ) { const nodeModulesPathParts = getNodeModulePathParts(fileName); - if (nodeModulesPathParts && fileName.lastIndexOf(nodeModulesPathPart) === nodeModulesPathParts.topLevelNodeModulesIndex) { + if ( + nodeModulesPathParts + && fileName.lastIndexOf(nodeModulesPathPart) === nodeModulesPathParts.topLevelNodeModulesIndex + ) { // Second check ensures the fileName only contains one `/node_modules/`. If there's more than one I give up. const packageDirectory = fileName.substring(0, nodeModulesPathParts.packageRootIndex); const packageJsonCache = project.getModuleResolutionCache()?.getPackageJsonInfoCache(); const compilerOptions = project.getCompilationSettings(); - const packageJson = getPackageScopeForPath(getNormalizedAbsolutePath(packageDirectory + "/package.json", project.getCurrentDirectory()), getTemporaryModuleResolutionState(packageJsonCache, project, compilerOptions)); + const packageJson = getPackageScopeForPath( + getNormalizedAbsolutePath(packageDirectory + "/package.json", project.getCurrentDirectory()), + getTemporaryModuleResolutionState(packageJsonCache, project, compilerOptions), + ); if (!packageJson) return undefined; // Use fake options instead of actual compiler options to avoid following export map if the project uses node16 or nodenext - // Mapping from an export map entry across packages is out of scope for now. Returned entrypoints will only be what can be @@ -1573,23 +1756,31 @@ export class Session implements EventSender { packageJson, { moduleResolution: ModuleResolutionKind.Node10 }, project, - project.getModuleResolutionCache()); + project.getModuleResolutionCache(), + ); // This substring is correct only because we checked for a single `/node_modules/` at the top. const packageNamePathPart = fileName.substring( nodeModulesPathParts.topLevelPackageNameIndex + 1, - nodeModulesPathParts.packageRootIndex); + nodeModulesPathParts.packageRootIndex, + ); const packageName = getPackageNameFromTypesPackageName(unmangleScopedPackageName(packageNamePathPart)); const path = project.toPath(fileName); if (entrypoints && some(entrypoints, e => project.toPath(e) === path)) { // This file was the main entrypoint of a package. Try to resolve that same package name with // the auxiliary project that only resolves to implementation files. - return auxiliaryProject.resolutionCache.resolveSingleModuleNameWithoutWatching(packageName, resolveFromFile).resolvedModule?.resolvedFileName; + return auxiliaryProject.resolutionCache.resolveSingleModuleNameWithoutWatching( + packageName, + resolveFromFile, + ).resolvedModule?.resolvedFileName; } else { // It wasn't the main entrypoint but we are in node_modules. Try a subpath into the package. const pathToFileInPackage = fileName.substring(nodeModulesPathParts.packageRootIndex + 1); const specifier = `${packageName}/${removeFileExtension(pathToFileInPackage)}`; - return auxiliaryProject.resolutionCache.resolveSingleModuleNameWithoutWatching(specifier, resolveFromFile).resolvedModule?.resolvedFileName; + return auxiliaryProject.resolutionCache.resolveSingleModuleNameWithoutWatching( + specifier, + resolveFromFile, + ).resolvedModule?.resolvedFileName; } } // We're not in node_modules, and we only get to this function if non-dts module resolution failed. @@ -1599,18 +1790,26 @@ export class Session implements EventSender { // In 'foo.bar./**/baz', if we got not results on 'baz', see if we can get an ambient definition // for 'bar' or 'foo' (in that order) so we can search for declarations of 'baz' later. - function getAmbientCandidatesByClimbingAccessChain(): readonly { name: string, fileName: string }[] { + function getAmbientCandidatesByClimbingAccessChain(): readonly { name: string; fileName: string; }[] { const ls = project.getLanguageService(); const program = ls.getProgram()!; const initialNode = getTouchingPropertyName(program.getSourceFile(file)!, position); - if ((isStringLiteralLike(initialNode) || isIdentifier(initialNode)) && isAccessExpression(initialNode.parent)) { + if ( + (isStringLiteralLike(initialNode) || isIdentifier(initialNode)) + && isAccessExpression(initialNode.parent) + ) { return forEachNameInAccessChainWalkingLeft(initialNode, nameInChain => { if (nameInChain === initialNode) return undefined; - const candidates = ls.getDefinitionAtPosition(file, nameInChain.getStart(), /*searchOtherFilesOnly*/ true, /*stopAtAlias*/ false) + const candidates = ls.getDefinitionAtPosition( + file, + nameInChain.getStart(), + /*searchOtherFilesOnly*/ true, + /*stopAtAlias*/ false, + ) ?.filter(d => toNormalizedPath(d.fileName) !== file && d.isAmbient) .map(d => ({ fileName: d.fileName, - name: getTextOfIdentifierOrLiteral(initialNode) + name: getTextOfIdentifierOrLiteral(initialNode), })); if (some(candidates)) { return candidates; @@ -1642,7 +1841,13 @@ export class Session implements EventSender { if (symbol && decl) { // I think the last argument to this is supposed to be the start node, but it doesn't seem important. // Callers internal to GoToDefinition already get confused about this. - return GoToDefinition.createDefinitionInfo(decl, noDtsProgram.getTypeChecker(), symbol, decl, /*unverified*/ true); + return GoToDefinition.createDefinitionInfo( + decl, + noDtsProgram.getTypeChecker(), + symbol, + decl, + /*unverified*/ true, + ); } }); } @@ -1664,20 +1869,24 @@ export class Session implements EventSender { return { emitSkipped: true, outputFiles: [], diagnostics: [] }; } const result = project.getLanguageService().getEmitOutput(file); - return args.richResponse ? - { + return args.richResponse + ? { ...result, - diagnostics: args.includeLinePosition ? - this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(result.diagnostics) : - result.diagnostics.map(d => formatDiagnosticToProtocol(d, /*includeFileName*/ true)) - } : - result; + diagnostics: args.includeLinePosition + ? this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(result.diagnostics) + : result.diagnostics.map(d => formatDiagnosticToProtocol(d, /*includeFileName*/ true)), + } + : result; } - private mapJSDocTagInfo(tags: JSDocTagInfo[] | undefined, project: Project, richResponse: boolean): protocol.JSDocTagInfo[] { + private mapJSDocTagInfo( + tags: JSDocTagInfo[] | undefined, + project: Project, + richResponse: boolean, + ): protocol.JSDocTagInfo[] { return tags ? tags.map(tag => ({ ...tag, - text: richResponse ? this.mapDisplayParts(tag.text, project) : tag.text?.map(part => part.text).join("") + text: richResponse ? this.mapDisplayParts(tag.text, project) : tag.text?.map(part => part.text).join(""), })) : []; } @@ -1685,23 +1894,42 @@ export class Session implements EventSender { if (!parts) { return []; } - return parts.map(part => part.kind !== "linkName" ? part : { - ...part, - target: this.toFileSpan((part as JSDocLinkDisplayPart).target.fileName, (part as JSDocLinkDisplayPart).target.textSpan, project), - }); + return parts.map(part => + part.kind !== "linkName" ? part : { + ...part, + target: this.toFileSpan( + (part as JSDocLinkDisplayPart).target.fileName, + (part as JSDocLinkDisplayPart).target.textSpan, + project, + ), + } + ); } - private mapSignatureHelpItems(items: SignatureHelpItem[], project: Project, richResponse: boolean): protocol.SignatureHelpItem[] { + private mapSignatureHelpItems( + items: SignatureHelpItem[], + project: Project, + richResponse: boolean, + ): protocol.SignatureHelpItem[] { return items.map(item => ({ ...item, documentation: this.mapDisplayParts(item.documentation, project), - parameters: item.parameters.map(p => ({ ...p, documentation: this.mapDisplayParts(p.documentation, project) })), + parameters: item.parameters.map(p => ({ + ...p, + documentation: this.mapDisplayParts(p.documentation, project), + })), tags: this.mapJSDocTagInfo(item.tags, project, richResponse), })); } - private mapDefinitionInfo(definitions: readonly DefinitionInfo[], project: Project): readonly protocol.DefinitionInfo[] { - return definitions.map(def => ({ ...this.toFileSpanWithContext(def.fileName, def.textSpan, def.contextSpan, project), ...def.unverified && { unverified: def.unverified } })); + private mapDefinitionInfo( + definitions: readonly DefinitionInfo[], + project: Project, + ): readonly protocol.DefinitionInfo[] { + return definitions.map(def => ({ + ...this.toFileSpanWithContext(def.fileName, def.textSpan, def.contextSpan, project), + ...def.unverified && { unverified: def.unverified }, + })); } /* @@ -1710,10 +1938,13 @@ export class Session implements EventSender { * This retains the existing behavior for the "simplified" (VS Code) protocol but stores the .d.ts location in a * set of additional fields, and does the reverse for VS (store the .d.ts location where * it used to be and stores the .ts location in the additional fields). - */ + */ private static mapToOriginalLocation(def: T): T { if (def.originalFileName) { - Debug.assert(def.originalTextSpan !== undefined, "originalTextSpan should be present if originalFileName is"); + Debug.assert( + def.originalTextSpan !== undefined, + "originalTextSpan should be present if originalFileName is", + ); return { ...def as any, fileName: def.originalFileName, @@ -1721,7 +1952,7 @@ export class Session implements EventSender { targetFileName: def.fileName, targetTextSpan: def.textSpan, contextSpan: def.originalContextSpan, - targetContextSpan: def.contextSpan + targetContextSpan: def.contextSpan, }; } return def; @@ -1735,27 +1966,38 @@ export class Session implements EventSender { return { file: fileName, start: { line: start.line + 1, offset: start.character + 1 }, - end: { line: end.line + 1, offset: end.character + 1 } + end: { line: end.line + 1, offset: end.character + 1 }, }; } - private toFileSpanWithContext(fileName: string, textSpan: TextSpan, contextSpan: TextSpan | undefined, project: Project): protocol.FileSpanWithContext { + private toFileSpanWithContext( + fileName: string, + textSpan: TextSpan, + contextSpan: TextSpan | undefined, + project: Project, + ): protocol.FileSpanWithContext { const fileSpan = this.toFileSpan(fileName, textSpan, project); const context = contextSpan && this.toFileSpan(fileName, contextSpan, project); - return context ? - { ...fileSpan, contextStart: context.start, contextEnd: context.end } : - fileSpan; + return context + ? { ...fileSpan, contextStart: context.start, contextEnd: context.end } + : fileSpan; } private getTypeDefinition(args: protocol.FileLocationRequestArgs): readonly protocol.FileSpanWithContext[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - const definitions = this.mapDefinitionInfoLocations(project.getLanguageService().getTypeDefinitionAtPosition(file, position) || emptyArray, project); + const definitions = this.mapDefinitionInfoLocations( + project.getLanguageService().getTypeDefinitionAtPosition(file, position) || emptyArray, + project, + ); return this.mapDefinitionInfo(definitions, project); } - private mapImplementationLocations(implementations: readonly ImplementationLocation[], project: Project): readonly ImplementationLocation[] { + private mapImplementationLocations( + implementations: readonly ImplementationLocation[], + project: Project, + ): readonly ImplementationLocation[] { return implementations.map((info): ImplementationLocation => { const newDocumentSpan = getMappedDocumentSpanForProject(info, project); return !newDocumentSpan ? info : { @@ -1766,13 +2008,21 @@ export class Session implements EventSender { }); } - private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): readonly protocol.FileSpanWithContext[] | readonly ImplementationLocation[] { + private getImplementation( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.FileSpanWithContext[] | readonly ImplementationLocation[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - const implementations = this.mapImplementationLocations(project.getLanguageService().getImplementationAtPosition(file, position) || emptyArray, project); - return simplifiedResult ? - implementations.map(({ fileName, textSpan, contextSpan }) => this.toFileSpanWithContext(fileName, textSpan, contextSpan, project)) : - implementations.map(Session.mapToOriginalLocation); + const implementations = this.mapImplementationLocations( + project.getLanguageService().getImplementationAtPosition(file, position) || emptyArray, + project, + ); + return simplifiedResult + ? implementations.map(({ fileName, textSpan, contextSpan }) => + this.toFileSpanWithContext(fileName, textSpan, contextSpan, project) + ) + : implementations.map(Session.mapToOriginalLocation); } private getSyntacticDiagnosticsSync(args: protocol.SyntacticDiagnosticsSyncRequestArgs) { @@ -1782,7 +2032,12 @@ export class Session implements EventSender { return emptyArray; } - return this.getDiagnosticsWorker(args, /*isSemantic*/ false, (project, file) => project.getLanguageService().getSyntacticDiagnostics(file), !!args.includeLinePosition); + return this.getDiagnosticsWorker( + args, + /*isSemantic*/ false, + (project, file) => project.getLanguageService().getSyntacticDiagnostics(file), + !!args.includeLinePosition, + ); } private getSemanticDiagnosticsSync(args: protocol.SemanticDiagnosticsSyncRequestArgs) { @@ -1790,7 +2045,12 @@ export class Session implements EventSender { if (configFile) { return this.getConfigFileDiagnostics(configFile, project!, !!args.includeLinePosition); // TODO: GH#18217 } - return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file).filter(d => !!d.file), !!args.includeLinePosition); + return this.getDiagnosticsWorker( + args, + /*isSemantic*/ true, + (project, file) => project.getLanguageService().getSemanticDiagnostics(file).filter(d => !!d.file), + !!args.includeLinePosition, + ); } private getSuggestionDiagnosticsSync(args: protocol.SuggestionDiagnosticsSyncRequestArgs) { @@ -1800,7 +2060,12 @@ export class Session implements EventSender { return emptyArray; } // isSemantic because we don't want to info diagnostics in declaration files for JS-only users - return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSuggestionDiagnostics(file), !!args.includeLinePosition); + return this.getDiagnosticsWorker( + args, + /*isSemantic*/ true, + (project, file) => project.getLanguageService().getSuggestionDiagnostics(file), + !!args.includeLinePosition, + ); } private getJsxClosingTag(args: protocol.JsxClosingTagRequestArgs): TextInsertion | undefined { @@ -1810,7 +2075,9 @@ export class Session implements EventSender { return tag === undefined ? undefined : { newText: tag.newText, caretOffset: 0 }; } - private getLinkedEditingRange(args: protocol.FileLocationRequestArgs): protocol.LinkedEditingRangesBody | undefined { + private getLinkedEditingRange( + args: protocol.FileLocationRequestArgs, + ): protocol.LinkedEditingRangesBody | undefined { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const position = this.getPositionInFile(args, file); const linkedEditInfo = languageService.getLinkedEditingRangeAtPosition(file, position); @@ -1819,10 +2086,17 @@ export class Session implements EventSender { return convertLinkedEditInfoToRanges(linkedEditInfo, scriptInfo); } - private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] { + private getDocumentHighlights( + args: protocol.DocumentHighlightsRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.DocumentHighlightsItem[] | readonly DocumentHighlights[] { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); - const documentHighlights = project.getLanguageService().getDocumentHighlights(file, position, args.filesToSearch); + const documentHighlights = project.getLanguageService().getDocumentHighlights( + file, + position, + args.filesToSearch, + ); if (!documentHighlights) return emptyArray; if (!simplifiedResult) return documentHighlights; @@ -1833,8 +2107,8 @@ export class Session implements EventSender { file: fileName, highlightSpans: highlightSpans.map(({ textSpan, kind, contextSpan }) => ({ ...toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo), - kind - })) + kind, + })), }; }); } @@ -1855,8 +2129,8 @@ export class Session implements EventSender { span: span && { start: scriptInfo.positionToLineOffset(span.start), end: scriptInfo.positionToLineOffset(span.start + span.length), - file: file! - } + file: file!, + }, })), }; }); @@ -1867,16 +2141,27 @@ export class Session implements EventSender { } private getProjectInfo(args: protocol.ProjectInfoRequestArgs): protocol.ProjectInfo { - return this.getProjectInfoWorker(args.file, args.projectFileName, args.needFileNameList, /*excludeConfigFiles*/ false); + return this.getProjectInfoWorker( + args.file, + args.projectFileName, + args.needFileNameList, + /*excludeConfigFiles*/ false, + ); } - private getProjectInfoWorker(uncheckedFileName: string, projectFileName: string | undefined, needFileNameList: boolean, excludeConfigFiles: boolean) { + private getProjectInfoWorker( + uncheckedFileName: string, + projectFileName: string | undefined, + needFileNameList: boolean, + excludeConfigFiles: boolean, + ) { const { project } = this.getFileAndProjectWorker(uncheckedFileName, projectFileName); updateProjectIfDirty(project); const projectInfo = { configFileName: project.getProjectName(), languageServiceDisabled: !project.languageServiceEnabled, - fileNames: needFileNameList ? project.getFileNames(/*excludeFilesFromExternalLibraries*/ false, excludeConfigFiles) : undefined + fileNames: needFileNameList + ? project.getFileNames(/*excludeFilesFromExternalLibraries*/ false, excludeConfigFiles) : undefined, }; return projectInfo; } @@ -1888,7 +2173,11 @@ export class Session implements EventSender { return project.getLanguageService().getRenameInfo(file, position, preferences); } - private getProjects(args: protocol.FileRequestArgs, getScriptInfoEnsuringProjectsUptoDate?: boolean, ignoreNoProjectError?: boolean): Projects { + private getProjects( + args: protocol.FileRequestArgs, + getScriptInfoEnsuringProjectsUptoDate?: boolean, + ignoreNoProjectError?: boolean, + ): Projects { let projects: readonly Project[] | undefined; let symLinkedProjects: MultiMap | undefined; if (args.projectFileName) { @@ -1898,9 +2187,9 @@ export class Session implements EventSender { } } else { - const scriptInfo = getScriptInfoEnsuringProjectsUptoDate ? - this.projectService.getScriptInfoEnsuringProjectsUptoDate(args.file) : - this.projectService.getScriptInfo(args.file); + const scriptInfo = getScriptInfoEnsuringProjectsUptoDate + ? this.projectService.getScriptInfoEnsuringProjectsUptoDate(args.file) + : this.projectService.getScriptInfo(args.file); if (!scriptInfo) { if (ignoreNoProjectError) return emptyArray; this.projectService.logErrorForScriptInfoNotFound(args.file); @@ -1936,14 +2225,19 @@ export class Session implements EventSender { return info.getDefaultProject(); } - private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | readonly RenameLocation[] { + private getRenameLocations( + args: protocol.RenameRequestArgs, + simplifiedResult: boolean, + ): protocol.RenameResponseBody | readonly RenameLocation[] { const file = toNormalizedPath(args.file); const position = this.getPositionInFile(args, file); const projects = this.getProjects(args); const defaultProject = this.getDefaultProject(args); const preferences = this.getPreferences(file); const renameInfo: protocol.RenameInfo = this.mapRenameInfo( - defaultProject.getLanguageService().getRenameInfo(file, position, preferences), Debug.checkDefined(this.projectService.getScriptInfo(file))); + defaultProject.getLanguageService().getRenameInfo(file, position, preferences), + Debug.checkDefined(this.projectService.getScriptInfo(file)), + ); if (!renameInfo.canRename) return simplifiedResult ? { info: renameInfo, locs: [] } : []; @@ -1963,7 +2257,16 @@ export class Session implements EventSender { if (info.canRename) { const { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan } = info; return identity( - { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: toProtocolTextSpan(triggerSpan, scriptInfo) }); + { + canRename, + fileToRename, + displayName, + fullDisplayName, + kind, + kindModifiers, + triggerSpan: toProtocolTextSpan(triggerSpan, scriptInfo), + }, + ); } else { return info; @@ -1972,16 +2275,32 @@ export class Session implements EventSender { private toSpanGroups(locations: readonly RenameLocation[]): readonly protocol.SpanGroup[] { const map = new Map(); - for (const { fileName, textSpan, contextSpan, originalContextSpan: _2, originalTextSpan: _, originalFileName: _1, ...prefixSuffixText } of locations) { + for ( + const { + fileName, + textSpan, + contextSpan, + originalContextSpan: _2, + originalTextSpan: _, + originalFileName: _1, + ...prefixSuffixText + } of locations + ) { let group = map.get(fileName); if (!group) map.set(fileName, group = { file: fileName, locs: [] }); const scriptInfo = Debug.checkDefined(this.projectService.getScriptInfo(fileName)); - group.locs.push({ ...toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo), ...prefixSuffixText }); + group.locs.push({ + ...toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo), + ...prefixSuffixText, + }); } return arrayFrom(map.values()); } - private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | readonly ReferencedSymbol[] { + private getReferences( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): protocol.ReferencesResponseBody | readonly ReferencedSymbol[] { const file = toNormalizedPath(args.file); const projects = this.getProjects(args); const position = this.getPositionInFile(args, file); @@ -2003,12 +2322,17 @@ export class Session implements EventSender { const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0; const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : ""; const refs: readonly protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol => { - return referencedSymbol.references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences)); + return referencedSymbol.references.map(entry => + referenceEntryToReferencesResponseItem(this.projectService, entry, preferences) + ); }); return { refs, symbolName, symbolStartOffset, symbolDisplayString }; } - private getFileReferences(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.FileReferencesResponseBody | readonly ReferenceEntry[] { + private getFileReferences( + args: protocol.FileRequestArgs, + simplifiedResult: boolean, + ): protocol.FileReferencesResponseBody | readonly ReferenceEntry[] { const projects = this.getProjects(args); const fileName = args.file; const preferences = this.getPreferences(toNormalizedPath(fileName)); @@ -2031,10 +2355,12 @@ export class Session implements EventSender { }); if (!simplifiedResult) return references; - const refs = references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences)); + const refs = references.map(entry => + referenceEntryToReferencesResponseItem(this.projectService, entry, preferences) + ); return { refs, - symbolName: `"${args.file}"` + symbolName: `"${args.file}"`, }; } @@ -2042,15 +2368,26 @@ export class Session implements EventSender { * @param fileName is the name of the file to be opened * @param fileContent is a version of the file content that is known to be more up to date than the one on disk */ - private openClientFile(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: NormalizedPath) { - this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath); + private openClientFile( + fileName: NormalizedPath, + fileContent?: string, + scriptKind?: ScriptKind, + projectRootPath?: NormalizedPath, + ) { + this.projectService.openClientFileWithNormalizedPath( + fileName, + fileContent, + scriptKind, + /*hasMixedContent*/ false, + projectRootPath, + ); } - private getPosition(args: protocol.Location & { position?: number }, scriptInfo: ScriptInfo): number { + private getPosition(args: protocol.Location & { position?: number; }, scriptInfo: ScriptInfo): number { return args.position !== undefined ? args.position : scriptInfo.lineOffsetToPosition(args.line, args.offset); } - private getPositionInFile(args: protocol.Location & { position?: number }, file: NormalizedPath): number { + private getPositionInFile(args: protocol.Location & { position?: number; }, file: NormalizedPath): number { const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; return this.getPosition(args, scriptInfo); } @@ -2063,17 +2400,23 @@ export class Session implements EventSender { const { file, project } = this.getFileAndProject(args); return { file, - languageService: project.getLanguageService(/*ensureSynchronized*/ false) + languageService: project.getLanguageService(/*ensureSynchronized*/ false), }; } - private getFileAndProjectWorker(uncheckedFileName: string, projectFileName: string | undefined): { file: NormalizedPath, project: Project } { + private getFileAndProjectWorker( + uncheckedFileName: string, + projectFileName: string | undefined, + ): { file: NormalizedPath; project: Project; } { const file = toNormalizedPath(uncheckedFileName); const project = this.getProject(projectFileName) || this.projectService.ensureDefaultProjectForFile(file); return { file, project }; } - private getOutliningSpans(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.OutliningSpan[] | OutliningSpan[] { + private getOutliningSpans( + args: protocol.FileRequestArgs, + simplifiedResult: boolean, + ): protocol.OutliningSpan[] | OutliningSpan[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const spans = languageService.getOutliningSpans(file); if (simplifiedResult) { @@ -2083,7 +2426,7 @@ export class Session implements EventSender { hintSpan: toProtocolTextSpan(s.hintSpan, scriptInfo), bannerText: s.bannerText, autoCollapse: s.autoCollapse, - kind: s.kind + kind: s.kind, })); } else { @@ -2099,7 +2442,12 @@ export class Session implements EventSender { private getDocCommentTemplate(args: protocol.FileLocationRequestArgs) { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const position = this.getPositionInFile(args, file); - return languageService.getDocCommentTemplateAtPosition(file, position, this.getPreferences(file), this.getFormatOptions(file)); + return languageService.getDocCommentTemplateAtPosition( + file, + position, + this.getPreferences(file), + this.getFormatOptions(file), + ); } private getSpanOfEnclosingComment(args: protocol.SpanOfEnclosingCommentRequestArgs) { @@ -2135,7 +2483,10 @@ export class Session implements EventSender { return languageService.isValidBraceCompletionAtPosition(file, position, args.openingBrace.charCodeAt(0)); } - private getQuickInfoWorker(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.QuickInfoResponseBody | QuickInfo | undefined { + private getQuickInfoWorker( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): protocol.QuickInfoResponseBody | QuickInfo | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const quickInfo = project.getLanguageService().getQuickInfoAtPosition(file, this.getPosition(args, scriptInfo)); @@ -2152,14 +2503,15 @@ export class Session implements EventSender { start: scriptInfo.positionToLineOffset(quickInfo.textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(quickInfo.textSpan)), displayString, - documentation: useDisplayParts ? this.mapDisplayParts(quickInfo.documentation, project) : displayPartsToString(quickInfo.documentation), + documentation: useDisplayParts ? this.mapDisplayParts(quickInfo.documentation, project) + : displayPartsToString(quickInfo.documentation), tags: this.mapJSDocTagInfo(quickInfo.tags, project, useDisplayParts), }; } else { return useDisplayParts ? quickInfo : { ...quickInfo, - tags: this.mapJSDocTagInfo(quickInfo.tags, project, /*richResponse*/ false) as JSDocTagInfo[] + tags: this.mapJSDocTagInfo(quickInfo.tags, project, /*richResponse*/ false) as JSDocTagInfo[], }; } } @@ -2172,7 +2524,12 @@ export class Session implements EventSender { const endPosition = scriptInfo.lineOffsetToPosition(args.endLine, args.endOffset); // TODO: avoid duplicate code (with formatonkey) - const edits = languageService.getFormattingEditsForRange(file, startPosition, endPosition, this.getFormatOptions(file)); + const edits = languageService.getFormattingEditsForRange( + file, + startPosition, + endPosition, + this.getFormatOptions(file), + ); if (!edits) { return undefined; } @@ -2203,8 +2560,7 @@ export class Session implements EventSender { const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = scriptInfo.lineOffsetToPosition(args.line, args.offset); const formatOptions = this.getFormatOptions(file); - const edits = languageService.getFormattingEditsAfterKeystroke(file, position, args.key, - formatOptions); + const edits = languageService.getFormattingEditsAfterKeystroke(file, position, args.key, formatOptions); // Check whether we should auto-indent. This will be when // the position is on a line containing only whitespace. // This should leave the edits returned from @@ -2233,7 +2589,7 @@ export class Session implements EventSender { const firstNoWhiteSpacePosition = absolutePosition + i; edits.push({ span: createTextSpanFromBounds(absolutePosition, firstNoWhiteSpacePosition), - newText: formatting.getIndentationString(preferredIndent, formatOptions) + newText: formatting.getIndentationString(preferredIndent, formatOptions), }); } } @@ -2243,16 +2599,22 @@ export class Session implements EventSender { return undefined; } - return edits.map((edit) => { + return edits.map(edit => { return { start: scriptInfo.positionToLineOffset(edit.span.start), end: scriptInfo.positionToLineOffset(textSpanEnd(edit.span)), - newText: edit.newText ? edit.newText : "" + newText: edit.newText ? edit.newText : "", }; }); } - private getCompletions(args: protocol.CompletionsRequestArgs, kind: protocol.CommandTypes.CompletionInfo | protocol.CommandTypes.Completions | protocol.CommandTypes.CompletionsFull): WithMetadata | protocol.CompletionInfo | CompletionInfo | undefined { + private getCompletions( + args: protocol.CompletionsRequestArgs, + kind: + | protocol.CommandTypes.CompletionInfo + | protocol.CommandTypes.Completions + | protocol.CommandTypes.CompletionsFull, + ): WithMetadata | protocol.CompletionInfo | CompletionInfo | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -2292,7 +2654,8 @@ export class Session implements EventSender { isRecommended, isPackageJsonImport, isImportStatementCompletion, - data } = entry; + data, + } = entry; const convertedSpan = replacementSpan ? toProtocolTextSpan(replacementSpan, scriptInfo) : undefined; // Use `hasAction || undefined` to avoid serializing `false`. return { @@ -2311,25 +2674,31 @@ export class Session implements EventSender { isRecommended, isPackageJsonImport, isImportStatementCompletion, - data + data, }; } }); if (kind === protocol.CommandTypes.Completions) { - if (completions.metadata) (entries as WithMetadata).metadata = completions.metadata; + if (completions.metadata) { + (entries as WithMetadata).metadata = completions.metadata; + } return entries; } const res: protocol.CompletionInfo = { ...completions, - optionalReplacementSpan: completions.optionalReplacementSpan && toProtocolTextSpan(completions.optionalReplacementSpan, scriptInfo), + optionalReplacementSpan: completions.optionalReplacementSpan + && toProtocolTextSpan(completions.optionalReplacementSpan, scriptInfo), entries, }; return res; } - private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs, fullResult: boolean): readonly protocol.CompletionEntryDetails[] | readonly CompletionEntryDetails[] { + private getCompletionEntryDetails( + args: protocol.CompletionDetailsRequestArgs, + fullResult: boolean, + ): readonly protocol.CompletionEntryDetails[] | readonly CompletionEntryDetails[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -2337,11 +2706,24 @@ export class Session implements EventSender { const useDisplayParts = !!this.getPreferences(file).displayPartsForJSDoc; const result = mapDefined(args.entryNames, entryName => { - const { name, source, data } = typeof entryName === "string" ? { name: entryName, source: undefined, data: undefined } : entryName; - return project.getLanguageService().getCompletionEntryDetails(file, position, name, formattingOptions, source, this.getPreferences(file), data ? cast(data, isCompletionEntryData) : undefined); + const { name, source, data } = typeof entryName === "string" + ? { name: entryName, source: undefined, data: undefined } : entryName; + return project.getLanguageService().getCompletionEntryDetails( + file, + position, + name, + formattingOptions, + source, + this.getPreferences(file), + data ? cast(data, isCompletionEntryData) : undefined, + ); }); return fullResult - ? (useDisplayParts ? result : result.map(details => ({ ...details, tags: this.mapJSDocTagInfo(details.tags, project, /*richResponse*/ false) as JSDocTagInfo[] }))) + ? (useDisplayParts ? result + : result.map(details => ({ + ...details, + tags: this.mapJSDocTagInfo(details.tags, project, /*richResponse*/ false) as JSDocTagInfo[], + }))) : result.map(details => ({ ...details, codeActions: map(details.codeActions, action => this.mapCodeAction(action)), @@ -2350,8 +2732,14 @@ export class Session implements EventSender { })); } - private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): readonly protocol.CompileOnSaveAffectedFileListSingleProject[] { - const projects = this.getProjects(args, /*getScriptInfoEnsuringProjectsUptoDate*/ true, /*ignoreNoProjectError*/ true); + private getCompileOnSaveAffectedFileList( + args: protocol.FileRequestArgs, + ): readonly protocol.CompileOnSaveAffectedFileListSingleProject[] { + const projects = this.getProjects( + args, + /*getScriptInfoEnsuringProjectsUptoDate*/ true, + /*ignoreNoProjectError*/ true, + ); const info = this.projectService.getScriptInfo(args.file); if (!info) { return emptyArray; @@ -2368,7 +2756,10 @@ export class Session implements EventSender { const compilationSettings = project.getCompilationSettings(); - if (!!compilationSettings.noEmit || isDeclarationFileName(info.fileName) && !dtsChangeCanAffectEmit(compilationSettings)) { + if ( + !!compilationSettings.noEmit + || isDeclarationFileName(info.fileName) && !dtsChangeCanAffectEmit(compilationSettings) + ) { // avoid triggering emit when a change is made in a .d.ts when declaration emit and decorator metadata emit are disabled return undefined; } @@ -2376,9 +2767,9 @@ export class Session implements EventSender { return { projectFileName: project.getProjectName(), fileNames: project.getCompileOnSaveAffectedFileList(info), - projectUsesOutFile: !!outFile(compilationSettings) + projectUsesOutFile: !!outFile(compilationSettings), }; - } + }, ); } @@ -2391,18 +2782,24 @@ export class Session implements EventSender { return args.richResponse ? { emitSkipped: true, diagnostics: [] } : false; } const scriptInfo = project.getScriptInfo(file)!; - const { emitSkipped, diagnostics } = project.emitFile(scriptInfo, (path, data, writeByteOrderMark) => this.host.writeFile(path, data, writeByteOrderMark)); - return args.richResponse ? - { + const { emitSkipped, diagnostics } = project.emitFile( + scriptInfo, + (path, data, writeByteOrderMark) => this.host.writeFile(path, data, writeByteOrderMark), + ); + return args.richResponse + ? { emitSkipped, - diagnostics: args.includeLinePosition ? - this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics) : - diagnostics.map(d => formatDiagnosticToProtocol(d, /*includeFileName*/ true)) - } : - !emitSkipped; + diagnostics: args.includeLinePosition + ? this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics) + : diagnostics.map(d => formatDiagnosticToProtocol(d, /*includeFileName*/ true)), + } + : !emitSkipped; } - private getSignatureHelpItems(args: protocol.SignatureHelpRequestArgs, simplifiedResult: boolean): protocol.SignatureHelpItems | SignatureHelpItems | undefined { + private getSignatureHelpItems( + args: protocol.SignatureHelpRequestArgs, + simplifiedResult: boolean, + ): protocol.SignatureHelpItems | SignatureHelpItems | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -2414,7 +2811,7 @@ export class Session implements EventSender { ...helpItems, applicableSpan: { start: scriptInfo.positionToLineOffset(span.start), - end: scriptInfo.positionToLineOffset(span.start + span.length) + end: scriptInfo.positionToLineOffset(span.start + span.length), }, items: this.mapSignatureHelpItems(helpItems.items, project, useDisplayParts), }; @@ -2425,7 +2822,10 @@ export class Session implements EventSender { else { return { ...helpItems, - items: helpItems.items.map(item => ({ ...item, tags: this.mapJSDocTagInfo(item.tags, project, /*richResponse*/ false) as JSDocTagInfo[] })) + items: helpItems.items.map(item => ({ + ...item, + tags: this.mapJSDocTagInfo(item.tags, project, /*richResponse*/ false) as JSDocTagInfo[], + })), }; } } @@ -2455,10 +2855,13 @@ export class Session implements EventSender { const end = scriptInfo.lineOffsetToPosition(args.endLine, args.endOffset); if (start >= 0) { this.changeSeq++; - this.projectService.applyChangesToFile(scriptInfo, singleIterator({ - span: { start, length: end - start }, - newText: args.insertString! // TODO: GH#18217 - })); + this.projectService.applyChangesToFile( + scriptInfo, + singleIterator({ + span: { start, length: end - start }, + newText: args.insertString!, // TODO: GH#18217 + }), + ); } } @@ -2490,25 +2893,31 @@ export class Session implements EventSender { this.projectService.closeClientFile(file); } - private mapLocationNavigationBarItems(items: NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] { + private mapLocationNavigationBarItems( + items: NavigationBarItem[], + scriptInfo: ScriptInfo, + ): protocol.NavigationBarItem[] { return map(items, item => ({ text: item.text, kind: item.kind, kindModifiers: item.kindModifiers, spans: item.spans.map(span => toProtocolTextSpan(span, scriptInfo)), childItems: this.mapLocationNavigationBarItems(item.childItems, scriptInfo), - indent: item.indent + indent: item.indent, })); } - private getNavigationBarItems(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.NavigationBarItem[] | NavigationBarItem[] | undefined { + private getNavigationBarItems( + args: protocol.FileRequestArgs, + simplifiedResult: boolean, + ): protocol.NavigationBarItem[] | NavigationBarItem[] | undefined { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const items = languageService.getNavigationBarItems(file); return !items ? undefined : simplifiedResult - ? this.mapLocationNavigationBarItems(items, this.projectService.getScriptInfoForNormalizedPath(file)!) - : items; + ? this.mapLocationNavigationBarItems(items, this.projectService.getScriptInfoForNormalizedPath(file)!) + : items; } private toLocationNavigationTree(tree: NavigationTree, scriptInfo: ScriptInfo): protocol.NavigationTree { @@ -2518,49 +2927,56 @@ export class Session implements EventSender { kindModifiers: tree.kindModifiers, spans: tree.spans.map(span => toProtocolTextSpan(span, scriptInfo)), nameSpan: tree.nameSpan && toProtocolTextSpan(tree.nameSpan, scriptInfo), - childItems: map(tree.childItems, item => this.toLocationNavigationTree(item, scriptInfo)) + childItems: map(tree.childItems, item => this.toLocationNavigationTree(item, scriptInfo)), }; } - private getNavigationTree(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.NavigationTree | NavigationTree | undefined { + private getNavigationTree( + args: protocol.FileRequestArgs, + simplifiedResult: boolean, + ): protocol.NavigationTree | NavigationTree | undefined { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const tree = languageService.getNavigationTree(file); return !tree ? undefined : simplifiedResult - ? this.toLocationNavigationTree(tree, this.projectService.getScriptInfoForNormalizedPath(file)!) - : tree; + ? this.toLocationNavigationTree(tree, this.projectService.getScriptInfoForNormalizedPath(file)!) + : tree; } - private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): readonly protocol.NavtoItem[] | readonly NavigateToItem[] { + private getNavigateToItems( + args: protocol.NavtoRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.NavtoItem[] | readonly NavigateToItem[] { const full = this.getFullNavigateToItems(args); - return !simplifiedResult ? - flatMap(full, ({ navigateToItems }) => navigateToItems) : - flatMap( + return !simplifiedResult + ? flatMap(full, ({ navigateToItems }) => navigateToItems) + : flatMap( full, - ({ project, navigateToItems }) => navigateToItems.map(navItem => { - const scriptInfo = project.getScriptInfo(navItem.fileName)!; - const bakedItem: protocol.NavtoItem = { - name: navItem.name, - kind: navItem.kind, - kindModifiers: navItem.kindModifiers, - isCaseSensitive: navItem.isCaseSensitive, - matchKind: navItem.matchKind, - file: navItem.fileName, - start: scriptInfo.positionToLineOffset(navItem.textSpan.start), - end: scriptInfo.positionToLineOffset(textSpanEnd(navItem.textSpan)) - }; - if (navItem.kindModifiers && (navItem.kindModifiers !== "")) { - bakedItem.kindModifiers = navItem.kindModifiers; - } - if (navItem.containerName && (navItem.containerName.length > 0)) { - bakedItem.containerName = navItem.containerName; - } - if (navItem.containerKind && (navItem.containerKind.length > 0)) { - bakedItem.containerKind = navItem.containerKind; - } - return bakedItem; - }) + ({ project, navigateToItems }) => + navigateToItems.map(navItem => { + const scriptInfo = project.getScriptInfo(navItem.fileName)!; + const bakedItem: protocol.NavtoItem = { + name: navItem.name, + kind: navItem.kind, + kindModifiers: navItem.kindModifiers, + isCaseSensitive: navItem.isCaseSensitive, + matchKind: navItem.matchKind, + file: navItem.fileName, + start: scriptInfo.positionToLineOffset(navItem.textSpan.start), + end: scriptInfo.positionToLineOffset(textSpanEnd(navItem.textSpan)), + }; + if (navItem.kindModifiers && (navItem.kindModifiers !== "")) { + bakedItem.kindModifiers = navItem.kindModifiers; + } + if (navItem.containerName && (navItem.containerName.length > 0)) { + bakedItem.containerName = navItem.containerName; + } + if (navItem.containerKind && (navItem.containerKind.length > 0)) { + bakedItem.containerKind = navItem.containerKind; + } + return bakedItem; + }), ); } @@ -2570,7 +2986,10 @@ export class Session implements EventSender { if (currentFileOnly) { Debug.assertIsDefined(args.file); const { file, project } = this.getFileAndProject(args as protocol.FileRequestArgs); - return [{ project, navigateToItems: project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, file) }]; + return [{ + project, + navigateToItems: project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, file), + }]; } const outputs: ProjectNavigateToItems[] = []; @@ -2605,8 +3024,16 @@ export class Session implements EventSender { // Mutates `outputs` function addItemsForProject(project: Project) { - const projectItems = project.getLanguageService().getNavigateToItems(searchValue, maxResultCount, /*fileName*/ undefined, /*excludeDts*/ project.isNonTsProject()); - const unseenItems = filter(projectItems, item => tryAddSeenItem(item) && !getMappedLocationForProject(documentSpanLocation(item), project)); + const projectItems = project.getLanguageService().getNavigateToItems( + searchValue, + maxResultCount, + /*fileName*/ undefined, + /*excludeDts*/ project.isNonTsProject(), + ); + const unseenItems = filter( + projectItems, + item => tryAddSeenItem(item) && !getMappedLocationForProject(documentSpanLocation(item), project), + ); if (unseenItems.length) { outputs.push({ project, navigateToItems: unseenItems }); } @@ -2639,16 +3066,16 @@ export class Session implements EventSender { if (!a || !b) { return false; } - return a.containerKind === b.containerKind && - a.containerName === b.containerName && - a.fileName === b.fileName && - a.isCaseSensitive === b.isCaseSensitive && - a.kind === b.kind && - a.kindModifiers === b.kindModifiers && - a.matchKind === b.matchKind && - a.name === b.name && - a.textSpan.start === b.textSpan.start && - a.textSpan.length === b.textSpan.length; + return a.containerKind === b.containerKind + && a.containerName === b.containerName + && a.fileName === b.fileName + && a.isCaseSensitive === b.isCaseSensitive + && a.kind === b.kind + && a.kindModifiers === b.kindModifiers + && a.matchKind === b.matchKind + && a.name === b.name + && a.textSpan.start === b.textSpan.start + && a.textSpan.length === b.textSpan.length; } } @@ -2663,11 +3090,16 @@ export class Session implements EventSender { return project.getLanguageService().getSupportedCodeFixes(); } - private isLocation(locationOrSpan: protocol.FileLocationOrRangeRequestArgs): locationOrSpan is protocol.FileLocationRequestArgs { + private isLocation( + locationOrSpan: protocol.FileLocationOrRangeRequestArgs, + ): locationOrSpan is protocol.FileLocationRequestArgs { return (locationOrSpan as protocol.FileLocationRequestArgs).line !== undefined; } - private extractPositionOrRange(args: protocol.FileLocationOrRangeRequestArgs, scriptInfo: ScriptInfo): number | TextRange { + private extractPositionOrRange( + args: protocol.FileLocationOrRangeRequestArgs, + scriptInfo: ScriptInfo, + ): number | TextRange { let position: number | undefined; let textRange: TextRange | undefined; if (this.isLocation(args)) { @@ -2689,13 +3121,25 @@ export class Session implements EventSender { return { pos: startPosition, end: endPosition }; } - private getApplicableRefactors(args: protocol.GetApplicableRefactorsRequestArgs): protocol.ApplicableRefactorInfo[] { + private getApplicableRefactors( + args: protocol.GetApplicableRefactorsRequestArgs, + ): protocol.ApplicableRefactorInfo[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file)!; - return project.getLanguageService().getApplicableRefactors(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file), args.triggerReason, args.kind, args.includeInteractiveActions); + return project.getLanguageService().getApplicableRefactors( + file, + this.extractPositionOrRange(args, scriptInfo), + this.getPreferences(file), + args.triggerReason, + args.kind, + args.includeInteractiveActions, + ); } - private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): RefactorEditInfo | protocol.RefactorEditInfo { + private getEditsForRefactor( + args: protocol.GetEditsForRefactorRequestArgs, + simplifiedResult: boolean, + ): RefactorEditInfo | protocol.RefactorEditInfo { const { file, project } = this.getFileAndProject(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file)!; const result = project.getLanguageService().getEditsForRefactor( @@ -2705,12 +3149,12 @@ export class Session implements EventSender { args.refactor, args.action, this.getPreferences(file), - args.interactiveRefactorArguments + args.interactiveRefactorArguments, ); if (result === undefined) { return { - edits: [] + edits: [], }; } @@ -2719,7 +3163,12 @@ export class Session implements EventSender { let mappedRenameLocation: protocol.Location | undefined; if (renameFilename !== undefined && renameLocation !== undefined) { const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(renameFilename))!; - mappedRenameLocation = getLocationInNewDocument(getSnapshotText(renameScriptInfo.getSnapshot()), renameFilename, renameLocation, edits); + mappedRenameLocation = getLocationInNewDocument( + getSnapshotText(renameScriptInfo.getSnapshot()), + renameFilename, + renameLocation, + edits, + ); } return { renameLocation: mappedRenameLocation, @@ -2731,23 +3180,33 @@ export class Session implements EventSender { return result; } - private getMoveToRefactoringFileSuggestions(args: protocol.GetMoveToRefactoringFileSuggestionsRequestArgs): { newFileName: string, files: string[] }{ + private getMoveToRefactoringFileSuggestions( + args: protocol.GetMoveToRefactoringFileSuggestionsRequestArgs, + ): { newFileName: string; files: string[]; } { const { file, project } = this.getFileAndProject(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file)!; - return project.getLanguageService().getMoveToRefactoringFileSuggestions(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file)); + return project.getLanguageService().getMoveToRefactoringFileSuggestions( + file, + this.extractPositionOrRange(args, scriptInfo), + this.getPreferences(file), + ); } - private organizeImports(args: protocol.OrganizeImportsRequestArgs, simplifiedResult: boolean): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { + private organizeImports( + args: protocol.OrganizeImportsRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { Debug.assert(args.scope.type === "file"); const { file, project } = this.getFileAndProject(args.scope.args); const changes = project.getLanguageService().organizeImports( { fileName: file, - mode: args.mode as OrganizeImportsMode | undefined ?? (args.skipDestructiveCodeActions ? OrganizeImportsMode.SortAndCombine : undefined), + mode: args.mode as OrganizeImportsMode | undefined + ?? (args.skipDestructiveCodeActions ? OrganizeImportsMode.SortAndCombine : undefined), type: "file", }, this.getFormatOptions(file), - this.getPreferences(file) + this.getPreferences(file), ); if (simplifiedResult) { return this.mapTextChangesToCodeEdits(changes); @@ -2757,13 +3216,15 @@ export class Session implements EventSender { } } - private getEditsForFileRename(args: protocol.GetEditsForFileRenameRequestArgs, simplifiedResult: boolean): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { + private getEditsForFileRename( + args: protocol.GetEditsForFileRenameRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { const oldPath = toNormalizedPath(args.oldFilePath); const newPath = toNormalizedPath(args.newFilePath); const formatOptions = this.getHostFormatOptions(); const preferences = this.getHostPreferences(); - const seenFiles = new Set(); const textChanges: FileTextChanges[] = []; // TODO (https://github.com/microsoft/TypeScript/issues/47839) @@ -2771,7 +3232,12 @@ export class Session implements EventSender { // those that are downstream from already-loaded projects. this.projectService.loadAncestorProjectTree(); this.projectService.forEachEnabledProject(project => { - const projectTextChanges = project.getLanguageService().getEditsForFileRename(oldPath, newPath, formatOptions, preferences); + const projectTextChanges = project.getLanguageService().getEditsForFileRename( + oldPath, + newPath, + formatOptions, + preferences, + ); const projectFiles: string[] = []; for (const textChange of projectTextChanges) { if (!seenFiles.has(textChange.fileName)) { @@ -2787,7 +3253,10 @@ export class Session implements EventSender { return simplifiedResult ? textChanges.map(c => this.mapTextChangeToCodeEdit(c)) : textChanges; } - private getCodeFixes(args: protocol.CodeFixRequestArgs, simplifiedResult: boolean): readonly protocol.CodeFixAction[] | readonly CodeFixAction[] | undefined { + private getCodeFixes( + args: protocol.CodeFixRequestArgs, + simplifiedResult: boolean, + ): readonly protocol.CodeFixAction[] | readonly CodeFixAction[] | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file)!; @@ -2795,30 +3264,49 @@ export class Session implements EventSender { let codeActions: readonly CodeFixAction[]; try { - codeActions = project.getLanguageService().getCodeFixesAtPosition(file, startPosition, endPosition, args.errorCodes, this.getFormatOptions(file), this.getPreferences(file)); + codeActions = project.getLanguageService().getCodeFixesAtPosition( + file, + startPosition, + endPosition, + args.errorCodes, + this.getFormatOptions(file), + this.getPreferences(file), + ); } - catch(e) { + catch (e) { const ls = project.getLanguageService(); const existingDiagCodes = [ ...ls.getSyntacticDiagnostics(file), ...ls.getSemanticDiagnostics(file), - ...ls.getSuggestionDiagnostics(file) + ...ls.getSuggestionDiagnostics(file), ].map(d => decodedTextSpanIntersectsWith(startPosition, endPosition - startPosition, d.start!, d.length!) - && d.code); + && d.code + ); const badCode = args.errorCodes.find(c => !existingDiagCodes.includes(c)); if (badCode !== undefined) { - e.message = `BADCLIENT: Bad error code, ${badCode} not found in range ${startPosition}..${endPosition} (found: ${existingDiagCodes.join(", ")}); could have caused this error:\n${e.message}`; + e.message = + `BADCLIENT: Bad error code, ${badCode} not found in range ${startPosition}..${endPosition} (found: ${ + existingDiagCodes.join(", ") + }); could have caused this error:\n${e.message}`; } throw e; } return simplifiedResult ? codeActions.map(codeAction => this.mapCodeFixAction(codeAction)) : codeActions; } - private getCombinedCodeFix({ scope, fixId }: protocol.GetCombinedCodeFixRequestArgs, simplifiedResult: boolean): protocol.CombinedCodeActions | CombinedCodeActions { + private getCombinedCodeFix( + { scope, fixId }: protocol.GetCombinedCodeFixRequestArgs, + simplifiedResult: boolean, + ): protocol.CombinedCodeActions | CombinedCodeActions { Debug.assert(scope.type === "file"); const { file, project } = this.getFileAndProject(scope.args); - const res = project.getLanguageService().getCombinedCodeFix({ type: "file", fileName: file }, fixId, this.getFormatOptions(file), this.getPreferences(file)); + const res = project.getLanguageService().getCombinedCodeFix( + { type: "file", fileName: file }, + fixId, + this.getFormatOptions(file), + this.getPreferences(file), + ); if (simplifiedResult) { return { changes: this.mapTextChangesToCodeEdits(res.changes), commands: res.commands }; } @@ -2832,8 +3320,9 @@ export class Session implements EventSender { for (const command of toArray(commands)) { const { file, project } = this.getFileAndProject(command); project.getLanguageService().applyCodeActionCommand(command, this.getFormatOptions(file)).then( - _result => { /* TODO: GH#20447 report success message? */ }, - _error => { /* TODO: GH#20447 report errors */ }); + _result => {/* TODO: GH#20447 report success message? */}, + _error => {/* TODO: GH#20447 report errors */}, + ); } return {}; } @@ -2864,8 +3353,17 @@ export class Session implements EventSender { return { description, changes: this.mapTextChangesToCodeEdits(changes), commands }; } - private mapCodeFixAction({ fixName, description, changes, commands, fixId, fixAllDescription }: CodeFixAction): protocol.CodeFixAction { - return { fixName, description, changes: this.mapTextChangesToCodeEdits(changes), commands, fixId, fixAllDescription }; + private mapCodeFixAction( + { fixName, description, changes, commands, fixId, fixAllDescription }: CodeFixAction, + ): protocol.CodeFixAction { + return { + fixName, + description, + changes: this.mapTextChangesToCodeEdits(changes), + commands, + fixId, + fixAllDescription, + }; } private mapTextChangesToCodeEdits(textChanges: readonly FileTextChanges[]): protocol.FileCodeEdits[] { @@ -2878,10 +3376,18 @@ export class Session implements EventSender { if (!scriptInfo) { // and !isNewFile this.projectService.logErrorForScriptInfoNotFound(textChanges.fileName); } - Debug.fail("Expected isNewFile for (only) new files. " + JSON.stringify({ isNewFile: !!textChanges.isNewFile, hasScriptInfo: !!scriptInfo })); + Debug.fail( + "Expected isNewFile for (only) new files. " + + JSON.stringify({ isNewFile: !!textChanges.isNewFile, hasScriptInfo: !!scriptInfo }), + ); } return scriptInfo - ? { fileName: textChanges.fileName, textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEdit(textChange, scriptInfo)) } + ? { + fileName: textChanges.fileName, + textChanges: textChanges.textChanges.map(textChange => + convertTextChangeToCodeEdit(textChange, scriptInfo) + ), + } : convertNewFileTextChangeToCodeEdit(textChanges); } @@ -2889,11 +3395,14 @@ export class Session implements EventSender { return { start: scriptInfo.positionToLineOffset(change.span.start), end: scriptInfo.positionToLineOffset(change.span.start + change.span.length), - newText: change.newText ? change.newText : "" + newText: change.newText ? change.newText : "", }; } - private getBraceMatching(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.TextSpan[] | TextSpan[] | undefined { + private getBraceMatching( + args: protocol.FileLocationRequestArgs, + simplifiedResult: boolean, + ): protocol.TextSpan[] | TextSpan[] | undefined { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const position = this.getPosition(args, scriptInfo); @@ -2902,8 +3411,8 @@ export class Session implements EventSender { return !spans ? undefined : simplifiedResult - ? spans.map(span => toProtocolTextSpan(span, scriptInfo)) - : spans; + ? spans.map(span => toProtocolTextSpan(span, scriptInfo)) + : spans; } private getDiagnosticsForProject(next: NextStep, delay: number, fileName: string): void { @@ -2911,7 +3420,12 @@ export class Session implements EventSender { return; } - const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(fileName, /*projectFileName*/ undefined, /*needFileNameList*/ true, /*excludeConfigFiles*/ true); + const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker( + fileName, + /*projectFileName*/ undefined, + /*needFileNameList*/ true, + /*excludeConfigFiles*/ true, + ); if (languageServiceDisabled) { return; } @@ -2949,7 +3463,12 @@ export class Session implements EventSender { } } - const sortedFiles = [...highPriorityFiles, ...mediumPriorityFiles, ...lowPriorityFiles, ...veryLowPriorityFiles]; + const sortedFiles = [ + ...highPriorityFiles, + ...mediumPriorityFiles, + ...lowPriorityFiles, + ...veryLowPriorityFiles, + ]; const checkList = sortedFiles.map(fileName => ({ fileName, project })); // Project level error analysis runs on background files too, therefore // doesn't require the file to be opened @@ -2972,7 +3491,10 @@ export class Session implements EventSender { }); } - private toggleLineComment(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] { + private toggleLineComment( + args: protocol.FileRangeRequestArgs, + simplifiedResult: boolean, + ): TextChange[] | protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfo(file)!; const textRange = this.getRange(args, scriptInfo); @@ -2988,7 +3510,10 @@ export class Session implements EventSender { return textChanges; } - private toggleMultilineComment(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] { + private toggleMultilineComment( + args: protocol.FileRangeRequestArgs, + simplifiedResult: boolean, + ): TextChange[] | protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const textRange = this.getRange(args, scriptInfo); @@ -3004,7 +3529,10 @@ export class Session implements EventSender { return textChanges; } - private commentSelection(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] { + private commentSelection( + args: protocol.FileRangeRequestArgs, + simplifiedResult: boolean, + ): TextChange[] | protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const textRange = this.getRange(args, scriptInfo); @@ -3020,7 +3548,10 @@ export class Session implements EventSender { return textChanges; } - private uncommentSelection(args: protocol.FileRangeRequestArgs, simplifiedResult: boolean): TextChange[] | protocol.CodeEdit[] { + private uncommentSelection( + args: protocol.FileRangeRequestArgs, + simplifiedResult: boolean, + ): TextChange[] | protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!; const textRange = this.getRange(args, scriptInfo); @@ -3065,26 +3596,33 @@ export class Session implements EventSender { file: item.file, containerName: item.containerName, span: toProtocolTextSpan(item.span, scriptInfo), - selectionSpan: toProtocolTextSpan(item.selectionSpan, scriptInfo) + selectionSpan: toProtocolTextSpan(item.selectionSpan, scriptInfo), }; } - private toProtocolCallHierarchyIncomingCall(incomingCall: CallHierarchyIncomingCall): protocol.CallHierarchyIncomingCall { + private toProtocolCallHierarchyIncomingCall( + incomingCall: CallHierarchyIncomingCall, + ): protocol.CallHierarchyIncomingCall { const scriptInfo = this.getScriptInfoFromProjectService(incomingCall.from.file); return { from: this.toProtocolCallHierarchyItem(incomingCall.from), - fromSpans: incomingCall.fromSpans.map(fromSpan => toProtocolTextSpan(fromSpan, scriptInfo)) + fromSpans: incomingCall.fromSpans.map(fromSpan => toProtocolTextSpan(fromSpan, scriptInfo)), }; } - private toProtocolCallHierarchyOutgoingCall(outgoingCall: CallHierarchyOutgoingCall, scriptInfo: ScriptInfo): protocol.CallHierarchyOutgoingCall { + private toProtocolCallHierarchyOutgoingCall( + outgoingCall: CallHierarchyOutgoingCall, + scriptInfo: ScriptInfo, + ): protocol.CallHierarchyOutgoingCall { return { to: this.toProtocolCallHierarchyItem(outgoingCall.to), - fromSpans: outgoingCall.fromSpans.map(fromSpan => toProtocolTextSpan(fromSpan, scriptInfo)) + fromSpans: outgoingCall.fromSpans.map(fromSpan => toProtocolTextSpan(fromSpan, scriptInfo)), }; } - private prepareCallHierarchy(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyItem | protocol.CallHierarchyItem[] | undefined { + private prepareCallHierarchy( + args: protocol.FileLocationRequestArgs, + ): protocol.CallHierarchyItem | protocol.CallHierarchyItem[] | undefined { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file); if (scriptInfo) { @@ -3095,17 +3633,27 @@ export class Session implements EventSender { return undefined; } - private provideCallHierarchyIncomingCalls(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyIncomingCall[] { + private provideCallHierarchyIncomingCalls( + args: protocol.FileLocationRequestArgs, + ): protocol.CallHierarchyIncomingCall[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.getScriptInfoFromProjectService(file); - const incomingCalls = project.getLanguageService().provideCallHierarchyIncomingCalls(file, this.getPosition(args, scriptInfo)); + const incomingCalls = project.getLanguageService().provideCallHierarchyIncomingCalls( + file, + this.getPosition(args, scriptInfo), + ); return incomingCalls.map(call => this.toProtocolCallHierarchyIncomingCall(call)); } - private provideCallHierarchyOutgoingCalls(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyOutgoingCall[] { + private provideCallHierarchyOutgoingCalls( + args: protocol.FileLocationRequestArgs, + ): protocol.CallHierarchyOutgoingCall[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = this.getScriptInfoFromProjectService(file); - const outgoingCalls = project.getLanguageService().provideCallHierarchyOutgoingCalls(file, this.getPosition(args, scriptInfo)); + const outgoingCalls = project.getLanguageService().provideCallHierarchyOutgoingCalls( + file, + this.getPosition(args, scriptInfo), + ); return outgoingCalls.map(call => this.toProtocolCallHierarchyOutgoingCall(call, scriptInfo)); } @@ -3114,7 +3662,7 @@ export class Session implements EventSender { return normalizePath(name); } - exit() { /*overridden*/ } + exit() {/*overridden*/} private notRequired(): HandlerResponse { return { responseRequired: false }; @@ -3145,7 +3693,10 @@ export class Session implements EventSender { return this.requiredResponse(/*response*/ true); }, [protocol.CommandTypes.SynchronizeProjectList]: (request: protocol.SynchronizeProjectListRequest) => { - const result = this.projectService.synchronizeProjectList(request.arguments.knownProjects, request.arguments.includeProjectReferenceRedirectInfo); + const result = this.projectService.synchronizeProjectList( + request.arguments.knownProjects, + request.arguments.includeProjectReferenceRedirectInfo, + ); if (!result.some(p => p.projectErrors && p.projectErrors.length !== 0)) { return this.requiredResponse(result); } @@ -3157,7 +3708,7 @@ export class Session implements EventSender { info: p.info, changes: p.changes, files: p.files, - projectErrors: this.convertToDiagnosticsWithLinePosition(p.projectErrors, /*scriptInfo*/ undefined) + projectErrors: this.convertToDiagnosticsWithLinePosition(p.projectErrors, /*scriptInfo*/ undefined), }; }); return this.requiredResponse(converted); @@ -3169,7 +3720,7 @@ export class Session implements EventSender { fileName: file.file, content: file.fileContent, scriptKind: file.scriptKindName, - projectRootPath: file.projectRootPath + projectRootPath: file.projectRootPath, })), request.arguments.changedFiles && mapIterator(request.arguments.changedFiles, file => ({ fileName: file.fileName, @@ -3177,10 +3728,11 @@ export class Session implements EventSender { const scriptInfo = Debug.checkDefined(this.projectService.getScriptInfo(file.fileName)); const start = scriptInfo.lineOffsetToPosition(change.start.line, change.start.offset); const end = scriptInfo.lineOffsetToPosition(change.end.line, change.end.offset); - return start >= 0 ? { span: { start, length: end - start }, newText: change.newText } : undefined; - }) + return start >= 0 ? { span: { start, length: end - start }, newText: change.newText } + : undefined; + }), })), - request.arguments.closedFiles + request.arguments.closedFiles, ); return this.requiredResponse(/*response*/ true); }, @@ -3191,9 +3743,9 @@ export class Session implements EventSender { request.arguments.changedFiles && mapIterator(request.arguments.changedFiles, file => ({ fileName: file.fileName, // apply changes in reverse order - changes: arrayReverseIterator(file.changes) + changes: arrayReverseIterator(file.changes), })), - request.arguments.closedFiles + request.arguments.closedFiles, ); // TODO: report errors return this.requiredResponse(/*response*/ true); @@ -3249,7 +3801,8 @@ export class Session implements EventSender { toNormalizedPath(request.arguments.file), request.arguments.fileContent, convertScriptKindName(request.arguments.scriptKindName!), // TODO: GH#18217 - request.arguments.projectRootPath ? toNormalizedPath(request.arguments.projectRootPath) : undefined); + request.arguments.projectRootPath ? toNormalizedPath(request.arguments.projectRootPath) : undefined, + ); return this.notRequired(); }, [protocol.CommandTypes.Quickinfo]: (request: protocol.QuickInfoRequest) => { @@ -3321,7 +3874,9 @@ export class Session implements EventSender { [protocol.CommandTypes.CompletionDetailsFull]: (request: protocol.CompletionDetailsRequest) => { return this.requiredResponse(this.getCompletionEntryDetails(request.arguments, /*fullResult*/ true)); }, - [protocol.CommandTypes.CompileOnSaveAffectedFileList]: (request: protocol.CompileOnSaveAffectedFileListRequest) => { + [protocol.CommandTypes.CompileOnSaveAffectedFileList]: ( + request: protocol.CompileOnSaveAffectedFileListRequest, + ) => { return this.requiredResponse(this.getCompileOnSaveAffectedFileList(request.arguments)); }, [protocol.CommandTypes.CompileOnSaveEmitFile]: (request: protocol.CompileOnSaveEmitFileRequest) => { @@ -3333,13 +3888,19 @@ export class Session implements EventSender { [protocol.CommandTypes.SignatureHelpFull]: (request: protocol.SignatureHelpRequest) => { return this.requiredResponse(this.getSignatureHelpItems(request.arguments, /*simplifiedResult*/ false)); }, - [protocol.CommandTypes.CompilerOptionsDiagnosticsFull]: (request: protocol.CompilerOptionsDiagnosticsRequest) => { + [protocol.CommandTypes.CompilerOptionsDiagnosticsFull]: ( + request: protocol.CompilerOptionsDiagnosticsRequest, + ) => { return this.requiredResponse(this.getCompilerOptionsDiagnostics(request.arguments)); }, - [protocol.CommandTypes.EncodedSyntacticClassificationsFull]: (request: protocol.EncodedSyntacticClassificationsRequest) => { + [protocol.CommandTypes.EncodedSyntacticClassificationsFull]: ( + request: protocol.EncodedSyntacticClassificationsRequest, + ) => { return this.requiredResponse(this.getEncodedSyntacticClassifications(request.arguments)); }, - [protocol.CommandTypes.EncodedSemanticClassificationsFull]: (request: protocol.EncodedSemanticClassificationsRequest) => { + [protocol.CommandTypes.EncodedSemanticClassificationsFull]: ( + request: protocol.EncodedSemanticClassificationsRequest, + ) => { return this.requiredResponse(this.getEncodedSemanticClassifications(request.arguments)); }, [protocol.CommandTypes.Cleanup]: () => { @@ -3356,11 +3917,15 @@ export class Session implements EventSender { return this.requiredResponse(this.getSuggestionDiagnosticsSync(request.arguments)); }, [protocol.CommandTypes.Geterr]: (request: protocol.GeterrRequest) => { - this.errorCheck.startNew(next => this.getDiagnostics(next, request.arguments.delay, request.arguments.files)); + this.errorCheck.startNew(next => + this.getDiagnostics(next, request.arguments.delay, request.arguments.files) + ); return this.notRequired(); }, [protocol.CommandTypes.GeterrForProject]: (request: protocol.GeterrForProjectRequest) => { - this.errorCheck.startNew(next => this.getDiagnosticsForProject(next, request.arguments.delay, request.arguments.file)); + this.errorCheck.startNew(next => + this.getDiagnosticsForProject(next, request.arguments.delay, request.arguments.file) + ); return this.notRequired(); }, [protocol.CommandTypes.Change]: (request: protocol.ChangeRequest) => { @@ -3416,7 +3981,9 @@ export class Session implements EventSender { [protocol.CommandTypes.DocumentHighlightsFull]: (request: protocol.DocumentHighlightsRequest) => { return this.requiredResponse(this.getDocumentHighlights(request.arguments, /*simplifiedResult*/ false)); }, - [protocol.CommandTypes.CompilerOptionsForInferredProjects]: (request: protocol.SetCompilerOptionsForInferredProjectsRequest) => { + [protocol.CommandTypes.CompilerOptionsForInferredProjects]: ( + request: protocol.SetCompilerOptionsForInferredProjectsRequest, + ) => { this.setCompilerOptionsForInferredProjects(request.arguments); return this.requiredResponse(/*response*/ true); }, @@ -3457,7 +4024,9 @@ export class Session implements EventSender { [protocol.CommandTypes.GetEditsForRefactor]: (request: protocol.GetEditsForRefactorRequest) => { return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ true)); }, - [protocol.CommandTypes.GetMoveToRefactoringFileSuggestions]: (request: protocol.GetMoveToRefactoringFileSuggestionsRequest) => { + [protocol.CommandTypes.GetMoveToRefactoringFileSuggestions]: ( + request: protocol.GetMoveToRefactoringFileSuggestionsRequest, + ) => { return this.requiredResponse(this.getMoveToRefactoringFileSuggestions(request.arguments)); }, [protocol.CommandTypes.GetEditsForRefactorFull]: (request: protocol.GetEditsForRefactorRequest) => { @@ -3489,10 +4058,14 @@ export class Session implements EventSender { [protocol.CommandTypes.PrepareCallHierarchy]: (request: protocol.PrepareCallHierarchyRequest) => { return this.requiredResponse(this.prepareCallHierarchy(request.arguments)); }, - [protocol.CommandTypes.ProvideCallHierarchyIncomingCalls]: (request: protocol.ProvideCallHierarchyIncomingCallsRequest) => { + [protocol.CommandTypes.ProvideCallHierarchyIncomingCalls]: ( + request: protocol.ProvideCallHierarchyIncomingCallsRequest, + ) => { return this.requiredResponse(this.provideCallHierarchyIncomingCalls(request.arguments)); }, - [protocol.CommandTypes.ProvideCallHierarchyOutgoingCalls]: (request: protocol.ProvideCallHierarchyOutgoingCallsRequest) => { + [protocol.CommandTypes.ProvideCallHierarchyOutgoingCalls]: ( + request: protocol.ProvideCallHierarchyOutgoingCallsRequest, + ) => { return this.requiredResponse(this.provideCallHierarchyOutgoingCalls(request.arguments)); }, [protocol.CommandTypes.ToggleLineComment]: (request: protocol.ToggleLineCommentRequest) => { @@ -3521,7 +4094,7 @@ export class Session implements EventSender { }, [protocol.CommandTypes.ProvideInlayHints]: (request: protocol.InlayHintsRequest) => { return this.requiredResponse(this.provideInlayHints(request.arguments)); - } + }, })); public addProtocolHandler(command: string, handler: (request: protocol.Request) => HandlerResponse) { @@ -3562,7 +4135,13 @@ export class Session implements EventSender { } 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, + `Unrecognized JSON command: ${request.command}`, + ); return { responseRequired: false }; } } @@ -3584,33 +4163,53 @@ export class Session implements EventSender { let relevantFile: protocol.FileRequestArgs | undefined; try { request = this.parseMessage(message); - relevantFile = request.arguments && (request as protocol.FileRequest).arguments.file ? (request as protocol.FileRequest).arguments : undefined; + relevantFile = request.arguments && (request as protocol.FileRequest).arguments.file + ? (request as protocol.FileRequest).arguments : undefined; tracing?.instant(tracing.Phase.Session, "request", { seq: request.seq, command: request.command }); perfLogger?.logStartCommand("" + request.command, this.toStringMessage(message).substring(0, 100)); - tracing?.push(tracing.Phase.Session, "executeCommand", { seq: request.seq, command: request.command }, /*separateBeginAndEnd*/ true); + tracing?.push( + tracing.Phase.Session, + "executeCommand", + { seq: request.seq, command: request.command }, + /*separateBeginAndEnd*/ true, + ); const { response, responseRequired } = this.executeCommand(request); tracing?.pop(); if (this.logger.hasLevel(LogLevel.requestTime)) { const elapsedTime = hrTimeToMilliseconds(this.hrtime(start)).toFixed(4); if (responseRequired) { - this.logger.perftrc(`${request.seq}::${request.command}: elapsed time (in milliseconds) ${elapsedTime}`); + this.logger.perftrc( + `${request.seq}::${request.command}: elapsed time (in milliseconds) ${elapsedTime}`, + ); } else { - this.logger.perftrc(`${request.seq}::${request.command}: async elapsed time (in milliseconds) ${elapsedTime}`); + this.logger.perftrc( + `${request.seq}::${request.command}: async elapsed time (in milliseconds) ${elapsedTime}`, + ); } } // Note: Log before writing the response, else the editor can complete its activity before the server does perfLogger?.logStopCommand("" + request.command, "Success"); - tracing?.instant(tracing.Phase.Session, "response", { seq: request.seq, command: request.command, success: !!response }); + 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); } 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, + "No content available.", + ); } } catch (err) { @@ -3620,21 +4219,29 @@ export class Session implements EventSender { if (err instanceof OperationCanceledException) { // Handle cancellation exceptions perfLogger?.logStopCommand("" + (request && request.command), "Canceled: " + err); - tracing?.instant(tracing.Phase.Session, "commandCanceled", { seq: request?.seq, command: request?.command }); + tracing?.instant(tracing.Phase.Session, "commandCanceled", { + seq: request?.seq, + command: request?.command, + }); this.doOutput({ canceled: true }, request!.command, request!.seq, /*success*/ true); return; } this.logErrorWorker(err, this.toStringMessage(message), relevantFile); perfLogger?.logStopCommand("" + (request && request.command), "Error: " + err); - tracing?.instant(tracing.Phase.Session, "commandError", { seq: request?.seq, command: request?.command, message: (err as Error).message }); + tracing?.instant(tracing.Phase.Session, "commandError", { + seq: request?.seq, + command: request?.command, + message: (err as Error).message, + }); this.doOutput( /*info*/ undefined, request ? request.command : protocol.CommandTypes.Unknown, request ? request.seq : 0, /*success*/ false, - "Error processing request. " + (err as StackTraceError).message + "\n" + (err as StackTraceError).stack); + "Error processing request. " + (err as StackTraceError).message + "\n" + (err as StackTraceError).stack, + ); } } @@ -3671,35 +4278,47 @@ interface FileAndProject { function toProtocolTextSpan(textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan { return { start: scriptInfo.positionToLineOffset(textSpan.start), - end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) + end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)), }; } -function toProtocolTextSpanWithContext(span: TextSpan, contextSpan: TextSpan | undefined, scriptInfo: ScriptInfo): protocol.TextSpanWithContext { +function toProtocolTextSpanWithContext( + span: TextSpan, + contextSpan: TextSpan | undefined, + scriptInfo: ScriptInfo, +): protocol.TextSpanWithContext { const textSpan = toProtocolTextSpan(span, scriptInfo); const contextTextSpan = contextSpan && toProtocolTextSpan(contextSpan, scriptInfo); - return contextTextSpan ? - { ...textSpan, contextStart: contextTextSpan.start, contextEnd: contextTextSpan.end } : - textSpan; + return contextTextSpan + ? { ...textSpan, contextStart: contextTextSpan.start, contextEnd: contextTextSpan.end } + : textSpan; } function convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfoOrConfig): protocol.CodeEdit { - return { start: positionToLineOffset(scriptInfo, change.span.start), end: positionToLineOffset(scriptInfo, textSpanEnd(change.span)), newText: change.newText }; + return { + start: positionToLineOffset(scriptInfo, change.span.start), + end: positionToLineOffset(scriptInfo, textSpanEnd(change.span)), + newText: change.newText, + }; } function positionToLineOffset(info: ScriptInfoOrConfig, position: number): protocol.Location { - return isConfigFile(info) ? locationFromLineAndCharacter(info.getLineAndCharacterOfPosition(position)) : info.positionToLineOffset(position); + return isConfigFile(info) ? locationFromLineAndCharacter(info.getLineAndCharacterOfPosition(position)) + : info.positionToLineOffset(position); } -function convertLinkedEditInfoToRanges(linkedEdit: LinkedEditingInfo, scriptInfo: ScriptInfo): protocol.LinkedEditingRangesBody { +function convertLinkedEditInfoToRanges( + linkedEdit: LinkedEditingInfo, + scriptInfo: ScriptInfo, +): protocol.LinkedEditingRangesBody { const ranges = linkedEdit.ranges.map( - r => { - return { - start: scriptInfo.positionToLineOffset(r.start), - end: scriptInfo.positionToLineOffset(r.start + r.length), - }; - } - ); + r => { + return { + start: scriptInfo.positionToLineOffset(r.start), + end: scriptInfo.positionToLineOffset(r.start + r.length), + }; + }, + ); if (!linkedEdit.wordPattern) return { ranges }; return { ranges, wordPattern: linkedEdit.wordPattern }; } @@ -3712,7 +4331,10 @@ function convertNewFileTextChangeToCodeEdit(textChanges: FileTextChanges): proto Debug.assert(textChanges.textChanges.length === 1); const change = first(textChanges.textChanges); Debug.assert(change.span.start === 0 && change.span.length === 0); - return { fileName: textChanges.fileName, textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: change.newText }] }; + return { + fileName: textChanges.fileName, + textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: change.newText }], + }; } export interface HandlerResponse { @@ -3720,8 +4342,14 @@ export interface HandlerResponse { responseRequired?: boolean; } -/** @internal */ // Exported only for tests -export function getLocationInNewDocument(oldText: string, renameFilename: string, renameLocation: number, edits: readonly FileTextChanges[]): protocol.Location { +/** @internal */ +// Exported only for tests +export function getLocationInNewDocument( + oldText: string, + renameFilename: string, + renameLocation: number, + edits: readonly FileTextChanges[], +): protocol.Location { const newText = applyEdits(oldText, renameFilename, edits); const { line, character } = computeLineAndCharacterOfPosition(computeLineStarts(newText), renameLocation); return { line: line + 1, offset: character + 1 }; @@ -3742,7 +4370,11 @@ function applyEdits(text: string, textFilename: string, edits: readonly FileText return text; } -function referenceEntryToReferencesResponseItem(projectService: ProjectService, { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferencedSymbolEntry, { disableLineTextInReferences }: protocol.UserPreferences): protocol.ReferencesResponseItem { +function referenceEntryToReferencesResponseItem( + projectService: ProjectService, + { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferencedSymbolEntry, + { disableLineTextInReferences }: protocol.UserPreferences, +): protocol.ReferencesResponseItem { const scriptInfo = Debug.checkDefined(projectService.getScriptInfo(fileName)); const span = toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo); const lineText = disableLineTextInReferences ? undefined : getLineText(scriptInfo, span); @@ -3751,7 +4383,7 @@ function referenceEntryToReferencesResponseItem(projectService: ProjectService, ...span, lineText, isWriteAccess, - isDefinition + isDefinition, }; } @@ -3762,8 +4394,8 @@ function getLineText(scriptInfo: ScriptInfo, span: protocol.TextSpanWithContext) function isCompletionEntryData(data: any): data is CompletionEntryData { return data === undefined || data && typeof data === "object" - && typeof data.exportName === "string" - && (data.fileName === undefined || typeof data.fileName === "string") - && (data.ambientModuleName === undefined || typeof data.ambientModuleName === "string" - && (data.isPackageJsonImport === undefined || typeof data.isPackageJsonImport === "boolean")); + && typeof data.exportName === "string" + && (data.fileName === undefined || typeof data.fileName === "string") + && (data.ambientModuleName === undefined || typeof data.ambientModuleName === "string" + && (data.isPackageJsonImport === undefined || typeof data.isPackageJsonImport === "boolean")); } diff --git a/src/server/types.ts b/src/server/types.ts index 8e1c38f9a42a3..72b6ef4ada2c6 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -12,14 +12,27 @@ export interface CompressedData { data: any; } -export type ModuleImportResult = { module: {}, error: undefined } | { module: undefined, error: { stack?: string, message?: string } }; +export type ModuleImportResult = { module: {}; error: undefined; } | { + module: undefined; + error: { stack?: string; message?: string; }; +}; /** @deprecated Use {@link ModuleImportResult} instead. */ 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; + watchFile( + path: string, + callback: FileWatcherCallback, + pollingInterval?: number, + options?: WatchOptions, + ): FileWatcher; + watchDirectory( + path: string, + callback: DirectoryWatcherCallback, + recursive?: boolean, + options?: WatchOptions, + ): FileWatcher; setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any; clearTimeout(timeoutId: any): void; setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; diff --git a/src/server/typingsCache.ts b/src/server/typingsCache.ts index 42c91be6047d1..a5df9426dae63 100644 --- a/src/server/typingsCache.ts +++ b/src/server/typingsCache.ts @@ -28,7 +28,11 @@ export interface InstallPackageOptionsWithProject extends InstallPackageOptions export interface ITypingsInstaller { isKnownTypesPackageName(name: string): boolean; installPackage(options: InstallPackageOptionsWithProject): Promise; - enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray | undefined): void; + enqueueInstallTypingsRequest( + p: Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray | undefined, + ): void; attach(projectService: ProjectService): void; onProjectClosed(p: Project): void; readonly globalTypingsCacheLocation: string | undefined; @@ -41,7 +45,7 @@ export const nullTypingsInstaller: ITypingsInstaller = { enqueueInstallTypingsRequest: noop, attach: noop, onProjectClosed: noop, - globalTypingsCacheLocation: undefined! // TODO: GH#18217 + globalTypingsCacheLocation: undefined!, // TODO: GH#18217 }; interface TypingsCacheEntry { @@ -83,9 +87,9 @@ function setIsEqualTo(arr1: string[] | undefined, arr2: string[] | undefined): b } function typeAcquisitionChanged(opt1: TypeAcquisition, opt2: TypeAcquisition): boolean { - return opt1.enable !== opt2.enable || - !setIsEqualTo(opt1.include, opt2.include) || - !setIsEqualTo(opt1.exclude, opt2.exclude); + return opt1.enable !== opt2.enable + || !setIsEqualTo(opt1.include, opt2.include) + || !setIsEqualTo(opt1.exclude, opt2.exclude); } function compilerOptionsChanged(opt1: CompilerOptions, opt2: CompilerOptions): boolean { @@ -93,7 +97,10 @@ function compilerOptionsChanged(opt1: CompilerOptions, opt2: CompilerOptions): b return getAllowJSCompilerOption(opt1) !== getAllowJSCompilerOption(opt2); } -function unresolvedImportsChanged(imports1: SortedReadonlyArray | undefined, imports2: SortedReadonlyArray | undefined): boolean { +function unresolvedImportsChanged( + imports1: SortedReadonlyArray | undefined, + imports2: SortedReadonlyArray | undefined, +): boolean { if (imports1 === imports2) { return false; } @@ -115,7 +122,11 @@ export class TypingsCache { return this.installer.installPackage(options); } - enqueueInstallTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray | undefined, forceRefresh: boolean) { + enqueueInstallTypingsForProject( + project: Project, + unresolvedImports: SortedReadonlyArray | undefined, + forceRefresh: boolean, + ) { const typeAcquisition = project.getTypeAcquisition(); if (!typeAcquisition || !typeAcquisition.enable) { @@ -123,11 +134,13 @@ export class TypingsCache { } const entry = this.perProjectCache.get(project.getProjectName()); - if (forceRefresh || - !entry || - typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) || - compilerOptionsChanged(project.getCompilationSettings(), entry.compilerOptions) || - unresolvedImportsChanged(unresolvedImports, entry.unresolvedImports)) { + 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(), { @@ -135,21 +148,27 @@ export class TypingsCache { typeAcquisition, typings: entry ? entry.typings : emptyArray, unresolvedImports, - poisoned: true + 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, newTypings: string[]) { + updateTypingsForProject( + projectName: string, + compilerOptions: CompilerOptions, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + newTypings: string[], + ) { const typings = sort(newTypings); this.perProjectCache.set(projectName, { compilerOptions, typeAcquisition, typings, unresolvedImports, - poisoned: false + poisoned: false, }); return !typeAcquisition || !typeAcquisition.enable ? emptyArray : typings; } diff --git a/src/server/utilities.ts b/src/server/utilities.ts index c9bd0ea1c6700..def0cbf5e5621 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -34,7 +34,10 @@ export class ThrottledOperations { this.host.clearTimeout(pendingTimeout); } // schedule new operation, pass arguments - this.pendingTimeouts.set(operationId, this.host.setTimeout(ThrottledOperations.run, delay, operationId, this, cb)); + this.pendingTimeouts.set( + operationId, + this.host.setTimeout(ThrottledOperations.run, delay, operationId, this, cb), + ); if (this.logger) { this.logger.info(`Scheduled: ${operationId}${pendingTimeout ? ", Cancelled earlier one" : ""}`); } diff --git a/src/server/utilitiesPublic.ts b/src/server/utilitiesPublic.ts index b6b6b8d11f7bf..c762eb6277b95 100644 --- a/src/server/utilitiesPublic.ts +++ b/src/server/utilitiesPublic.ts @@ -16,7 +16,7 @@ export enum LogLevel { terse, normal, requestTime, - verbose + verbose, } export const emptyArray: SortedReadonlyArray = createSortedArray(); @@ -41,16 +41,23 @@ export enum Msg { Perf = "Perf", } -export function createInstallTypingsRequest(project: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray, cachePath?: string): DiscoverTypings { +export function createInstallTypingsRequest( + project: Project, + typeAcquisition: TypeAcquisition, + unresolvedImports: SortedReadonlyArray, + cachePath?: string, +): DiscoverTypings { return { projectName: project.getProjectName(), - fileNames: project.getFileNames(/*excludeFilesFromExternalLibraries*/ true, /*excludeConfigFiles*/ true).concat(project.getExcludedFiles() as NormalizedPath[]), + fileNames: project.getFileNames(/*excludeFilesFromExternalLibraries*/ true, /*excludeConfigFiles*/ true).concat( + project.getExcludedFiles() as NormalizedPath[], + ), compilerOptions: project.getCompilationSettings(), typeAcquisition, unresolvedImports, projectRootPath: project.getCurrentDirectory() as Path, cachePath, - kind: "discover" + kind: "discover", }; } @@ -66,14 +73,19 @@ export namespace Errors { } } -export type NormalizedPath = string & { __normalizedPathTag: any }; +export type NormalizedPath = string & { __normalizedPathTag: any; }; export function toNormalizedPath(fileName: string): NormalizedPath { return normalizePath(fileName) as NormalizedPath; } -export function normalizedPathToPath(normalizedPath: NormalizedPath, currentDirectory: string, getCanonicalFileName: (f: string) => string): Path { - const f = isRootedDiskPath(normalizedPath) ? normalizedPath : getNormalizedAbsolutePath(normalizedPath, currentDirectory); +export function normalizedPathToPath( + normalizedPath: NormalizedPath, + currentDirectory: string, + getCanonicalFileName: (f: string) => string, +): Path { + const f = isRootedDiskPath(normalizedPath) ? normalizedPath + : getNormalizedAbsolutePath(normalizedPath, currentDirectory); return getCanonicalFileName(f) as Path; } @@ -102,7 +114,7 @@ export function createNormalizedPathMap(): NormalizedPathMap { }, remove(path) { map.delete(path); - } + }, }; } diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index f06f85142b862..f36ade5661b95 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -110,14 +110,17 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num function textSpan(startNode: Node, endNode?: Node) { const lastDecorator = canHaveDecorators(startNode) ? findLast(startNode.modifiers, isDecorator) : undefined; - const start = lastDecorator ? - skipTrivia(sourceFile.text, lastDecorator.end) : - startNode.getStart(sourceFile); + const start = lastDecorator + ? skipTrivia(sourceFile.text, lastDecorator.end) + : startNode.getStart(sourceFile); return createTextSpanFromBounds(start, (endNode || startNode).getEnd()); } function textSpanEndingAtNextToken(startNode: Node, previousTokenToFindNextEndToken: Node): TextSpan { - return textSpan(startNode, findNextToken(previousTokenToFindNextEndToken, previousTokenToFindNextEndToken.parent, sourceFile)); + return textSpan( + startNode, + findNextToken(previousTokenToFindNextEndToken, previousTokenToFindNextEndToken.parent, sourceFile), + ); } function spanInNodeIfStartsOnSameLine(node: Node | undefined, otherwiseOnNode?: Node): TextSpan | undefined { @@ -127,7 +130,11 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num return spanInNode(otherwiseOnNode); } - function spanInNodeArray(nodeArray: NodeArray | undefined, node: T, match: (value: Node) => boolean) { + function spanInNodeArray( + nodeArray: NodeArray | undefined, + node: T, + match: (value: Node) => boolean, + ) { if (nodeArray) { const index = nodeArray.indexOf(node); if (index >= 0) { @@ -135,7 +142,10 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num let end = index + 1; while (start > 0 && match(nodeArray[start - 1])) start--; while (end < nodeArray.length && match(nodeArray[end])) end++; - return createTextSpanFromBounds(skipTrivia(sourceFile.text, nodeArray[start].pos), nodeArray[end - 1].end); + return createTextSpanFromBounds( + skipTrivia(sourceFile.text, nodeArray[start].pos), + nodeArray[end - 1].end, + ); } } return textSpan(node); @@ -160,7 +170,9 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num case SyntaxKind.VariableDeclaration: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - return spanInVariableDeclaration(node as VariableDeclaration | PropertyDeclaration | PropertySignature); + return spanInVariableDeclaration( + node as VariableDeclaration | PropertyDeclaration | PropertySignature, + ); case SyntaxKind.Parameter: return spanInParameterDeclaration(node as ParameterDeclaration); @@ -346,11 +358,13 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num // Set breakpoint on identifier element of destructuring pattern // `a` or `...c` or `d: x` from // `[a, b, ...c]` or `{ a, b }` or `{ d: x }` from destructuring pattern - if ((node.kind === SyntaxKind.Identifier || - node.kind === SyntaxKind.SpreadElement || - node.kind === SyntaxKind.PropertyAssignment || - node.kind === SyntaxKind.ShorthandPropertyAssignment) && - isArrayLiteralOrObjectLiteralDestructuringPattern(parent)) { + if ( + (node.kind === SyntaxKind.Identifier + || node.kind === SyntaxKind.SpreadElement + || node.kind === SyntaxKind.PropertyAssignment + || node.kind === SyntaxKind.ShorthandPropertyAssignment) + && isArrayLiteralOrObjectLiteralDestructuringPattern(parent) + ) { return textSpan(node); } @@ -362,10 +376,14 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num // {a, b, c} = expression if (isArrayLiteralOrObjectLiteralDestructuringPattern(left)) { return spanInArrayLiteralOrObjectLiteralDestructuringPattern( - left as ArrayLiteralExpression | ObjectLiteralExpression); + left as ArrayLiteralExpression | ObjectLiteralExpression, + ); } - if (operatorToken.kind === SyntaxKind.EqualsToken && isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) { + if ( + operatorToken.kind === SyntaxKind.EqualsToken + && isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent) + ) { // Set breakpoint on assignment expression element of destructuring pattern // a = expression of // [a = expression, b, c] = someExpression or @@ -411,8 +429,10 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num switch (node.parent.kind) { case SyntaxKind.PropertyAssignment: // If this is name of property assignment, set breakpoint in the initializer - if ((node.parent as PropertyAssignment).name === node && - !isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.parent)) { + if ( + (node.parent as PropertyAssignment).name === node + && !isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.parent) + ) { return spanInNode((node.parent as PropertyAssignment).initializer); } break; @@ -451,10 +471,18 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num } } - function textSpanFromVariableDeclaration(variableDeclaration: VariableDeclaration | PropertyDeclaration | PropertySignature): TextSpan { - if (isVariableDeclarationList(variableDeclaration.parent) && variableDeclaration.parent.declarations[0] === variableDeclaration) { + function textSpanFromVariableDeclaration( + variableDeclaration: VariableDeclaration | PropertyDeclaration | PropertySignature, + ): TextSpan { + if ( + isVariableDeclarationList(variableDeclaration.parent) + && variableDeclaration.parent.declarations[0] === variableDeclaration + ) { // First declaration - include let keyword - return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent)!, variableDeclaration); + return textSpan( + findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent)!, + variableDeclaration, + ); } else { // Span only on this declaration @@ -462,7 +490,9 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num } } - function spanInVariableDeclaration(variableDeclaration: VariableDeclaration | PropertyDeclaration | PropertySignature): TextSpan | undefined { + function spanInVariableDeclaration( + variableDeclaration: VariableDeclaration | PropertyDeclaration | PropertySignature, + ): TextSpan | undefined { // If declaration of for in statement, just set the span in parent if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) { return spanInNode(variableDeclaration.parent.parent); @@ -476,14 +506,18 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num // Breakpoint is possible in variableDeclaration only if there is initialization // or its declaration from 'for of' - if ((hasOnlyExpressionInitializer(variableDeclaration) && variableDeclaration.initializer) || - hasSyntacticModifier(variableDeclaration, ModifierFlags.Export) || - parent.parent.kind === SyntaxKind.ForOfStatement) { + if ( + (hasOnlyExpressionInitializer(variableDeclaration) && variableDeclaration.initializer) + || hasSyntacticModifier(variableDeclaration, ModifierFlags.Export) + || parent.parent.kind === SyntaxKind.ForOfStatement + ) { return textSpanFromVariableDeclaration(variableDeclaration); } - if (isVariableDeclarationList(variableDeclaration.parent) && - variableDeclaration.parent.declarations[0] !== variableDeclaration) { + if ( + isVariableDeclarationList(variableDeclaration.parent) + && variableDeclaration.parent.declarations[0] !== variableDeclaration + ) { // If we cannot set breakpoint on this declaration, set it on previous one // Because the variable declaration may be binding pattern and // we would like to set breakpoint in last binding element if that's the case, @@ -494,8 +528,8 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num function canHaveSpanInParameterDeclaration(parameter: ParameterDeclaration): boolean { // Breakpoint is possible on parameter only if it has initializer, is a rest parameter, or has public or private modifier - return !!parameter.initializer || parameter.dotDotDotToken !== undefined || - hasSyntacticModifier(parameter, ModifierFlags.Public | ModifierFlags.Private); + return !!parameter.initializer || parameter.dotDotDotToken !== undefined + || hasSyntacticModifier(parameter, ModifierFlags.Public | ModifierFlags.Private); } function spanInParameterDeclaration(parameter: ParameterDeclaration): TextSpan | undefined { @@ -522,8 +556,9 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num } function canFunctionHaveSpanInWholeDeclaration(functionDeclaration: FunctionLikeDeclaration) { - return hasSyntacticModifier(functionDeclaration, ModifierFlags.Export) || - (functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration && functionDeclaration.kind !== SyntaxKind.Constructor); + return hasSyntacticModifier(functionDeclaration, ModifierFlags.Export) + || (functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration + && functionDeclaration.kind !== SyntaxKind.Constructor); } function spanInFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration): TextSpan | undefined { @@ -553,7 +588,9 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num function spanInBlock(block: Block): TextSpan | undefined { switch (block.parent.kind) { case SyntaxKind.ModuleDeclaration: - if (getModuleInstanceState(block.parent as ModuleDeclaration) !== ModuleInstanceState.Instantiated) { + if ( + getModuleInstanceState(block.parent as ModuleDeclaration) !== ModuleInstanceState.Instantiated + ) { return undefined; } @@ -567,14 +604,19 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num // Set span on previous token if it starts on same line otherwise on the first statement of the block case SyntaxKind.ForStatement: case SyntaxKind.ForOfStatement: - return spanInNodeIfStartsOnSameLine(findPrecedingToken(block.pos, sourceFile, block.parent), block.statements[0]); + return spanInNodeIfStartsOnSameLine( + findPrecedingToken(block.pos, sourceFile, block.parent), + block.statements[0], + ); } // Default action is to set on first statement return spanInNode(block.statements[0]); } - function spanInInitializerOfForLike(forLikeStatement: ForStatement | ForOfStatement | ForInStatement): TextSpan | undefined { + function spanInInitializerOfForLike( + forLikeStatement: ForStatement | ForOfStatement | ForInStatement, + ): TextSpan | undefined { if (forLikeStatement.initializer!.kind === SyntaxKind.VariableDeclarationList) { // Declaration list - set breakpoint in first declaration const variableDeclarationList = forLikeStatement.initializer as VariableDeclarationList; @@ -603,8 +645,10 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num function spanInBindingPattern(bindingPattern: BindingPattern): TextSpan | undefined { // Set breakpoint in first binding element - const firstBindingElement = forEach(bindingPattern.elements, - element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined); + const firstBindingElement = forEach( + bindingPattern.elements, + element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined, + ); if (firstBindingElement) { return spanInNode(firstBindingElement); @@ -619,12 +663,17 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num return textSpanFromVariableDeclaration(bindingPattern.parent as VariableDeclaration); } - function spanInArrayLiteralOrObjectLiteralDestructuringPattern(node: DestructuringPattern): TextSpan | undefined { + function spanInArrayLiteralOrObjectLiteralDestructuringPattern( + node: DestructuringPattern, + ): TextSpan | undefined { Debug.assert(node.kind !== SyntaxKind.ArrayBindingPattern && node.kind !== SyntaxKind.ObjectBindingPattern); - const elements: NodeArray = node.kind === SyntaxKind.ArrayLiteralExpression ? node.elements : node.properties; + const elements: NodeArray = + node.kind === SyntaxKind.ArrayLiteralExpression ? node.elements : node.properties; - const firstBindingElement = forEach(elements, - element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined); + const firstBindingElement = forEach( + elements, + element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined, + ); if (firstBindingElement) { return spanInNode(firstBindingElement); @@ -642,11 +691,19 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num switch (node.parent.kind) { case SyntaxKind.EnumDeclaration: const enumDeclaration = node.parent as EnumDeclaration; - return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile, node.parent), enumDeclaration.members.length ? enumDeclaration.members[0] : enumDeclaration.getLastToken(sourceFile)); + return spanInNodeIfStartsOnSameLine( + findPrecedingToken(node.pos, sourceFile, node.parent), + enumDeclaration.members.length ? enumDeclaration.members[0] + : enumDeclaration.getLastToken(sourceFile), + ); case SyntaxKind.ClassDeclaration: const classDeclaration = node.parent as ClassDeclaration; - return spanInNodeIfStartsOnSameLine(findPrecedingToken(node.pos, sourceFile, node.parent), classDeclaration.members.length ? classDeclaration.members[0] : classDeclaration.getLastToken(sourceFile)); + return spanInNodeIfStartsOnSameLine( + findPrecedingToken(node.pos, sourceFile, node.parent), + classDeclaration.members.length ? classDeclaration.members[0] + : classDeclaration.getLastToken(sourceFile), + ); case SyntaxKind.CaseBlock: return spanInNodeIfStartsOnSameLine(node.parent.parent, (node.parent as CaseBlock).clauses[0]); @@ -660,7 +717,10 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num switch (node.parent.kind) { case SyntaxKind.ModuleBlock: // If this is not an instantiated module block, no bp span - if (getModuleInstanceState(node.parent.parent as ModuleDeclaration) !== ModuleInstanceState.Instantiated) { + if ( + getModuleInstanceState(node.parent.parent as ModuleDeclaration) + !== ModuleInstanceState.Instantiated + ) { return undefined; } // falls through @@ -725,9 +785,11 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num } function spanInOpenParenToken(node: Node): TextSpan | undefined { - if (node.parent.kind === SyntaxKind.DoStatement || // Go to while keyword and do action instead - node.parent.kind === SyntaxKind.CallExpression || - node.parent.kind === SyntaxKind.NewExpression) { + if ( + node.parent.kind === SyntaxKind.DoStatement // Go to while keyword and do action instead + || node.parent.kind === SyntaxKind.CallExpression + || node.parent.kind === SyntaxKind.NewExpression + ) { return spanInPreviousNode(node); } @@ -767,9 +829,11 @@ export function spanInSourceFileAtLocation(sourceFile: SourceFile, position: num function spanInColonToken(node: Node): TextSpan | undefined { // Is this : specifying return annotation of the function declaration - if (isFunctionLike(node.parent) || - node.parent.kind === SyntaxKind.PropertyAssignment || - node.parent.kind === SyntaxKind.Parameter) { + if ( + isFunctionLike(node.parent) + || node.parent.kind === SyntaxKind.PropertyAssignment + || node.parent.kind === SyntaxKind.Parameter + ) { return spanInPreviousNode(node); } diff --git a/src/services/callHierarchy.ts b/src/services/callHierarchy.ts index a2d32e6da717f..ea702adb678fd 100644 --- a/src/services/callHierarchy.ts +++ b/src/services/callHierarchy.ts @@ -108,9 +108,8 @@ import { /** @internal */ export type NamedExpression = - | ClassExpression & { name: Identifier } - | FunctionExpression & { name: Identifier } - ; + | ClassExpression & { name: Identifier; } + | FunctionExpression & { name: Identifier; }; /** Indictates whether a node is named function or class expression. */ function isNamedExpression(node: Node): node is NamedExpression { @@ -119,10 +118,9 @@ function isNamedExpression(node: Node): node is NamedExpression { /** @internal */ export type ConstNamedExpression = - | ClassExpression & { name: undefined, parent: VariableDeclaration & { name: Identifier } } - | FunctionExpression & { name: undefined, parent: VariableDeclaration & { name: Identifier } } - | ArrowFunction & { name: undefined, parent: VariableDeclaration & { name: Identifier } } - ; + | ClassExpression & { name: undefined; parent: VariableDeclaration & { name: Identifier; }; } + | FunctionExpression & { name: undefined; parent: VariableDeclaration & { name: Identifier; }; } + | ArrowFunction & { name: undefined; parent: VariableDeclaration & { name: Identifier; }; }; /** Indicates whether a node is a function, arrow, or class expression assigned to a constant variable. */ function isConstNamedExpression(node: Node): node is ConstNamedExpression { @@ -136,7 +134,7 @@ function isConstNamedExpression(node: Node): node is ConstNamedExpression { /** @internal */ export type CallHierarchyDeclaration = | SourceFile - | ModuleDeclaration & { name: Identifier } + | ModuleDeclaration & { name: Identifier; } | FunctionDeclaration | ClassDeclaration | ClassStaticBlockDeclaration @@ -144,8 +142,7 @@ export type CallHierarchyDeclaration = | GetAccessorDeclaration | SetAccessorDeclaration | NamedExpression - | ConstNamedExpression - ; + | ConstNamedExpression; /** * Indicates whether a node could possibly be a call hierarchy declaration. @@ -186,7 +183,9 @@ function isValidCallHierarchyDeclaration(node: Node): node is CallHierarchyDecla } /** Gets the node that can be used as a reference to a call hierarchy declaration. */ -function getCallHierarchyDeclarationReferenceNode(node: Exclude) { +function getCallHierarchyDeclarationReferenceNode( + node: Exclude, +) { if (isSourceFile(node)) return node; if (isNamedDeclaration(node)) return node.name; if (isConstNamedExpression(node)) return node.parent.name; @@ -198,13 +197,19 @@ function isDefaultModifier(node: Node) { } /** Gets the symbol for a call hierarchy declaration. */ -function getSymbolOfCallHierarchyDeclaration(typeChecker: TypeChecker, node: Exclude) { +function getSymbolOfCallHierarchyDeclaration( + typeChecker: TypeChecker, + node: Exclude, +) { const location = getCallHierarchyDeclarationReferenceNode(node); return location && typeChecker.getSymbolAtLocation(location); } /** Gets the text and range for the name of a call hierarchy declaration. */ -function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclaration): { text: string, pos: number, end: number } { +function getCallHierarchyItemName( + program: Program, + node: CallHierarchyDeclaration, +): { text: string; pos: number; end: number; } { if (isSourceFile(node)) { return { text: node.fileName, pos: 0, end: 0 }; } @@ -226,16 +231,15 @@ function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclarati return { text: `${prefix}static {}`, pos, end }; } - const declName = isConstNamedExpression(node) ? node.parent.name : - Debug.checkDefined(getNameOfDeclaration(node), "Expected call hierarchy item to have a name"); + const declName = isConstNamedExpression(node) ? node.parent.name + : Debug.checkDefined(getNameOfDeclaration(node), "Expected call hierarchy item to have a name"); - let text = - isIdentifier(declName) ? idText(declName) : - isStringOrNumericLiteralLike(declName) ? declName.text : - isComputedPropertyName(declName) ? - isStringOrNumericLiteralLike(declName.expression) ? declName.expression.text : - undefined : - undefined; + let text = isIdentifier(declName) ? idText(declName) + : isStringOrNumericLiteralLike(declName) ? declName.text + : isComputedPropertyName(declName) + ? isStringOrNumericLiteralLike(declName.expression) ? declName.expression.text + : undefined + : undefined; if (text === undefined) { const typeChecker = program.getTypeChecker(); const symbol = typeChecker.getSymbolAtLocation(declName); @@ -246,14 +250,19 @@ function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclarati if (text === undefined) { // get the text from printing the node on a single line without comments... const printer = createPrinterWithRemoveCommentsOmitTrailingSemicolon(); - text = usingSingleLineStringWriter(writer => printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer)); + text = usingSingleLineStringWriter(writer => + printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer) + ); } return { text, pos: declName.getStart(), end: declName.getEnd() }; } function getCallHierarchItemContainerName(node: CallHierarchyDeclaration): string | undefined { if (isConstNamedExpression(node)) { - if (isModuleBlock(node.parent.parent.parent.parent) && isIdentifier(node.parent.parent.parent.parent.parent.name)) { + if ( + isModuleBlock(node.parent.parent.parent.parent) + && isIdentifier(node.parent.parent.parent.parent.parent.name) + ) { return node.parent.parent.parent.parent.parent.name.getText(); } return; @@ -277,9 +286,18 @@ function getCallHierarchItemContainerName(node: CallHierarchyDeclaration): strin } /** Finds the implementation of a function-like declaration, if one exists. */ -function findImplementation(typeChecker: TypeChecker, node: Extract): Extract | undefined; -function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined; -function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclaration): FunctionLikeDeclaration | undefined { +function findImplementation( + typeChecker: TypeChecker, + node: Extract, +): Extract | undefined; +function findImplementation( + typeChecker: TypeChecker, + node: FunctionLikeDeclaration, +): FunctionLikeDeclaration | undefined; +function findImplementation( + typeChecker: TypeChecker, + node: FunctionLikeDeclaration, +): FunctionLikeDeclaration | undefined { if (node.body) { return node; } @@ -288,7 +306,10 @@ function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclarat } if (isFunctionDeclaration(node) || isMethodDeclaration(node)) { const symbol = getSymbolOfCallHierarchyDeclaration(typeChecker, node); - if (symbol && symbol.valueDeclaration && isFunctionLikeDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.body) { + if ( + symbol && symbol.valueDeclaration && isFunctionLikeDeclaration(symbol.valueDeclaration) + && symbol.valueDeclaration.body + ) { return symbol.valueDeclaration; } return undefined; @@ -296,7 +317,10 @@ function findImplementation(typeChecker: TypeChecker, node: FunctionLikeDeclarat return node; } -function findAllInitialDeclarations(typeChecker: TypeChecker, node: Exclude) { +function findAllInitialDeclarations( + typeChecker: TypeChecker, + node: Exclude, +) { const symbol = getSymbolOfCallHierarchyDeclaration(typeChecker, node); let declarations: CallHierarchyDeclaration[] | undefined; if (symbol && symbol.declarations) { @@ -318,14 +342,17 @@ function findAllInitialDeclarations(typeChecker: TypeChecker, node: Exclude createTextSpanFromRange(entry.range))); + return createCallHierarchyIncomingCall( + createCallHierarchyItem(program, entries[0].declaration), + map(entries, entry => createTextSpanFromRange(entry.range)), + ); } /** @@ -462,24 +503,49 @@ function convertCallSiteGroupToIncomingCall(program: Program, entries: readonly * * @internal */ -export function getIncomingCalls(program: Program, declaration: CallHierarchyDeclaration, cancellationToken: CancellationToken): CallHierarchyIncomingCall[] { +export function getIncomingCalls( + program: Program, + declaration: CallHierarchyDeclaration, + cancellationToken: CancellationToken, +): CallHierarchyIncomingCall[] { // Source files and modules have no incoming calls. if (isSourceFile(declaration) || isModuleDeclaration(declaration) || isClassStaticBlockDeclaration(declaration)) { return []; } const location = getCallHierarchyDeclarationReferenceNode(declaration); - const calls = filter(FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, program.getSourceFiles(), location, /*position*/ 0, { use: FindAllReferences.FindReferencesUse.References }, convertEntryToCallSite), isDefined); - return calls ? group(calls, getCallSiteGroupKey, entries => convertCallSiteGroupToIncomingCall(program, entries)) : []; + const calls = filter( + FindAllReferences.findReferenceOrRenameEntries( + program, + cancellationToken, + program.getSourceFiles(), + location, + /*position*/ 0, + { use: FindAllReferences.FindReferencesUse.References }, + convertEntryToCallSite, + ), + isDefined, + ); + return calls ? group(calls, getCallSiteGroupKey, entries => convertCallSiteGroupToIncomingCall(program, entries)) + : []; } function createCallSiteCollector(program: Program, callSites: CallSite[]): (node: Node | undefined) => void { - function recordCallSite(node: CallExpression | NewExpression | TaggedTemplateExpression | PropertyAccessExpression | ElementAccessExpression | Decorator | JsxOpeningLikeElement | ClassStaticBlockDeclaration) { - const target = - isTaggedTemplateExpression(node) ? node.tag : - isJsxOpeningLikeElement(node) ? node.tagName : - isAccessExpression(node) ? node : - isClassStaticBlockDeclaration(node) ? node : - node.expression; + function recordCallSite( + node: + | CallExpression + | NewExpression + | TaggedTemplateExpression + | PropertyAccessExpression + | ElementAccessExpression + | Decorator + | JsxOpeningLikeElement + | ClassStaticBlockDeclaration, + ) { + const target = isTaggedTemplateExpression(node) ? node.tag + : isJsxOpeningLikeElement(node) ? node.tagName + : isAccessExpression(node) ? node + : isClassStaticBlockDeclaration(node) ? node + : node.expression; const declaration = resolveCallHierarchyDeclaration(program, target); if (declaration) { const range = createTextRangeFromNode(target, node.getSourceFile()); @@ -596,7 +662,11 @@ function collectCallSitesOfModuleDeclaration(node: ModuleDeclaration, collect: ( } } -function collectCallSitesOfFunctionLikeDeclaration(typeChecker: TypeChecker, node: FunctionLikeDeclaration, collect: (node: Node | undefined) => void) { +function collectCallSitesOfFunctionLikeDeclaration( + typeChecker: TypeChecker, + node: FunctionLikeDeclaration, + collect: (node: Node | undefined) => void, +) { const implementation = findImplementation(typeChecker, node); if (implementation) { forEach(implementation.parameters, collect); @@ -604,7 +674,10 @@ function collectCallSitesOfFunctionLikeDeclaration(typeChecker: TypeChecker, nod } } -function collectCallSitesOfClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, collect: (node: Node | undefined) => void) { +function collectCallSitesOfClassStaticBlockDeclaration( + node: ClassStaticBlockDeclaration, + collect: (node: Node | undefined) => void, +) { collect(node.body); } @@ -667,7 +740,10 @@ function createCallHierarchyOutgoingCall(to: CallHierarchyItem, fromSpans: TextS } function convertCallSiteGroupToOutgoingCall(program: Program, entries: readonly CallSite[]) { - return createCallHierarchyOutgoingCall(createCallHierarchyItem(program, entries[0].declaration), map(entries, entry => createTextSpanFromRange(entry.range))); + return createCallHierarchyOutgoingCall( + createCallHierarchyItem(program, entries[0].declaration), + map(entries, entry => createTextSpanFromRange(entry.range)), + ); } /** @@ -679,5 +755,9 @@ export function getOutgoingCalls(program: Program, declaration: CallHierarchyDec if (declaration.flags & NodeFlags.Ambient || isMethodSignature(declaration)) { return []; } - return group(collectCallSites(program, declaration), getCallSiteGroupKey, entries => convertCallSiteGroupToOutgoingCall(program, entries)); + return group( + collectCallSites(program, declaration), + getCallSiteGroupKey, + entries => convertCallSiteGroupToOutgoingCall(program, entries), + ); } diff --git a/src/services/classifier.ts b/src/services/classifier.ts index 9e2a34583e5cb..da95cf9c8e7c3 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -81,13 +81,24 @@ import { export function createClassifier(): Classifier { const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false); - function getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult { - return convertClassificationsToResult(getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent), text); + function getClassificationsForLine( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent: boolean, + ): ClassificationResult { + return convertClassificationsToResult( + getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent), + text, + ); } // If there is a syntactic classifier ('syntacticClassifierAbsent' is false), // we will be more conservative in order to avoid conflicting with the syntactic classifier. - function getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): Classifications { + function getEncodedLexicalClassifications( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent: boolean, + ): Classifications { let token = SyntaxKind.Unknown; let lastNonTriviaToken = SyntaxKind.Unknown; @@ -160,13 +171,17 @@ export function createClassifier(): Classifier { endOfLineState = end; } } - } while (token !== SyntaxKind.EndOfFileToken); + } + while (token !== SyntaxKind.EndOfFileToken); function handleToken(): void { switch (token) { case SyntaxKind.SlashToken: case SyntaxKind.SlashEqualsToken: - if (!noRegexTable[lastNonTriviaToken] && scanner.reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { + if ( + !noRegexTable[lastNonTriviaToken] + && scanner.reScanSlashToken() === SyntaxKind.RegularExpressionLiteral + ) { token = SyntaxKind.RegularExpressionLiteral; } break; @@ -220,11 +235,19 @@ export function createClassifier(): Classifier { templateStack.pop(); } else { - Debug.assertEqual(token, SyntaxKind.TemplateMiddle, "Should have been a template middle."); + Debug.assertEqual( + token, + SyntaxKind.TemplateMiddle, + "Should have been a template middle.", + ); } } else { - Debug.assertEqual(lastTemplateStackToken, SyntaxKind.OpenBraceToken, "Should have been an open brace"); + Debug.assertEqual( + lastTemplateStackToken, + SyntaxKind.OpenBraceToken, + "Should have been an open brace", + ); templateStack.pop(); } } @@ -237,7 +260,9 @@ export function createClassifier(): Classifier { if (lastNonTriviaToken === SyntaxKind.DotToken) { token = SyntaxKind.Identifier; } - else if (isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token)) { + else if ( + isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token) + ) { // We have two keywords in a row. Only treat the second as a keyword if // it's a sequence that could legally occur in the language. Otherwise // treat it as an identifier. This way, if someone writes "private var" @@ -257,23 +282,31 @@ export function createClassifier(): Classifier { /// If we consider every slash token to be a regex, we could be missing cases like "1/2/3", where /// we have a series of divide operator. this list allows us to be more accurate by ruling out /// locations where a regexp cannot exist. -const noRegexTable: true[] = arrayToNumericMap([ - SyntaxKind.Identifier, - SyntaxKind.StringLiteral, - SyntaxKind.NumericLiteral, - SyntaxKind.BigIntLiteral, - SyntaxKind.RegularExpressionLiteral, - SyntaxKind.ThisKeyword, - SyntaxKind.PlusPlusToken, - SyntaxKind.MinusMinusToken, - SyntaxKind.CloseParenToken, - SyntaxKind.CloseBracketToken, - SyntaxKind.CloseBraceToken, - SyntaxKind.TrueKeyword, - SyntaxKind.FalseKeyword, -], token => token, () => true); - -function getNewEndOfLineState(scanner: Scanner, token: SyntaxKind, lastOnTemplateStack: SyntaxKind | undefined): EndOfLineState | undefined { +const noRegexTable: true[] = arrayToNumericMap( + [ + SyntaxKind.Identifier, + SyntaxKind.StringLiteral, + SyntaxKind.NumericLiteral, + SyntaxKind.BigIntLiteral, + SyntaxKind.RegularExpressionLiteral, + SyntaxKind.ThisKeyword, + SyntaxKind.PlusPlusToken, + SyntaxKind.MinusMinusToken, + SyntaxKind.CloseParenToken, + SyntaxKind.CloseBracketToken, + SyntaxKind.CloseBraceToken, + SyntaxKind.TrueKeyword, + SyntaxKind.FalseKeyword, + ], + token => token, + () => true, +); + +function getNewEndOfLineState( + scanner: Scanner, + token: SyntaxKind, + lastOnTemplateStack: SyntaxKind | undefined, +): EndOfLineState | undefined { switch (token) { case SyntaxKind.StringLiteral: { // Check to see if we finished up on a multiline string literal. @@ -288,7 +321,8 @@ function getNewEndOfLineState(scanner: Scanner, token: SyntaxKind, lastOnTemplat // If we have an odd number of backslashes, then the multiline string is unclosed if ((numBackslashes & 1) === 0) return undefined; - return tokenText.charCodeAt(0) === CharacterCodes.doubleQuote ? EndOfLineState.InDoubleQuoteStringLiteral : EndOfLineState.InSingleQuoteStringLiteral; + return tokenText.charCodeAt(0) === CharacterCodes.doubleQuote ? EndOfLineState.InDoubleQuoteStringLiteral + : EndOfLineState.InSingleQuoteStringLiteral; } case SyntaxKind.MultiLineCommentTrivia: // Check to see if the multiline comment was unclosed. @@ -304,14 +338,24 @@ function getNewEndOfLineState(scanner: Scanner, token: SyntaxKind, lastOnTemplat case SyntaxKind.NoSubstitutionTemplateLiteral: return EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate; default: - return Debug.fail("Only 'NoSubstitutionTemplateLiteral's and 'TemplateTail's can be unterminated; got SyntaxKind #" + token); + return Debug.fail( + "Only 'NoSubstitutionTemplateLiteral's and 'TemplateTail's can be unterminated; got SyntaxKind #" + + token, + ); } } - return lastOnTemplateStack === SyntaxKind.TemplateHead ? EndOfLineState.InTemplateSubstitutionPosition : undefined; + return lastOnTemplateStack === SyntaxKind.TemplateHead ? EndOfLineState.InTemplateSubstitutionPosition + : undefined; } } -function pushEncodedClassification(start: number, end: number, offset: number, classification: ClassificationType, result: number[]): void { +function pushEncodedClassification( + start: number, + end: number, + offset: number, + classification: ClassificationType, + result: number[], +): void { if (classification === ClassificationType.whiteSpace) { // Don't bother with whitespace classifications. They're not needed. return; @@ -363,14 +407,22 @@ function convertClassificationsToResult(classifications: Classifications, text: function convertClassification(type: ClassificationType): TokenClass { switch (type) { - case ClassificationType.comment: return TokenClass.Comment; - case ClassificationType.keyword: return TokenClass.Keyword; - case ClassificationType.numericLiteral: return TokenClass.NumberLiteral; - case ClassificationType.bigintLiteral: return TokenClass.BigIntLiteral; - case ClassificationType.operator: return TokenClass.Operator; - case ClassificationType.stringLiteral: return TokenClass.StringLiteral; - case ClassificationType.whiteSpace: return TokenClass.Whitespace; - case ClassificationType.punctuation: return TokenClass.Punctuation; + case ClassificationType.comment: + return TokenClass.Comment; + case ClassificationType.keyword: + return TokenClass.Keyword; + case ClassificationType.numericLiteral: + return TokenClass.NumberLiteral; + case ClassificationType.bigintLiteral: + return TokenClass.BigIntLiteral; + case ClassificationType.operator: + return TokenClass.Operator; + case ClassificationType.stringLiteral: + return TokenClass.StringLiteral; + case ClassificationType.whiteSpace: + return TokenClass.Whitespace; + case ClassificationType.punctuation: + return TokenClass.Punctuation; case ClassificationType.identifier: case ClassificationType.className: case ClassificationType.enumName: @@ -405,7 +457,7 @@ function canFollow(keyword1: SyntaxKind, keyword2: SyntaxKind): boolean { } } -function getPrefixFromLexState(lexState: EndOfLineState): { readonly prefix: string, readonly pushTemplate?: true } { +function getPrefixFromLexState(lexState: EndOfLineState): { readonly prefix: string; readonly pushTemplate?: true; } { // If we're in a string literal, then prepend: "\ // (and a newline). That way when we lex we'll think we're still in a string literal. // @@ -413,7 +465,7 @@ function getPrefixFromLexState(lexState: EndOfLineState): { readonly prefix: str // (and a newline). That way when we lex we'll think we're still in a multiline comment. switch (lexState) { case EndOfLineState.InDoubleQuoteStringLiteral: - return { prefix: "\"\\\n" }; + return { prefix: '"\\\n' }; case EndOfLineState.InSingleQuoteStringLiteral: return { prefix: "'\\\n" }; case EndOfLineState.InMultiLineCommentTrivia: @@ -532,8 +584,16 @@ function classFromKind(token: SyntaxKind): ClassificationType { } /** @internal */ -export function getSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: ReadonlySet<__String>, span: TextSpan): ClassifiedSpan[] { - return convertClassificationsToSpans(getEncodedSemanticClassifications(typeChecker, cancellationToken, sourceFile, classifiableNames, span)); +export function getSemanticClassifications( + typeChecker: TypeChecker, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + classifiableNames: ReadonlySet<__String>, + span: TextSpan, +): ClassifiedSpan[] { + return convertClassificationsToSpans( + getEncodedSemanticClassifications(typeChecker, cancellationToken, sourceFile, classifiableNames, span), + ); } function checkForClassificationCancellation(cancellationToken: CancellationToken, kind: SyntaxKind) { @@ -560,7 +620,13 @@ function checkForClassificationCancellation(cancellationToken: CancellationToken } /** @internal */ -export function getEncodedSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: ReadonlySet<__String>, span: TextSpan): Classifications { +export function getEncodedSemanticClassifications( + typeChecker: TypeChecker, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + classifiableNames: ReadonlySet<__String>, + span: TextSpan, +): Classifications { const spans: number[] = []; sourceFile.forEachChild(function cb(node: Node): void { // Only walk into nodes that intersect the requested span. @@ -593,7 +659,11 @@ export function getEncodedSemanticClassifications(typeChecker: TypeChecker, canc } } -function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning, checker: TypeChecker): ClassificationType | undefined { +function classifySymbol( + symbol: Symbol, + meaningAtPosition: SemanticMeaning, + checker: TypeChecker, +): ClassificationType | undefined { const flags = symbol.getFlags(); if ((flags & SymbolFlags.Classifiable) === SymbolFlags.None) { return undefined; @@ -611,13 +681,16 @@ function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning, chec // Only classify a module as such if // - It appears in a namespace context. // - There exists a module declaration which actually impacts the value side. - return meaningAtPosition & SemanticMeaning.Namespace || meaningAtPosition & SemanticMeaning.Value && hasValueSideModule(symbol) ? ClassificationType.moduleName : undefined; + return meaningAtPosition & SemanticMeaning.Namespace + || meaningAtPosition & SemanticMeaning.Value && hasValueSideModule(symbol) + ? ClassificationType.moduleName : undefined; } else if (flags & SymbolFlags.Alias) { return classifySymbol(checker.getAliasedSymbol(symbol), meaningAtPosition, checker); } else if (meaningAtPosition & SemanticMeaning.Type) { - return flags & SymbolFlags.Interface ? ClassificationType.interfaceName : flags & SymbolFlags.TypeParameter ? ClassificationType.typeParameterName : undefined; + return flags & SymbolFlags.Interface ? ClassificationType.interfaceName + : flags & SymbolFlags.TypeParameter ? ClassificationType.typeParameterName : undefined; } else { return undefined; @@ -626,37 +699,66 @@ function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning, chec /** Returns true if there exists a module that introduces entities on the value side. */ function hasValueSideModule(symbol: Symbol): boolean { - return some(symbol.declarations, declaration => - isModuleDeclaration(declaration) && getModuleInstanceState(declaration) === ModuleInstanceState.Instantiated); + return some( + symbol.declarations, + declaration => + isModuleDeclaration(declaration) + && getModuleInstanceState(declaration) === ModuleInstanceState.Instantiated, + ); } function getClassificationTypeName(type: ClassificationType): ClassificationTypeNames { switch (type) { - case ClassificationType.comment: return ClassificationTypeNames.comment; - case ClassificationType.identifier: return ClassificationTypeNames.identifier; - case ClassificationType.keyword: return ClassificationTypeNames.keyword; - case ClassificationType.numericLiteral: return ClassificationTypeNames.numericLiteral; - case ClassificationType.bigintLiteral: return ClassificationTypeNames.bigintLiteral; - case ClassificationType.operator: return ClassificationTypeNames.operator; - case ClassificationType.stringLiteral: return ClassificationTypeNames.stringLiteral; - case ClassificationType.whiteSpace: return ClassificationTypeNames.whiteSpace; - case ClassificationType.text: return ClassificationTypeNames.text; - case ClassificationType.punctuation: return ClassificationTypeNames.punctuation; - case ClassificationType.className: return ClassificationTypeNames.className; - case ClassificationType.enumName: return ClassificationTypeNames.enumName; - case ClassificationType.interfaceName: return ClassificationTypeNames.interfaceName; - case ClassificationType.moduleName: return ClassificationTypeNames.moduleName; - case ClassificationType.typeParameterName: return ClassificationTypeNames.typeParameterName; - case ClassificationType.typeAliasName: return ClassificationTypeNames.typeAliasName; - case ClassificationType.parameterName: return ClassificationTypeNames.parameterName; - case ClassificationType.docCommentTagName: return ClassificationTypeNames.docCommentTagName; - case ClassificationType.jsxOpenTagName: return ClassificationTypeNames.jsxOpenTagName; - case ClassificationType.jsxCloseTagName: return ClassificationTypeNames.jsxCloseTagName; - case ClassificationType.jsxSelfClosingTagName: return ClassificationTypeNames.jsxSelfClosingTagName; - case ClassificationType.jsxAttribute: return ClassificationTypeNames.jsxAttribute; - case ClassificationType.jsxText: return ClassificationTypeNames.jsxText; - case ClassificationType.jsxAttributeStringLiteralValue: return ClassificationTypeNames.jsxAttributeStringLiteralValue; - default: return undefined!; // TODO: GH#18217 Debug.assertNever(type); + case ClassificationType.comment: + return ClassificationTypeNames.comment; + case ClassificationType.identifier: + return ClassificationTypeNames.identifier; + case ClassificationType.keyword: + return ClassificationTypeNames.keyword; + case ClassificationType.numericLiteral: + return ClassificationTypeNames.numericLiteral; + case ClassificationType.bigintLiteral: + return ClassificationTypeNames.bigintLiteral; + case ClassificationType.operator: + return ClassificationTypeNames.operator; + case ClassificationType.stringLiteral: + return ClassificationTypeNames.stringLiteral; + case ClassificationType.whiteSpace: + return ClassificationTypeNames.whiteSpace; + case ClassificationType.text: + return ClassificationTypeNames.text; + case ClassificationType.punctuation: + return ClassificationTypeNames.punctuation; + case ClassificationType.className: + return ClassificationTypeNames.className; + case ClassificationType.enumName: + return ClassificationTypeNames.enumName; + case ClassificationType.interfaceName: + return ClassificationTypeNames.interfaceName; + case ClassificationType.moduleName: + return ClassificationTypeNames.moduleName; + case ClassificationType.typeParameterName: + return ClassificationTypeNames.typeParameterName; + case ClassificationType.typeAliasName: + return ClassificationTypeNames.typeAliasName; + case ClassificationType.parameterName: + return ClassificationTypeNames.parameterName; + case ClassificationType.docCommentTagName: + return ClassificationTypeNames.docCommentTagName; + case ClassificationType.jsxOpenTagName: + return ClassificationTypeNames.jsxOpenTagName; + case ClassificationType.jsxCloseTagName: + return ClassificationTypeNames.jsxCloseTagName; + case ClassificationType.jsxSelfClosingTagName: + return ClassificationTypeNames.jsxSelfClosingTagName; + case ClassificationType.jsxAttribute: + return ClassificationTypeNames.jsxAttribute; + case ClassificationType.jsxText: + return ClassificationTypeNames.jsxText; + case ClassificationType.jsxAttributeStringLiteralValue: + return ClassificationTypeNames.jsxAttributeStringLiteralValue; + default: + return undefined!; // TODO: GH#18217 Debug.assertNever(type); } } @@ -667,7 +769,7 @@ function convertClassificationsToSpans(classifications: Classifications): Classi for (let i = 0; i < dense.length; i += 3) { result.push({ textSpan: createTextSpan(dense[i], dense[i + 1]), - classificationType: getClassificationTypeName(dense[i + 2]) + classificationType: getClassificationTypeName(dense[i + 2]), }); } @@ -675,18 +777,36 @@ function convertClassificationsToSpans(classifications: Classifications): Classi } /** @internal */ -export function getSyntacticClassifications(cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { +export function getSyntacticClassifications( + cancellationToken: CancellationToken, + sourceFile: SourceFile, + span: TextSpan, +): ClassifiedSpan[] { return convertClassificationsToSpans(getEncodedSyntacticClassifications(cancellationToken, sourceFile, span)); } /** @internal */ -export function getEncodedSyntacticClassifications(cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { +export function getEncodedSyntacticClassifications( + cancellationToken: CancellationToken, + sourceFile: SourceFile, + span: TextSpan, +): Classifications { const spanStart = span.start; const spanLength = span.length; // Make a scanner we can get trivia from. - const triviaScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, sourceFile.languageVariant, sourceFile.text); - const mergeConflictScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, sourceFile.languageVariant, sourceFile.text); + const triviaScanner = createScanner( + ScriptTarget.Latest, + /*skipTrivia*/ false, + sourceFile.languageVariant, + sourceFile.text, + ); + const mergeConflictScanner = createScanner( + ScriptTarget.Latest, + /*skipTrivia*/ false, + sourceFile.languageVariant, + sourceFile.text, + ); const result: number[] = []; processElement(sourceFile); @@ -799,7 +919,11 @@ export function getEncodedSyntacticClassifications(cancellationToken: Cancellati } pushClassification(tag.pos, 1, ClassificationType.punctuation); // "@" - pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); // e.g. "param" + pushClassification( + tag.tagName.pos, + tag.tagName.end - tag.tagName.pos, + ClassificationType.docCommentTagName, + ); // e.g. "param" pos = tag.tagName.end; let commentStart = tag.tagName.end; @@ -821,7 +945,9 @@ export function getEncodedSyntacticClassifications(cancellationToken: Cancellati break; case SyntaxKind.JSDocTypedefTag: const type = tag as JSDocTypedefTag; - commentStart = type.typeExpression?.kind === SyntaxKind.JSDocTypeExpression && type.fullName?.end || type.typeExpression?.end || commentStart; + commentStart = + type.typeExpression?.kind === SyntaxKind.JSDocTypeExpression && type.fullName?.end + || type.typeExpression?.end || commentStart; break; case SyntaxKind.JSDocCallbackTag: commentStart = (tag as JSDocCallbackTag).typeExpression.end; @@ -1088,18 +1214,22 @@ export function getEncodedSyntacticClassifications(cancellationToken: Cancellati const parent = token.parent; if (tokenKind === SyntaxKind.EqualsToken) { // the '=' in a variable declaration is special cased here. - if (parent.kind === SyntaxKind.VariableDeclaration || - parent.kind === SyntaxKind.PropertyDeclaration || - parent.kind === SyntaxKind.Parameter || - parent.kind === SyntaxKind.JsxAttribute) { + if ( + parent.kind === SyntaxKind.VariableDeclaration + || parent.kind === SyntaxKind.PropertyDeclaration + || parent.kind === SyntaxKind.Parameter + || parent.kind === SyntaxKind.JsxAttribute + ) { return ClassificationType.operator; } } - if (parent.kind === SyntaxKind.BinaryExpression || - parent.kind === SyntaxKind.PrefixUnaryExpression || - parent.kind === SyntaxKind.PostfixUnaryExpression || - parent.kind === SyntaxKind.ConditionalExpression) { + if ( + parent.kind === SyntaxKind.BinaryExpression + || parent.kind === SyntaxKind.PrefixUnaryExpression + || parent.kind === SyntaxKind.PostfixUnaryExpression + || parent.kind === SyntaxKind.ConditionalExpression + ) { return ClassificationType.operator; } } @@ -1113,7 +1243,8 @@ export function getEncodedSyntacticClassifications(cancellationToken: Cancellati return ClassificationType.bigintLiteral; } else if (tokenKind === SyntaxKind.StringLiteral) { - return token && token.parent.kind === SyntaxKind.JsxAttribute ? ClassificationType.jsxAttributeStringLiteralValue : ClassificationType.stringLiteral; + return token && token.parent.kind === SyntaxKind.JsxAttribute + ? ClassificationType.jsxAttributeStringLiteralValue : ClassificationType.stringLiteral; } else if (tokenKind === SyntaxKind.RegularExpressionLiteral) { // TODO: we should get another classification type for these literals. @@ -1156,7 +1287,8 @@ export function getEncodedSyntacticClassifications(cancellationToken: Cancellati return; case SyntaxKind.Parameter: if ((token.parent as ParameterDeclaration).name === token) { - return isThisIdentifier(token) ? ClassificationType.keyword : ClassificationType.parameterName; + return isThisIdentifier(token) ? ClassificationType.keyword + : ClassificationType.parameterName; } return; } diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index 96e246a85db80..56e97cc0278de 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -48,17 +48,33 @@ import { /** @internal */ export const enum TokenEncodingConsts { typeOffset = 8, - modifierMask = (1 << typeOffset) - 1 + modifierMask = (1 << typeOffset) - 1, } /** @internal */ export const enum TokenType { - class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member + class, + enum, + interface, + namespace, + typeParameter, + type, + parameter, + variable, + enumMember, + property, + function, + member, } /** @internal */ export const enum TokenModifier { - declaration, static, async, readonly, defaultLibrary, local + declaration, + static, + async, + readonly, + defaultLibrary, + local, } /** @@ -66,7 +82,12 @@ export const enum TokenModifier { * * @internal */ -export function getSemanticClassifications(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan2020[] { +export function getSemanticClassifications( + program: Program, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + span: TextSpan, +): ClassifiedSpan2020[] { const classifications = getEncodedSemanticClassifications(program, cancellationToken, sourceFile, span); Debug.assert(classifications.spans.length % 3 === 0); @@ -75,7 +96,7 @@ export function getSemanticClassifications(program: Program, cancellationToken: for (let i = 0; i < dense.length; i += 3) { result.push({ textSpan: createTextSpan(dense[i], dense[i + 1]), - classificationType: dense[i + 2] + classificationType: dense[i + 2], }); } @@ -83,18 +104,32 @@ export function getSemanticClassifications(program: Program, cancellationToken: } /** @internal */ -export function getEncodedSemanticClassifications(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { +export function getEncodedSemanticClassifications( + program: Program, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + span: TextSpan, +): Classifications { return { spans: getSemanticTokens(program, sourceFile, span, cancellationToken), - endOfLineState: EndOfLineState.None + endOfLineState: EndOfLineState.None, }; } -function getSemanticTokens(program: Program, sourceFile: SourceFile, span: TextSpan, cancellationToken: CancellationToken): number[] { +function getSemanticTokens( + program: Program, + sourceFile: SourceFile, + span: TextSpan, + cancellationToken: CancellationToken, +): number[] { const resultTokens: number[] = []; const collector = (node: Node, typeIdx: number, modifierSet: number) => { - resultTokens.push(node.getStart(sourceFile), node.getWidth(sourceFile), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); + resultTokens.push( + node.getStart(sourceFile), + node.getWidth(sourceFile), + ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet, + ); }; if (program && sourceFile) { @@ -103,13 +138,19 @@ function getSemanticTokens(program: Program, sourceFile: SourceFile, span: TextS return resultTokens; } -function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void, cancellationToken: CancellationToken) { +function collectTokens( + program: Program, + sourceFile: SourceFile, + span: TextSpan, + collector: (node: Node, tokenType: number, tokenModifier: number) => void, + cancellationToken: CancellationToken, +) { const typeChecker = program.getTypeChecker(); let inJSXElement = false; function visit(node: Node) { - switch(node.kind) { + switch (node.kind) { case SyntaxKind.ModuleDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: @@ -141,7 +182,8 @@ function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, if (typeIdx !== undefined) { let modifierSet = 0; if (node.parent) { - const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping.get(node.parent.kind) === typeIdx); + const parentIsDeclaration = isBindingElement(node.parent) + || tokenFromDeclarationMapping.get(node.parent.kind) === typeIdx; if (parentIsDeclaration && (node.parent as NamedDeclaration).name === node) { modifierSet = 1 << TokenModifier.declaration; } @@ -165,23 +207,31 @@ function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, modifierSet |= 1 << TokenModifier.async; } if (typeIdx !== TokenType.class && typeIdx !== TokenType.interface) { - if ((modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) || (symbol.getFlags() & SymbolFlags.EnumMember)) { + if ( + (modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) + || (symbol.getFlags() & SymbolFlags.EnumMember) + ) { modifierSet |= 1 << TokenModifier.readonly; } } - if ((typeIdx === TokenType.variable || typeIdx === TokenType.function) && isLocalDeclaration(decl, sourceFile)) { + if ( + (typeIdx === TokenType.variable || typeIdx === TokenType.function) + && isLocalDeclaration(decl, sourceFile) + ) { modifierSet |= 1 << TokenModifier.local; } if (program.isSourceFileDefaultLibrary(decl.getSourceFile())) { modifierSet |= 1 << TokenModifier.defaultLibrary; } } - else if (symbol.declarations && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile()))) { + else if ( + symbol.declarations + && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile())) + ) { modifierSet |= 1 << TokenModifier.defaultLibrary; } collector(node, typeIdx, modifierSet); - } } } @@ -200,7 +250,7 @@ function classifySymbol(symbol: Symbol, meaning: SemanticMeaning): TokenType | u else if (flags & SymbolFlags.Enum) { return TokenType.enum; } - else if (flags & SymbolFlags.TypeAlias) { + else if (flags & SymbolFlags.TypeAlias) { return TokenType.type; } else if (flags & SymbolFlags.Interface) { @@ -229,7 +279,10 @@ function reclassifyByType(typeChecker: TypeChecker, node: Node, typeIdx: TokenTy if (typeIdx !== TokenType.parameter && test(t => t.getConstructSignatures().length > 0)) { return TokenType.class; } - if (test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) || isExpressionInCallExpression(node)) { + if ( + test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) + || isExpressionInCallExpression(node) + ) { return typeIdx === TokenType.property ? TokenType.member : TokenType.function; } } @@ -242,7 +295,8 @@ function isLocalDeclaration(decl: Declaration, sourceFile: SourceFile): boolean decl = getDeclarationForBindingElement(decl); } if (isVariableDeclaration(decl)) { - return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) && decl.getSourceFile() === sourceFile; + return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) + && decl.getSourceFile() === sourceFile; } else if (isFunctionDeclaration(decl)) { return !isSourceFile(decl.parent) && decl.getSourceFile() === sourceFile; @@ -274,7 +328,8 @@ function isExpressionInCallExpression(node: Node): boolean { } function isRightSideOfQualifiedNameOrPropertyAccess(node: Node): boolean { - return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); + return (isQualifiedName(node.parent) && node.parent.right === node) + || (isPropertyAccessExpression(node.parent) && node.parent.name === node); } const tokenFromDeclarationMapping = new Map([ @@ -296,5 +351,5 @@ const tokenFromDeclarationMapping = new Map([ [SyntaxKind.TypeAliasDeclaration, TokenType.type], [SyntaxKind.TypeParameter, TokenType.typeParameter], [SyntaxKind.PropertyAssignment, TokenType.property], - [SyntaxKind.ShorthandPropertyAssignment, TokenType.property] + [SyntaxKind.ShorthandPropertyAssignment, TokenType.property], ]); diff --git a/src/services/codeFixProvider.ts b/src/services/codeFixProvider.ts index 67dbdbc9a9280..2ae0f7d8745ec 100644 --- a/src/services/codeFixProvider.ts +++ b/src/services/codeFixProvider.ts @@ -28,21 +28,66 @@ const errorCodeToFixes = createMultiMap(); const fixIdToRegistration = new Map(); /** @internal */ -export function createCodeFixActionWithoutFixAll(fixName: string, changes: FileTextChanges[], description: DiagnosticOrDiagnosticAndArguments) { - return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, /*fixId*/ undefined, /*fixAllDescription*/ undefined); +export function createCodeFixActionWithoutFixAll( + fixName: string, + changes: FileTextChanges[], + description: DiagnosticOrDiagnosticAndArguments, +) { + return createCodeFixActionWorker( + fixName, + diagnosticToString(description), + changes, + /*fixId*/ undefined, + /*fixAllDescription*/ undefined, + ); } /** @internal */ -export function createCodeFixAction(fixName: string, changes: FileTextChanges[], description: DiagnosticOrDiagnosticAndArguments, fixId: {}, fixAllDescription: DiagnosticOrDiagnosticAndArguments, command?: CodeActionCommand): CodeFixAction { - return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, fixId, diagnosticToString(fixAllDescription), command); +export function createCodeFixAction( + fixName: string, + changes: FileTextChanges[], + description: DiagnosticOrDiagnosticAndArguments, + fixId: {}, + fixAllDescription: DiagnosticOrDiagnosticAndArguments, + command?: CodeActionCommand, +): CodeFixAction { + return createCodeFixActionWorker( + fixName, + diagnosticToString(description), + changes, + fixId, + diagnosticToString(fixAllDescription), + command, + ); } /** @internal */ -export function createCodeFixActionMaybeFixAll(fixName: string, changes: FileTextChanges[], description: DiagnosticOrDiagnosticAndArguments, fixId?: {}, fixAllDescription?: DiagnosticOrDiagnosticAndArguments, command?: CodeActionCommand) { - return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, fixId, fixAllDescription && diagnosticToString(fixAllDescription), command); +export function createCodeFixActionMaybeFixAll( + fixName: string, + changes: FileTextChanges[], + description: DiagnosticOrDiagnosticAndArguments, + fixId?: {}, + fixAllDescription?: DiagnosticOrDiagnosticAndArguments, + command?: CodeActionCommand, +) { + return createCodeFixActionWorker( + fixName, + diagnosticToString(description), + changes, + fixId, + fixAllDescription && diagnosticToString(fixAllDescription), + command, + ); } -function createCodeFixActionWorker(fixName: string, description: string, changes: FileTextChanges[], fixId?: {}, fixAllDescription?: string, command?: CodeActionCommand): CodeFixAction { +function createCodeFixActionWorker( + fixName: string, + description: string, + changes: FileTextChanges[], + fixId?: {}, + fixAllDescription?: string, + command?: CodeActionCommand, +): CodeFixAction { return { fixName, description, changes, fixId, fixAllDescription, commands: command ? [command] : undefined }; } @@ -94,7 +139,10 @@ export function getAllFixes(context: CodeFixAllContext): CombinedCodeActions { } /** @internal */ -export function createCombinedCodeActions(changes: FileTextChanges[], commands?: CodeActionCommand[]): CombinedCodeActions { +export function createCombinedCodeActions( + changes: FileTextChanges[], + commands?: CodeActionCommand[], +): CombinedCodeActions { return { changes, commands }; } @@ -110,12 +158,19 @@ export function codeFixAll( use: (changes: textChanges.ChangeTracker, error: DiagnosticWithLocation, commands: CodeActionCommand[]) => void, ): CombinedCodeActions { const commands: CodeActionCommand[] = []; - const changes = textChanges.ChangeTracker.with(context, t => eachDiagnostic(context, errorCodes, diag => use(t, diag, commands))); + const changes = textChanges.ChangeTracker.with( + context, + t => eachDiagnostic(context, errorCodes, diag => use(t, diag, commands)), + ); return createCombinedCodeActions(changes, commands.length === 0 ? undefined : commands); } /** @internal */ -export function eachDiagnostic(context: CodeFixAllContext, errorCodes: readonly number[], cb: (diag: DiagnosticWithLocation) => void): void { +export function eachDiagnostic( + context: CodeFixAllContext, + errorCodes: readonly number[], + cb: (diag: DiagnosticWithLocation) => void, +): void { for (const diag of getDiagnostics(context)) { if (contains(errorCodes, diag.code)) { cb(diag as DiagnosticWithLocation); @@ -127,6 +182,6 @@ function getDiagnostics({ program, sourceFile, cancellationToken }: CodeFixConte return [ ...program.getSemanticDiagnostics(sourceFile, cancellationToken), ...program.getSyntacticDiagnostics(sourceFile, cancellationToken), - ...computeSuggestionDiagnostics(sourceFile, program, cancellationToken) + ...computeSuggestionDiagnostics(sourceFile, program, cancellationToken), ]; } diff --git a/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts b/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts index 0360e9d117a52..d12d054c24aec 100644 --- a/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts +++ b/src/services/codefixes/addConvertToUnknownForNonOverlappingTypes.ts @@ -19,25 +19,42 @@ import { } from "../_namespaces/ts.codefix"; const fixId = "addConvertToUnknownForNonOverlappingTypes"; -const errorCodes = [Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first.code]; +const errorCodes = [ + Diagnostics + .Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first + .code, +]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddConvertToUnknownForNonOverlappingTypes(context) { const assertion = getAssertion(context.sourceFile, context.span.start); if (assertion === undefined) return undefined; const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, assertion)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_unknown_conversion_for_non_overlapping_types, fixId, Diagnostics.Add_unknown_to_all_conversions_of_non_overlapping_types)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_unknown_conversion_for_non_overlapping_types, + fixId, + Diagnostics.Add_unknown_to_all_conversions_of_non_overlapping_types, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const assertion = getAssertion(diag.file, diag.start); - if (assertion) { - makeChange(changes, diag.file, assertion); - } - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const assertion = getAssertion(diag.file, diag.start); + if (assertion) { + makeChange(changes, diag.file, assertion); + } + }), }); -function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, assertion: AsExpression | TypeAssertion) { +function makeChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + assertion: AsExpression | TypeAssertion, +) { const replacement = isAsExpression(assertion) ? factory.createAsExpression(assertion.expression, factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword)) : factory.createTypeAssertion(factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword), assertion.expression); @@ -46,5 +63,8 @@ function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: Source function getAssertion(sourceFile: SourceFile, pos: number): AsExpression | TypeAssertion | undefined { if (isInJSFile(sourceFile)) return undefined; - return findAncestor(getTokenAtPosition(sourceFile, pos), (n): n is AsExpression | TypeAssertion => isAsExpression(n) || isTypeAssertionExpression(n)); + return findAncestor( + getTokenAtPosition(sourceFile, pos), + (n): n is AsExpression | TypeAssertion => isAsExpression(n) || isTypeAssertionExpression(n), + ); } diff --git a/src/services/codefixes/addEmptyExportDeclaration.ts b/src/services/codefixes/addEmptyExportDeclaration.ts index b490c66af5ecd..eb707e8aa2486 100644 --- a/src/services/codefixes/addEmptyExportDeclaration.ts +++ b/src/services/codefixes/addEmptyExportDeclaration.ts @@ -10,9 +10,15 @@ import { registerCodeFix({ errorCodes: [ - Diagnostics.await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module.code, - Diagnostics.await_using_statements_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module.code, - Diagnostics.for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module.code, + Diagnostics + .await_expressions_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module + .code, + Diagnostics + .await_using_statements_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module + .code, + Diagnostics + .for_await_loops_are_only_allowed_at_the_top_level_of_a_file_when_that_file_is_a_module_but_this_file_has_no_imports_or_exports_Consider_adding_an_empty_export_to_make_this_file_a_module + .code, ], getCodeActions: function getCodeActionsToAddEmptyExportDeclaration(context) { const { sourceFile } = context; @@ -21,10 +27,16 @@ registerCodeFix({ /*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports([]), - /*moduleSpecifier*/ undefined + /*moduleSpecifier*/ undefined, ); changes.insertNodeAtEndOfScope(sourceFile, sourceFile, exportDeclaration); }); - return [createCodeFixActionWithoutFixAll("addEmptyExportDeclaration", changes, Diagnostics.Add_export_to_make_this_file_into_a_module)]; + return [ + createCodeFixActionWithoutFixAll( + "addEmptyExportDeclaration", + changes, + Diagnostics.Add_export_to_make_this_file_into_a_module, + ), + ]; }, -}); \ No newline at end of file +}); diff --git a/src/services/codefixes/addMissingAsync.ts b/src/services/codefixes/addMissingAsync.ts index bb0510a90d0ad..31b3ed7fdc40a 100644 --- a/src/services/codefixes/addMissingAsync.ts +++ b/src/services/codefixes/addMissingAsync.ts @@ -40,7 +40,7 @@ const fixId = "addMissingAsync"; const errorCodes = [ Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code, Diagnostics.Type_0_is_not_assignable_to_type_1.code, - Diagnostics.Type_0_is_not_comparable_to_type_1.code + Diagnostics.Type_0_is_not_comparable_to_type_1.code, ]; registerCodeFix({ @@ -48,8 +48,15 @@ registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddMissingAsync(context) { const { sourceFile, errorCode, cancellationToken, program, span } = context; - const diagnostic = find(program.getTypeChecker().getDiagnostics(sourceFile, cancellationToken), getIsMatchingAsyncError(span, errorCode)); - const directSpan = diagnostic && diagnostic.relatedInformation && find(diagnostic.relatedInformation, r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code) as TextSpan | undefined; + const diagnostic = find( + program.getTypeChecker().getDiagnostics(sourceFile, cancellationToken), + getIsMatchingAsyncError(span, errorCode), + ); + const directSpan = diagnostic && diagnostic.relatedInformation + && find( + diagnostic.relatedInformation, + r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code, + ) as TextSpan | undefined; const decl = getFixableErrorSpanDeclaration(sourceFile, directSpan); if (!decl) { @@ -63,7 +70,11 @@ registerCodeFix({ const { sourceFile } = context; const fixedDeclarations = new Set(); return codeFixAll(context, errorCodes, (t, diagnostic) => { - const span = diagnostic.relatedInformation && find(diagnostic.relatedInformation, r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code) as TextSpan | undefined; + const span = diagnostic.relatedInformation + && find( + diagnostic.relatedInformation, + r => r.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code, + ) as TextSpan | undefined; const decl = getFixableErrorSpanDeclaration(sourceFile, span); if (!decl) { return; @@ -75,12 +86,28 @@ registerCodeFix({ }); type FixableDeclaration = ArrowFunction | FunctionDeclaration | FunctionExpression | MethodDeclaration; -function getFix(context: CodeFixContext | CodeFixAllContext, decl: FixableDeclaration, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Set) { +function getFix( + context: CodeFixContext | CodeFixAllContext, + decl: FixableDeclaration, + trackChanges: ContextualTrackChangesFunction, + fixedDeclarations?: Set, +) { const changes = trackChanges(t => makeChange(t, context.sourceFile, decl, fixedDeclarations)); - return createCodeFixAction(fixId, changes, Diagnostics.Add_async_modifier_to_containing_function, fixId, Diagnostics.Add_all_missing_async_modifiers); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Add_async_modifier_to_containing_function, + fixId, + Diagnostics.Add_all_missing_async_modifiers, + ); } -function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, insertionSite: FixableDeclaration, fixedDeclarations?: Set) { +function makeChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + insertionSite: FixableDeclaration, + fixedDeclarations?: Set, +) { if (fixedDeclarations) { if (fixedDeclarations.has(getNodeId(insertionSite))) { return; @@ -89,14 +116,21 @@ function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: Source fixedDeclarations?.add(getNodeId(insertionSite)); const cloneWithModifier = factory.updateModifiers( getSynthesizedDeepClone(insertionSite, /*includeTrivia*/ true), - factory.createNodeArray(factory.createModifiersFromModifierFlags(getSyntacticModifierFlags(insertionSite) | ModifierFlags.Async))); + factory.createNodeArray( + factory.createModifiersFromModifierFlags(getSyntacticModifierFlags(insertionSite) | ModifierFlags.Async), + ), + ); changeTracker.replaceNode( sourceFile, insertionSite, - cloneWithModifier); + cloneWithModifier, + ); } -function getFixableErrorSpanDeclaration(sourceFile: SourceFile, span: TextSpan | undefined): FixableDeclaration | undefined { +function getFixableErrorSpanDeclaration( + sourceFile: SourceFile, + span: TextSpan | undefined, +): FixableDeclaration | undefined { if (!span) return undefined; const token = getTokenAtPosition(sourceFile, span.start); // Checker has already done work to determine that async might be possible, and has attached @@ -106,7 +140,8 @@ function getFixableErrorSpanDeclaration(sourceFile: SourceFile, span: TextSpan | if (node.getStart(sourceFile) < span.start || node.getEnd() > textSpanEnd(span)) { return "quit"; } - return (isArrowFunction(node) || isMethodDeclaration(node) || isFunctionExpression(node) || isFunctionDeclaration(node)) && textSpansEqual(span, createTextSpanFromNode(node, sourceFile)); + return (isArrowFunction(node) || isMethodDeclaration(node) || isFunctionExpression(node) + || isFunctionDeclaration(node)) && textSpansEqual(span, createTextSpanFromNode(node, sourceFile)); }) as FixableDeclaration | undefined; return decl; @@ -114,8 +149,11 @@ function getFixableErrorSpanDeclaration(sourceFile: SourceFile, span: TextSpan | function getIsMatchingAsyncError(span: TextSpan, errorCode: number) { return ({ start, length, relatedInformation, code }: Diagnostic) => - isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) && - code === errorCode && - !!relatedInformation && - some(relatedInformation, related => related.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code); + isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) + && code === errorCode + && !!relatedInformation + && some( + relatedInformation, + related => related.code === Diagnostics.Did_you_mean_to_mark_this_function_as_async.code, + ); } diff --git a/src/services/codefixes/addMissingAwait.ts b/src/services/codefixes/addMissingAwait.ts index 267ecca7e01e1..5ff2eb308e948 100644 --- a/src/services/codefixes/addMissingAwait.ts +++ b/src/services/codefixes/addMissingAwait.ts @@ -69,8 +69,12 @@ const errorCodes = [ Diagnostics.This_condition_will_always_return_true_since_this_0_is_always_defined.code, Diagnostics.Type_0_is_not_an_array_type.code, Diagnostics.Type_0_is_not_an_array_type_or_a_string_type.code, - Diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher.code, - Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator.code, + Diagnostics + .Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher + .code, + Diagnostics + .Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator + .code, Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator.code, Diagnostics.Type_0_must_have_a_Symbol_iterator_method_that_returns_an_iterator.code, Diagnostics.Type_0_must_have_a_Symbol_asyncIterator_method_that_returns_an_async_iterator.code, @@ -93,14 +97,21 @@ registerCodeFix({ const trackChanges: ContextualTrackChangesFunction = cb => textChanges.ChangeTracker.with(context, cb); return compact([ getDeclarationSiteFix(context, expression, errorCode, checker, trackChanges), - getUseSiteFix(context, expression, errorCode, checker, trackChanges)]); + getUseSiteFix(context, expression, errorCode, checker, trackChanges), + ]); }, getAllCodeActions: context => { const { sourceFile, program, cancellationToken } = context; const checker = context.program.getTypeChecker(); const fixedDeclarations = new Set(); return codeFixAll(context, errorCodes, (t, diagnostic) => { - const expression = getAwaitErrorSpanExpression(sourceFile, diagnostic.code, diagnostic, cancellationToken, program); + const expression = getAwaitErrorSpanExpression( + sourceFile, + diagnostic.code, + diagnostic, + cancellationToken, + program, + ); if (!expression) { return; } @@ -111,19 +122,41 @@ registerCodeFix({ }, }); -function getAwaitErrorSpanExpression(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program) { +function getAwaitErrorSpanExpression( + sourceFile: SourceFile, + errorCode: number, + span: TextSpan, + cancellationToken: CancellationToken, + program: Program, +) { const expression = getFixableErrorSpanExpression(sourceFile, span); return expression - && isMissingAwaitError(sourceFile, errorCode, span, cancellationToken, program) - && isInsideAwaitableBody(expression) ? expression : undefined; + && isMissingAwaitError(sourceFile, errorCode, span, cancellationToken, program) + && isInsideAwaitableBody(expression) ? expression : undefined; } -function getDeclarationSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Set) { +function getDeclarationSiteFix( + context: CodeFixContext | CodeFixAllContext, + expression: Expression, + errorCode: number, + checker: TypeChecker, + trackChanges: ContextualTrackChangesFunction, + fixedDeclarations?: Set, +) { const { sourceFile, program, cancellationToken } = context; - const awaitableInitializers = findAwaitableInitializers(expression, sourceFile, cancellationToken, program, checker); + const awaitableInitializers = findAwaitableInitializers( + expression, + sourceFile, + cancellationToken, + program, + checker, + ); if (awaitableInitializers) { const initializerChanges = trackChanges(t => { - forEach(awaitableInitializers.initializers, ({ expression }) => makeChange(t, errorCode, sourceFile, checker, expression, fixedDeclarations)); + forEach( + awaitableInitializers.initializers, + ({ expression }) => makeChange(t, errorCode, sourceFile, checker, expression, fixedDeclarations), + ); if (fixedDeclarations && awaitableInitializers.needsSecondPassForFixAll) { makeChange(t, errorCode, sourceFile, checker, expression, fixedDeclarations); } @@ -134,24 +167,52 @@ function getDeclarationSiteFix(context: CodeFixContext | CodeFixAllContext, expr "addMissingAwaitToInitializer", initializerChanges, awaitableInitializers.initializers.length === 1 - ? [Diagnostics.Add_await_to_initializer_for_0, awaitableInitializers.initializers[0].declarationSymbol.name] - : Diagnostics.Add_await_to_initializers); + ? [ + Diagnostics.Add_await_to_initializer_for_0, + awaitableInitializers.initializers[0].declarationSymbol.name, + ] + : Diagnostics.Add_await_to_initializers, + ); } } -function getUseSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Set) { - const changes = trackChanges(t => makeChange(t, errorCode, context.sourceFile, checker, expression, fixedDeclarations)); - return createCodeFixAction(fixId, changes, Diagnostics.Add_await, fixId, Diagnostics.Fix_all_expressions_possibly_missing_await); +function getUseSiteFix( + context: CodeFixContext | CodeFixAllContext, + expression: Expression, + errorCode: number, + checker: TypeChecker, + trackChanges: ContextualTrackChangesFunction, + fixedDeclarations?: Set, +) { + const changes = trackChanges(t => + makeChange(t, errorCode, context.sourceFile, checker, expression, fixedDeclarations) + ); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Add_await, + fixId, + Diagnostics.Fix_all_expressions_possibly_missing_await, + ); } -function isMissingAwaitError(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program) { +function isMissingAwaitError( + sourceFile: SourceFile, + errorCode: number, + span: TextSpan, + cancellationToken: CancellationToken, + program: Program, +) { const checker = program.getTypeChecker(); const diagnostics = checker.getDiagnostics(sourceFile, cancellationToken); - return some(diagnostics, ({ start, length, relatedInformation, code }) => - isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) && - code === errorCode && - !!relatedInformation && - some(relatedInformation, related => related.code === Diagnostics.Did_you_forget_to_use_await.code)); + return some( + diagnostics, + ({ start, length, relatedInformation, code }) => + isNumber(start) && isNumber(length) && textSpansEqual({ start, length }, span) + && code === errorCode + && !!relatedInformation + && some(relatedInformation, related => related.code === Diagnostics.Did_you_forget_to_use_await.code), + ); } interface AwaitableInitializer { @@ -187,21 +248,29 @@ function findAwaitableInitializers( const declaration = tryCast(symbol.valueDeclaration, isVariableDeclaration); const variableName = declaration && tryCast(declaration.name, isIdentifier); const variableStatement = getAncestor(declaration, SyntaxKind.VariableStatement); - if (!declaration || !variableStatement || - declaration.type || - !declaration.initializer || - variableStatement.getSourceFile() !== sourceFile || - hasSyntacticModifier(variableStatement, ModifierFlags.Export) || - !variableName || - !isInsideAwaitableBody(declaration.initializer)) { + if ( + !declaration || !variableStatement + || declaration.type + || !declaration.initializer + || variableStatement.getSourceFile() !== sourceFile + || hasSyntacticModifier(variableStatement, ModifierFlags.Export) + || !variableName + || !isInsideAwaitableBody(declaration.initializer) + ) { isCompleteFix = false; continue; } const diagnostics = program.getSemanticDiagnostics(sourceFile, cancellationToken); - const isUsedElsewhere = FindAllReferences.Core.eachSymbolReferenceInFile(variableName, checker, sourceFile, reference => { - return identifier !== reference && !symbolReferenceIsAlsoMissingAwait(reference, diagnostics, sourceFile, checker); - }); + const isUsedElsewhere = FindAllReferences.Core.eachSymbolReferenceInFile( + variableName, + checker, + sourceFile, + reference => { + return identifier !== reference + && !symbolReferenceIsAlsoMissingAwait(reference, diagnostics, sourceFile, checker); + }, + ); if (isUsedElsewhere) { isCompleteFix = false; @@ -248,15 +317,20 @@ function getIdentifiersFromErrorSpanExpression(expression: Node, checker: TypeCh } } -function symbolReferenceIsAlsoMissingAwait(reference: Identifier, diagnostics: readonly Diagnostic[], sourceFile: SourceFile, checker: TypeChecker) { - const errorNode = isPropertyAccessExpression(reference.parent) ? reference.parent.name : - isBinaryExpression(reference.parent) ? reference.parent : - reference; +function symbolReferenceIsAlsoMissingAwait( + reference: Identifier, + diagnostics: readonly Diagnostic[], + sourceFile: SourceFile, + checker: TypeChecker, +) { + const errorNode = isPropertyAccessExpression(reference.parent) ? reference.parent.name + : isBinaryExpression(reference.parent) ? reference.parent + : reference; const diagnostic = find(diagnostics, diagnostic => - diagnostic.start === errorNode.getStart(sourceFile) && - (diagnostic.start + diagnostic.length!) === errorNode.getEnd()); + diagnostic.start === errorNode.getStart(sourceFile) + && (diagnostic.start + diagnostic.length!) === errorNode.getEnd()); - return diagnostic && contains(errorCodes, diagnostic.code) || + return diagnostic && contains(errorCodes, diagnostic.code) // A Promise is usually not correct in a binary expression (it's not valid // in an arithmetic expression and an equality comparison seems unusual), // but if the other side of the binary expression has an error, the side @@ -264,26 +338,48 @@ function symbolReferenceIsAlsoMissingAwait(reference: Identifier, diagnostics: r // Promise as an invalid operand. So if the whole binary expression is // typed `any` as a result, there is a strong likelihood that this Promise // is accidentally missing `await`. - checker.getTypeAtLocation(errorNode).flags & TypeFlags.Any; + || checker.getTypeAtLocation(errorNode).flags & TypeFlags.Any; } function isInsideAwaitableBody(node: Node) { - return node.flags & NodeFlags.AwaitContext || !!findAncestor(node, ancestor => - ancestor.parent && isArrowFunction(ancestor.parent) && ancestor.parent.body === ancestor || - isBlock(ancestor) && ( - ancestor.parent.kind === SyntaxKind.FunctionDeclaration || - ancestor.parent.kind === SyntaxKind.FunctionExpression || - ancestor.parent.kind === SyntaxKind.ArrowFunction || - ancestor.parent.kind === SyntaxKind.MethodDeclaration)); + return node.flags & NodeFlags.AwaitContext + || !!findAncestor( + node, + ancestor => + ancestor.parent && isArrowFunction(ancestor.parent) && ancestor.parent.body === ancestor + || isBlock(ancestor) && ( + ancestor.parent.kind === SyntaxKind.FunctionDeclaration + || ancestor.parent.kind === SyntaxKind.FunctionExpression + || ancestor.parent.kind === SyntaxKind.ArrowFunction + || ancestor.parent.kind === SyntaxKind.MethodDeclaration + ), + ); } -function makeChange(changeTracker: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, checker: TypeChecker, insertionSite: Expression, fixedDeclarations?: Set) { +function makeChange( + changeTracker: textChanges.ChangeTracker, + errorCode: number, + sourceFile: SourceFile, + checker: TypeChecker, + insertionSite: Expression, + fixedDeclarations?: Set, +) { if (isForOfStatement(insertionSite.parent) && !insertionSite.parent.awaitModifier) { const exprType = checker.getTypeAtLocation(insertionSite); const asyncIter = checker.getAsyncIterableType(); if (asyncIter && checker.isTypeAssignableTo(exprType, asyncIter)) { const forOf = insertionSite.parent; - changeTracker.replaceNode(sourceFile, forOf, factory.updateForOfStatement(forOf, factory.createToken(SyntaxKind.AwaitKeyword), forOf.initializer, forOf.expression, forOf.statement)); + changeTracker.replaceNode( + sourceFile, + forOf, + factory.updateForOfStatement( + forOf, + factory.createToken(SyntaxKind.AwaitKeyword), + forOf.initializer, + forOf.expression, + forOf.statement, + ), + ); return; } } @@ -310,7 +406,8 @@ function makeChange(changeTracker: textChanges.ChangeTracker, errorCode: number, changeTracker.replaceNode( sourceFile, insertionSite.parent.expression, - factory.createParenthesizedExpression(factory.createAwaitExpression(insertionSite.parent.expression))); + factory.createParenthesizedExpression(factory.createAwaitExpression(insertionSite.parent.expression)), + ); insertLeadingSemicolonIfNeeded(changeTracker, insertionSite.parent.expression, sourceFile); } else if (contains(callableConstructableErrorCodes, errorCode) && isCallOrNewExpression(insertionSite.parent)) { @@ -320,11 +417,17 @@ function makeChange(changeTracker: textChanges.ChangeTracker, errorCode: number, return; } } - changeTracker.replaceNode(sourceFile, insertionSite, factory.createParenthesizedExpression(factory.createAwaitExpression(insertionSite))); + changeTracker.replaceNode( + sourceFile, + insertionSite, + factory.createParenthesizedExpression(factory.createAwaitExpression(insertionSite)), + ); insertLeadingSemicolonIfNeeded(changeTracker, insertionSite, sourceFile); } else { - if (fixedDeclarations && isVariableDeclaration(insertionSite.parent) && isIdentifier(insertionSite.parent.name)) { + if ( + fixedDeclarations && isVariableDeclaration(insertionSite.parent) && isIdentifier(insertionSite.parent.name) + ) { const symbol = checker.getSymbolAtLocation(insertionSite.parent.name); if (symbol && !tryAddToSet(fixedDeclarations, getSymbolId(symbol))) { return; @@ -334,7 +437,11 @@ function makeChange(changeTracker: textChanges.ChangeTracker, errorCode: number, } } -function insertLeadingSemicolonIfNeeded(changeTracker: textChanges.ChangeTracker, beforeNode: Node, sourceFile: SourceFile) { +function insertLeadingSemicolonIfNeeded( + changeTracker: textChanges.ChangeTracker, + beforeNode: Node, + sourceFile: SourceFile, +) { const precedingToken = findPrecedingToken(beforeNode.pos, sourceFile); if (precedingToken && positionIsASICandidate(precedingToken.end, precedingToken.parent, sourceFile)) { changeTracker.insertText(sourceFile, beforeNode.getStart(sourceFile), ";"); diff --git a/src/services/codefixes/addMissingConst.ts b/src/services/codefixes/addMissingConst.ts index 8a848c2616f80..952bfc16117ce 100644 --- a/src/services/codefixes/addMissingConst.ts +++ b/src/services/codefixes/addMissingConst.ts @@ -27,34 +27,60 @@ import { const fixId = "addMissingConst"; const errorCodes = [ Diagnostics.Cannot_find_name_0.code, - Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer.code + Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer.code, ]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddMissingConst(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start, context.program)); + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span.start, context.program), + ); if (changes.length > 0) { - return [createCodeFixAction(fixId, changes, Diagnostics.Add_const_to_unresolved_variable, fixId, Diagnostics.Add_const_to_all_unresolved_variables)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_const_to_unresolved_variable, + fixId, + Diagnostics.Add_const_to_all_unresolved_variables, + ), + ]; } }, fixIds: [fixId], getAllCodeActions: context => { const fixedNodes = new Set(); - return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start, context.program, fixedNodes)); + return codeFixAll( + context, + errorCodes, + (changes, diag) => makeChange(changes, diag.file, diag.start, context.program, fixedNodes), + ); }, }); -function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, program: Program, fixedNodes?: Set) { +function makeChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + pos: number, + program: Program, + fixedNodes?: Set, +) { const token = getTokenAtPosition(sourceFile, pos); - const forInitializer = findAncestor(token, node => - isForInOrOfStatement(node.parent) ? node.parent.initializer === node : - isPossiblyPartOfDestructuring(node) ? false : "quit" + const forInitializer = findAncestor( + token, + node => + isForInOrOfStatement(node.parent) ? node.parent.initializer === node + : isPossiblyPartOfDestructuring(node) ? false : "quit", ); if (forInitializer) return applyChange(changeTracker, forInitializer, sourceFile, fixedNodes); const parent = token.parent; - if (isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken && isExpressionStatement(parent.parent)) { + if ( + isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken + && isExpressionStatement(parent.parent) + ) { return applyChange(changeTracker, token, sourceFile, fixedNodes); } @@ -68,9 +94,8 @@ function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: Source } const commaExpression = findAncestor(token, node => - isExpressionStatement(node.parent) ? true : - isPossiblyPartOfCommaSeperatedInitializer(node) ? false : "quit" - ); + isExpressionStatement(node.parent) ? true + : isPossiblyPartOfCommaSeperatedInitializer(node) ? false : "quit"); if (commaExpression) { const checker = program.getTypeChecker(); if (!expressionCouldBeVariableDeclaration(commaExpression, checker)) { @@ -81,7 +106,12 @@ function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: Source } } -function applyChange(changeTracker: textChanges.ChangeTracker, initializer: Node, sourceFile: SourceFile, fixedNodes?: Set) { +function applyChange( + changeTracker: textChanges.ChangeTracker, + initializer: Node, + sourceFile: SourceFile, + fixedNodes?: Set, +) { if (!fixedNodes || tryAddToSet(fixedNodes, initializer)) { changeTracker.insertModifierBefore(sourceFile, SyntaxKind.ConstKeyword, initializer); } @@ -101,10 +131,10 @@ function isPossiblyPartOfDestructuring(node: Node): boolean { } function arrayElementCouldBeVariableDeclaration(expression: Expression, checker: TypeChecker): boolean { - const identifier = - isIdentifier(expression) ? expression : - isAssignmentExpression(expression, /*excludeCompoundAssignment*/ true) && isIdentifier(expression.left) ? expression.left : - undefined; + const identifier = isIdentifier(expression) ? expression + : isAssignmentExpression(expression, /*excludeCompoundAssignment*/ true) && isIdentifier(expression.left) + ? expression.left + : undefined; return !!identifier && !checker.getSymbolAtLocation(identifier); } @@ -125,7 +155,10 @@ function expressionCouldBeVariableDeclaration(expression: Node, checker: TypeChe } if (expression.operatorToken.kind === SyntaxKind.CommaToken) { - return every([expression.left, expression.right], expression => expressionCouldBeVariableDeclaration(expression, checker)); + return every( + [expression.left, expression.right], + expression => expressionCouldBeVariableDeclaration(expression, checker), + ); } return expression.operatorToken.kind === SyntaxKind.EqualsToken diff --git a/src/services/codefixes/addMissingDeclareProperty.ts b/src/services/codefixes/addMissingDeclareProperty.ts index c46c353b37f3e..bc2adab63d02d 100644 --- a/src/services/codefixes/addMissingDeclareProperty.ts +++ b/src/services/codefixes/addMissingDeclareProperty.ts @@ -16,32 +16,56 @@ import { const fixId = "addMissingDeclareProperty"; const errorCodes = [ - Diagnostics.Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration.code, + Diagnostics + .Property_0_will_overwrite_the_base_property_in_1_If_this_is_intentional_add_an_initializer_Otherwise_add_a_declare_modifier_or_remove_the_redundant_declaration + .code, ]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddMissingDeclareOnProperty(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start)); + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span.start), + ); if (changes.length > 0) { - return [createCodeFixAction(fixId, changes, Diagnostics.Prefix_with_declare, fixId, Diagnostics.Prefix_all_incorrect_property_declarations_with_declare)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Prefix_with_declare, + fixId, + Diagnostics.Prefix_all_incorrect_property_declarations_with_declare, + ), + ]; } }, fixIds: [fixId], getAllCodeActions: context => { const fixedNodes = new Set(); - return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start, fixedNodes)); + return codeFixAll( + context, + errorCodes, + (changes, diag) => makeChange(changes, diag.file, diag.start, fixedNodes), + ); }, }); -function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, fixedNodes?: Set) { +function makeChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + pos: number, + fixedNodes?: Set, +) { const token = getTokenAtPosition(sourceFile, pos); if (!isIdentifier(token)) { return; } const declaration = token.parent; - if (declaration.kind === SyntaxKind.PropertyDeclaration && - (!fixedNodes || tryAddToSet(fixedNodes, declaration))) { + if ( + declaration.kind === SyntaxKind.PropertyDeclaration + && (!fixedNodes || tryAddToSet(fixedNodes, declaration)) + ) { changeTracker.insertModifierBefore(sourceFile, SyntaxKind.DeclareKeyword, declaration); } } diff --git a/src/services/codefixes/addMissingInvocationForDecorator.ts b/src/services/codefixes/addMissingInvocationForDecorator.ts index 330757c9fa76f..9f5ca45a6e15f 100644 --- a/src/services/codefixes/addMissingInvocationForDecorator.ts +++ b/src/services/codefixes/addMissingInvocationForDecorator.ts @@ -15,21 +15,40 @@ import { } from "../_namespaces/ts.codefix"; const fixId = "addMissingInvocationForDecorator"; -const errorCodes = [Diagnostics._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0.code]; +const errorCodes = [ + Diagnostics._0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write_0 + .code, +]; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddMissingInvocationForDecorator(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start)); - return [createCodeFixAction(fixId, changes, Diagnostics.Call_decorator_expression, fixId, Diagnostics.Add_to_all_uncalled_decorators)]; + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span.start), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Call_decorator_expression, + fixId, + Diagnostics.Add_to_all_uncalled_decorators, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)), }); function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { const token = getTokenAtPosition(sourceFile, pos); const decorator = findAncestor(token, isDecorator)!; Debug.assert(!!decorator, "Expected position to be owned by a decorator."); - const replacement = factory.createCallExpression(decorator.expression, /*typeArguments*/ undefined, /*argumentsArray*/ undefined); + const replacement = factory.createCallExpression( + decorator.expression, + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, + ); changeTracker.replaceNode(sourceFile, decorator.expression, replacement); } diff --git a/src/services/codefixes/addNameToNamelessParameter.ts b/src/services/codefixes/addNameToNamelessParameter.ts index dc36931d79237..f61b887458e09 100644 --- a/src/services/codefixes/addNameToNamelessParameter.ts +++ b/src/services/codefixes/addNameToNamelessParameter.ts @@ -19,11 +19,23 @@ const errorCodes = [Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_ registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToAddNameToNamelessParameter(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_parameter_name, fixId, Diagnostics.Add_names_to_all_parameters_without_names)]; + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span.start), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_parameter_name, + fixId, + Diagnostics.Add_names_to_all_parameters_without_names, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start)), }); function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { @@ -44,6 +56,7 @@ function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: Source "arg" + i, param.questionToken, param.dotDotDotToken ? factory.createArrayTypeNode(typeNode) : typeNode, - param.initializer); + param.initializer, + ); changeTracker.replaceNode(sourceFile, param, replacement); } diff --git a/src/services/codefixes/addOptionalPropertyUndefined.ts b/src/services/codefixes/addOptionalPropertyUndefined.ts index 7664bea35be10..cb453e7f651b4 100644 --- a/src/services/codefixes/addOptionalPropertyUndefined.ts +++ b/src/services/codefixes/addOptionalPropertyUndefined.ts @@ -35,9 +35,15 @@ import { const addOptionalPropertyUndefined = "addOptionalPropertyUndefined"; const errorCodes = [ - Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target.code, - Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code, - Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target + .code, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + .code, + Diagnostics + .Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + .code, ]; registerCodeFix({ @@ -49,7 +55,13 @@ registerCodeFix({ return undefined; } const changes = textChanges.ChangeTracker.with(context, t => addUndefinedToOptionalProperty(t, toAdd)); - return [createCodeFixActionWithoutFixAll(addOptionalPropertyUndefined, changes, Diagnostics.Add_undefined_to_optional_property_type)]; + return [ + createCodeFixActionWithoutFixAll( + addOptionalPropertyUndefined, + changes, + Diagnostics.Add_undefined_to_optional_property_type, + ), + ]; }, fixIds: [addOptionalPropertyUndefined], }); @@ -69,7 +81,11 @@ function getPropertiesToAdd(file: SourceFile, span: TextSpan, checker: TypeCheck return checker.getExactOptionalProperties(target); } -function shouldUseParentTypeOfProperty(sourceNode: Node, targetNode: Node, checker: TypeChecker): targetNode is PropertyAccessExpression { +function shouldUseParentTypeOfProperty( + sourceNode: Node, + targetNode: Node, + checker: TypeChecker, +): targetNode is PropertyAccessExpression { return isPropertyAccessExpression(targetNode) && !!checker.getExactOptionalProperties(checker.getTypeAtLocation(targetNode.expression)).length && checker.getTypeAtLocation(sourceNode) === checker.getUndefinedType(); @@ -79,7 +95,10 @@ function shouldUseParentTypeOfProperty(sourceNode: Node, targetNode: Node, check * Find the source and target of the incorrect assignment. * The call is recursive for property assignments. */ -function getSourceTarget(errorNode: Node | undefined, checker: TypeChecker): { source: Node, target: Node } | undefined { +function getSourceTarget( + errorNode: Node | undefined, + checker: TypeChecker, +): { source: Node; target: Node; } | undefined { if (!errorNode) { return undefined; } @@ -98,16 +117,21 @@ function getSourceTarget(errorNode: Node | undefined, checker: TypeChecker): { s const name = (n.valueDeclaration as any as SignatureDeclaration).parameters[i].name; if (isIdentifier(name)) return { source: errorNode, target: name }; } - else if (isPropertyAssignment(errorNode.parent) && isIdentifier(errorNode.parent.name) || - isShorthandPropertyAssignment(errorNode.parent)) { + else if ( + isPropertyAssignment(errorNode.parent) && isIdentifier(errorNode.parent.name) + || isShorthandPropertyAssignment(errorNode.parent) + ) { const parentTarget = getSourceTarget(errorNode.parent.parent, checker); if (!parentTarget) return undefined; - const prop = checker.getPropertyOfType(checker.getTypeAtLocation(parentTarget.target), (errorNode.parent.name as Identifier).text); + const prop = checker.getPropertyOfType( + checker.getTypeAtLocation(parentTarget.target), + (errorNode.parent.name as Identifier).text, + ); const declaration = prop?.declarations?.[0]; if (!declaration) return undefined; return { source: isPropertyAssignment(errorNode.parent) ? errorNode.parent.initializer : errorNode.parent.name, - target: declaration + target: declaration, }; } return undefined; @@ -119,7 +143,7 @@ function addUndefinedToOptionalProperty(changes: textChanges.ChangeTracker, toAd if (d && (isPropertySignature(d) || isPropertyDeclaration(d)) && d.type) { const t = factory.createUnionTypeNode([ ...d.type.kind === SyntaxKind.UnionType ? (d.type as UnionTypeNode).types : [d.type], - factory.createTypeReferenceNode("undefined") + factory.createTypeReferenceNode("undefined"), ]); changes.replaceNode(d.getSourceFile(), d.type, t); } diff --git a/src/services/codefixes/annotateWithTypeFromJSDoc.ts b/src/services/codefixes/annotateWithTypeFromJSDoc.ts index a2cfc5e97224c..de0a8748c4537 100644 --- a/src/services/codefixes/annotateWithTypeFromJSDoc.ts +++ b/src/services/codefixes/annotateWithTypeFromJSDoc.ts @@ -56,13 +56,22 @@ registerCodeFix({ const decl = getDeclaration(context.sourceFile, context.span.start); if (!decl) return; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, decl)); - return [createCodeFixAction(fixId, changes, Diagnostics.Annotate_with_type_from_JSDoc, fixId, Diagnostics.Annotate_everything_with_types_from_JSDoc)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Annotate_with_type_from_JSDoc, + fixId, + Diagnostics.Annotate_everything_with_types_from_JSDoc, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const decl = getDeclaration(diag.file, diag.start); - if (decl) doChange(changes, diag.file, decl); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const decl = getDeclaration(diag.file, diag.start); + if (decl) doChange(changes, diag.file, decl); + }), }); function getDeclaration(file: SourceFile, pos: number): DeclarationWithType | undefined { @@ -96,17 +105,37 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, de if (typeParameters.length) changes.insertTypeParameters(sourceFile, decl, typeParameters); } const needParens = isArrowFunction(decl) && !findChildOfKind(decl, SyntaxKind.OpenParenToken, sourceFile); - if (needParens) changes.insertNodeBefore(sourceFile, first(decl.parameters), factory.createToken(SyntaxKind.OpenParenToken)); + if (needParens) { + changes.insertNodeBefore( + sourceFile, + first(decl.parameters), + factory.createToken(SyntaxKind.OpenParenToken), + ); + } for (const param of decl.parameters) { if (!param.type) { const paramType = getJSDocType(param); - if (paramType) changes.tryInsertTypeAnnotation(sourceFile, param, visitNode(paramType, transformJSDocType, isTypeNode)); + if (paramType) { + changes.tryInsertTypeAnnotation( + sourceFile, + param, + visitNode(paramType, transformJSDocType, isTypeNode), + ); + } } } - if (needParens) changes.insertNodeAfter(sourceFile, last(decl.parameters), factory.createToken(SyntaxKind.CloseParenToken)); + if (needParens) { + changes.insertNodeAfter(sourceFile, last(decl.parameters), factory.createToken(SyntaxKind.CloseParenToken)); + } if (!decl.type) { const returnType = getJSDocReturnType(decl); - if (returnType) changes.tryInsertTypeAnnotation(sourceFile, decl, visitNode(returnType, transformJSDocType, isTypeNode)); + if (returnType) { + changes.tryInsertTypeAnnotation( + sourceFile, + decl, + visitNode(returnType, transformJSDocType, isTypeNode), + ); + } } } else { @@ -117,10 +146,10 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, de } function isDeclarationWithType(node: Node): node is DeclarationWithType { - return isFunctionLikeDeclaration(node) || - node.kind === SyntaxKind.VariableDeclaration || - node.kind === SyntaxKind.PropertySignature || - node.kind === SyntaxKind.PropertyDeclaration; + return isFunctionLikeDeclaration(node) + || node.kind === SyntaxKind.VariableDeclaration + || node.kind === SyntaxKind.PropertySignature + || node.kind === SyntaxKind.PropertyDeclaration; } function transformJSDocType(node: Node): Node { @@ -155,17 +184,25 @@ function transformJSDocTypeLiteral(node: JSDocTypeLiteral) { /*modifiers*/ undefined, isIdentifier(tag.name) ? tag.name : tag.name.right, isOptionalJSDocPropertyLikeTag(tag) ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - tag.typeExpression && visitNode(tag.typeExpression.type, transformJSDocType, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)))); + tag.typeExpression && visitNode(tag.typeExpression.type, transformJSDocType, isTypeNode) + || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + ))); setEmitFlags(typeNode, EmitFlags.SingleLine); return typeNode; } function transformJSDocOptionalType(node: JSDocOptionalType) { - return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType, isTypeNode), factory.createTypeReferenceNode("undefined", emptyArray)]); + return factory.createUnionTypeNode([ + visitNode(node.type, transformJSDocType, isTypeNode), + factory.createTypeReferenceNode("undefined", emptyArray), + ]); } function transformJSDocNullableType(node: JSDocNullableType) { - return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType, isTypeNode), factory.createTypeReferenceNode("null", emptyArray)]); + return factory.createUnionTypeNode([ + visitNode(node.type, transformJSDocType, isTypeNode), + factory.createTypeReferenceNode("null", emptyArray), + ]); } function transformJSDocVariadicType(node: JSDocVariadicType) { @@ -175,7 +212,11 @@ function transformJSDocVariadicType(node: JSDocVariadicType) { function transformJSDocFunctionType(node: JSDocFunctionType) { // TODO: This does not properly handle `function(new:C, string)` per https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System#the-javascript-type-language // however we do handle it correctly in `serializeTypeForDeclaration` in checker.ts - return factory.createFunctionTypeNode(emptyArray, node.parameters.map(transformJSDocParameter), node.type ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)); + return factory.createFunctionTypeNode( + emptyArray, + node.parameters.map(transformJSDocParameter), + node.type ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + ); } function transformJSDocParameter(node: ParameterDeclaration) { @@ -183,7 +224,14 @@ function transformJSDocParameter(node: ParameterDeclaration) { const isRest = node.type!.kind === SyntaxKind.JSDocVariadicType && index === node.parent.parameters.length - 1; // TODO: GH#18217 const name = node.name || (isRest ? "rest" : "arg" + index); const dotdotdot = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : node.dotDotDotToken; - return factory.createParameterDeclaration(node.modifiers, dotdotdot, name, node.questionToken, visitNode(node.type, transformJSDocType, isTypeNode), node.initializer); + return factory.createParameterDeclaration( + node.modifiers, + dotdotdot, + name, + node.questionToken, + visitNode(node.type, transformJSDocType, isTypeNode), + node.initializer, + ); } function transformJSDocTypeReference(node: TypeReferenceNode) { @@ -224,9 +272,15 @@ function transformJSDocIndexSignature(node: TypeReferenceNode) { /*dotDotDotToken*/ undefined, node.typeArguments![0].kind === SyntaxKind.NumberKeyword ? "n" : "s", /*questionToken*/ undefined, - factory.createTypeReferenceNode(node.typeArguments![0].kind === SyntaxKind.NumberKeyword ? "number" : "string", []), - /*initializer*/ undefined); - const indexSignature = factory.createTypeLiteralNode([factory.createIndexSignature(/*modifiers*/ undefined, [index], node.typeArguments![1])]); + factory.createTypeReferenceNode( + node.typeArguments![0].kind === SyntaxKind.NumberKeyword ? "number" : "string", + [], + ), + /*initializer*/ undefined, + ); + const indexSignature = factory.createTypeLiteralNode([ + factory.createIndexSignature(/*modifiers*/ undefined, [index], node.typeArguments![1]), + ]); setEmitFlags(indexSignature, EmitFlags.SingleLine); return indexSignature; } diff --git a/src/services/codefixes/convertConstToLet.ts b/src/services/codefixes/convertConstToLet.ts index d9817ab8250b2..de69362391c1c 100644 --- a/src/services/codefixes/convertConstToLet.ts +++ b/src/services/codefixes/convertConstToLet.ts @@ -32,7 +32,15 @@ registerCodeFix({ if (info === undefined) return; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info.token)); - return [createCodeFixActionMaybeFixAll(fixId, changes, Diagnostics.Convert_const_to_let, fixId, Diagnostics.Convert_all_const_to_let)]; + return [ + createCodeFixActionMaybeFixAll( + fixId, + changes, + Diagnostics.Convert_const_to_let, + fixId, + Diagnostics.Convert_all_const_to_let, + ), + ]; }, getAllCodeActions: context => { const { program } = context; @@ -50,7 +58,7 @@ registerCodeFix({ }); })); }, - fixIds: [fixId] + fixIds: [fixId], }); interface Info { @@ -66,7 +74,11 @@ function getInfo(sourceFile: SourceFile, pos: number, program: Program): Info | const declaration = tryCast(symbol?.valueDeclaration?.parent, isVariableDeclarationList); if (declaration === undefined) return; - const constToken = findChildOfKind>(declaration, SyntaxKind.ConstKeyword, sourceFile); + const constToken = findChildOfKind>( + declaration, + SyntaxKind.ConstKeyword, + sourceFile, + ); if (constToken === undefined) return; return { symbol, token: constToken }; diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index 5073d687a67ed..f0e73c44e9b7b 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -72,18 +72,57 @@ const errorCodes = [Diagnostics.This_constructor_function_may_be_converted_to_a_ registerCodeFix({ errorCodes, getCodeActions(context: CodeFixContext) { - const changes = textChanges.ChangeTracker.with(context, t => - doChange(t, context.sourceFile, context.span.start, context.program.getTypeChecker(), context.preferences, context.program.getCompilerOptions())); - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_function_to_an_ES2015_class, fixId, Diagnostics.Convert_all_constructor_functions_to_classes)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange( + t, + context.sourceFile, + context.span.start, + context.program.getTypeChecker(), + context.preferences, + context.program.getCompilerOptions(), + ), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_function_to_an_ES2015_class, + fixId, + Diagnostics.Convert_all_constructor_functions_to_classes, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => - doChange(changes, err.file, err.start, context.program.getTypeChecker(), context.preferences, context.program.getCompilerOptions())), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, err) => + doChange( + changes, + err.file, + err.start, + context.program.getTypeChecker(), + context.preferences, + context.program.getCompilerOptions(), + ), + ), }); -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker, preferences: UserPreferences, compilerOptions: CompilerOptions): void { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + position: number, + checker: TypeChecker, + preferences: UserPreferences, + compilerOptions: CompilerOptions, +): void { const ctorSymbol = checker.getSymbolAtLocation(getTokenAtPosition(sourceFile, position))!; - if (!ctorSymbol || !ctorSymbol.valueDeclaration || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) { + if ( + !ctorSymbol || !ctorSymbol.valueDeclaration + || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable)) + ) { // Bad input return undefined; } @@ -116,11 +155,12 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po if (member.name === "prototype" && member.declarations) { const firstDeclaration = member.declarations[0]; // only one "x.prototype = { ... }" will pass - if (member.declarations.length === 1 && - isPropertyAccessExpression(firstDeclaration) && - isBinaryExpression(firstDeclaration.parent) && - firstDeclaration.parent.operatorToken.kind === SyntaxKind.EqualsToken && - isObjectLiteralExpression(firstDeclaration.parent.right) + if ( + member.declarations.length === 1 + && isPropertyAccessExpression(firstDeclaration) + && isBinaryExpression(firstDeclaration.parent) + && firstDeclaration.parent.operatorToken.kind === SyntaxKind.EqualsToken + && isObjectLiteralExpression(firstDeclaration.parent.right) ) { const prototypes = firstDeclaration.parent.right; createClassElement(prototypes.symbol, /*modifiers*/ undefined, memberElements); @@ -137,7 +177,11 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po symbol.members.forEach((member, key) => { if (key === "constructor" && member.valueDeclaration) { const prototypeAssignment = symbol.exports?.get("prototype" as __String)?.declarations?.[0]?.parent; - if (prototypeAssignment && isBinaryExpression(prototypeAssignment) && isObjectLiteralExpression(prototypeAssignment.right) && some(prototypeAssignment.right.properties, isConstructorAssignment)) { + if ( + prototypeAssignment && isBinaryExpression(prototypeAssignment) + && isObjectLiteralExpression(prototypeAssignment.right) + && some(prototypeAssignment.right.properties, isConstructorAssignment) + ) { // fn.prototype = { constructor: fn } // Already deleted in `createClassElement` in first pass } @@ -166,7 +210,9 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po // a() {} if (isMethodDeclaration(property) || isGetOrSetAccessorDeclaration(property)) return true; // a: function() {} - if (isPropertyAssignment(property) && isFunctionExpression(property.initializer) && !!property.name) return true; + if ( + isPropertyAssignment(property) && isFunctionExpression(property.initializer) && !!property.name + ) return true; // x.prototype.constructor = fn if (isConstructorAssignment(property)) return true; return false; @@ -188,29 +234,42 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po return; } - if (some(members, m => { - const name = getNameOfDeclaration(m); - if (name && isIdentifier(name) && idText(name) === symbolName(symbol)) { - return true; // class member already made for this name - } - return false; - })) { + if ( + some(members, m => { + const name = getNameOfDeclaration(m); + if (name && isIdentifier(name) && idText(name) === symbolName(symbol)) { + return true; // class member already made for this name + } + return false; + }) + ) { return; } // delete the entire statement if this expression is the sole expression to take care of the semicolon at the end - const nodeToDelete = assignmentBinaryExpression.parent && assignmentBinaryExpression.parent.kind === SyntaxKind.ExpressionStatement + const nodeToDelete = assignmentBinaryExpression.parent + && assignmentBinaryExpression.parent.kind === SyntaxKind.ExpressionStatement ? assignmentBinaryExpression.parent : assignmentBinaryExpression; changes.delete(sourceFile, nodeToDelete); if (!assignmentExpr) { - members.push(factory.createPropertyDeclaration(modifiers, symbol.name, /*questionOrExclamationToken*/ undefined, - /*type*/ undefined, /*initializer*/ undefined)); + members.push( + factory.createPropertyDeclaration( + modifiers, + symbol.name, + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined, + ), + ); return; } // f.x = expr - if (isAccessExpression(memberDeclaration) && (isFunctionExpression(assignmentExpr) || isArrowFunction(assignmentExpr))) { + if ( + isAccessExpression(memberDeclaration) + && (isFunctionExpression(assignmentExpr) || isArrowFunction(assignmentExpr)) + ) { const quotePreference = getQuotePreference(sourceFile, preferences); const name = tryGetPropertyName(memberDeclaration, compilerOptions, quotePreference); if (name) { @@ -233,7 +292,7 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po // Drop constructor assignments if (isConstructorAssignment(property)) return; return; - } + }, ); return; } @@ -241,27 +300,56 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po // Don't try to declare members in JavaScript files if (isSourceFileJS(sourceFile)) return; if (!isPropertyAccessExpression(memberDeclaration)) return; - const prop = factory.createPropertyDeclaration(modifiers, memberDeclaration.name, /*questionOrExclamationToken*/ undefined, /*type*/ undefined, assignmentExpr); + const prop = factory.createPropertyDeclaration( + modifiers, + memberDeclaration.name, + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + assignmentExpr, + ); copyLeadingComments(assignmentBinaryExpression.parent, prop, sourceFile); members.push(prop); return; } - function createFunctionLikeExpressionMember(members: ClassElement[], expression: FunctionExpression | ArrowFunction, name: PropertyName) { + function createFunctionLikeExpressionMember( + members: ClassElement[], + expression: FunctionExpression | ArrowFunction, + name: PropertyName, + ) { if (isFunctionExpression(expression)) return createFunctionExpressionMember(members, expression, name); else return createArrowFunctionExpressionMember(members, expression, name); } - function createFunctionExpressionMember(members: ClassElement[], functionExpression: FunctionExpression, name: PropertyName) { - const fullModifiers = concatenate(modifiers, getModifierKindFromSource(functionExpression, SyntaxKind.AsyncKeyword)); - const method = factory.createMethodDeclaration(fullModifiers, /*asteriskToken*/ undefined, name, /*questionToken*/ undefined, - /*typeParameters*/ undefined, functionExpression.parameters, /*type*/ undefined, functionExpression.body); + function createFunctionExpressionMember( + members: ClassElement[], + functionExpression: FunctionExpression, + name: PropertyName, + ) { + const fullModifiers = concatenate( + modifiers, + getModifierKindFromSource(functionExpression, SyntaxKind.AsyncKeyword), + ); + const method = factory.createMethodDeclaration( + fullModifiers, + /*asteriskToken*/ undefined, + name, + /*questionToken*/ undefined, + /*typeParameters*/ undefined, + functionExpression.parameters, + /*type*/ undefined, + functionExpression.body, + ); copyLeadingComments(assignmentBinaryExpression, method, sourceFile); members.push(method); return; } - function createArrowFunctionExpressionMember(members: ClassElement[], arrowFunction: ArrowFunction, name: PropertyName) { + function createArrowFunctionExpressionMember( + members: ClassElement[], + arrowFunction: ArrowFunction, + name: PropertyName, + ) { const arrowFunctionBody = arrowFunction.body; let bodyBlock: Block; @@ -273,9 +361,20 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po else { bodyBlock = factory.createBlock([factory.createReturnStatement(arrowFunctionBody)]); } - const fullModifiers = concatenate(modifiers, getModifierKindFromSource(arrowFunction, SyntaxKind.AsyncKeyword)); - const method = factory.createMethodDeclaration(fullModifiers, /*asteriskToken*/ undefined, name, /*questionToken*/ undefined, - /*typeParameters*/ undefined, arrowFunction.parameters, /*type*/ undefined, bodyBlock); + const fullModifiers = concatenate( + modifiers, + getModifierKindFromSource(arrowFunction, SyntaxKind.AsyncKeyword), + ); + const method = factory.createMethodDeclaration( + fullModifiers, + /*asteriskToken*/ undefined, + name, + /*questionToken*/ undefined, + /*typeParameters*/ undefined, + arrowFunction.parameters, + /*type*/ undefined, + bodyBlock, + ); copyLeadingComments(assignmentBinaryExpression, method, sourceFile); members.push(method); } @@ -290,12 +389,19 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po const memberElements = createClassElementsFromSymbol(node.symbol); if (initializer.body) { - memberElements.unshift(factory.createConstructorDeclaration(/*modifiers*/ undefined, initializer.parameters, initializer.body)); + memberElements.unshift( + factory.createConstructorDeclaration(/*modifiers*/ undefined, initializer.parameters, initializer.body), + ); } const modifiers = getModifierKindFromSource(node.parent.parent, SyntaxKind.ExportKeyword); - const cls = factory.createClassDeclaration(modifiers, node.name, - /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements); + const cls = factory.createClassDeclaration( + modifiers, + node.name, + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + memberElements, + ); // Don't call copyComments here because we'll already leave them in place return cls; } @@ -303,19 +409,27 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, po function createClassFromFunction(node: FunctionDeclaration | FunctionExpression): ClassDeclaration { const memberElements = createClassElementsFromSymbol(ctorSymbol); if (node.body) { - memberElements.unshift(factory.createConstructorDeclaration(/*modifiers*/ undefined, node.parameters, node.body)); + memberElements.unshift( + factory.createConstructorDeclaration(/*modifiers*/ undefined, node.parameters, node.body), + ); } const modifiers = getModifierKindFromSource(node, SyntaxKind.ExportKeyword); - const cls = factory.createClassDeclaration(modifiers, node.name, - /*typeParameters*/ undefined, /*heritageClauses*/ undefined, memberElements); + const cls = factory.createClassDeclaration( + modifiers, + node.name, + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + memberElements, + ); // Don't call copyComments here because we'll already leave them in place return cls; } } function getModifierKindFromSource(source: Node, kind: Modifier["kind"]): readonly Modifier[] | undefined { - return canHaveModifiers(source) ? filter(source.modifiers, (modifier): modifier is Modifier => modifier.kind === kind) : undefined; + return canHaveModifiers(source) + ? filter(source.modifiers, (modifier): modifier is Modifier => modifier.kind === kind) : undefined; } function isConstructorAssignment(x: ObjectLiteralElementLike | PropertyAccessExpression) { @@ -324,7 +438,11 @@ function isConstructorAssignment(x: ObjectLiteralElementLike | PropertyAccessExp return false; } -function tryGetPropertyName(node: AccessExpression, compilerOptions: CompilerOptions, quotePreference: QuotePreference): PropertyName | undefined { +function tryGetPropertyName( + node: AccessExpression, + compilerOptions: CompilerOptions, + quotePreference: QuotePreference, +): PropertyName | undefined { if (isPropertyAccessExpression(node)) { return node.name; } @@ -335,8 +453,10 @@ function tryGetPropertyName(node: AccessExpression, compilerOptions: CompilerOpt } if (isStringLiteralLike(propName)) { - return isIdentifierText(propName.text, getEmitScriptTarget(compilerOptions)) ? factory.createIdentifier(propName.text) - : isNoSubstitutionTemplateLiteral(propName) ? factory.createStringLiteral(propName.text, quotePreference === QuotePreference.Single) + return isIdentifierText(propName.text, getEmitScriptTarget(compilerOptions)) + ? factory.createIdentifier(propName.text) + : isNoSubstitutionTemplateLiteral(propName) + ? factory.createStringLiteral(propName.text, quotePreference === QuotePreference.Single) : propName; } diff --git a/src/services/codefixes/convertLiteralTypeToMappedType.ts b/src/services/codefixes/convertLiteralTypeToMappedType.ts index 1e68d28758d1c..a8807dc206c8a 100644 --- a/src/services/codefixes/convertLiteralTypeToMappedType.ts +++ b/src/services/codefixes/convertLiteralTypeToMappedType.ts @@ -18,7 +18,9 @@ import { } from "../_namespaces/ts.codefix"; const fixId = "convertLiteralTypeToMappedType"; -const errorCodes = [Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0.code]; +const errorCodes = [ + Diagnostics._0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Did_you_mean_to_use_1_in_0.code, +]; registerCodeFix({ errorCodes, @@ -30,19 +32,28 @@ registerCodeFix({ } const { name, constraint } = info; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_1_in_0, constraint, name], fixId, Diagnostics.Convert_all_type_literals_to_mapped_type)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Convert_0_to_1_in_0, constraint, name], + fixId, + Diagnostics.Convert_all_type_literals_to_mapped_type, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, diag.start); - if (info) { - doChange(changes, diag.file, info); - } - }) + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, diag.start); + if (info) { + doChange(changes, diag.file, info); + } + }), }); interface Info { - container: TypeLiteralNode, + container: TypeLiteralNode; typeNode: TypeNode | undefined; constraint: string; name: string; @@ -63,12 +74,25 @@ function getInfo(sourceFile: SourceFile, pos: number): Info | undefined { return undefined; } -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { container, typeNode, constraint, name }: Info): void { - changes.replaceNode(sourceFile, container, factory.createMappedTypeNode( - /*readonlyToken*/ undefined, - factory.createTypeParameterDeclaration(/*modifiers*/ undefined, name, factory.createTypeReferenceNode(constraint)), - /*nameType*/ undefined, - /*questionToken*/ undefined, - typeNode, - /*members*/ undefined)); +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { container, typeNode, constraint, name }: Info, +): void { + changes.replaceNode( + sourceFile, + container, + factory.createMappedTypeNode( + /*readonlyToken*/ undefined, + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + name, + factory.createTypeReferenceNode(constraint), + ), + /*nameType*/ undefined, + /*questionToken*/ undefined, + typeNode, + /*members*/ undefined, + ), + ); } diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts index 734f1b09ec44a..d77dc005b5463 100644 --- a/src/services/codefixes/convertToAsyncFunction.ts +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -91,11 +91,26 @@ registerCodeFix({ errorCodes, getCodeActions(context: CodeFixContext) { codeActionSucceeded = true; - const changes = textChanges.ChangeTracker.with(context, (t) => convertToAsyncFunction(t, context.sourceFile, context.span.start, context.program.getTypeChecker())); - return codeActionSucceeded ? [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_async_function, fixId, Diagnostics.Convert_all_to_async_functions)] : []; + const changes = textChanges.ChangeTracker.with( + context, + t => convertToAsyncFunction(t, context.sourceFile, context.span.start, context.program.getTypeChecker()), + ); + return codeActionSucceeded + ? [createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_async_function, + fixId, + Diagnostics.Convert_all_to_async_functions, + )] : []; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker())), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker()), + ), }); const enum SynthBindingNameKind { @@ -134,18 +149,28 @@ interface PromiseReturningCallExpression extends CallExpres }; } -function convertToAsyncFunction(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker): void { +function convertToAsyncFunction( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + position: number, + checker: TypeChecker, +): void { // get the function declaration - returns a promise const tokenAtPosition = getTokenAtPosition(sourceFile, position); let functionToConvert: FunctionLikeDeclaration | undefined; // if the parent of a FunctionLikeDeclaration is a variable declaration, the convertToAsync diagnostic will be reported on the variable name - if (isIdentifier(tokenAtPosition) && isVariableDeclaration(tokenAtPosition.parent) && - tokenAtPosition.parent.initializer && isFunctionLikeDeclaration(tokenAtPosition.parent.initializer)) { + if ( + isIdentifier(tokenAtPosition) && isVariableDeclaration(tokenAtPosition.parent) + && tokenAtPosition.parent.initializer && isFunctionLikeDeclaration(tokenAtPosition.parent.initializer) + ) { functionToConvert = tokenAtPosition.parent.initializer; } else { - functionToConvert = tryCast(getContainingFunction(getTokenAtPosition(sourceFile, position)), canBeConvertedToAsync); + functionToConvert = tryCast( + getContainingFunction(getTokenAtPosition(sourceFile, position)), + canBeConvertedToAsync, + ); } if (!functionToConvert) { @@ -160,7 +185,8 @@ function convertToAsyncFunction(changes: textChanges.ChangeTracker, sourceFile: return; } - const returnStatements = functionToConvertRenamed.body && isBlock(functionToConvertRenamed.body) ? getReturnStatementsWithPromiseHandlers(functionToConvertRenamed.body, checker) : emptyArray; + const returnStatements = functionToConvertRenamed.body && isBlock(functionToConvertRenamed.body) + ? getReturnStatementsWithPromiseHandlers(functionToConvertRenamed.body, checker) : emptyArray; const transformer: Transformer = { checker, synthNamesMap, setOfExpressionsToReturn, isInJSFile: isInJavascript }; if (!returnStatements.length) { return; @@ -213,8 +239,10 @@ function getAllPromiseExpressionsToReturn(func: FunctionLikeDeclaration, checker setOfExpressionsToReturn.add(getNodeId(node)); forEach(node.arguments, visit); } - else if (isPromiseReturningCallExpression(node, checker, "catch") || - isPromiseReturningCallExpression(node, checker, "finally")) { + else if ( + isPromiseReturningCallExpression(node, checker, "catch") + || isPromiseReturningCallExpression(node, checker, "finally") + ) { setOfExpressionsToReturn.add(getNodeId(node)); // if .catch() or .finally() is the last call in the chain, move leftward in the chain until we hit something else that should be returned forEachChild(node, visit); @@ -231,7 +259,11 @@ function getAllPromiseExpressionsToReturn(func: FunctionLikeDeclaration, checker return setOfExpressionsToReturn; } -function isPromiseReturningCallExpression(node: Node, checker: TypeChecker, name: Name): node is PromiseReturningCallExpression { +function isPromiseReturningCallExpression( + node: Node, + checker: TypeChecker, + name: Name, +): node is PromiseReturningCallExpression { if (!isCallExpression(node)) return false; const isExpressionOfName = hasPropertyAccessExpressionWithName(node, name); const nodeType = isExpressionOfName && checker.getTypeAtLocation(node); @@ -245,7 +277,11 @@ function isReferenceToType(type: Type, target: Type) { && (type as TypeReference).target === target; } -function getExplicitPromisedTypeOfPromiseReturningCallExpression(node: PromiseReturningCallExpression<"then" | "catch" | "finally">, callback: Expression, checker: TypeChecker) { +function getExplicitPromisedTypeOfPromiseReturningCallExpression( + node: PromiseReturningCallExpression<"then" | "catch" | "finally">, + callback: Expression, + checker: TypeChecker, +) { if (node.expression.name.escapedText === "finally") { // for a `finally`, there's no type argument return undefined; @@ -255,8 +291,10 @@ function getExplicitPromisedTypeOfPromiseReturningCallExpression(node: PromiseRe // type argument supplied for the callback. For other promise types we would need a more complex heuristic to determine // which type argument is safe to use as an annotation. const promiseType = checker.getTypeAtLocation(node.expression.expression); - if (isReferenceToType(promiseType, checker.getPromiseType()) || - isReferenceToType(promiseType, checker.getPromiseLikeType())) { + if ( + isReferenceToType(promiseType, checker.getPromiseType()) + || isReferenceToType(promiseType, checker.getPromiseLikeType()) + ) { if (node.expression.name.escapedText === "then") { if (callback === elementAt(node.arguments, 0)) { // for the `onfulfilled` callback, use the first type argument @@ -283,7 +321,11 @@ function isPromiseTypedExpression(node: Node, checker: TypeChecker): node is Exp This function collects all existing identifier names and names of identifiers that will be created in the refactor. It then checks for any collisions and renames them through getSynthesizedDeepClone */ -function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: TypeChecker, synthNamesMap: Map): FunctionLikeDeclaration { +function renameCollidingVarNames( + nodeToRename: FunctionLikeDeclaration, + checker: TypeChecker, + synthNamesMap: Map, +): FunctionLikeDeclaration { const identsToRenameMap = new Map(); // key is the symbol id const collidingSymbolMap = createMultiMap(); forEachChild(nodeToRename, function visit(node: Node) { @@ -303,18 +345,24 @@ function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: // will eventually become // const response = await fetch('...') // so we push an entry for 'response'. - if (lastCallSignature && !isParameter(node.parent) && !isFunctionLikeDeclaration(node.parent) && !synthNamesMap.has(symbolIdString)) { + if ( + lastCallSignature && !isParameter(node.parent) && !isFunctionLikeDeclaration(node.parent) + && !synthNamesMap.has(symbolIdString) + ) { const firstParameter = firstOrUndefined(lastCallSignature.parameters); const ident = firstParameter?.valueDeclaration - && isParameter(firstParameter.valueDeclaration) - && tryCast(firstParameter.valueDeclaration.name, isIdentifier) + && isParameter(firstParameter.valueDeclaration) + && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic); const synthName = getNewNameIfConflict(ident, collidingSymbolMap); synthNamesMap.set(symbolIdString, synthName); collidingSymbolMap.add(ident.text, symbol); } // We only care about identifiers that are parameters, variable declarations, or binding elements - else if (node.parent && (isParameter(node.parent) || isVariableDeclaration(node.parent) || isBindingElement(node.parent))) { + else if ( + node.parent + && (isParameter(node.parent) || isVariableDeclaration(node.parent) || isBindingElement(node.parent)) + ) { const originalName = node.text; const collidingSymbols = collidingSymbolMap.get(originalName); @@ -343,7 +391,8 @@ function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: original.dotDotDotToken, original.propertyName || original.name, renameInfo, - original.initializer); + original.initializer, + ); } } else if (isIdentifier(original)) { @@ -377,9 +426,22 @@ function silentFail() { * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows the continuation to which this expression belongs. * @param continuationArgName The argument name for the continuation that follows this call. */ -function transformExpression(returnContextNode: Expression, node: Expression, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { +function transformExpression( + returnContextNode: Expression, + node: Expression, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, +): readonly Statement[] { if (isPromiseReturningCallExpression(node, transformer.checker, "then")) { - return transformThen(node, elementAt(node.arguments, 0), elementAt(node.arguments, 1), transformer, hasContinuation, continuationArgName); + return transformThen( + node, + elementAt(node.arguments, 0), + elementAt(node.arguments, 1), + transformer, + hasContinuation, + continuationArgName, + ); } if (isPromiseReturningCallExpression(node, transformer.checker, "catch")) { return transformCatch(node, elementAt(node.arguments, 0), transformer, hasContinuation, continuationArgName); @@ -388,13 +450,25 @@ function transformExpression(returnContextNode: Expression, node: Expression, tr return transformFinally(node, elementAt(node.arguments, 0), transformer, hasContinuation, continuationArgName); } if (isPropertyAccessExpression(node)) { - return transformExpression(returnContextNode, node.expression, transformer, hasContinuation, continuationArgName); + return transformExpression( + returnContextNode, + node.expression, + transformer, + hasContinuation, + continuationArgName, + ); } const nodeType = transformer.checker.getTypeAtLocation(node); if (nodeType && transformer.checker.getPromisedTypeOfPromise(nodeType)) { Debug.assertNode(getOriginalNode(node).parent, isPropertyAccessExpression); - return transformPromiseExpressionOfPropertyAccess(returnContextNode, node, transformer, hasContinuation, continuationArgName); + return transformPromiseExpressionOfPropertyAccess( + returnContextNode, + node, + transformer, + hasContinuation, + continuationArgName, + ); } return silentFail(); @@ -414,7 +488,11 @@ function createUniqueSynthName(prevArgName: SynthIdentifier): SynthIdentifier { return createSynthIdentifier(renamedPrevArg); } -function getPossibleNameForVarDecl(node: PromiseReturningCallExpression<"then" | "catch" | "finally">, transformer: Transformer, continuationArgName?: SynthBindingName) { +function getPossibleNameForVarDecl( + node: PromiseReturningCallExpression<"then" | "catch" | "finally">, + transformer: Transformer, + continuationArgName?: SynthBindingName, +) { let possibleNameForVarDecl: SynthIdentifier | undefined; // If there is another call in the chain after the .catch() or .finally() we are transforming, we will need to save the result of both paths @@ -433,7 +511,10 @@ function getPossibleNameForVarDecl(node: PromiseReturningCallExpression<"then" | }); } else { - possibleNameForVarDecl = createSynthIdentifier(factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic), continuationArgName.types); + possibleNameForVarDecl = createSynthIdentifier( + factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic), + continuationArgName.types, + ); } // We are about to write a 'let' variable declaration, but `transformExpression` for both @@ -445,7 +526,13 @@ function getPossibleNameForVarDecl(node: PromiseReturningCallExpression<"then" | return possibleNameForVarDecl; } -function finishCatchOrFinallyTransform(node: PromiseReturningCallExpression<"then" | "catch" | "finally">, transformer: Transformer, tryStatement: TryStatement, possibleNameForVarDecl: SynthIdentifier | undefined, continuationArgName?: SynthBindingName) { +function finishCatchOrFinallyTransform( + node: PromiseReturningCallExpression<"then" | "catch" | "finally">, + transformer: Transformer, + tryStatement: TryStatement, + possibleNameForVarDecl: SynthIdentifier | undefined, + continuationArgName?: SynthBindingName, +) { const statements: Statement[] = []; // In order to avoid an implicit any, we will synthesize a type for the declaration using the unions of the types of both paths (try block and catch block) @@ -455,9 +542,15 @@ function finishCatchOrFinallyTransform(node: PromiseReturningCallExpression<"the varDeclIdentifier = getSynthesizedDeepClone(declareSynthIdentifier(possibleNameForVarDecl)); const typeArray: Type[] = possibleNameForVarDecl.types; const unionType = transformer.checker.getUnionType(typeArray, UnionReduction.Subtype); - const unionTypeNode = transformer.isInJSFile ? undefined : transformer.checker.typeToTypeNode(unionType, /*enclosingDeclaration*/ undefined, /*flags*/ undefined); - const varDecl = [factory.createVariableDeclaration(varDeclIdentifier, /*exclamationToken*/ undefined, unionTypeNode)]; - const varDeclList = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList(varDecl, NodeFlags.Let)); + const unionTypeNode = transformer.isInJSFile ? undefined + : transformer.checker.typeToTypeNode(unionType, /*enclosingDeclaration*/ undefined, /*flags*/ undefined); + const varDecl = [ + factory.createVariableDeclaration(varDeclIdentifier, /*exclamationToken*/ undefined, unionTypeNode), + ]; + const varDeclList = factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList(varDecl, NodeFlags.Let), + ); statements.push(varDeclList); } @@ -471,9 +564,10 @@ function finishCatchOrFinallyTransform(node: PromiseReturningCallExpression<"the getSynthesizedDeepClone(declareSynthBindingPattern(continuationArgName)), /*exclamationToken*/ undefined, /*type*/ undefined, - varDeclIdentifier - )], - NodeFlags.Const))); + varDeclIdentifier, + ), + ], NodeFlags.Const), + )); } return statements; @@ -483,21 +577,46 @@ function finishCatchOrFinallyTransform(node: PromiseReturningCallExpression<"the * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows this continuation. * @param continuationArgName The argument name for the continuation that follows this call. */ -function transformFinally(node: PromiseReturningCallExpression<"finally">, onFinally: Expression | undefined, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { +function transformFinally( + node: PromiseReturningCallExpression<"finally">, + onFinally: Expression | undefined, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, +): readonly Statement[] { if (!onFinally || isNullOrUndefined(transformer, onFinally)) { // Ignore this call as it has no effect on the result - return transformExpression(/* returnContextNode */ node, node.expression.expression, transformer, hasContinuation, continuationArgName); + return transformExpression( + /* returnContextNode */ node, + node.expression.expression, + transformer, + hasContinuation, + continuationArgName, + ); } const possibleNameForVarDecl = getPossibleNameForVarDecl(node, transformer, continuationArgName); // Transform the left-hand-side of `.finally` into an array of inlined statements. We pass `true` for hasContinuation as `node` is the outer continuation. - const inlinedLeftHandSide = transformExpression(/*returnContextNode*/ node, node.expression.expression, transformer, /*hasContinuation*/ true, possibleNameForVarDecl); + const inlinedLeftHandSide = transformExpression( + /*returnContextNode*/ node, + node.expression.expression, + transformer, + /*hasContinuation*/ true, + possibleNameForVarDecl, + ); if (hasFailed()) return silentFail(); // shortcut out of more work // Transform the callback argument into an array of inlined statements. We pass whether we have an outer continuation here // as that indicates whether `return` is valid. - const inlinedCallback = transformCallbackArgument(onFinally, hasContinuation, /*continuationArgName*/ undefined, /*inputArgName*/ undefined, node, transformer); + const inlinedCallback = transformCallbackArgument( + onFinally, + hasContinuation, + /*continuationArgName*/ undefined, + /*inputArgName*/ undefined, + node, + transformer, + ); if (hasFailed()) return silentFail(); // shortcut out of more work const tryBlock = factory.createBlock(inlinedLeftHandSide); @@ -510,26 +629,54 @@ function transformFinally(node: PromiseReturningCallExpression<"finally">, onFin * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows this continuation. * @param continuationArgName The argument name for the continuation that follows this call. */ -function transformCatch(node: PromiseReturningCallExpression<"then" | "catch">, onRejected: Expression | undefined, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { +function transformCatch( + node: PromiseReturningCallExpression<"then" | "catch">, + onRejected: Expression | undefined, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, +): readonly Statement[] { if (!onRejected || isNullOrUndefined(transformer, onRejected)) { // Ignore this call as it has no effect on the result - return transformExpression(/* returnContextNode */ node, node.expression.expression, transformer, hasContinuation, continuationArgName); + return transformExpression( + /* returnContextNode */ node, + node.expression.expression, + transformer, + hasContinuation, + continuationArgName, + ); } const inputArgName = getArgBindingName(onRejected, transformer); const possibleNameForVarDecl = getPossibleNameForVarDecl(node, transformer, continuationArgName); // Transform the left-hand-side of `.then`/`.catch` into an array of inlined statements. We pass `true` for hasContinuation as `node` is the outer continuation. - const inlinedLeftHandSide = transformExpression(/*returnContextNode*/ node, node.expression.expression, transformer, /*hasContinuation*/ true, possibleNameForVarDecl); + const inlinedLeftHandSide = transformExpression( + /*returnContextNode*/ node, + node.expression.expression, + transformer, + /*hasContinuation*/ true, + possibleNameForVarDecl, + ); if (hasFailed()) return silentFail(); // shortcut out of more work // Transform the callback argument into an array of inlined statements. We pass whether we have an outer continuation here // as that indicates whether `return` is valid. - const inlinedCallback = transformCallbackArgument(onRejected, hasContinuation, possibleNameForVarDecl, inputArgName, node, transformer); + const inlinedCallback = transformCallbackArgument( + onRejected, + hasContinuation, + possibleNameForVarDecl, + inputArgName, + node, + transformer, + ); if (hasFailed()) return silentFail(); // shortcut out of more work const tryBlock = factory.createBlock(inlinedLeftHandSide); - const catchClause = factory.createCatchClause(inputArgName && getSynthesizedDeepClone(declareSynthBindingName(inputArgName)), factory.createBlock(inlinedCallback)); + const catchClause = factory.createCatchClause( + inputArgName && getSynthesizedDeepClone(declareSynthBindingName(inputArgName)), + factory.createBlock(inlinedCallback), + ); const tryStatement = factory.createTryStatement(tryBlock, catchClause, /*finallyBlock*/ undefined); return finishCatchOrFinallyTransform(node, transformer, tryStatement, possibleNameForVarDecl, continuationArgName); } @@ -538,7 +685,14 @@ function transformCatch(node: PromiseReturningCallExpression<"then" | "catch">, * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows this continuation. * @param continuationArgName The argument name for the continuation that follows this call. */ -function transformThen(node: PromiseReturningCallExpression<"then">, onFulfilled: Expression | undefined, onRejected: Expression | undefined, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { +function transformThen( + node: PromiseReturningCallExpression<"then">, + onFulfilled: Expression | undefined, + onRejected: Expression | undefined, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, +): readonly Statement[] { if (!onFulfilled || isNullOrUndefined(transformer, onFulfilled)) { // If we don't have an `onfulfilled` callback, try treating this as a `.catch`. return transformCatch(node, onRejected, transformer, hasContinuation, continuationArgName); @@ -552,12 +706,25 @@ function transformThen(node: PromiseReturningCallExpression<"then">, onFulfilled const inputArgName = getArgBindingName(onFulfilled, transformer); // Transform the left-hand-side of `.then` into an array of inlined statements. We pass `true` for hasContinuation as `node` is the outer continuation. - const inlinedLeftHandSide = transformExpression(node.expression.expression, node.expression.expression, transformer, /*hasContinuation*/ true, inputArgName); + const inlinedLeftHandSide = transformExpression( + node.expression.expression, + node.expression.expression, + transformer, + /*hasContinuation*/ true, + inputArgName, + ); if (hasFailed()) return silentFail(); // shortcut out of more work // Transform the callback argument into an array of inlined statements. We pass whether we have an outer continuation here // as that indicates whether `return` is valid. - const inlinedCallback = transformCallbackArgument(onFulfilled, hasContinuation, continuationArgName, inputArgName, node, transformer); + const inlinedCallback = transformCallbackArgument( + onFulfilled, + hasContinuation, + continuationArgName, + inputArgName, + node, + transformer, + ); if (hasFailed()) return silentFail(); // shortcut out of more work return concatenate(inlinedLeftHandSide, inlinedCallback); @@ -566,7 +733,13 @@ function transformThen(node: PromiseReturningCallExpression<"then">, onFulfilled /** * Transforms the 'x' part of `x.then(...)`, or the 'y()' part of `y().catch(...)`, where 'x' and 'y()' are Promises. */ -function transformPromiseExpressionOfPropertyAccess(returnContextNode: Expression, node: Expression, transformer: Transformer, hasContinuation: boolean, continuationArgName?: SynthBindingName): readonly Statement[] { +function transformPromiseExpressionOfPropertyAccess( + returnContextNode: Expression, + node: Expression, + transformer: Transformer, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, +): readonly Statement[] { if (shouldReturn(returnContextNode, transformer)) { let returnValue = getSynthesizedDeepClone(node); if (hasContinuation) { @@ -575,10 +748,18 @@ function transformPromiseExpressionOfPropertyAccess(returnContextNode: Expressio return [factory.createReturnStatement(returnValue)]; } - return createVariableOrAssignmentOrExpressionStatement(continuationArgName, factory.createAwaitExpression(node), /*typeAnnotation*/ undefined); + return createVariableOrAssignmentOrExpressionStatement( + continuationArgName, + factory.createAwaitExpression(node), + /*typeAnnotation*/ undefined, + ); } -function createVariableOrAssignmentOrExpressionStatement(variableName: SynthBindingName | undefined, rightHandSide: Expression, typeAnnotation: TypeNode | undefined): readonly Statement[] { +function createVariableOrAssignmentOrExpressionStatement( + variableName: SynthBindingName | undefined, + rightHandSide: Expression, + typeAnnotation: TypeNode | undefined, +): readonly Statement[] { if (!variableName || isEmptyBindingName(variableName)) { // if there's no argName to assign to, there still might be side effects return [factory.createExpressionStatement(rightHandSide)]; @@ -586,7 +767,14 @@ function createVariableOrAssignmentOrExpressionStatement(variableName: SynthBind if (isSynthIdentifier(variableName) && variableName.hasBeenDeclared) { // if the variable has already been declared, we don't need "let" or "const" - return [factory.createExpressionStatement(factory.createAssignment(getSynthesizedDeepClone(referenceSynthIdentifier(variableName)), rightHandSide))]; + return [ + factory.createExpressionStatement( + factory.createAssignment( + getSynthesizedDeepClone(referenceSynthIdentifier(variableName)), + rightHandSide, + ), + ), + ]; } return [ @@ -597,16 +785,26 @@ function createVariableOrAssignmentOrExpressionStatement(variableName: SynthBind getSynthesizedDeepClone(declareSynthBindingName(variableName)), /*exclamationToken*/ undefined, typeAnnotation, - rightHandSide)], - NodeFlags.Const))]; + rightHandSide, + ), + ], NodeFlags.Const), + ), + ]; } -function maybeAnnotateAndReturn(expressionToReturn: Expression | undefined, typeAnnotation: TypeNode | undefined): Statement[] { +function maybeAnnotateAndReturn( + expressionToReturn: Expression | undefined, + typeAnnotation: TypeNode | undefined, +): Statement[] { if (typeAnnotation && expressionToReturn) { const name = factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic); return [ - ...createVariableOrAssignmentOrExpressionStatement(createSynthIdentifier(name), expressionToReturn, typeAnnotation), - factory.createReturnStatement(name) + ...createVariableOrAssignmentOrExpressionStatement( + createSynthIdentifier(name), + expressionToReturn, + typeAnnotation, + ), + factory.createReturnStatement(name), ]; } return [factory.createReturnStatement(expressionToReturn)]; @@ -618,7 +816,14 @@ function maybeAnnotateAndReturn(expressionToReturn: Expression | undefined, type * @param continuationArgName The argument name for the continuation that follows this call. * @param inputArgName The argument name provided to this call */ -function transformCallbackArgument(func: Expression, hasContinuation: boolean, continuationArgName: SynthBindingName | undefined, inputArgName: SynthBindingName | undefined, parent: PromiseReturningCallExpression<"then" | "catch" | "finally">, transformer: Transformer): readonly Statement[] { +function transformCallbackArgument( + func: Expression, + hasContinuation: boolean, + continuationArgName: SynthBindingName | undefined, + inputArgName: SynthBindingName | undefined, + parent: PromiseReturningCallExpression<"then" | "catch" | "finally">, + transformer: Transformer, +): readonly Statement[] { switch (func.kind) { case SyntaxKind.NullKeyword: // do not produce a transformed statement for a null argument @@ -630,10 +835,17 @@ function transformCallbackArgument(func: Expression, hasContinuation: boolean, c break; } - const synthCall = factory.createCallExpression(getSynthesizedDeepClone(func as Identifier | PropertyAccessExpression), /*typeArguments*/ undefined, isSynthIdentifier(inputArgName) ? [referenceSynthIdentifier(inputArgName)] : []); + const synthCall = factory.createCallExpression( + getSynthesizedDeepClone(func as Identifier | PropertyAccessExpression), + /*typeArguments*/ undefined, + isSynthIdentifier(inputArgName) ? [referenceSynthIdentifier(inputArgName)] : [], + ); if (shouldReturn(parent, transformer)) { - return maybeAnnotateAndReturn(synthCall, getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker)); + return maybeAnnotateAndReturn( + synthCall, + getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker), + ); } const type = transformer.checker.getTypeAtLocation(func); @@ -643,7 +855,11 @@ function transformCallbackArgument(func: Expression, hasContinuation: boolean, c return silentFail(); } const returnType = callSignatures[0].getReturnType(); - const varDeclOrAssignment = createVariableOrAssignmentOrExpressionStatement(continuationArgName, factory.createAwaitExpression(synthCall), getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker)); + const varDeclOrAssignment = createVariableOrAssignmentOrExpressionStatement( + continuationArgName, + factory.createAwaitExpression(synthCall), + getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker), + ); if (continuationArgName) { continuationArgName.types.push(transformer.checker.getAwaitedType(returnType) || returnType); } @@ -652,7 +868,8 @@ function transformCallbackArgument(func: Expression, hasContinuation: boolean, c case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: { const funcBody = (func as FunctionExpression | ArrowFunction).body; - const returnType = getLastCallSignature(transformer.checker.getTypeAtLocation(func), transformer.checker)?.getReturnType(); + const returnType = getLastCallSignature(transformer.checker.getTypeAtLocation(func), transformer.checker) + ?.getReturnType(); // Arrow functions with block bodies { } will enter this control flow if (isBlock(funcBody)) { @@ -662,11 +879,29 @@ function transformCallbackArgument(func: Expression, hasContinuation: boolean, c if (isReturnStatement(statement)) { seenReturnStatement = true; if (isReturnStatementWithFixablePromiseHandler(statement, transformer.checker)) { - refactoredStmts = refactoredStmts.concat(transformReturnStatementWithFixablePromiseHandler(transformer, statement, hasContinuation, continuationArgName)); + refactoredStmts = refactoredStmts.concat( + transformReturnStatementWithFixablePromiseHandler( + transformer, + statement, + hasContinuation, + continuationArgName, + ), + ); } else { - const possiblyAwaitedRightHandSide = returnType && statement.expression ? getPossiblyAwaitedRightHandSide(transformer.checker, returnType, statement.expression) : statement.expression; - refactoredStmts.push(...maybeAnnotateAndReturn(possiblyAwaitedRightHandSide, getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker))); + const possiblyAwaitedRightHandSide = returnType && statement.expression + ? getPossiblyAwaitedRightHandSide(transformer.checker, returnType, statement.expression) + : statement.expression; + refactoredStmts.push( + ...maybeAnnotateAndReturn( + possiblyAwaitedRightHandSide, + getExplicitPromisedTypeOfPromiseReturningCallExpression( + parent, + func, + transformer.checker, + ), + ), + ); } } else if (hasContinuation && forEachReturnStatement(statement, returnTrue)) { @@ -688,7 +923,7 @@ function transformCallbackArgument(func: Expression, hasContinuation: boolean, c // However, branching returns in the outermost continuation are acceptable as no other continuation follows it: // // source | result - //--------------------------------------|--------------------------------------- + // --------------------------------------|--------------------------------------- // function f() { | async function f() { // return foo().then(res => { | const res = await foo(); // if (res.ok) { | if (res.ok) { @@ -720,29 +955,48 @@ function transformCallbackArgument(func: Expression, hasContinuation: boolean, c refactoredStmts, continuationArgName, transformer, - seenReturnStatement); + seenReturnStatement, + ); } else { - const inlinedStatements = isFixablePromiseHandler(funcBody, transformer.checker) ? - transformReturnStatementWithFixablePromiseHandler(transformer, factory.createReturnStatement(funcBody), hasContinuation, continuationArgName) : - emptyArray; + const inlinedStatements = isFixablePromiseHandler(funcBody, transformer.checker) + ? transformReturnStatementWithFixablePromiseHandler( + transformer, + factory.createReturnStatement(funcBody), + hasContinuation, + continuationArgName, + ) + : emptyArray; if (inlinedStatements.length > 0) { return inlinedStatements; } if (returnType) { - const possiblyAwaitedRightHandSide = getPossiblyAwaitedRightHandSide(transformer.checker, returnType, funcBody); + const possiblyAwaitedRightHandSide = getPossiblyAwaitedRightHandSide( + transformer.checker, + returnType, + funcBody, + ); if (!shouldReturn(parent, transformer)) { - const transformedStatement = createVariableOrAssignmentOrExpressionStatement(continuationArgName, possiblyAwaitedRightHandSide, /*typeAnnotation*/ undefined); + const transformedStatement = createVariableOrAssignmentOrExpressionStatement( + continuationArgName, + possiblyAwaitedRightHandSide, + /*typeAnnotation*/ undefined, + ); if (continuationArgName) { - continuationArgName.types.push(transformer.checker.getAwaitedType(returnType) || returnType); + continuationArgName.types.push( + transformer.checker.getAwaitedType(returnType) || returnType, + ); } return transformedStatement; } else { - return maybeAnnotateAndReturn(possiblyAwaitedRightHandSide, getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker)); + return maybeAnnotateAndReturn( + possiblyAwaitedRightHandSide, + getExplicitPromisedTypeOfPromiseReturningCallExpression(parent, func, transformer.checker), + ); } } else { @@ -757,7 +1011,11 @@ function transformCallbackArgument(func: Expression, hasContinuation: boolean, c return emptyArray; } -function getPossiblyAwaitedRightHandSide(checker: TypeChecker, type: Type, expr: Expression): AwaitExpression | Expression { +function getPossiblyAwaitedRightHandSide( + checker: TypeChecker, + type: Type, + expr: Expression, +): AwaitExpression | Expression { const rightHandSide = getSynthesizedDeepClone(expr); return !!checker.getPromisedTypeOfPromise(type) ? factory.createAwaitExpression(rightHandSide) : rightHandSide; } @@ -767,21 +1025,42 @@ function getLastCallSignature(type: Type, checker: TypeChecker): Signature | und return lastOrUndefined(callSignatures); } -function removeReturns(stmts: readonly Statement[], prevArgName: SynthBindingName | undefined, transformer: Transformer, seenReturnStatement: boolean): readonly Statement[] { +function removeReturns( + stmts: readonly Statement[], + prevArgName: SynthBindingName | undefined, + transformer: Transformer, + seenReturnStatement: boolean, +): readonly Statement[] { const ret: Statement[] = []; for (const stmt of stmts) { if (isReturnStatement(stmt)) { if (stmt.expression) { - const possiblyAwaitedExpression = isPromiseTypedExpression(stmt.expression, transformer.checker) ? factory.createAwaitExpression(stmt.expression) : stmt.expression; + const possiblyAwaitedExpression = isPromiseTypedExpression(stmt.expression, transformer.checker) + ? factory.createAwaitExpression(stmt.expression) : stmt.expression; if (prevArgName === undefined) { ret.push(factory.createExpressionStatement(possiblyAwaitedExpression)); } else if (isSynthIdentifier(prevArgName) && prevArgName.hasBeenDeclared) { - ret.push(factory.createExpressionStatement(factory.createAssignment(referenceSynthIdentifier(prevArgName), possiblyAwaitedExpression))); + ret.push( + factory.createExpressionStatement( + factory.createAssignment(referenceSynthIdentifier(prevArgName), possiblyAwaitedExpression), + ), + ); } else { - ret.push(factory.createVariableStatement(/*modifiers*/ undefined, - (factory.createVariableDeclarationList([factory.createVariableDeclaration(declareSynthBindingName(prevArgName), /*exclamationToken*/ undefined, /*type*/ undefined, possiblyAwaitedExpression)], NodeFlags.Const)))); + ret.push( + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration( + declareSynthBindingName(prevArgName), + /*exclamationToken*/ undefined, + /*type*/ undefined, + possiblyAwaitedExpression, + ), + ], NodeFlags.Const), + ), + ); } } } @@ -792,8 +1071,19 @@ function removeReturns(stmts: readonly Statement[], prevArgName: SynthBindingNam // if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables if (!seenReturnStatement && prevArgName !== undefined) { - ret.push(factory.createVariableStatement(/*modifiers*/ undefined, - (factory.createVariableDeclarationList([factory.createVariableDeclaration(declareSynthBindingName(prevArgName), /*exclamationToken*/ undefined, /*type*/ undefined, factory.createIdentifier("undefined"))], NodeFlags.Const)))); + ret.push( + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration( + declareSynthBindingName(prevArgName), + /*exclamationToken*/ undefined, + /*type*/ undefined, + factory.createIdentifier("undefined"), + ), + ], NodeFlags.Const), + ), + ); } return ret; @@ -803,7 +1093,12 @@ function removeReturns(stmts: readonly Statement[], prevArgName: SynthBindingNam * @param hasContinuation Whether another `then`, `catch`, or `finally` continuation follows the continuation to which this statement belongs. * @param continuationArgName The argument name for the continuation that follows this call. */ -function transformReturnStatementWithFixablePromiseHandler(transformer: Transformer, innerRetStmt: ReturnStatement, hasContinuation: boolean, continuationArgName?: SynthBindingName) { +function transformReturnStatementWithFixablePromiseHandler( + transformer: Transformer, + innerRetStmt: ReturnStatement, + hasContinuation: boolean, + continuationArgName?: SynthBindingName, +) { let innerCbBody: Statement[] = []; forEachChild(innerRetStmt, function visit(node) { if (isCallExpression(node)) { @@ -887,10 +1182,20 @@ function isEmptyBindingName(bindingName: SynthBindingName | undefined): boolean } function createSynthIdentifier(identifier: Identifier, types: Type[] = []): SynthIdentifier { - return { kind: SynthBindingNameKind.Identifier, identifier, types, hasBeenDeclared: false, hasBeenReferenced: false }; + return { + kind: SynthBindingNameKind.Identifier, + identifier, + types, + hasBeenDeclared: false, + hasBeenReferenced: false, + }; } -function createSynthBindingPattern(bindingPattern: BindingPattern, elements: readonly SynthBindingName[] = emptyArray, types: Type[] = []): SynthBindingPattern { +function createSynthBindingPattern( + bindingPattern: BindingPattern, + elements: readonly SynthBindingName[] = emptyArray, + types: Type[] = [], +): SynthBindingPattern { return { kind: SynthBindingNameKind.BindingPattern, bindingPattern, elements, types }; } diff --git a/src/services/codefixes/convertToEsModule.ts b/src/services/codefixes/convertToEsModule.ts index b15a0521c1cb1..1de471e11884b 100644 --- a/src/services/codefixes/convertToEsModule.ts +++ b/src/services/codefixes/convertToEsModule.ts @@ -87,10 +87,21 @@ registerCodeFix({ getCodeActions(context) { const { sourceFile, program, preferences } = context; const changes = textChanges.ChangeTracker.with(context, changes => { - const moduleExportsChangedToDefault = convertFileToEsModule(sourceFile, program.getTypeChecker(), changes, getEmitScriptTarget(program.getCompilerOptions()), getQuotePreference(sourceFile, preferences)); + const moduleExportsChangedToDefault = convertFileToEsModule( + sourceFile, + program.getTypeChecker(), + changes, + getEmitScriptTarget(program.getCompilerOptions()), + getQuotePreference(sourceFile, preferences), + ); if (moduleExportsChangedToDefault) { for (const importingFile of program.getSourceFiles()) { - fixImportOfModuleExports(importingFile, sourceFile, changes, getQuotePreference(importingFile, preferences)); + fixImportOfModuleExports( + importingFile, + sourceFile, + changes, + getQuotePreference(importingFile, preferences), + ); } } }); @@ -99,9 +110,18 @@ registerCodeFix({ }, }); -function fixImportOfModuleExports(importingFile: SourceFile, exportingFile: SourceFile, changes: textChanges.ChangeTracker, quotePreference: QuotePreference) { +function fixImportOfModuleExports( + importingFile: SourceFile, + exportingFile: SourceFile, + changes: textChanges.ChangeTracker, + quotePreference: QuotePreference, +) { for (const moduleSpecifier of importingFile.imports) { - const imported = getResolvedModule(importingFile, moduleSpecifier.text, getModeForUsageLocation(importingFile, moduleSpecifier)); + const imported = getResolvedModule( + importingFile, + moduleSpecifier.text, + getModeForUsageLocation(importingFile, moduleSpecifier), + ); if (!imported || imported.resolvedFileName !== exportingFile.fileName) { continue; } @@ -109,11 +129,19 @@ function fixImportOfModuleExports(importingFile: SourceFile, exportingFile: Sour const importNode = importFromModuleSpecifier(moduleSpecifier); switch (importNode.kind) { case SyntaxKind.ImportEqualsDeclaration: - changes.replaceNode(importingFile, importNode, makeImport(importNode.name, /*namedImports*/ undefined, moduleSpecifier, quotePreference)); + changes.replaceNode( + importingFile, + importNode, + makeImport(importNode.name, /*namedImports*/ undefined, moduleSpecifier, quotePreference), + ); break; case SyntaxKind.CallExpression: if (isRequireCall(importNode, /*requireStringLiteralLikeArgument*/ false)) { - changes.replaceNode(importingFile, importNode, factory.createPropertyAccessExpression(getSynthesizedDeepClone(importNode), "default")); + changes.replaceNode( + importingFile, + importNode, + factory.createPropertyAccessExpression(getSynthesizedDeepClone(importNode), "default"), + ); } break; } @@ -121,7 +149,13 @@ function fixImportOfModuleExports(importingFile: SourceFile, exportingFile: Sour } /** @returns Whether we converted a `module.exports =` to a default export. */ -function convertFileToEsModule(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, target: ScriptTarget, quotePreference: QuotePreference): ModuleExportsChanged { +function convertFileToEsModule( + sourceFile: SourceFile, + checker: TypeChecker, + changes: textChanges.ChangeTracker, + target: ScriptTarget, + quotePreference: QuotePreference, +): ModuleExportsChanged { const identifiers: Identifiers = { original: collectFreeIdentifiers(sourceFile), additional: new Set() }; const exports = collectExportRenames(sourceFile, checker, identifiers); convertExportsAccesses(sourceFile, exports, changes); @@ -129,14 +163,32 @@ function convertFileToEsModule(sourceFile: SourceFile, checker: TypeChecker, cha let useSitesToUnqualify: Map | undefined; // Process variable statements first to collect use sites that need to be updated inside other transformations for (const statement of filter(sourceFile.statements, isVariableStatement)) { - const newUseSites = convertVariableStatement(sourceFile, statement, changes, checker, identifiers, target, quotePreference); + const newUseSites = convertVariableStatement( + sourceFile, + statement, + changes, + checker, + identifiers, + target, + quotePreference, + ); if (newUseSites) { copyEntries(newUseSites, useSitesToUnqualify ??= new Map()); } } // `convertStatement` will delete entries from `useSitesToUnqualify` when containing statements are replaced for (const statement of filter(sourceFile.statements, s => !isVariableStatement(s))) { - const moduleExportsChanged = convertStatement(sourceFile, statement, checker, changes, identifiers, target, exports, useSitesToUnqualify, quotePreference); + const moduleExportsChanged = convertStatement( + sourceFile, + statement, + checker, + changes, + identifiers, + target, + exports, + useSitesToUnqualify, + quotePreference, + ); moduleExportsChangedToDefault = moduleExportsChangedToDefault || moduleExportsChanged; } // Remaining use sites can be changed directly @@ -162,8 +214,10 @@ function collectExportRenames(sourceFile: SourceFile, checker: TypeChecker, iden const res = new Map(); forEachExportReference(sourceFile, node => { const { text } = node.name; - if (!res.has(text) && (isIdentifierANonContextualKeyword(node.name) - || checker.resolveName(text, node, SymbolFlags.Value, /*excludeGlobals*/ true))) { + if ( + !res.has(text) && (isIdentifierANonContextualKeyword(node.name) + || checker.resolveName(text, node, SymbolFlags.Value, /*excludeGlobals*/ true)) + ) { // Unconditionally add an underscore in case `text` is a keyword. res.set(text, makeUniqueName(`_${text}`, identifiers)); } @@ -171,7 +225,11 @@ function collectExportRenames(sourceFile: SourceFile, checker: TypeChecker, iden return res; } -function convertExportsAccesses(sourceFile: SourceFile, exports: ExportRenames, changes: textChanges.ChangeTracker): void { +function convertExportsAccesses( + sourceFile: SourceFile, + exports: ExportRenames, + changes: textChanges.ChangeTracker, +): void { forEachExportReference(sourceFile, (node, isAssignmentLhs) => { if (isAssignmentLhs) { return; @@ -181,11 +239,21 @@ function convertExportsAccesses(sourceFile: SourceFile, exports: ExportRenames, }); } -function forEachExportReference(sourceFile: SourceFile, cb: (node: (PropertyAccessExpression & { name: Identifier }), isAssignmentLhs: boolean) => void): void { +function forEachExportReference( + sourceFile: SourceFile, + cb: (node: PropertyAccessExpression & { name: Identifier; }, isAssignmentLhs: boolean) => void, +): void { sourceFile.forEachChild(function recur(node) { - if (isPropertyAccessExpression(node) && isExportsOrModuleExportsOrAlias(sourceFile, node.expression) && isIdentifier(node.name)) { + if ( + isPropertyAccessExpression(node) && isExportsOrModuleExportsOrAlias(sourceFile, node.expression) + && isIdentifier(node.name) + ) { const { parent } = node; - cb(node as typeof node & { name: Identifier }, isBinaryExpression(parent) && parent.left === node && parent.operatorToken.kind === SyntaxKind.EqualsToken); + cb( + node as typeof node & { name: Identifier; }, + isBinaryExpression(parent) && parent.left === node + && parent.operatorToken.kind === SyntaxKind.EqualsToken, + ); } node.forEachChild(recur); }); @@ -203,11 +271,19 @@ function convertStatement( target: ScriptTarget, exports: ExportRenames, useSitesToUnqualify: Map | undefined, - quotePreference: QuotePreference + quotePreference: QuotePreference, ): ModuleExportsChanged { switch (statement.kind) { case SyntaxKind.VariableStatement: - convertVariableStatement(sourceFile, statement as VariableStatement, changes, checker, identifiers, target, quotePreference); + convertVariableStatement( + sourceFile, + statement as VariableStatement, + changes, + checker, + identifiers, + target, + quotePreference, + ); return false; case SyntaxKind.ExpressionStatement: { const { expression } = statement as ExpressionStatement; @@ -215,13 +291,30 @@ function convertStatement( case SyntaxKind.CallExpression: { if (isRequireCall(expression, /*requireStringLiteralLikeArgument*/ true)) { // For side-effecting require() call, just make a side-effecting import. - changes.replaceNode(sourceFile, statement, makeImport(/*defaultImport*/ undefined, /*namedImports*/ undefined, expression.arguments[0], quotePreference)); + changes.replaceNode( + sourceFile, + statement, + makeImport( + /*defaultImport*/ undefined, + /*namedImports*/ undefined, + expression.arguments[0], + quotePreference, + ), + ); } return false; } case SyntaxKind.BinaryExpression: { const { operatorToken } = expression as BinaryExpression; - return operatorToken.kind === SyntaxKind.EqualsToken && convertAssignment(sourceFile, checker, expression as BinaryExpression, changes, exports, useSitesToUnqualify); + return operatorToken.kind === SyntaxKind.EqualsToken + && convertAssignment( + sourceFile, + checker, + expression as BinaryExpression, + changes, + exports, + useSitesToUnqualify, + ); } } } @@ -252,15 +345,36 @@ function convertVariableStatement( } else if (isRequireCall(initializer, /*requireStringLiteralLikeArgument*/ true)) { foundImport = true; - return convertSingleImport(name, initializer.arguments[0], checker, identifiers, target, quotePreference); + return convertSingleImport( + name, + initializer.arguments[0], + checker, + identifiers, + target, + quotePreference, + ); } - else if (isPropertyAccessExpression(initializer) && isRequireCall(initializer.expression, /*requireStringLiteralLikeArgument*/ true)) { + else if ( + isPropertyAccessExpression(initializer) + && isRequireCall(initializer.expression, /*requireStringLiteralLikeArgument*/ true) + ) { foundImport = true; - return convertPropertyAccessImport(name, initializer.name.text, initializer.expression.arguments[0], identifiers, quotePreference); + return convertPropertyAccessImport( + name, + initializer.name.text, + initializer.expression.arguments[0], + identifiers, + quotePreference, + ); } } // Move it out to its own variable statement. (This will not be used if `!foundImport`) - return convertedImports([factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([decl], declarationList.flags))]); + return convertedImports([ + factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([decl], declarationList.flags), + ), + ]); }); if (foundImport) { // useNonAdjustedEndPosition to ensure we don't eat the newline after the statement. @@ -277,12 +391,18 @@ function convertVariableStatement( } /** Converts `const name = require("moduleSpecifier").propertyName` */ -function convertPropertyAccessImport(name: BindingName, propertyName: string, moduleSpecifier: StringLiteralLike, identifiers: Identifiers, quotePreference: QuotePreference): ConvertedImports { +function convertPropertyAccessImport( + name: BindingName, + propertyName: string, + moduleSpecifier: StringLiteralLike, + identifiers: Identifiers, + quotePreference: QuotePreference, +): ConvertedImports { switch (name.kind) { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: { // `const [a, b] = require("c").d` --> `import { d } from "c"; const [a, b] = d;` - const tmp = makeUniqueName(propertyName, identifiers); + const tmp = makeUniqueName(propertyName, identifiers); return convertedImports([ makeSingleImport(tmp, propertyName, moduleSpecifier, quotePreference), makeConst(/*modifiers*/ undefined, name, factory.createIdentifier(tmp)), @@ -292,7 +412,10 @@ function convertPropertyAccessImport(name: BindingName, propertyName: string, mo // `const a = require("b").c` --> `import { c as a } from "./b"; return convertedImports([makeSingleImport(name.text, propertyName, moduleSpecifier, quotePreference)]); default: - return Debug.assertNever(name, `Convert to ES module got invalid syntax form ${(name as BindingName).kind}`); + return Debug.assertNever( + name, + `Convert to ES module got invalid syntax form ${(name as BindingName).kind}`, + ); } } @@ -315,21 +438,32 @@ function convertAssignment( changes.delete(sourceFile, assignment.parent); } else { - const replacement = isObjectLiteralExpression(right) ? tryChangeModuleExportsObject(right, useSitesToUnqualify) - : isRequireCall(right, /*requireStringLiteralLikeArgument*/ true) ? convertReExportAll(right.arguments[0], checker) + const replacement = isObjectLiteralExpression(right) + ? tryChangeModuleExportsObject(right, useSitesToUnqualify) + : isRequireCall(right, /*requireStringLiteralLikeArgument*/ true) + ? convertReExportAll(right.arguments[0], checker) : undefined; if (replacement) { changes.replaceNodeWithNodes(sourceFile, assignment.parent, replacement[0]); return replacement[1]; } else { - changes.replaceRangeWithText(sourceFile, createRange(left.getStart(sourceFile), right.pos), "export default"); + changes.replaceRangeWithText( + sourceFile, + createRange(left.getStart(sourceFile), right.pos), + "export default", + ); return true; } } } else if (isExportsOrModuleExportsOrAlias(sourceFile, left.expression)) { - convertNamedExport(sourceFile, assignment as BinaryExpression & { left: PropertyAccessExpression }, changes, exports); + convertNamedExport( + sourceFile, + assignment as BinaryExpression & { left: PropertyAccessExpression; }, + changes, + exports, + ); } return false; @@ -339,7 +473,10 @@ function convertAssignment( * Convert `module.exports = { ... }` to individual exports.. * We can't always do this if the module has interesting members -- then it will be a default export instead. */ -function tryChangeModuleExportsObject(object: ObjectLiteralExpression, useSitesToUnqualify: Map | undefined): [readonly Statement[], ModuleExportsChanged] | undefined { +function tryChangeModuleExportsObject( + object: ObjectLiteralExpression, + useSitesToUnqualify: Map | undefined, +): [readonly Statement[], ModuleExportsChanged] | undefined { const statements = mapAllOrFail(object.properties, prop => { switch (prop.kind) { case SyntaxKind.GetAccessor: @@ -350,11 +487,21 @@ function tryChangeModuleExportsObject(object: ObjectLiteralExpression, useSitesT case SyntaxKind.SpreadAssignment: return undefined; case SyntaxKind.PropertyAssignment: - return !isIdentifier(prop.name) ? undefined : convertExportsDotXEquals_replaceNode(prop.name.text, prop.initializer, useSitesToUnqualify); + return !isIdentifier(prop.name) ? undefined + : convertExportsDotXEquals_replaceNode(prop.name.text, prop.initializer, useSitesToUnqualify); case SyntaxKind.MethodDeclaration: - return !isIdentifier(prop.name) ? undefined : functionExpressionToDeclaration(prop.name.text, [factory.createToken(SyntaxKind.ExportKeyword)], prop, useSitesToUnqualify); + return !isIdentifier(prop.name) ? undefined + : functionExpressionToDeclaration( + prop.name.text, + [factory.createToken(SyntaxKind.ExportKeyword)], + prop, + useSitesToUnqualify, + ); default: - Debug.assertNever(prop, `Convert to ES6 got invalid prop kind ${(prop as ObjectLiteralElementLike).kind}`); + Debug.assertNever( + prop, + `Convert to ES6 got invalid prop kind ${(prop as ObjectLiteralElementLike).kind}`, + ); } }); return statements && [statements, false]; @@ -362,7 +509,7 @@ function tryChangeModuleExportsObject(object: ObjectLiteralExpression, useSitesT function convertNamedExport( sourceFile: SourceFile, - assignment: BinaryExpression & { left: PropertyAccessExpression }, + assignment: BinaryExpression & { left: PropertyAccessExpression; }, changes: textChanges.ChangeTracker, exports: ExportRenames, ): void { @@ -385,28 +532,46 @@ function convertNamedExport( } } -function convertReExportAll(reExported: StringLiteralLike, checker: TypeChecker): [readonly Statement[], ModuleExportsChanged] { +function convertReExportAll( + reExported: StringLiteralLike, + checker: TypeChecker, +): [readonly Statement[], ModuleExportsChanged] { // `module.exports = require("x");` ==> `export * from "x"; export { default } from "x";` const moduleSpecifier = reExported.text; const moduleSymbol = checker.getSymbolAtLocation(reExported); const exports = moduleSymbol ? moduleSymbol.exports! : emptyMap as ReadonlyCollection<__String>; - return exports.has(InternalSymbolName.ExportEquals) ? [[reExportDefault(moduleSpecifier)], true] : - !exports.has(InternalSymbolName.Default) ? [[reExportStar(moduleSpecifier)], false] : + return exports.has(InternalSymbolName.ExportEquals) ? [[reExportDefault(moduleSpecifier)], true] + : !exports.has(InternalSymbolName.Default) ? [[reExportStar(moduleSpecifier)], false] // If there's some non-default export, must include both `export *` and `export default`. - exports.size > 1 ? [[reExportStar(moduleSpecifier), reExportDefault(moduleSpecifier)], true] : [[reExportDefault(moduleSpecifier)], true]; + : exports.size > 1 ? [[reExportStar(moduleSpecifier), reExportDefault(moduleSpecifier)], true] + : [[reExportDefault(moduleSpecifier)], true]; } function reExportStar(moduleSpecifier: string): ExportDeclaration { return makeExportDeclaration(/*exportSpecifiers*/ undefined, moduleSpecifier); } function reExportDefault(moduleSpecifier: string): ExportDeclaration { - return makeExportDeclaration([factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, "default")], moduleSpecifier); + return makeExportDeclaration([ + factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, "default"), + ], moduleSpecifier); } -function convertExportsPropertyAssignment({ left, right, parent }: BinaryExpression & { left: PropertyAccessExpression }, sourceFile: SourceFile, changes: textChanges.ChangeTracker): void { +function convertExportsPropertyAssignment( + { left, right, parent }: BinaryExpression & { left: PropertyAccessExpression; }, + sourceFile: SourceFile, + changes: textChanges.ChangeTracker, +): void { const name = left.name.text; - if ((isFunctionExpression(right) || isArrowFunction(right) || isClassExpression(right)) && (!right.name || right.name.text === name)) { + if ( + (isFunctionExpression(right) || isArrowFunction(right) || isClassExpression(right)) + && (!right.name || right.name.text === name) + ) { // `exports.f = function() {}` -> `export function f() {}` -- Replace `exports.f = ` with `export `, and insert the name after `function`. - changes.replaceRange(sourceFile, { pos: left.getStart(sourceFile), end: right.getStart(sourceFile) }, factory.createToken(SyntaxKind.ExportKeyword), { suffix: " " }); + changes.replaceRange( + sourceFile, + { pos: left.getStart(sourceFile), end: right.getStart(sourceFile) }, + factory.createToken(SyntaxKind.ExportKeyword), + { suffix: " " }, + ); if (!right.name) changes.insertName(sourceFile, right, name); @@ -415,14 +580,22 @@ function convertExportsPropertyAssignment({ left, right, parent }: BinaryExpress } else { // `exports.f = function g() {}` -> `export const f = function g() {}` -- just replace `exports.` with `export const ` - changes.replaceNodeRangeWithNodes(sourceFile, left.expression, findChildOfKind(left, SyntaxKind.DotToken, sourceFile)!, + changes.replaceNodeRangeWithNodes( + sourceFile, + left.expression, + findChildOfKind(left, SyntaxKind.DotToken, sourceFile)!, [factory.createToken(SyntaxKind.ExportKeyword), factory.createToken(SyntaxKind.ConstKeyword)], - { joiner: " ", suffix: " " }); + { joiner: " ", suffix: " " }, + ); } } // TODO: GH#22492 this will cause an error if a change has been made inside the body of the node. -function convertExportsDotXEquals_replaceNode(name: string | undefined, exported: Expression, useSitesToUnqualify: Map | undefined): Statement { +function convertExportsDotXEquals_replaceNode( + name: string | undefined, + exported: Expression, + useSitesToUnqualify: Map | undefined, +): Statement { const modifiers = [factory.createToken(SyntaxKind.ExportKeyword)]; switch (exported.kind) { case SyntaxKind.FunctionExpression: { @@ -436,7 +609,12 @@ function convertExportsDotXEquals_replaceNode(name: string | undefined, exported // falls through case SyntaxKind.ArrowFunction: // `exports.f = function() {}` --> `export function f() {}` - return functionExpressionToDeclaration(name, modifiers, exported as FunctionExpression | ArrowFunction, useSitesToUnqualify); + return functionExpressionToDeclaration( + name, + modifiers, + exported as FunctionExpression | ArrowFunction, + useSitesToUnqualify, + ); case SyntaxKind.ClassExpression: // `exports.C = class {}` --> `export class C {}` return classExpressionToDeclaration(name, modifiers, exported as ClassExpression, useSitesToUnqualify); @@ -446,14 +624,27 @@ function convertExportsDotXEquals_replaceNode(name: string | undefined, exported function exportConst() { // `exports.x = 0;` --> `export const x = 0;` - return makeConst(modifiers, factory.createIdentifier(name!), replaceImportUseSites(exported, useSitesToUnqualify)); // TODO: GH#18217 + return makeConst( + modifiers, + factory.createIdentifier(name!), + replaceImportUseSites(exported, useSitesToUnqualify), + ); // TODO: GH#18217 } } function replaceImportUseSites(node: T, useSitesToUnqualify: Map | undefined): T; -function replaceImportUseSites(nodes: NodeArray, useSitesToUnqualify: Map | undefined): NodeArray; -function replaceImportUseSites(nodeOrNodes: T | NodeArray, useSitesToUnqualify: Map | undefined) { - if (!useSitesToUnqualify || !some(arrayFrom(useSitesToUnqualify.keys()), original => rangeContainsRange(nodeOrNodes, original))) { +function replaceImportUseSites( + nodes: NodeArray, + useSitesToUnqualify: Map | undefined, +): NodeArray; +function replaceImportUseSites( + nodeOrNodes: T | NodeArray, + useSitesToUnqualify: Map | undefined, +) { + if ( + !useSitesToUnqualify + || !some(arrayFrom(useSitesToUnqualify.keys()), original => rangeContainsRange(nodeOrNodes, original)) + ) { return nodeOrNodes; } @@ -487,12 +678,17 @@ function convertSingleImport( ): ConvertedImports { switch (name.kind) { case SyntaxKind.ObjectBindingPattern: { - const importSpecifiers = mapAllOrFail(name.elements, e => - e.dotDotDotToken || e.initializer || e.propertyName && !isIdentifier(e.propertyName) || !isIdentifier(e.name) + const importSpecifiers = mapAllOrFail( + name.elements, + e => e.dotDotDotToken || e.initializer || e.propertyName && !isIdentifier(e.propertyName) + || !isIdentifier(e.name) ? undefined - : makeImportSpecifier(e.propertyName && e.propertyName.text, e.name.text)); + : makeImportSpecifier(e.propertyName && e.propertyName.text, e.name.text), + ); if (importSpecifiers) { - return convertedImports([makeImport(/*defaultImport*/ undefined, importSpecifiers, moduleSpecifier, quotePreference)]); + return convertedImports([ + makeImport(/*defaultImport*/ undefined, importSpecifiers, moduleSpecifier, quotePreference), + ]); } } // falls through -- object destructuring has an interesting pattern and must be a variable declaration @@ -520,7 +716,13 @@ function convertSingleImport( * - Convert `x.default()` to `x()` to handle ES6 default export * - Converts uses like `x.y()` to `y()` and uses a named import. */ -function convertSingleIdentifierImport(name: Identifier, moduleSpecifier: StringLiteralLike, checker: TypeChecker, identifiers: Identifiers, quotePreference: QuotePreference): ConvertedImports { +function convertSingleIdentifierImport( + name: Identifier, + moduleSpecifier: StringLiteralLike, + checker: TypeChecker, + identifiers: Identifiers, + quotePreference: QuotePreference, +): ConvertedImports { const nameSymbol = checker.getSymbolAtLocation(name); // Maps from module property name to name actually used. (The same if there isn't shadowing.) const namedBindingsNames = new Map(); @@ -559,15 +761,27 @@ function convertSingleIdentifierImport(name: Identifier, moduleSpecifier: String } } - const namedBindings = namedBindingsNames.size === 0 ? undefined : arrayFrom(mapIterator(namedBindingsNames.entries(), ([propertyName, idName]) => - factory.createImportSpecifier(/*isTypeOnly*/ false, propertyName === idName ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(idName)))); + const namedBindings = namedBindingsNames.size === 0 ? undefined + : arrayFrom( + mapIterator(namedBindingsNames.entries(), ([propertyName, idName]) => + factory.createImportSpecifier( + /*isTypeOnly*/ false, + propertyName === idName ? undefined : factory.createIdentifier(propertyName), + factory.createIdentifier(idName), + )), + ); if (!namedBindings) { // If it was unused, ensure that we at least import *something*. needDefaultImport = true; } return convertedImports( - [makeImport(needDefaultImport ? getSynthesizedDeepClone(name) : undefined, namedBindings, moduleSpecifier, quotePreference)], - useSitesToUnqualify + [makeImport( + needDefaultImport ? getSynthesizedDeepClone(name) : undefined, + namedBindings, + moduleSpecifier, + quotePreference, + )], + useSitesToUnqualify, ); } @@ -624,7 +838,12 @@ function isFreeIdentifier(node: Identifier): boolean { // Node helpers -function functionExpressionToDeclaration(name: string | undefined, additionalModifiers: readonly Modifier[], fn: FunctionExpression | ArrowFunction | MethodDeclaration, useSitesToUnqualify: Map | undefined): FunctionDeclaration { +function functionExpressionToDeclaration( + name: string | undefined, + additionalModifiers: readonly Modifier[], + fn: FunctionExpression | ArrowFunction | MethodDeclaration, + useSitesToUnqualify: Map | undefined, +): FunctionDeclaration { return factory.createFunctionDeclaration( concatenate(additionalModifiers, getSynthesizedDeepClones(fn.modifiers)), getSynthesizedDeepClone(fn.asteriskToken), @@ -632,42 +851,73 @@ function functionExpressionToDeclaration(name: string | undefined, additionalMod getSynthesizedDeepClones(fn.typeParameters), getSynthesizedDeepClones(fn.parameters), getSynthesizedDeepClone(fn.type), - factory.converters.convertToFunctionBlock(replaceImportUseSites(fn.body!, useSitesToUnqualify))); + factory.converters.convertToFunctionBlock(replaceImportUseSites(fn.body!, useSitesToUnqualify)), + ); } -function classExpressionToDeclaration(name: string | undefined, additionalModifiers: readonly Modifier[], cls: ClassExpression, useSitesToUnqualify: Map | undefined): ClassDeclaration { +function classExpressionToDeclaration( + name: string | undefined, + additionalModifiers: readonly Modifier[], + cls: ClassExpression, + useSitesToUnqualify: Map | undefined, +): ClassDeclaration { return factory.createClassDeclaration( concatenate(additionalModifiers, getSynthesizedDeepClones(cls.modifiers)), name, getSynthesizedDeepClones(cls.typeParameters), getSynthesizedDeepClones(cls.heritageClauses), - replaceImportUseSites(cls.members, useSitesToUnqualify)); + replaceImportUseSites(cls.members, useSitesToUnqualify), + ); } -function makeSingleImport(localName: string, propertyName: string, moduleSpecifier: StringLiteralLike, quotePreference: QuotePreference): ImportDeclaration { +function makeSingleImport( + localName: string, + propertyName: string, + moduleSpecifier: StringLiteralLike, + quotePreference: QuotePreference, +): ImportDeclaration { return propertyName === "default" ? makeImport(factory.createIdentifier(localName), /*namedImports*/ undefined, moduleSpecifier, quotePreference) - : makeImport(/*defaultImport*/ undefined, [makeImportSpecifier(propertyName, localName)], moduleSpecifier, quotePreference); + : makeImport( + /*defaultImport*/ undefined, + [makeImportSpecifier(propertyName, localName)], + moduleSpecifier, + quotePreference, + ); } function makeImportSpecifier(propertyName: string | undefined, name: string): ImportSpecifier { - return factory.createImportSpecifier(/*isTypeOnly*/ false, propertyName !== undefined && propertyName !== name ? factory.createIdentifier(propertyName) : undefined, factory.createIdentifier(name)); + return factory.createImportSpecifier( + /*isTypeOnly*/ false, + propertyName !== undefined && propertyName !== name ? factory.createIdentifier(propertyName) : undefined, + factory.createIdentifier(name), + ); } -function makeConst(modifiers: readonly Modifier[] | undefined, name: string | BindingName, init: Expression): VariableStatement { +function makeConst( + modifiers: readonly Modifier[] | undefined, + name: string | BindingName, + init: Expression, +): VariableStatement { return factory.createVariableStatement( modifiers, factory.createVariableDeclarationList( [factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, /*type*/ undefined, init)], - NodeFlags.Const)); + NodeFlags.Const, + ), + ); } -function makeExportDeclaration(exportSpecifiers: ExportSpecifier[] | undefined, moduleSpecifier?: string): ExportDeclaration { +function makeExportDeclaration( + exportSpecifiers: ExportSpecifier[] | undefined, + moduleSpecifier?: string, +): ExportDeclaration { return factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ false, exportSpecifiers && factory.createNamedExports(exportSpecifiers), - moduleSpecifier === undefined ? undefined : factory.createStringLiteral(moduleSpecifier)); + moduleSpecifier === undefined ? undefined : factory.createStringLiteral(moduleSpecifier), + ); } interface ConvertedImports { @@ -678,6 +928,6 @@ interface ConvertedImports { function convertedImports(newImports: readonly Node[], useSitesToUnqualify?: Map): ConvertedImports { return { newImports, - useSitesToUnqualify + useSitesToUnqualify, }; } diff --git a/src/services/codefixes/convertToMappedObjectType.ts b/src/services/codefixes/convertToMappedObjectType.ts index 1a3b8498a49f5..b1f4bc29b36de 100644 --- a/src/services/codefixes/convertToMappedObjectType.ts +++ b/src/services/codefixes/convertToMappedObjectType.ts @@ -29,7 +29,11 @@ import { } from "../_namespaces/ts.codefix"; const fixId = "fixConvertToMappedObjectType"; -const errorCodes = [Diagnostics.An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead.code]; +const errorCodes = [ + Diagnostics + .An_index_signature_parameter_type_cannot_be_a_literal_type_or_generic_type_Consider_using_a_mapped_object_type_instead + .code, +]; type FixableDeclaration = InterfaceDeclaration | TypeAliasDeclaration; @@ -41,43 +45,67 @@ registerCodeFix({ if (!info) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info)); const name = idText(info.container.name); - return [createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_mapped_object_type, name], fixId, [Diagnostics.Convert_0_to_mapped_object_type, name])]; + return [ + createCodeFixAction(fixId, changes, [Diagnostics.Convert_0_to_mapped_object_type, name], fixId, [ + Diagnostics.Convert_0_to_mapped_object_type, + name, + ]), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, diag.start); - if (info) doChange(changes, diag.file, info); - }) + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, diag.start); + if (info) doChange(changes, diag.file, info); + }), }); -interface Info { readonly indexSignature: IndexSignatureDeclaration; readonly container: FixableDeclaration; } +interface Info { + readonly indexSignature: IndexSignatureDeclaration; + readonly container: FixableDeclaration; +} function getInfo(sourceFile: SourceFile, pos: number): Info | undefined { const token = getTokenAtPosition(sourceFile, pos); const indexSignature = tryCast(token.parent.parent, isIndexSignatureDeclaration); if (!indexSignature) return undefined; - const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : tryCast(indexSignature.parent.parent, isTypeAliasDeclaration); + const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent + : tryCast(indexSignature.parent.parent, isTypeAliasDeclaration); if (!container) return undefined; return { indexSignature, container }; } function createTypeAliasFromInterface(declaration: FixableDeclaration, type: TypeNode): TypeAliasDeclaration { - return factory.createTypeAliasDeclaration(declaration.modifiers, declaration.name, declaration.typeParameters, type); + return factory.createTypeAliasDeclaration( + declaration.modifiers, + declaration.name, + declaration.typeParameters, + type, + ); } -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { indexSignature, container }: Info): void { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { indexSignature, container }: Info, +): void { const members = isInterfaceDeclaration(container) ? container.members : (container.type as TypeLiteralNode).members; const otherMembers = members.filter(member => !isIndexSignatureDeclaration(member)); const parameter = first(indexSignature.parameters); - const mappedTypeParameter = factory.createTypeParameterDeclaration(/*modifiers*/ undefined, cast(parameter.name, isIdentifier), parameter.type); + const mappedTypeParameter = factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + cast(parameter.name, isIdentifier), + parameter.type, + ); const mappedIntersectionType = factory.createMappedTypeNode( hasEffectiveReadonlyModifier(indexSignature) ? factory.createModifier(SyntaxKind.ReadonlyKeyword) : undefined, mappedTypeParameter, /*nameType*/ undefined, indexSignature.questionToken, indexSignature.type, - /*members*/ undefined); + /*members*/ undefined, + ); const intersectionType = factory.createIntersectionTypeNode([ ...getAllSuperTypeNodes(container), mappedIntersectionType, diff --git a/src/services/codefixes/convertToTypeOnlyExport.ts b/src/services/codefixes/convertToTypeOnlyExport.ts index b0e67f43b4cbd..2aa0e4451b162 100644 --- a/src/services/codefixes/convertToTypeOnlyExport.ts +++ b/src/services/codefixes/convertToTypeOnlyExport.ts @@ -29,9 +29,24 @@ const fixId = "convertToTypeOnlyExport"; registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToConvertToTypeOnlyExport(context) { - const changes = textChanges.ChangeTracker.with(context, t => fixSingleExportDeclaration(t, getExportSpecifierForDiagnosticSpan(context.span, context.sourceFile), context)); + const changes = textChanges.ChangeTracker.with( + context, + t => fixSingleExportDeclaration( + t, + getExportSpecifierForDiagnosticSpan(context.span, context.sourceFile), + context, + ), + ); if (changes.length) { - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_type_only_export, fixId, Diagnostics.Convert_all_re_exported_types_to_type_only_exports)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_type_only_export, + fixId, + Diagnostics.Convert_all_re_exported_types_to_type_only_exports, + ), + ]; } }, fixIds: [fixId], @@ -43,14 +58,18 @@ registerCodeFix({ fixSingleExportDeclaration(changes, exportSpecifier, context); } }); - } + }, }); function getExportSpecifierForDiagnosticSpan(span: TextSpan, sourceFile: SourceFile) { return tryCast(getTokenAtPosition(sourceFile, span.start).parent, isExportSpecifier); } -function fixSingleExportDeclaration(changes: textChanges.ChangeTracker, exportSpecifier: ExportSpecifier | undefined, context: CodeFixContextBase) { +function fixSingleExportDeclaration( + changes: textChanges.ChangeTracker, + exportSpecifier: ExportSpecifier | undefined, + context: CodeFixContextBase, +) { if (!exportSpecifier) { return; } @@ -66,27 +85,33 @@ function fixSingleExportDeclaration(changes: textChanges.ChangeTracker, exportSp exportDeclaration, exportDeclaration.modifiers, /*isTypeOnly*/ false, - factory.updateNamedExports(exportClause, filter(exportClause.elements, e => !contains(typeExportSpecifiers, e))), + factory.updateNamedExports( + exportClause, + filter(exportClause.elements, e => !contains(typeExportSpecifiers, e)), + ), exportDeclaration.moduleSpecifier, - /*assertClause*/ undefined + /*assertClause*/ undefined, ); const typeExportDeclaration = factory.createExportDeclaration( /*modifiers*/ undefined, /*isTypeOnly*/ true, factory.createNamedExports(typeExportSpecifiers), exportDeclaration.moduleSpecifier, - /*assertClause*/ undefined + /*assertClause*/ undefined, ); changes.replaceNode(context.sourceFile, exportDeclaration, valueExportDeclaration, { leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, - trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, }); changes.insertNodeAfter(context.sourceFile, exportDeclaration, typeExportDeclaration); } } -function getTypeExportSpecifiers(originExportSpecifier: ExportSpecifier, context: CodeFixContextBase): readonly ExportSpecifier[] { +function getTypeExportSpecifiers( + originExportSpecifier: ExportSpecifier, + context: CodeFixContextBase, +): readonly ExportSpecifier[] { const exportClause = originExportSpecifier.parent; if (exportClause.elements.length === 1) { return exportClause.elements; @@ -94,7 +119,8 @@ function getTypeExportSpecifiers(originExportSpecifier: ExportSpecifier, context const diagnostics = getDiagnosticsWithinSpan( createTextSpanFromNode(exportClause), - context.program.getSemanticDiagnostics(context.sourceFile, context.cancellationToken)); + context.program.getSemanticDiagnostics(context.sourceFile, context.cancellationToken), + ); return filter(exportClause.elements, element => { return element === originExportSpecifier || findDiagnosticForNode(element, diagnostics)?.code === errorCodes[0]; diff --git a/src/services/codefixes/convertToTypeOnlyImport.ts b/src/services/codefixes/convertToTypeOnlyImport.ts index fd5cd3cc2eefc..8ab21a1eb9114 100644 --- a/src/services/codefixes/convertToTypeOnlyImport.ts +++ b/src/services/codefixes/convertToTypeOnlyImport.ts @@ -26,7 +26,9 @@ import { } from "../_namespaces/ts.codefix"; const errorCodes = [ - Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error.code, + Diagnostics + .This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error + .code, Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled.code, ]; const fixId = "convertToTypeOnlyImport"; @@ -37,8 +39,12 @@ registerCodeFix({ const declaration = getDeclaration(context.sourceFile, context.span.start); if (declaration) { const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declaration)); - const importDeclarationChanges = declaration.kind === SyntaxKind.ImportSpecifier && canConvertImportDeclarationForSpecifier(declaration, context.sourceFile, context.program) - ? textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, declaration.parent.parent.parent)) + const importDeclarationChanges = declaration.kind === SyntaxKind.ImportSpecifier + && canConvertImportDeclarationForSpecifier(declaration, context.sourceFile, context.program) + ? textChanges.ChangeTracker.with( + context, + t => doChange(t, context.sourceFile, declaration.parent.parent.parent), + ) : undefined; const mainAction = createCodeFixAction( fixId, @@ -47,12 +53,13 @@ registerCodeFix({ ? [Diagnostics.Use_type_0, declaration.propertyName?.text ?? declaration.name.text] : Diagnostics.Use_import_type, fixId, - Diagnostics.Fix_all_with_type_only_imports); + Diagnostics.Fix_all_with_type_only_imports, + ); if (some(importDeclarationChanges)) { return [ createCodeFixActionWithoutFixAll(fixId, importDeclarationChanges, Diagnostics.Use_import_type), - mainAction + mainAction, ]; } return [mainAction]; @@ -64,11 +71,15 @@ registerCodeFix({ const fixedImportDeclarations = new Set(); return codeFixAll(context, errorCodes, (changes, diag) => { const errorDeclaration = getDeclaration(diag.file, diag.start); - if (errorDeclaration?.kind === SyntaxKind.ImportDeclaration && !fixedImportDeclarations.has(errorDeclaration)) { + if ( + errorDeclaration?.kind === SyntaxKind.ImportDeclaration + && !fixedImportDeclarations.has(errorDeclaration) + ) { doChange(changes, diag.file, errorDeclaration); fixedImportDeclarations.add(errorDeclaration); } - else if (errorDeclaration?.kind === SyntaxKind.ImportSpecifier + else if ( + errorDeclaration?.kind === SyntaxKind.ImportSpecifier && !fixedImportDeclarations.has(errorDeclaration.parent.parent.parent) && canConvertImportDeclarationForSpecifier(errorDeclaration, diag.file, context.program) ) { @@ -79,7 +90,7 @@ registerCodeFix({ doChange(changes, diag.file, errorDeclaration); } }); - } + }, }); function getDeclaration(sourceFile: SourceFile, pos: number) { @@ -87,8 +98,11 @@ function getDeclaration(sourceFile: SourceFile, pos: number) { return isImportSpecifier(parent) || isImportDeclaration(parent) && parent.importClause ? parent : undefined; } - -function canConvertImportDeclarationForSpecifier(specifier: ImportSpecifier, sourceFile: SourceFile, program: Program): boolean { +function canConvertImportDeclarationForSpecifier( + specifier: ImportSpecifier, + sourceFile: SourceFile, + program: Program, +): boolean { if (specifier.parent.parent.name) { // An import declaration with a default import and named bindings can't be type-only return false; @@ -101,9 +115,14 @@ function canConvertImportDeclarationForSpecifier(specifier: ImportSpecifier, sou // Otherwise, we need to check the usage of the other specifiers const checker = program.getTypeChecker(); for (const specifier of nonTypeOnlySpecifiers) { - const isUsedAsValue = FindAllReferences.Core.eachSymbolReferenceInFile(specifier.name, checker, sourceFile, usage => { - return !isValidTypeOnlyAliasUseSite(usage); - }); + const isUsedAsValue = FindAllReferences.Core.eachSymbolReferenceInFile( + specifier.name, + checker, + sourceFile, + usage => { + return !isValidTypeOnlyAliasUseSite(usage); + }, + ); if (isUsedAsValue) { return false; } @@ -112,9 +131,17 @@ function canConvertImportDeclarationForSpecifier(specifier: ImportSpecifier, sou return true; } -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ImportDeclaration | ImportSpecifier) { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + declaration: ImportDeclaration | ImportSpecifier, +) { if (isImportSpecifier(declaration)) { - changes.replaceNode(sourceFile, declaration, factory.updateImportSpecifier(declaration, /*isTypeOnly*/ true, declaration.propertyName, declaration.name)); + changes.replaceNode( + sourceFile, + declaration, + factory.updateImportSpecifier(declaration, /*isTypeOnly*/ true, declaration.propertyName, declaration.name), + ); } else { const importClause = declaration.importClause as ImportClause; @@ -122,13 +149,21 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, de changes.replaceNodeWithNodes(sourceFile, declaration, [ factory.createImportDeclaration( getSynthesizedDeepClones(declaration.modifiers, /*includeTrivia*/ true), - factory.createImportClause(/*isTypeOnly*/ true, getSynthesizedDeepClone(importClause.name, /*includeTrivia*/ true), /*namedBindings*/ undefined), + factory.createImportClause( + /*isTypeOnly*/ true, + getSynthesizedDeepClone(importClause.name, /*includeTrivia*/ true), + /*namedBindings*/ undefined, + ), getSynthesizedDeepClone(declaration.moduleSpecifier, /*includeTrivia*/ true), getSynthesizedDeepClone(declaration.assertClause, /*includeTrivia*/ true), ), factory.createImportDeclaration( getSynthesizedDeepClones(declaration.modifiers, /*includeTrivia*/ true), - factory.createImportClause(/*isTypeOnly*/ true, /*name*/ undefined, getSynthesizedDeepClone(importClause.namedBindings, /*includeTrivia*/ true)), + factory.createImportClause( + /*isTypeOnly*/ true, + /*name*/ undefined, + getSynthesizedDeepClone(importClause.namedBindings, /*includeTrivia*/ true), + ), getSynthesizedDeepClone(declaration.moduleSpecifier, /*includeTrivia*/ true), getSynthesizedDeepClone(declaration.assertClause, /*includeTrivia*/ true), ), @@ -138,10 +173,19 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, de const newNamedBindings = importClause.namedBindings?.kind === SyntaxKind.NamedImports ? factory.updateNamedImports( importClause.namedBindings, - sameMap(importClause.namedBindings.elements, e => factory.updateImportSpecifier(e, /*isTypeOnly*/ false, e.propertyName, e.name))) + sameMap( + importClause.namedBindings.elements, + e => factory.updateImportSpecifier(e, /*isTypeOnly*/ false, e.propertyName, e.name), + ), + ) : importClause.namedBindings; - const importDeclaration = factory.updateImportDeclaration(declaration, declaration.modifiers, - factory.updateImportClause(importClause, /*isTypeOnly*/ true, importClause.name, newNamedBindings), declaration.moduleSpecifier, declaration.assertClause); + const importDeclaration = factory.updateImportDeclaration( + declaration, + declaration.modifiers, + factory.updateImportClause(importClause, /*isTypeOnly*/ true, importClause.name, newNamedBindings), + declaration.moduleSpecifier, + declaration.assertClause, + ); changes.replaceNode(sourceFile, declaration, importDeclaration); } } diff --git a/src/services/codefixes/convertTypedefToType.ts b/src/services/codefixes/convertTypedefToType.ts index ea233c1d2d1d1..8d0afaffe2ae6 100644 --- a/src/services/codefixes/convertTypedefToType.ts +++ b/src/services/codefixes/convertTypedefToType.ts @@ -24,7 +24,11 @@ import { textChanges, TypeAliasDeclaration, } from "../_namespaces/ts"; -import { codeFixAll, createCodeFixAction, registerCodeFix } from "../_namespaces/ts.codefix"; +import { + codeFixAll, + createCodeFixAction, + registerCodeFix, +} from "../_namespaces/ts.codefix"; const fixId = "convertTypedefToType"; const errorCodes = [Diagnostics.JSDoc_typedef_may_be_converted_to_TypeScript_type.code]; @@ -35,11 +39,14 @@ registerCodeFix({ const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options); const node = getTokenAtPosition( context.sourceFile, - context.span.start + context.span.start, ); if (!node) return; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, node, context.sourceFile, newLineCharacter)); + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, node, context.sourceFile, newLineCharacter), + ); if (changes.length > 0) { return [ @@ -53,16 +60,17 @@ registerCodeFix({ ]; } }, - getAllCodeActions: context => codeFixAll( - context, - errorCodes, - (changes, diag) => { - const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options); - const node = getTokenAtPosition(diag.file, diag.start); - const fixAll = true; - if (node) doChange(changes, node, diag.file, newLineCharacter, fixAll); - } - ) + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => { + const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options); + const node = getTokenAtPosition(diag.file, diag.start); + const fixAll = true; + if (node) doChange(changes, node, diag.file, newLineCharacter, fixAll); + }, + ), }); function doChange( @@ -70,7 +78,7 @@ function doChange( node: Node, sourceFile: SourceFile, newLine: string, - fixAll = false + fixAll = false, ) { if (!isJSDocTypedefTag(node)) return; @@ -120,13 +128,12 @@ function doChange( changes.replaceRange(sourceFile, { pos, end }, declaration, { prefix, suffix }); } -function getLeftAndRightSiblings(typedefNode: JSDocTypedefTag): { leftSibling?: Node, rightSibling?: Node } { - +function getLeftAndRightSiblings(typedefNode: JSDocTypedefTag): { leftSibling?: Node; rightSibling?: Node; } { const commentNode = typedefNode.parent; const maxChildIndex = commentNode.getChildCount() - 1; const currentNodeIndex = commentNode.getChildren().findIndex( - (n) => n.getStart() === typedefNode.getStart() && n.getEnd() === typedefNode.getEnd() + n => n.getStart() === typedefNode.getStart() && n.getEnd() === typedefNode.getEnd(), ); const leftSibling = currentNodeIndex > 0 ? commentNode.getChildAt(currentNodeIndex - 1) : undefined; @@ -143,7 +150,7 @@ function findEndOfTextBetween(jsDocComment: JSDoc, from: number, to: number): nu const comment = jsDocComment.getText().substring(from - jsDocComment.getStart(), to - jsDocComment.getStart()); for (let i = comment.length; i > 0; i--) { - if(!/[*/\s]/g.test(comment.substring(i - 1, i))) { + if (!/[*/\s]/g.test(comment.substring(i - 1, i))) { return from + i; } } @@ -171,7 +178,7 @@ function createDeclaration(tag: JSDocTypedefTag): InterfaceDeclaration | TypeAli function createInterfaceForTypeLiteral( typeName: string, - typeLiteral: JSDocTypeLiteral + typeLiteral: JSDocTypeLiteral, ): InterfaceDeclaration | undefined { const propertySignatures = createSignatureFromTypeLiteral(typeLiteral); if (!some(propertySignatures)) return; @@ -187,7 +194,7 @@ function createInterfaceForTypeLiteral( function createTypeAliasForTypeExpression( typeName: string, - typeExpression: JSDocTypeExpression + typeExpression: JSDocTypeExpression, ): TypeAliasDeclaration | undefined { const typeReference = getSynthesizedDeepClone(typeExpression.type); if (!typeReference) return; @@ -196,7 +203,7 @@ function createTypeAliasForTypeExpression( /*modifiers*/ undefined, factory.createIdentifier(typeName), /*typeParameters*/ undefined, - typeReference + typeReference, ); } @@ -227,7 +234,7 @@ function createSignatureFromTypeLiteral(typeLiteral: JSDocTypeLiteral): Property /*modifiers*/ undefined, name, questionToken, - typeReference + typeReference, ); } }; @@ -242,7 +249,7 @@ function getPropertyName(tag: JSDocPropertyLikeTag): string | undefined { /** @internal */ export function getJSDocTypedefNodes(node: Node): readonly JSDocTag[] { if (hasJSDocNodes(node)) { - return flatMap(node.jsDoc, (doc) => doc.tags?.filter((tag) => isJSDocTypedefTag(tag))); + return flatMap(node.jsDoc, doc => doc.tags?.filter(tag => isJSDocTypedefTag(tag))); } return []; diff --git a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts index 466a8a9bcd719..f3dbb49a91e93 100644 --- a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts +++ b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts @@ -18,7 +18,11 @@ import { } from "../_namespaces/ts.codefix"; const fixId = "correctQualifiedNameToIndexedAccessType"; -const errorCodes = [Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1.code]; +const errorCodes = [ + Diagnostics + .Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1 + .code, +]; registerCodeFix({ errorCodes, getCodeActions(context) { @@ -26,27 +30,41 @@ registerCodeFix({ if (!qualifiedName) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, qualifiedName)); const newText = `${qualifiedName.left.text}["${qualifiedName.right.text}"]`; - return [createCodeFixAction(fixId, changes, [Diagnostics.Rewrite_as_the_indexed_access_type_0, newText], fixId, Diagnostics.Rewrite_all_as_indexed_access_types)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Rewrite_as_the_indexed_access_type_0, newText], + fixId, + Diagnostics.Rewrite_all_as_indexed_access_types, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: (context) => codeFixAll(context, errorCodes, (changes, diag) => { - const q = getQualifiedName(diag.file, diag.start); - if (q) { - doChange(changes, diag.file, q); - } - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const q = getQualifiedName(diag.file, diag.start); + if (q) { + doChange(changes, diag.file, q); + } + }), }); -function getQualifiedName(sourceFile: SourceFile, pos: number): QualifiedName & { left: Identifier } | undefined { +function getQualifiedName(sourceFile: SourceFile, pos: number): QualifiedName & { left: Identifier; } | undefined { const qualifiedName = findAncestor(getTokenAtPosition(sourceFile, pos), isQualifiedName)!; Debug.assert(!!qualifiedName, "Expected position to be owned by a qualified name."); - return isIdentifier(qualifiedName.left) ? qualifiedName as QualifiedName & { left: Identifier } : undefined; + return isIdentifier(qualifiedName.left) ? qualifiedName as QualifiedName & { left: Identifier; } : undefined; } -function doChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, qualifiedName: QualifiedName): void { +function doChange( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + qualifiedName: QualifiedName, +): void { const rightText = qualifiedName.right.text; const replacement = factory.createIndexedAccessTypeNode( factory.createTypeReferenceNode(qualifiedName.left, /*typeArguments*/ undefined), - factory.createLiteralTypeNode(factory.createStringLiteral(rightText))); + factory.createLiteralTypeNode(factory.createStringLiteral(rightText)), + ); changeTracker.replaceNode(sourceFile, qualifiedName, replacement); } diff --git a/src/services/codefixes/disableJsDiagnostics.ts b/src/services/codefixes/disableJsDiagnostics.ts index 96202931ae090..f89dbfe7b0184 100644 --- a/src/services/codefixes/disableJsDiagnostics.ts +++ b/src/services/codefixes/disableJsDiagnostics.ts @@ -38,21 +38,34 @@ registerCodeFix({ return undefined; } - const newLineCharacter = sourceFile.checkJsDirective ? "" : getNewLineOrDefaultFromHost(host, formatContext.options); + const newLineCharacter = sourceFile.checkJsDirective ? "" + : getNewLineOrDefaultFromHost(host, formatContext.options); const fixes: CodeFixAction[] = [ // fixId unnecessary because adding `// @ts-nocheck` even once will ignore every error in the file. createCodeFixActionWithoutFixAll( fixName, [createFileTextChanges(sourceFile.fileName, [ - createTextChange(sourceFile.checkJsDirective - ? createTextSpanFromBounds(sourceFile.checkJsDirective.pos, sourceFile.checkJsDirective.end) - : createTextSpan(0, 0), `// @ts-nocheck${newLineCharacter}`), + createTextChange( + sourceFile.checkJsDirective + ? createTextSpanFromBounds(sourceFile.checkJsDirective.pos, sourceFile.checkJsDirective.end) + : createTextSpan(0, 0), + `// @ts-nocheck${newLineCharacter}`, + ), ])], - Diagnostics.Disable_checking_for_this_file), + Diagnostics.Disable_checking_for_this_file, + ), ]; if (textChanges.isValidLocationToAddComment(sourceFile, span.start)) { - fixes.unshift(createCodeFixAction(fixName, textChanges.ChangeTracker.with(context, t => makeChange(t, sourceFile, span.start)), Diagnostics.Ignore_this_error_message, fixId, Diagnostics.Add_ts_ignore_to_all_error_messages)); + fixes.unshift( + createCodeFixAction( + fixName, + textChanges.ChangeTracker.with(context, t => makeChange(t, sourceFile, span.start)), + Diagnostics.Ignore_this_error_message, + fixId, + Diagnostics.Add_ts_ignore_to_all_error_messages, + ), + ); } return fixes; @@ -68,7 +81,12 @@ registerCodeFix({ }, }); -function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, seenLines?: Set) { +function makeChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + position: number, + seenLines?: Set, +) { const { line: lineNumber } = getLineAndCharacterOfPosition(sourceFile, position); // Only need to add `// @ts-ignore` for a line once. if (!seenLines || tryAddToSet(seenLines, lineNumber)) { diff --git a/src/services/codefixes/fixAddMissingConstraint.ts b/src/services/codefixes/fixAddMissingConstraint.ts index c5b2bd3573789..7752f7a354f8b 100644 --- a/src/services/codefixes/fixAddMissingConstraint.ts +++ b/src/services/codefixes/fixAddMissingConstraint.ts @@ -43,9 +43,13 @@ const errorCodes = [ // Diagnostics.This_type_parameter_probably_needs_an_extends_0_constraint Diagnostics.Type_0_is_not_comparable_to_type_1.code, Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated.code, - Diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code, + Diagnostics + .Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + .code, Diagnostics.Type_0_is_not_assignable_to_type_1.code, - Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties.code, + Diagnostics + .Argument_of_type_0_is_not_assignable_to_parameter_of_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_types_of_the_target_s_properties + .code, Diagnostics.Property_0_is_incompatible_with_index_signature.code, Diagnostics.Property_0_in_type_1_is_not_assignable_to_type_2.code, Diagnostics.Type_0_does_not_satisfy_the_constraint_1.code, @@ -57,8 +61,19 @@ registerCodeFix({ const info = getInfo(program, sourceFile, span); if (info === undefined) return; - const changes = textChanges.ChangeTracker.with(context, t => addMissingConstraint(t, program, preferences, host, sourceFile, info)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_extends_constraint, fixId, Diagnostics.Add_extends_constraint_to_all_type_parameters)]; + const changes = textChanges.ChangeTracker.with( + context, + t => addMissingConstraint(t, program, preferences, host, sourceFile, info), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_extends_constraint, + fixId, + Diagnostics.Add_extends_constraint_to_all_type_parameters, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => { @@ -76,7 +91,7 @@ registerCodeFix({ return undefined; }); })); - } + }, }); interface Info { @@ -86,11 +101,20 @@ interface Info { } function getInfo(program: Program, sourceFile: SourceFile, span: TextSpan): Info | undefined { - const diag = find(program.getSemanticDiagnostics(sourceFile), diag => diag.start === span.start && diag.length === span.length); + const diag = find( + program.getSemanticDiagnostics(sourceFile), + diag => diag.start === span.start && diag.length === span.length, + ); if (diag === undefined || diag.relatedInformation === undefined) return; - const related = find(diag.relatedInformation, related => related.code === Diagnostics.This_type_parameter_might_need_an_extends_0_constraint.code); - if (related === undefined || related.file === undefined || related.start === undefined || related.length === undefined) return; + const related = find( + diag.relatedInformation, + related => related.code === Diagnostics.This_type_parameter_might_need_an_extends_0_constraint.code, + ); + if ( + related === undefined || related.file === undefined || related.start === undefined + || related.length === undefined + ) return; let declaration = findAncestorMatchingSpan(related.file, createTextSpan(related.start, related.length)); if (declaration === undefined) return; @@ -105,14 +129,22 @@ function getInfo(program: Program, sourceFile: SourceFile, span: TextSpan): Info const token = getTokenAtPosition(sourceFile, span.start); const checker = program.getTypeChecker(); - const constraint = tryGetConstraintType(checker, token) || tryGetConstraintFromDiagnosticMessage(related.messageText); + const constraint = tryGetConstraintType(checker, token) + || tryGetConstraintFromDiagnosticMessage(related.messageText); return { constraint, declaration, token }; } return undefined; } -function addMissingConstraint(changes: textChanges.ChangeTracker, program: Program, preferences: UserPreferences, host: LanguageServiceHost, sourceFile: SourceFile, info: Info): void { +function addMissingConstraint( + changes: textChanges.ChangeTracker, + program: Program, + preferences: UserPreferences, + host: LanguageServiceHost, + sourceFile: SourceFile, + info: Info, +): void { const { declaration, constraint } = info; const checker = program.getTypeChecker(); @@ -123,9 +155,27 @@ function addMissingConstraint(changes: textChanges.ChangeTracker, program: Progr const scriptTarget = getEmitScriptTarget(program.getCompilerOptions()); const tracker = getNoopSymbolTrackerWithResolver({ program, host }); const importAdder = createImportAdder(sourceFile, program, preferences, host); - const typeNode = typeToAutoImportableTypeNode(checker, importAdder, constraint, /*contextNode*/ undefined, scriptTarget, /*flags*/ undefined, tracker); + const typeNode = typeToAutoImportableTypeNode( + checker, + importAdder, + constraint, + /*contextNode*/ undefined, + scriptTarget, + /*flags*/ undefined, + tracker, + ); if (typeNode) { - changes.replaceNode(sourceFile, declaration, factory.updateTypeParameterDeclaration(declaration, /*modifiers*/ undefined, declaration.name, typeNode, declaration.default)); + changes.replaceNode( + sourceFile, + declaration, + factory.updateTypeParameterDeclaration( + declaration, + /*modifiers*/ undefined, + declaration.name, + typeNode, + declaration.default, + ), + ); importAdder.writeFixes(changes); } } diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 5c9efb68258fe..8671f0a5c1fe3 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -138,7 +138,7 @@ const errorCodes = [ Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2.code, Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more.code, Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code, - Diagnostics.Cannot_find_name_0.code + Diagnostics.Cannot_find_name_0.code, ]; enum InfoKind { @@ -160,28 +160,69 @@ registerCodeFix({ } if (info.kind === InfoKind.ObjectLiteral) { const changes = textChanges.ChangeTracker.with(context, t => addObjectLiteralProperties(t, context, info)); - return [createCodeFixAction(fixMissingProperties, changes, Diagnostics.Add_missing_properties, fixMissingProperties, Diagnostics.Add_all_missing_properties)]; + return [ + createCodeFixAction( + fixMissingProperties, + changes, + Diagnostics.Add_missing_properties, + fixMissingProperties, + Diagnostics.Add_all_missing_properties, + ), + ]; } if (info.kind === InfoKind.JsxAttributes) { const changes = textChanges.ChangeTracker.with(context, t => addJsxAttributes(t, context, info)); - return [createCodeFixAction(fixMissingAttributes, changes, Diagnostics.Add_missing_attributes, fixMissingAttributes, Diagnostics.Add_all_missing_attributes)]; + return [ + createCodeFixAction( + fixMissingAttributes, + changes, + Diagnostics.Add_missing_attributes, + fixMissingAttributes, + Diagnostics.Add_all_missing_attributes, + ), + ]; } if (info.kind === InfoKind.Function || info.kind === InfoKind.Signature) { const changes = textChanges.ChangeTracker.with(context, t => addFunctionDeclaration(t, context, info)); - return [createCodeFixAction(fixMissingFunctionDeclaration, changes, [Diagnostics.Add_missing_function_declaration_0, info.token.text], fixMissingFunctionDeclaration, Diagnostics.Add_all_missing_function_declarations)]; + return [ + createCodeFixAction( + fixMissingFunctionDeclaration, + changes, + [Diagnostics.Add_missing_function_declaration_0, info.token.text], + fixMissingFunctionDeclaration, + Diagnostics.Add_all_missing_function_declarations, + ), + ]; } if (info.kind === InfoKind.Enum) { - const changes = textChanges.ChangeTracker.with(context, t => addEnumMemberDeclaration(t, context.program.getTypeChecker(), info)); - return [createCodeFixAction(fixMissingMember, changes, [Diagnostics.Add_missing_enum_member_0, info.token.text], fixMissingMember, Diagnostics.Add_all_missing_members)]; + const changes = textChanges.ChangeTracker.with( + context, + t => addEnumMemberDeclaration(t, context.program.getTypeChecker(), info), + ); + return [ + createCodeFixAction( + fixMissingMember, + changes, + [Diagnostics.Add_missing_enum_member_0, info.token.text], + fixMissingMember, + Diagnostics.Add_all_missing_members, + ), + ]; } - return concatenate(getActionsForMissingMethodDeclaration(context, info), getActionsForMissingMemberDeclaration(context, info)); + return concatenate( + getActionsForMissingMethodDeclaration(context, info), + getActionsForMissingMemberDeclaration(context, info), + ); }, fixIds: [fixMissingMember, fixMissingFunctionDeclaration, fixMissingProperties, fixMissingAttributes], getAllCodeActions: context => { const { program, fixId } = context; const checker = program.getTypeChecker(); const seen = new Map(); - const typeDeclToMembers = new Map(); + const typeDeclToMembers = new Map< + ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + TypeLikeDeclarationInfo[] + >(); return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => { eachDiagnostic(context, errorCodes, diag => { @@ -189,7 +230,10 @@ registerCodeFix({ if (!info || !addToSeen(seen, getNodeId(info.parentDeclaration) + "#" + info.token.text)) { return; } - if (fixId === fixMissingFunctionDeclaration && (info.kind === InfoKind.Function || info.kind === InfoKind.Signature)) { + if ( + fixId === fixMissingFunctionDeclaration + && (info.kind === InfoKind.Function || info.kind === InfoKind.Signature) + ) { addFunctionDeclaration(changes, context, info); } else if (fixId === fixMissingProperties && info.kind === InfoKind.ObjectLiteral) { @@ -216,23 +260,49 @@ registerCodeFix({ const supers = isTypeLiteralNode(declaration) ? undefined : getAllSupers(declaration, checker); for (const info of infos) { // If some superclass added this property, don't add it again. - if (supers?.some(superClassOrInterface => { - const superInfos = typeDeclToMembers.get(superClassOrInterface); - return !!superInfos && superInfos.some(({ token }) => token.text === info.token.text); - })) continue; + if ( + supers?.some(superClassOrInterface => { + const superInfos = typeDeclToMembers.get(superClassOrInterface); + return !!superInfos && superInfos.some(({ token }) => token.text === info.token.text); + }) + ) continue; const { parentDeclaration, declSourceFile, modifierFlags, token, call, isJSFile } = info; // Always prefer to add a method declaration if possible. if (call && !isPrivateIdentifier(token)) { - addMethodDeclaration(context, changes, call, token, modifierFlags & ModifierFlags.Static, parentDeclaration, declSourceFile); + addMethodDeclaration( + context, + changes, + call, + token, + modifierFlags & ModifierFlags.Static, + parentDeclaration, + declSourceFile, + ); } else { - if (isJSFile && !isInterfaceDeclaration(parentDeclaration) && !isTypeLiteralNode(parentDeclaration)) { - addMissingMemberInJs(changes, declSourceFile, parentDeclaration, token, !!(modifierFlags & ModifierFlags.Static)); + if ( + isJSFile && !isInterfaceDeclaration(parentDeclaration) + && !isTypeLiteralNode(parentDeclaration) + ) { + addMissingMemberInJs( + changes, + declSourceFile, + parentDeclaration, + token, + !!(modifierFlags & ModifierFlags.Static), + ); } else { const typeNode = getTypeNode(checker, parentDeclaration, token); - addPropertyDeclaration(changes, declSourceFile, parentDeclaration, token.text, typeNode, modifierFlags & ModifierFlags.Static); + addPropertyDeclaration( + changes, + declSourceFile, + parentDeclaration, + token.text, + typeNode, + modifierFlags & ModifierFlags.Static, + ); } } } @@ -291,7 +361,13 @@ interface SignatureInfo { readonly parentDeclaration: Node; } -function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, checker: TypeChecker, program: Program): Info | undefined { +function getInfo( + sourceFile: SourceFile, + tokenPos: number, + errorCode: number, + checker: TypeChecker, + program: Program, +): Info | undefined { // The identifier of the missing property. eg: // this.missing = 1; // ^^^^^^^ @@ -299,7 +375,10 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch const parent = token.parent; if (errorCode === Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code) { - if (!(token.kind === SyntaxKind.OpenBraceToken && isObjectLiteralExpression(parent) && isCallExpression(parent.parent))) return undefined; + if ( + !(token.kind === SyntaxKind.OpenBraceToken && isObjectLiteralExpression(parent) + && isCallExpression(parent.parent)) + ) return undefined; const argIndex = findIndex(parent.parent.arguments, arg => arg === parent); if (argIndex < 0) return undefined; @@ -310,16 +389,33 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch const param = signature.parameters[argIndex].valueDeclaration; if (!(param && isParameter(param) && isIdentifier(param.name))) return undefined; - const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent), checker.getParameterType(signature, argIndex), /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false)); + const properties = arrayFrom( + checker.getUnmatchedProperties( + checker.getTypeAtLocation(parent), + checker.getParameterType(signature, argIndex), + /*requireOptionalProperties*/ false, + /*matchDiscriminantProperties*/ false, + ), + ); if (!length(properties)) return undefined; return { kind: InfoKind.ObjectLiteral, token: param.name, properties, parentDeclaration: parent }; } if (!isMemberName(token)) return undefined; - if (isIdentifier(token) && hasInitializer(parent) && parent.initializer && isObjectLiteralExpression(parent.initializer)) { + if ( + isIdentifier(token) && hasInitializer(parent) && parent.initializer + && isObjectLiteralExpression(parent.initializer) + ) { const targetType = checker.getContextualType(token) || checker.getTypeAtLocation(token); - const properties = arrayFrom(checker.getUnmatchedProperties(checker.getTypeAtLocation(parent.initializer), targetType, /*requireOptionalProperties*/ false, /*matchDiscriminantProperties*/ false)); + const properties = arrayFrom( + checker.getUnmatchedProperties( + checker.getTypeAtLocation(parent.initializer), + targetType, + /*requireOptionalProperties*/ false, + /*matchDiscriminantProperties*/ false, + ), + ); if (!length(properties)) return undefined; return { kind: InfoKind.ObjectLiteral, token, properties, parentDeclaration: parent.initializer }; @@ -340,7 +436,14 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch return { kind: InfoKind.Signature, token, signature, sourceFile, parentDeclaration: findScope(token) }; } if (isCallExpression(parent) && parent.expression === token) { - return { kind: InfoKind.Function, token, call: parent, sourceFile, modifierFlags: ModifierFlags.None, parentDeclaration: findScope(token) }; + return { + kind: InfoKind.Function, + token, + call: parent, + sourceFile, + modifierFlags: ModifierFlags.None, + parentDeclaration: findScope(token), + }; } } @@ -353,15 +456,32 @@ function getInfo(sourceFile: SourceFile, tokenPos: number, errorCode: number, ch if (isIdentifier(token) && isCallExpression(parent.parent)) { const moduleDeclaration = find(symbol.declarations, isModuleDeclaration); const moduleDeclarationSourceFile = moduleDeclaration?.getSourceFile(); - if (moduleDeclaration && moduleDeclarationSourceFile && !isSourceFileFromLibrary(program, moduleDeclarationSourceFile)) { - return { kind: InfoKind.Function, token, call: parent.parent, sourceFile, modifierFlags: ModifierFlags.Export, parentDeclaration: moduleDeclaration }; + if ( + moduleDeclaration && moduleDeclarationSourceFile + && !isSourceFileFromLibrary(program, moduleDeclarationSourceFile) + ) { + return { + kind: InfoKind.Function, + token, + call: parent.parent, + sourceFile, + modifierFlags: ModifierFlags.Export, + parentDeclaration: moduleDeclaration, + }; } const moduleSourceFile = find(symbol.declarations, isSourceFile); if (sourceFile.commonJsModuleIndicator) return undefined; if (moduleSourceFile && !isSourceFileFromLibrary(program, moduleSourceFile)) { - return { kind: InfoKind.Function, token, call: parent.parent, sourceFile: moduleSourceFile, modifierFlags: ModifierFlags.Export, parentDeclaration: moduleSourceFile }; + return { + kind: InfoKind.Function, + token, + call: parent.parent, + sourceFile: moduleSourceFile, + modifierFlags: ModifierFlags.Export, + parentDeclaration: moduleSourceFile, + }; } } @@ -370,49 +490,95 @@ 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)) as + | InterfaceDeclaration + | TypeLiteralNode + | undefined; if (declaration && !isSourceFileFromLibrary(program, declaration.getSourceFile())) { - const makeStatic = !isTypeLiteralNode(declaration) && ((leftExpressionType as TypeReference).target || leftExpressionType) !== checker.getDeclaredTypeOfSymbol(symbol); + const makeStatic = !isTypeLiteralNode(declaration) + && ((leftExpressionType as TypeReference).target || leftExpressionType) + !== checker.getDeclaredTypeOfSymbol(symbol); if (makeStatic && (isPrivateIdentifier(token) || isInterfaceDeclaration(declaration))) return undefined; const declSourceFile = declaration.getSourceFile(); - const modifierFlags = isTypeLiteralNode(declaration) ? ModifierFlags.None : - (makeStatic ? ModifierFlags.Static : ModifierFlags.None) | (startsWithUnderscore(token.text) ? ModifierFlags.Private : ModifierFlags.None); + const modifierFlags = isTypeLiteralNode(declaration) ? ModifierFlags.None + : (makeStatic ? ModifierFlags.Static : ModifierFlags.None) + | (startsWithUnderscore(token.text) ? ModifierFlags.Private : ModifierFlags.None); const isJSFile = isSourceFileJS(declSourceFile); const call = tryCast(parent.parent, isCallExpression); - return { kind: InfoKind.TypeLikeDeclaration, token, call, modifierFlags, parentDeclaration: declaration, declSourceFile, isJSFile }; + return { + kind: InfoKind.TypeLikeDeclaration, + token, + call, + modifierFlags, + parentDeclaration: declaration, + declSourceFile, + isJSFile, + }; } const enumDeclaration = find(symbol.declarations, isEnumDeclaration); - if (enumDeclaration && !(leftExpressionType.flags & TypeFlags.EnumLike) && !isPrivateIdentifier(token) && !isSourceFileFromLibrary(program, enumDeclaration.getSourceFile())) { + if ( + enumDeclaration && !(leftExpressionType.flags & TypeFlags.EnumLike) && !isPrivateIdentifier(token) + && !isSourceFileFromLibrary(program, enumDeclaration.getSourceFile()) + ) { return { kind: InfoKind.Enum, token, parentDeclaration: enumDeclaration }; } return undefined; } -function getActionsForMissingMemberDeclaration(context: CodeFixContext, info: TypeLikeDeclarationInfo): CodeFixAction[] | undefined { - return info.isJSFile ? singleElementArray(createActionForAddMissingMemberInJavascriptFile(context, info)) : - createActionsForAddMissingMemberInTypeScriptFile(context, info); +function getActionsForMissingMemberDeclaration( + context: CodeFixContext, + info: TypeLikeDeclarationInfo, +): CodeFixAction[] | undefined { + return info.isJSFile ? singleElementArray(createActionForAddMissingMemberInJavascriptFile(context, info)) + : createActionsForAddMissingMemberInTypeScriptFile(context, info); } -function createActionForAddMissingMemberInJavascriptFile(context: CodeFixContext, { parentDeclaration, declSourceFile, modifierFlags, token }: TypeLikeDeclarationInfo): CodeFixAction | undefined { +function createActionForAddMissingMemberInJavascriptFile( + context: CodeFixContext, + { parentDeclaration, declSourceFile, modifierFlags, token }: TypeLikeDeclarationInfo, +): CodeFixAction | undefined { if (isInterfaceDeclaration(parentDeclaration) || isTypeLiteralNode(parentDeclaration)) { return undefined; } - const changes = textChanges.ChangeTracker.with(context, t => addMissingMemberInJs(t, declSourceFile, parentDeclaration, token, !!(modifierFlags & ModifierFlags.Static))); + const changes = textChanges.ChangeTracker.with( + context, + t => addMissingMemberInJs( + t, + declSourceFile, + parentDeclaration, + token, + !!(modifierFlags & ModifierFlags.Static), + ), + ); if (changes.length === 0) { return undefined; } - const diagnostic = modifierFlags & ModifierFlags.Static ? Diagnostics.Initialize_static_property_0 : - isPrivateIdentifier(token) ? Diagnostics.Declare_a_private_field_named_0 : Diagnostics.Initialize_property_0_in_the_constructor; - - return createCodeFixAction(fixMissingMember, changes, [diagnostic, token.text], fixMissingMember, Diagnostics.Add_all_missing_members); + const diagnostic = modifierFlags & ModifierFlags.Static ? Diagnostics.Initialize_static_property_0 + : isPrivateIdentifier(token) ? Diagnostics.Declare_a_private_field_named_0 + : Diagnostics.Initialize_property_0_in_the_constructor; + + return createCodeFixAction( + fixMissingMember, + changes, + [diagnostic, token.text], + fixMissingMember, + Diagnostics.Add_all_missing_members, + ); } -function addMissingMemberInJs(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier | PrivateIdentifier, makeStatic: boolean): void { +function addMissingMemberInJs( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + classDeclaration: ClassLikeDeclaration, + token: Identifier | PrivateIdentifier, + makeStatic: boolean, +): void { const tokenName = token.text; if (makeStatic) { if (classDeclaration.kind === SyntaxKind.ClassExpression) { @@ -428,7 +594,8 @@ function addMissingMemberInJs(changeTracker: textChanges.ChangeTracker, sourceFi tokenName, /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - /*initializer*/ undefined); + /*initializer*/ undefined, + ); const lastProp = getNodeToInsertPropertyAfter(classDeclaration); if (lastProp) { @@ -449,48 +616,92 @@ function addMissingMemberInJs(changeTracker: textChanges.ChangeTracker, sourceFi } function initializePropertyToUndefined(obj: Expression, propertyName: string) { - return factory.createExpressionStatement(factory.createAssignment(factory.createPropertyAccessExpression(obj, propertyName), createUndefined())); + return factory.createExpressionStatement( + factory.createAssignment(factory.createPropertyAccessExpression(obj, propertyName), createUndefined()), + ); } -function createActionsForAddMissingMemberInTypeScriptFile(context: CodeFixContext, { parentDeclaration, declSourceFile, modifierFlags, token }: TypeLikeDeclarationInfo): CodeFixAction[] | undefined { +function createActionsForAddMissingMemberInTypeScriptFile( + context: CodeFixContext, + { parentDeclaration, declSourceFile, modifierFlags, token }: TypeLikeDeclarationInfo, +): CodeFixAction[] | undefined { const memberName = token.text; const isStatic = modifierFlags & ModifierFlags.Static; const typeNode = getTypeNode(context.program.getTypeChecker(), parentDeclaration, token); - const addPropertyDeclarationChanges = (modifierFlags: ModifierFlags) => textChanges.ChangeTracker.with(context, t => addPropertyDeclaration(t, declSourceFile, parentDeclaration, memberName, typeNode, modifierFlags)); - - const actions = [createCodeFixAction(fixMissingMember, addPropertyDeclarationChanges(modifierFlags & ModifierFlags.Static), [isStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0, memberName], fixMissingMember, Diagnostics.Add_all_missing_members)]; + const addPropertyDeclarationChanges = (modifierFlags: ModifierFlags) => + textChanges.ChangeTracker.with( + context, + t => addPropertyDeclaration(t, declSourceFile, parentDeclaration, memberName, typeNode, modifierFlags), + ); + + const actions = [ + createCodeFixAction( + fixMissingMember, + addPropertyDeclarationChanges(modifierFlags & ModifierFlags.Static), + [isStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0, memberName], + fixMissingMember, + Diagnostics.Add_all_missing_members, + ), + ]; if (isStatic || isPrivateIdentifier(token)) { return actions; } if (modifierFlags & ModifierFlags.Private) { - actions.unshift(createCodeFixActionWithoutFixAll(fixMissingMember, addPropertyDeclarationChanges(ModifierFlags.Private), [Diagnostics.Declare_private_property_0, memberName])); + actions.unshift( + createCodeFixActionWithoutFixAll(fixMissingMember, addPropertyDeclarationChanges(ModifierFlags.Private), [ + Diagnostics.Declare_private_property_0, + memberName, + ]), + ); } actions.push(createAddIndexSignatureAction(context, declSourceFile, parentDeclaration, token.text, typeNode)); return actions; } -function getTypeNode(checker: TypeChecker, node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, token: Node) { +function getTypeNode( + checker: TypeChecker, + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + token: Node, +) { let typeNode: TypeNode | undefined; if (token.parent.parent.kind === SyntaxKind.BinaryExpression) { const binaryExpression = token.parent.parent as BinaryExpression; const otherExpression = token.parent === binaryExpression.left ? binaryExpression.right : binaryExpression.left; - const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(otherExpression))); + const widenedType = checker.getWidenedType( + checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(otherExpression)), + ); typeNode = checker.typeToTypeNode(widenedType, node, NodeBuilderFlags.NoTruncation); } else { const contextualType = checker.getContextualType(token.parent as Expression); - typeNode = contextualType ? checker.typeToTypeNode(contextualType, /*enclosingDeclaration*/ undefined, NodeBuilderFlags.NoTruncation) : undefined; + typeNode = contextualType + ? checker.typeToTypeNode(contextualType, /*enclosingDeclaration*/ undefined, NodeBuilderFlags.NoTruncation) + : undefined; } return typeNode || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); } -function addPropertyDeclaration(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, tokenName: string, typeNode: TypeNode, modifierFlags: ModifierFlags): void { - const modifiers = modifierFlags ? factory.createNodeArray(factory.createModifiersFromModifierFlags(modifierFlags)) : undefined; +function addPropertyDeclaration( + changeTracker: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + tokenName: string, + typeNode: TypeNode, + modifierFlags: ModifierFlags, +): void { + const modifiers = modifierFlags ? factory.createNodeArray(factory.createModifiersFromModifierFlags(modifierFlags)) + : undefined; const property = isClassLike(node) - ? factory.createPropertyDeclaration(modifiers, tokenName, /*questionOrExclamationToken*/ undefined, typeNode, /*initializer*/ undefined) + ? factory.createPropertyDeclaration( + modifiers, + tokenName, + /*questionOrExclamationToken*/ undefined, + typeNode, + /*initializer*/ undefined, + ) : factory.createPropertySignature(/*modifiers*/ undefined, tokenName, /*questionToken*/ undefined, typeNode); const lastProp = getNodeToInsertPropertyAfter(node); @@ -503,7 +714,9 @@ function addPropertyDeclaration(changeTracker: textChanges.ChangeTracker, source } // Gets the last of the first run of PropertyDeclarations, or undefined if the class does not start with a PropertyDeclaration. -function getNodeToInsertPropertyAfter(node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode): PropertyDeclaration | undefined { +function getNodeToInsertPropertyAfter( + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, +): PropertyDeclaration | undefined { let res: PropertyDeclaration | undefined; for (const member of node.members) { if (!isPropertyDeclaration(member)) break; @@ -512,7 +725,13 @@ function getNodeToInsertPropertyAfter(node: ClassLikeDeclaration | InterfaceDecl return res; } -function createAddIndexSignatureAction(context: CodeFixContext, sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, tokenName: string, typeNode: TypeNode): CodeFixAction { +function createAddIndexSignatureAction( + context: CodeFixContext, + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + tokenName: string, + typeNode: TypeNode, +): CodeFixAction { // Index signatures cannot have the static modifier. const stringTypeNode = factory.createKeywordTypeNode(SyntaxKind.StringKeyword); const indexingParameter = factory.createParameterDeclaration( @@ -521,28 +740,60 @@ function createAddIndexSignatureAction(context: CodeFixContext, sourceFile: Sour "x", /*questionToken*/ undefined, stringTypeNode, - /*initializer*/ undefined); + /*initializer*/ undefined, + ); const indexSignature = factory.createIndexSignature( /*modifiers*/ undefined, [indexingParameter], - typeNode); + typeNode, + ); - const changes = textChanges.ChangeTracker.with(context, t => t.insertMemberAtStart(sourceFile, node, indexSignature)); + const changes = textChanges.ChangeTracker.with( + context, + t => t.insertMemberAtStart(sourceFile, node, indexSignature), + ); // No fixId here because code-fix-all currently only works on adding individual named properties. - return createCodeFixActionWithoutFixAll(fixMissingMember, changes, [Diagnostics.Add_index_signature_for_property_0, tokenName]); + return createCodeFixActionWithoutFixAll(fixMissingMember, changes, [ + Diagnostics.Add_index_signature_for_property_0, + tokenName, + ]); } -function getActionsForMissingMethodDeclaration(context: CodeFixContext, info: TypeLikeDeclarationInfo): CodeFixAction[] | undefined { +function getActionsForMissingMethodDeclaration( + context: CodeFixContext, + info: TypeLikeDeclarationInfo, +): CodeFixAction[] | undefined { const { parentDeclaration, declSourceFile, modifierFlags, token, call } = info; if (call === undefined) { return undefined; } const methodName = token.text; - const addMethodDeclarationChanges = (modifierFlags: ModifierFlags) => textChanges.ChangeTracker.with(context, t => addMethodDeclaration(context, t, call, token, modifierFlags, parentDeclaration, declSourceFile)); - const actions = [createCodeFixAction(fixMissingMember, addMethodDeclarationChanges(modifierFlags & ModifierFlags.Static), [modifierFlags & ModifierFlags.Static ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0, methodName], fixMissingMember, Diagnostics.Add_all_missing_members)]; + const addMethodDeclarationChanges = (modifierFlags: ModifierFlags) => + textChanges.ChangeTracker.with( + context, + t => addMethodDeclaration(context, t, call, token, modifierFlags, parentDeclaration, declSourceFile), + ); + const actions = [ + createCodeFixAction( + fixMissingMember, + addMethodDeclarationChanges(modifierFlags & ModifierFlags.Static), + [ + modifierFlags & ModifierFlags.Static ? Diagnostics.Declare_static_method_0 + : Diagnostics.Declare_method_0, + methodName, + ], + fixMissingMember, + Diagnostics.Add_all_missing_members, + ), + ]; if (modifierFlags & ModifierFlags.Private) { - actions.unshift(createCodeFixActionWithoutFixAll(fixMissingMember, addMethodDeclarationChanges(ModifierFlags.Private), [Diagnostics.Declare_private_method_0, methodName])); + actions.unshift( + createCodeFixActionWithoutFixAll(fixMissingMember, addMethodDeclarationChanges(ModifierFlags.Private), [ + Diagnostics.Declare_private_method_0, + methodName, + ]), + ); } return actions; } @@ -558,7 +809,15 @@ function addMethodDeclaration( ): void { const importAdder = createImportAdder(sourceFile, context.program, context.preferences, context.host); const kind = isClassLike(parentDeclaration) ? SyntaxKind.MethodDeclaration : SyntaxKind.MethodSignature; - const signatureDeclaration = createSignatureDeclarationFromCallExpression(kind, context, importAdder, callExpression, name, modifierFlags, parentDeclaration) as MethodDeclaration; + const signatureDeclaration = createSignatureDeclarationFromCallExpression( + kind, + context, + importAdder, + callExpression, + name, + modifierFlags, + parentDeclaration, + ) as MethodDeclaration; const containingMethodDeclaration = tryGetContainingMethodDeclaration(parentDeclaration, callExpression); if (containingMethodDeclaration) { changes.insertNodeAfter(sourceFile, containingMethodDeclaration, signatureDeclaration); @@ -569,7 +828,11 @@ function addMethodDeclaration( importAdder.writeFixes(changes); } -function addEnumMemberDeclaration(changes: textChanges.ChangeTracker, checker: TypeChecker, { token, parentDeclaration }: EnumInfo) { +function addEnumMemberDeclaration( + changes: textChanges.ChangeTracker, + checker: TypeChecker, + { token, parentDeclaration }: EnumInfo, +) { /** * create initializer only literal enum that has string initializer. * value of initializer is a string literal that equal to name of enum member. @@ -580,30 +843,66 @@ function addEnumMemberDeclaration(changes: textChanges.ChangeTracker, checker: T return !!(type && type.flags & TypeFlags.StringLike); }); - const enumMember = factory.createEnumMember(token, hasStringInitializer ? factory.createStringLiteral(token.text) : undefined); - changes.replaceNode(parentDeclaration.getSourceFile(), parentDeclaration, factory.updateEnumDeclaration( + const enumMember = factory.createEnumMember( + token, + hasStringInitializer ? factory.createStringLiteral(token.text) : undefined, + ); + changes.replaceNode( + parentDeclaration.getSourceFile(), parentDeclaration, - parentDeclaration.modifiers, - parentDeclaration.name, - concatenate(parentDeclaration.members, singleElementArray(enumMember)) - ), { - leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, - trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude - }); + factory.updateEnumDeclaration( + parentDeclaration, + parentDeclaration.modifiers, + parentDeclaration.name, + concatenate(parentDeclaration.members, singleElementArray(enumMember)), + ), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, + trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, + }, + ); } -function addFunctionDeclaration(changes: textChanges.ChangeTracker, context: CodeFixContextBase, info: FunctionInfo | SignatureInfo) { +function addFunctionDeclaration( + changes: textChanges.ChangeTracker, + context: CodeFixContextBase, + info: FunctionInfo | SignatureInfo, +) { const quotePreference = getQuotePreference(context.sourceFile, context.preferences); const importAdder = createImportAdder(context.sourceFile, context.program, context.preferences, context.host); const functionDeclaration = info.kind === InfoKind.Function - ? createSignatureDeclarationFromCallExpression(SyntaxKind.FunctionDeclaration, context, importAdder, info.call, idText(info.token), info.modifierFlags, info.parentDeclaration) - : createSignatureDeclarationFromSignature(SyntaxKind.FunctionDeclaration, context, quotePreference, info.signature, createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), info.token, /*modifiers*/ undefined, /*optional*/ undefined, /*enclosingDeclaration*/ undefined, importAdder); + ? createSignatureDeclarationFromCallExpression( + SyntaxKind.FunctionDeclaration, + context, + importAdder, + info.call, + idText(info.token), + info.modifierFlags, + info.parentDeclaration, + ) + : createSignatureDeclarationFromSignature( + SyntaxKind.FunctionDeclaration, + context, + quotePreference, + info.signature, + createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), + info.token, + /*modifiers*/ undefined, + /*optional*/ undefined, + /*enclosingDeclaration*/ undefined, + importAdder, + ); if (functionDeclaration === undefined) { Debug.fail("fixMissingFunctionDeclaration codefix got unexpected error."); } isReturnStatement(info.parentDeclaration) - ? changes.insertNodeBefore(info.sourceFile, info.parentDeclaration, functionDeclaration, /*blankLineBetween*/ true) + ? changes.insertNodeBefore( + info.sourceFile, + info.parentDeclaration, + functionDeclaration, + /*blankLineBetween*/ true, + ) : changes.insertNodeAtEndOfScope(info.sourceFile, info.parentDeclaration, functionDeclaration); importAdder.writeFixes(changes); } @@ -615,38 +914,76 @@ function addJsxAttributes(changes: textChanges.ChangeTracker, context: CodeFixCo const jsxAttributesNode = info.parentDeclaration.attributes; const hasSpreadAttribute = some(jsxAttributesNode.properties, isJsxSpreadAttribute); const attrs = map(info.attributes, attr => { - const value = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(attr), info.parentDeclaration); + const value = tryGetValueFromType( + context, + checker, + importAdder, + quotePreference, + checker.getTypeOfSymbol(attr), + info.parentDeclaration, + ); const name = factory.createIdentifier(attr.name); - const jsxAttribute = factory.createJsxAttribute(name, factory.createJsxExpression(/*dotDotDotToken*/ undefined, value)); + const jsxAttribute = factory.createJsxAttribute( + name, + factory.createJsxExpression(/*dotDotDotToken*/ undefined, value), + ); // formattingScanner requires the Identifier to have a context for scanning attributes with "-" (data-foo). setParent(name, jsxAttribute); return jsxAttribute; }); - const jsxAttributes = factory.createJsxAttributes(hasSpreadAttribute ? [...attrs, ...jsxAttributesNode.properties] : [...jsxAttributesNode.properties, ...attrs]); + const jsxAttributes = factory.createJsxAttributes( + hasSpreadAttribute ? [...attrs, ...jsxAttributesNode.properties] : [...jsxAttributesNode.properties, ...attrs], + ); const options = { prefix: jsxAttributesNode.pos === jsxAttributesNode.end ? " " : undefined }; changes.replaceNode(context.sourceFile, jsxAttributesNode, jsxAttributes, options); importAdder.writeFixes(changes); } -function addObjectLiteralProperties(changes: textChanges.ChangeTracker, context: CodeFixContextBase, info: ObjectLiteralInfo) { +function addObjectLiteralProperties( + changes: textChanges.ChangeTracker, + context: CodeFixContextBase, + info: ObjectLiteralInfo, +) { const importAdder = createImportAdder(context.sourceFile, context.program, context.preferences, context.host); const quotePreference = getQuotePreference(context.sourceFile, context.preferences); const target = getEmitScriptTarget(context.program.getCompilerOptions()); const checker = context.program.getTypeChecker(); const props = map(info.properties, prop => { - const initializer = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(prop), info.parentDeclaration); - return factory.createPropertyAssignment(createPropertyNameFromSymbol(prop, target, quotePreference, checker), initializer); + const initializer = tryGetValueFromType( + context, + checker, + importAdder, + quotePreference, + checker.getTypeOfSymbol(prop), + info.parentDeclaration, + ); + return factory.createPropertyAssignment( + createPropertyNameFromSymbol(prop, target, quotePreference, checker), + initializer, + ); }); const options = { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, - indentation: info.indentation + indentation: info.indentation, }; - changes.replaceNode(context.sourceFile, info.parentDeclaration, factory.createObjectLiteralExpression([...info.parentDeclaration.properties, ...props], /*multiLine*/ true), options); + changes.replaceNode( + context.sourceFile, + info.parentDeclaration, + factory.createObjectLiteralExpression([...info.parentDeclaration.properties, ...props], /*multiLine*/ true), + options, + ); importAdder.writeFixes(changes); } -function tryGetValueFromType(context: CodeFixContextBase, checker: TypeChecker, importAdder: ImportAdder, quotePreference: QuotePreference, type: Type, enclosingDeclaration: Node | undefined): Expression { +function tryGetValueFromType( + context: CodeFixContextBase, + checker: TypeChecker, + importAdder: ImportAdder, + quotePreference: QuotePreference, + type: Type, + enclosingDeclaration: Node | undefined, +): Expression { if (type.flags & TypeFlags.AnyOrUnknown) { return createUndefined(); } @@ -664,8 +1001,14 @@ function tryGetValueFromType(context: CodeFixContextBase, checker: TypeChecker, } if (type.flags & TypeFlags.EnumLike) { const enumMember = type.symbol.exports ? firstOrUndefinedIterator(type.symbol.exports.values()) : type.symbol; - const name = checker.symbolToExpression(type.symbol.parent ? type.symbol.parent : type.symbol, SymbolFlags.Value, /*enclosingDeclaration*/ undefined, /*flags*/ undefined); - return enumMember === undefined || name === undefined ? factory.createNumericLiteral(0) : factory.createPropertyAccessExpression(name, checker.symbolToString(enumMember)); + const name = checker.symbolToExpression( + type.symbol.parent ? type.symbol.parent : type.symbol, + SymbolFlags.Value, + /*enclosingDeclaration*/ undefined, + /*flags*/ undefined, + ); + return enumMember === undefined || name === undefined ? factory.createNumericLiteral(0) + : factory.createPropertyAccessExpression(name, checker.symbolToString(enumMember)); } if (type.flags & TypeFlags.NumberLiteral) { return factory.createNumericLiteral((type as NumberLiteralType).value); @@ -674,16 +1017,23 @@ function tryGetValueFromType(context: CodeFixContextBase, checker: TypeChecker, return factory.createBigIntLiteral((type as BigIntLiteralType).value); } if (type.flags & TypeFlags.StringLiteral) { - return factory.createStringLiteral((type as StringLiteralType).value, /* isSingleQuote */ quotePreference === QuotePreference.Single); + return factory.createStringLiteral( + (type as StringLiteralType).value, + /* isSingleQuote */ quotePreference === QuotePreference.Single, + ); } if (type.flags & TypeFlags.BooleanLiteral) { - return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) ? factory.createFalse() : factory.createTrue(); + return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) + ? factory.createFalse() : factory.createTrue(); } if (type.flags & TypeFlags.Null) { return factory.createNull(); } if (type.flags & TypeFlags.Union) { - const expression = firstDefined((type as UnionType).types, t => tryGetValueFromType(context, checker, importAdder, quotePreference, t, enclosingDeclaration)); + const expression = firstDefined( + (type as UnionType).types, + t => tryGetValueFromType(context, checker, importAdder, quotePreference, t, enclosingDeclaration), + ); return expression ?? createUndefined(); } if (checker.isArrayLikeType(type)) { @@ -691,20 +1041,40 @@ function tryGetValueFromType(context: CodeFixContextBase, checker: TypeChecker, } if (isObjectLiteralType(type)) { const props = map(checker.getPropertiesOfType(type), prop => { - const initializer = tryGetValueFromType(context, checker, importAdder, quotePreference, checker.getTypeOfSymbol(prop), enclosingDeclaration); + const initializer = tryGetValueFromType( + context, + checker, + importAdder, + quotePreference, + checker.getTypeOfSymbol(prop), + enclosingDeclaration, + ); return factory.createPropertyAssignment(prop.name, initializer); }); return factory.createObjectLiteralExpression(props, /*multiLine*/ true); } if (getObjectFlags(type) & ObjectFlags.Anonymous) { - const decl = find(type.symbol.declarations || emptyArray, or(isFunctionTypeNode, isMethodSignature, isMethodDeclaration)); + const decl = find( + type.symbol.declarations || emptyArray, + or(isFunctionTypeNode, isMethodSignature, isMethodDeclaration), + ); if (decl === undefined) return createUndefined(); const signature = checker.getSignaturesOfType(type, SignatureKind.Call); if (signature === undefined) return createUndefined(); - const func = createSignatureDeclarationFromSignature(SyntaxKind.FunctionExpression, context, quotePreference, signature[0], - createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), /*name*/ undefined, /*modifiers*/ undefined, /*optional*/ undefined, /*enclosingDeclaration*/ enclosingDeclaration, importAdder) as FunctionExpression | undefined; + const func = createSignatureDeclarationFromSignature( + SyntaxKind.FunctionExpression, + context, + quotePreference, + signature[0], + createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), + /*name*/ undefined, + /*modifiers*/ undefined, + /*optional*/ undefined, + /*enclosingDeclaration*/ enclosingDeclaration, + importAdder, + ) as FunctionExpression | undefined; return func ?? createUndefined(); } if (getObjectFlags(type) & ObjectFlags.Class) { @@ -714,7 +1084,11 @@ function tryGetValueFromType(context: CodeFixContextBase, checker: TypeChecker, const constructorDeclaration = getFirstConstructorWithBody(classDeclaration); if (constructorDeclaration && length(constructorDeclaration.parameters)) return createUndefined(); - return factory.createNewExpression(factory.createIdentifier(type.symbol.name), /*typeArguments*/ undefined, /*argumentsArray*/ undefined); + return factory.createNewExpression( + factory.createIdentifier(type.symbol.name), + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, + ); } return createUndefined(); } @@ -724,8 +1098,9 @@ function createUndefined() { } function isObjectLiteralType(type: Type) { - return (type.flags & TypeFlags.Object) && - ((getObjectFlags(type) & ObjectFlags.ObjectLiteral) || (type.symbol && tryCast(singleOrUndefined(type.symbol.declarations), isTypeLiteralNode))); + return (type.flags & TypeFlags.Object) + && ((getObjectFlags(type) & ObjectFlags.ObjectLiteral) + || (type.symbol && tryCast(singleOrUndefined(type.symbol.declarations), isTypeLiteralNode))); } function getUnmatchedAttributes(checker: TypeChecker, target: ScriptTarget, source: JsxOpeningLikeElement) { @@ -747,11 +1122,19 @@ function getUnmatchedAttributes(checker: TypeChecker, target: ScriptTarget, sour } } } - return filter(targetProps, targetProp => - isIdentifierText(targetProp.name, target, LanguageVariant.JSX) && !((targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial) || seenNames.has(targetProp.escapedName))); + return filter( + targetProps, + targetProp => + isIdentifierText(targetProp.name, target, LanguageVariant.JSX) + && !((targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial) + || seenNames.has(targetProp.escapedName)), + ); } -function tryGetContainingMethodDeclaration(node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, callExpression: CallExpression) { +function tryGetContainingMethodDeclaration( + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + callExpression: CallExpression, +) { if (isTypeLiteralNode(node)) { return undefined; } @@ -759,12 +1142,26 @@ function tryGetContainingMethodDeclaration(node: ClassLikeDeclaration | Interfac return declaration && declaration.parent === node ? declaration : undefined; } -function createPropertyNameFromSymbol(symbol: Symbol, target: ScriptTarget, quotePreference: QuotePreference, checker: TypeChecker) { +function createPropertyNameFromSymbol( + symbol: Symbol, + target: ScriptTarget, + quotePreference: QuotePreference, + checker: TypeChecker, +) { if (isTransientSymbol(symbol)) { - const prop = checker.symbolToNode(symbol, SymbolFlags.Value, /*enclosingDeclaration*/ undefined, NodeBuilderFlags.WriteComputedProps); + const prop = checker.symbolToNode( + symbol, + SymbolFlags.Value, + /*enclosingDeclaration*/ undefined, + NodeBuilderFlags.WriteComputedProps, + ); if (prop && isComputedPropertyName(prop)) return prop; } - return createPropertyNameNodeForIdentifierOrLiteral(symbol.name, target, quotePreference === QuotePreference.Single); + return createPropertyNameNodeForIdentifierOrLiteral( + symbol.name, + target, + quotePreference === QuotePreference.Single, + ); } function findScope(node: Node) { diff --git a/src/services/codefixes/fixAddMissingNewOperator.ts b/src/services/codefixes/fixAddMissingNewOperator.ts index 32b17b39233d8..3bd1762741811 100644 --- a/src/services/codefixes/fixAddMissingNewOperator.ts +++ b/src/services/codefixes/fixAddMissingNewOperator.ts @@ -23,11 +23,19 @@ registerCodeFix({ getCodeActions(context) { const { sourceFile, span } = context; const changes = textChanges.ChangeTracker.with(context, t => addMissingNewOperator(t, sourceFile, span)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_new_operator_to_call, fixId, Diagnostics.Add_missing_new_operator_to_all_calls)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_missing_new_operator_to_call, + fixId, + Diagnostics.Add_missing_new_operator_to_all_calls, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => - addMissingNewOperator(changes, context.sourceFile, diag)), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => addMissingNewOperator(changes, context.sourceFile, diag)), }); function addMissingNewOperator(changes: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan): void { diff --git a/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts b/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts index 20e76fbb1bf23..12e6eb02a576c 100644 --- a/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts +++ b/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts @@ -16,7 +16,9 @@ import { const fixIdAddMissingTypeof = "fixAddModuleReferTypeMissingTypeof"; const fixId = fixIdAddMissingTypeof; -const errorCodes = [Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0.code]; +const errorCodes = [ + Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here_Did_you_mean_typeof_import_0.code, +]; registerCodeFix({ errorCodes, @@ -24,11 +26,17 @@ registerCodeFix({ const { sourceFile, span } = context; const importType = getImportTypeNode(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, importType)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_typeof, fixId, Diagnostics.Add_missing_typeof)]; + return [ + createCodeFixAction(fixId, changes, Diagnostics.Add_missing_typeof, fixId, Diagnostics.Add_missing_typeof), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => - doChange(changes, context.sourceFile, getImportTypeNode(diag.file, diag.start))), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => doChange(changes, context.sourceFile, getImportTypeNode(diag.file, diag.start)), + ), }); function getImportTypeNode(sourceFile: SourceFile, pos: number): ImportTypeNode { @@ -39,6 +47,13 @@ function getImportTypeNode(sourceFile: SourceFile, pos: number): ImportTypeNode } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importType: ImportTypeNode) { - const newTypeNode = factory.updateImportTypeNode(importType, importType.argument, importType.assertions, importType.qualifier, importType.typeArguments, /*isTypeOf*/ true); + const newTypeNode = factory.updateImportTypeNode( + importType, + importType.argument, + importType.assertions, + importType.qualifier, + importType.typeArguments, + /*isTypeOf*/ true, + ); changes.replaceNode(sourceFile, importType, newTypeNode); } diff --git a/src/services/codefixes/fixAddVoidToPromise.ts b/src/services/codefixes/fixAddVoidToPromise.ts index 4abb3cdedda2d..10230e22d8cae 100644 --- a/src/services/codefixes/fixAddVoidToPromise.ts +++ b/src/services/codefixes/fixAddVoidToPromise.ts @@ -34,26 +34,52 @@ import { const fixName = "addVoidToPromise"; const fixId = "addVoidToPromise"; const errorCodes = [ - Diagnostics.Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments.code, - Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise.code + Diagnostics + .Expected_1_argument_but_got_0_new_Promise_needs_a_JSDoc_hint_to_produce_a_resolve_that_can_be_called_without_arguments + .code, + Diagnostics.Expected_0_arguments_but_got_1_Did_you_forget_to_include_void_in_your_type_argument_to_Promise.code, ]; registerCodeFix({ errorCodes, fixIds: [fixId], getCodeActions(context) { - const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span, context.program)); + const changes = textChanges.ChangeTracker.with( + context, + t => makeChange(t, context.sourceFile, context.span, context.program), + ); if (changes.length > 0) { - return [createCodeFixAction(fixName, changes, Diagnostics.Add_void_to_Promise_resolved_without_a_value, fixId, Diagnostics.Add_void_to_all_Promises_resolved_without_a_value)]; + return [ + createCodeFixAction( + fixName, + changes, + Diagnostics.Add_void_to_Promise_resolved_without_a_value, + fixId, + Diagnostics.Add_void_to_all_Promises_resolved_without_a_value, + ), + ]; } }, getAllCodeActions(context: CodeFixAllContext) { - return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag, context.program, new Set())); - } + return codeFixAll( + context, + errorCodes, + (changes, diag) => makeChange(changes, diag.file, diag, context.program, new Set()), + ); + }, }); -function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan, program: Program, seen?: Set) { +function makeChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + span: TextSpan, + program: Program, + seen?: Set, +) { const node = getTokenAtPosition(sourceFile, span.start); - if (!isIdentifier(node) || !isCallExpression(node.parent) || node.parent.expression !== node || node.parent.arguments.length !== 0) return; + if ( + !isIdentifier(node) || !isCallExpression(node.parent) || node.parent.expression !== node + || node.parent.arguments.length !== 0 + ) return; const checker = program.getTypeChecker(); const symbol = checker.getSymbolAtLocation(node); @@ -70,8 +96,11 @@ function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, if (some(typeArguments)) { // append ` | void` to type argument const typeArgument = typeArguments[0]; - const needsParens = !isUnionTypeNode(typeArgument) && !isParenthesizedTypeNode(typeArgument) && - isParenthesizedTypeNode(factory.createUnionTypeNode([typeArgument, factory.createKeywordTypeNode(SyntaxKind.VoidKeyword)]).types[0]); + const needsParens = !isUnionTypeNode(typeArgument) && !isParenthesizedTypeNode(typeArgument) + && isParenthesizedTypeNode( + factory.createUnionTypeNode([typeArgument, factory.createKeywordTypeNode(SyntaxKind.VoidKeyword)]) + .types[0], + ); if (needsParens) { changes.insertText(sourceFile, typeArgument.pos, "("); } @@ -86,7 +115,11 @@ function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, if (!parameterType || parameterType.flags & TypeFlags.AnyOrUnknown) { // give the expression a type changes.insertText(sourceFile, decl.parent.parent.end, `)`); - changes.insertText(sourceFile, skipTrivia(sourceFile.text, decl.parent.parent.pos), `/** @type {Promise} */(`); + changes.insertText( + sourceFile, + skipTrivia(sourceFile.text, decl.parent.parent.pos), + `/** @type {Promise} */(`, + ); } } else { @@ -102,7 +135,10 @@ function getEffectiveTypeArguments(node: NewExpression) { if (isInJSFile(node)) { if (isParenthesizedExpression(node.parent)) { const jsDocType = getJSDocTypeTag(node.parent)?.typeExpression.type; - if (jsDocType && isTypeReferenceNode(jsDocType) && isIdentifier(jsDocType.typeName) && idText(jsDocType.typeName) === "Promise") { + if ( + jsDocType && isTypeReferenceNode(jsDocType) && isIdentifier(jsDocType.typeName) + && idText(jsDocType.typeName) === "Promise" + ) { return jsDocType.typeArguments; } } diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index ee1f5f73a4c31..79ed7d04ceaca 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -31,7 +31,7 @@ const errorCodes = [ Diagnostics.await_expressions_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code, Diagnostics.await_using_statements_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code, Diagnostics.for_await_loops_are_only_allowed_within_async_functions_and_at_the_top_levels_of_modules.code, - Diagnostics.Cannot_find_name_0_Did_you_mean_to_write_this_in_an_async_function.code + Diagnostics.Cannot_find_name_0_Did_you_mean_to_write_this_in_an_async_function.code, ]; registerCodeFix({ errorCodes, @@ -40,7 +40,15 @@ registerCodeFix({ const nodes = getNodes(sourceFile, span.start); if (!nodes) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, nodes)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_async_modifier_to_containing_function, fixId, Diagnostics.Add_all_missing_async_modifiers)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_async_modifier_to_containing_function, + fixId, + Diagnostics.Add_all_missing_async_modifiers, + ), + ]; }, fixIds: [fixId], getAllCodeActions: function getAllCodeActionsToFixAwaitInSyncFunction(context) { @@ -57,14 +65,19 @@ function getReturnType(expr: FunctionDeclaration | MethodDeclaration | FunctionE if (expr.type) { return expr.type; } - if (isVariableDeclaration(expr.parent) && - expr.parent.type && - isFunctionTypeNode(expr.parent.type)) { + if ( + isVariableDeclaration(expr.parent) + && expr.parent.type + && isFunctionTypeNode(expr.parent.type) + ) { return expr.parent.type.type; } } -function getNodes(sourceFile: SourceFile, start: number): { insertBefore: Node, returnType: TypeNode | undefined } | undefined { +function getNodes( + sourceFile: SourceFile, + start: number, +): { insertBefore: Node; returnType: TypeNode | undefined; } | undefined { const token = getTokenAtPosition(sourceFile, start); const containingFunction = getContainingFunction(token); if (!containingFunction) { @@ -82,7 +95,8 @@ function getNodes(sourceFile: SourceFile, start: number): { insertBefore: Node, break; case SyntaxKind.ArrowFunction: const kind = containingFunction.typeParameters ? SyntaxKind.LessThanToken : SyntaxKind.OpenParenToken; - insertBefore = findChildOfKind(containingFunction, kind, sourceFile) || first(containingFunction.parameters); + insertBefore = findChildOfKind(containingFunction, kind, sourceFile) + || first(containingFunction.parameters); break; default: return; @@ -90,19 +104,23 @@ function getNodes(sourceFile: SourceFile, start: number): { insertBefore: Node, return insertBefore && { insertBefore, - returnType: getReturnType(containingFunction) + returnType: getReturnType(containingFunction), }; } function doChange( changes: textChanges.ChangeTracker, sourceFile: SourceFile, - { insertBefore, returnType }: { insertBefore: Node, returnType: TypeNode | undefined }): void { - + { insertBefore, returnType }: { insertBefore: Node; returnType: TypeNode | undefined; }, +): void { if (returnType) { const entityName = getEntityNameFromTypeNode(returnType); if (!entityName || entityName.kind !== SyntaxKind.Identifier || entityName.text !== "Promise") { - changes.replaceNode(sourceFile, returnType, factory.createTypeReferenceNode("Promise", factory.createNodeArray([returnType]))); + changes.replaceNode( + sourceFile, + returnType, + factory.createTypeReferenceNode("Promise", factory.createNodeArray([returnType])), + ); } } changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, insertBefore); diff --git a/src/services/codefixes/fixCannotFindModule.ts b/src/services/codefixes/fixCannotFindModule.ts index d128045f7f075..66970931e89de 100644 --- a/src/services/codefixes/fixCannotFindModule.ts +++ b/src/services/codefixes/fixCannotFindModule.ts @@ -35,7 +35,14 @@ registerCodeFix({ const typesPackageName = getTypesPackageNameToInstall(packageName, host, context.errorCode); return typesPackageName === undefined ? [] - : [createCodeFixAction(fixName, /*changes*/ [], [Diagnostics.Install_0, typesPackageName], fixIdInstallTypesPackage, Diagnostics.Install_all_missing_types_packages, getInstallCommand(sourceFile.fileName, typesPackageName))]; + : [createCodeFixAction( + fixName, + /*changes*/ [], + [Diagnostics.Install_0, typesPackageName], + fixIdInstallTypesPackage, + Diagnostics.Install_all_missing_types_packages, + getInstallCommand(sourceFile.fileName, typesPackageName), + )]; }, fixIds: [fixIdInstallTypesPackage], getAllCodeActions: context => { @@ -69,7 +76,11 @@ function tryGetImportedPackageName(sourceFile: SourceFile, pos: number): string return isExternalModuleNameRelative(packageName) ? undefined : packageName; } -function getTypesPackageNameToInstall(packageName: string, host: LanguageServiceHost, diagCode: number): string | undefined { +function getTypesPackageNameToInstall( + packageName: string, + host: LanguageServiceHost, + diagCode: number, +): string | undefined { return diagCode === errorCodeCannotFindModule ? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined) : (host.isKnownTypesPackageName?.(packageName) ? getTypesPackageName(packageName) : undefined); diff --git a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts index 80649e31bc5dd..1d5bbe3d2c929 100644 --- a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts +++ b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts @@ -33,9 +33,18 @@ registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToFixClassNotImplementingInheritedMembers(context) { const { sourceFile, span } = context; - const changes = textChanges.ChangeTracker.with(context, t => - addMissingMembers(getClass(sourceFile, span.start), sourceFile, context, t, context.preferences)); - return changes.length === 0 ? undefined : [createCodeFixAction(fixId, changes, Diagnostics.Implement_inherited_abstract_class, fixId, Diagnostics.Implement_all_inherited_abstract_classes)]; + const changes = textChanges.ChangeTracker.with( + context, + t => addMissingMembers(getClass(sourceFile, span.start), sourceFile, context, t, context.preferences), + ); + return changes.length === 0 ? undefined + : [createCodeFixAction( + fixId, + changes, + Diagnostics.Implement_inherited_abstract_class, + fixId, + Diagnostics.Implement_all_inherited_abstract_classes, + )]; }, fixIds: [fixId], getAllCodeActions: function getAllCodeActionsToFixClassDoesntImplementInheritedAbstractMember(context) { @@ -56,17 +65,33 @@ function getClass(sourceFile: SourceFile, pos: number): ClassLikeDeclaration { return cast(token.parent, isClassLike); } -function addMissingMembers(classDeclaration: ClassLikeDeclaration, sourceFile: SourceFile, context: TypeConstructionContext, changeTracker: textChanges.ChangeTracker, preferences: UserPreferences): void { +function addMissingMembers( + classDeclaration: ClassLikeDeclaration, + sourceFile: SourceFile, + context: TypeConstructionContext, + changeTracker: textChanges.ChangeTracker, + preferences: UserPreferences, +): void { const extendsNode = getEffectiveBaseTypeNode(classDeclaration)!; const checker = context.program.getTypeChecker(); const instantiatedExtendsType = checker.getTypeAtLocation(extendsNode); // Note that this is ultimately derived from a map indexed by symbol names, // so duplicates cannot occur. - const abstractAndNonPrivateExtendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType).filter(symbolPointsToNonPrivateAndAbstractMember); + const abstractAndNonPrivateExtendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType).filter( + symbolPointsToNonPrivateAndAbstractMember, + ); const importAdder = createImportAdder(sourceFile, context.program, preferences, context.host); - createMissingMemberNodes(classDeclaration, abstractAndNonPrivateExtendsSymbols, sourceFile, context, preferences, importAdder, member => changeTracker.insertMemberAtStart(sourceFile, classDeclaration, member as ClassElement)); + createMissingMemberNodes( + classDeclaration, + abstractAndNonPrivateExtendsSymbols, + sourceFile, + context, + preferences, + importAdder, + member => changeTracker.insertMemberAtStart(sourceFile, classDeclaration, member as ClassElement), + ); importAdder.writeFixes(changeTracker); } diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index f91c49c9bece9..ed7c2083f657d 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -40,7 +40,8 @@ import { const errorCodes = [ Diagnostics.Class_0_incorrectly_implements_interface_1.code, - Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass.code + Diagnostics.Class_0_incorrectly_implements_class_1_Did_you_mean_to_extend_1_and_inherit_its_members_as_a_subclass + .code, ]; const fixId = "fixClassIncorrectlyImplementsInterface"; // TODO: share a group with fixClassDoesntImplementInheritedAbstractMember? registerCodeFix({ @@ -48,10 +49,28 @@ registerCodeFix({ getCodeActions(context) { const { sourceFile, span } = context; const classDeclaration = getClass(sourceFile, span.start); - return mapDefined(getEffectiveImplementsTypeNodes(classDeclaration), implementedTypeNode => { - const changes = textChanges.ChangeTracker.with(context, t => addMissingDeclarations(context, implementedTypeNode, sourceFile, classDeclaration, t, context.preferences)); - return changes.length === 0 ? undefined : createCodeFixAction(fixId, changes, [Diagnostics.Implement_interface_0, implementedTypeNode.getText(sourceFile)], fixId, Diagnostics.Implement_all_unimplemented_interfaces); - }); + return mapDefined( + getEffectiveImplementsTypeNodes(classDeclaration), + implementedTypeNode => { + const changes = textChanges.ChangeTracker.with(context, t => + addMissingDeclarations( + context, + implementedTypeNode, + sourceFile, + classDeclaration, + t, + context.preferences, + )); + return changes.length === 0 ? undefined + : createCodeFixAction( + fixId, + changes, + [Diagnostics.Implement_interface_0, implementedTypeNode.getText(sourceFile)], + fixId, + Diagnostics.Implement_all_unimplemented_interfaces, + ); + }, + ); }, fixIds: [fixId], getAllCodeActions(context) { @@ -60,7 +79,14 @@ registerCodeFix({ const classDeclaration = getClass(diag.file, diag.start); if (addToSeen(seenClassDeclarations, getNodeId(classDeclaration))) { for (const implementedTypeNode of getEffectiveImplementsTypeNodes(classDeclaration)!) { - addMissingDeclarations(context, implementedTypeNode, diag.file, classDeclaration, changes, context.preferences); + addMissingDeclarations( + context, + implementedTypeNode, + diag.file, + classDeclaration, + changes, + context.preferences, + ); } } }); @@ -68,7 +94,10 @@ registerCodeFix({ }); function getClass(sourceFile: SourceFile, pos: number): ClassLikeDeclaration { - return Debug.checkDefined(getContainingClass(getTokenAtPosition(sourceFile, pos)), "There should be a containing class"); + return Debug.checkDefined( + getContainingClass(getTokenAtPosition(sourceFile, pos)), + "There should be a containing class", + ); } function symbolPointsToNonPrivateMember(symbol: Symbol) { @@ -89,7 +118,9 @@ function addMissingDeclarations( // so duplicates cannot occur. const implementedType = checker.getTypeAtLocation(implementedTypeNode) as InterfaceType; const implementedTypeSymbols = checker.getPropertiesOfType(implementedType); - const nonPrivateAndNotExistedInHeritageClauseMembers = implementedTypeSymbols.filter(and(symbolPointsToNonPrivateMember, symbol => !maybeHeritageClauseSymbol.has(symbol.escapedName))); + const nonPrivateAndNotExistedInHeritageClauseMembers = implementedTypeSymbols.filter( + and(symbolPointsToNonPrivateMember, symbol => !maybeHeritageClauseSymbol.has(symbol.escapedName)), + ); const classType = checker.getTypeAtLocation(classDeclaration); const constructor = find(classDeclaration.members, m => isConstructorDeclaration(m)); @@ -102,18 +133,39 @@ function addMissingDeclarations( } const importAdder = createImportAdder(sourceFile, context.program, preferences, context.host); - createMissingMemberNodes(classDeclaration, nonPrivateAndNotExistedInHeritageClauseMembers, sourceFile, context, preferences, importAdder, member => insertInterfaceMemberNode(sourceFile, classDeclaration, member as ClassElement)); + createMissingMemberNodes( + classDeclaration, + nonPrivateAndNotExistedInHeritageClauseMembers, + sourceFile, + context, + preferences, + importAdder, + member => insertInterfaceMemberNode(sourceFile, classDeclaration, member as ClassElement), + ); importAdder.writeFixes(changeTracker); function createMissingIndexSignatureDeclaration(type: InterfaceType, kind: IndexKind): void { const indexInfoOfKind = checker.getIndexInfoOfType(type, kind); if (indexInfoOfKind) { - insertInterfaceMemberNode(sourceFile, classDeclaration, checker.indexInfoToIndexSignatureDeclaration(indexInfoOfKind, classDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context))!); + insertInterfaceMemberNode( + sourceFile, + classDeclaration, + checker.indexInfoToIndexSignatureDeclaration( + indexInfoOfKind, + classDeclaration, + /*flags*/ undefined, + getNoopSymbolTrackerWithResolver(context), + )!, + ); } } // Either adds the node at the top of the class, or if there's a constructor right after that - function insertInterfaceMemberNode(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration, newElement: ClassElement): void { + function insertInterfaceMemberNode( + sourceFile: SourceFile, + cls: ClassLikeDeclaration | InterfaceDeclaration, + newElement: ClassElement, + ): void { if (constructor) { changeTracker.insertNodeAfter(sourceFile, constructor, newElement); } diff --git a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts index 02276f8d7a482..cf2d21b4c9012 100644 --- a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts +++ b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts @@ -33,7 +33,15 @@ registerCodeFix({ if (!nodes) return undefined; const { constructor, superCall } = nodes; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, constructor, superCall)); - return [createCodeFixAction(fixId, changes, Diagnostics.Make_super_call_the_first_statement_in_the_constructor, fixId, Diagnostics.Make_all_super_calls_the_first_statement_in_their_constructor)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Make_super_call_the_first_statement_in_the_constructor, + fixId, + Diagnostics.Make_all_super_calls_the_first_statement_in_their_constructor, + ), + ]; }, fixIds: [fixId], getAllCodeActions(context) { @@ -50,25 +58,35 @@ registerCodeFix({ }, }); -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, constructor: ConstructorDeclaration, superCall: ExpressionStatement): void { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + constructor: ConstructorDeclaration, + superCall: ExpressionStatement, +): void { changes.insertNodeAtConstructorStart(sourceFile, constructor, superCall); changes.delete(sourceFile, superCall); } -function getNodes(sourceFile: SourceFile, pos: number): { readonly constructor: ConstructorDeclaration, readonly superCall: ExpressionStatement } | undefined { +function getNodes( + sourceFile: SourceFile, + pos: number, +): { readonly constructor: ConstructorDeclaration; readonly superCall: ExpressionStatement; } | undefined { const token = getTokenAtPosition(sourceFile, pos); if (token.kind !== SyntaxKind.ThisKeyword) return undefined; const constructor = getContainingFunction(token) as ConstructorDeclaration; const superCall = findSuperCall(constructor.body!); // figure out if the `this` access is actually inside the supercall // i.e. super(this.a), since in that case we won't suggest a fix - return superCall && !superCall.expression.arguments.some(arg => isPropertyAccessExpression(arg) && arg.expression === token) ? { constructor, superCall } : undefined; + return superCall + && !superCall.expression.arguments.some(arg => isPropertyAccessExpression(arg) && arg.expression === token) + ? { constructor, superCall } : undefined; } -function findSuperCall(n: Node): ExpressionStatement & { expression: CallExpression } | undefined { +function findSuperCall(n: Node): ExpressionStatement & { expression: CallExpression; } | undefined { return isExpressionStatement(n) && isSuperCall(n.expression) - ? n as ExpressionStatement & { expression: CallExpression } + ? n as ExpressionStatement & { expression: CallExpression; } : isFunctionLike(n) - ? undefined - : forEachChild(n, findSuperCall); + ? undefined + : forEachChild(n, findSuperCall); } diff --git a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts index feee99da0d0cf..e4455024b3af8 100644 --- a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts +++ b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts @@ -23,11 +23,23 @@ registerCodeFix({ const { sourceFile, span } = context; const ctr = getNode(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, ctr)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_super_call, fixId, Diagnostics.Add_all_missing_super_calls)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_missing_super_call, + fixId, + Diagnostics.Add_all_missing_super_calls, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => - doChange(changes, context.sourceFile, getNode(diag.file, diag.start))), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => doChange(changes, context.sourceFile, getNode(diag.file, diag.start)), + ), }); function getNode(sourceFile: SourceFile, pos: number): ConstructorDeclaration { @@ -37,6 +49,8 @@ function getNode(sourceFile: SourceFile, pos: number): ConstructorDeclaration { } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, ctr: ConstructorDeclaration) { - const superCall = factory.createExpressionStatement(factory.createCallExpression(factory.createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray)); + const superCall = factory.createExpressionStatement( + factory.createCallExpression(factory.createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray), + ); changes.insertNodeAtConstructorStart(sourceFile, ctr, superCall); } diff --git a/src/services/codefixes/fixEnableJsxFlag.ts b/src/services/codefixes/fixEnableJsxFlag.ts index 4870e021120f7..daeae293dbf7c 100644 --- a/src/services/codefixes/fixEnableJsxFlag.ts +++ b/src/services/codefixes/fixEnableJsxFlag.ts @@ -21,11 +21,13 @@ registerCodeFix({ return undefined; } - const changes = textChanges.ChangeTracker.with(context, changeTracker => - doChange(changeTracker, configFile) - ); + const changes = textChanges.ChangeTracker.with(context, changeTracker => doChange(changeTracker, configFile)); return [ - createCodeFixActionWithoutFixAll(fixID, changes, Diagnostics.Enable_the_jsx_flag_in_your_configuration_file) + createCodeFixActionWithoutFixAll( + fixID, + changes, + Diagnostics.Enable_the_jsx_flag_in_your_configuration_file, + ), ]; }, fixIds: [fixID], @@ -37,7 +39,7 @@ registerCodeFix({ } doChange(changes, configFile); - }) + }), }); function doChange(changeTracker: textChanges.ChangeTracker, configFile: TsConfigSourceFile) { diff --git a/src/services/codefixes/fixExpectedComma.ts b/src/services/codefixes/fixExpectedComma.ts index ed571ab443352..c2cdca8f82288 100644 --- a/src/services/codefixes/fixExpectedComma.ts +++ b/src/services/codefixes/fixExpectedComma.ts @@ -33,25 +33,28 @@ registerCodeFix({ changes, [Diagnostics.Change_0_to_1, ";", ","], fixId, - [Diagnostics.Change_0_to_1, ";", ","] + [Diagnostics.Change_0_to_1, ";", ","], )]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, diag.start, diag.code); - if (info) doChange(changes, context.sourceFile, info); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, diag.start, diag.code); + if (info) doChange(changes, context.sourceFile, info); + }), }); -interface Info { readonly node: Node; } +interface Info { + readonly node: Node; +} function getInfo(sourceFile: SourceFile, pos: number, _: number): Info | undefined { const node = getTokenAtPosition(sourceFile, pos); - return (node.kind === SyntaxKind.SemicolonToken && - node.parent && - (isObjectLiteralExpression(node.parent) || - isArrayLiteralExpression(node.parent))) ? { node } : undefined; + return (node.kind === SyntaxKind.SemicolonToken + && node.parent + && (isObjectLiteralExpression(node.parent) + || isArrayLiteralExpression(node.parent))) ? { node } : undefined; } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { node }: Info): void { diff --git a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts index 7beffebd59986..3e32a9ac6c21e 100644 --- a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts +++ b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts @@ -25,14 +25,26 @@ registerCodeFix({ const nodes = getNodes(sourceFile, context.span.start); if (!nodes) return undefined; const { extendsToken, heritageClauses } = nodes; - const changes = textChanges.ChangeTracker.with(context, t => doChanges(t, sourceFile, extendsToken, heritageClauses)); - return [createCodeFixAction(fixId, changes, Diagnostics.Change_extends_to_implements, fixId, Diagnostics.Change_all_extended_interfaces_to_implements)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChanges(t, sourceFile, extendsToken, heritageClauses), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Change_extends_to_implements, + fixId, + Diagnostics.Change_all_extended_interfaces_to_implements, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const nodes = getNodes(diag.file, diag.start); - if (nodes) doChanges(changes, diag.file, nodes.extendsToken, nodes.heritageClauses); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const nodes = getNodes(diag.file, diag.start); + if (nodes) doChanges(changes, diag.file, nodes.extendsToken, nodes.heritageClauses); + }), }); function getNodes(sourceFile: SourceFile, pos: number) { @@ -42,17 +54,27 @@ function getNodes(sourceFile: SourceFile, pos: number) { return extendsToken.kind === SyntaxKind.ExtendsKeyword ? { extendsToken, heritageClauses } : undefined; } -function doChanges(changes: textChanges.ChangeTracker, sourceFile: SourceFile, extendsToken: Node, heritageClauses: readonly HeritageClause[]): void { +function doChanges( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + extendsToken: Node, + heritageClauses: readonly HeritageClause[], +): void { changes.replaceNode(sourceFile, extendsToken, factory.createToken(SyntaxKind.ImplementsKeyword)); // If there is already an implements clause, replace the implements keyword with a comma. - if (heritageClauses.length === 2 && - heritageClauses[0].token === SyntaxKind.ExtendsKeyword && - heritageClauses[1].token === SyntaxKind.ImplementsKeyword) { - + if ( + heritageClauses.length === 2 + && heritageClauses[0].token === SyntaxKind.ExtendsKeyword + && heritageClauses[1].token === SyntaxKind.ImplementsKeyword + ) { const implementsToken = heritageClauses[1].getFirstToken()!; const implementsFullStart = implementsToken.getFullStart(); - changes.replaceRange(sourceFile, { pos: implementsFullStart, end: implementsFullStart }, factory.createToken(SyntaxKind.CommaToken)); + changes.replaceRange( + sourceFile, + { pos: implementsFullStart, end: implementsFullStart }, + factory.createToken(SyntaxKind.CommaToken), + ); // Rough heuristic: delete trailing whitespace after keyword so that it's not excessive. // (Trailing because leading might be indentation, which is more sensitive.) diff --git a/src/services/codefixes/fixForgottenThisPropertyAccess.ts b/src/services/codefixes/fixForgottenThisPropertyAccess.ts index ae8d0cd294f0b..a26bf23f3c0fb 100644 --- a/src/services/codefixes/fixForgottenThisPropertyAccess.ts +++ b/src/services/codefixes/fixForgottenThisPropertyAccess.ts @@ -21,7 +21,9 @@ const fixId = "forgottenThisPropertyAccess"; const didYouMeanStaticMemberCode = Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0.code; const errorCodes = [ Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code, - Diagnostics.Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression.code, + Diagnostics + .Private_identifiers_are_only_allowed_in_class_bodies_and_may_only_be_used_as_part_of_a_class_member_declaration_property_access_or_on_the_left_hand_side_of_an_in_expression + .code, didYouMeanStaticMemberCode, ]; registerCodeFix({ @@ -33,13 +35,22 @@ registerCodeFix({ return undefined; } const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Add_0_to_unresolved_variable, info.className || "this"], fixId, Diagnostics.Add_qualifier_to_all_unresolved_variables_matching_a_member_name)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Add_0_to_unresolved_variable, info.className || "this"], + fixId, + Diagnostics.Add_qualifier_to_all_unresolved_variables_matching_a_member_name, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, diag.start, diag.code); - if (info) doChange(changes, context.sourceFile, info); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, diag.start, diag.code); + if (info) doChange(changes, context.sourceFile, info); + }), }); interface Info { @@ -50,12 +61,22 @@ interface Info { function getInfo(sourceFile: SourceFile, pos: number, diagCode: number): Info | undefined { const node = getTokenAtPosition(sourceFile, pos); if (isIdentifier(node) || isPrivateIdentifier(node)) { - return { node, className: diagCode === didYouMeanStaticMemberCode ? getContainingClass(node)!.name!.text : undefined }; + return { + node, + className: diagCode === didYouMeanStaticMemberCode ? getContainingClass(node)!.name!.text : undefined, + }; } } function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { node, className }: Info): void { // TODO (https://github.com/Microsoft/TypeScript/issues/21246): use shared helper suppressLeadingAndTrailingTrivia(node); - changes.replaceNode(sourceFile, node, factory.createPropertyAccessExpression(className ? factory.createIdentifier(className) : factory.createThis(), node)); + changes.replaceNode( + sourceFile, + node, + factory.createPropertyAccessExpression( + className ? factory.createIdentifier(className) : factory.createThis(), + node, + ), + ); } diff --git a/src/services/codefixes/fixImplicitThis.ts b/src/services/codefixes/fixImplicitThis.ts index 86c8adad40bd3..074d492b1c6e2 100644 --- a/src/services/codefixes/fixImplicitThis.ts +++ b/src/services/codefixes/fixImplicitThis.ts @@ -34,22 +34,32 @@ registerCodeFix({ const changes = textChanges.ChangeTracker.with(context, t => { diagnostic = doChange(t, sourceFile, span.start, program.getTypeChecker()); }); - return diagnostic ? [createCodeFixAction(fixId, changes, diagnostic, fixId, Diagnostics.Fix_all_implicit_this_errors)] : emptyArray; + return diagnostic + ? [createCodeFixAction(fixId, changes, diagnostic, fixId, Diagnostics.Fix_all_implicit_this_errors)] + : emptyArray; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - doChange(changes, diag.file, diag.start, context.program.getTypeChecker()); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + doChange(changes, diag.file, diag.start, context.program.getTypeChecker()); + }), }); -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, checker: TypeChecker): DiagnosticOrDiagnosticAndArguments | undefined { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + pos: number, + checker: TypeChecker, +): DiagnosticOrDiagnosticAndArguments | undefined { const token = getTokenAtPosition(sourceFile, pos); if (!isThis(token)) return undefined; const fn = getThisContainer(token, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); if (!isFunctionDeclaration(fn) && !isFunctionExpression(fn)) return undefined; - if (!isSourceFile(getThisContainer(fn, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false))) { // 'this' is defined outside, convert to arrow function + if ( + !isSourceFile(getThisContainer(fn, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false)) + ) { // 'this' is defined outside, convert to arrow function const fnKeyword = Debug.checkDefined(findChildOfKind(fn, SyntaxKind.FunctionKeyword, sourceFile)); const { name } = fn; const body = Debug.checkDefined(fn.body); // Should be defined because the function contained a 'this' expression diff --git a/src/services/codefixes/fixImportNonExportedMember.ts b/src/services/codefixes/fixImportNonExportedMember.ts index ba25afcbf5505..60f7a6a2c8576 100644 --- a/src/services/codefixes/fixImportNonExportedMember.ts +++ b/src/services/codefixes/fixImportNonExportedMember.ts @@ -53,7 +53,15 @@ registerCodeFix({ if (info === undefined) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, program, info)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Export_0_from_module_1, info.exportName.node.text, info.moduleSpecifier], fixId, Diagnostics.Export_all_referenced_locals)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Export_0_from_module_1, info.exportName.node.text, info.moduleSpecifier], + fixId, + Diagnostics.Export_all_referenced_locals, + ), + ]; }, getAllCodeActions(context) { const { program } = context; @@ -65,7 +73,10 @@ registerCodeFix({ if (info === undefined) return undefined; const { exportName, node, moduleSourceFile } = info; - if (tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly) === undefined && canHaveExportModifier(node)) { + if ( + tryGetExportDeclaration(moduleSourceFile, exportName.isTypeOnly) === undefined + && canHaveExportModifier(node) + ) { changes.insertExportModifier(moduleSourceFile, node); } else { @@ -84,14 +95,23 @@ registerCodeFix({ const exportDeclaration = tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ true); if (exportDeclaration && exportDeclaration.isTypeOnly) { doChanges(changes, program, moduleSourceFile, moduleExports.typeOnlyExports, exportDeclaration); - doChanges(changes, program, moduleSourceFile, moduleExports.exports, tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ false)); + doChanges( + changes, + program, + moduleSourceFile, + moduleExports.exports, + tryGetExportDeclaration(moduleSourceFile, /*isTypeOnly*/ false), + ); } else { - doChanges(changes, program, moduleSourceFile, [...moduleExports.exports, ...moduleExports.typeOnlyExports], exportDeclaration); + doChanges(changes, program, moduleSourceFile, [ + ...moduleExports.exports, + ...moduleExports.typeOnlyExports, + ], exportDeclaration); } }); })); - } + }, }); interface ModuleExports { @@ -117,7 +137,8 @@ function getInfo(sourceFile: SourceFile, pos: number, program: Program): Info | const importDeclaration = findAncestor(token, isImportDeclaration); if (importDeclaration === undefined) return undefined; - const moduleSpecifier = isStringLiteral(importDeclaration.moduleSpecifier) ? importDeclaration.moduleSpecifier.text : undefined; + const moduleSpecifier = isStringLiteral(importDeclaration.moduleSpecifier) + ? importDeclaration.moduleSpecifier.text : undefined; if (moduleSpecifier === undefined) return undefined; const resolvedModule = getResolvedModule(sourceFile, moduleSpecifier, /*mode*/ undefined); @@ -155,7 +176,13 @@ function doChange(changes: textChanges.ChangeTracker, program: Program, { export } } -function doChanges(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, moduleExports: ExportName[], node: ExportDeclaration | undefined) { +function doChanges( + changes: textChanges.ChangeTracker, + program: Program, + sourceFile: SourceFile, + moduleExports: ExportName[], + node: ExportDeclaration | undefined, +) { if (length(moduleExports)) { if (node) { updateExport(changes, program, sourceFile, node, moduleExports); @@ -172,23 +199,64 @@ function tryGetExportDeclaration(sourceFile: SourceFile, isTypeOnly: boolean) { return findLast(sourceFile.statements, predicate); } -function updateExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, node: ExportDeclaration, names: ExportName[]) { - const namedExports = node.exportClause && isNamedExports(node.exportClause) ? node.exportClause.elements : factory.createNodeArray([]); - const allowTypeModifier = !node.isTypeOnly && !!(getIsolatedModules(program.getCompilerOptions()) || find(namedExports, e => e.isTypeOnly)); - changes.replaceNode(sourceFile, node, - factory.updateExportDeclaration(node, node.modifiers, node.isTypeOnly, +function updateExport( + changes: textChanges.ChangeTracker, + program: Program, + sourceFile: SourceFile, + node: ExportDeclaration, + names: ExportName[], +) { + const namedExports = node.exportClause && isNamedExports(node.exportClause) ? node.exportClause.elements + : factory.createNodeArray([]); + const allowTypeModifier = !node.isTypeOnly + && !!(getIsolatedModules(program.getCompilerOptions()) || find(namedExports, e => e.isTypeOnly)); + changes.replaceNode( + sourceFile, + node, + factory.updateExportDeclaration( + node, + node.modifiers, + node.isTypeOnly, factory.createNamedExports( - factory.createNodeArray([...namedExports, ...createExportSpecifiers(names, allowTypeModifier)], /*hasTrailingComma*/ namedExports.hasTrailingComma)), node.moduleSpecifier, node.assertClause)); + factory.createNodeArray( + [...namedExports, ...createExportSpecifiers(names, allowTypeModifier)], + /*hasTrailingComma*/ namedExports.hasTrailingComma, + ), + ), + node.moduleSpecifier, + node.assertClause, + ), + ); } -function createExport(changes: textChanges.ChangeTracker, program: Program, sourceFile: SourceFile, names: ExportName[]) { - changes.insertNodeAtEndOfScope(sourceFile, sourceFile, - factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, - factory.createNamedExports(createExportSpecifiers(names, /*allowTypeModifier*/ getIsolatedModules(program.getCompilerOptions()))), /*moduleSpecifier*/ undefined, /*assertClause*/ undefined)); +function createExport( + changes: textChanges.ChangeTracker, + program: Program, + sourceFile: SourceFile, + names: ExportName[], +) { + changes.insertNodeAtEndOfScope( + sourceFile, + sourceFile, + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports( + createExportSpecifiers(names, /*allowTypeModifier*/ getIsolatedModules(program.getCompilerOptions())), + ), + /*moduleSpecifier*/ undefined, + /*assertClause*/ undefined, + ), + ); } function createExportSpecifiers(names: ExportName[], allowTypeModifier: boolean) { - return factory.createNodeArray(map(names, n => factory.createExportSpecifier(allowTypeModifier && n.isTypeOnly, /*propertyName*/ undefined, n.node))); + return factory.createNodeArray( + map( + names, + n => factory.createExportSpecifier(allowTypeModifier && n.isTypeOnly, /*propertyName*/ undefined, n.node), + ), + ); } function getNodeOfSymbol(symbol: Symbol) { @@ -196,6 +264,8 @@ function getNodeOfSymbol(symbol: Symbol) { return firstOrUndefined(symbol.declarations); } const declaration = symbol.valueDeclaration; - const variableStatement = isVariableDeclaration(declaration) ? tryCast(declaration.parent.parent, isVariableStatement) : undefined; - return variableStatement && length(variableStatement.declarationList.declarations) === 1 ? variableStatement : declaration; + const variableStatement = isVariableDeclaration(declaration) + ? tryCast(declaration.parent.parent, isVariableStatement) : undefined; + return variableStatement && length(variableStatement.declarationList.declarations) === 1 ? variableStatement + : declaration; } diff --git a/src/services/codefixes/fixIncorrectNamedTupleSyntax.ts b/src/services/codefixes/fixIncorrectNamedTupleSyntax.ts index f7e8345b217f0..756764758d724 100644 --- a/src/services/codefixes/fixIncorrectNamedTupleSyntax.ts +++ b/src/services/codefixes/fixIncorrectNamedTupleSyntax.ts @@ -18,8 +18,10 @@ import { const fixId = "fixIncorrectNamedTupleSyntax"; const errorCodes = [ - Diagnostics.A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type.code, - Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type.code + Diagnostics + .A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type + .code, + Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type.code, ]; registerCodeFix({ @@ -28,9 +30,17 @@ registerCodeFix({ const { sourceFile, span } = context; const namedTupleMember = getNamedTupleMember(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, namedTupleMember)); - return [createCodeFixAction(fixId, changes, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, fixId, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, + fixId, + Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, + ), + ]; }, - fixIds: [fixId] + fixIds: [fixId], }); function getNamedTupleMember(sourceFile: SourceFile, pos: number) { @@ -44,7 +54,10 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, na let unwrappedType = namedTupleMember.type; let sawOptional = false; let sawRest = false; - while (unwrappedType.kind === SyntaxKind.OptionalType || unwrappedType.kind === SyntaxKind.RestType || unwrappedType.kind === SyntaxKind.ParenthesizedType) { + while ( + unwrappedType.kind === SyntaxKind.OptionalType || unwrappedType.kind === SyntaxKind.RestType + || unwrappedType.kind === SyntaxKind.ParenthesizedType + ) { if (unwrappedType.kind === SyntaxKind.OptionalType) { sawOptional = true; } @@ -58,7 +71,7 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, na namedTupleMember.dotDotDotToken || (sawRest ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined), namedTupleMember.name, namedTupleMember.questionToken || (sawOptional ? factory.createToken(SyntaxKind.QuestionToken) : undefined), - unwrappedType + unwrappedType, ); if (updated === namedTupleMember) { return; diff --git a/src/services/codefixes/fixInvalidImportSyntax.ts b/src/services/codefixes/fixInvalidImportSyntax.ts index bae3f2d2c0f16..b594cf19ac48d 100644 --- a/src/services/codefixes/fixInvalidImportSyntax.ts +++ b/src/services/codefixes/fixInvalidImportSyntax.ts @@ -39,16 +39,33 @@ function getCodeFixesForImportDeclaration(context: CodeFixContext, node: ImportD const variations: CodeFixAction[] = []; // import Bluebird from "bluebird"; - variations.push(createAction(context, sourceFile, node, makeImport(namespace.name, /*namedImports*/ undefined, node.moduleSpecifier, getQuotePreference(sourceFile, context.preferences)))); + variations.push( + createAction( + context, + sourceFile, + node, + makeImport( + namespace.name, + /*namedImports*/ undefined, + node.moduleSpecifier, + getQuotePreference(sourceFile, context.preferences), + ), + ), + ); if (getEmitModuleKind(opts) === ModuleKind.CommonJS) { // import Bluebird = require("bluebird"); - variations.push(createAction(context, sourceFile, node, factory.createImportEqualsDeclaration( - /*modifiers*/ undefined, - /*isTypeOnly*/ false, - namespace.name, - factory.createExternalModuleReference(node.moduleSpecifier) - ))); + variations.push(createAction( + context, + sourceFile, + node, + factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + namespace.name, + factory.createExternalModuleReference(node.moduleSpecifier), + ), + )); } return variations; @@ -56,7 +73,10 @@ function getCodeFixesForImportDeclaration(context: CodeFixContext, node: ImportD function createAction(context: CodeFixContext, sourceFile: SourceFile, node: Node, replacement: Node): CodeFixAction { const changes = textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, node, replacement)); - return createCodeFixActionWithoutFixAll(fixName, changes, [Diagnostics.Replace_import_with_0, changes[0].textChanges[0].newText]); + return createCodeFixActionWithoutFixAll(fixName, changes, [ + Diagnostics.Replace_import_with_0, + changes[0].textChanges[0].newText, + ]); } registerCodeFix({ @@ -64,13 +84,16 @@ registerCodeFix({ Diagnostics.This_expression_is_not_callable.code, Diagnostics.This_expression_is_not_constructable.code, ], - getCodeActions: getActionsForUsageOfInvalidImport + getCodeActions: getActionsForUsageOfInvalidImport, }); function getActionsForUsageOfInvalidImport(context: CodeFixContext): CodeFixAction[] | undefined { const sourceFile = context.sourceFile; - const targetKind = Diagnostics.This_expression_is_not_callable.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression; - const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind) as CallExpression | NewExpression; + const targetKind = Diagnostics.This_expression_is_not_callable.code === context.errorCode + ? SyntaxKind.CallExpression : SyntaxKind.NewExpression; + const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind) as + | CallExpression + | NewExpression; if (!node) { return []; } @@ -84,7 +107,8 @@ registerCodeFix({ Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code, Diagnostics.Type_0_does_not_satisfy_the_constraint_1.code, Diagnostics.Type_0_is_not_assignable_to_type_1.code, - Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated.code, + Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated + .code, Diagnostics.Type_predicate_0_is_not_assignable_to_1.code, Diagnostics.Property_0_of_type_1_is_not_assignable_to_2_index_type_3.code, Diagnostics._0_index_type_1_is_not_assignable_to_2_index_type_3.code, @@ -93,12 +117,15 @@ registerCodeFix({ Diagnostics.Property_0_of_JSX_spread_attribute_is_not_assignable_to_target_property.code, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1.code, ], - getCodeActions: getActionsForInvalidImportLocation + getCodeActions: getActionsForInvalidImportLocation, }); function getActionsForInvalidImportLocation(context: CodeFixContext): CodeFixAction[] | undefined { const sourceFile = context.sourceFile; - const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)); + const node = findAncestor( + getTokenAtPosition(sourceFile, context.span.start), + a => a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length), + ); if (!node) { return []; } @@ -117,7 +144,10 @@ function getImportCodeFixesForExpression(context: CodeFixContext, expr: Node): C } if (isExpression(expr) && !(isNamedDeclaration(expr.parent) && expr.parent.name === expr)) { const sourceFile = context.sourceFile; - const changes = textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, expr, factory.createPropertyAccessExpression(expr, "default"), {})); + const changes = textChanges.ChangeTracker.with( + context, + t => t.replaceNode(sourceFile, expr, factory.createPropertyAccessExpression(expr, "default"), {}), + ); fixes.push(createCodeFixActionWithoutFixAll(fixName, changes, Diagnostics.Use_synthetic_default_member)); } return fixes; diff --git a/src/services/codefixes/fixInvalidJsxCharacters.ts b/src/services/codefixes/fixInvalidJsxCharacters.ts index aea34c0c42cef..23e069ddb571a 100644 --- a/src/services/codefixes/fixInvalidJsxCharacters.ts +++ b/src/services/codefixes/fixInvalidJsxCharacters.ts @@ -17,7 +17,7 @@ const fixIdHtmlEntity = "fixInvalidJsxCharacters_htmlEntity"; const errorCodes = [ Diagnostics.Unexpected_token_Did_you_mean_or_gt.code, - Diagnostics.Unexpected_token_Did_you_mean_or_rbrace.code + Diagnostics.Unexpected_token_Did_you_mean_or_rbrace.code, ]; registerCodeFix({ @@ -25,17 +25,46 @@ registerCodeFix({ fixIds: [fixIdExpression, fixIdHtmlEntity], getCodeActions(context) { const { sourceFile, preferences, span } = context; - const changeToExpression = textChanges.ChangeTracker.with(context, t => doChange(t, preferences, sourceFile, span.start, /*useHtmlEntity*/ false)); - const changeToHtmlEntity = textChanges.ChangeTracker.with(context, t => doChange(t, preferences, sourceFile, span.start, /*useHtmlEntity*/ true)); + const changeToExpression = textChanges.ChangeTracker.with( + context, + t => doChange(t, preferences, sourceFile, span.start, /*useHtmlEntity*/ false), + ); + const changeToHtmlEntity = textChanges.ChangeTracker.with( + context, + t => doChange(t, preferences, sourceFile, span.start, /*useHtmlEntity*/ true), + ); return [ - createCodeFixAction(fixIdExpression, changeToExpression, Diagnostics.Wrap_invalid_character_in_an_expression_container, fixIdExpression, Diagnostics.Wrap_all_invalid_characters_in_an_expression_container), - createCodeFixAction(fixIdHtmlEntity, changeToHtmlEntity, Diagnostics.Convert_invalid_character_to_its_html_entity_code, fixIdHtmlEntity, Diagnostics.Convert_all_invalid_characters_to_HTML_entity_code) + createCodeFixAction( + fixIdExpression, + changeToExpression, + Diagnostics.Wrap_invalid_character_in_an_expression_container, + fixIdExpression, + Diagnostics.Wrap_all_invalid_characters_in_an_expression_container, + ), + createCodeFixAction( + fixIdHtmlEntity, + changeToHtmlEntity, + Diagnostics.Convert_invalid_character_to_its_html_entity_code, + fixIdHtmlEntity, + Diagnostics.Convert_all_invalid_characters_to_HTML_entity_code, + ), ]; }, getAllCodeActions(context) { - return codeFixAll(context, errorCodes, (changes, diagnostic) => doChange(changes, context.preferences, diagnostic.file, diagnostic.start, context.fixId === fixIdHtmlEntity)); - } + return codeFixAll( + context, + errorCodes, + (changes, diagnostic) => + doChange( + changes, + context.preferences, + diagnostic.file, + diagnostic.start, + context.fixId === fixIdHtmlEntity, + ), + ); + }, }); const htmlEntity = { @@ -47,7 +76,13 @@ function isValidCharacter(character: string): character is keyof typeof htmlEnti return hasProperty(htmlEntity, character); } -function doChange(changes: textChanges.ChangeTracker, preferences: UserPreferences, sourceFile: SourceFile, start: number, useHtmlEntity: boolean) { +function doChange( + changes: textChanges.ChangeTracker, + preferences: UserPreferences, + sourceFile: SourceFile, + start: number, + useHtmlEntity: boolean, +) { const character = sourceFile.getText()[start]; // sanity check if (!isValidCharacter(character)) { diff --git a/src/services/codefixes/fixJSDocTypes.ts b/src/services/codefixes/fixJSDocTypes.ts index 3a50e7579675c..bcce48826074a 100644 --- a/src/services/codefixes/fixJSDocTypes.ts +++ b/src/services/codefixes/fixJSDocTypes.ts @@ -58,13 +58,28 @@ registerCodeFix({ if (typeNode.kind === SyntaxKind.JSDocNullableType) { // for nullable types, suggest the flow-compatible `T | null | undefined` // in addition to the jsdoc/closure-compatible `T | null` - actions.push(fix(type, fixIdNullable, Diagnostics.Change_all_jsdoc_style_types_to_TypeScript_and_add_undefined_to_nullable_types)); + actions.push( + fix( + type, + fixIdNullable, + Diagnostics.Change_all_jsdoc_style_types_to_TypeScript_and_add_undefined_to_nullable_types, + ), + ); } return actions; function fix(type: Type, fixId: string, fixAllDescription: DiagnosticMessage): CodeFixAction { - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, typeNode, type, checker)); - return createCodeFixAction("jdocTypes", changes, [Diagnostics.Change_0_to_1, original, checker.typeToString(type)], fixId, fixAllDescription); + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, typeNode, type, checker), + ); + return createCodeFixAction( + "jdocTypes", + changes, + [Diagnostics.Change_0_to_1, original, checker.typeToString(type)], + fixId, + fixAllDescription, + ); } }, fixIds: [fixIdPlain, fixIdNullable], @@ -75,17 +90,32 @@ registerCodeFix({ const info = getInfo(err.file, err.start, checker); if (!info) return; const { typeNode, type } = info; - const fixedType = typeNode.kind === SyntaxKind.JSDocNullableType && fixId === fixIdNullable ? checker.getNullableType(type, TypeFlags.Undefined) : type; + const fixedType = typeNode.kind === SyntaxKind.JSDocNullableType && fixId === fixIdNullable + ? checker.getNullableType(type, TypeFlags.Undefined) : type; doChange(changes, sourceFile, typeNode, fixedType, checker); }); - } + }, }); -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, oldTypeNode: TypeNode, newType: Type, checker: TypeChecker): void { - changes.replaceNode(sourceFile, oldTypeNode, checker.typeToTypeNode(newType, /*enclosingDeclaration*/ oldTypeNode, /*flags*/ undefined)!); // TODO: GH#18217 +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + oldTypeNode: TypeNode, + newType: Type, + checker: TypeChecker, +): void { + changes.replaceNode( + sourceFile, + oldTypeNode, + checker.typeToTypeNode(newType, /*enclosingDeclaration*/ oldTypeNode, /*flags*/ undefined)!, + ); // TODO: GH#18217 } -function getInfo(sourceFile: SourceFile, pos: number, checker: TypeChecker): { readonly typeNode: TypeNode, readonly type: Type } | undefined { +function getInfo( + sourceFile: SourceFile, + pos: number, + checker: TypeChecker, +): { readonly typeNode: TypeNode; readonly type: Type; } | undefined { const decl = findAncestor(getTokenAtPosition(sourceFile, pos), isTypeContainer); const typeNode = decl && decl.type; return typeNode && { typeNode, type: getType(checker, typeNode) }; @@ -93,10 +123,22 @@ function getInfo(sourceFile: SourceFile, pos: number, checker: TypeChecker): { r // TODO: GH#19856 Node & { type: TypeNode } type TypeContainer = - | AsExpression | CallSignatureDeclaration | ConstructSignatureDeclaration | FunctionDeclaration - | GetAccessorDeclaration | IndexSignatureDeclaration | MappedTypeNode | MethodDeclaration - | MethodSignature | ParameterDeclaration | PropertyDeclaration | PropertySignature | SetAccessorDeclaration - | TypeAliasDeclaration | TypeAssertion | VariableDeclaration; + | AsExpression + | CallSignatureDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration + | GetAccessorDeclaration + | IndexSignatureDeclaration + | MappedTypeNode + | MethodDeclaration + | MethodSignature + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature + | SetAccessorDeclaration + | TypeAliasDeclaration + | TypeAssertion + | VariableDeclaration; function isTypeContainer(node: Node): node is TypeContainer { // NOTE: Some locations are not handled yet: // MappedTypeNode.typeParameters and SignatureDeclaration.typeParameters, as well as CallExpression.typeArguments @@ -130,7 +172,8 @@ function getType(checker: TypeChecker, node: TypeNode) { return type; } return checker.getUnionType( - append([type, checker.getUndefinedType()], node.postfix ? undefined : checker.getNullType())); + append([type, checker.getUndefinedType()], node.postfix ? undefined : checker.getNullType()), + ); } return checker.getTypeFromTypeNode(node); } diff --git a/src/services/codefixes/fixMissingCallParentheses.ts b/src/services/codefixes/fixMissingCallParentheses.ts index 4fcc89c87fcc0..3cb9a2f0246fb 100644 --- a/src/services/codefixes/fixMissingCallParentheses.ts +++ b/src/services/codefixes/fixMissingCallParentheses.ts @@ -17,7 +17,9 @@ import { const fixId = "fixMissingCallParentheses"; const errorCodes = [ - Diagnostics.This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead.code, + Diagnostics + .This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead + .code, ]; registerCodeFix({ @@ -29,16 +31,29 @@ registerCodeFix({ if (!callName) return; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, callName)); - return [createCodeFixAction(fixId, changes, Diagnostics.Add_missing_call_parentheses, fixId, Diagnostics.Add_all_missing_call_parentheses)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Add_missing_call_parentheses, + fixId, + Diagnostics.Add_all_missing_call_parentheses, + ), + ]; }, - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const callName = getCallName(diag.file, diag.start); - if (callName) doChange(changes, diag.file, callName); - }) + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const callName = getCallName(diag.file, diag.start); + if (callName) doChange(changes, diag.file, callName); + }), }); -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, name: Identifier | PrivateIdentifier): void { - changes.replaceNodeWithText(sourceFile, name, `${ name.text }()`); +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + name: Identifier | PrivateIdentifier, +): void { + changes.replaceNodeWithText(sourceFile, name, `${name.text}()`); } function getCallName(sourceFile: SourceFile, start: number): Identifier | PrivateIdentifier | undefined { diff --git a/src/services/codefixes/fixModuleAndTargetOptions.ts b/src/services/codefixes/fixModuleAndTargetOptions.ts index 0cc3e489ab25d..a6028ae07ae9d 100644 --- a/src/services/codefixes/fixModuleAndTargetOptions.ts +++ b/src/services/codefixes/fixModuleAndTargetOptions.ts @@ -19,9 +19,15 @@ import { registerCodeFix({ errorCodes: [ - Diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher.code, - Diagnostics.Top_level_await_using_statements_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher.code, - Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher.code, + Diagnostics + .Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher + .code, + Diagnostics + .Top_level_await_using_statements_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher + .code, + Diagnostics + .Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_or_nodenext_and_the_target_option_is_set_to_es2017_or_higher + .code, ], getCodeActions: function getCodeActionsToFixModuleAndTarget(context) { const compilerOptions = context.program.getCompilerOptions(); @@ -37,7 +43,12 @@ registerCodeFix({ const changes = textChanges.ChangeTracker.with(context, changes => { setJsonCompilerOptionValue(changes, configFile, "module", factory.createStringLiteral("esnext")); }); - codeFixes.push(createCodeFixActionWithoutFixAll("fixModuleOption", changes, [Diagnostics.Set_the_module_option_in_your_configuration_file_to_0, "esnext"])); + codeFixes.push( + createCodeFixActionWithoutFixAll("fixModuleOption", changes, [ + Diagnostics.Set_the_module_option_in_your_configuration_file_to_0, + "esnext", + ]), + ); } const target = getEmitScriptTarget(compilerOptions); @@ -56,9 +67,14 @@ registerCodeFix({ setJsonCompilerOptionValues(tracker, configFile, options); }); - codeFixes.push(createCodeFixActionWithoutFixAll("fixTargetOption", changes, [Diagnostics.Set_the_target_option_in_your_configuration_file_to_0, "es2017"])); + codeFixes.push( + createCodeFixActionWithoutFixAll("fixTargetOption", changes, [ + Diagnostics.Set_the_target_option_in_your_configuration_file_to_0, + "es2017", + ]), + ); } return codeFixes.length ? codeFixes : undefined; - } + }, }); diff --git a/src/services/codefixes/fixNaNEquality.ts b/src/services/codefixes/fixNaNEquality.ts index 4370bd0d1c584..5ace1965a2ebc 100644 --- a/src/services/codefixes/fixNaNEquality.ts +++ b/src/services/codefixes/fixNaNEquality.ts @@ -36,7 +36,15 @@ registerCodeFix({ const { suggestion, expression, arg } = info; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, arg, expression)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Use_0, suggestion], fixId, Diagnostics.Use_Number_isNaN_in_all_conditions)]; + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Use_0, suggestion], + fixId, + Diagnostics.Use_Number_isNaN_in_all_conditions, + ), + ]; }, fixIds: [fixId], getAllCodeActions: context => { @@ -46,7 +54,7 @@ registerCodeFix({ doChange(changes, diag.file, info.arg, info.expression); } }); - } + }, }); interface Info { @@ -56,11 +64,17 @@ interface Info { } function getInfo(program: Program, sourceFile: SourceFile, span: TextSpan): Info | undefined { - const diag = find(program.getSemanticDiagnostics(sourceFile), diag => diag.start === span.start && diag.length === span.length); + const diag = find( + program.getSemanticDiagnostics(sourceFile), + diag => diag.start === span.start && diag.length === span.length, + ); if (diag === undefined || diag.relatedInformation === undefined) return; const related = find(diag.relatedInformation, related => related.code === Diagnostics.Did_you_mean_0.code); - if (related === undefined || related.file === undefined || related.start === undefined || related.length === undefined) return; + if ( + related === undefined || related.file === undefined || related.start === undefined + || related.length === undefined + ) return; const token = findAncestorMatchingSpan(related.file, createTextSpan(related.start, related.length)); if (token === undefined) return; @@ -71,13 +85,24 @@ function getInfo(program: Program, sourceFile: SourceFile, span: TextSpan): Info return undefined; } -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, arg: Expression, expression: BinaryExpression) { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + arg: Expression, + expression: BinaryExpression, +) { const callExpression = factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier("Number"), factory.createIdentifier("isNaN")), /*typeArguments*/ undefined, [arg]); - const operator = expression.operatorToken.kind ; - changes.replaceNode(sourceFile, expression, + factory.createPropertyAccessExpression(factory.createIdentifier("Number"), factory.createIdentifier("isNaN")), + /*typeArguments*/ undefined, + [arg], + ); + const operator = expression.operatorToken.kind; + changes.replaceNode( + sourceFile, + expression, operator === SyntaxKind.ExclamationEqualsEqualsToken || operator === SyntaxKind.ExclamationEqualsToken - ? factory.createPrefixUnaryExpression(SyntaxKind.ExclamationToken, callExpression) : callExpression); + ? factory.createPrefixUnaryExpression(SyntaxKind.ExclamationToken, callExpression) : callExpression, + ); } function getSuggestion(messageText: string | DiagnosticMessageChain) { diff --git a/src/services/codefixes/fixNoPropertyAccessFromIndexSignature.ts b/src/services/codefixes/fixNoPropertyAccessFromIndexSignature.ts index 7a35126032924..9abe666cd2d63 100644 --- a/src/services/codefixes/fixNoPropertyAccessFromIndexSignature.ts +++ b/src/services/codefixes/fixNoPropertyAccessFromIndexSignature.ts @@ -20,7 +20,7 @@ import { const fixId = "fixNoPropertyAccessFromIndexSignature"; const errorCodes = [ - Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0.code + Diagnostics.Property_0_comes_from_an_index_signature_so_it_must_be_accessed_with_0.code, ]; registerCodeFix({ @@ -29,22 +29,43 @@ registerCodeFix({ getCodeActions(context) { const { sourceFile, span, preferences } = context; const property = getPropertyAccessExpression(sourceFile, span.start); - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, property, preferences)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Use_element_access_for_0, property.name.text], fixId, Diagnostics.Use_element_access_for_all_undeclared_properties)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, context.sourceFile, property, preferences), + ); + return [ + createCodeFixAction( + fixId, + changes, + [Diagnostics.Use_element_access_for_0, property.name.text], + fixId, + Diagnostics.Use_element_access_for_all_undeclared_properties, + ), + ]; }, getAllCodeActions: context => - codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, getPropertyAccessExpression(diag.file, diag.start), context.preferences)) + codeFixAll( + context, + errorCodes, + (changes, diag) => + doChange(changes, diag.file, getPropertyAccessExpression(diag.file, diag.start), context.preferences), + ), }); -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: PropertyAccessExpression, preferences: UserPreferences): void { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: PropertyAccessExpression, + preferences: UserPreferences, +): void { const quotePreference = getQuotePreference(sourceFile, preferences); const argumentsExpression = factory.createStringLiteral(node.name.text, quotePreference === QuotePreference.Single); changes.replaceNode( sourceFile, node, - isPropertyAccessChain(node) ? - factory.createElementAccessChain(node.expression, node.questionDotToken, argumentsExpression) : - factory.createElementAccessExpression(node.expression, argumentsExpression) + isPropertyAccessChain(node) + ? factory.createElementAccessChain(node.expression, node.questionDotToken, argumentsExpression) + : factory.createElementAccessExpression(node.expression, argumentsExpression), ); } diff --git a/src/services/codefixes/fixOverrideModifier.ts b/src/services/codefixes/fixOverrideModifier.ts index f76a8420e0699..879f50ab1f4fb 100644 --- a/src/services/codefixes/fixOverrideModifier.ts +++ b/src/services/codefixes/fixOverrideModifier.ts @@ -52,14 +52,26 @@ type ClassElementLikeHasJSDoc = const errorCodes = [ Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0.code, - Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code, - Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code, + Diagnostics + .This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code, + Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0 + .code, Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code, - Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code, - Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code, - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class.code, - Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code, - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0.code, + Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 + .code, + Diagnostics + .This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code, + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + .code, + Diagnostics + .This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code, + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + .code, ]; interface ErrorCodeFixInfo { @@ -75,35 +87,58 @@ const errorCodeFixIdMap: Record = { fixId: fixAddOverrideId, fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, }, - [Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code]: { + [ + Diagnostics + .This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code + ]: { descriptions: Diagnostics.Add_override_modifier, fixId: fixAddOverrideId, - fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers + fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, }, // case #2: - [Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code]: { + [ + Diagnostics + .This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class + .code + ]: { descriptions: Diagnostics.Remove_override_modifier, fixId: fixRemoveOverrideId, fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, }, - [Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class.code]: { + [ + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + .code + ]: { descriptions: Diagnostics.Remove_override_modifier, fixId: fixRemoveOverrideId, - fixAllDescriptions: Diagnostics.Remove_override_modifier + fixAllDescriptions: Diagnostics.Remove_override_modifier, }, // case #3: - [Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code]: { + [ + Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 + .code + ]: { descriptions: Diagnostics.Add_override_modifier, fixId: fixAddOverrideId, fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, }, - [Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code]: { + [ + Diagnostics + .This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code + ]: { descriptions: Diagnostics.Add_override_modifier, fixId: fixAddOverrideId, fixAllDescriptions: Diagnostics.Add_all_missing_override_modifiers, }, // case #4: - [Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code]: { + [ + Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0 + .code + ]: { descriptions: Diagnostics.Add_override_modifier, fixId: fixAddOverrideId, fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, @@ -114,11 +149,15 @@ const errorCodeFixIdMap: Record = { fixId: fixRemoveOverrideId, fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, }, - [Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0.code]: { + [ + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + .code + ]: { descriptions: Diagnostics.Remove_override_modifier, fixId: fixRemoveOverrideId, fixAllDescriptions: Diagnostics.Remove_all_unnecessary_override_modifiers, - } + }, }; registerCodeFix({ @@ -130,10 +169,13 @@ registerCodeFix({ if (!info) return emptyArray; const { descriptions, fixId, fixAllDescriptions } = info; - const changes = textChanges.ChangeTracker.with(context, changes => dispatchChanges(changes, context, errorCode, span.start)); + const changes = textChanges.ChangeTracker.with( + context, + changes => dispatchChanges(changes, context, errorCode, span.start), + ); return [ - createCodeFixActionMaybeFixAll(fixName, changes, descriptions, fixId, fixAllDescriptions) + createCodeFixActionMaybeFixAll(fixName, changes, descriptions, fixId, fixAllDescriptions), ]; }, fixIds: [fixName, fixAddOverrideId, fixRemoveOverrideId], @@ -146,25 +188,41 @@ registerCodeFix({ } dispatchChanges(changes, context, code, start); - }) + }), }); function dispatchChanges( changeTracker: textChanges.ChangeTracker, context: CodeFixContext | CodeFixAllContext, errorCode: number, - pos: number) { + pos: number, +) { switch (errorCode) { - case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code: - case Diagnostics.This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code: - case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code: - case Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code: - case Diagnostics.This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0.code: + case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0 + .code: + case Diagnostics + .This_member_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code: + case Diagnostics + .This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0 + .code: + case Diagnostics + .This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code: + case Diagnostics + .This_parameter_property_must_have_a_JSDoc_comment_with_an_override_tag_because_it_overrides_a_member_in_the_base_class_0 + .code: return doAddOverrideModifierChange(changeTracker, context.sourceFile, pos); - case Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0.code: - case Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0.code: - case Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code: - case Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class.code: + case Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0 + .code: + case Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0 + .code: + case Diagnostics + .This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class + .code: + case Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_its_containing_class_0_does_not_extend_another_class + .code: return doRemoveOverrideModifierChange(changeTracker, context.sourceFile, pos); default: Debug.fail("Unexpected error code: " + errorCode); @@ -174,7 +232,9 @@ function dispatchChanges( function doAddOverrideModifierChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { const classElement = findContainerClassElementLike(sourceFile, pos); if (isSourceFileJS(sourceFile)) { - changeTracker.addJSDocTags(sourceFile, classElement, [factory.createJSDocOverrideTag(factory.createIdentifier("override"))]); + changeTracker.addJSDocTags(sourceFile, classElement, [ + factory.createJSDocOverrideTag(factory.createIdentifier("override")), + ]); return; } const modifiers = classElement.modifiers || emptyArray; @@ -182,10 +242,10 @@ function doAddOverrideModifierChange(changeTracker: textChanges.ChangeTracker, s const abstractModifier = find(modifiers, isAbstractModifier); const accessibilityModifier = find(modifiers, m => isAccessibilityModifier(m.kind)); const lastDecorator = findLast(modifiers, isDecorator); - const modifierPos = abstractModifier ? abstractModifier.end : - staticModifier ? staticModifier.end : - accessibilityModifier ? accessibilityModifier.end : - lastDecorator ? skipTrivia(sourceFile.text, lastDecorator.end) : classElement.getStart(sourceFile); + const modifierPos = abstractModifier ? abstractModifier.end + : staticModifier ? staticModifier.end + : accessibilityModifier ? accessibilityModifier.end + : lastDecorator ? skipTrivia(sourceFile.text, lastDecorator.end) : classElement.getStart(sourceFile); const options = accessibilityModifier || staticModifier || abstractModifier ? { prefix: " " } : { suffix: " " }; changeTracker.insertModifierAt(sourceFile, modifierPos, SyntaxKind.OverrideKeyword, options); } @@ -227,4 +287,3 @@ function findContainerClassElementLike(sourceFile: SourceFile, pos: number) { Debug.assert(classElement && isClassElementLikeHasJSDoc(classElement)); return classElement; } - diff --git a/src/services/codefixes/fixPropertyAssignment.ts b/src/services/codefixes/fixPropertyAssignment.ts index 2f1ef5a198044..2a328759f7a8f 100644 --- a/src/services/codefixes/fixPropertyAssignment.ts +++ b/src/services/codefixes/fixPropertyAssignment.ts @@ -17,7 +17,9 @@ import { const fixId = "fixPropertyAssignment"; const errorCodes = [ - Diagnostics.Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern.code + Diagnostics + .Did_you_mean_to_use_a_Colon_An_can_only_follow_a_property_name_when_the_containing_object_literal_is_part_of_a_destructuring_pattern + .code, ]; registerCodeFix({ @@ -27,14 +29,28 @@ registerCodeFix({ const { sourceFile, span } = context; const property = getProperty(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, property)); - return [createCodeFixAction(fixId, changes, [Diagnostics.Change_0_to_1, "=", ":"], fixId, [Diagnostics.Switch_each_misused_0_to_1, "=", ":"])]; + return [ + createCodeFixAction(fixId, changes, [Diagnostics.Change_0_to_1, "=", ":"], fixId, [ + Diagnostics.Switch_each_misused_0_to_1, + "=", + ":", + ]), + ]; }, getAllCodeActions: context => - codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, getProperty(diag.file, diag.start))) + codeFixAll( + context, + errorCodes, + (changes, diag) => doChange(changes, diag.file, getProperty(diag.file, diag.start)), + ), }); function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: ShorthandPropertyAssignment): void { - changes.replaceNode(sourceFile, node, factory.createPropertyAssignment(node.name, node.objectAssignmentInitializer as Expression)); + changes.replaceNode( + sourceFile, + node, + factory.createPropertyAssignment(node.name, node.objectAssignmentInitializer as Expression), + ); } function getProperty(sourceFile: SourceFile, pos: number): ShorthandPropertyAssignment { diff --git a/src/services/codefixes/fixPropertyOverrideAccessor.ts b/src/services/codefixes/fixPropertyOverrideAccessor.ts index 954a90ba6f34a..632aaf842ca41 100644 --- a/src/services/codefixes/fixPropertyOverrideAccessor.ts +++ b/src/services/codefixes/fixPropertyOverrideAccessor.ts @@ -30,29 +30,50 @@ registerCodeFix({ getCodeActions(context) { const edits = doChange(context.sourceFile, context.span.start, context.span.length, context.errorCode, context); if (edits) { - return [createCodeFixAction(fixId, edits, Diagnostics.Generate_get_and_set_accessors, fixId, Diagnostics.Generate_get_and_set_accessors_for_all_overriding_properties)]; + return [ + createCodeFixAction( + fixId, + edits, + Diagnostics.Generate_get_and_set_accessors, + fixId, + Diagnostics.Generate_get_and_set_accessors_for_all_overriding_properties, + ), + ]; } }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const edits = doChange(diag.file, diag.start, diag.length, diag.code, context); - if (edits) { - for (const edit of edits) { - changes.pushRaw(context.sourceFile, edit); + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const edits = doChange(diag.file, diag.start, diag.length, diag.code, context); + if (edits) { + for (const edit of edits) { + changes.pushRaw(context.sourceFile, edit); + } } - } - }), + }), }); -function doChange(file: SourceFile, start: number, length: number, code: number, context: CodeFixContext | CodeFixAllContext) { +function doChange( + file: SourceFile, + start: number, + length: number, + code: number, + context: CodeFixContext | CodeFixAllContext, +) { let startPosition: number; let endPosition: number; - if (code === Diagnostics._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property.code) { + if ( + code + === Diagnostics._0_is_defined_as_an_accessor_in_class_1_but_is_overridden_here_in_2_as_an_instance_property + .code + ) { startPosition = start; endPosition = start + length; } - else if (code === Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor.code) { + else if ( + code === Diagnostics._0_is_defined_as_a_property_in_class_1_but_is_overridden_here_in_2_as_an_accessor.code + ) { const checker = context.program.getTypeChecker(); const node = getTokenAtPosition(file, start).parent; Debug.assert(isAccessor(node), "error span of fixPropertyOverrideAccessor should only be on an accessor"); @@ -72,5 +93,12 @@ function doChange(file: SourceFile, start: number, length: number, code: number, else { Debug.fail("fixPropertyOverrideAccessor codefix got unexpected error code " + code); } - return generateAccessorFromProperty(file, context.program, startPosition, endPosition, context, Diagnostics.Generate_get_and_set_accessors.message); + return generateAccessorFromProperty( + file, + context.program, + startPosition, + endPosition, + context, + Diagnostics.Generate_get_and_set_accessors.message, + ); } diff --git a/src/services/codefixes/fixReturnTypeInAsyncFunction.ts b/src/services/codefixes/fixReturnTypeInAsyncFunction.ts index a7071d6e143f4..0464810e56634 100644 --- a/src/services/codefixes/fixReturnTypeInAsyncFunction.ts +++ b/src/services/codefixes/fixReturnTypeInAsyncFunction.ts @@ -19,7 +19,9 @@ import { const fixId = "fixReturnTypeInAsyncFunction"; const errorCodes = [ - Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0.code, + Diagnostics + .The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type_Did_you_mean_to_write_Promise_0 + .code, ]; interface Info { @@ -40,19 +42,29 @@ registerCodeFix({ return undefined; } const { returnTypeNode, returnType, promisedTypeNode, promisedType } = info; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, returnTypeNode, promisedTypeNode)); + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, returnTypeNode, promisedTypeNode), + ); return [createCodeFixAction( - fixId, changes, - [Diagnostics.Replace_0_with_Promise_1, - checker.typeToString(returnType), checker.typeToString(promisedType)], - fixId, Diagnostics.Fix_all_incorrect_return_type_of_an_async_functions)]; + fixId, + changes, + [ + Diagnostics.Replace_0_with_Promise_1, + checker.typeToString(returnType), + checker.typeToString(promisedType), + ], + fixId, + Diagnostics.Fix_all_incorrect_return_type_of_an_async_functions, + )]; }, - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, context.program.getTypeChecker(), diag.start); - if (info) { - doChange(changes, diag.file, info.returnTypeNode, info.promisedTypeNode); - } - }) + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, context.program.getTypeChecker(), diag.start); + if (info) { + doChange(changes, diag.file, info.returnTypeNode, info.promisedTypeNode); + } + }), }); function getInfo(sourceFile: SourceFile, checker: TypeChecker, pos: number): Info | undefined { @@ -69,12 +81,21 @@ function getInfo(sourceFile: SourceFile, checker: TypeChecker, pos: number): Inf const returnType = checker.getTypeFromTypeNode(returnTypeNode); const promisedType = checker.getAwaitedType(returnType) || checker.getVoidType(); - const promisedTypeNode = checker.typeToTypeNode(promisedType, /*enclosingDeclaration*/ returnTypeNode, /*flags*/ undefined); + const promisedTypeNode = checker.typeToTypeNode( + promisedType, + /*enclosingDeclaration*/ returnTypeNode, + /*flags*/ undefined, + ); if (promisedTypeNode) { return { returnTypeNode, returnType, promisedTypeNode, promisedType }; } } -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, returnTypeNode: TypeNode, promisedTypeNode: TypeNode): void { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + returnTypeNode: TypeNode, + promisedTypeNode: TypeNode, +): void { changes.replaceNode(sourceFile, returnTypeNode, factory.createTypeReferenceNode("Promise", [promisedTypeNode])); } diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index 8e3574aa60cde..a5b533eefccce 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -56,8 +56,12 @@ const errorCodes = [ Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code, Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0.code, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2.code, - Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1.code, - Diagnostics.This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1.code, + Diagnostics + .This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 + .code, + Diagnostics + .This_member_cannot_have_a_JSDoc_comment_with_an_override_tag_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1 + .code, // for JSX class components Diagnostics.No_overload_matches_this_call.code, // for JSX FC @@ -71,28 +75,48 @@ registerCodeFix({ if (!info) return undefined; const { node, suggestedSymbol } = info; const target = getEmitScriptTarget(context.host.getCompilationSettings()); - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node, suggestedSymbol, target)); - return [createCodeFixAction("spelling", changes, [Diagnostics.Change_spelling_to_0, symbolName(suggestedSymbol)], fixId, Diagnostics.Fix_all_detected_spelling_errors)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, node, suggestedSymbol, target), + ); + return [ + createCodeFixAction( + "spelling", + changes, + [Diagnostics.Change_spelling_to_0, symbolName(suggestedSymbol)], + fixId, + Diagnostics.Fix_all_detected_spelling_errors, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, diag.start, context, diag.code); - const target = getEmitScriptTarget(context.host.getCompilationSettings()); - if (info) doChange(changes, context.sourceFile, info.node, info.suggestedSymbol, target); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, diag.start, context, diag.code); + const target = getEmitScriptTarget(context.host.getCompilationSettings()); + if (info) doChange(changes, context.sourceFile, info.node, info.suggestedSymbol, target); + }), }); -function getInfo(sourceFile: SourceFile, pos: number, context: CodeFixContextBase, errorCode: number): { node: Node, suggestedSymbol: Symbol } | undefined { +function getInfo( + sourceFile: SourceFile, + pos: number, + context: CodeFixContextBase, + errorCode: number, +): { node: Node; suggestedSymbol: Symbol; } | undefined { // This is the identifier of the misspelled word. eg: // this.speling = 1; // ^^^^^^^ const node = getTokenAtPosition(sourceFile, pos); const parent = node.parent; // Only fix spelling for No_overload_matches_this_call emitted on the React class component - if (( - errorCode === Diagnostics.No_overload_matches_this_call.code || - errorCode === Diagnostics.Type_0_is_not_assignable_to_type_1.code) && - !isJsxAttribute(parent)) return undefined; + if ( + ( + errorCode === Diagnostics.No_overload_matches_this_call.code + || errorCode === Diagnostics.Type_0_is_not_assignable_to_type_1.code + ) + && !isJsxAttribute(parent) + ) return undefined; const checker = context.program.getTypeChecker(); let suggestedSymbol: Symbol | undefined; @@ -104,7 +128,10 @@ function getInfo(sourceFile: SourceFile, pos: number, context: CodeFixContextBas } suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, containingType); } - else if (isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.InKeyword && parent.left === node && isPrivateIdentifier(node)) { + else if ( + isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.InKeyword && parent.left === node + && isPrivateIdentifier(node) + ) { const receiverType = checker.getTypeAtLocation(parent.right); suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, receiverType); } @@ -140,13 +167,23 @@ function getInfo(sourceFile: SourceFile, pos: number, context: CodeFixContextBas const meaning = getMeaningFromLocation(node); const name = getTextOfNode(node); Debug.assert(name !== undefined, "name should be defined"); - suggestedSymbol = checker.getSuggestedSymbolForNonexistentSymbol(node, name, convertSemanticMeaningToSymbolFlags(meaning)); + suggestedSymbol = checker.getSuggestedSymbolForNonexistentSymbol( + node, + name, + convertSemanticMeaningToSymbolFlags(meaning), + ); } return suggestedSymbol === undefined ? undefined : { node, suggestedSymbol }; } -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: Node, suggestedSymbol: Symbol, target: ScriptTarget) { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: Node, + suggestedSymbol: Symbol, + target: ScriptTarget, +) { const suggestion = symbolName(suggestedSymbol); if (!isIdentifierText(suggestion, target) && isPropertyAccessExpression(node.parent)) { const valDecl = suggestedSymbol.valueDeclaration; @@ -154,7 +191,11 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, no changes.replaceNode(sourceFile, node, factory.createIdentifier(suggestion)); } else { - changes.replaceNode(sourceFile, node.parent, factory.createElementAccessExpression(node.parent.expression, factory.createStringLiteral(suggestion))); + changes.replaceNode( + sourceFile, + node.parent, + factory.createElementAccessExpression(node.parent.expression, factory.createStringLiteral(suggestion)), + ); } } else { @@ -176,10 +217,18 @@ function convertSemanticMeaningToSymbolFlags(meaning: SemanticMeaning): SymbolFl return flags; } -function getResolvedSourceFileFromImportDeclaration(sourceFile: SourceFile, context: CodeFixContextBase, importDeclaration: ImportDeclaration): SourceFile | undefined { +function getResolvedSourceFileFromImportDeclaration( + sourceFile: SourceFile, + context: CodeFixContextBase, + importDeclaration: ImportDeclaration, +): SourceFile | undefined { if (!importDeclaration || !isStringLiteralLike(importDeclaration.moduleSpecifier)) return undefined; - const resolvedModule = getResolvedModule(sourceFile, importDeclaration.moduleSpecifier.text, getModeForUsageLocation(sourceFile, importDeclaration.moduleSpecifier)); + const resolvedModule = getResolvedModule( + sourceFile, + importDeclaration.moduleSpecifier.text, + getModeForUsageLocation(sourceFile, importDeclaration.moduleSpecifier), + ); if (!resolvedModule) return undefined; return context.program.getSourceFile(resolvedModule.resolvedFileName); diff --git a/src/services/codefixes/fixStrictClassInitialization.ts b/src/services/codefixes/fixStrictClassInitialization.ts index fa78042e08217..695a7ab9b61b0 100644 --- a/src/services/codefixes/fixStrictClassInitialization.ts +++ b/src/services/codefixes/fixStrictClassInitialization.ts @@ -94,13 +94,29 @@ function getInfo(sourceFile: SourceFile, pos: number): Info | undefined { return undefined; } -function getActionForAddMissingDefiniteAssignmentAssertion(context: CodeFixContext, info: Info): CodeFixAction | undefined { +function getActionForAddMissingDefiniteAssignmentAssertion( + context: CodeFixContext, + info: Info, +): CodeFixAction | undefined { if (info.isJs) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => addDefiniteAssignmentAssertion(t, context.sourceFile, info.prop)); - return createCodeFixAction(fixName, changes, [Diagnostics.Add_definite_assignment_assertion_to_property_0, info.prop.getText()], fixIdAddDefiniteAssignmentAssertions, Diagnostics.Add_definite_assignment_assertions_to_all_uninitialized_properties); + const changes = textChanges.ChangeTracker.with( + context, + t => addDefiniteAssignmentAssertion(t, context.sourceFile, info.prop), + ); + return createCodeFixAction( + fixName, + changes, + [Diagnostics.Add_definite_assignment_assertion_to_property_0, info.prop.getText()], + fixIdAddDefiniteAssignmentAssertions, + Diagnostics.Add_definite_assignment_assertions_to_all_uninitialized_properties, + ); } -function addDefiniteAssignmentAssertion(changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration): void { +function addDefiniteAssignmentAssertion( + changeTracker: textChanges.ChangeTracker, + propertyDeclarationSourceFile: SourceFile, + propertyDeclaration: PropertyDeclaration, +): void { suppressLeadingAndTrailingTrivia(propertyDeclaration); const property = factory.updatePropertyDeclaration( propertyDeclaration, @@ -108,22 +124,31 @@ function addDefiniteAssignmentAssertion(changeTracker: textChanges.ChangeTracker propertyDeclaration.name, factory.createToken(SyntaxKind.ExclamationToken), propertyDeclaration.type, - propertyDeclaration.initializer + propertyDeclaration.initializer, ); changeTracker.replaceNode(propertyDeclarationSourceFile, propertyDeclaration, property); } function getActionForAddMissingUndefinedType(context: CodeFixContext, info: Info): CodeFixAction { const changes = textChanges.ChangeTracker.with(context, t => addUndefinedType(t, context.sourceFile, info)); - return createCodeFixAction(fixName, changes, [Diagnostics.Add_undefined_type_to_property_0, info.prop.name.getText()], fixIdAddUndefinedType, Diagnostics.Add_undefined_type_to_all_uninitialized_properties); + return createCodeFixAction( + fixName, + changes, + [Diagnostics.Add_undefined_type_to_property_0, info.prop.name.getText()], + fixIdAddUndefinedType, + Diagnostics.Add_undefined_type_to_all_uninitialized_properties, + ); } function addUndefinedType(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info): void { const undefinedTypeNode = factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword); - const types = isUnionTypeNode(info.type) ? info.type.types.concat(undefinedTypeNode) : [info.type, undefinedTypeNode]; + const types = isUnionTypeNode(info.type) ? info.type.types.concat(undefinedTypeNode) + : [info.type, undefinedTypeNode]; const unionTypeNode = factory.createUnionTypeNode(types); if (info.isJs) { - changeTracker.addJSDocTags(sourceFile, info.prop, [factory.createJSDocTypeTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(unionTypeNode))]); + changeTracker.addJSDocTags(sourceFile, info.prop, [ + factory.createJSDocTypeTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(unionTypeNode)), + ]); } else { changeTracker.replaceNode(sourceFile, info.type, unionTypeNode); @@ -137,11 +162,25 @@ function getActionForAddMissingInitializer(context: CodeFixContext, info: Info): const initializer = getInitializer(checker, info.prop); if (!initializer) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => addInitializer(t, context.sourceFile, info.prop, initializer)); - return createCodeFixAction(fixName, changes, [Diagnostics.Add_initializer_to_property_0, info.prop.name.getText()], fixIdAddInitializer, Diagnostics.Add_initializers_to_all_uninitialized_properties); + const changes = textChanges.ChangeTracker.with( + context, + t => addInitializer(t, context.sourceFile, info.prop, initializer), + ); + return createCodeFixAction( + fixName, + changes, + [Diagnostics.Add_initializer_to_property_0, info.prop.name.getText()], + fixIdAddInitializer, + Diagnostics.Add_initializers_to_all_uninitialized_properties, + ); } -function addInitializer(changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration, initializer: Expression): void { +function addInitializer( + changeTracker: textChanges.ChangeTracker, + propertyDeclarationSourceFile: SourceFile, + propertyDeclaration: PropertyDeclaration, + initializer: Expression, +): void { suppressLeadingAndTrailingTrivia(propertyDeclaration); const property = factory.updatePropertyDeclaration( propertyDeclaration, @@ -149,7 +188,7 @@ function addInitializer(changeTracker: textChanges.ChangeTracker, propertyDeclar propertyDeclaration.name, propertyDeclaration.questionToken, propertyDeclaration.type, - initializer + initializer, ); changeTracker.replaceNode(propertyDeclarationSourceFile, propertyDeclaration, property); } @@ -160,7 +199,8 @@ function getInitializer(checker: TypeChecker, propertyDeclaration: PropertyDecla function getDefaultValueFromType(checker: TypeChecker, type: Type): Expression | undefined { if (type.flags & TypeFlags.BooleanLiteral) { - return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) ? factory.createFalse() : factory.createTrue(); + return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) + ? factory.createFalse() : factory.createTrue(); } else if (type.isStringLiteral()) { return factory.createStringLiteral(type.value); @@ -181,7 +221,11 @@ function getDefaultValueFromType(checker: TypeChecker, type: Type): Expression | const constructorDeclaration = getFirstConstructorWithBody(classDeclaration); if (constructorDeclaration && constructorDeclaration.parameters.length) return undefined; - return factory.createNewExpression(factory.createIdentifier(type.symbol.name), /*typeArguments*/ undefined, /*argumentsArray*/ undefined); + return factory.createNewExpression( + factory.createIdentifier(type.symbol.name), + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, + ); } else if (checker.isArrayLikeType(type)) { return factory.createArrayLiteralExpression(); diff --git a/src/services/codefixes/fixUnmatchedParameter.ts b/src/services/codefixes/fixUnmatchedParameter.ts index 267e207a6ccac..aa1cf5cea0730 100644 --- a/src/services/codefixes/fixUnmatchedParameter.ts +++ b/src/services/codefixes/fixUnmatchedParameter.ts @@ -57,7 +57,10 @@ registerCodeFix({ eachDiagnostic(context, errorCodes, ({ file, start }) => { const info = getInfo(file, start); if (info) { - tagsToSignature.set(info.signature, append(tagsToSignature.get(info.signature), info.jsDocParameterTag)); + tagsToSignature.set( + info.signature, + append(tagsToSignature.get(info.signature), info.jsDocParameterTag), + ); } }); @@ -68,18 +71,20 @@ registerCodeFix({ } }); })); - } + }, }); function getDeleteAction(context: CodeFixContext, { name, jsDocHost, jsDocParameterTag }: Info) { - const changes = textChanges.ChangeTracker.with(context, changeTracker => - changeTracker.filterJSDocTags(context.sourceFile, jsDocHost, t => t !== jsDocParameterTag)); + const changes = textChanges.ChangeTracker.with( + context, + changeTracker => changeTracker.filterJSDocTags(context.sourceFile, jsDocHost, t => t !== jsDocParameterTag), + ); return createCodeFixAction( deleteUnmatchedParameter, changes, [Diagnostics.Delete_unused_param_tag_0, name.getText(context.sourceFile)], deleteUnmatchedParameter, - Diagnostics.Delete_all_unused_param_tags + Diagnostics.Delete_all_unused_param_tags, ); } @@ -96,8 +101,10 @@ function getRenameAction(context: CodeFixContext, { name, jsDocHost, signature, } // @todo - match to all available names instead to the first parameter name // @see /codeFixRenameUnmatchedParameter3.ts - const parameterName = firstDefined(signature.parameters, p => - isIdentifier(p.name) && !names.has(p.name.escapedText) ? p.name.getText(sourceFile) : undefined); + const parameterName = firstDefined( + signature.parameters, + p => isIdentifier(p.name) && !names.has(p.name.escapedText) ? p.name.getText(sourceFile) : undefined, + ); if (parameterName === undefined) return undefined; const newJSDocParameterTag = factory.updateJSDocParameterTag( @@ -107,11 +114,22 @@ function getRenameAction(context: CodeFixContext, { name, jsDocHost, signature, jsDocParameterTag.isBracketed, jsDocParameterTag.typeExpression, jsDocParameterTag.isNameFirst, - jsDocParameterTag.comment + jsDocParameterTag.comment, + ); + const changes = textChanges.ChangeTracker.with( + context, + changeTracker => + changeTracker.replaceJSDocComment( + sourceFile, + jsDocHost, + map(tags, t => t === jsDocParameterTag ? newJSDocParameterTag : t), + ), ); - const changes = textChanges.ChangeTracker.with(context, changeTracker => - changeTracker.replaceJSDocComment(sourceFile, jsDocHost, map(tags, t => t === jsDocParameterTag ? newJSDocParameterTag : t))); - return createCodeFixActionWithoutFixAll(renameUnmatchedParameter, changes, [Diagnostics.Rename_param_tag_name_0_to_1, name.getText(sourceFile), parameterName]); + return createCodeFixActionWithoutFixAll(renameUnmatchedParameter, changes, [ + Diagnostics.Rename_param_tag_name_0_to_1, + name.getText(sourceFile), + parameterName, + ]); } interface Info { diff --git a/src/services/codefixes/fixUnreachableCode.ts b/src/services/codefixes/fixUnreachableCode.ts index 17afabda71a93..cf4a359fd1ff2 100644 --- a/src/services/codefixes/fixUnreachableCode.ts +++ b/src/services/codefixes/fixUnreachableCode.ts @@ -25,16 +25,41 @@ const errorCodes = [Diagnostics.Unreachable_code_detected.code]; registerCodeFix({ errorCodes, getCodeActions(context) { - const syntacticDiagnostics = context.program.getSyntacticDiagnostics(context.sourceFile, context.cancellationToken); + const syntacticDiagnostics = context.program.getSyntacticDiagnostics( + context.sourceFile, + context.cancellationToken, + ); if (syntacticDiagnostics.length) return; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start, context.span.length, context.errorCode)); - return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unreachable_code, fixId, Diagnostics.Remove_all_unreachable_code)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, context.sourceFile, context.span.start, context.span.length, context.errorCode), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Remove_unreachable_code, + fixId, + Diagnostics.Remove_all_unreachable_code, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start, diag.length, diag.code)), + getAllCodeActions: context => + codeFixAll( + context, + errorCodes, + (changes, diag) => doChange(changes, diag.file, diag.start, diag.length, diag.code), + ), }); -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number, length: number, errorCode: number): void { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + start: number, + length: number, + errorCode: number, +): void { const token = getTokenAtPosition(sourceFile, start); const statement = findAncestor(token, isStatement)!; if (statement.getStart(sourceFile) !== token.getStart(sourceFile)) { @@ -43,7 +68,7 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, st tokenKind: Debug.formatSyntaxKind(token.kind), errorCode, start, - length + length, }); Debug.fail("Token and statement should start at the same point. " + logData); } @@ -71,7 +96,10 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, st if (isBlock(statement.parent)) { const end = start + length; - const lastStatement = Debug.checkDefined(lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end), "Some statement should be last"); + const lastStatement = Debug.checkDefined( + lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end), + "Some statement should be last", + ); changes.deleteNodeRange(sourceFile, statement, lastStatement); } else { diff --git a/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts b/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts index 4c35ee6b9629a..d76e3bfddb1e4 100644 --- a/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts +++ b/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts @@ -30,34 +30,64 @@ import { } from "../_namespaces/ts.codefix"; const fixId = "fixUnreferenceableDecoratorMetadata"; -const errorCodes = [Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled.code]; +const errorCodes = [ + Diagnostics + .A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled + .code, +]; registerCodeFix({ errorCodes, getCodeActions: context => { const importDeclaration = getImportDeclaration(context.sourceFile, context.program, context.span.start); if (!importDeclaration) return; - const namespaceChanges = textChanges.ChangeTracker.with(context, t => importDeclaration.kind === SyntaxKind.ImportSpecifier && doNamespaceImportChange(t, context.sourceFile, importDeclaration, context.program)); - const typeOnlyChanges = textChanges.ChangeTracker.with(context, t => doTypeOnlyImportChange(t, context.sourceFile, importDeclaration, context.program)); + const namespaceChanges = textChanges.ChangeTracker.with( + context, + t => importDeclaration.kind === SyntaxKind.ImportSpecifier + && doNamespaceImportChange(t, context.sourceFile, importDeclaration, context.program), + ); + const typeOnlyChanges = textChanges.ChangeTracker.with( + context, + t => doTypeOnlyImportChange(t, context.sourceFile, importDeclaration, context.program), + ); let actions: CodeFixAction[] | undefined; if (namespaceChanges.length) { - actions = append(actions, createCodeFixActionWithoutFixAll(fixId, namespaceChanges, Diagnostics.Convert_named_imports_to_namespace_import)); + actions = append( + actions, + createCodeFixActionWithoutFixAll( + fixId, + namespaceChanges, + Diagnostics.Convert_named_imports_to_namespace_import, + ), + ); } if (typeOnlyChanges.length) { - actions = append(actions, createCodeFixActionWithoutFixAll(fixId, typeOnlyChanges, Diagnostics.Use_import_type)); + actions = append( + actions, + createCodeFixActionWithoutFixAll(fixId, typeOnlyChanges, Diagnostics.Use_import_type), + ); } return actions; }, fixIds: [fixId], }); -function getImportDeclaration(sourceFile: SourceFile, program: Program, start: number): ImportClause | ImportSpecifier | ImportEqualsDeclaration | undefined { +function getImportDeclaration( + sourceFile: SourceFile, + program: Program, + start: number, +): ImportClause | ImportSpecifier | ImportEqualsDeclaration | undefined { const identifier = tryCast(getTokenAtPosition(sourceFile, start), isIdentifier); if (!identifier || identifier.parent.kind !== SyntaxKind.TypeReference) return; const checker = program.getTypeChecker(); const symbol = checker.getSymbolAtLocation(identifier); - return find(symbol?.declarations || emptyArray, or(isImportClause, isImportSpecifier, isImportEqualsDeclaration) as (n: Node) => n is ImportClause | ImportSpecifier | ImportEqualsDeclaration); + return find( + symbol?.declarations || emptyArray, + or(isImportClause, isImportSpecifier, isImportEqualsDeclaration) as ( + n: Node, + ) => n is ImportClause | ImportSpecifier | ImportEqualsDeclaration, + ); } // Converts the import declaration of the offending import to a type-only import, @@ -65,13 +95,19 @@ function getImportDeclaration(sourceFile: SourceFile, program: Program, start: n // cannot be done cleanly, we could offer to *extract* the offending import to a // new type-only import declaration, but honestly I doubt anyone will ever use this // codefix at all, so it's probably not worth the lines of code. -function doTypeOnlyImportChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDeclaration: ImportClause | ImportSpecifier | ImportEqualsDeclaration, program: Program) { +function doTypeOnlyImportChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + importDeclaration: ImportClause | ImportSpecifier | ImportEqualsDeclaration, + program: Program, +) { if (importDeclaration.kind === SyntaxKind.ImportEqualsDeclaration) { changes.insertModifierBefore(sourceFile, SyntaxKind.TypeKeyword, importDeclaration.name); return; } - const importClause = importDeclaration.kind === SyntaxKind.ImportClause ? importDeclaration : importDeclaration.parent.parent; + const importClause = importDeclaration.kind === SyntaxKind.ImportClause ? importDeclaration + : importDeclaration.parent.parent; if (importClause.name && importClause.namedBindings) { // Cannot convert an import with a default import and named bindings to type-only // (it's a grammar error). @@ -93,6 +129,11 @@ function doTypeOnlyImportChange(changes: textChanges.ChangeTracker, sourceFile: changes.insertModifierBefore(sourceFile, SyntaxKind.TypeKeyword, importClause); } -function doNamespaceImportChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDeclaration: ImportSpecifier, program: Program) { +function doNamespaceImportChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + importDeclaration: ImportSpecifier, + program: Program, +) { refactor.doChangeNamedToNamespaceOrDefault(sourceFile, program, changes, importDeclaration.parent); } diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index 4da1d6ce22d9c..39ba73b735470 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -89,7 +89,12 @@ registerCodeFix({ const token = getTokenAtPosition(sourceFile, context.span.start); if (isJSDocTemplateTag(token)) { - return [createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token)), Diagnostics.Remove_template_tag)]; + return [ + createDeleteFix( + textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token)), + Diagnostics.Remove_template_tag, + ), + ]; } if (token.kind === SyntaxKind.LessThanToken) { const changes = textChanges.ChangeTracker.with(context, t => deleteTypeParameters(t, sourceFile, token)); @@ -98,12 +103,40 @@ registerCodeFix({ const importDecl = tryGetFullImport(token); if (importDecl) { const changes = textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, importDecl)); - return [createCodeFixAction(fixName, changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], fixIdDeleteImports, Diagnostics.Delete_all_unused_imports)]; + return [ + createCodeFixAction( + fixName, + changes, + [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], + fixIdDeleteImports, + Diagnostics.Delete_all_unused_imports, + ), + ]; } else if (isImport(token)) { - const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(sourceFile, token, t, checker, sourceFiles, program, cancellationToken, /*isFixAll*/ false)); + const deletion = textChanges.ChangeTracker.with( + context, + t => tryDeleteDeclaration( + sourceFile, + token, + t, + checker, + sourceFiles, + program, + cancellationToken, + /*isFixAll*/ false, + ), + ); if (deletion.length) { - return [createCodeFixAction(fixName, deletion, [Diagnostics.Remove_unused_declaration_for_Colon_0, token.getText(sourceFile)], fixIdDeleteImports, Diagnostics.Delete_all_unused_imports)]; + return [ + createCodeFixAction( + fixName, + deletion, + [Diagnostics.Remove_unused_declaration_for_Colon_0, token.getText(sourceFile)], + fixIdDeleteImports, + Diagnostics.Delete_all_unused_imports, + ), + ]; } } @@ -111,24 +144,45 @@ registerCodeFix({ if (isParameter(token.parent.parent)) { const elements = token.parent.elements; const diagnostic: [DiagnosticMessage, string] = [ - elements.length > 1 ? Diagnostics.Remove_unused_declarations_for_Colon_0 : Diagnostics.Remove_unused_declaration_for_Colon_0, - map(elements, e => e.getText(sourceFile)).join(", ") + elements.length > 1 ? Diagnostics.Remove_unused_declarations_for_Colon_0 + : Diagnostics.Remove_unused_declaration_for_Colon_0, + map(elements, e => e.getText(sourceFile)).join(", "), ]; return [ - createDeleteFix(textChanges.ChangeTracker.with(context, t => - deleteDestructuringElements(t, sourceFile, token.parent as ObjectBindingPattern | ArrayBindingPattern)), diagnostic) + createDeleteFix( + textChanges.ChangeTracker.with(context, t => + deleteDestructuringElements( + t, + sourceFile, + token.parent as ObjectBindingPattern | ArrayBindingPattern, + )), + diagnostic, + ), ]; } return [ - createDeleteFix(textChanges.ChangeTracker.with(context, t => - deleteDestructuring(context, t, sourceFile, token.parent as ObjectBindingPattern | ArrayBindingPattern)), Diagnostics.Remove_unused_destructuring_declaration), + createDeleteFix( + textChanges.ChangeTracker.with(context, t => + deleteDestructuring( + context, + t, + sourceFile, + token.parent as ObjectBindingPattern | ArrayBindingPattern, + )), + Diagnostics.Remove_unused_destructuring_declaration, + ), ]; } if (canDeleteEntireVariableStatement(sourceFile, token)) { return [ - createDeleteFix(textChanges.ChangeTracker.with(context, t => - deleteEntireVariableStatement(t, sourceFile, token.parent as VariableDeclarationList)), Diagnostics.Remove_variable_statement) + createDeleteFix( + textChanges.ChangeTracker.with( + context, + t => deleteEntireVariableStatement(t, sourceFile, token.parent as VariableDeclarationList), + ), + Diagnostics.Remove_variable_statement, + ), ]; } @@ -136,20 +190,55 @@ registerCodeFix({ if (token.kind === SyntaxKind.InferKeyword) { const changes = textChanges.ChangeTracker.with(context, t => changeInferToUnknown(t, sourceFile, token)); const name = cast(token.parent, isInferTypeNode).typeParameter.name.text; - result.push(createCodeFixAction(fixName, changes, [Diagnostics.Replace_infer_0_with_unknown, name], fixIdInfer, Diagnostics.Replace_all_unused_infer_with_unknown)); + result.push( + createCodeFixAction( + fixName, + changes, + [Diagnostics.Replace_infer_0_with_unknown, name], + fixIdInfer, + Diagnostics.Replace_all_unused_infer_with_unknown, + ), + ); } else { - const deletion = textChanges.ChangeTracker.with(context, t => - tryDeleteDeclaration(sourceFile, token, t, checker, sourceFiles, program, cancellationToken, /*isFixAll*/ false)); + const deletion = textChanges.ChangeTracker.with( + context, + t => tryDeleteDeclaration( + sourceFile, + token, + t, + checker, + sourceFiles, + program, + cancellationToken, + /*isFixAll*/ false, + ), + ); if (deletion.length) { const name = isComputedPropertyName(token.parent) ? token.parent : token; - result.push(createDeleteFix(deletion, [Diagnostics.Remove_unused_declaration_for_Colon_0, name.getText(sourceFile)])); + result.push( + createDeleteFix(deletion, [ + Diagnostics.Remove_unused_declaration_for_Colon_0, + name.getText(sourceFile), + ]), + ); } } - const prefix = textChanges.ChangeTracker.with(context, t => tryPrefixDeclaration(t, errorCode, sourceFile, token)); + const prefix = textChanges.ChangeTracker.with( + context, + t => tryPrefixDeclaration(t, errorCode, sourceFile, token), + ); if (prefix.length) { - result.push(createCodeFixAction(fixName, prefix, [Diagnostics.Prefix_0_with_an_underscore, token.getText(sourceFile)], fixIdPrefix, Diagnostics.Prefix_all_unused_declarations_with_where_possible)); + result.push( + createCodeFixAction( + fixName, + prefix, + [Diagnostics.Prefix_0_with_an_underscore, token.getText(sourceFile)], + fixIdPrefix, + Diagnostics.Prefix_all_unused_declarations_with_where_possible, + ), + ); } return result; @@ -171,7 +260,16 @@ registerCodeFix({ changes.delete(sourceFile, importDecl); } else if (isImport(token)) { - tryDeleteDeclaration(sourceFile, token, changes, checker, sourceFiles, program, cancellationToken, /*isFixAll*/ true); + tryDeleteDeclaration( + sourceFile, + token, + changes, + checker, + sourceFiles, + program, + cancellationToken, + /*isFixAll*/ true, + ); } break; } @@ -189,7 +287,10 @@ registerCodeFix({ if (token.parent.parent.initializer) { break; } - else if (!isParameter(token.parent.parent) || isNotProvidedArguments(token.parent.parent, checker, sourceFiles)) { + else if ( + !isParameter(token.parent.parent) + || isNotProvidedArguments(token.parent.parent, checker, sourceFiles) + ) { changes.delete(sourceFile, token.parent.parent); } } @@ -200,7 +301,16 @@ registerCodeFix({ deleteEntireVariableStatement(changes, sourceFile, token.parent as VariableDeclarationList); } else { - tryDeleteDeclaration(sourceFile, token, changes, checker, sourceFiles, program, cancellationToken, /*isFixAll*/ true); + tryDeleteDeclaration( + sourceFile, + token, + changes, + checker, + sourceFiles, + program, + cancellationToken, + /*isFixAll*/ true, + ); } break; } @@ -225,12 +335,19 @@ function createDeleteFix(changes: FileTextChanges[], diag: DiagnosticOrDiagnosti } function deleteTypeParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void { - changes.delete(sourceFile, Debug.checkDefined(cast(token.parent, isDeclarationWithTypeParameterChildren).typeParameters, "The type parameter to delete should exist")); + changes.delete( + sourceFile, + Debug.checkDefined( + cast(token.parent, isDeclarationWithTypeParameterChildren).typeParameters, + "The type parameter to delete should exist", + ), + ); } function isImport(token: Node) { return token.kind === SyntaxKind.ImportKeyword - || token.kind === SyntaxKind.Identifier && (token.parent.kind === SyntaxKind.ImportSpecifier || token.parent.kind === SyntaxKind.ImportClause); + || token.kind === SyntaxKind.Identifier + && (token.parent.kind === SyntaxKind.ImportSpecifier || token.parent.kind === SyntaxKind.ImportClause); } /** Sometimes the diagnostic span is an entire ImportDeclaration, so we should remove the whole thing. */ @@ -242,15 +359,28 @@ function canDeleteEntireVariableStatement(sourceFile: SourceFile, token: Node): return isVariableDeclarationList(token.parent) && first(token.parent.getChildren(sourceFile)) === token; } -function deleteEntireVariableStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: VariableDeclarationList) { +function deleteEntireVariableStatement( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: VariableDeclarationList, +) { changes.delete(sourceFile, node.parent.kind === SyntaxKind.VariableStatement ? node.parent : node); } -function deleteDestructuringElements(changes: textChanges.ChangeTracker, sourceFile: SourceFile, node: ObjectBindingPattern | ArrayBindingPattern) { +function deleteDestructuringElements( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + node: ObjectBindingPattern | ArrayBindingPattern, +) { forEach(node.elements, n => changes.delete(sourceFile, n)); } -function deleteDestructuring(context: CodeFixContext, changes: textChanges.ChangeTracker, sourceFile: SourceFile, { parent }: ObjectBindingPattern | ArrayBindingPattern) { +function deleteDestructuring( + context: CodeFixContext, + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { parent }: ObjectBindingPattern | ArrayBindingPattern, +) { if (isVariableDeclaration(parent) && parent.initializer && isCallLikeExpression(parent.initializer)) { if (isVariableDeclarationList(parent.parent) && length(parent.parent.declarations) > 1) { const varStatement = parent.parent.parent; @@ -258,7 +388,8 @@ function deleteDestructuring(context: CodeFixContext, changes: textChanges.Chang const end = varStatement.end; changes.delete(sourceFile, parent); changes.insertNodeAt(sourceFile, end, parent.initializer, { - prefix: getNewLineOrDefaultFromHost(context.host, context.formatContext.options) + sourceFile.text.slice(getPrecedingNonSpaceCharacterPosition(sourceFile.text, pos - 1), pos), + prefix: getNewLineOrDefaultFromHost(context.host, context.formatContext.options) + + sourceFile.text.slice(getPrecedingNonSpaceCharacterPosition(sourceFile.text, pos - 1), pos), suffix: probablyUsesSemicolons(sourceFile) ? ";" : "", }); } @@ -271,7 +402,12 @@ function deleteDestructuring(context: CodeFixContext, changes: textChanges.Chang } } -function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, token: Node): void { +function tryPrefixDeclaration( + changes: textChanges.ChangeTracker, + errorCode: number, + sourceFile: SourceFile, + token: Node, +): void { // Don't offer to prefix a property. if (errorCode === Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code) return; if (token.kind === SyntaxKind.InferKeyword) { @@ -280,7 +416,7 @@ function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: num if (isIdentifier(token) && canPrefix(token)) { changes.replaceNode(sourceFile, token, factory.createIdentifier(`_${token.text}`)); if (isParameter(token.parent)) { - getJSDocParameterTags(token.parent).forEach((tag) => { + getJSDocParameterTags(token.parent).forEach(tag => { if (isIdentifier(tag.name)) { changes.replaceNode(sourceFile, tag.name, factory.createIdentifier(`_${tag.name.text}`)); } @@ -306,7 +442,16 @@ function canPrefix(token: Identifier): boolean { return false; } -function tryDeleteDeclaration(sourceFile: SourceFile, token: Node, changes: textChanges.ChangeTracker, checker: TypeChecker, sourceFiles: readonly SourceFile[], program: Program, cancellationToken: CancellationToken, isFixAll: boolean) { +function tryDeleteDeclaration( + sourceFile: SourceFile, + token: Node, + changes: textChanges.ChangeTracker, + checker: TypeChecker, + sourceFiles: readonly SourceFile[], + program: Program, + cancellationToken: CancellationToken, + isFixAll: boolean, +) { tryDeleteDeclarationWorker(token, changes, sourceFile, checker, sourceFiles, program, cancellationToken, isFixAll); if (isIdentifier(token)) { FindAllReferences.Core.eachSymbolReferenceInFile(token, checker, sourceFile, (ref: Node) => { @@ -318,12 +463,24 @@ function tryDeleteDeclaration(sourceFile: SourceFile, token: Node, changes: text } } -function tryDeleteDeclarationWorker(token: Node, changes: textChanges.ChangeTracker, sourceFile: SourceFile, checker: TypeChecker, sourceFiles: readonly SourceFile[], program: Program, cancellationToken: CancellationToken, isFixAll: boolean): void { +function tryDeleteDeclarationWorker( + token: Node, + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + checker: TypeChecker, + sourceFiles: readonly SourceFile[], + program: Program, + cancellationToken: CancellationToken, + isFixAll: boolean, +): void { const { parent } = token; if (isParameter(parent)) { tryDeleteParameter(changes, sourceFile, parent, checker, sourceFiles, program, cancellationToken, isFixAll); } - else if (!(isFixAll && isIdentifier(token) && FindAllReferences.Core.isSymbolReferencedInFile(token, checker, sourceFile))) { + else if ( + !(isFixAll && isIdentifier(token) + && FindAllReferences.Core.isSymbolReferencedInFile(token, checker, sourceFile)) + ) { const node = isImportClause(parent) ? token : isComputedPropertyName(parent) ? parent.parent : parent; Debug.assert(node !== sourceFile, "should not delete whole source file"); changes.delete(sourceFile, node); @@ -338,10 +495,14 @@ function tryDeleteParameter( sourceFiles: readonly SourceFile[], program: Program, cancellationToken: CancellationToken, - isFixAll = false): void { + isFixAll = false, +): void { if (mayDeleteParameter(checker, sourceFile, parameter, sourceFiles, program, cancellationToken, isFixAll)) { - if (parameter.modifiers && parameter.modifiers.length > 0 && - (!isIdentifier(parameter.name) || FindAllReferences.Core.isSymbolReferencedInFile(parameter.name, checker, sourceFile))) { + if ( + parameter.modifiers && parameter.modifiers.length > 0 + && (!isIdentifier(parameter.name) + || FindAllReferences.Core.isSymbolReferencedInFile(parameter.name, checker, sourceFile)) + ) { for (const modifier of parameter.modifiers) { if (isModifier(modifier)) { changes.deleteModifier(sourceFile, modifier); @@ -354,20 +515,43 @@ function tryDeleteParameter( } } -function isNotProvidedArguments(parameter: ParameterDeclaration, checker: TypeChecker, sourceFiles: readonly SourceFile[]) { +function isNotProvidedArguments( + parameter: ParameterDeclaration, + checker: TypeChecker, + sourceFiles: readonly SourceFile[], +) { const index = parameter.parent.parameters.indexOf(parameter); // Just in case the call didn't provide enough arguments. - return !FindAllReferences.Core.someSignatureUsage(parameter.parent, sourceFiles, checker, (_, call) => !call || call.arguments.length > index); + return !FindAllReferences.Core.someSignatureUsage( + parameter.parent, + sourceFiles, + checker, + (_, call) => !call || call.arguments.length > index, + ); } -function mayDeleteParameter(checker: TypeChecker, sourceFile: SourceFile, parameter: ParameterDeclaration, sourceFiles: readonly SourceFile[], program: Program, cancellationToken: CancellationToken, isFixAll: boolean): boolean { +function mayDeleteParameter( + checker: TypeChecker, + sourceFile: SourceFile, + parameter: ParameterDeclaration, + sourceFiles: readonly SourceFile[], + program: Program, + cancellationToken: CancellationToken, + isFixAll: boolean, +): boolean { const { parent } = parameter; switch (parent.kind) { case SyntaxKind.MethodDeclaration: case SyntaxKind.Constructor: const index = parent.parameters.indexOf(parameter); const referent = isMethodDeclaration(parent) ? parent.name : parent; - const entries = FindAllReferences.Core.getReferencedSymbolsForNode(parent.pos, referent, program, sourceFiles, cancellationToken); + const entries = FindAllReferences.Core.getReferencedSymbolsForNode( + parent.pos, + referent, + program, + sourceFiles, + cancellationToken, + ); if (entries) { for (const entry of entries) { for (const reference of entry.references) { @@ -382,7 +566,8 @@ function mayDeleteParameter(checker: TypeChecker, sourceFile: SourceFile, parame && isCallExpression(reference.node.parent.parent) && reference.node.parent.parent.arguments.length > index; // parameter in overridden or overriding method - const isOverriddenMethod = (isMethodDeclaration(reference.node.parent) || isMethodSignature(reference.node.parent)) + const isOverriddenMethod = + (isMethodDeclaration(reference.node.parent) || isMethodSignature(reference.node.parent)) && reference.node.parent !== parameter.parent && reference.node.parent.parameters.length > index; if (isSuperCall || isSuperMethodCall || isOverriddenMethod) return false; @@ -416,20 +601,27 @@ function mayDeleteParameter(checker: TypeChecker, sourceFile: SourceFile, parame } function isCallbackLike(checker: TypeChecker, sourceFile: SourceFile, name: Identifier): boolean { - return !!FindAllReferences.Core.eachSymbolReferenceInFile(name, checker, sourceFile, reference => - isIdentifier(reference) && isCallExpression(reference.parent) && reference.parent.arguments.indexOf(reference) >= 0); + return !!FindAllReferences.Core.eachSymbolReferenceInFile( + name, + checker, + sourceFile, + reference => + isIdentifier(reference) && isCallExpression(reference.parent) + && reference.parent.arguments.indexOf(reference) >= 0, + ); } function isLastParameter(func: FunctionLikeDeclaration, parameter: ParameterDeclaration, isFixAll: boolean): boolean { const parameters = func.parameters; const index = parameters.indexOf(parameter); Debug.assert(index !== -1, "The parameter should already be in the list"); - return isFixAll ? - parameters.slice(index + 1).every(p => isIdentifier(p.name) && !p.symbol.isReferenced) : - index === parameters.length - 1; + return isFixAll + ? parameters.slice(index + 1).every(p => isIdentifier(p.name) && !p.symbol.isReferenced) + : index === parameters.length - 1; } function mayDeleteExpression(node: Node) { - return ((isBinaryExpression(node.parent) && node.parent.left === node) || - ((isPostfixUnaryExpression(node.parent) || isPrefixUnaryExpression(node.parent)) && node.parent.operand === node)) && isExpressionStatement(node.parent.parent); + return ((isBinaryExpression(node.parent) && node.parent.left === node) + || ((isPostfixUnaryExpression(node.parent) || isPrefixUnaryExpression(node.parent)) + && node.parent.operand === node)) && isExpressionStatement(node.parent.parent); } diff --git a/src/services/codefixes/fixUnusedLabel.ts b/src/services/codefixes/fixUnusedLabel.ts index 88e6aed5d41a6..c30b26f5a405a 100644 --- a/src/services/codefixes/fixUnusedLabel.ts +++ b/src/services/codefixes/fixUnusedLabel.ts @@ -21,11 +21,23 @@ const errorCodes = [Diagnostics.Unused_label.code]; registerCodeFix({ errorCodes, getCodeActions(context) { - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start)); - return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unused_label, fixId, Diagnostics.Remove_all_unused_labels)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, context.sourceFile, context.span.start), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Remove_unused_label, + fixId, + Diagnostics.Remove_all_unused_labels, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start)), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start)), }); function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number): void { @@ -35,6 +47,10 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, st const statementPos = labeledStatement.statement.getStart(sourceFile); // If label is on a separate line, just delete the rest of that line, but not the indentation of the labeled statement. const end = positionsAreOnSameLine(pos, statementPos, sourceFile) ? statementPos - : skipTrivia(sourceFile.text, findChildOfKind(labeledStatement, SyntaxKind.ColonToken, sourceFile)!.end, /*stopAfterLineBreak*/ true); + : skipTrivia( + sourceFile.text, + findChildOfKind(labeledStatement, SyntaxKind.ColonToken, sourceFile)!.end, + /*stopAfterLineBreak*/ true, + ); changes.deleteRange(sourceFile, { pos, end }); } diff --git a/src/services/codefixes/generateAccessors.ts b/src/services/codefixes/generateAccessors.ts index 772abe45614af..dc1f226d06c57 100644 --- a/src/services/codefixes/generateAccessors.ts +++ b/src/services/codefixes/generateAccessors.ts @@ -80,7 +80,14 @@ export interface AccessorInfo { } /** @internal */ -export function generateAccessorFromProperty(file: SourceFile, program: Program, start: number, end: number, context: textChanges.TextChangesContext, _actionName: string): FileTextChanges[] | undefined { +export function generateAccessorFromProperty( + file: SourceFile, + program: Program, + start: number, + end: number, + context: textChanges.TextChangesContext, + _actionName: string, +): FileTextChanges[] | undefined { const fieldInfo = getAccessorConvertiblePropertyAtPosition(file, program, start, end); if (!fieldInfo || refactor.isRefactorErrorInfo(fieldInfo)) return undefined; @@ -102,7 +109,9 @@ export function generateAccessorFromProperty(file: SourceFile, program: Program, fieldModifiers = modifiers; } else { - accessorModifiers = factory.createModifiersFromModifierFlags(prepareModifierFlagsForAccessor(modifierFlags)); + accessorModifiers = factory.createModifiersFromModifierFlags( + prepareModifierFlagsForAccessor(modifierFlags), + ); fieldModifiers = factory.createModifiersFromModifierFlags(prepareModifierFlagsForField(modifierFlags)); } if (canHaveDecorators(declaration)) { @@ -120,7 +129,13 @@ export function generateAccessorFromProperty(file: SourceFile, program: Program, // readonly modifier only existed in classLikeDeclaration const constructor = getFirstConstructorWithBody(container as ClassLikeDeclaration); if (constructor) { - updateReadonlyPropertyInitializerStatementConstructor(changeTracker, file, constructor, fieldName.text, originalName); + updateReadonlyPropertyInitializerStatementConstructor( + changeTracker, + file, + constructor, + fieldName.text, + originalName, + ); } } else { @@ -137,16 +152,22 @@ function isConvertibleName(name: DeclarationName): name is AcceptedNameType { } function isAcceptedDeclaration(node: Node): node is AcceptedDeclaration { - return isParameterPropertyDeclaration(node, node.parent) || isPropertyDeclaration(node) || isPropertyAssignment(node); + return isParameterPropertyDeclaration(node, node.parent) || isPropertyDeclaration(node) + || isPropertyAssignment(node); } function createPropertyName(name: string, originalName: AcceptedNameType) { return isIdentifier(originalName) ? factory.createIdentifier(name) : factory.createStringLiteral(name); } -function createAccessorAccessExpression(fieldName: AcceptedNameType, isStatic: boolean, container: ContainerDeclaration) { +function createAccessorAccessExpression( + fieldName: AcceptedNameType, + isStatic: boolean, + container: ContainerDeclaration, +) { const leftHead = isStatic ? (container as ClassLikeDeclaration).name! : factory.createThis(); // TODO: GH#18217 - return isIdentifier(fieldName) ? factory.createPropertyAccessExpression(leftHead, fieldName) : factory.createElementAccessExpression(leftHead, factory.createStringLiteralFromNode(fieldName)); + return isIdentifier(fieldName) ? factory.createPropertyAccessExpression(leftHead, fieldName) + : factory.createElementAccessExpression(leftHead, factory.createStringLiteralFromNode(fieldName)); } function prepareModifierFlagsForAccessor(modifierFlags: ModifierFlags): ModifierFlags { @@ -168,7 +189,13 @@ function prepareModifierFlagsForField(modifierFlags: ModifierFlags): ModifierFla } /** @internal */ -export function getAccessorConvertiblePropertyAtPosition(file: SourceFile, program: Program, start: number, end: number, considerEmptySpans = true): AccessorOrRefactorErrorInfo | undefined { +export function getAccessorConvertiblePropertyAtPosition( + file: SourceFile, + program: Program, + start: number, + end: number, + considerEmptySpans = true, +): AccessorOrRefactorErrorInfo | undefined { const node = getTokenAtPosition(file, start); const cursorRequest = start === end && considerEmptySpans; const declaration = findAncestor(node.parent, isAcceptedDeclaration); @@ -177,26 +204,32 @@ export function getAccessorConvertiblePropertyAtPosition(file: SourceFile, progr if (!declaration || (!(nodeOverlapsWithStartEnd(declaration.name, file, start, end) || cursorRequest))) { return { - error: getLocaleSpecificMessage(Diagnostics.Could_not_find_property_for_which_to_generate_accessor) + error: getLocaleSpecificMessage(Diagnostics.Could_not_find_property_for_which_to_generate_accessor), }; } if (!isConvertibleName(declaration.name)) { return { - error: getLocaleSpecificMessage(Diagnostics.Name_is_not_valid) + error: getLocaleSpecificMessage(Diagnostics.Name_is_not_valid), }; } if (((getEffectiveModifierFlags(declaration) & ModifierFlags.Modifier) | meaning) !== meaning) { return { - error: getLocaleSpecificMessage(Diagnostics.Can_only_convert_property_with_modifier) + error: getLocaleSpecificMessage(Diagnostics.Can_only_convert_property_with_modifier), }; } const name = declaration.name.text; const startWithUnderscore = startsWithUnderscore(name); - const fieldName = createPropertyName(startWithUnderscore ? name : getUniqueName(`_${name}`, file), declaration.name); - const accessorName = createPropertyName(startWithUnderscore ? getUniqueName(name.substring(1), file) : name, declaration.name); + const fieldName = createPropertyName( + startWithUnderscore ? name : getUniqueName(`_${name}`, file), + declaration.name, + ); + const accessorName = createPropertyName( + startWithUnderscore ? getUniqueName(name.substring(1), file) : name, + declaration.name, + ); return { isStatic: hasStaticModifier(declaration), isReadonly: hasEffectiveReadonlyModifier(declaration), @@ -206,11 +239,18 @@ export function getAccessorConvertiblePropertyAtPosition(file: SourceFile, progr declaration, fieldName, accessorName, - renameAccessor: startWithUnderscore + renameAccessor: startWithUnderscore, }; } -function generateGetAccessor(fieldName: AcceptedNameType, accessorName: AcceptedNameType, type: TypeNode | undefined, modifiers: readonly ModifierLike[] | undefined, isStatic: boolean, container: ContainerDeclaration) { +function generateGetAccessor( + fieldName: AcceptedNameType, + accessorName: AcceptedNameType, + type: TypeNode | undefined, + modifiers: readonly ModifierLike[] | undefined, + isStatic: boolean, + container: ContainerDeclaration, +) { return factory.createGetAccessorDeclaration( modifiers, accessorName, @@ -218,13 +258,20 @@ function generateGetAccessor(fieldName: AcceptedNameType, accessorName: Accepted type, factory.createBlock([ factory.createReturnStatement( - createAccessorAccessExpression(fieldName, isStatic, container) - ) - ], /*multiLine*/ true) + createAccessorAccessExpression(fieldName, isStatic, container), + ), + ], /*multiLine*/ true), ); } -function generateSetAccessor(fieldName: AcceptedNameType, accessorName: AcceptedNameType, type: TypeNode | undefined, modifiers: readonly ModifierLike[] | undefined, isStatic: boolean, container: ContainerDeclaration) { +function generateSetAccessor( + fieldName: AcceptedNameType, + accessorName: AcceptedNameType, + type: TypeNode | undefined, + modifiers: readonly ModifierLike[] | undefined, + isStatic: boolean, + container: ContainerDeclaration, +) { return factory.createSetAccessorDeclaration( modifiers, accessorName, @@ -233,32 +280,44 @@ function generateSetAccessor(fieldName: AcceptedNameType, accessorName: Accepted /*dotDotDotToken*/ undefined, factory.createIdentifier("value"), /*questionToken*/ undefined, - type + type, )], factory.createBlock([ factory.createExpressionStatement( factory.createAssignment( createAccessorAccessExpression(fieldName, isStatic, container), - factory.createIdentifier("value") - ) - ) - ], /*multiLine*/ true) + factory.createIdentifier("value"), + ), + ), + ], /*multiLine*/ true), ); } -function updatePropertyDeclaration(changeTracker: textChanges.ChangeTracker, file: SourceFile, declaration: PropertyDeclaration, type: TypeNode | undefined, fieldName: AcceptedNameType, modifiers: readonly ModifierLike[] | undefined) { +function updatePropertyDeclaration( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + declaration: PropertyDeclaration, + type: TypeNode | undefined, + fieldName: AcceptedNameType, + modifiers: readonly ModifierLike[] | undefined, +) { const property = factory.updatePropertyDeclaration( declaration, modifiers, fieldName, declaration.questionToken || declaration.exclamationToken, type, - declaration.initializer + declaration.initializer, ); changeTracker.replaceNode(file, declaration, property); } -function updatePropertyAssignmentDeclaration(changeTracker: textChanges.ChangeTracker, file: SourceFile, declaration: PropertyAssignment, fieldName: AcceptedNameType) { +function updatePropertyAssignmentDeclaration( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + declaration: PropertyAssignment, + fieldName: AcceptedNameType, +) { let assignment = factory.updatePropertyAssignment(declaration, fieldName, declaration.initializer); // Remove grammar errors from assignment if (assignment.modifiers || assignment.questionToken || assignment.exclamationToken) { @@ -270,7 +329,14 @@ function updatePropertyAssignmentDeclaration(changeTracker: textChanges.ChangeTr changeTracker.replacePropertyAssignment(file, declaration, assignment); } -function updateFieldDeclaration(changeTracker: textChanges.ChangeTracker, file: SourceFile, declaration: AcceptedDeclaration, type: TypeNode | undefined, fieldName: AcceptedNameType, modifiers: readonly ModifierLike[] | undefined) { +function updateFieldDeclaration( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + declaration: AcceptedDeclaration, + type: TypeNode | undefined, + fieldName: AcceptedNameType, + modifiers: readonly ModifierLike[] | undefined, +) { if (isPropertyDeclaration(declaration)) { updatePropertyDeclaration(changeTracker, file, declaration, type, fieldName, modifiers); } @@ -278,28 +344,57 @@ function updateFieldDeclaration(changeTracker: textChanges.ChangeTracker, file: updatePropertyAssignmentDeclaration(changeTracker, file, declaration, fieldName); } else { - changeTracker.replaceNode(file, declaration, - factory.updateParameterDeclaration(declaration, modifiers, declaration.dotDotDotToken, cast(fieldName, isIdentifier), declaration.questionToken, declaration.type, declaration.initializer)); + changeTracker.replaceNode( + file, + declaration, + factory.updateParameterDeclaration( + declaration, + modifiers, + declaration.dotDotDotToken, + cast(fieldName, isIdentifier), + declaration.questionToken, + declaration.type, + declaration.initializer, + ), + ); } } -function insertAccessor(changeTracker: textChanges.ChangeTracker, file: SourceFile, accessor: AccessorDeclaration, declaration: AcceptedDeclaration, container: ContainerDeclaration) { - isParameterPropertyDeclaration(declaration, declaration.parent) ? changeTracker.insertMemberAtStart(file, container as ClassLikeDeclaration, accessor) : - isPropertyAssignment(declaration) ? changeTracker.insertNodeAfterComma(file, declaration, accessor) : - changeTracker.insertNodeAfter(file, declaration, accessor); +function insertAccessor( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + accessor: AccessorDeclaration, + declaration: AcceptedDeclaration, + container: ContainerDeclaration, +) { + isParameterPropertyDeclaration(declaration, declaration.parent) + ? changeTracker.insertMemberAtStart(file, container as ClassLikeDeclaration, accessor) + : isPropertyAssignment(declaration) ? changeTracker.insertNodeAfterComma(file, declaration, accessor) + : changeTracker.insertNodeAfter(file, declaration, accessor); } -function updateReadonlyPropertyInitializerStatementConstructor(changeTracker: textChanges.ChangeTracker, file: SourceFile, constructor: ConstructorDeclaration, fieldName: string, originalName: string) { +function updateReadonlyPropertyInitializerStatementConstructor( + changeTracker: textChanges.ChangeTracker, + file: SourceFile, + constructor: ConstructorDeclaration, + fieldName: string, + originalName: string, +) { if (!constructor.body) return; constructor.body.forEachChild(function recur(node) { - if (isElementAccessExpression(node) && - node.expression.kind === SyntaxKind.ThisKeyword && - isStringLiteral(node.argumentExpression) && - node.argumentExpression.text === originalName && - isWriteAccess(node)) { + if ( + isElementAccessExpression(node) + && node.expression.kind === SyntaxKind.ThisKeyword + && isStringLiteral(node.argumentExpression) + && node.argumentExpression.text === originalName + && isWriteAccess(node) + ) { changeTracker.replaceNode(file, node.argumentExpression, factory.createStringLiteral(fieldName)); } - if (isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword && node.name.text === originalName && isWriteAccess(node)) { + if ( + isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.ThisKeyword + && node.name.text === originalName && isWriteAccess(node) + ) { changeTracker.replaceNode(file, node.name, factory.createIdentifier(fieldName)); } if (!isFunctionLike(node) && !isClassLike(node)) { diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 1116d70c19ccf..659a2ce917999 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -112,7 +112,9 @@ import { visitNode, visitNodes, } from "../_namespaces/ts"; -import { ImportAdder } from "../_namespaces/ts.codefix"; +import { + ImportAdder, +} from "../_namespaces/ts.codefix"; /** * Finds members of the resolved type that are missing in the class pointed to by class decl @@ -130,11 +132,21 @@ export function createMissingMemberNodes( context: TypeConstructionContext, preferences: UserPreferences, importAdder: ImportAdder | undefined, - addClassElement: (node: AddNode) => void): void { + addClassElement: (node: AddNode) => void, +): void { const classMembers = classDeclaration.symbol.members!; for (const symbol of possiblyMissingSymbols) { if (!classMembers.has(symbol.escapedName)) { - addNewNodeForMemberSymbol(symbol, classDeclaration, sourceFile, context, preferences, importAdder, addClassElement, /*body*/ undefined); + addNewNodeForMemberSymbol( + symbol, + classDeclaration, + sourceFile, + context, + preferences, + importAdder, + addClassElement, + /*body*/ undefined, + ); } } } @@ -154,13 +166,19 @@ export interface TypeConstructionContext { } /** @internal */ -export type AddNode = PropertyDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction; +export type AddNode = + | PropertyDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration + | MethodDeclaration + | FunctionExpression + | ArrowFunction; /** @internal */ export const enum PreserveOptionalFlags { - Method = 1 << 0, + Method = 1 << 0, Property = 1 << 1, - All = Method | Property + All = Method | Property, } /** @@ -204,10 +222,9 @@ export function addNewNodeForMemberSymbol( const declarationName = createDeclarationName(symbol, declaration); const effectiveModifierFlags = declaration ? getEffectiveModifierFlags(declaration) : ModifierFlags.None; let modifierFlags = effectiveModifierFlags & ModifierFlags.Static; - modifierFlags |= - effectiveModifierFlags & ModifierFlags.Public ? ModifierFlags.Public : - effectiveModifierFlags & ModifierFlags.Protected ? ModifierFlags.Protected : - ModifierFlags.None; + modifierFlags |= effectiveModifierFlags & ModifierFlags.Public ? ModifierFlags.Public + : effectiveModifierFlags & ModifierFlags.Protected ? ModifierFlags.Protected + : ModifierFlags.None; if (declaration && isAutoAccessorPropertyDeclaration(declaration)) { modifierFlags |= ModifierFlags.Accessor; } @@ -220,8 +237,14 @@ export function addNewNodeForMemberSymbol( switch (kind) { case SyntaxKind.PropertySignature: case SyntaxKind.PropertyDeclaration: - const flags = quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : undefined; - let typeNode = checker.typeToTypeNode(type, enclosingDeclaration, flags, getNoopSymbolTrackerWithResolver(context)); + const flags = quotePreference === QuotePreference.Single + ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : undefined; + let typeNode = checker.typeToTypeNode( + type, + enclosingDeclaration, + flags, + getNoopSymbolTrackerWithResolver(context), + ); if (importAdder) { const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget); if (importableReference) { @@ -232,14 +255,21 @@ export function addNewNodeForMemberSymbol( addClassElement(factory.createPropertyDeclaration( modifiers, declaration ? createName(declarationName) : symbol.getName(), - optional && (preserveOptional & PreserveOptionalFlags.Property) ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + optional && (preserveOptional & PreserveOptionalFlags.Property) + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, typeNode, - /*initializer*/ undefined)); + /*initializer*/ undefined, + )); break; case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: { Debug.assertIsDefined(declarations); - let typeNode = checker.typeToTypeNode(type, enclosingDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context)); + let typeNode = checker.typeToTypeNode( + type, + enclosingDeclaration, + /*flags*/ undefined, + getNoopSymbolTrackerWithResolver(context), + ); const allAccessors = getAllAccessorDeclarations(declarations, declaration as AccessorDeclaration); const orderedAccessors = allAccessors.secondAccessor ? [allAccessors.firstAccessor, allAccessors.secondAccessor] @@ -258,17 +288,24 @@ export function addNewNodeForMemberSymbol( createName(declarationName), emptyArray, createTypeNode(typeNode), - createBody(body, quotePreference, ambient))); + createBody(body, quotePreference, ambient), + )); } else { - Debug.assertNode(accessor, isSetAccessorDeclaration, "The counterpart to a getter should be a setter"); + Debug.assertNode( + accessor, + isSetAccessorDeclaration, + "The counterpart to a getter should be a setter", + ); const parameter = getSetAccessorValueParameter(accessor); - const parameterName = parameter && isIdentifier(parameter.name) ? idText(parameter.name) : undefined; + const parameterName = parameter && isIdentifier(parameter.name) ? idText(parameter.name) + : undefined; addClassElement(factory.createSetAccessorDeclaration( modifiers, createName(declarationName), createDummyParameters(1, [parameterName], [createTypeNode(typeNode)], 1, /*inJs*/ false), - createBody(body, quotePreference, ambient))); + createBody(body, quotePreference, ambient), + )); } } break; @@ -283,7 +320,8 @@ export function addNewNodeForMemberSymbol( // (eg: an abstract method or interface declaration), there is a 1-1 // correspondence of declarations and signatures. Debug.assertIsDefined(declarations); - const signatures = type.isUnion() ? flatMap(type.types, t => t.getCallSignatures()) : type.getCallSignatures(); + const signatures = type.isUnion() ? flatMap(type.types, t => t.getCallSignatures()) + : type.getCallSignatures(); if (!some(signatures)) { break; } @@ -291,7 +329,13 @@ export function addNewNodeForMemberSymbol( if (declarations.length === 1) { Debug.assert(signatures.length === 1, "One declaration implies one signature"); const signature = signatures[0]; - outputMethod(quotePreference, signature, modifiers, createName(declarationName), createBody(body, quotePreference, ambient)); + outputMethod( + quotePreference, + signature, + modifiers, + createName(declarationName), + createBody(body, quotePreference, ambient), + ); break; } @@ -302,19 +346,59 @@ export function addNewNodeForMemberSymbol( if (!ambient) { if (declarations.length > signatures.length) { - const signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration)!; - outputMethod(quotePreference, signature, modifiers, createName(declarationName), createBody(body, quotePreference)); + const signature = checker.getSignatureFromDeclaration( + declarations[declarations.length - 1] as SignatureDeclaration, + )!; + outputMethod( + quotePreference, + signature, + modifiers, + createName(declarationName), + createBody(body, quotePreference), + ); } else { - Debug.assert(declarations.length === signatures.length, "Declarations and signatures should match count"); - addClassElement(createMethodImplementingSignatures(checker, context, enclosingDeclaration, signatures, createName(declarationName), optional && !!(preserveOptional & PreserveOptionalFlags.Method), modifiers, quotePreference, body)); + Debug.assert( + declarations.length === signatures.length, + "Declarations and signatures should match count", + ); + addClassElement( + createMethodImplementingSignatures( + checker, + context, + enclosingDeclaration, + signatures, + createName(declarationName), + optional && !!(preserveOptional & PreserveOptionalFlags.Method), + modifiers, + quotePreference, + body, + ), + ); } } break; } - function outputMethod(quotePreference: QuotePreference, signature: Signature, modifiers: NodeArray | undefined, name: PropertyName, body?: Block): void { - const method = createSignatureDeclarationFromSignature(SyntaxKind.MethodDeclaration, context, quotePreference, signature, body, name, modifiers, optional && !!(preserveOptional & PreserveOptionalFlags.Method), enclosingDeclaration, importAdder) as MethodDeclaration; + function outputMethod( + quotePreference: QuotePreference, + signature: Signature, + modifiers: NodeArray | undefined, + name: PropertyName, + body?: Block, + ): void { + const method = createSignatureDeclarationFromSignature( + SyntaxKind.MethodDeclaration, + context, + quotePreference, + signature, + body, + name, + modifiers, + optional && !!(preserveOptional & PreserveOptionalFlags.Method), + enclosingDeclaration, + importAdder, + ) as MethodDeclaration; if (method) addClassElement(method); } @@ -333,19 +417,22 @@ export function addNewNodeForMemberSymbol( } function shouldAddOverrideKeyword(): boolean { - return !!(context.program.getCompilerOptions().noImplicitOverride && declaration && hasAbstractModifier(declaration)); + return !!(context.program.getCompilerOptions().noImplicitOverride && declaration + && hasAbstractModifier(declaration)); } function createName(node: PropertyName) { if (isIdentifier(node) && node.escapedText === "constructor") { - return factory.createComputedPropertyName(factory.createStringLiteral(idText(node), quotePreference === QuotePreference.Single)); + return factory.createComputedPropertyName( + factory.createStringLiteral(idText(node), quotePreference === QuotePreference.Single), + ); } return getSynthesizedDeepClone(node, /*includeTrivia*/ false); } function createBody(block: Block | undefined, quotePreference: QuotePreference, ambient?: boolean) { - return ambient ? undefined : - getSynthesizedDeepClone(block, /*includeTrivia*/ false) || createStubbedMethodBody(quotePreference); + return ambient ? undefined + : getSynthesizedDeepClone(block, /*includeTrivia*/ false) || createStubbedMethodBody(quotePreference); } function createTypeNode(typeNode: TypeNode | undefined) { @@ -378,18 +465,24 @@ export function createSignatureDeclarationFromSignature( modifiers: NodeArray | undefined, optional: boolean | undefined, enclosingDeclaration: Node | undefined, - importAdder: ImportAdder | undefined + importAdder: ImportAdder | undefined, ) { const program = context.program; const checker = program.getTypeChecker(); const scriptTarget = getEmitScriptTarget(program.getCompilerOptions()); const isJs = isInJSFile(enclosingDeclaration); - const flags = - NodeBuilderFlags.NoTruncation + const flags = NodeBuilderFlags.NoTruncation | NodeBuilderFlags.SuppressAnyReturnType | NodeBuilderFlags.AllowEmptyTuple - | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : NodeBuilderFlags.None); - const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, kind, enclosingDeclaration, flags, getNoopSymbolTrackerWithResolver(context)) as ArrowFunction | FunctionExpression | MethodDeclaration | FunctionDeclaration; + | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType + : NodeBuilderFlags.None); + const signatureDeclaration = checker.signatureToSignatureDeclaration( + signature, + kind, + enclosingDeclaration, + flags, + getNoopSymbolTrackerWithResolver(context), + ) as ArrowFunction | FunctionExpression | MethodDeclaration | FunctionDeclaration; if (!signatureDeclaration) { return undefined; } @@ -421,11 +514,14 @@ export function createSignatureDeclarationFromSignature( typeParameterDecl.modifiers, typeParameterDecl.name, constraint, - defaultType + defaultType, ); }); if (typeParameters !== newTypeParameters) { - typeParameters = setTextRange(factory.createNodeArray(newTypeParameters, typeParameters.hasTrailingComma), typeParameters); + typeParameters = setTextRange( + factory.createNodeArray(newTypeParameters, typeParameters.hasTrailingComma), + typeParameters, + ); } } const newParameters = sameMap(parameters, parameterDecl => { @@ -444,7 +540,7 @@ export function createSignatureDeclarationFromSignature( parameterDecl.name, isJs ? undefined : parameterDecl.questionToken, type, - parameterDecl.initializer + parameterDecl.initializer, ); }); if (parameters !== newParameters) { @@ -462,16 +558,52 @@ export function createSignatureDeclarationFromSignature( const questionToken = optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; const asteriskToken = signatureDeclaration.asteriskToken; if (isFunctionExpression(signatureDeclaration)) { - return factory.updateFunctionExpression(signatureDeclaration, modifiers, signatureDeclaration.asteriskToken, tryCast(name, isIdentifier), typeParameters, parameters, type, body ?? signatureDeclaration.body); + return factory.updateFunctionExpression( + signatureDeclaration, + modifiers, + signatureDeclaration.asteriskToken, + tryCast(name, isIdentifier), + typeParameters, + parameters, + type, + body ?? signatureDeclaration.body, + ); } if (isArrowFunction(signatureDeclaration)) { - return factory.updateArrowFunction(signatureDeclaration, modifiers, typeParameters, parameters, type, signatureDeclaration.equalsGreaterThanToken, body ?? signatureDeclaration.body); + return factory.updateArrowFunction( + signatureDeclaration, + modifiers, + typeParameters, + parameters, + type, + signatureDeclaration.equalsGreaterThanToken, + body ?? signatureDeclaration.body, + ); } if (isMethodDeclaration(signatureDeclaration)) { - return factory.updateMethodDeclaration(signatureDeclaration, modifiers, asteriskToken, name ?? factory.createIdentifier(""), questionToken, typeParameters, parameters, type, body); + return factory.updateMethodDeclaration( + signatureDeclaration, + modifiers, + asteriskToken, + name ?? factory.createIdentifier(""), + questionToken, + typeParameters, + parameters, + type, + body, + ); } if (isFunctionDeclaration(signatureDeclaration)) { - return factory.updateFunctionDeclaration(signatureDeclaration, modifiers, signatureDeclaration.asteriskToken, tryCast(name, isIdentifier), typeParameters, parameters, type, body ?? signatureDeclaration.body); + return factory.updateFunctionDeclaration( + signatureDeclaration, + modifiers, + signatureDeclaration.asteriskToken, + tryCast(name, isIdentifier), + typeParameters, + parameters, + type, + body ?? signatureDeclaration.body, + ); } return undefined; } @@ -484,7 +616,7 @@ export function createSignatureDeclarationFromCallExpression( call: CallExpression, name: Identifier | PrivateIdentifier | string, modifierFlags: ModifierFlags, - contextNode: Node + contextNode: Node, ): MethodDeclaration | FunctionDeclaration | MethodSignature { const quotePreference = getQuotePreference(context.sourceFile, context.preferences); const scriptTarget = getEmitScriptTarget(context.program.getCompilerOptions()); @@ -494,11 +626,21 @@ export function createSignatureDeclarationFromCallExpression( const { typeArguments, arguments: args, parent } = call; const contextualType = isJs ? undefined : checker.getContextualType(call); - const names = map(args, arg => - isIdentifier(arg) ? arg.text : isPropertyAccessExpression(arg) && isIdentifier(arg.name) ? arg.name.text : undefined); + const names = map( + args, + arg => + isIdentifier(arg) ? arg.text + : isPropertyAccessExpression(arg) && isIdentifier(arg.name) ? arg.name.text : undefined, + ); const instanceTypes = isJs ? [] : map(args, arg => checker.getTypeAtLocation(arg)); const { argumentTypeNodes, argumentTypeParameters } = getArgumentTypesAndTypeParameters( - checker, importAdder, instanceTypes, contextNode, scriptTarget, NodeBuilderFlags.NoTruncation, tracker + checker, + importAdder, + instanceTypes, + contextNode, + scriptTarget, + NodeBuilderFlags.NoTruncation, + tracker, ); const modifiers = modifierFlags @@ -507,8 +649,15 @@ export function createSignatureDeclarationFromCallExpression( const asteriskToken = isYieldExpression(parent) ? factory.createToken(SyntaxKind.AsteriskToken) : undefined; - const typeParameters = isJs ? undefined : createTypeParametersForArguments(checker, argumentTypeParameters, typeArguments); - const parameters = createDummyParameters(args.length, names, argumentTypeNodes, /*minArgumentCount*/ undefined, isJs); + const typeParameters = isJs ? undefined + : createTypeParametersForArguments(checker, argumentTypeParameters, typeArguments); + const parameters = createDummyParameters( + args.length, + names, + argumentTypeNodes, + /*minArgumentCount*/ undefined, + isJs, + ); const type = isJs || contextualType === undefined ? undefined : checker.typeToTypeNode(contextualType, contextNode, /*flags*/ undefined, tracker); @@ -523,7 +672,7 @@ export function createSignatureDeclarationFromCallExpression( typeParameters, parameters, type, - createStubbedMethodBody(quotePreference) + createStubbedMethodBody(quotePreference), ); case SyntaxKind.MethodSignature: return factory.createMethodSignature( @@ -532,7 +681,7 @@ export function createSignatureDeclarationFromCallExpression( /*questionToken*/ undefined, typeParameters, parameters, - type === undefined ? factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword) : type + type === undefined ? factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword) : type, ); case SyntaxKind.FunctionDeclaration: Debug.assert(typeof name === "string" || isIdentifier(name), "Unexpected name"); @@ -543,7 +692,7 @@ export function createSignatureDeclarationFromCallExpression( typeParameters, parameters, type, - createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference) + createStubbedBody(Diagnostics.Function_not_implemented.message, quotePreference), ); default: Debug.fail("Unexpected kind"); @@ -556,12 +705,18 @@ export interface ArgumentTypeParameterAndConstraint { constraint?: TypeNode; } -function createTypeParametersForArguments(checker: TypeChecker, argumentTypeParameters: [string, ArgumentTypeParameterAndConstraint | undefined][], typeArguments: NodeArray | undefined) { +function createTypeParametersForArguments( + checker: TypeChecker, + argumentTypeParameters: [string, ArgumentTypeParameterAndConstraint | undefined][], + typeArguments: NodeArray | undefined, +) { const usedNames = new Set(argumentTypeParameters.map(pair => pair[0])); const constraintsByName = new Map(argumentTypeParameters); if (typeArguments) { - const typeArgumentsWithNewTypes = typeArguments.filter(typeArgument => !argumentTypeParameters.some(pair => checker.getTypeAtLocation(typeArgument) === pair[1]?.argumentType)); + const typeArgumentsWithNewTypes = typeArguments.filter(typeArgument => + !argumentTypeParameters.some(pair => checker.getTypeAtLocation(typeArgument) === pair[1]?.argumentType) + ); const targetSize = usedNames.size + typeArgumentsWithNewTypes.length; for (let i = 0; usedNames.size < targetSize; i += 1) { usedNames.add(createTypeParameterName(i)); @@ -570,7 +725,12 @@ function createTypeParametersForArguments(checker: TypeChecker, argumentTypePara return arrayFrom( usedNames.values(), - usedName => factory.createTypeParameterDeclaration(/*modifiers*/ undefined, usedName, constraintsByName.get(usedName)?.constraint), + usedName => + factory.createTypeParameterDeclaration( + /*modifiers*/ undefined, + usedName, + constraintsByName.get(usedName)?.constraint, + ), ); } @@ -581,7 +741,15 @@ function createTypeParameterName(index: number) { } /** @internal */ -export function typeToAutoImportableTypeNode(checker: TypeChecker, importAdder: ImportAdder, type: Type, contextNode: Node | undefined, scriptTarget: ScriptTarget, flags?: NodeBuilderFlags, tracker?: SymbolTracker): TypeNode | undefined { +export function typeToAutoImportableTypeNode( + checker: TypeChecker, + importAdder: ImportAdder, + type: Type, + contextNode: Node | undefined, + scriptTarget: ScriptTarget, + flags?: NodeBuilderFlags, + tracker?: SymbolTracker, +): TypeNode | undefined { let typeNode = checker.typeToTypeNode(type, contextNode, flags, tracker); if (typeNode && isImportTypeNode(typeNode)) { const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget); @@ -604,7 +772,15 @@ function typeContainsTypeParameter(type: Type) { } /** @internal */ -export function getArgumentTypesAndTypeParameters(checker: TypeChecker, importAdder: ImportAdder, instanceTypes: Type[], contextNode: Node | undefined, scriptTarget: ScriptTarget, flags?: NodeBuilderFlags, tracker?: SymbolTracker) { +export 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) @@ -647,7 +823,15 @@ export function getArgumentTypesAndTypeParameters(checker: TypeChecker, importAd // Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {" const widenedInstanceType = checker.getBaseTypeOfLiteralType(instanceType); - const argumentTypeNode = typeToAutoImportableTypeNode(checker, importAdder, widenedInstanceType, contextNode, scriptTarget, flags, tracker); + const argumentTypeNode = typeToAutoImportableTypeNode( + checker, + importAdder, + widenedInstanceType, + contextNode, + scriptTarget, + flags, + tracker, + ); if (!argumentTypeNode) { continue; } @@ -664,12 +848,24 @@ export function getArgumentTypesAndTypeParameters(checker: TypeChecker, importAd // function added(value: T) { ... } // We instead want to output: // function added(value: T) { ... } - const instanceTypeConstraint = instanceType.isTypeParameter() && instanceType.constraint && !isAnonymousObjectConstraintType(instanceType.constraint) - ? typeToAutoImportableTypeNode(checker, importAdder, instanceType.constraint, contextNode, scriptTarget, flags, tracker) + const instanceTypeConstraint = instanceType.isTypeParameter() && instanceType.constraint + && !isAnonymousObjectConstraintType(instanceType.constraint) + ? typeToAutoImportableTypeNode( + checker, + importAdder, + instanceType.constraint, + contextNode, + scriptTarget, + flags, + tracker, + ) : undefined; if (argumentTypeParameter) { - argumentTypeParameters.set(argumentTypeParameter, { argumentType: instanceType, constraint: instanceTypeConstraint }); + argumentTypeParameters.set(argumentTypeParameter, { + argumentType: instanceType, + constraint: instanceTypeConstraint, + }); } } @@ -695,7 +891,13 @@ function getFirstTypeParameterName(type: Type): string | undefined { : undefined; } -function createDummyParameters(argCount: number, names: (string | undefined)[] | undefined, types: (TypeNode | undefined)[] | undefined, minArgumentCount: number | undefined, inJs: boolean): ParameterDeclaration[] { +function createDummyParameters( + argCount: number, + names: (string | undefined)[] | undefined, + types: (TypeNode | undefined)[] | undefined, + minArgumentCount: number | undefined, + inJs: boolean, +): ParameterDeclaration[] { const parameters: ParameterDeclaration[] = []; const parameterNameCounts = new Map(); for (let i = 0; i < argCount; i++) { @@ -707,9 +909,11 @@ function createDummyParameters(argCount: number, names: (string | undefined)[] | /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ parameterName + (parameterNameCount || ""), - /*questionToken*/ minArgumentCount !== undefined && i >= minArgumentCount ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + /*questionToken*/ minArgumentCount !== undefined && i >= minArgumentCount + ? factory.createToken(SyntaxKind.QuestionToken) : undefined, /*type*/ inJs ? undefined : types?.[i] || factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword), - /*initializer*/ undefined); + /*initializer*/ undefined, + ); parameters.push(newParameter); } return parameters; @@ -738,22 +942,33 @@ function createMethodImplementingSignatures( if (signatureHasRestParameter(sig)) { someSigHasRestParameter = true; } - if (sig.parameters.length >= maxArgsSignature.parameters.length && (!signatureHasRestParameter(sig) || signatureHasRestParameter(maxArgsSignature))) { + if ( + sig.parameters.length >= maxArgsSignature.parameters.length + && (!signatureHasRestParameter(sig) || signatureHasRestParameter(maxArgsSignature)) + ) { maxArgsSignature = sig; } } const maxNonRestArgs = maxArgsSignature.parameters.length - (signatureHasRestParameter(maxArgsSignature) ? 1 : 0); const maxArgsParameterSymbolNames = maxArgsSignature.parameters.map(symbol => symbol.name); - const parameters = createDummyParameters(maxNonRestArgs, maxArgsParameterSymbolNames, /*types*/ undefined, minArgumentCount, /*inJs*/ false); + const parameters = createDummyParameters( + maxNonRestArgs, + maxArgsParameterSymbolNames, + /*types*/ undefined, + minArgumentCount, + /*inJs*/ false, + ); if (someSigHasRestParameter) { const restParameter = factory.createParameterDeclaration( /*modifiers*/ undefined, factory.createToken(SyntaxKind.DotDotDotToken), maxArgsParameterSymbolNames[maxNonRestArgs] || "rest", - /*questionToken*/ maxNonRestArgs >= minArgumentCount ? factory.createToken(SyntaxKind.QuestionToken) : undefined, + /*questionToken*/ maxNonRestArgs >= minArgumentCount ? factory.createToken(SyntaxKind.QuestionToken) + : undefined, factory.createArrayTypeNode(factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword)), - /*initializer*/ undefined); + /*initializer*/ undefined, + ); parameters.push(restParameter); } @@ -765,13 +980,24 @@ function createMethodImplementingSignatures( parameters, getReturnTypeFromSignatures(signatures, checker, context, enclosingDeclaration), quotePreference, - body); + body, + ); } -function getReturnTypeFromSignatures(signatures: readonly Signature[], checker: TypeChecker, context: TypeConstructionContext, enclosingDeclaration: ClassLikeDeclaration): TypeNode | undefined { +function getReturnTypeFromSignatures( + signatures: readonly Signature[], + checker: TypeChecker, + context: TypeConstructionContext, + enclosingDeclaration: ClassLikeDeclaration, +): TypeNode | undefined { if (length(signatures)) { const type = checker.getUnionType(map(signatures, checker.getReturnTypeOfSignature)); - return checker.typeToTypeNode(type, enclosingDeclaration, NodeBuilderFlags.NoTruncation, getNoopSymbolTrackerWithResolver(context)); + return checker.typeToTypeNode( + type, + enclosingDeclaration, + NodeBuilderFlags.NoTruncation, + getNoopSymbolTrackerWithResolver(context), + ); } } @@ -783,7 +1009,7 @@ function createStubbedMethod( parameters: readonly ParameterDeclaration[], returnType: TypeNode | undefined, quotePreference: QuotePreference, - body: Block | undefined + body: Block | undefined, ): MethodDeclaration { return factory.createMethodDeclaration( modifiers, @@ -793,7 +1019,8 @@ function createStubbedMethod( typeParameters, parameters, returnType, - body || createStubbedMethodBody(quotePreference)); + body || createStubbedMethodBody(quotePreference), + ); } function createStubbedMethodBody(quotePreference: QuotePreference) { @@ -808,24 +1035,35 @@ export function createStubbedBody(text: string, quotePreference: QuotePreference factory.createIdentifier("Error"), /*typeArguments*/ undefined, // TODO Handle auto quote preference. - [factory.createStringLiteral(text, /*isSingleQuote*/ quotePreference === QuotePreference.Single)]))], - /*multiLine*/ true); + [factory.createStringLiteral(text, /*isSingleQuote*/ quotePreference === QuotePreference.Single)], + ), + )], + /*multiLine*/ true, + ); } /** @internal */ export function setJsonCompilerOptionValues( changeTracker: textChanges.ChangeTracker, configFile: TsConfigSourceFile, - options: [string, Expression][] + options: [string, Expression][], ) { const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression(configFile); if (!tsconfigObjectLiteral) return undefined; const compilerOptionsProperty = findJsonProperty(tsconfigObjectLiteral, "compilerOptions"); if (compilerOptionsProperty === undefined) { - changeTracker.insertNodeAtObjectStart(configFile, tsconfigObjectLiteral, createJsonPropertyAssignment( - "compilerOptions", - factory.createObjectLiteralExpression(options.map(([optionName, optionValue]) => createJsonPropertyAssignment(optionName, optionValue)), /*multiLine*/ true))); + changeTracker.insertNodeAtObjectStart( + configFile, + tsconfigObjectLiteral, + createJsonPropertyAssignment( + "compilerOptions", + factory.createObjectLiteralExpression( + options.map(([optionName, optionValue]) => createJsonPropertyAssignment(optionName, optionValue)), + /*multiLine*/ true, + ), + ), + ); return; } @@ -837,7 +1075,11 @@ export function setJsonCompilerOptionValues( for (const [optionName, optionValue] of options) { const optionProperty = findJsonProperty(compilerOptions, optionName); if (optionProperty === undefined) { - changeTracker.insertNodeAtObjectStart(configFile, compilerOptions, createJsonPropertyAssignment(optionName, optionValue)); + changeTracker.insertNodeAtObjectStart( + configFile, + compilerOptions, + createJsonPropertyAssignment(optionName, optionValue), + ); } else { changeTracker.replaceNode(configFile, optionProperty.initializer, optionValue); @@ -862,7 +1104,11 @@ export function createJsonPropertyAssignment(name: string, initializer: Expressi /** @internal */ export 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); + return find( + obj.properties, + (p): p is PropertyAssignment => + isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name, + ); } /** @@ -872,7 +1118,10 @@ export function findJsonProperty(obj: ObjectLiteralExpression, name: string): Pr * * @internal */ -export function tryGetAutoImportableReferenceFromTypeNode(importTypeNode: TypeNode | undefined, scriptTarget: ScriptTarget) { +export function tryGetAutoImportableReferenceFromTypeNode( + importTypeNode: TypeNode | undefined, + scriptTarget: ScriptTarget, +) { let symbols: Symbol[] | undefined; const typeNode = visitNode(importTypeNode, visit, isTypeNode); if (symbols && typeNode) { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index e6f0eb91405e3..3deb4c6232961 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -171,19 +171,29 @@ registerCodeFix({ const { errorCode, preferences, sourceFile, span, program } = context; const info = getFixInfos(context, errorCode, span.start, /*useAutoImportProvider*/ true); if (!info) return undefined; - return info.map(({ fix, symbolName, errorIdentifierText }) => codeActionForFix( - context, - sourceFile, - symbolName, - fix, - /*includeSymbolNameInDescription*/ symbolName !== errorIdentifierText, - program.getCompilerOptions(), - preferences)); + return info.map(({ fix, symbolName, errorIdentifierText }) => + codeActionForFix( + context, + sourceFile, + symbolName, + fix, + /*includeSymbolNameInDescription*/ symbolName !== errorIdentifierText, + program.getCompilerOptions(), + preferences, + ) + ); }, fixIds: [importFixId], getAllCodeActions: context => { const { sourceFile, program, preferences, host, cancellationToken } = context; - const importAdder = createImportAdderWorker(sourceFile, program, /*useAutoImportProvider*/ true, preferences, host, cancellationToken); + const importAdder = createImportAdderWorker( + sourceFile, + program, + /*useAutoImportProvider*/ true, + preferences, + host, + cancellationToken, + ); eachDiagnostic(context, errorCodes, diag => importAdder.addImportFromDiagnostic(diag, context)); return createCombinedCodeActions(textChanges.ChangeTracker.with(context, importAdder.writeFixes)); }, @@ -202,8 +212,21 @@ export interface ImportAdder { } /** @internal */ -export function createImportAdder(sourceFile: SourceFile, program: Program, preferences: UserPreferences, host: LanguageServiceHost, cancellationToken?: CancellationToken): ImportAdder { - return createImportAdderWorker(sourceFile, program, /*useAutoImportProvider*/ false, preferences, host, cancellationToken); +export function createImportAdder( + sourceFile: SourceFile, + program: Program, + preferences: UserPreferences, + host: LanguageServiceHost, + cancellationToken?: CancellationToken, +): ImportAdder { + return createImportAdderWorker( + sourceFile, + program, + /*useAutoImportProvider*/ false, + preferences, + host, + cancellationToken, + ); } interface AddToExistingState { @@ -212,7 +235,14 @@ interface AddToExistingState { readonly namedImports: Map; } -function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAutoImportProvider: boolean, preferences: UserPreferences, host: LanguageServiceHost, cancellationToken: CancellationToken | undefined): ImportAdder { +function createImportAdderWorker( + sourceFile: SourceFile, + program: Program, + useAutoImportProvider: boolean, + preferences: UserPreferences, + host: LanguageServiceHost, + cancellationToken: CancellationToken | undefined, +): ImportAdder { const compilerOptions = program.getCompilerOptions(); // Namespace fixes don't conflict, so just build a list. const addToNamespace: FixUseNamespaceImport[] = []; @@ -222,7 +252,7 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu type NewImportsKey = `${0 | 1}|${string}`; /** Use `getNewImportEntry` for access */ - const newImports = new Map>(); + const newImports = new Map>(); return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes }; function addImportFromDiagnostic(diagnostic: DiagnosticWithLocation, context: CodeFixContextBase) { @@ -236,9 +266,28 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu const symbolName = getNameForExportedSymbol(exportedSymbol, getEmitScriptTarget(compilerOptions)); const checker = program.getTypeChecker(); const symbol = checker.getMergedSymbol(skipAlias(exportedSymbol, checker)); - const exportInfo = getAllExportInfoForSymbol(sourceFile, symbol, symbolName, moduleSymbol, /*preferCapitalized*/ false, program, host, preferences, cancellationToken); + const exportInfo = getAllExportInfoForSymbol( + sourceFile, + symbol, + symbolName, + moduleSymbol, + /*preferCapitalized*/ false, + program, + host, + preferences, + cancellationToken, + ); const useRequire = shouldUseRequire(sourceFile, program); - const fix = getImportFixForSymbol(sourceFile, Debug.checkDefined(exportInfo), program, /*position*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences); + const fix = getImportFixForSymbol( + sourceFile, + Debug.checkDefined(exportInfo), + program, + /*position*/ undefined, + !!isValidTypeOnlyUseSite, + useRequire, + host, + preferences, + ); if (fix) { addImport({ fix, symbolName, errorIdentifierText: undefined }); } @@ -258,14 +307,20 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu const key = String(getNodeId(importClauseOrBindingPattern)); let entry = addToExisting.get(key); if (!entry) { - addToExisting.set(key, entry = { importClauseOrBindingPattern, defaultImport: undefined, namedImports: new Map() }); + addToExisting.set( + key, + entry = { importClauseOrBindingPattern, defaultImport: undefined, namedImports: new Map() }, + ); } if (importKind === ImportKind.Named) { const prevValue = entry?.namedImports.get(symbolName); entry.namedImports.set(symbolName, reduceAddAsTypeOnlyValues(prevValue, addAsTypeOnly)); } else { - Debug.assert(entry.defaultImport === undefined || entry.defaultImport.name === symbolName, "(Add to Existing) Default import should be missing or match symbolName"); + Debug.assert( + entry.defaultImport === undefined || entry.defaultImport.name === symbolName, + "(Add to Existing) Default import should be missing or match symbolName", + ); entry.defaultImport = { name: symbolName, addAsTypeOnly: reduceAddAsTypeOnlyValues(entry.defaultImport?.addAsTypeOnly, addAsTypeOnly), @@ -276,12 +331,21 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu case ImportFixKind.AddNew: { const { moduleSpecifier, importKind, useRequire, addAsTypeOnly } = fix; const entry = getNewImportEntry(moduleSpecifier, importKind, useRequire, addAsTypeOnly); - Debug.assert(entry.useRequire === useRequire, "(Add new) Tried to add an `import` and a `require` for the same module"); + Debug.assert( + entry.useRequire === useRequire, + "(Add new) Tried to add an `import` and a `require` for the same module", + ); switch (importKind) { case ImportKind.Default: - Debug.assert(entry.defaultImport === undefined || entry.defaultImport.name === symbolName, "(Add new) Default import should be missing or match symbolName"); - entry.defaultImport = { name: symbolName, addAsTypeOnly: reduceAddAsTypeOnlyValues(entry.defaultImport?.addAsTypeOnly, addAsTypeOnly) }; + Debug.assert( + entry.defaultImport === undefined || entry.defaultImport.name === symbolName, + "(Add new) Default import should be missing or match symbolName", + ); + entry.defaultImport = { + name: symbolName, + addAsTypeOnly: reduceAddAsTypeOnlyValues(entry.defaultImport?.addAsTypeOnly, addAsTypeOnly), + }; break; case ImportKind.Named: const prevValue = (entry.namedImports ||= new Map()).get(symbolName); @@ -289,7 +353,10 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu break; case ImportKind.CommonJS: case ImportKind.Namespace: - Debug.assert(entry.namespaceLikeImport === undefined || entry.namespaceLikeImport.name === symbolName, "Namespacelike import shoudl be missing or match symbolName"); + Debug.assert( + entry.namespaceLikeImport === undefined || entry.namespaceLikeImport.name === symbolName, + "Namespacelike import shoudl be missing or match symbolName", + ); entry.namespaceLikeImport = { importKind, name: symbolName, addAsTypeOnly }; break; } @@ -302,7 +369,10 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu Debug.assertNever(fix, `fix wasn't never - got kind ${(fix as ImportFix).kind}`); } - function reduceAddAsTypeOnlyValues(prevValue: AddAsTypeOnly | undefined, newValue: AddAsTypeOnly): AddAsTypeOnly { + function reduceAddAsTypeOnlyValues( + prevValue: AddAsTypeOnly | undefined, + newValue: AddAsTypeOnly, + ): AddAsTypeOnly { // `NotAllowed` overrides `Required` because one addition of a new import might be required to be type-only // because of `--importsNotUsedAsValues=error`, but if a second addition of the same import is `NotAllowed` // to be type-only, the reason the first one was `Required` - the unused runtime dependency - is now moot. @@ -312,7 +382,12 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu return Math.max(prevValue ?? 0, newValue); } - function getNewImportEntry(moduleSpecifier: string, importKind: ImportKind, useRequire: boolean, addAsTypeOnly: AddAsTypeOnly): Mutable { + function getNewImportEntry( + moduleSpecifier: string, + importKind: ImportKind, + useRequire: boolean, + addAsTypeOnly: AddAsTypeOnly, + ): Mutable { // A default import that requires type-only makes the whole import type-only. // (We could add `default` as a named import, but that style seems undesirable.) // Under `--preserveValueImports` and `--importsNotUsedAsValues=error`, if a @@ -323,11 +398,11 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu const nonTypeOnlyKey = newImportsKey(moduleSpecifier, /*topLevelTypeOnly*/ false); const typeOnlyEntry = newImports.get(typeOnlyKey); const nonTypeOnlyEntry = newImports.get(nonTypeOnlyKey); - const newEntry: ImportsCollection & { useRequire: boolean } = { + const newEntry: ImportsCollection & { useRequire: boolean; } = { defaultImport: undefined, namedImports: undefined, namespaceLikeImport: undefined, - useRequire + useRequire, }; if (importKind === ImportKind.Default && addAsTypeOnly === AddAsTypeOnly.Required) { if (typeOnlyEntry) return typeOnlyEntry; @@ -371,7 +446,8 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu importClauseOrBindingPattern, defaultImport, arrayFrom(namedImports.entries(), ([name, addAsTypeOnly]) => ({ addAsTypeOnly, name })), - preferences); + preferences, + ); }); let newDeclarations: AnyImportOrRequireStatement | readonly AnyImportOrRequireStatement[] | undefined; @@ -384,7 +460,8 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu defaultImport, namedImports && arrayFrom(namedImports.entries(), ([name, addAsTypeOnly]) => ({ addAsTypeOnly, name })), namespaceLikeImport, - compilerOptions); + compilerOptions, + ); newDeclarations = combine(newDeclarations, declarations); }); if (newDeclarations) { @@ -402,17 +479,22 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu * * @internal */ - export interface ImportSpecifierResolver { +export interface ImportSpecifierResolver { getModuleSpecifierForBestExportInfo( exportInfo: readonly SymbolExportInfo[], position: number, isValidTypeOnlyUseSite: boolean, - fromCacheOnly?: boolean - ): { exportInfo?: SymbolExportInfo, moduleSpecifier: string, computedWithoutCacheCount: number } | undefined; + fromCacheOnly?: boolean, + ): { exportInfo?: SymbolExportInfo; moduleSpecifier: string; computedWithoutCacheCount: number; } | undefined; } /** @internal */ -export function createImportSpecifierResolver(importingFile: SourceFile, program: Program, host: LanguageServiceHost, preferences: UserPreferences): ImportSpecifierResolver { +export function createImportSpecifierResolver( + importingFile: SourceFile, + program: Program, + host: LanguageServiceHost, + preferences: UserPreferences, +): ImportSpecifierResolver { const packageJsonImportFilter = createPackageJsonImportFilter(importingFile, preferences, host); const importMap = createExistingImportMap(program.getTypeChecker(), importingFile, program.getCompilerOptions()); return { getModuleSpecifierForBestExportInfo }; @@ -422,7 +504,7 @@ export function createImportSpecifierResolver(importingFile: SourceFile, program position: number, isValidTypeOnlyUseSite: boolean, fromCacheOnly?: boolean, - ): { exportInfo?: SymbolExportInfo, moduleSpecifier: string, computedWithoutCacheCount: number } | undefined { + ): { exportInfo?: SymbolExportInfo; moduleSpecifier: string; computedWithoutCacheCount: number; } | undefined { const { fixes, computedWithoutCacheCount } = getImportFixes( exportInfo, position, @@ -433,25 +515,41 @@ export function createImportSpecifierResolver(importingFile: SourceFile, program host, preferences, importMap, - fromCacheOnly); + fromCacheOnly, + ); const result = getBestFix(fixes, importingFile, program, packageJsonImportFilter, host); return result && { ...result, computedWithoutCacheCount }; } } // Sorted with the preferred fix coming first. -const enum ImportFixKind { UseNamespace, JsdocTypeImport, AddToExisting, AddNew, PromoteTypeOnly } +const enum ImportFixKind { + UseNamespace, + JsdocTypeImport, + AddToExisting, + AddNew, + PromoteTypeOnly, +} // These should not be combined as bitflags, but are given powers of 2 values to // easily detect conflicts between `NotAllowed` and `Required` by giving them a unique sum. // They're also ordered in terms of increasing priority for a fix-all scenario (see // `reduceAddAsTypeOnlyValues`). const enum AddAsTypeOnly { - Allowed = 1 << 0, - Required = 1 << 1, + Allowed = 1 << 0, + Required = 1 << 1, NotAllowed = 1 << 2, } -type ImportFix = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport | FixPromoteTypeOnlyImport; -type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; +type ImportFix = + | FixUseNamespaceImport + | FixAddJsdocTypeImport + | FixAddToExistingImport + | FixAddNewImport + | FixPromoteTypeOnlyImport; +type ImportFixWithModuleSpecifier = + | FixUseNamespaceImport + | FixAddJsdocTypeImport + | FixAddToExistingImport + | FixAddNewImport; // Properties are be undefined if fix is derived from an existing import interface ImportFixBase { @@ -490,7 +588,6 @@ interface FixPromoteTypeOnlyImport { readonly typeOnlyAliasDeclaration: TypeOnlyAliasDeclaration; } - /** Information needed to augment an existing import declaration. */ interface FixAddToExistingImportInfo { readonly declaration: AnyImportOrRequire; @@ -513,27 +610,51 @@ export function getImportCompletionAction( position: number, preferences: UserPreferences, cancellationToken: CancellationToken, -): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } { +): { readonly moduleSpecifier: string; readonly codeAction: CodeAction; } { const compilerOptions = program.getCompilerOptions(); let exportInfos; if (exportMapKey) { // The new way: `exportMapKey` should be in the `data` of each auto-import completion entry and // sent back when asking for details. - exportInfos = getExportInfoMap(sourceFile, host, program, preferences, cancellationToken).get(sourceFile.path, exportMapKey); + exportInfos = getExportInfoMap(sourceFile, host, program, preferences, cancellationToken).get( + sourceFile.path, + exportMapKey, + ); Debug.assertIsDefined(exportInfos, "Some exportInfo should match the specified exportMapKey"); } else { // The old way, kept alive for super old editors that don't give us `data` back. exportInfos = pathIsBareSpecifier(stripQuotes(moduleSymbol.name)) ? [getSingleExportInfoForSymbol(targetSymbol, symbolName, moduleSymbol, program, host)] - : getAllExportInfoForSymbol(sourceFile, targetSymbol, symbolName, moduleSymbol, isJsxTagName, program, host, preferences, cancellationToken); + : getAllExportInfoForSymbol( + sourceFile, + targetSymbol, + symbolName, + moduleSymbol, + isJsxTagName, + program, + host, + preferences, + cancellationToken, + ); Debug.assertIsDefined(exportInfos, "Some exportInfo should match the specified symbol / moduleSymbol"); } const useRequire = shouldUseRequire(sourceFile, program); const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite(getTokenAtPosition(sourceFile, position)); - const fix = Debug.checkDefined(getImportFixForSymbol(sourceFile, exportInfos, program, position, isValidTypeOnlyUseSite, useRequire, host, preferences)); + const fix = Debug.checkDefined( + getImportFixForSymbol( + sourceFile, + exportInfos, + program, + position, + isValidTypeOnlyUseSite, + useRequire, + host, + preferences, + ), + ); return { moduleSpecifier: fix.moduleSpecifier, codeAction: codeFixActionToCodeAction(codeActionForFix( @@ -543,55 +664,136 @@ export function getImportCompletionAction( fix, /*includeSymbolNameInDescription*/ false, compilerOptions, - preferences)) + preferences, + )), }; } /** @internal */ -export function getPromoteTypeOnlyCompletionAction(sourceFile: SourceFile, symbolToken: Identifier, program: Program, host: LanguageServiceHost, formatContext: formatting.FormatContext, preferences: UserPreferences) { +export function getPromoteTypeOnlyCompletionAction( + sourceFile: SourceFile, + symbolToken: Identifier, + program: Program, + host: LanguageServiceHost, + formatContext: formatting.FormatContext, + preferences: UserPreferences, +) { const compilerOptions = program.getCompilerOptions(); - const symbolName = single(getSymbolNamesToImport(sourceFile, program.getTypeChecker(), symbolToken, compilerOptions)); + const symbolName = single( + getSymbolNamesToImport(sourceFile, program.getTypeChecker(), symbolToken, compilerOptions), + ); const fix = getTypeOnlyPromotionFix(sourceFile, symbolToken, symbolName, program); const includeSymbolNameInDescription = symbolName !== symbolToken.text; - return fix && codeFixActionToCodeAction(codeActionForFix({ host, formatContext, preferences }, sourceFile, symbolName, fix, includeSymbolNameInDescription, compilerOptions, preferences)); + return fix + && codeFixActionToCodeAction( + codeActionForFix( + { host, formatContext, preferences }, + sourceFile, + symbolName, + fix, + includeSymbolNameInDescription, + compilerOptions, + preferences, + ), + ); } -function getImportFixForSymbol(sourceFile: SourceFile, exportInfos: readonly SymbolExportInfo[], program: Program, position: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, host: LanguageServiceHost, preferences: UserPreferences) { +function getImportFixForSymbol( + sourceFile: SourceFile, + exportInfos: readonly SymbolExportInfo[], + program: Program, + position: number | undefined, + isValidTypeOnlyUseSite: boolean, + useRequire: boolean, + host: LanguageServiceHost, + preferences: UserPreferences, +) { const packageJsonImportFilter = createPackageJsonImportFilter(sourceFile, preferences, host); - return getBestFix(getImportFixes(exportInfos, position, isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences).fixes, sourceFile, program, packageJsonImportFilter, host); + return getBestFix( + getImportFixes( + exportInfos, + position, + isValidTypeOnlyUseSite, + useRequire, + program, + sourceFile, + host, + preferences, + ).fixes, + sourceFile, + program, + packageJsonImportFilter, + host, + ); } function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAction): CodeAction { return { description, changes, commands }; } -function getAllExportInfoForSymbol(importingFile: SourceFile, symbol: Symbol, symbolName: string, moduleSymbol: Symbol, preferCapitalized: boolean, program: Program, host: LanguageServiceHost, preferences: UserPreferences, cancellationToken: CancellationToken | undefined): readonly SymbolExportInfo[] | undefined { +function getAllExportInfoForSymbol( + importingFile: SourceFile, + symbol: Symbol, + symbolName: string, + moduleSymbol: Symbol, + preferCapitalized: boolean, + program: Program, + host: LanguageServiceHost, + preferences: UserPreferences, + cancellationToken: CancellationToken | undefined, +): readonly SymbolExportInfo[] | undefined { const getChecker = createGetChecker(program, host); return getExportInfoMap(importingFile, host, program, preferences, cancellationToken) .search(importingFile.path, preferCapitalized, name => name === symbolName, info => { - if (skipAlias(info[0].symbol, getChecker(info[0].isFromPackageJson)) === symbol && info.some(i => i.moduleSymbol === moduleSymbol || i.symbol.parent === moduleSymbol)) { + if ( + skipAlias(info[0].symbol, getChecker(info[0].isFromPackageJson)) === symbol + && info.some(i => i.moduleSymbol === moduleSymbol || i.symbol.parent === moduleSymbol) + ) { return info; } }); } -function getSingleExportInfoForSymbol(symbol: Symbol, symbolName: string, moduleSymbol: Symbol, program: Program, host: LanguageServiceHost): SymbolExportInfo { +function getSingleExportInfoForSymbol( + symbol: Symbol, + symbolName: string, + moduleSymbol: Symbol, + program: Program, + host: LanguageServiceHost, +): SymbolExportInfo { const compilerOptions = program.getCompilerOptions(); const mainProgramInfo = getInfoWithChecker(program.getTypeChecker(), /*isFromPackageJson*/ false); if (mainProgramInfo) { return mainProgramInfo; } const autoImportProvider = host.getPackageJsonAutoImportProvider?.()?.getTypeChecker(); - return Debug.checkDefined(autoImportProvider && getInfoWithChecker(autoImportProvider, /*isFromPackageJson*/ true), `Could not find symbol in specified module for code actions`); + return Debug.checkDefined( + autoImportProvider && getInfoWithChecker(autoImportProvider, /*isFromPackageJson*/ true), + `Could not find symbol in specified module for code actions`, + ); function getInfoWithChecker(checker: TypeChecker, isFromPackageJson: boolean): SymbolExportInfo | undefined { const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); if (defaultInfo && skipAlias(defaultInfo.symbol, checker) === symbol) { - return { symbol: defaultInfo.symbol, moduleSymbol, moduleFileName: undefined, exportKind: defaultInfo.exportKind, targetFlags: skipAlias(symbol, checker).flags, isFromPackageJson }; + return { + symbol: defaultInfo.symbol, + moduleSymbol, + moduleFileName: undefined, + exportKind: defaultInfo.exportKind, + targetFlags: skipAlias(symbol, checker).flags, + isFromPackageJson, + }; } const named = checker.tryGetMemberInModuleExportsAndProperties(symbolName, moduleSymbol); if (named && skipAlias(named, checker) === symbol) { - return { symbol: named, moduleSymbol, moduleFileName: undefined, exportKind: ExportKind.Named, targetFlags: skipAlias(symbol, checker).flags, isFromPackageJson }; + return { + symbol: named, + moduleSymbol, + moduleFileName: undefined, + exportKind: ExportKind.Named, + targetFlags: skipAlias(symbol, checker).flags, + isFromPackageJson, + }; } } } @@ -607,11 +809,16 @@ function getImportFixes( preferences: UserPreferences, importMap = createExistingImportMap(program.getTypeChecker(), sourceFile, program.getCompilerOptions()), fromCacheOnly?: boolean, -): { computedWithoutCacheCount: number, fixes: readonly ImportFixWithModuleSpecifier[] } { +): { computedWithoutCacheCount: number; fixes: readonly ImportFixWithModuleSpecifier[]; } { const checker = program.getTypeChecker(); const existingImports = flatMap(exportInfos, importMap.getImportsForExportInfo); const useNamespace = usagePosition !== undefined && tryUseExistingNamespaceImport(existingImports, usagePosition); - const addToExisting = tryAddToExistingImport(existingImports, isValidTypeOnlyUseSite, checker, program.getCompilerOptions()); + const addToExisting = tryAddToExistingImport( + existingImports, + isValidTypeOnlyUseSite, + checker, + program.getCompilerOptions(), + ); if (addToExisting) { // Don't bother providing an action to add a new import if we can add to an existing one. return { @@ -630,14 +837,18 @@ function getImportFixes( useRequire, host, preferences, - fromCacheOnly); + fromCacheOnly, + ); return { computedWithoutCacheCount, fixes: [...(useNamespace ? [useNamespace] : emptyArray), ...fixes], }; } -function tryUseExistingNamespaceImport(existingImports: readonly FixAddToExistingImportInfo[], position: number): FixUseNamespaceImport | undefined { +function tryUseExistingNamespaceImport( + existingImports: readonly FixAddToExistingImportInfo[], + position: number, +): FixUseNamespaceImport | undefined { // It is possible that multiple import statements with the same specifier exist in the file. // e.g. // @@ -679,7 +890,7 @@ function getAddAsTypeOnly( symbol: Symbol, targetFlags: SymbolFlags, checker: TypeChecker, - compilerOptions: CompilerOptions + compilerOptions: CompilerOptions, ) { if (!isValidTypeOnlyUseSite) { // Can't use a type-only import if the usage is an emitting position @@ -689,8 +900,9 @@ function getAddAsTypeOnly( // Not writing a (top-level) type-only import here would create an error because the runtime dependency is unnecessary return AddAsTypeOnly.Required; } - if (importNameElisionDisabled(compilerOptions) && - (!(targetFlags & SymbolFlags.Value) || !!checker.getTypeOnlyAliasDeclaration(symbol)) + if ( + importNameElisionDisabled(compilerOptions) + && (!(targetFlags & SymbolFlags.Value) || !!checker.getTypeOnlyAliasDeclaration(symbol)) ) { // A type-only import is required for this symbol if under these settings if the symbol will // be erased, which will happen if the target symbol is purely a type or if it was exported/imported @@ -700,15 +912,20 @@ function getAddAsTypeOnly( return AddAsTypeOnly.Allowed; } -function tryAddToExistingImport(existingImports: readonly FixAddToExistingImportInfo[], isValidTypeOnlyUseSite: boolean, checker: TypeChecker, compilerOptions: CompilerOptions): FixAddToExistingImport | undefined { +function tryAddToExistingImport( + existingImports: readonly FixAddToExistingImportInfo[], + isValidTypeOnlyUseSite: boolean, + checker: TypeChecker, + compilerOptions: CompilerOptions, +): FixAddToExistingImport | undefined { let best: FixAddToExistingImport | undefined; for (const existingImport of existingImports) { const fix = getAddToExistingImportFix(existingImport); if (!fix) continue; const isTypeOnly = isTypeOnlyImportDeclaration(fix.importClauseOrBindingPattern); if ( - fix.addAsTypeOnly !== AddAsTypeOnly.NotAllowed && isTypeOnly || - fix.addAsTypeOnly === AddAsTypeOnly.NotAllowed && !isTypeOnly + fix.addAsTypeOnly !== AddAsTypeOnly.NotAllowed && isTypeOnly + || fix.addAsTypeOnly === AddAsTypeOnly.NotAllowed && !isTypeOnly ) { // Give preference to putting types in existing type-only imports and avoiding conversions // of import statements to/from type-only. @@ -718,15 +935,27 @@ function tryAddToExistingImport(existingImports: readonly FixAddToExistingImport } return best; - function getAddToExistingImportFix({ declaration, importKind, symbol, targetFlags }: FixAddToExistingImportInfo): FixAddToExistingImport | undefined { - if (importKind === ImportKind.CommonJS || importKind === ImportKind.Namespace || declaration.kind === SyntaxKind.ImportEqualsDeclaration) { + function getAddToExistingImportFix( + { declaration, importKind, symbol, targetFlags }: FixAddToExistingImportInfo, + ): FixAddToExistingImport | undefined { + if ( + importKind === ImportKind.CommonJS || importKind === ImportKind.Namespace + || declaration.kind === SyntaxKind.ImportEqualsDeclaration + ) { // These kinds of imports are not combinable with anything return undefined; } if (declaration.kind === SyntaxKind.VariableDeclaration) { - return (importKind === ImportKind.Named || importKind === ImportKind.Default) && declaration.name.kind === SyntaxKind.ObjectBindingPattern - ? { kind: ImportFixKind.AddToExisting, importClauseOrBindingPattern: declaration.name, importKind, moduleSpecifier: declaration.initializer.arguments[0].text, addAsTypeOnly: AddAsTypeOnly.NotAllowed } + return (importKind === ImportKind.Named || importKind === ImportKind.Default) + && declaration.name.kind === SyntaxKind.ObjectBindingPattern + ? { + kind: ImportFixKind.AddToExisting, + importClauseOrBindingPattern: declaration.name, + importKind, + moduleSpecifier: declaration.initializer.arguments[0].text, + addAsTypeOnly: AddAsTypeOnly.NotAllowed, + } : undefined; } @@ -744,16 +973,26 @@ function tryAddToExistingImport(existingImports: readonly FixAddToExistingImport // N.B. we don't have to figure out whether to use the main program checker // or the AutoImportProvider checker because we're adding to an existing import; the existence of // the import guarantees the symbol came from the main program. - const addAsTypeOnly = getAddAsTypeOnly(isValidTypeOnlyUseSite, /*isForNewImportDeclaration*/ false, symbol, targetFlags, checker, compilerOptions); + const addAsTypeOnly = getAddAsTypeOnly( + isValidTypeOnlyUseSite, + /*isForNewImportDeclaration*/ false, + symbol, + targetFlags, + checker, + compilerOptions, + ); - if (importKind === ImportKind.Default && ( - name || // Cannot add a default import to a declaration that already has one - addAsTypeOnly === AddAsTypeOnly.Required && namedBindings // Cannot add a default import as type-only if the import already has named bindings - )) { + if ( + importKind === ImportKind.Default && ( + name // Cannot add a default import to a declaration that already has one + || addAsTypeOnly === AddAsTypeOnly.Required && namedBindings // Cannot add a default import as type-only if the import already has named bindings + ) + ) { return undefined; } - if (importKind === ImportKind.Named && - namedBindings?.kind === SyntaxKind.NamespaceImport // Cannot add a named import to a declaration that has a namespace import + if ( + importKind === ImportKind.Named + && namedBindings?.kind === SyntaxKind.NamespaceImport // Cannot add a named import to a declaration that has a namespace import ) { return undefined; } @@ -787,14 +1026,16 @@ function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile } return { - getImportsForExportInfo: ({ moduleSymbol, exportKind, targetFlags, symbol }: SymbolExportInfo): readonly FixAddToExistingImportInfo[] => { + getImportsForExportInfo: ( + { moduleSymbol, exportKind, targetFlags, symbol }: SymbolExportInfo, + ): readonly FixAddToExistingImportInfo[] => { // Can't use an es6 import for a type in JS. if (!(targetFlags & SymbolFlags.Value) && isSourceFileJS(importingFile)) return emptyArray; const matchingDeclarations = importMap?.get(getSymbolId(moduleSymbol)); if (!matchingDeclarations) return emptyArray; const importKind = getImportKind(importingFile, exportKind, compilerOptions); return matchingDeclarations.map(declaration => ({ declaration, importKind, symbol, targetFlags })); - } + }, }; } @@ -821,7 +1062,9 @@ function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean { // 5. Match the first other JS file in the program that's unambiguously CJS or ESM for (const otherFile of program.getSourceFiles()) { - if (otherFile === sourceFile || !isSourceFileJS(otherFile) || program.isSourceFileFromExternalLibrary(otherFile)) continue; + if ( + otherFile === sourceFile || !isSourceFileJS(otherFile) || program.isSourceFileFromExternalLibrary(otherFile) + ) continue; if (otherFile.commonJsModuleIndicator && !otherFile.externalModuleIndicator) return true; if (otherFile.externalModuleIndicator && !otherFile.commonJsModuleIndicator) return false; } @@ -831,7 +1074,9 @@ function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean { } function createGetChecker(program: Program, host: LanguageServiceHost) { - return memoizeOne((isFromPackageJson: boolean) => isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() : program.getTypeChecker()); + return memoizeOne((isFromPackageJson: boolean) => + isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() : program.getTypeChecker() + ); } function getNewImportFixes( @@ -844,7 +1089,7 @@ function getNewImportFixes( host: LanguageServiceHost, preferences: UserPreferences, fromCacheOnly?: boolean, -): { computedWithoutCacheCount: number, fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[] } { +): { computedWithoutCacheCount: number; fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[]; } { const isJs = isSourceFileJS(sourceFile); const compilerOptions = program.getCompilerOptions(); const moduleSpecifierResolutionHost = createModuleSpecifierResolutionHost(program, host); @@ -852,15 +1097,38 @@ function getNewImportFixes( const moduleResolution = getEmitModuleResolutionKind(compilerOptions); const rejectNodeModulesRelativePaths = moduleResolutionUsesNodeModules(moduleResolution); const getModuleSpecifiers = fromCacheOnly - ? (moduleSymbol: Symbol) => ({ moduleSpecifiers: moduleSpecifiers.tryGetModuleSpecifiersFromCache(moduleSymbol, sourceFile, moduleSpecifierResolutionHost, preferences), computedWithoutCache: false }) - : (moduleSymbol: Symbol, checker: TypeChecker) => moduleSpecifiers.getModuleSpecifiersWithCacheInfo(moduleSymbol, checker, compilerOptions, sourceFile, moduleSpecifierResolutionHost, preferences); + ? (moduleSymbol: Symbol) => ({ + moduleSpecifiers: moduleSpecifiers.tryGetModuleSpecifiersFromCache( + moduleSymbol, + sourceFile, + moduleSpecifierResolutionHost, + preferences, + ), + computedWithoutCache: false, + }) + : (moduleSymbol: Symbol, checker: TypeChecker) => + moduleSpecifiers.getModuleSpecifiersWithCacheInfo( + moduleSymbol, + checker, + compilerOptions, + sourceFile, + moduleSpecifierResolutionHost, + preferences, + ); let computedWithoutCacheCount = 0; const fixes = flatMap(exportInfo, (exportInfo, i) => { const checker = getChecker(exportInfo.isFromPackageJson); const { computedWithoutCache, moduleSpecifiers } = getModuleSpecifiers(exportInfo.moduleSymbol, checker); const importedSymbolHasValueMeaning = !!(exportInfo.targetFlags & SymbolFlags.Value); - const addAsTypeOnly = getAddAsTypeOnly(isValidTypeOnlyUseSite, /*isForNewImportDeclaration*/ true, exportInfo.symbol, exportInfo.targetFlags, checker, compilerOptions); + const addAsTypeOnly = getAddAsTypeOnly( + isValidTypeOnlyUseSite, + /*isForNewImportDeclaration*/ true, + exportInfo.symbol, + exportInfo.targetFlags, + checker, + compilerOptions, + ); computedWithoutCacheCount += computedWithoutCache ? 1 : 0; return mapDefined(moduleSpecifiers, (moduleSpecifier): FixAddNewImport | FixAddJsdocTypeImport | undefined => { if (rejectNodeModulesRelativePaths && pathContainsNodeModules(moduleSpecifier)) { @@ -868,11 +1136,20 @@ function getNewImportFixes( } if (!importedSymbolHasValueMeaning && isJs && usagePosition !== undefined) { // `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types. - return { kind: ImportFixKind.JsdocTypeImport, moduleSpecifier, usagePosition, exportInfo, isReExport: i > 0 }; + return { + kind: ImportFixKind.JsdocTypeImport, + moduleSpecifier, + usagePosition, + exportInfo, + isReExport: i > 0, + }; } const importKind = getImportKind(sourceFile, exportInfo.exportKind, compilerOptions); let qualification: Qualification | undefined; - if (usagePosition !== undefined && importKind === ImportKind.CommonJS && exportInfo.exportKind === ExportKind.Named) { + if ( + usagePosition !== undefined && importKind === ImportKind.CommonJS + && exportInfo.exportKind === ExportKind.Named + ) { // Compiler options are restricting our import options to a require, but we need to access // a named export or property of the exporting module. We need to import the entire module // and insert a property access, e.g. `writeFile` becomes @@ -887,7 +1164,8 @@ function getNewImportFixes( namespacePrefix ||= moduleSymbolToValidIdentifier( exportInfo.moduleSymbol, getEmitScriptTarget(compilerOptions), - /*forceCapitalize*/ false); + /*forceCapitalize*/ false, + ); qualification = { namespacePrefix, usagePosition }; } return { @@ -917,9 +1195,30 @@ function getFixesForAddImport( host: LanguageServiceHost, preferences: UserPreferences, fromCacheOnly?: boolean, -): { computedWithoutCacheCount?: number, fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[] } { - const existingDeclaration = firstDefined(existingImports, info => newImportInfoFromExistingSpecifier(info, isValidTypeOnlyUseSite, useRequire, program.getTypeChecker(), program.getCompilerOptions())); - return existingDeclaration ? { fixes: [existingDeclaration] } : getNewImportFixes(program, sourceFile, usagePosition, isValidTypeOnlyUseSite, useRequire, exportInfos, host, preferences, fromCacheOnly); +): { computedWithoutCacheCount?: number; fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[]; } { + const existingDeclaration = firstDefined( + existingImports, + info => + newImportInfoFromExistingSpecifier( + info, + isValidTypeOnlyUseSite, + useRequire, + program.getTypeChecker(), + program.getCompilerOptions(), + ), + ); + return existingDeclaration ? { fixes: [existingDeclaration] } + : getNewImportFixes( + program, + sourceFile, + usagePosition, + isValidTypeOnlyUseSite, + useRequire, + exportInfos, + host, + preferences, + fromCacheOnly, + ); } function newImportInfoFromExistingSpecifier( @@ -927,13 +1226,20 @@ function newImportInfoFromExistingSpecifier( isValidTypeOnlyUseSite: boolean, useRequire: boolean, checker: TypeChecker, - compilerOptions: CompilerOptions + compilerOptions: CompilerOptions, ): FixAddNewImport | undefined { const moduleSpecifier = tryGetModuleSpecifierFromDeclaration(declaration)?.text; if (moduleSpecifier) { const addAsTypeOnly = useRequire ? AddAsTypeOnly.NotAllowed - : getAddAsTypeOnly(isValidTypeOnlyUseSite, /*isForNewImportDeclaration*/ true, symbol, targetFlags, checker, compilerOptions); + : getAddAsTypeOnly( + isValidTypeOnlyUseSite, + /*isForNewImportDeclaration*/ true, + symbol, + targetFlags, + checker, + compilerOptions, + ); return { kind: ImportFixKind.AddNew, moduleSpecifier, importKind, addAsTypeOnly, useRequire }; } } @@ -944,17 +1250,33 @@ interface FixInfo { readonly errorIdentifierText: string | undefined; readonly isJsxNamespaceFix?: boolean; } -function getFixInfos(context: CodeFixContextBase, errorCode: number, pos: number, useAutoImportProvider: boolean): readonly FixInfo[] | undefined { +function getFixInfos( + context: CodeFixContextBase, + errorCode: number, + pos: number, + useAutoImportProvider: boolean, +): readonly FixInfo[] | undefined { const symbolToken = getTokenAtPosition(context.sourceFile, pos); let info; - if (errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) { + if ( + errorCode + === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead + .code + ) { info = getFixesInfoForUMDImport(context, symbolToken); } else if (!isIdentifier(symbolToken)) { return undefined; } else if (errorCode === Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type.code) { - const symbolName = single(getSymbolNamesToImport(context.sourceFile, context.program.getTypeChecker(), symbolToken, context.program.getCompilerOptions())); + const symbolName = single( + getSymbolNamesToImport( + context.sourceFile, + context.program.getTypeChecker(), + symbolToken, + context.program.getCompilerOptions(), + ), + ); const fix = getTypeOnlyPromotionFix(context.sourceFile, symbolToken, symbolName, context.program); return fix && [{ fix, symbolName, errorIdentifierText: symbolToken.text }]; } @@ -962,19 +1284,42 @@ function getFixInfos(context: CodeFixContextBase, errorCode: number, pos: number info = getFixesInfoForNonUMDImport(context, symbolToken, useAutoImportProvider); } - const packageJsonImportFilter = createPackageJsonImportFilter(context.sourceFile, context.preferences, context.host); + const packageJsonImportFilter = createPackageJsonImportFilter( + context.sourceFile, + context.preferences, + context.host, + ); return info && sortFixInfo(info, context.sourceFile, context.program, packageJsonImportFilter, context.host); } -function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier })[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier })[] { +function sortFixInfo( + fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[], + sourceFile: SourceFile, + program: Program, + packageJsonImportFilter: PackageJsonImportFilter, + host: LanguageServiceHost, +): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] { const _toPath = (fileName: string) => toPath(fileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host)); return sort(fixes, (a, b) => - compareBooleans(!!a.isJsxNamespaceFix, !!b.isJsxNamespaceFix) || - compareValues(a.fix.kind, b.fix.kind) || - compareModuleSpecifiers(a.fix, b.fix, sourceFile, program, packageJsonImportFilter.allowsImportingSpecifier, _toPath)); + compareBooleans(!!a.isJsxNamespaceFix, !!b.isJsxNamespaceFix) + || compareValues(a.fix.kind, b.fix.kind) + || compareModuleSpecifiers( + a.fix, + b.fix, + sourceFile, + program, + packageJsonImportFilter.allowsImportingSpecifier, + _toPath, + )); } -function getBestFix(fixes: readonly ImportFixWithModuleSpecifier[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): ImportFixWithModuleSpecifier | undefined { +function getBestFix( + fixes: readonly ImportFixWithModuleSpecifier[], + sourceFile: SourceFile, + program: Program, + packageJsonImportFilter: PackageJsonImportFilter, + host: LanguageServiceHost, +): ImportFixWithModuleSpecifier | undefined { if (!some(fixes)) return; // These will always be placed first if available, and are better than other kinds if (fixes[0].kind === ImportFixKind.UseNamespace || fixes[0].kind === ImportFixKind.AddToExisting) { @@ -984,13 +1329,13 @@ function getBestFix(fixes: readonly ImportFixWithModuleSpecifier[], sourceFile: return fixes.reduce((best, fix) => // Takes true branch of conditional if `fix` is better than `best` compareModuleSpecifiers( - fix, - best, - sourceFile, - program, - packageJsonImportFilter.allowsImportingSpecifier, - fileName => toPath(fileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), - ) === Comparison.LessThan ? fix : best + fix, + best, + sourceFile, + program, + packageJsonImportFilter.allowsImportingSpecifier, + fileName => toPath(fileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), + ) === Comparison.LessThan ? fix : best ); } @@ -1008,7 +1353,8 @@ function compareModuleSpecifiers( || compareNodeCoreModuleSpecifiers(a.moduleSpecifier, b.moduleSpecifier, importingFile, program) || compareBooleans( isFixPossiblyReExportingImportingFile(a, importingFile, program.getCompilerOptions(), toPath), - isFixPossiblyReExportingImportingFile(b, importingFile, program.getCompilerOptions(), toPath)) + isFixPossiblyReExportingImportingFile(b, importingFile, program.getCompilerOptions(), toPath), + ) || compareNumberOfDirectorySeparators(a.moduleSpecifier, b.moduleSpecifier); } return Comparison.EqualTo; @@ -1019,14 +1365,20 @@ function compareModuleSpecifiers( // This can produce false positives or negatives if re-exports cross into sibling directories // (e.g. `export * from "../whatever"`) or are not named "index" (we don't even try to consider // this if we're in a resolution mode where you can't drop trailing "/index" from paths). -function isFixPossiblyReExportingImportingFile(fix: ImportFixWithModuleSpecifier, importingFile: SourceFile, compilerOptions: CompilerOptions, toPath: (fileName: string) => Path): boolean { - if (fix.isReExport && - fix.exportInfo?.moduleFileName && - getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node10 && - isIndexFileName(fix.exportInfo.moduleFileName) +function isFixPossiblyReExportingImportingFile( + fix: ImportFixWithModuleSpecifier, + importingFile: SourceFile, + compilerOptions: CompilerOptions, + toPath: (fileName: string) => Path, +): boolean { + if ( + fix.isReExport + && fix.exportInfo?.moduleFileName + && getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node10 + && isIndexFileName(fix.exportInfo.moduleFileName) ) { const reExportDir = toPath(getDirectoryPath(fix.exportInfo.moduleFileName)); - return startsWith((importingFile.path), reExportDir); + return startsWith(importingFile.path, reExportDir); } return false; } @@ -1035,19 +1387,38 @@ function isIndexFileName(fileName: string) { return getBaseFileName(fileName, [".js", ".jsx", ".d.ts", ".ts", ".tsx"], /*ignoreCase*/ true) === "index"; } -function compareNodeCoreModuleSpecifiers(a: string, b: string, importingFile: SourceFile, program: Program): Comparison { - if (startsWith(a, "node:") && !startsWith(b, "node:")) return shouldUseUriStyleNodeCoreModules(importingFile, program) ? Comparison.LessThan : Comparison.GreaterThan; - if (startsWith(b, "node:") && !startsWith(a, "node:")) return shouldUseUriStyleNodeCoreModules(importingFile, program) ? Comparison.GreaterThan : Comparison.LessThan; +function compareNodeCoreModuleSpecifiers( + a: string, + b: string, + importingFile: SourceFile, + program: Program, +): Comparison { + if (startsWith(a, "node:") && !startsWith(b, "node:")) { + return shouldUseUriStyleNodeCoreModules(importingFile, program) ? Comparison.LessThan : Comparison.GreaterThan; + } + if (startsWith(b, "node:") && !startsWith(a, "node:")) { + return shouldUseUriStyleNodeCoreModules(importingFile, program) ? Comparison.GreaterThan : Comparison.LessThan; + } return Comparison.EqualTo; } -function getFixesInfoForUMDImport({ sourceFile, program, host, preferences }: CodeFixContextBase, token: Node): (FixInfo & { fix: ImportFixWithModuleSpecifier })[] | undefined { +function getFixesInfoForUMDImport( + { sourceFile, program, host, preferences }: CodeFixContextBase, + token: Node, +): (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { const checker = program.getTypeChecker(); const umdSymbol = getUmdSymbol(token, checker); if (!umdSymbol) return undefined; const symbol = checker.getAliasedSymbol(umdSymbol); const symbolName = umdSymbol.name; - const exportInfo: readonly SymbolExportInfo[] = [{ symbol: umdSymbol, moduleSymbol: symbol, moduleFileName: undefined, exportKind: ExportKind.UMD, targetFlags: symbol.flags, isFromPackageJson: false }]; + const exportInfo: readonly SymbolExportInfo[] = [{ + symbol: umdSymbol, + moduleSymbol: symbol, + moduleFileName: undefined, + exportKind: ExportKind.UMD, + targetFlags: symbol.flags, + isFromPackageJson: false, + }]; const useRequire = shouldUseRequire(sourceFile, program); // `usagePosition` is undefined because `token` may not actually be a usage of the symbol we're importing. // For example, we might need to import `React` in order to use an arbitrary JSX tag. We could send a position @@ -1055,7 +1426,16 @@ function getFixesInfoForUMDImport({ sourceFile, program, host, preferences }: Co // before a named import, like converting `writeFile` to `fs.writeFile` (whether `fs` is already imported or // not), and this function will only be called for UMD symbols, which are necessarily an `export =`, not a // named export. - const fixes = getImportFixes(exportInfo, /*usagePosition*/ undefined, /*isValidTypeOnlyUseSite*/ false, useRequire, program, sourceFile, host, preferences).fixes; + const fixes = getImportFixes( + exportInfo, + /*usagePosition*/ undefined, + /*isValidTypeOnlyUseSite*/ false, + useRequire, + program, + sourceFile, + host, + preferences, + ).fixes; return fixes.map(fix => ({ fix, symbolName, errorIdentifierText: tryCast(token, isIdentifier)?.text })); } function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined { @@ -1066,7 +1446,12 @@ function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined { // The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`. const { parent } = token; if ((isJsxOpeningLikeElement(parent) && parent.tagName === token) || isJsxOpeningFragment(parent)) { - const parentSymbol = checker.resolveName(checker.getJsxNamespace(parent), isJsxOpeningLikeElement(parent) ? token : parent, SymbolFlags.Value, /*excludeGlobals*/ false); + const parentSymbol = checker.resolveName( + checker.getJsxNamespace(parent), + isJsxOpeningLikeElement(parent) ? token : parent, + SymbolFlags.Value, + /*excludeGlobals*/ false, + ); if (isUMDExportSymbol(parentSymbol)) { return parentSymbol; } @@ -1080,21 +1465,39 @@ function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined { * * @internal */ -export function getImportKind(importingFile: SourceFile, exportKind: ExportKind, compilerOptions: CompilerOptions, forceImportKeyword?: boolean): ImportKind { - if (compilerOptions.verbatimModuleSyntax && (getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS || importingFile.impliedNodeFormat === ModuleKind.CommonJS)) { +export function getImportKind( + importingFile: SourceFile, + exportKind: ExportKind, + compilerOptions: CompilerOptions, + forceImportKeyword?: boolean, +): ImportKind { + if ( + compilerOptions.verbatimModuleSyntax + && (getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS + || importingFile.impliedNodeFormat === ModuleKind.CommonJS) + ) { // TODO: if the exporting file is ESM under nodenext, or `forceImport` is given in a JS file, this is impossible return ImportKind.CommonJS; } switch (exportKind) { - case ExportKind.Named: return ImportKind.Named; - case ExportKind.Default: return ImportKind.Default; - case ExportKind.ExportEquals: return getExportEqualsImportKind(importingFile, compilerOptions, !!forceImportKeyword); - case ExportKind.UMD: return getUmdImportKind(importingFile, compilerOptions, !!forceImportKeyword); - default: return Debug.assertNever(exportKind); + case ExportKind.Named: + return ImportKind.Named; + case ExportKind.Default: + return ImportKind.Default; + case ExportKind.ExportEquals: + return getExportEqualsImportKind(importingFile, compilerOptions, !!forceImportKeyword); + case ExportKind.UMD: + return getUmdImportKind(importingFile, compilerOptions, !!forceImportKeyword); + default: + return Debug.assertNever(exportKind); } } -function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions, forceImportKeyword: boolean): ImportKind { +function getUmdImportKind( + importingFile: SourceFile, + compilerOptions: CompilerOptions, + forceImportKeyword: boolean, +): ImportKind { // Import a synthetic `default` if enabled. if (getAllowSyntheticDefaultImports(compilerOptions)) { return ImportKind.Default; @@ -1107,7 +1510,8 @@ function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOp case ModuleKind.CommonJS: case ModuleKind.UMD: if (isInJSFile(importingFile)) { - return isExternalModule(importingFile) || forceImportKeyword ? ImportKind.Namespace : ImportKind.CommonJS; + return isExternalModule(importingFile) || forceImportKeyword ? ImportKind.Namespace + : ImportKind.CommonJS; } return ImportKind.CommonJS; case ModuleKind.System: @@ -1126,7 +1530,11 @@ function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOp } } -function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier })[] | undefined { +function getFixesInfoForNonUMDImport( + { sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, + symbolToken: Identifier, + useAutoImportProvider: boolean, +): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { const checker = program.getTypeChecker(); const compilerOptions = program.getCompilerOptions(); return flatMap(getSymbolNamesToImport(sourceFile, checker, symbolToken, compilerOptions), symbolName => { @@ -1136,16 +1544,48 @@ function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, h } const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite(symbolToken); const useRequire = shouldUseRequire(sourceFile, program); - const exportInfo = getExportInfos(symbolName, isJSXTagName(symbolToken), getMeaningFromLocation(symbolToken), cancellationToken, sourceFile, program, useAutoImportProvider, host, preferences); + const exportInfo = getExportInfos( + symbolName, + isJSXTagName(symbolToken), + getMeaningFromLocation(symbolToken), + cancellationToken, + sourceFile, + program, + useAutoImportProvider, + host, + preferences, + ); return arrayFrom( - flatMapIterator(exportInfo.values(), exportInfos => - getImportFixes(exportInfos, symbolToken.getStart(sourceFile), isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences).fixes), - fix => ({ fix, symbolName, errorIdentifierText: symbolToken.text, isJsxNamespaceFix: symbolName !== symbolToken.text }) + flatMapIterator( + exportInfo.values(), + exportInfos => + getImportFixes( + exportInfos, + symbolToken.getStart(sourceFile), + isValidTypeOnlyUseSite, + useRequire, + program, + sourceFile, + host, + preferences, + ).fixes, + ), + fix => ({ + fix, + symbolName, + errorIdentifierText: symbolToken.text, + isJsxNamespaceFix: symbolName !== symbolToken.text, + }), ); }); } -function getTypeOnlyPromotionFix(sourceFile: SourceFile, symbolToken: Identifier, symbolName: string, program: Program): FixPromoteTypeOnlyImport | undefined { +function getTypeOnlyPromotionFix( + sourceFile: SourceFile, + symbolToken: Identifier, + symbolName: string, + program: Program, +): FixPromoteTypeOnlyImport | undefined { const checker = program.getTypeChecker(); const symbol = checker.resolveName(symbolName, symbolToken, SymbolFlags.Value, /*excludeGlobals*/ true); if (!symbol) return undefined; @@ -1156,12 +1596,21 @@ function getTypeOnlyPromotionFix(sourceFile: SourceFile, symbolToken: Identifier return { kind: ImportFixKind.PromoteTypeOnly, typeOnlyAliasDeclaration }; } -function getSymbolNamesToImport(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier, compilerOptions: CompilerOptions): string[] { +function getSymbolNamesToImport( + sourceFile: SourceFile, + checker: TypeChecker, + symbolToken: Identifier, + compilerOptions: CompilerOptions, +): string[] { const parent = symbolToken.parent; - if ((isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken && jsxModeNeedsExplicitImport(compilerOptions.jsx)) { + if ( + (isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken + && jsxModeNeedsExplicitImport(compilerOptions.jsx) + ) { const jsxNamespace = checker.getJsxNamespace(sourceFile); if (needsJsxNamespaceFix(jsxNamespace, symbolToken, checker)) { - const needsComponentNameFix = !isIntrinsicJsxName(symbolToken.text) && !checker.resolveName(symbolToken.text, symbolToken, SymbolFlags.Value, /*excludeGlobals*/ false); + const needsComponentNameFix = !isIntrinsicJsxName(symbolToken.text) + && !checker.resolveName(symbolToken.text, symbolToken, SymbolFlags.Value, /*excludeGlobals*/ false); return needsComponentNameFix ? [symbolToken.text, jsxNamespace] : [jsxNamespace]; } } @@ -1171,7 +1620,9 @@ function getSymbolNamesToImport(sourceFile: SourceFile, checker: TypeChecker, sy function needsJsxNamespaceFix(jsxNamespace: string, symbolToken: Identifier, checker: TypeChecker) { if (isIntrinsicJsxName(symbolToken.text)) return true; // If we were triggered by a matching error code on an intrinsic, the error must have been about missing the JSX factory const namespaceSymbol = checker.resolveName(jsxNamespace, symbolToken, SymbolFlags.Value, /*excludeGlobals*/ true); - return !namespaceSymbol || some(namespaceSymbol.declarations, isTypeOnlyImportOrExportDeclaration) && !(namespaceSymbol.flags & SymbolFlags.Value); + return !namespaceSymbol + || some(namespaceSymbol.declarations, isTypeOnlyImportOrExportDeclaration) + && !(namespaceSymbol.flags & SymbolFlags.Value); } // Returns a map from an exported symbol's ID to a list of every way it's (re-)exported. @@ -1192,37 +1643,97 @@ function getExportInfos( const packageJsonFilter = createPackageJsonImportFilter(fromFile, preferences, host); const moduleSpecifierCache = host.getModuleSpecifierCache?.(); const getModuleSpecifierResolutionHost = memoizeOne((isFromPackageJson: boolean) => { - return createModuleSpecifierResolutionHost(isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, host); + return createModuleSpecifierResolutionHost( + isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, + host, + ); }); - function addSymbol(moduleSymbol: Symbol, toFile: SourceFile | undefined, exportedSymbol: Symbol, exportKind: ExportKind, program: Program, isFromPackageJson: boolean): void { + function addSymbol( + moduleSymbol: Symbol, + toFile: SourceFile | undefined, + exportedSymbol: Symbol, + exportKind: ExportKind, + program: Program, + isFromPackageJson: boolean, + ): void { const moduleSpecifierResolutionHost = getModuleSpecifierResolutionHost(isFromPackageJson); - if (toFile && isImportableFile(program, fromFile, toFile, preferences, packageJsonFilter, moduleSpecifierResolutionHost, moduleSpecifierCache) || - !toFile && packageJsonFilter.allowsImportingAmbientModule(moduleSymbol, moduleSpecifierResolutionHost) + if ( + toFile + && isImportableFile( + program, + fromFile, + toFile, + preferences, + packageJsonFilter, + moduleSpecifierResolutionHost, + moduleSpecifierCache, + ) + || !toFile && packageJsonFilter.allowsImportingAmbientModule(moduleSymbol, moduleSpecifierResolutionHost) ) { const checker = program.getTypeChecker(); - originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { symbol: exportedSymbol, moduleSymbol, moduleFileName: toFile?.fileName, exportKind, targetFlags: skipAlias(exportedSymbol, checker).flags, isFromPackageJson }); + originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { + symbol: exportedSymbol, + moduleSymbol, + moduleFileName: toFile?.fileName, + exportKind, + targetFlags: skipAlias(exportedSymbol, checker).flags, + isFromPackageJson, + }); } } - forEachExternalModuleToImportFrom(program, host, preferences, useAutoImportProvider, (moduleSymbol, sourceFile, program, isFromPackageJson) => { - const checker = program.getTypeChecker(); - cancellationToken.throwIfCancellationRequested(); - - const compilerOptions = program.getCompilerOptions(); - const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); - if (defaultInfo && (defaultInfo.name === symbolName || moduleSymbolToValidIdentifier(moduleSymbol, getEmitScriptTarget(compilerOptions), isJsxTagName) === symbolName) && symbolHasMeaning(defaultInfo.resolvedSymbol, currentTokenMeaning)) { - addSymbol(moduleSymbol, sourceFile, defaultInfo.symbol, defaultInfo.exportKind, program, isFromPackageJson); - } + forEachExternalModuleToImportFrom( + program, + host, + preferences, + useAutoImportProvider, + (moduleSymbol, sourceFile, program, isFromPackageJson) => { + const checker = program.getTypeChecker(); + cancellationToken.throwIfCancellationRequested(); + + const compilerOptions = program.getCompilerOptions(); + const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); + if ( + defaultInfo + && (defaultInfo.name === symbolName + || moduleSymbolToValidIdentifier(moduleSymbol, getEmitScriptTarget(compilerOptions), isJsxTagName) + === symbolName) + && symbolHasMeaning(defaultInfo.resolvedSymbol, currentTokenMeaning) + ) { + addSymbol( + moduleSymbol, + sourceFile, + defaultInfo.symbol, + defaultInfo.exportKind, + program, + isFromPackageJson, + ); + } - // check exports with the same name - const exportSymbolWithIdenticalName = checker.tryGetMemberInModuleExportsAndProperties(symbolName, moduleSymbol); - if (exportSymbolWithIdenticalName && symbolHasMeaning(exportSymbolWithIdenticalName, currentTokenMeaning)) { - addSymbol(moduleSymbol, sourceFile, exportSymbolWithIdenticalName, ExportKind.Named, program, isFromPackageJson); - } - }); + // check exports with the same name + const exportSymbolWithIdenticalName = checker.tryGetMemberInModuleExportsAndProperties( + symbolName, + moduleSymbol, + ); + if (exportSymbolWithIdenticalName && symbolHasMeaning(exportSymbolWithIdenticalName, currentTokenMeaning)) { + addSymbol( + moduleSymbol, + sourceFile, + exportSymbolWithIdenticalName, + ExportKind.Named, + program, + isFromPackageJson, + ); + } + }, + ); return originalSymbolToExportInfos; } -function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions, forceImportKeyword: boolean): ImportKind { +function getExportEqualsImportKind( + importingFile: SourceFile, + compilerOptions: CompilerOptions, + forceImportKeyword: boolean, +): ImportKind { const allowSyntheticDefaults = getAllowSyntheticDefaultImports(compilerOptions); const isJS = isInJSFile(importingFile); // 1. 'import =' will not work in es2015+ TS files, so the decision is between a default @@ -1251,14 +1762,38 @@ function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: C return allowSyntheticDefaults ? ImportKind.Default : ImportKind.CommonJS; } -function codeActionForFix(context: textChanges.TextChangesContext, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, compilerOptions: CompilerOptions, preferences: UserPreferences): CodeFixAction { +function codeActionForFix( + context: textChanges.TextChangesContext, + sourceFile: SourceFile, + symbolName: string, + fix: ImportFix, + includeSymbolNameInDescription: boolean, + compilerOptions: CompilerOptions, + preferences: UserPreferences, +): CodeFixAction { let diag!: DiagnosticOrDiagnosticAndArguments; const changes = textChanges.ChangeTracker.with(context, tracker => { - diag = codeActionForFixWorker(tracker, sourceFile, symbolName, fix, includeSymbolNameInDescription, compilerOptions, preferences); + diag = codeActionForFixWorker( + tracker, + sourceFile, + symbolName, + fix, + includeSymbolNameInDescription, + compilerOptions, + preferences, + ); }); return createCodeFixAction(importFixName, changes, diag, importFixId, Diagnostics.Add_all_missing_imports); } -function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, compilerOptions: CompilerOptions, preferences: UserPreferences): DiagnosticOrDiagnosticAndArguments { +function codeActionForFixWorker( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + symbolName: string, + fix: ImportFix, + includeSymbolNameInDescription: boolean, + compilerOptions: CompilerOptions, + preferences: UserPreferences, +): DiagnosticOrDiagnosticAndArguments { const quotePreference = getQuotePreference(sourceFile, preferences); switch (fix.kind) { case ImportFixKind.UseNamespace: @@ -1266,7 +1801,11 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: return [Diagnostics.Change_0_to_1, symbolName, `${fix.namespacePrefix}.${symbolName}`]; case ImportFixKind.JsdocTypeImport: addImportType(changes, sourceFile, fix, quotePreference); - return [Diagnostics.Change_0_to_1, symbolName, getImportTypePrefix(fix.moduleSpecifier, quotePreference) + symbolName]; + return [ + Diagnostics.Change_0_to_1, + symbolName, + getImportTypePrefix(fix.moduleSpecifier, quotePreference) + symbolName, + ]; case ImportFixKind.AddToExisting: { const { importClauseOrBindingPattern, importKind, addAsTypeOnly, moduleSpecifier } = fix; doAddExistingFix( @@ -1275,7 +1814,8 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: importClauseOrBindingPattern, importKind === ImportKind.Default ? { name: symbolName, addAsTypeOnly } : undefined, importKind === ImportKind.Named ? [{ name: symbolName, addAsTypeOnly }] : emptyArray, - preferences); + preferences, + ); const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier); return includeSymbolNameInDescription ? [Diagnostics.Import_0_from_1, symbolName, moduleSpecifierWithoutQuotes] @@ -1284,18 +1824,27 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: case ImportFixKind.AddNew: { const { importKind, moduleSpecifier, addAsTypeOnly, useRequire, qualification } = fix; const getDeclarations = useRequire ? getNewRequires : getNewImports; - const defaultImport: Import | undefined = importKind === ImportKind.Default ? { name: symbolName, addAsTypeOnly } : undefined; - const namedImports: Import[] | undefined = importKind === ImportKind.Named ? [{ name: symbolName, addAsTypeOnly }] : undefined; + const defaultImport: Import | undefined = importKind === ImportKind.Default + ? { name: symbolName, addAsTypeOnly } : undefined; + const namedImports: Import[] | undefined = importKind === ImportKind.Named + ? [{ name: symbolName, addAsTypeOnly }] : undefined; const namespaceLikeImport = importKind === ImportKind.Namespace || importKind === ImportKind.CommonJS ? { importKind, name: qualification?.namespacePrefix || symbolName, addAsTypeOnly } : undefined; - insertImports(changes, sourceFile, getDeclarations( - moduleSpecifier, - quotePreference, - defaultImport, - namedImports, - namespaceLikeImport, - compilerOptions), /*blankLineBetween*/ true, preferences); + insertImports( + changes, + sourceFile, + getDeclarations( + moduleSpecifier, + quotePreference, + defaultImport, + namedImports, + namespaceLikeImport, + compilerOptions, + ), + /*blankLineBetween*/ true, + preferences, + ); if (qualification) { addNamespaceQualifier(changes, sourceFile, qualification); } @@ -1305,9 +1854,19 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: } case ImportFixKind.PromoteTypeOnly: { const { typeOnlyAliasDeclaration } = fix; - const promotedDeclaration = promoteFromTypeOnly(changes, typeOnlyAliasDeclaration, compilerOptions, sourceFile, preferences); + const promotedDeclaration = promoteFromTypeOnly( + changes, + typeOnlyAliasDeclaration, + compilerOptions, + sourceFile, + preferences, + ); return promotedDeclaration.kind === SyntaxKind.ImportSpecifier - ? [Diagnostics.Remove_type_from_import_of_0_from_1, symbolName, getModuleSpecifierText(promotedDeclaration.parent.parent)] + ? [ + Diagnostics.Remove_type_from_import_of_0_from_1, + symbolName, + getModuleSpecifierText(promotedDeclaration.parent.parent), + ] : [Diagnostics.Remove_type_from_import_declaration_from_0, getModuleSpecifierText(promotedDeclaration)]; } default: @@ -1317,23 +1876,52 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: function getModuleSpecifierText(promotedDeclaration: ImportClause | ImportEqualsDeclaration): string { return promotedDeclaration.kind === SyntaxKind.ImportEqualsDeclaration - ? tryCast(tryCast(promotedDeclaration.moduleReference, isExternalModuleReference)?.expression, isStringLiteralLike)?.text || promotedDeclaration.moduleReference.getText() + ? tryCast( + tryCast(promotedDeclaration.moduleReference, isExternalModuleReference)?.expression, + isStringLiteralLike, + )?.text || promotedDeclaration.moduleReference.getText() : cast(promotedDeclaration.parent.moduleSpecifier, isStringLiteral).text; } -function promoteFromTypeOnly(changes: textChanges.ChangeTracker, aliasDeclaration: TypeOnlyAliasDeclaration, compilerOptions: CompilerOptions, sourceFile: SourceFile, preferences: UserPreferences) { +function promoteFromTypeOnly( + changes: textChanges.ChangeTracker, + aliasDeclaration: TypeOnlyAliasDeclaration, + compilerOptions: CompilerOptions, + sourceFile: SourceFile, + preferences: UserPreferences, +) { // See comment in `doAddExistingFix` on constant with the same name. const convertExistingToTypeOnly = importNameElisionDisabled(compilerOptions); switch (aliasDeclaration.kind) { case SyntaxKind.ImportSpecifier: if (aliasDeclaration.isTypeOnly) { - const sortKind = OrganizeImports.detectImportSpecifierSorting(aliasDeclaration.parent.elements, preferences); + const sortKind = OrganizeImports.detectImportSpecifierSorting( + aliasDeclaration.parent.elements, + preferences, + ); if (aliasDeclaration.parent.elements.length > 1 && sortKind) { changes.delete(sourceFile, aliasDeclaration); - const newSpecifier = factory.updateImportSpecifier(aliasDeclaration, /*isTypeOnly*/ false, aliasDeclaration.propertyName, aliasDeclaration.name); - const comparer = OrganizeImports.getOrganizeImportsComparer(preferences, sortKind === SortKind.CaseInsensitive); - const insertionIndex = OrganizeImports.getImportSpecifierInsertionIndex(aliasDeclaration.parent.elements, newSpecifier, comparer); - changes.insertImportSpecifierAtIndex(sourceFile, newSpecifier, aliasDeclaration.parent, insertionIndex); + const newSpecifier = factory.updateImportSpecifier( + aliasDeclaration, + /*isTypeOnly*/ false, + aliasDeclaration.propertyName, + aliasDeclaration.name, + ); + const comparer = OrganizeImports.getOrganizeImportsComparer( + preferences, + sortKind === SortKind.CaseInsensitive, + ); + const insertionIndex = OrganizeImports.getImportSpecifierInsertionIndex( + aliasDeclaration.parent.elements, + newSpecifier, + comparer, + ); + changes.insertImportSpecifierAtIndex( + sourceFile, + newSpecifier, + aliasDeclaration.parent, + insertionIndex, + ); } else { changes.deleteRange(sourceFile, aliasDeclaration.getFirstToken()!); @@ -1363,18 +1951,27 @@ function promoteFromTypeOnly(changes: textChanges.ChangeTracker, aliasDeclaratio // Change .ts extension to .js if necessary if (!compilerOptions.allowImportingTsExtensions) { const moduleSpecifier = tryGetModuleSpecifierFromDeclaration(importClause.parent); - const resolvedModule = moduleSpecifier && getResolvedModule(sourceFile, moduleSpecifier.text, getModeForUsageLocation(sourceFile, moduleSpecifier)); + const resolvedModule = moduleSpecifier + && getResolvedModule( + sourceFile, + moduleSpecifier.text, + getModeForUsageLocation(sourceFile, moduleSpecifier), + ); if (resolvedModule?.resolvedUsingTsExtension) { - const changedExtension = changeAnyExtension(moduleSpecifier!.text, getOutputExtension(moduleSpecifier!.text, compilerOptions)); + const changedExtension = changeAnyExtension( + moduleSpecifier!.text, + getOutputExtension(moduleSpecifier!.text, compilerOptions), + ); changes.replaceNode(sourceFile, moduleSpecifier!, factory.createStringLiteral(changedExtension)); } } if (convertExistingToTypeOnly) { const namedImports = tryCast(importClause.namedBindings, isNamedImports); if (namedImports && namedImports.elements.length > 1) { - if (OrganizeImports.detectImportSpecifierSorting(namedImports.elements, preferences) && - aliasDeclaration.kind === SyntaxKind.ImportSpecifier && - namedImports.elements.indexOf(aliasDeclaration) !== 0 + if ( + OrganizeImports.detectImportSpecifierSorting(namedImports.elements, preferences) + && aliasDeclaration.kind === SyntaxKind.ImportSpecifier + && namedImports.elements.indexOf(aliasDeclaration) !== 0 ) { // The import specifier being promoted will be the only non-type-only, // import in the NamedImports, so it should be moved to the front. @@ -1409,12 +2006,15 @@ function doAddExistingFix( return; } - const promoteFromTypeOnly = clause.isTypeOnly && some([defaultImport, ...namedImports], i => i?.addAsTypeOnly === AddAsTypeOnly.NotAllowed); + const promoteFromTypeOnly = clause.isTypeOnly + && some([defaultImport, ...namedImports], i => i?.addAsTypeOnly === AddAsTypeOnly.NotAllowed); const existingSpecifiers = clause.namedBindings && tryCast(clause.namedBindings, isNamedImports)?.elements; if (defaultImport) { Debug.assert(!clause.name, "Cannot add a default import to an import clause that already has one"); - changes.insertNodeAt(sourceFile, clause.getStart(sourceFile), factory.createIdentifier(defaultImport.name), { suffix: ", " }); + changes.insertNodeAt(sourceFile, clause.getStart(sourceFile), factory.createIdentifier(defaultImport.name), { + suffix: ", ", + }); } if (namedImports.length) { @@ -1438,18 +2038,23 @@ function doAddExistingFix( const comparer = OrganizeImports.getOrganizeImportsComparer(preferences, ignoreCaseForSorting); const newSpecifiers = stableSort( - namedImports.map(namedImport => factory.createImportSpecifier( - (!clause.isTypeOnly || promoteFromTypeOnly) && needsTypeOnly(namedImport), - /*propertyName*/ undefined, - factory.createIdentifier(namedImport.name))), - (s1, s2) => OrganizeImports.compareImportOrExportSpecifiers(s1, s2, comparer)); + namedImports.map(namedImport => + factory.createImportSpecifier( + (!clause.isTypeOnly || promoteFromTypeOnly) && needsTypeOnly(namedImport), + /*propertyName*/ undefined, + factory.createIdentifier(namedImport.name), + ) + ), + (s1, s2) => OrganizeImports.compareImportOrExportSpecifiers(s1, s2, comparer), + ); // The sorting preference computed earlier may or may not have validated that these particular // import specifiers are sorted. If they aren't, `getImportSpecifierInsertionIndex` will return // nonsense. So if there are existing specifiers, even if we know the sorting preference, we // need to ensure that the existing specifiers are sorted according to the preference in order // to do a sorted insertion. - const specifierSort = existingSpecifiers?.length && OrganizeImports.detectImportSpecifierSorting(existingSpecifiers, preferences); + const specifierSort = existingSpecifiers?.length + && OrganizeImports.detectImportSpecifierSorting(existingSpecifiers, preferences); if (specifierSort && !(ignoreCaseForSorting && specifierSort === SortKind.CaseSensitive)) { for (const spec of newSpecifiers) { // Organize imports puts type-only import specifiers last, so if we're @@ -1458,7 +2063,12 @@ function doAddExistingFix( const insertionIndex = promoteFromTypeOnly && !spec.isTypeOnly ? 0 : OrganizeImports.getImportSpecifierInsertionIndex(existingSpecifiers, spec, comparer); - changes.insertImportSpecifierAtIndex(sourceFile, spec, clause.namedBindings as NamedImports, insertionIndex); + changes.insertImportSpecifierAtIndex( + sourceFile, + spec, + clause.namedBindings as NamedImports, + insertionIndex, + ); } } else if (existingSpecifiers?.length) { @@ -1473,7 +2083,14 @@ function doAddExistingFix( changes.replaceNode(sourceFile, clause.namedBindings, namedImports); } else { - changes.insertNodeAfter(sourceFile, Debug.checkDefined(clause.name, "Import clause must have either named imports or a default import"), namedImports); + changes.insertNodeAfter( + sourceFile, + Debug.checkDefined( + clause.name, + "Import clause must have either named imports or a default import", + ), + namedImports, + ); } } } @@ -1492,7 +2109,11 @@ function doAddExistingFix( } } - function addElementToBindingPattern(bindingPattern: ObjectBindingPattern, name: string, propertyName: string | undefined) { + function addElementToBindingPattern( + bindingPattern: ObjectBindingPattern, + name: string, + propertyName: string | undefined, + ) { const element = factory.createBindingElement(/*dotDotDotToken*/ undefined, propertyName, name); if (bindingPattern.elements.length) { changes.insertNodeInListAfter(sourceFile, last(bindingPattern.elements), element); @@ -1503,11 +2124,20 @@ function doAddExistingFix( } } -function addNamespaceQualifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { namespacePrefix, usagePosition }: Qualification): void { +function addNamespaceQualifier( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { namespacePrefix, usagePosition }: Qualification, +): void { changes.insertText(sourceFile, usagePosition, namespacePrefix + "."); } -function addImportType(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { moduleSpecifier, usagePosition: position }: FixAddJsdocTypeImport, quotePreference: QuotePreference): void { +function addImportType( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + { moduleSpecifier, usagePosition: position }: FixAddJsdocTypeImport, + quotePreference: QuotePreference, +): void { changes.insertText(sourceFile, position, getImportTypePrefix(moduleSpecifier, quotePreference)); } @@ -1531,7 +2161,7 @@ interface ImportsCollection { }; } -function needsTypeOnly({ addAsTypeOnly }: { addAsTypeOnly: AddAsTypeOnly }): boolean { +function needsTypeOnly({ addAsTypeOnly }: { addAsTypeOnly: AddAsTypeOnly; }): boolean { return addAsTypeOnly === AddAsTypeOnly.Required; } @@ -1540,7 +2170,7 @@ function getNewImports( quotePreference: QuotePreference, defaultImport: Import | undefined, namedImports: readonly Import[] | undefined, - namespaceLikeImport: Import & { importKind: ImportKind.CommonJS | ImportKind.Namespace } | undefined, + namespaceLikeImport: Import & { importKind: ImportKind.CommonJS | ImportKind.Namespace; } | undefined, compilerOptions: CompilerOptions, ): AnyImportSyntax | readonly AnyImportSyntax[] { const quotedModuleSpecifier = makeStringLiteral(moduleSpecifier, quotePreference); @@ -1548,19 +2178,26 @@ function getNewImports( if (defaultImport !== undefined || namedImports?.length) { // `verbatimModuleSyntax` should prefer top-level `import type` - // even though it's not an error, it would add unnecessary runtime emit. - const topLevelTypeOnly = (!defaultImport || needsTypeOnly(defaultImport)) && every(namedImports, needsTypeOnly) || - compilerOptions.verbatimModuleSyntax && - defaultImport?.addAsTypeOnly !== AddAsTypeOnly.NotAllowed && - !some(namedImports, i => i.addAsTypeOnly === AddAsTypeOnly.NotAllowed); - statements = combine(statements, makeImport( - defaultImport && factory.createIdentifier(defaultImport.name), - namedImports?.map(({ addAsTypeOnly, name }) => factory.createImportSpecifier( - !topLevelTypeOnly && addAsTypeOnly === AddAsTypeOnly.Required, - /*propertyName*/ undefined, - factory.createIdentifier(name))), - moduleSpecifier, - quotePreference, - topLevelTypeOnly)); + const topLevelTypeOnly = (!defaultImport || needsTypeOnly(defaultImport)) && every(namedImports, needsTypeOnly) + || compilerOptions.verbatimModuleSyntax + && defaultImport?.addAsTypeOnly !== AddAsTypeOnly.NotAllowed + && !some(namedImports, i => i.addAsTypeOnly === AddAsTypeOnly.NotAllowed); + statements = combine( + statements, + makeImport( + defaultImport && factory.createIdentifier(defaultImport.name), + namedImports?.map(({ addAsTypeOnly, name }) => + factory.createImportSpecifier( + !topLevelTypeOnly && addAsTypeOnly === AddAsTypeOnly.Required, + /*propertyName*/ undefined, + factory.createIdentifier(name), + ) + ), + moduleSpecifier, + quotePreference, + topLevelTypeOnly, + ), + ); } if (namespaceLikeImport) { @@ -1569,30 +2206,46 @@ function getNewImports( /*modifiers*/ undefined, needsTypeOnly(namespaceLikeImport), factory.createIdentifier(namespaceLikeImport.name), - factory.createExternalModuleReference(quotedModuleSpecifier)) + factory.createExternalModuleReference(quotedModuleSpecifier), + ) : factory.createImportDeclaration( /*modifiers*/ undefined, factory.createImportClause( needsTypeOnly(namespaceLikeImport), /*name*/ undefined, - factory.createNamespaceImport(factory.createIdentifier(namespaceLikeImport.name))), + factory.createNamespaceImport(factory.createIdentifier(namespaceLikeImport.name)), + ), quotedModuleSpecifier, - /*assertClause*/ undefined); + /*assertClause*/ undefined, + ); statements = combine(statements, declaration); } return Debug.checkDefined(statements); } -function getNewRequires(moduleSpecifier: string, quotePreference: QuotePreference, defaultImport: Import | undefined, namedImports: readonly Import[] | undefined, namespaceLikeImport: Import | undefined): RequireVariableStatement | readonly RequireVariableStatement[] { +function getNewRequires( + moduleSpecifier: string, + quotePreference: QuotePreference, + defaultImport: Import | undefined, + namedImports: readonly Import[] | undefined, + namespaceLikeImport: Import | undefined, +): RequireVariableStatement | readonly RequireVariableStatement[] { const quotedModuleSpecifier = makeStringLiteral(moduleSpecifier, quotePreference); let statements: RequireVariableStatement | readonly RequireVariableStatement[] | undefined; // const { default: foo, bar, etc } = require('./mod'); if (defaultImport || namedImports?.length) { - const bindingElements = namedImports?.map(({ name }) => factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, name)) || []; + const bindingElements = namedImports?.map(({ name }) => + factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, name) + ) || []; if (defaultImport) { - bindingElements.unshift(factory.createBindingElement(/*dotDotDotToken*/ undefined, "default", defaultImport.name)); + bindingElements.unshift( + factory.createBindingElement(/*dotDotDotToken*/ undefined, "default", defaultImport.name), + ); } - const declaration = createConstEqualsRequireDeclaration(factory.createObjectBindingPattern(bindingElements), quotedModuleSpecifier); + const declaration = createConstEqualsRequireDeclaration( + factory.createObjectBindingPattern(bindingElements), + quotedModuleSpecifier, + ); statements = combine(statements, declaration); } // const foo = require('./mod'); @@ -1603,7 +2256,10 @@ function getNewRequires(moduleSpecifier: string, quotePreference: QuotePreferenc return Debug.checkDefined(statements); } -function createConstEqualsRequireDeclaration(name: string | ObjectBindingPattern, quotedModuleSpecifier: StringLiteral): RequireVariableStatement { +function createConstEqualsRequireDeclaration( + name: string | ObjectBindingPattern, + quotedModuleSpecifier: StringLiteral, +): RequireVariableStatement { return factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList([ @@ -1611,8 +2267,12 @@ function createConstEqualsRequireDeclaration(name: string | ObjectBindingPattern typeof name === "string" ? factory.createIdentifier(name) : name, /*exclamationToken*/ undefined, /*type*/ undefined, - factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [quotedModuleSpecifier]))], - NodeFlags.Const)) as RequireVariableStatement; + factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [ + quotedModuleSpecifier, + ]), + ), + ], NodeFlags.Const), + ) as RequireVariableStatement; } function symbolHasMeaning({ declarations }: Symbol, meaning: SemanticMeaning): boolean { @@ -1620,12 +2280,24 @@ function symbolHasMeaning({ declarations }: Symbol, meaning: SemanticMeaning): b } /** @internal */ -export function moduleSymbolToValidIdentifier(moduleSymbol: Symbol, target: ScriptTarget | undefined, forceCapitalize: boolean): string { - return moduleSpecifierToValidIdentifier(removeFileExtension(stripQuotes(moduleSymbol.name)), target, forceCapitalize); +export function moduleSymbolToValidIdentifier( + moduleSymbol: Symbol, + target: ScriptTarget | undefined, + forceCapitalize: boolean, +): string { + return moduleSpecifierToValidIdentifier( + removeFileExtension(stripQuotes(moduleSymbol.name)), + target, + forceCapitalize, + ); } /** @internal */ -export function moduleSpecifierToValidIdentifier(moduleSpecifier: string, target: ScriptTarget | undefined, forceCapitalize?: boolean): string { +export function moduleSpecifierToValidIdentifier( + moduleSpecifier: string, + target: ScriptTarget | undefined, + forceCapitalize?: boolean, +): string { const baseName = getBaseFileName(removeSuffix(moduleSpecifier, "/index")); let res = ""; let lastCharWasValid = true; diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index af21562a22a27..41e335a2e532f 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -145,11 +145,13 @@ const errorCodes = [ Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code, // Get Accessor declarations - Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage.code, + Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage + .code, Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage.code, // Set Accessor declarations - Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage.code, + Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage + .code, // Property declarations Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code, @@ -165,18 +167,44 @@ registerCodeFix({ const token = getTokenAtPosition(sourceFile, start); let declaration: Declaration | undefined; const changes = textChanges.ChangeTracker.with(context, changes => { - declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeen*/ returnTrue, host, preferences); + declaration = doChange( + changes, + sourceFile, + token, + errorCode, + program, + cancellationToken, + /*markSeen*/ returnTrue, + host, + preferences, + ); }); const name = declaration && getNameOfDeclaration(declaration); return !name || changes.length === 0 ? undefined - : [createCodeFixAction(fixId, changes, [getDiagnostic(errorCode, token), getTextOfNode(name)], fixId, Diagnostics.Infer_all_types_from_usage)]; + : [createCodeFixAction( + fixId, + changes, + [getDiagnostic(errorCode, token), getTextOfNode(name)], + fixId, + Diagnostics.Infer_all_types_from_usage, + )]; }, fixIds: [fixId], getAllCodeActions(context) { const { sourceFile, program, cancellationToken, host, preferences } = context; const markSeen = nodeSeenTracker(); return codeFixAll(context, errorCodes, (changes, err) => { - doChange(changes, sourceFile, getTokenAtPosition(err.file, err.start), err.code, program, cancellationToken, markSeen, host, preferences); + doChange( + changes, + sourceFile, + getTokenAtPosition(err.file, err.start), + err.code, + program, + cancellationToken, + markSeen, + host, + preferences, + ); }); }, }); @@ -185,7 +213,8 @@ function getDiagnostic(errorCode: number, token: Node): DiagnosticMessage { switch (errorCode) { case Diagnostics.Parameter_0_implicitly_has_an_1_type.code: case Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code: - return isSetAccessorDeclaration(getContainingFunction(token)!) ? Diagnostics.Infer_type_of_0_from_usage : Diagnostics.Infer_parameter_types_from_usage; // TODO: GH#18217 + return isSetAccessorDeclaration(getContainingFunction(token)!) ? Diagnostics.Infer_type_of_0_from_usage + : Diagnostics.Infer_parameter_types_from_usage; // TODO: GH#18217 case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code: case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics.Infer_parameter_types_from_usage; @@ -199,28 +228,47 @@ function getDiagnostic(errorCode: number, token: Node): DiagnosticMessage { /** Map suggestion code to error code */ function mapSuggestionDiagnostic(errorCode: number) { switch (errorCode) { - case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage.code: - return Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code; + case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_but_a_better_type_may_be_inferred_from_usage + .code: + return Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined + .code; case Diagnostics.Variable_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics.Variable_0_implicitly_has_an_1_type.code; case Diagnostics.Parameter_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics.Parameter_0_implicitly_has_an_1_type.code; case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code; - case Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage.code: - return Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code; + case Diagnostics + .Property_0_implicitly_has_type_any_but_a_better_type_for_its_get_accessor_may_be_inferred_from_usage.code: + return Diagnostics + .Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code; case Diagnostics._0_implicitly_has_an_1_return_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type.code; - case Diagnostics.Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage.code: - return Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code; + case Diagnostics + .Property_0_implicitly_has_type_any_but_a_better_type_for_its_set_accessor_may_be_inferred_from_usage.code: + return Diagnostics + .Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code; case Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code: return Diagnostics.Member_0_implicitly_has_an_1_type.code; } return errorCode; } -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, markSeen: NodeSeenTracker, host: LanguageServiceHost, preferences: UserPreferences): Declaration | undefined { - if (!isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier && token.kind !== SyntaxKind.DotDotDotToken && token.kind !== SyntaxKind.ThisKeyword) { +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + token: Node, + errorCode: number, + program: Program, + cancellationToken: CancellationToken, + markSeen: NodeSeenTracker, + host: LanguageServiceHost, + preferences: UserPreferences, +): Declaration | undefined { + if ( + !isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier + && token.kind !== SyntaxKind.DotDotDotToken && token.kind !== SyntaxKind.ThisKeyword + ) { return undefined; } @@ -231,7 +279,10 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, to // Variable and Property declarations case Diagnostics.Member_0_implicitly_has_an_1_type.code: case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code: - if ((isVariableDeclaration(parent) && markSeen(parent)) || isPropertyDeclaration(parent) || isPropertySignature(parent)) { // handle bad location + if ( + (isVariableDeclaration(parent) && markSeen(parent)) || isPropertyDeclaration(parent) + || isPropertySignature(parent) + ) { // handle bad location annotateVariableDeclaration(changes, importAdder, sourceFile, parent, program, host, cancellationToken); importAdder.writeFixes(changes); return parent; @@ -241,7 +292,11 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, to const typeNode = getTypeNodeIfAccessible(type, parent, program, host); if (typeNode) { // Note that the codefix will never fire with an existing `@type` tag, so there is no need to merge tags - const typeTag = factory.createJSDocTypeTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(typeNode), /*comment*/ undefined); + const typeTag = factory.createJSDocTypeTag( + /*tagName*/ undefined, + factory.createJSDocTypeExpression(typeNode), + /*comment*/ undefined, + ); changes.addJSDocTags(sourceFile, cast(parent.parent.parent, isExpressionStatement), [typeTag]); } importAdder.writeFixes(changes); @@ -251,8 +306,19 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, to case Diagnostics.Variable_0_implicitly_has_an_1_type.code: { const symbol = program.getTypeChecker().getSymbolAtLocation(token); - if (symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && markSeen(symbol.valueDeclaration)) { - annotateVariableDeclaration(changes, importAdder, getSourceFileOfNode(symbol.valueDeclaration), symbol.valueDeclaration, program, host, cancellationToken); + if ( + symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) + && markSeen(symbol.valueDeclaration) + ) { + annotateVariableDeclaration( + changes, + importAdder, + getSourceFileOfNode(symbol.valueDeclaration), + symbol.valueDeclaration, + program, + host, + cancellationToken, + ); importAdder.writeFixes(changes); return symbol.valueDeclaration; } @@ -270,7 +336,15 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, to // Parameter declarations case Diagnostics.Parameter_0_implicitly_has_an_1_type.code: if (isSetAccessorDeclaration(containingFunction)) { - annotateSetAccessor(changes, importAdder, sourceFile, containingFunction, program, host, cancellationToken); + annotateSetAccessor( + changes, + importAdder, + sourceFile, + containingFunction, + program, + host, + cancellationToken, + ); declaration = containingFunction; break; } @@ -278,24 +352,51 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, to case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code: if (markSeen(containingFunction)) { const param = cast(parent, isParameter); - annotateParameters(changes, importAdder, sourceFile, param, containingFunction, program, host, cancellationToken); + annotateParameters( + changes, + importAdder, + sourceFile, + param, + containingFunction, + program, + host, + cancellationToken, + ); declaration = param; } break; // Get Accessor declarations - case Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code: + case Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation + .code: case Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type.code: if (isGetAccessorDeclaration(containingFunction) && isIdentifier(containingFunction.name)) { - annotate(changes, importAdder, sourceFile, containingFunction, inferTypeForVariableFromUsage(containingFunction.name, program, cancellationToken), program, host); + annotate( + changes, + importAdder, + sourceFile, + containingFunction, + inferTypeForVariableFromUsage(containingFunction.name, program, cancellationToken), + program, + host, + ); declaration = containingFunction; } break; // Set Accessor declarations - case Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code: + case Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation + .code: if (isSetAccessorDeclaration(containingFunction)) { - annotateSetAccessor(changes, importAdder, sourceFile, containingFunction, program, host, cancellationToken); + annotateSetAccessor( + changes, + importAdder, + sourceFile, + containingFunction, + program, + host, + cancellationToken, + ); declaration = containingFunction; } break; @@ -326,7 +427,15 @@ function annotateVariableDeclaration( cancellationToken: CancellationToken, ): void { if (isIdentifier(declaration.name)) { - annotate(changes, importAdder, sourceFile, declaration, inferTypeForVariableFromUsage(declaration.name, program, cancellationToken), program, host); + annotate( + changes, + importAdder, + sourceFile, + declaration, + inferTypeForVariableFromUsage(declaration.name, program, cancellationToken), + program, + host, + ); } } @@ -344,25 +453,53 @@ function annotateParameters( return; } - const parameterInferences = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken); - Debug.assert(containingFunction.parameters.length === parameterInferences.length, "Parameter count and inference count should match"); + const parameterInferences = inferTypeForParametersFromUsage( + containingFunction, + sourceFile, + program, + cancellationToken, + ); + Debug.assert( + containingFunction.parameters.length === parameterInferences.length, + "Parameter count and inference count should match", + ); if (isInJSFile(containingFunction)) { annotateJSDocParameters(changes, sourceFile, parameterInferences, program, host); } else { - const needParens = isArrowFunction(containingFunction) && !findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile); - if (needParens) changes.insertNodeBefore(sourceFile, first(containingFunction.parameters), factory.createToken(SyntaxKind.OpenParenToken)); + const needParens = isArrowFunction(containingFunction) + && !findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile); + if (needParens) { + changes.insertNodeBefore( + sourceFile, + first(containingFunction.parameters), + factory.createToken(SyntaxKind.OpenParenToken), + ); + } for (const { declaration, type } of parameterInferences) { if (declaration && !declaration.type && !declaration.initializer) { annotate(changes, importAdder, sourceFile, declaration, type, program, host); } } - if (needParens) changes.insertNodeAfter(sourceFile, last(containingFunction.parameters), factory.createToken(SyntaxKind.CloseParenToken)); + if (needParens) { + changes.insertNodeAfter( + sourceFile, + last(containingFunction.parameters), + factory.createToken(SyntaxKind.CloseParenToken), + ); + } } } -function annotateThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile, containingFunction: textChanges.ThisTypeAnnotatable, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken) { +function annotateThis( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + containingFunction: textChanges.ThisTypeAnnotatable, + program: Program, + host: LanguageServiceHost, + cancellationToken: CancellationToken, +) { const references = getFunctionReferences(containingFunction, sourceFile, program, cancellationToken); if (!references || !references.length) { return; @@ -381,7 +518,12 @@ function annotateThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile } } -function annotateJSDocThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile, containingFunction: SignatureDeclaration, typeNode: TypeNode) { +function annotateJSDocThis( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + containingFunction: SignatureDeclaration, + typeNode: TypeNode, +) { changes.addJSDocTags(sourceFile, containingFunction, [ factory.createJSDocThisTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(typeNode)), ]); @@ -395,7 +537,6 @@ function annotateSetAccessor( program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken, - ): void { const param = firstOrUndefined(setAccessorDeclaration.parameters); if (param && isIdentifier(setAccessorDeclaration.name) && isIdentifier(param.name)) { @@ -412,19 +553,39 @@ function annotateSetAccessor( } } -function annotate(changes: textChanges.ChangeTracker, importAdder: ImportAdder, sourceFile: SourceFile, declaration: textChanges.TypeAnnotatable, type: Type, program: Program, host: LanguageServiceHost): void { +function annotate( + changes: textChanges.ChangeTracker, + importAdder: ImportAdder, + sourceFile: SourceFile, + declaration: textChanges.TypeAnnotatable, + type: Type, + program: Program, + host: LanguageServiceHost, +): void { const typeNode = getTypeNodeIfAccessible(type, declaration, program, host); if (typeNode) { if (isInJSFile(sourceFile) && declaration.kind !== SyntaxKind.PropertySignature) { - const parent = isVariableDeclaration(declaration) ? tryCast(declaration.parent.parent, isVariableStatement) : declaration; + const parent = isVariableDeclaration(declaration) ? tryCast(declaration.parent.parent, isVariableStatement) + : declaration; if (!parent) { return; } const typeExpression = factory.createJSDocTypeExpression(typeNode); - const typeTag = isGetAccessorDeclaration(declaration) ? factory.createJSDocReturnTag(/*tagName*/ undefined, typeExpression, /*comment*/ undefined) : factory.createJSDocTypeTag(/*tagName*/ undefined, typeExpression, /*comment*/ undefined); + const typeTag = isGetAccessorDeclaration(declaration) + ? factory.createJSDocReturnTag(/*tagName*/ undefined, typeExpression, /*comment*/ undefined) + : factory.createJSDocTypeTag(/*tagName*/ undefined, typeExpression, /*comment*/ undefined); changes.addJSDocTags(sourceFile, parent, [typeTag]); } - else if (!tryReplaceImportTypeNodeWithAutoImport(typeNode, declaration, sourceFile, changes, importAdder, getEmitScriptTarget(program.getCompilerOptions()))) { + else if ( + !tryReplaceImportTypeNodeWithAutoImport( + typeNode, + declaration, + sourceFile, + changes, + importAdder, + getEmitScriptTarget(program.getCompilerOptions()), + ) + ) { changes.tryInsertTypeAnnotation(sourceFile, declaration, typeNode); } } @@ -436,17 +597,26 @@ function tryReplaceImportTypeNodeWithAutoImport( sourceFile: SourceFile, changes: textChanges.ChangeTracker, importAdder: ImportAdder, - scriptTarget: ScriptTarget + scriptTarget: ScriptTarget, ): boolean { const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget); if (importableReference && changes.tryInsertTypeAnnotation(sourceFile, declaration, importableReference.typeNode)) { - forEach(importableReference.symbols, s => importAdder.addImportFromExportedSymbol(s, /*isValidTypeOnlyUseSite*/ true)); + forEach( + importableReference.symbols, + s => importAdder.addImportFromExportedSymbol(s, /*isValidTypeOnlyUseSite*/ true), + ); return true; } return false; } -function annotateJSDocParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parameterInferences: readonly ParameterInference[], program: Program, host: LanguageServiceHost): void { +function annotateJSDocParameters( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + parameterInferences: readonly ParameterInference[], + program: Program, + host: LanguageServiceHost, +): void { const signature = parameterInferences.length && parameterInferences[0].declaration.parent; if (!signature) { return; @@ -471,60 +641,107 @@ function annotateJSDocParameters(changes: textChanges.ChangeTracker, sourceFile: } if (isArrowFunction(signature) || isFunctionExpression(signature)) { - const needParens = isArrowFunction(signature) && !findChildOfKind(signature, SyntaxKind.OpenParenToken, sourceFile); + const needParens = isArrowFunction(signature) + && !findChildOfKind(signature, SyntaxKind.OpenParenToken, sourceFile); if (needParens) { - changes.insertNodeBefore(sourceFile, first(signature.parameters), factory.createToken(SyntaxKind.OpenParenToken)); + changes.insertNodeBefore( + sourceFile, + first(signature.parameters), + factory.createToken(SyntaxKind.OpenParenToken), + ); } forEach(inferences, ({ typeNode, param }) => { - const typeTag = factory.createJSDocTypeTag(/*tagName*/ undefined, factory.createJSDocTypeExpression(typeNode)); + const typeTag = factory.createJSDocTypeTag( + /*tagName*/ undefined, + factory.createJSDocTypeExpression(typeNode), + ); const jsDoc = factory.createJSDocComment(/*comment*/ undefined, [typeTag]); changes.insertNodeAt(sourceFile, param.getStart(sourceFile), jsDoc, { suffix: " " }); }); if (needParens) { - changes.insertNodeAfter(sourceFile, last(signature.parameters), factory.createToken(SyntaxKind.CloseParenToken)); + changes.insertNodeAfter( + sourceFile, + last(signature.parameters), + factory.createToken(SyntaxKind.CloseParenToken), + ); } } else { - const paramTags = map(inferences, ({ name, typeNode, isOptional }) => - factory.createJSDocParameterTag(/*tagName*/ undefined, name, /*isBracketed*/ !!isOptional, factory.createJSDocTypeExpression(typeNode), /*isNameFirst*/ false, /*comment*/ undefined)); + const paramTags = map( + inferences, + ({ name, typeNode, isOptional }) => + factory.createJSDocParameterTag( + /*tagName*/ undefined, + name, + /*isBracketed*/ !!isOptional, + factory.createJSDocTypeExpression(typeNode), + /*isNameFirst*/ false, + /*comment*/ undefined, + ), + ); changes.addJSDocTags(sourceFile, signature, paramTags); } } -function getReferences(token: PropertyName | Token, program: Program, cancellationToken: CancellationToken): readonly Identifier[] { +function getReferences( + token: PropertyName | Token, + program: Program, + cancellationToken: CancellationToken, +): readonly Identifier[] { // Position shouldn't matter since token is not a SourceFile. - return mapDefined(FindAllReferences.getReferenceEntriesForNode(-1, token, program, program.getSourceFiles(), cancellationToken), entry => - entry.kind !== FindAllReferences.EntryKind.Span ? tryCast(entry.node, isIdentifier) : undefined); + return mapDefined( + FindAllReferences.getReferenceEntriesForNode(-1, token, program, program.getSourceFiles(), cancellationToken), + entry => entry.kind !== FindAllReferences.EntryKind.Span ? tryCast(entry.node, isIdentifier) : undefined, + ); } -function inferTypeForVariableFromUsage(token: Identifier | PrivateIdentifier, program: Program, cancellationToken: CancellationToken): Type { +function inferTypeForVariableFromUsage( + token: Identifier | PrivateIdentifier, + program: Program, + cancellationToken: CancellationToken, +): Type { const references = getReferences(token, program, cancellationToken); return inferTypeFromReferences(program, references, cancellationToken).single(); } -function inferTypeForParametersFromUsage(func: SignatureDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken) { +function inferTypeForParametersFromUsage( + func: SignatureDeclaration, + sourceFile: SourceFile, + program: Program, + cancellationToken: CancellationToken, +) { const references = getFunctionReferences(func, sourceFile, program, cancellationToken); - return references && inferTypeFromReferences(program, references, cancellationToken).parameters(func) || - func.parameters.map(p => ({ + return references && inferTypeFromReferences(program, references, cancellationToken).parameters(func) + || func.parameters.map(p => ({ declaration: p, - type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType() + type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) + : program.getTypeChecker().getAnyType(), })); } -function getFunctionReferences(containingFunction: SignatureDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): readonly Identifier[] | undefined { +function getFunctionReferences( + containingFunction: SignatureDeclaration, + sourceFile: SourceFile, + program: Program, + cancellationToken: CancellationToken, +): readonly Identifier[] | undefined { let searchToken; switch (containingFunction.kind) { case SyntaxKind.Constructor: - searchToken = findChildOfKind>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile); + searchToken = findChildOfKind>( + containingFunction, + SyntaxKind.ConstructorKeyword, + sourceFile, + ); break; case SyntaxKind.ArrowFunction: case SyntaxKind.FunctionExpression: const parent = containingFunction.parent; - searchToken = (isVariableDeclaration(parent) || isPropertyDeclaration(parent)) && isIdentifier(parent.name) ? - parent.name : - containingFunction.name; + searchToken = (isVariableDeclaration(parent) || isPropertyDeclaration(parent)) && isIdentifier(parent.name) + ? parent.name + : containingFunction.name; break; case SyntaxKind.FunctionDeclaration: case SyntaxKind.MethodDeclaration: @@ -546,9 +763,13 @@ interface ParameterInference { readonly isOptional?: boolean; } -function inferTypeFromReferences(program: Program, references: readonly Identifier[], cancellationToken: CancellationToken) { +function inferTypeFromReferences( + program: Program, + references: readonly Identifier[], + cancellationToken: CancellationToken, +) { const checker = program.getTypeChecker(); - const builtinConstructors: { [s: string]: (t: Type) => Type } = { + const builtinConstructors: { [s: string]: (t: Type) => Type; } = { string: () => checker.getStringType(), number: () => checker.getNumberType(), Array: t => checker.createArrayType(t), @@ -669,14 +890,16 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi } } if (isIdentifier(parameter.name)) { - const inferred = inferTypesFromReferencesSingle(getReferences(parameter.name, program, cancellationToken)); + const inferred = inferTypesFromReferencesSingle( + getReferences(parameter.name, program, cancellationToken), + ); types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred)); } const type = combineTypes(types); return { type: isRest ? checker.createArrayType(type) : type, isOptional: isOptional && !isRest, - declaration: parameter + declaration: parameter, }; }); } @@ -782,8 +1005,8 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi usage.isNumberOrString = true; break; - // case SyntaxKind.ExclamationToken: - // no inferences here; + // case SyntaxKind.ExclamationToken: + // no inferences here; } } @@ -884,8 +1107,11 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi // LogicalOperator Or NullishCoalescing case SyntaxKind.BarBarToken: case SyntaxKind.QuestionQuestionToken: - if (node === parent.left && - (node.parent.parent.kind === SyntaxKind.VariableDeclaration || isAssignmentExpression(node.parent.parent, /*excludeCompoundAssignment*/ true))) { + if ( + node === parent.left + && (node.parent.parent.kind === SyntaxKind.VariableDeclaration + || isAssignmentExpression(node.parent.parent, /*excludeCompoundAssignment*/ true)) + ) { // var x = x || {}; // TODO: use getFalsyflagsOfType addCandidateType(usage, checker.getTypeAtLocation(parent.right)); @@ -907,7 +1133,7 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi function inferTypeFromCallExpression(parent: CallExpression | NewExpression, usage: Usage): void { const call: CallUsage = { argumentTypes: [], - return_: createEmptyUsage() + return_: createEmptyUsage(), }; if (parent.arguments) { @@ -935,7 +1161,11 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi usage.properties.set(name, propertyUsage); } - function inferTypeFromPropertyElementExpression(parent: ElementAccessExpression, node: Expression, usage: Usage): void { + function inferTypeFromPropertyElementExpression( + parent: ElementAccessExpression, + node: Expression, + usage: Usage, + ): void { if (node === parent.argumentExpression) { usage.isNumberOrString = true; return; @@ -953,10 +1183,13 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi } } - function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, usage: Usage) { - const nodeWithRealType = isVariableDeclaration(assignment.parent.parent) ? - assignment.parent.parent : - assignment.parent; + function inferTypeFromPropertyAssignment( + assignment: PropertyAssignment | ShorthandPropertyAssignment, + usage: Usage, + ) { + const nodeWithRealType = isVariableDeclaration(assignment.parent.parent) + ? assignment.parent.parent + : assignment.parent; addCandidateThisType(usage, checker.getTypeAtLocation(nodeWithRealType)); } @@ -996,23 +1229,28 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi const priorities: Priority[] = [ { high: t => t === checker.getStringType() || t === checker.getNumberType(), - low: t => t === stringNumber + low: t => t === stringNumber, }, { high: t => !(t.flags & (TypeFlags.Any | TypeFlags.Void)), - low: t => !!(t.flags & (TypeFlags.Any | TypeFlags.Void)) + low: t => !!(t.flags & (TypeFlags.Any | TypeFlags.Void)), }, { - high: t => !(t.flags & (TypeFlags.Nullable | TypeFlags.Any | TypeFlags.Void)) && !(getObjectFlags(t) & ObjectFlags.Anonymous), - low: t => !!(getObjectFlags(t) & ObjectFlags.Anonymous) - }]; + high: t => + !(t.flags & (TypeFlags.Nullable | TypeFlags.Any | TypeFlags.Void)) + && !(getObjectFlags(t) & ObjectFlags.Anonymous), + low: t => !!(getObjectFlags(t) & ObjectFlags.Anonymous), + }, + ]; let good = removeLowPriorityInferences(inferences, priorities); const anons = good.filter(i => getObjectFlags(i) & ObjectFlags.Anonymous) as AnonymousType[]; if (anons.length) { good = good.filter(i => !(getObjectFlags(i) & ObjectFlags.Anonymous)); good.push(combineAnonymousTypes(anons)); } - return checker.getWidenedType(checker.getUnionType(good.map(checker.getBaseTypeOfLiteralType), UnionReduction.Subtype)); + return checker.getWidenedType( + checker.getUnionType(good.map(checker.getBaseTypeOfLiteralType), UnionReduction.Subtype), + ); } function combineAnonymousTypes(anons: AnonymousType[]) { @@ -1028,7 +1266,11 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi const props = createMultiMap<__String, Type>(); for (const anon of anons) { for (const p of checker.getPropertiesOfType(anon)) { - props.add(p.escapedName, p.valueDeclaration ? checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration) : checker.getAnyType()); + props.add( + p.escapedName, + p.valueDeclaration ? checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration) + : checker.getAnyType(), + ); } calls.push(...checker.getSignaturesOfType(anon, SignatureKind.Call)); constructs.push(...checker.getSignaturesOfType(anon, SignatureKind.Construct)); @@ -1050,14 +1292,31 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi return [name, s]; }); const indexInfos = []; - if (stringIndices.length) indexInfos.push(checker.createIndexInfo(checker.getStringType(), checker.getUnionType(stringIndices), stringIndexReadonly)); - if (numberIndices.length) indexInfos.push(checker.createIndexInfo(checker.getNumberType(), checker.getUnionType(numberIndices), numberIndexReadonly)); + if (stringIndices.length) { + indexInfos.push( + checker.createIndexInfo( + checker.getStringType(), + checker.getUnionType(stringIndices), + stringIndexReadonly, + ), + ); + } + if (numberIndices.length) { + indexInfos.push( + checker.createIndexInfo( + checker.getNumberType(), + checker.getUnionType(numberIndices), + numberIndexReadonly, + ), + ); + } return checker.createAnonymousType( anons[0].symbol, members, calls, constructs, - indexInfos); + indexInfos, + ); } function inferTypes(usage: Usage): Type[] { @@ -1108,8 +1367,19 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi } const callSignatures: Signature[] = usage.calls ? [getSignatureFromCalls(usage.calls)] : []; const constructSignatures: Signature[] = usage.constructs ? [getSignatureFromCalls(usage.constructs)] : []; - const indexInfos = usage.stringIndex ? [checker.createIndexInfo(checker.getStringType(), combineFromUsage(usage.stringIndex), /*isReadonly*/ false)] : []; - return checker.createAnonymousType(/*symbol*/ undefined, members, callSignatures, constructSignatures, indexInfos); + const indexInfos = usage.stringIndex + ? [checker.createIndexInfo( + checker.getStringType(), + combineFromUsage(usage.stringIndex), + /*isReadonly*/ false, + )] : []; + return checker.createAnonymousType( + /*symbol*/ undefined, + members, + callSignatures, + constructSignatures, + indexInfos, + ); } function inferNamedTypesFromProperties(usage: Usage): Type[] { @@ -1165,9 +1435,14 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi return [usageType]; } else if (genericType.flags & TypeFlags.UnionOrIntersection) { - return flatMap((genericType as UnionOrIntersectionType).types, t => inferTypeParameters(t, usageType, typeParameter)); + return flatMap( + (genericType as UnionOrIntersectionType).types, + t => inferTypeParameters(t, usageType, typeParameter), + ); } - else if (getObjectFlags(genericType) & ObjectFlags.Reference && getObjectFlags(usageType) & ObjectFlags.Reference) { + else if ( + getObjectFlags(genericType) & ObjectFlags.Reference && getObjectFlags(usageType) & ObjectFlags.Reference + ) { // this is wrong because we need a reference to the targetType to, so we can check that it's also a reference const genericArgs = checker.getTypeArguments(genericType as TypeReference); const usageArgs = checker.getTypeArguments(usageType as TypeReference); @@ -1198,13 +1473,16 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi if (!usageParam) { break; } - let genericParamType = genericParam.valueDeclaration ? checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration) : checker.getAnyType(); + let genericParamType = genericParam.valueDeclaration + ? checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration) : checker.getAnyType(); const elementType = isRest && checker.getElementTypeOfArrayType(genericParamType); if (elementType) { genericParamType = elementType; } const targetType = tryCast(usageParam, isTransientSymbol)?.links.type - || (usageParam.valueDeclaration ? checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration) : checker.getAnyType()); + || (usageParam.valueDeclaration + ? checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration) + : checker.getAnyType()); types.push(...inferTypeParameters(genericParamType, targetType, typeParameter)); } const genericReturn = checker.getReturnTypeOfSignature(genericSig); @@ -1214,14 +1492,23 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi } function getFunctionFromCalls(calls: CallUsage[]) { - return checker.createAnonymousType(/*symbol*/ undefined, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, emptyArray); + return checker.createAnonymousType( + /*symbol*/ undefined, + createSymbolTable(), + [getSignatureFromCalls(calls)], + emptyArray, + emptyArray, + ); } function getSignatureFromCalls(calls: CallUsage[]): Signature { const parameters: Symbol[] = []; const length = Math.max(...calls.map(c => c.argumentTypes.length)); for (let i = 0; i < length; i++) { - const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`)); + const symbol = checker.createSymbol( + SymbolFlags.FunctionScopedVariable, + escapeLeadingUnderscores(`arg${i}`), + ); symbol.links.type = combineTypes(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType())); if (calls.some(call => call.argumentTypes[i] === undefined)) { symbol.flags |= SymbolFlags.Optional; @@ -1229,7 +1516,16 @@ function inferTypeFromReferences(program: Program, references: readonly Identifi parameters.push(symbol); } const returnType = combineFromUsage(combineUsages(calls.map(call => call.return_))); - return checker.createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, /*thisParameter*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, SignatureFlags.None); + return checker.createSignature( + /*declaration*/ undefined, + /*typeParameters*/ undefined, + /*thisParameter*/ undefined, + parameters, + returnType, + /*typePredicate*/ undefined, + length, + SignatureFlags.None, + ); } function addCandidateType(usage: Usage, type: Type | undefined) { diff --git a/src/services/codefixes/removeAccidentalCallParentheses.ts b/src/services/codefixes/removeAccidentalCallParentheses.ts index c4ad5c9ea3721..d639ed2485f4b 100644 --- a/src/services/codefixes/removeAccidentalCallParentheses.ts +++ b/src/services/codefixes/removeAccidentalCallParentheses.ts @@ -17,7 +17,10 @@ const errorCodes = [ registerCodeFix({ errorCodes, getCodeActions(context) { - const callExpression = findAncestor(getTokenAtPosition(context.sourceFile, context.span.start), isCallExpression); + const callExpression = findAncestor( + getTokenAtPosition(context.sourceFile, context.span.start), + isCallExpression, + ); if (!callExpression) { return undefined; } diff --git a/src/services/codefixes/removeUnnecessaryAwait.ts b/src/services/codefixes/removeUnnecessaryAwait.ts index 45e6dcdef0dcd..f54fe82547b16 100644 --- a/src/services/codefixes/removeUnnecessaryAwait.ts +++ b/src/services/codefixes/removeUnnecessaryAwait.ts @@ -30,7 +30,15 @@ registerCodeFix({ getCodeActions: function getCodeActionsToRemoveUnnecessaryAwait(context) { const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span)); if (changes.length > 0) { - return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unnecessary_await, fixId, Diagnostics.Remove_all_unnecessary_uses_of_await)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Remove_unnecessary_await, + fixId, + Diagnostics.Remove_all_unnecessary_uses_of_await, + ), + ]; } }, fixIds: [fixId], @@ -40,7 +48,10 @@ registerCodeFix({ }); function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, span: TextSpan) { - const awaitKeyword = tryCast(getTokenAtPosition(sourceFile, span.start), (node): node is AwaitKeyword => node.kind === SyntaxKind.AwaitKeyword); + const awaitKeyword = tryCast( + getTokenAtPosition(sourceFile, span.start), + (node): node is AwaitKeyword => node.kind === SyntaxKind.AwaitKeyword, + ); const awaitExpression = awaitKeyword && tryCast(awaitKeyword.parent, isAwaitExpression); if (!awaitExpression) { return; diff --git a/src/services/codefixes/requireInTs.ts b/src/services/codefixes/requireInTs.ts index 940cc8b690f92..a33b9b9563546 100644 --- a/src/services/codefixes/requireInTs.ts +++ b/src/services/codefixes/requireInTs.ts @@ -38,22 +38,45 @@ registerCodeFix({ return undefined; } const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, info)); - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_require_to_import, fixId, Diagnostics.Convert_all_require_to_import)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_require_to_import, + fixId, + Diagnostics.Convert_all_require_to_import, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, context.program, diag.start); - if (info) { - doChange(changes, context.sourceFile, info); - } - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, context.program, diag.start); + if (info) { + doChange(changes, context.sourceFile, info); + } + }), }); function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info) { const { allowSyntheticDefaults, defaultImportName, namedImports, statement, required } = info; - changes.replaceNode(sourceFile, statement, defaultImportName && !allowSyntheticDefaults - ? factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(required)) - : factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), required, /*assertClause*/ undefined)); + changes.replaceNode( + sourceFile, + statement, + defaultImportName && !allowSyntheticDefaults + ? factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + defaultImportName, + factory.createExternalModuleReference(required), + ) + : factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), + required, + /*assertClause*/ undefined, + ), + ); } interface Info { @@ -72,14 +95,15 @@ function getInfo(sourceFile: SourceFile, program: Program, pos: number): Info | const decl = cast(parent.parent, isVariableDeclaration); const defaultImportName = tryCast(decl.name, isIdentifier); - const namedImports = isObjectBindingPattern(decl.name) ? tryCreateNamedImportsFromObjectBindingPattern(decl.name) : undefined; + const namedImports = isObjectBindingPattern(decl.name) ? tryCreateNamedImportsFromObjectBindingPattern(decl.name) + : undefined; if (defaultImportName || namedImports) { return { allowSyntheticDefaults: getAllowSyntheticDefaultImports(program.getCompilerOptions()), defaultImportName, namedImports, statement: cast(decl.parent.parent, isVariableStatement), - required: first(parent.arguments) + required: first(parent.arguments), }; } } @@ -90,7 +114,13 @@ function tryCreateNamedImportsFromObjectBindingPattern(node: ObjectBindingPatter if (!isIdentifier(element.name) || element.initializer) { return undefined; } - importSpecifiers.push(factory.createImportSpecifier(/*isTypeOnly*/ false, tryCast(element.propertyName, isIdentifier), element.name)); + importSpecifiers.push( + factory.createImportSpecifier( + /*isTypeOnly*/ false, + tryCast(element.propertyName, isIdentifier), + element.name, + ), + ); } if (importSpecifiers.length) { diff --git a/src/services/codefixes/returnValueCorrect.ts b/src/services/codefixes/returnValueCorrect.ts index 5bca2c5788b91..11222c85e28a6 100644 --- a/src/services/codefixes/returnValueCorrect.ts +++ b/src/services/codefixes/returnValueCorrect.ts @@ -53,12 +53,12 @@ const fixIdWrapTheBlockWithParen = "fixWrapTheBlockWithParen"; const errorCodes = [ Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value.code, Diagnostics.Type_0_is_not_assignable_to_type_1.code, - Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code + Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code, ]; enum ProblemKind { MissingReturnStatement, - MissingParentheses + MissingParentheses, } interface MissingReturnInfo { @@ -90,32 +90,47 @@ registerCodeFix({ if (info.kind === ProblemKind.MissingReturnStatement) { return append( [getActionForfixAddReturnStatement(context, info.expression, info.statement)], - isArrowFunction(info.declaration) ? getActionForFixRemoveBracesFromArrowFunctionBody(context, info.declaration, info.expression, info.commentSource): undefined); + isArrowFunction(info.declaration) + ? getActionForFixRemoveBracesFromArrowFunctionBody( + context, + info.declaration, + info.expression, + info.commentSource, + ) : undefined, + ); } else { return [getActionForfixWrapTheBlockWithParen(context, info.declaration, info.expression)]; } }, - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(context.program.getTypeChecker(), diag.file, diag.start, diag.code); - if (!info) return undefined; + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(context.program.getTypeChecker(), diag.file, diag.start, diag.code); + if (!info) return undefined; - switch (context.fixId) { - case fixIdAddReturnStatement: - addReturnStatement(changes, diag.file, info.expression, info.statement); - break; - case fixRemoveBracesFromArrowFunctionBody: - if (!isArrowFunction(info.declaration)) return undefined; - removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, info.commentSource, /*withParen*/ false); - break; - case fixIdWrapTheBlockWithParen: - if (!isArrowFunction(info.declaration)) return undefined; - wrapBlockWithParen(changes, diag.file, info.declaration, info.expression); - break; - default: - Debug.fail(JSON.stringify(context.fixId)); - } - }), + switch (context.fixId) { + case fixIdAddReturnStatement: + addReturnStatement(changes, diag.file, info.expression, info.statement); + break; + case fixRemoveBracesFromArrowFunctionBody: + if (!isArrowFunction(info.declaration)) return undefined; + removeBlockBodyBrace( + changes, + diag.file, + info.declaration, + info.expression, + info.commentSource, + /*withParen*/ false, + ); + break; + case fixIdWrapTheBlockWithParen: + if (!isArrowFunction(info.declaration)) return undefined; + wrapBlockWithParen(changes, diag.file, info.declaration, info.expression); + break; + default: + Debug.fail(JSON.stringify(context.fixId)); + } + }), }); function createObjectTypeFromLabeledExpression(checker: TypeChecker, label: Identifier, expression: Expression) { @@ -125,50 +140,76 @@ function createObjectTypeFromLabeledExpression(checker: TypeChecker, label: Iden return checker.createAnonymousType(/*symbol*/ undefined, members, [], [], []); } -function getFixInfo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type, isFunctionType: boolean): Info | undefined { +function getFixInfo( + checker: TypeChecker, + declaration: FunctionLikeDeclaration, + expectType: Type, + isFunctionType: boolean, +): Info | undefined { if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) return undefined; const firstStatement = first(declaration.body.statements); - if (isExpressionStatement(firstStatement) && checkFixedAssignableTo(checker, declaration, checker.getTypeAtLocation(firstStatement.expression), expectType, isFunctionType)) { + if ( + isExpressionStatement(firstStatement) + && checkFixedAssignableTo( + checker, + declaration, + checker.getTypeAtLocation(firstStatement.expression), + expectType, + isFunctionType, + ) + ) { return { declaration, kind: ProblemKind.MissingReturnStatement, expression: firstStatement.expression, statement: firstStatement, - commentSource: firstStatement.expression + commentSource: firstStatement.expression, }; } else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) { - const node = factory.createObjectLiteralExpression([factory.createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]); - const nodeType = createObjectTypeFromLabeledExpression(checker, firstStatement.label, firstStatement.statement.expression); + const node = factory.createObjectLiteralExpression([ + factory.createPropertyAssignment(firstStatement.label, firstStatement.statement.expression), + ]); + const nodeType = createObjectTypeFromLabeledExpression( + checker, + firstStatement.label, + firstStatement.statement.expression, + ); if (checkFixedAssignableTo(checker, declaration, nodeType, expectType, isFunctionType)) { return isArrowFunction(declaration) ? { declaration, kind: ProblemKind.MissingParentheses, expression: node, statement: firstStatement, - commentSource: firstStatement.statement.expression + commentSource: firstStatement.statement.expression, } : { - declaration, - kind: ProblemKind.MissingReturnStatement, - expression: node, - statement: firstStatement, - commentSource: firstStatement.statement.expression - }; + declaration, + kind: ProblemKind.MissingReturnStatement, + expression: node, + statement: firstStatement, + commentSource: firstStatement.statement.expression, + }; } } else if (isBlock(firstStatement) && length(firstStatement.statements) === 1) { const firstBlockStatement = first(firstStatement.statements); if (isLabeledStatement(firstBlockStatement) && isExpressionStatement(firstBlockStatement.statement)) { - const node = factory.createObjectLiteralExpression([factory.createPropertyAssignment(firstBlockStatement.label, firstBlockStatement.statement.expression)]); - const nodeType = createObjectTypeFromLabeledExpression(checker, firstBlockStatement.label, firstBlockStatement.statement.expression); + const node = factory.createObjectLiteralExpression([ + factory.createPropertyAssignment(firstBlockStatement.label, firstBlockStatement.statement.expression), + ]); + const nodeType = createObjectTypeFromLabeledExpression( + checker, + firstBlockStatement.label, + firstBlockStatement.statement.expression, + ); if (checkFixedAssignableTo(checker, declaration, nodeType, expectType, isFunctionType)) { return { declaration, kind: ProblemKind.MissingReturnStatement, expression: node, statement: firstStatement, - commentSource: firstBlockStatement + commentSource: firstBlockStatement, }; } } @@ -177,7 +218,13 @@ function getFixInfo(checker: TypeChecker, declaration: FunctionLikeDeclaration, return undefined; } -function checkFixedAssignableTo(checker: TypeChecker, declaration: FunctionLikeDeclaration, exprType: Type, type: Type, isFunctionType: boolean) { +function checkFixedAssignableTo( + checker: TypeChecker, + declaration: FunctionLikeDeclaration, + exprType: Type, + type: Type, + isFunctionType: boolean, +) { if (isFunctionType) { const sig = checker.getSignatureFromDeclaration(declaration); if (sig) { @@ -192,13 +239,15 @@ function checkFixedAssignableTo(checker: TypeChecker, declaration: FunctionLikeD exprType, /*typePredicate*/ undefined, sig.minArgumentCount, - sig.flags); + sig.flags, + ); exprType = checker.createAnonymousType( /*symbol*/ undefined, createSymbolTable(), [newSig], [], - []); + [], + ); } else { exprType = checker.getAnyType(); @@ -214,8 +263,15 @@ function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number, const declaration = findAncestor(node.parent, isFunctionLikeDeclaration); switch (errorCode) { case Diagnostics.A_function_whose_declared_type_is_neither_undefined_void_nor_any_must_return_a_value.code: - if (!declaration || !declaration.body || !declaration.type || !rangeContainsRange(declaration.type, node)) return undefined; - return getFixInfo(checker, declaration, checker.getTypeFromTypeNode(declaration.type), /*isFunctionType*/ false); + if (!declaration || !declaration.body || !declaration.type || !rangeContainsRange(declaration.type, node)) { + return undefined; + } + return getFixInfo( + checker, + declaration, + checker.getTypeFromTypeNode(declaration.type), + /*isFunctionType*/ false, + ); case Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code: if (!declaration || !isCallExpression(declaration.parent) || !declaration.body) return undefined; const pos = declaration.parent.arguments.indexOf(declaration as Expression); @@ -224,7 +280,9 @@ function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number, if (!type) return undefined; return getFixInfo(checker, declaration, type, /*isFunctionType*/ true); case Diagnostics.Type_0_is_not_assignable_to_type_1.code: - if (!isDeclarationName(node) || !isVariableLike(node.parent) && !isJsxAttribute(node.parent)) return undefined; + if (!isDeclarationName(node) || !isVariableLike(node.parent) && !isJsxAttribute(node.parent)) { + return undefined; + } const initializer = getVariableLikeInitializer(node.parent); if (!initializer || !isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined; return getFixInfo(checker, initializer, checker.getTypeAtLocation(node.parent), /*isFunctionType*/ true); @@ -241,7 +299,8 @@ function getVariableLikeInitializer(declaration: VariableLikeDeclaration): Expre case SyntaxKind.PropertyAssignment: return declaration.initializer; case SyntaxKind.JsxAttribute: - return declaration.initializer && (isJsxExpression(declaration.initializer) ? declaration.initializer.expression : undefined); + return declaration.initializer + && (isJsxExpression(declaration.initializer) ? declaration.initializer.expression : undefined); case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.PropertySignature: case SyntaxKind.EnumMember: @@ -251,39 +310,93 @@ function getVariableLikeInitializer(declaration: VariableLikeDeclaration): Expre } } -function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, expression: Expression, statement: Statement) { +function addReturnStatement( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + expression: Expression, + statement: Statement, +) { suppressLeadingAndTrailingTrivia(expression); const probablyNeedSemi = probablyUsesSemicolons(sourceFile); changes.replaceNode(sourceFile, statement, factory.createReturnStatement(expression), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, - suffix: probablyNeedSemi ? ";" : undefined + suffix: probablyNeedSemi ? ";" : undefined, }); } -function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression, commentSource: Node, withParen: boolean) { - const newBody = (withParen || needsParentheses(expression)) ? factory.createParenthesizedExpression(expression) : expression; +function removeBlockBodyBrace( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + declaration: ArrowFunction, + expression: Expression, + commentSource: Node, + withParen: boolean, +) { + const newBody = (withParen || needsParentheses(expression)) ? factory.createParenthesizedExpression(expression) + : expression; suppressLeadingAndTrailingTrivia(commentSource); copyComments(commentSource, newBody); changes.replaceNode(sourceFile, declaration.body, newBody); } -function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression) { +function wrapBlockWithParen( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + declaration: ArrowFunction, + expression: Expression, +) { changes.replaceNode(sourceFile, declaration.body, factory.createParenthesizedExpression(expression)); } function getActionForfixAddReturnStatement(context: CodeFixContext, expression: Expression, statement: Statement) { - const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, expression, statement)); - return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Add_all_missing_return_statement); + const changes = textChanges.ChangeTracker.with( + context, + t => addReturnStatement(t, context.sourceFile, expression, statement), + ); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Add_a_return_statement, + fixIdAddReturnStatement, + Diagnostics.Add_all_missing_return_statement, + ); } -function getActionForFixRemoveBracesFromArrowFunctionBody(context: CodeFixContext, declaration: ArrowFunction, expression: Expression, commentSource: Node) { - const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, commentSource, /*withParen*/ false)); - return createCodeFixAction(fixId, changes, Diagnostics.Remove_braces_from_arrow_function_body, fixRemoveBracesFromArrowFunctionBody, Diagnostics.Remove_braces_from_all_arrow_function_bodies_with_relevant_issues); +function getActionForFixRemoveBracesFromArrowFunctionBody( + context: CodeFixContext, + declaration: ArrowFunction, + expression: Expression, + commentSource: Node, +) { + const changes = textChanges.ChangeTracker.with( + context, + t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, commentSource, /*withParen*/ false), + ); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Remove_braces_from_arrow_function_body, + fixRemoveBracesFromArrowFunctionBody, + Diagnostics.Remove_braces_from_all_arrow_function_bodies_with_relevant_issues, + ); } -function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) { - const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration, expression)); - return createCodeFixAction(fixId, changes, Diagnostics.Wrap_the_following_body_with_parentheses_which_should_be_an_object_literal, fixIdWrapTheBlockWithParen, Diagnostics.Wrap_all_object_literal_with_parentheses); +function getActionForfixWrapTheBlockWithParen( + context: CodeFixContext, + declaration: ArrowFunction, + expression: Expression, +) { + const changes = textChanges.ChangeTracker.with( + context, + t => wrapBlockWithParen(t, context.sourceFile, declaration, expression), + ); + return createCodeFixAction( + fixId, + changes, + Diagnostics.Wrap_the_following_body_with_parentheses_which_should_be_an_object_literal, + fixIdWrapTheBlockWithParen, + Diagnostics.Wrap_all_object_literal_with_parentheses, + ); } diff --git a/src/services/codefixes/splitTypeOnlyImport.ts b/src/services/codefixes/splitTypeOnlyImport.ts index 6af08a70ebff6..dbd0c75756efe 100644 --- a/src/services/codefixes/splitTypeOnlyImport.ts +++ b/src/services/codefixes/splitTypeOnlyImport.ts @@ -27,33 +27,66 @@ registerCodeFix({ return splitTypeOnlyImport(t, getImportDeclaration(context.sourceFile, context.span), context); }); if (changes.length) { - return [createCodeFixAction(fixId, changes, Diagnostics.Split_into_two_separate_import_declarations, fixId, Diagnostics.Split_all_invalid_type_only_imports)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Split_into_two_separate_import_declarations, + fixId, + Diagnostics.Split_all_invalid_type_only_imports, + ), + ]; } }, - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, error) => { - splitTypeOnlyImport(changes, getImportDeclaration(context.sourceFile, error), context); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, error) => { + splitTypeOnlyImport(changes, getImportDeclaration(context.sourceFile, error), context); + }), }); function getImportDeclaration(sourceFile: SourceFile, span: TextSpan) { return findAncestor(getTokenAtPosition(sourceFile, span.start), isImportDeclaration); } -function splitTypeOnlyImport(changes: textChanges.ChangeTracker, importDeclaration: ImportDeclaration | undefined, context: CodeFixContextBase) { +function splitTypeOnlyImport( + changes: textChanges.ChangeTracker, + importDeclaration: ImportDeclaration | undefined, + context: CodeFixContextBase, +) { if (!importDeclaration) { return; } const importClause = Debug.checkDefined(importDeclaration.importClause); - changes.replaceNode(context.sourceFile, importDeclaration, factory.updateImportDeclaration( + changes.replaceNode( + context.sourceFile, importDeclaration, - importDeclaration.modifiers, - factory.updateImportClause(importClause, importClause.isTypeOnly, importClause.name, /*namedBindings*/ undefined), - importDeclaration.moduleSpecifier, - importDeclaration.assertClause)); + factory.updateImportDeclaration( + importDeclaration, + importDeclaration.modifiers, + factory.updateImportClause( + importClause, + importClause.isTypeOnly, + importClause.name, + /*namedBindings*/ undefined, + ), + importDeclaration.moduleSpecifier, + importDeclaration.assertClause, + ), + ); - changes.insertNodeAfter(context.sourceFile, importDeclaration, factory.createImportDeclaration( - /*modifiers*/ undefined, - factory.updateImportClause(importClause, importClause.isTypeOnly, /*name*/ undefined, importClause.namedBindings), - importDeclaration.moduleSpecifier, - importDeclaration.assertClause)); + changes.insertNodeAfter( + context.sourceFile, + importDeclaration, + factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.updateImportClause( + importClause, + importClause.isTypeOnly, + /*name*/ undefined, + importClause.namedBindings, + ), + importDeclaration.moduleSpecifier, + importDeclaration.assertClause, + ), + ); } diff --git a/src/services/codefixes/useBigintLiteral.ts b/src/services/codefixes/useBigintLiteral.ts index 4492e176b5c57..c9f372048dd12 100644 --- a/src/services/codefixes/useBigintLiteral.ts +++ b/src/services/codefixes/useBigintLiteral.ts @@ -16,7 +16,9 @@ import { const fixId = "useBigintLiteral"; const errorCodes = [ - Diagnostics.Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers.code, + Diagnostics + .Numeric_literals_with_absolute_values_equal_to_2_53_or_greater_are_too_large_to_be_represented_accurately_as_integers + .code, ]; registerCodeFix({ @@ -24,7 +26,15 @@ registerCodeFix({ getCodeActions: function getCodeActionsToUseBigintLiteral(context) { const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span)); if (changes.length > 0) { - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_a_bigint_numeric_literal, fixId, Diagnostics.Convert_all_to_bigint_numeric_literals)]; + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_a_bigint_numeric_literal, + fixId, + Diagnostics.Convert_all_to_bigint_numeric_literals, + ), + ]; } }, fixIds: [fixId], diff --git a/src/services/codefixes/useDefaultImport.ts b/src/services/codefixes/useDefaultImport.ts index 75f72964530b6..893652ca2419d 100644 --- a/src/services/codefixes/useDefaultImport.ts +++ b/src/services/codefixes/useDefaultImport.ts @@ -28,14 +28,26 @@ registerCodeFix({ const { sourceFile, span: { start } } = context; const info = getInfo(sourceFile, start); if (!info) return undefined; - const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info, context.preferences)); - return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_default_import, fixId, Diagnostics.Convert_all_to_default_imports)]; + const changes = textChanges.ChangeTracker.with( + context, + t => doChange(t, sourceFile, info, context.preferences), + ); + return [ + createCodeFixAction( + fixId, + changes, + Diagnostics.Convert_to_default_import, + fixId, + Diagnostics.Convert_all_to_default_imports, + ), + ]; }, fixIds: [fixId], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, diag.start); - if (info) doChange(changes, diag.file, info, context.preferences); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const info = getInfo(diag.file, diag.start); + if (info) doChange(changes, diag.file, info, context.preferences); + }), }); interface Info { @@ -56,6 +68,20 @@ function getInfo(sourceFile: SourceFile, pos: number): Info | undefined { } } -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info, preferences: UserPreferences): void { - changes.replaceNode(sourceFile, info.importNode, makeImport(info.name, /*namedImports*/ undefined, info.moduleSpecifier, getQuotePreference(sourceFile, preferences))); +function doChange( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + info: Info, + preferences: UserPreferences, +): void { + changes.replaceNode( + sourceFile, + info.importNode, + makeImport( + info.name, + /*namedImports*/ undefined, + info.moduleSpecifier, + getQuotePreference(sourceFile, preferences), + ), + ); } diff --git a/src/services/codefixes/wrapJsxInFragment.ts b/src/services/codefixes/wrapJsxInFragment.ts index 78122a0840c62..89140c85854ca 100644 --- a/src/services/codefixes/wrapJsxInFragment.ts +++ b/src/services/codefixes/wrapJsxInFragment.ts @@ -27,14 +27,23 @@ registerCodeFix({ const node = findNodeToFix(sourceFile, span.start); if (!node) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node)); - return [createCodeFixAction(fixID, changes, Diagnostics.Wrap_in_JSX_fragment, fixID, Diagnostics.Wrap_all_unparented_JSX_in_JSX_fragment)]; + return [ + createCodeFixAction( + fixID, + changes, + Diagnostics.Wrap_in_JSX_fragment, + fixID, + Diagnostics.Wrap_all_unparented_JSX_in_JSX_fragment, + ), + ]; }, fixIds: [fixID], - getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const node = findNodeToFix(context.sourceFile, diag.start); - if (!node) return undefined; - doChange(changes, context.sourceFile, node); - }), + getAllCodeActions: context => + codeFixAll(context, errorCodes, (changes, diag) => { + const node = findNodeToFix(context.sourceFile, diag.start); + if (!node) return undefined; + doChange(changes, context.sourceFile, node); + }), }); function findNodeToFix(sourceFile: SourceFile, pos: number): BinaryExpression | undefined { @@ -54,7 +63,13 @@ function findNodeToFix(sourceFile: SourceFile, pos: number): BinaryExpression | function doChange(changeTracker: textChanges.ChangeTracker, sf: SourceFile, node: Node) { const jsx = flattenInvalidBinaryExpr(node); - if (jsx) changeTracker.replaceNode(sf, node, factory.createJsxFragment(factory.createJsxOpeningFragment(), jsx, factory.createJsxJsxClosingFragment())); + if (jsx) { + changeTracker.replaceNode( + sf, + node, + factory.createJsxFragment(factory.createJsxOpeningFragment(), jsx, factory.createJsxJsxClosingFragment()), + ); + } } // The invalid syntax is constructed as // InvalidJsxTree :: One of @@ -64,7 +79,10 @@ function flattenInvalidBinaryExpr(node: Node): JsxChild[] | undefined { const children: JsxChild[] = []; let current = node; while (true) { - if (isBinaryExpression(current) && nodeIsMissing(current.operatorToken) && current.operatorToken.kind === SyntaxKind.CommaToken) { + if ( + isBinaryExpression(current) && nodeIsMissing(current.operatorToken) + && current.operatorToken.kind === SyntaxKind.CommaToken + ) { children.push(current.left as JsxChild); if (isJsxChild(current.right)) { children.push(current.right); diff --git a/src/services/completions.ts b/src/services/completions.ts index 33ed264c3b620..fde92d084cf02 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -384,7 +384,9 @@ import { VariableDeclaration, walkUpParenthesizedExpressions, } from "./_namespaces/ts"; -import { StringCompletions } from "./_namespaces/ts.Completions"; +import { + StringCompletions, +} from "./_namespaces/ts.Completions"; // Exported only for tests /** @internal */ @@ -396,7 +398,7 @@ export const moduleSpecifierResolutionCacheAttemptLimit = 1000; export type Log = (message: string) => void; /** @internal */ -export type SortText = string & { __sortText: any }; +export type SortText = string & { __sortText: any; }; /** @internal */ export const SortText = { // Presets @@ -452,6 +454,7 @@ export enum CompletionSource { ObjectLiteralMemberWithComma = "ObjectLiteralMemberWithComma/", } +// dprint-ignore /** @internal */ export const enum SymbolOriginInfoKind { ThisType = 1 << 0, @@ -498,9 +501,9 @@ interface SymbolOriginInfoTypeOnlyImport extends SymbolOriginInfo { } interface SymbolOriginInfoObjectLiteralMethod extends SymbolOriginInfo { - insertText: string, - labelDetails: CompletionEntryLabelDetails, - isSnippet?: true, + insertText: string; + labelDetails: CompletionEntryLabelDetails; + isSnippet?: true; } interface SymbolOriginInfoComputedPropertyName extends SymbolOriginInfo { @@ -523,7 +526,9 @@ function originIsResolvedExport(origin: SymbolOriginInfo | undefined): origin is return !!(origin && origin.kind === SymbolOriginInfoKind.ResolvedExport); } -function originIncludesSymbolName(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoExport | SymbolOriginInfoResolvedExport | SymbolOriginInfoComputedPropertyName { +function originIncludesSymbolName( + origin: SymbolOriginInfo | undefined, +): origin is SymbolOriginInfoExport | SymbolOriginInfoResolvedExport | SymbolOriginInfoComputedPropertyName { return originIsExport(origin) || originIsResolvedExport(origin) || originIsComputedPropertyName(origin); } @@ -543,7 +548,9 @@ function originIsTypeOnlyAlias(origin: SymbolOriginInfo | undefined): origin is return !!(origin && origin.kind & SymbolOriginInfoKind.TypeOnlyAlias); } -function originIsObjectLiteralMethod(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoObjectLiteralMethod { +function originIsObjectLiteralMethod( + origin: SymbolOriginInfo | undefined, +): origin is SymbolOriginInfoObjectLiteralMethod { return !!(origin && origin.kind & SymbolOriginInfoKind.ObjectLiteralMethod); } @@ -551,7 +558,9 @@ function originIsIgnore(origin: SymbolOriginInfo | undefined): boolean { return !!(origin && origin.kind & SymbolOriginInfoKind.Ignore); } -function originIsComputedPropertyName(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoComputedPropertyName { +function originIsComputedPropertyName( + origin: SymbolOriginInfo | undefined, +): origin is SymbolOriginInfoComputedPropertyName { return !!(origin && origin.kind & SymbolOriginInfoKind.ComputedPropertyName); } @@ -575,6 +584,7 @@ export type SymbolOriginInfoMap = Record; */ export type SymbolSortTextMap = (SortText | undefined)[]; +// dprint-ignore const enum KeywordCompletionFilters { None, // No keywords All, // Every possible keyword (TODO: This is never appropriate) @@ -585,13 +595,20 @@ const enum KeywordCompletionFilters { TypeAssertionKeywords, TypeKeywords, TypeKeyword, // Literally just `type` - Last = TypeKeyword + Last = TypeKeyword, } -const enum GlobalsSearch { Continue, Success, Fail } +const enum GlobalsSearch { + Continue, + Success, + Fail, +} interface ModuleSpecifierResolutionContext { - tryResolve: (exportInfo: readonly SymbolExportInfo[], isFromAmbientModule: boolean) => ModuleSpecifierResolutionResult; + tryResolve: ( + exportInfo: readonly SymbolExportInfo[], + isFromAmbientModule: boolean, + ) => ModuleSpecifierResolutionResult; resolvedAny: () => boolean; skippedAny: () => boolean; resolvedBeyondLimit: () => boolean; @@ -619,7 +636,10 @@ function resolvingModuleSpecifiers( // relative path into node_modules), and we want to filter those completions out entirely. // Import statement completions always need specifier resolution because the module specifier is // part of their `insertText`, not the `codeActions` creating edits away from the cursor. - const needsFullResolution = isForImportStatementCompletion || moduleResolutionSupportsPackageJsonExportsAndImports(getEmitModuleResolutionKind(program.getCompilerOptions())); + const needsFullResolution = isForImportStatementCompletion + || moduleResolutionSupportsPackageJsonExportsAndImports( + getEmitModuleResolutionKind(program.getCompilerOptions()), + ); let skippedAny = false; let ambientCount = 0; let resolvedCount = 0; @@ -633,13 +653,19 @@ function resolvingModuleSpecifiers( resolvedBeyondLimit: () => resolvedCount > moduleSpecifierResolutionLimit, }); - const hitRateMessage = cacheAttemptCount ? ` (${(resolvedFromCacheCount / cacheAttemptCount * 100).toFixed(1)}% hit rate)` : ""; - host.log?.(`${logPrefix}: resolved ${resolvedCount} module specifiers, plus ${ambientCount} ambient and ${resolvedFromCacheCount} from cache${hitRateMessage}`); + const hitRateMessage = cacheAttemptCount + ? ` (${(resolvedFromCacheCount / cacheAttemptCount * 100).toFixed(1)}% hit rate)` : ""; + host.log?.( + `${logPrefix}: resolved ${resolvedCount} module specifiers, plus ${ambientCount} ambient and ${resolvedFromCacheCount} from cache${hitRateMessage}`, + ); host.log?.(`${logPrefix}: response is ${skippedAny ? "incomplete" : "complete"}`); host.log?.(`${logPrefix}: ${timestamp() - start}`); return result; - function tryResolve(exportInfo: readonly SymbolExportInfo[], isFromAmbientModule: boolean): ModuleSpecifierResolutionResult { + function tryResolve( + exportInfo: readonly SymbolExportInfo[], + isFromAmbientModule: boolean, + ): ModuleSpecifierResolutionResult { if (isFromAmbientModule) { const result = resolver.getModuleSpecifierForBestExportInfo(exportInfo, position, isValidTypeOnlyUseSite); if (result) { @@ -647,13 +673,23 @@ function resolvingModuleSpecifiers( } return result || "failed"; } - const shouldResolveModuleSpecifier = needsFullResolution || preferences.allowIncompleteCompletions && resolvedCount < moduleSpecifierResolutionLimit; - const shouldGetModuleSpecifierFromCache = !shouldResolveModuleSpecifier && preferences.allowIncompleteCompletions && cacheAttemptCount < moduleSpecifierResolutionCacheAttemptLimit; + const shouldResolveModuleSpecifier = needsFullResolution + || preferences.allowIncompleteCompletions && resolvedCount < moduleSpecifierResolutionLimit; + const shouldGetModuleSpecifierFromCache = !shouldResolveModuleSpecifier + && preferences.allowIncompleteCompletions && cacheAttemptCount < moduleSpecifierResolutionCacheAttemptLimit; const result = (shouldResolveModuleSpecifier || shouldGetModuleSpecifierFromCache) - ? resolver.getModuleSpecifierForBestExportInfo(exportInfo, position, isValidTypeOnlyUseSite, shouldGetModuleSpecifierFromCache) + ? resolver.getModuleSpecifierForBestExportInfo( + exportInfo, + position, + isValidTypeOnlyUseSite, + shouldGetModuleSpecifierFromCache, + ) : undefined; - if (!shouldResolveModuleSpecifier && !shouldGetModuleSpecifierFromCache || shouldGetModuleSpecifierFromCache && !result) { + if ( + !shouldResolveModuleSpecifier && !shouldGetModuleSpecifierFromCache + || shouldGetModuleSpecifierFromCache && !result + ) { skippedAny = true; } @@ -679,29 +715,50 @@ export function getCompletionsAtPosition( completionKind: CompletionTriggerKind | undefined, cancellationToken: CancellationToken, formatContext?: formatting.FormatContext, - includeSymbol = false + includeSymbol = false, ): CompletionInfo | undefined { const { previousToken } = getRelevantTokens(position, sourceFile); - if (triggerCharacter && !isInString(sourceFile, position, previousToken) && !isValidTrigger(sourceFile, triggerCharacter, previousToken, position)) { + if ( + triggerCharacter && !isInString(sourceFile, position, previousToken) + && !isValidTrigger(sourceFile, triggerCharacter, previousToken, position) + ) { return undefined; } if (triggerCharacter === " ") { // `isValidTrigger` ensures we are at `import |` if (preferences.includeCompletionsForImportStatements && preferences.includeCompletionsWithInsertText) { - return { isGlobalCompletion: true, isMemberCompletion: false, isNewIdentifierLocation: true, isIncomplete: true, entries: [] }; + return { + isGlobalCompletion: true, + isMemberCompletion: false, + isNewIdentifierLocation: true, + isIncomplete: true, + entries: [], + }; } return undefined; - } const compilerOptions = program.getCompilerOptions(); const checker = program.getTypeChecker(); // If the request is a continuation of an earlier `isIncomplete` response, // we can continue it from the cached previous response. - const incompleteCompletionsCache = preferences.allowIncompleteCompletions ? host.getIncompleteCompletionsCache?.() : undefined; - if (incompleteCompletionsCache && completionKind === CompletionTriggerKind.TriggerForIncompleteCompletions && previousToken && isIdentifier(previousToken)) { - const incompleteContinuation = continuePreviousIncompleteResponse(incompleteCompletionsCache, sourceFile, previousToken, program, host, preferences, cancellationToken, position); + const incompleteCompletionsCache = preferences.allowIncompleteCompletions ? host.getIncompleteCompletionsCache?.() + : undefined; + if ( + incompleteCompletionsCache && completionKind === CompletionTriggerKind.TriggerForIncompleteCompletions + && previousToken && isIdentifier(previousToken) + ) { + const incompleteContinuation = continuePreviousIncompleteResponse( + incompleteCompletionsCache, + sourceFile, + previousToken, + program, + host, + preferences, + cancellationToken, + position, + ); if (incompleteContinuation) { return incompleteContinuation; } @@ -710,24 +767,59 @@ export function getCompletionsAtPosition( incompleteCompletionsCache?.clear(); } - const stringCompletions = StringCompletions.getStringLiteralCompletions(sourceFile, position, previousToken, compilerOptions, host, program, log, preferences, includeSymbol); + const stringCompletions = StringCompletions.getStringLiteralCompletions( + sourceFile, + position, + previousToken, + compilerOptions, + host, + program, + log, + preferences, + includeSymbol, + ); if (stringCompletions) { return stringCompletions; } - if (previousToken && isBreakOrContinueStatement(previousToken.parent) - && (previousToken.kind === SyntaxKind.BreakKeyword || previousToken.kind === SyntaxKind.ContinueKeyword || previousToken.kind === SyntaxKind.Identifier)) { + if ( + previousToken && isBreakOrContinueStatement(previousToken.parent) + && (previousToken.kind === SyntaxKind.BreakKeyword || previousToken.kind === SyntaxKind.ContinueKeyword + || previousToken.kind === SyntaxKind.Identifier) + ) { return getLabelCompletionAtPosition(previousToken.parent); } - const completionData = getCompletionData(program, log, sourceFile, compilerOptions, position, preferences, /*detailsEntryId*/ undefined, host, formatContext, cancellationToken); + const completionData = getCompletionData( + program, + log, + sourceFile, + compilerOptions, + position, + preferences, + /*detailsEntryId*/ undefined, + host, + formatContext, + cancellationToken, + ); if (!completionData) { return undefined; } switch (completionData.kind) { case CompletionDataKind.Data: - const response = completionInfoFromData(sourceFile, host, program, compilerOptions, log, completionData, preferences, formatContext, position, includeSymbol); + const response = completionInfoFromData( + sourceFile, + host, + program, + compilerOptions, + log, + completionData, + preferences, + formatContext, + position, + includeSymbol, + ); if (response?.isIncomplete) { incompleteCompletionsCache?.set(response); } @@ -742,7 +834,9 @@ export function getCompletionsAtPosition( checker, compilerOptions, preferences, - /*tagNameOnly*/ true)]); + /*tagNameOnly*/ true, + ), + ]); case CompletionDataKind.JsDocTag: // If the current position is a jsDoc tag, only tags should be provided for completion return jsdocCompletionInfo([ @@ -753,11 +847,16 @@ export function getCompletionsAtPosition( checker, compilerOptions, preferences, - /*tagNameOnly*/ false)]); + /*tagNameOnly*/ false, + ), + ]); case CompletionDataKind.JsDocParameterName: return jsdocCompletionInfo(JsDoc.getJSDocParameterNameCompletions(completionData.tag)); case CompletionDataKind.Keywords: - return specificKeywordCompletionInfo(completionData.keywordCompletions, completionData.isNewIdentifierLocation); + return specificKeywordCompletionInfo( + completionData.keywordCompletions, + completionData.isNewIdentifierLocation, + ); default: return Debug.assertNever(completionData); } @@ -789,7 +888,9 @@ function compareCompletionEntries(entryInArray: CompletionEntry, entryToInsert: return result; } -function completionEntryDataIsResolved(data: CompletionEntryDataAutoImport | undefined): data is CompletionEntryDataResolved { +function completionEntryDataIsResolved( + data: CompletionEntryDataAutoImport | undefined, +): data is CompletionEntryDataResolved { return !!data?.moduleSpecifier; } @@ -829,10 +930,13 @@ function continuePreviousIncompleteResponse( return undefined; } - const { origin } = Debug.checkDefined(getAutoImportSymbolFromCompletionEntryData(entry.name, entry.data, program, host)); + const { origin } = Debug.checkDefined( + getAutoImportSymbolFromCompletionEntryData(entry.name, entry.data, program, host), + ); const info = exportMap.get(file.path, entry.data.exportMapKey); - const result = info && context.tryResolve(info, !isExternalModuleNameRelative(stripQuotes(origin.moduleSymbol.name))); + const result = info + && context.tryResolve(info, !isExternalModuleNameRelative(stripQuotes(origin.moduleSymbol.name))); if (result === "skipped") return entry; if (!result || result === "failed") { host.log?.(`Unexpected failure resolving auto import for '${entry.name}' from '${entry.source}'`); @@ -876,7 +980,8 @@ function getJSDocParameterCompletions( checker: TypeChecker, options: CompilerOptions, preferences: UserPreferences, - tagNameOnly: boolean): CompletionEntry[] { + tagNameOnly: boolean, +): CompletionEntry[] { const currentToken = getTokenAtPosition(sourceFile, position); if (!isJSDocTag(currentToken) && !isJSDoc(currentToken)) { return []; @@ -900,17 +1005,17 @@ function getJSDocParameterCompletions( if (isIdentifier(param.name)) { // Named parameter const tabstopCounter = { tabstop: 1 }; const paramName = param.name.text; - let displayText = - getJSDocParamAnnotation( - paramName, - param.initializer, - param.dotDotDotToken, - isJs, - /*isObject*/ false, - /*isSnippet*/ false, - checker, - options, - preferences); + let displayText = getJSDocParamAnnotation( + paramName, + param.initializer, + param.dotDotDotToken, + isJs, + /*isObject*/ false, + /*isSnippet*/ false, + checker, + options, + preferences, + ); let snippetText = isSnippet ? getJSDocParamAnnotation( paramName, @@ -922,7 +1027,8 @@ function getJSDocParameterCompletions( checker, options, preferences, - tabstopCounter) + tabstopCounter, + ) : undefined; if (tagNameOnly) { // Remove `@` displayText = displayText.slice(1); @@ -938,17 +1044,17 @@ function getJSDocParameterCompletions( } else if (param.parent.parameters.indexOf(param) === paramTagCount) { // Destructuring parameter; do it positionally const paramPath = `param${paramTagCount}`; - const displayTextResult = - generateJSDocParamTagsForDestructuring( - paramPath, - param.name, - param.initializer, - param.dotDotDotToken, - isJs, - /*isSnippet*/ false, - checker, - options, - preferences,); + const displayTextResult = generateJSDocParamTagsForDestructuring( + paramPath, + param.name, + param.initializer, + param.dotDotDotToken, + isJs, + /*isSnippet*/ false, + checker, + options, + preferences, + ); const snippetTextResult = isSnippet ? generateJSDocParamTagsForDestructuring( paramPath, @@ -959,7 +1065,8 @@ function getJSDocParameterCompletions( /*isSnippet*/ true, checker, options, - preferences,) + preferences, + ) : undefined; let displayText = displayTextResult.join(getNewLineCharacter(options) + "* "); let snippetText = snippetTextResult?.join(getNewLineCharacter(options) + "* "); @@ -987,7 +1094,8 @@ function generateJSDocParamTagsForDestructuring( isSnippet: boolean, checker: TypeChecker, options: CompilerOptions, - preferences: UserPreferences): string[] { + preferences: UserPreferences, +): string[] { if (!isJs) { return [ getJSDocParamAnnotation( @@ -1000,7 +1108,8 @@ function generateJSDocParamTagsForDestructuring( checker, options, preferences, - { tabstop: 1 }) + { tabstop: 1 }, + ), ]; } return patternWorker(path, pattern, initializer, dotDotDotToken, { tabstop: 1 }); @@ -1010,22 +1119,23 @@ function generateJSDocParamTagsForDestructuring( pattern: BindingPattern, initializer: Expression | undefined, dotDotDotToken: DotDotDotToken | undefined, - counter: TabStopCounter): string[] { + counter: TabStopCounter, + ): string[] { if (isObjectBindingPattern(pattern) && !dotDotDotToken) { const oldTabstop = counter.tabstop; const childCounter = { tabstop: oldTabstop }; - const rootParam = - getJSDocParamAnnotation( - path, - initializer, - dotDotDotToken, - isJs, - /*isObject*/ true, - isSnippet, - checker, - options, - preferences, - childCounter); + const rootParam = getJSDocParamAnnotation( + path, + initializer, + dotDotDotToken, + isJs, + /*isObject*/ true, + isSnippet, + checker, + options, + preferences, + childCounter, + ); let childTags: string[] | undefined = []; for (const element of pattern.elements) { const elementTags = elementWorker(path, element, childCounter); @@ -1053,15 +1163,17 @@ function generateJSDocParamTagsForDestructuring( checker, options, preferences, - counter) - ]; + counter, + ), + ]; } // Assumes binding element is inside object binding pattern. // We can't really deeply annotate an array binding pattern. function elementWorker(path: string, element: BindingElement, counter: TabStopCounter): string[] | undefined { if ((!element.propertyName && isIdentifier(element.name)) || isIdentifier(element.name)) { // `{ b }` or `{ b: newB }` - const propertyName = element.propertyName ? tryGetTextOfPropertyName(element.propertyName) : element.name.text; + const propertyName = element.propertyName ? tryGetTextOfPropertyName(element.propertyName) + : element.name.text; if (!propertyName) { return undefined; } @@ -1077,12 +1189,20 @@ function generateJSDocParamTagsForDestructuring( checker, options, preferences, - counter)]; + counter, + ), + ]; } else if (element.propertyName) { // `{ b: {...} }` or `{ b: [...] }` const propertyName = tryGetTextOfPropertyName(element.propertyName); return propertyName - && patternWorker(`${path}.${propertyName}`, element.name, element.initializer, element.dotDotDotToken, counter); + && patternWorker( + `${path}.${propertyName}`, + element.name, + element.initializer, + element.dotDotDotToken, + counter, + ); } return undefined; } @@ -1102,7 +1222,8 @@ function getJSDocParamAnnotation( checker: TypeChecker, options: CompilerOptions, preferences: UserPreferences, - tabstopCounter?: TabStopCounter) { + tabstopCounter?: TabStopCounter, +) { if (isSnippet) { Debug.assertIsDefined(tabstopCounter); } @@ -1124,8 +1245,13 @@ function getJSDocParamAnnotation( if (!(inferredType.flags & (TypeFlags.Any | TypeFlags.Void))) { const sourceFile = initializer.getSourceFile(); const quotePreference = getQuotePreference(sourceFile, preferences); - const builderFlags = (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : NodeBuilderFlags.None); - const typeNode = checker.typeToTypeNode(inferredType, findAncestor(initializer, isFunctionLike), builderFlags); + const builderFlags = quotePreference === QuotePreference.Single + ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : NodeBuilderFlags.None; + const typeNode = checker.typeToTypeNode( + inferredType, + findAncestor(initializer, isFunctionLike), + builderFlags, + ); if (typeNode) { const printer = isSnippet ? createSnippetPrinter({ @@ -1136,7 +1262,7 @@ function getJSDocParamAnnotation( : createPrinter({ removeComments: true, module: options.module, - target: options.target + target: options.target, }); setEmitFlags(typeNode, EmitFlags.SingleLine); type = printer.printNode(EmitHint.Unspecified, typeNode, sourceFile); @@ -1174,7 +1300,10 @@ function keywordToCompletionEntry(keyword: TokenSyntaxKind) { }; } -function specificKeywordCompletionInfo(entries: readonly CompletionEntry[], isNewIdentifierLocation: boolean): CompletionInfo { +function specificKeywordCompletionInfo( + entries: readonly CompletionEntry[], + isNewIdentifierLocation: boolean, +): CompletionInfo { return { isGlobalCompletion: false, isMemberCompletion: false, @@ -1183,7 +1312,11 @@ function specificKeywordCompletionInfo(entries: readonly CompletionEntry[], isNe }; } -function keywordCompletionData(keywordFilters: KeywordCompletionFilters, filterOutTsOnlyKeywords: boolean, isNewIdentifierLocation: boolean): Request { +function keywordCompletionData( + keywordFilters: KeywordCompletionFilters, + filterOutTsOnlyKeywords: boolean, + isNewIdentifierLocation: boolean, +): Request { return { kind: CompletionDataKind.Keywords, keywordCompletions: getKeywordCompletions(keywordFilters, filterOutTsOnlyKeywords), @@ -1193,8 +1326,10 @@ function keywordCompletionData(keywordFilters: KeywordCompletionFilters, filterO function keywordFiltersFromSyntaxKind(keywordCompletion: TokenSyntaxKind): KeywordCompletionFilters { switch (keywordCompletion) { - case SyntaxKind.TypeKeyword: return KeywordCompletionFilters.TypeKeyword; - default: Debug.fail("Unknown mapping from SyntaxKind to KeywordCompletionFilters"); + case SyntaxKind.TypeKeyword: + return KeywordCompletionFilters.TypeKeyword; + default: + Debug.fail("Unknown mapping from SyntaxKind to KeywordCompletionFilters"); } } @@ -1269,7 +1404,10 @@ function completionInfoFromData( const entries = createSortedArray(); const isChecked = isCheckedFile(sourceFile, compilerOptions); - if (isChecked && !isNewIdentifierLocation && (!symbols || symbols.length === 0) && keywordFilters === KeywordCompletionFilters.None) { + if ( + isChecked && !isNewIdentifierLocation && (!symbols || symbols.length === 0) + && keywordFilters === KeywordCompletionFilters.None + ) { return undefined; } const uniqueNames = getCompletionEntriesFromSymbols( @@ -1298,12 +1436,20 @@ function completionInfoFromData( symbolToSortTextMap, isJsxIdentifierExpected, isRightOfOpenTag, - includeSymbol + includeSymbol, ); if (keywordFilters !== KeywordCompletionFilters.None) { - for (const keywordEntry of getKeywordCompletions(keywordFilters, !insideJsDocTagTypeExpression && isSourceFileJS(sourceFile))) { - if (isTypeOnlyLocation && isTypeKeyword(stringToToken(keywordEntry.name)!) || !uniqueNames.has(keywordEntry.name)) { + for ( + const keywordEntry of getKeywordCompletions( + keywordFilters, + !insideJsDocTagTypeExpression && isSourceFileJS(sourceFile), + ) + ) { + if ( + isTypeOnlyLocation && isTypeKeyword(stringToToken(keywordEntry.name)!) + || !uniqueNames.has(keywordEntry.name) + ) { uniqueNames.add(keywordEntry.name); insertSorted(entries, keywordEntry, compareCompletionEntries, /*allowDuplicates*/ true); } @@ -1328,12 +1474,22 @@ function completionInfoFromData( } let caseBlock: CaseBlock | undefined; - if (preferences.includeCompletionsWithInsertText + if ( + preferences.includeCompletionsWithInsertText && contextToken && !isRightOfOpenTag && !isRightOfDotOrQuestionDot - && (caseBlock = findAncestor(contextToken, isCaseBlock))) { - const cases = getExhaustiveCaseSnippets(caseBlock, sourceFile, preferences, compilerOptions, host, program, formatContext); + && (caseBlock = findAncestor(contextToken, isCaseBlock)) + ) { + const cases = getExhaustiveCaseSnippets( + caseBlock, + sourceFile, + preferences, + compilerOptions, + host, + program, + formatContext, + ); if (cases) { entries.push(cases.entry); } @@ -1361,8 +1517,8 @@ function getExhaustiveCaseSnippets( options: CompilerOptions, host: LanguageServiceHost, program: Program, - formatContext: formatting.FormatContext | undefined): { entry: CompletionEntry, importAdder: codefix.ImportAdder } | undefined { - + formatContext: formatting.FormatContext | undefined, +): { entry: CompletionEntry; importAdder: codefix.ImportAdder; } | undefined { const clauses = caseBlock.clauses; const checker = program.getTypeChecker(); const switchType = checker.getTypeAtLocation(caseBlock.parent.expression); @@ -1380,7 +1536,8 @@ function getExhaustiveCaseSnippets( Debug.assert(type.symbol, "An enum member type should have a symbol"); Debug.assert(type.symbol.parent, "An enum member type should have a parent symbol (the enum symbol)"); // Filter existing enums by their values - const enumValue = type.symbol.valueDeclaration && checker.getConstantValue(type.symbol.valueDeclaration as EnumMember); + const enumValue = type.symbol.valueDeclaration + && checker.getConstantValue(type.symbol.valueDeclaration as EnumMember); if (enumValue !== undefined) { if (tracker.hasValue(enumValue)) { continue; @@ -1401,13 +1558,30 @@ function getExhaustiveCaseSnippets( else if (!tracker.hasValue(type.value)) { switch (typeof type.value) { case "object": - elements.push(type.value.negative ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createBigIntLiteral({ negative: false, base10Value: type.value.base10Value })) : factory.createBigIntLiteral(type.value)); + elements.push( + type.value.negative + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createBigIntLiteral({ + negative: false, + base10Value: type.value.base10Value, + }), + ) : factory.createBigIntLiteral(type.value), + ); break; case "number": - elements.push(type.value < 0 ? factory.createPrefixUnaryExpression(SyntaxKind.MinusToken, factory.createNumericLiteral(-type.value)) : factory.createNumericLiteral(type.value)); + elements.push( + type.value < 0 + ? factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral(-type.value), + ) : factory.createNumericLiteral(type.value), + ); break; case "string": - elements.push(factory.createStringLiteral(type.value, quotePreference === QuotePreference.Single)); + elements.push( + factory.createStringLiteral(type.value, quotePreference === QuotePreference.Single), + ); break; } } @@ -1422,14 +1596,14 @@ function getExhaustiveCaseSnippets( removeComments: true, module: options.module, target: options.target, - newLine: getNewLineKind(newLineChar) + newLine: getNewLineKind(newLineChar), }); const printNode = formatContext ? (node: Node) => printer.printAndFormatNode(EmitHint.Unspecified, node, sourceFile, formatContext) : (node: Node) => printer.printNode(EmitHint.Unspecified, node, sourceFile); const insertText = map(newClauses, (clause, i) => { if (preferences.includeCompletionsWithSnippetText) { - return `${printNode(clause)}$${i+1}`; + return `${printNode(clause)}$${i + 1}`; } return `${printNode(clause)}`; }).join(newLineChar); @@ -1452,16 +1626,26 @@ function getExhaustiveCaseSnippets( return undefined; } -function typeNodeToExpression(typeNode: TypeNode, languageVersion: ScriptTarget, quotePreference: QuotePreference): Expression | undefined { +function typeNodeToExpression( + typeNode: TypeNode, + languageVersion: ScriptTarget, + quotePreference: QuotePreference, +): Expression | undefined { switch (typeNode.kind) { case SyntaxKind.TypeReference: const typeName = (typeNode as TypeReferenceNode).typeName; return entityNameToExpression(typeName, languageVersion, quotePreference); case SyntaxKind.IndexedAccessType: - const objectExpression = - typeNodeToExpression((typeNode as IndexedAccessTypeNode).objectType, languageVersion, quotePreference); - const indexExpression = - typeNodeToExpression((typeNode as IndexedAccessTypeNode).indexType, languageVersion, quotePreference); + const objectExpression = typeNodeToExpression( + (typeNode as IndexedAccessTypeNode).objectType, + languageVersion, + quotePreference, + ); + const indexExpression = typeNodeToExpression( + (typeNode as IndexedAccessTypeNode).indexType, + languageVersion, + quotePreference, + ); return objectExpression && indexExpression && factory.createElementAccessExpression(objectExpression, indexExpression); @@ -1475,7 +1659,11 @@ function typeNodeToExpression(typeNode: TypeNode, languageVersion: ScriptTarget, } return undefined; case SyntaxKind.ParenthesizedType: - const exp = typeNodeToExpression((typeNode as ParenthesizedTypeNode).type, languageVersion, quotePreference); + const exp = typeNodeToExpression( + (typeNode as ParenthesizedTypeNode).type, + languageVersion, + quotePreference, + ); return exp && (isIdentifier(exp) ? exp : factory.createParenthesizedExpression(exp)); case SyntaxKind.TypeQuery: return entityNameToExpression((typeNode as TypeQueryNode).exprName, languageVersion, quotePreference); @@ -1486,7 +1674,11 @@ function typeNodeToExpression(typeNode: TypeNode, languageVersion: ScriptTarget, return undefined; } -function entityNameToExpression(entityName: EntityName, languageVersion: ScriptTarget, quotePreference: QuotePreference): Expression { +function entityNameToExpression( + entityName: EntityName, + languageVersion: ScriptTarget, + quotePreference: QuotePreference, +): Expression { if (isIdentifier(entityName)) { return entityName; } @@ -1494,12 +1686,14 @@ function entityNameToExpression(entityName: EntityName, languageVersion: ScriptT if (canUsePropertyAccess(unescapedName, languageVersion)) { return factory.createPropertyAccessExpression( entityNameToExpression(entityName.left, languageVersion, quotePreference), - unescapedName); + unescapedName, + ); } else { return factory.createElementAccessExpression( entityNameToExpression(entityName.left, languageVersion, quotePreference), - factory.createStringLiteral(unescapedName, quotePreference === QuotePreference.Single)); + factory.createStringLiteral(unescapedName, quotePreference === QuotePreference.Single), + ); } } @@ -1555,7 +1749,13 @@ function getJsxClosingTagCompletion(location: Node | undefined, sourceFile: Sour kindModifiers: undefined, sortText: SortText.LocationPriority, }; - return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: false, optionalReplacementSpan: replacementSpan, entries: [entry] }; + return { + isGlobalCompletion: false, + isMemberCompletion: true, + isNewIdentifierLocation: false, + optionalReplacementSpan: replacementSpan, + entries: [entry], + }; } return; } @@ -1565,7 +1765,8 @@ function getJSCompletionEntries( position: number, uniqueNames: UniqueNameSet, target: ScriptTarget, - entries: SortedArray): void { + entries: SortedArray, +): void { getNameTable(sourceFile).forEach((pos, name) => { // Skip identifiers produced only from the current location if (pos === position) { @@ -1579,19 +1780,32 @@ function getJSCompletionEntries( kind: ScriptElementKind.warning, kindModifiers: "", sortText: SortText.JavascriptIdentifiers, - isFromUncheckedFile: true + isFromUncheckedFile: true, }, compareCompletionEntries); } }); } -function completionNameForLiteral(sourceFile: SourceFile, preferences: UserPreferences, literal: string | number | PseudoBigInt): string { - return typeof literal === "object" ? pseudoBigIntToString(literal) + "n" : - isString(literal) ? quote(sourceFile, preferences, literal) : JSON.stringify(literal); +function completionNameForLiteral( + sourceFile: SourceFile, + preferences: UserPreferences, + literal: string | number | PseudoBigInt, +): string { + return typeof literal === "object" ? pseudoBigIntToString(literal) + "n" + : isString(literal) ? quote(sourceFile, preferences, literal) : JSON.stringify(literal); } -function createCompletionEntryForLiteral(sourceFile: SourceFile, preferences: UserPreferences, literal: string | number | PseudoBigInt): CompletionEntry { - return { name: completionNameForLiteral(sourceFile, preferences, literal), kind: ScriptElementKind.string, kindModifiers: ScriptElementKindModifier.none, sortText: SortText.LocationPriority }; +function createCompletionEntryForLiteral( + sourceFile: SourceFile, + preferences: UserPreferences, + literal: string | number | PseudoBigInt, +): CompletionEntry { + return { + name: completionNameForLiteral(sourceFile, preferences, literal), + kind: ScriptElementKind.string, + kindModifiers: ScriptElementKindModifier.none, + sortText: SortText.LocationPriority, + }; } function createCompletionEntry( @@ -1618,7 +1832,7 @@ function createCompletionEntry( formatContext: formatting.FormatContext | undefined, isJsxIdentifierExpected: boolean | undefined, isRightOfOpenTag: boolean | undefined, - includeSymbol: boolean + includeSymbol: boolean, ): CompletionEntry | undefined { let insertText: string | undefined; let filterText: string | undefined; @@ -1641,13 +1855,14 @@ function createCompletionEntry( // We should only have needsConvertPropertyAccess if there's a property access to convert. But see #21790. // Somehow there was a global with a non-identifier name. Hopefully someone will complain about getting a "foo bar" global completion and provide a repro. else if ((useBraces || insertQuestionDot) && propertyAccessToConvert) { - insertText = useBraces ? needsConvertPropertyAccess ? `[${quotePropertyName(sourceFile, preferences, name)}]` : `[${name}]` : name; + insertText = useBraces + ? needsConvertPropertyAccess ? `[${quotePropertyName(sourceFile, preferences, name)}]` : `[${name}]` : name; if (insertQuestionDot || propertyAccessToConvert.questionDotToken) { insertText = `?.${insertText}`; } - const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile) || - findChildOfKind(propertyAccessToConvert, SyntaxKind.QuestionDotToken, sourceFile); + const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile) + || findChildOfKind(propertyAccessToConvert, SyntaxKind.QuestionDotToken, sourceFile); if (!dot) { return undefined; } @@ -1672,7 +1887,8 @@ function createCompletionEntry( } awaitText += `(await ${propertyAccessToConvert.expression.getText()})`; - insertText = needsConvertPropertyAccess ? `${awaitText}${insertText}` : `${awaitText}${insertQuestionDot ? "?." : "."}${insertText}`; + insertText = needsConvertPropertyAccess ? `${awaitText}${insertText}` + : `${awaitText}${insertQuestionDot ? "?." : "."}${insertText}`; const isInAwaitExpression = tryCast(propertyAccessToConvert.parent, isAwaitExpression); const wrapNode = isInAwaitExpression ? propertyAccessToConvert.parent : propertyAccessToConvert.expression; replacementSpan = createTextSpanFromBounds(wrapNode.getStart(sourceFile), propertyAccessToConvert.end); @@ -1681,7 +1897,15 @@ function createCompletionEntry( if (originIsResolvedExport(origin)) { sourceDisplay = [textPart(origin.moduleSpecifier)]; if (importStatementCompletion) { - ({ insertText, replacementSpan } = getInsertTextAndReplacementSpanForImportCompletion(name, importStatementCompletion, origin, useSemicolons, sourceFile, options, preferences)); + ({ insertText, replacementSpan } = getInsertTextAndReplacementSpanForImportCompletion( + name, + importStatementCompletion, + origin, + useSemicolons, + sourceFile, + options, + preferences, + )); isSnippet = preferences.includeCompletionsWithSnippetText ? true : undefined; } } @@ -1701,25 +1925,44 @@ function createCompletionEntry( // const cc: I = { a: "red" | } // // Completion should add a comma after "red" and provide completions for b - if (completionKind === CompletionKind.ObjectPropertyDeclaration && contextToken && findPrecedingToken(contextToken.pos, sourceFile, contextToken)?.kind !== SyntaxKind.CommaToken) { - if (isMethodDeclaration(contextToken.parent.parent) || - isGetAccessorDeclaration(contextToken.parent.parent) || - isSetAccessorDeclaration(contextToken.parent.parent) || - isSpreadAssignment(contextToken.parent) || - findAncestor(contextToken.parent, isPropertyAssignment)?.getLastToken(sourceFile) === contextToken || - isShorthandPropertyAssignment(contextToken.parent) && getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line !== getLineAndCharacterOfPosition(sourceFile, position).line) { - + if ( + completionKind === CompletionKind.ObjectPropertyDeclaration && contextToken + && findPrecedingToken(contextToken.pos, sourceFile, contextToken)?.kind !== SyntaxKind.CommaToken + ) { + if ( + isMethodDeclaration(contextToken.parent.parent) + || isGetAccessorDeclaration(contextToken.parent.parent) + || isSetAccessorDeclaration(contextToken.parent.parent) + || isSpreadAssignment(contextToken.parent) + || findAncestor(contextToken.parent, isPropertyAssignment)?.getLastToken(sourceFile) === contextToken + || isShorthandPropertyAssignment(contextToken.parent) + && getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line + !== getLineAndCharacterOfPosition(sourceFile, position).line + ) { source = CompletionSource.ObjectLiteralMemberWithComma; hasAction = true; } } - if (preferences.includeCompletionsWithClassMemberSnippets && - preferences.includeCompletionsWithInsertText && - completionKind === CompletionKind.MemberLike && - isClassLikeMemberCompletion(symbol, location, sourceFile)) { + if ( + preferences.includeCompletionsWithClassMemberSnippets + && preferences.includeCompletionsWithInsertText + && completionKind === CompletionKind.MemberLike + && isClassLikeMemberCompletion(symbol, location, sourceFile) + ) { let importAdder; - const memberCompletionEntry = getEntryForMemberCompletion(host, program, options, preferences, name, symbol, location, position, contextToken, formatContext); + const memberCompletionEntry = getEntryForMemberCompletion( + host, + program, + options, + preferences, + name, + symbol, + location, + position, + contextToken, + formatContext, + ); if (memberCompletionEntry) { ({ insertText, filterText, isSnippet, importAdder } = memberCompletionEntry); if (importAdder?.hasFixes()) { @@ -1742,18 +1985,32 @@ function createCompletionEntry( sortText = SortText.SortBelow(sortText); } - if (isJsxIdentifierExpected && !isRightOfOpenTag + if ( + isJsxIdentifierExpected && !isRightOfOpenTag && preferences.includeCompletionsWithSnippetText && preferences.jsxAttributeCompletionStyle - && preferences.jsxAttributeCompletionStyle !== "none" && !(isJsxAttribute(location.parent) && location.parent.initializer)) { + && preferences.jsxAttributeCompletionStyle !== "none" + && !(isJsxAttribute(location.parent) && location.parent.initializer) + ) { let useBraces = preferences.jsxAttributeCompletionStyle === "braces"; const type = typeChecker.getTypeOfSymbolAtLocation(symbol, location); // If is boolean like or undefined, don't return a snippet we want just to return the completion. - if (preferences.jsxAttributeCompletionStyle === "auto" + if ( + preferences.jsxAttributeCompletionStyle === "auto" && !(type.flags & TypeFlags.BooleanLike) - && !(type.flags & TypeFlags.Union && find((type as UnionType).types, type => !!(type.flags & TypeFlags.BooleanLike))) + && !(type.flags & TypeFlags.Union + && find((type as UnionType).types, type => !!(type.flags & TypeFlags.BooleanLike))) ) { - if (type.flags & TypeFlags.StringLike || (type.flags & TypeFlags.Union && every((type as UnionType).types, type => !!(type.flags & (TypeFlags.StringLike | TypeFlags.Undefined) || isStringAndEmptyAnonymousObjectIntersection(type))))) { + if ( + type.flags & TypeFlags.StringLike + || (type.flags & TypeFlags.Union + && every( + (type as UnionType).types, + type => + !!(type.flags & (TypeFlags.StringLike | TypeFlags.Undefined) + || isStringAndEmptyAnonymousObjectIntersection(type)), + )) + ) { // If is string like or undefined use quotes insertText = `${escapeSnippetText(name)}=${quote(sourceFile, preferences, "$1")}`; isSnippet = true; @@ -1782,7 +2039,10 @@ function createCompletionEntry( const parentNamedImportOrExport = findAncestor(location, isNamedImportsOrExports); if (parentNamedImportOrExport?.kind === SyntaxKind.NamedImports) { const possibleToken = stringToToken(name); - if (parentNamedImportOrExport && possibleToken && (possibleToken === SyntaxKind.AwaitKeyword || isNonContextualKeyword(possibleToken))) { + if ( + parentNamedImportOrExport && possibleToken + && (possibleToken === SyntaxKind.AwaitKeyword || isNonContextualKeyword(possibleToken)) + ) { insertText = `${name} as ${name}_`; } } @@ -1812,7 +2072,7 @@ function createCompletionEntry( isPackageJsonImport: originIsPackageJsonImport(origin) || undefined, isImportStatementCompletion: !!importStatementCompletion || undefined, data, - ...includeSymbol ? { symbol } : undefined + ...includeSymbol ? { symbol } : undefined, }; } @@ -1823,8 +2083,7 @@ function isClassLikeMemberCompletion(symbol: Symbol, location: Node, sourceFile: } // Completion symbol must be for a class member. - const memberFlags = - SymbolFlags.ClassMember + const memberFlags = SymbolFlags.ClassMember & SymbolFlags.EnumMemberExcludes; /* In `class C { @@ -1846,21 +2105,21 @@ function isClassLikeMemberCompletion(symbol: Symbol, location: Node, sourceFile: `location` is a syntax list (with modifiers as children), and `location.parent` is a class-like declaration. */ - return !!(symbol.flags & memberFlags) && - ( - isClassLike(location) || - ( - location.parent && - location.parent.parent && - isClassElement(location.parent) && - location === location.parent.name && - location.parent.getLastToken(sourceFile) === location.parent.name && - isClassLike(location.parent.parent) - ) || - ( - location.parent && - isSyntaxList(location) && - isClassLike(location.parent) + return !!(symbol.flags & memberFlags) + && ( + isClassLike(location) + || ( + location.parent + && location.parent.parent + && isClassElement(location.parent) + && location === location.parent.name + && location.parent.getLastToken(sourceFile) === location.parent.name + && isClassLike(location.parent.parent) + ) + || ( + location.parent + && isSyntaxList(location) + && isClassLike(location.parent) ) ); } @@ -1876,7 +2135,13 @@ function getEntryForMemberCompletion( position: number, contextToken: Node | undefined, formatContext: formatting.FormatContext | undefined, -): { insertText: string, filterText?: string, isSnippet?: true, importAdder?: codefix.ImportAdder, eraseRange?: TextRange } | undefined { +): { + insertText: string; + filterText?: string; + isSnippet?: true; + importAdder?: codefix.ImportAdder; + eraseRange?: TextRange; +} | undefined { const classLikeDeclaration = findAncestor(location, isClassLike); if (!classLikeDeclaration) { return undefined; // This should never happen. @@ -1913,10 +2178,15 @@ function getEntryForMemberCompletion( } let modifiers = ModifierFlags.None; - const { modifiers: presentModifiers, range: eraseRange, decorators: presentDecorators } = getPresentModifiers(contextToken, sourceFile, position); + const { modifiers: presentModifiers, range: eraseRange, decorators: presentDecorators } = getPresentModifiers( + contextToken, + sourceFile, + position, + ); // Whether the suggested member should be abstract. // e.g. in `abstract class C { abstract | }`, we should offer abstract method signatures at position `|`. - const isAbstract = presentModifiers & ModifierFlags.Abstract && classLikeDeclaration.modifierFlagsCache & ModifierFlags.Abstract; + const isAbstract = presentModifiers & ModifierFlags.Abstract + && classLikeDeclaration.modifierFlagsCache & ModifierFlags.Abstract; let completionNodes: codefix.AddNode[] = []; codefix.addNewNodeForMemberSymbol( symbol, @@ -1937,8 +2207,11 @@ function getEntryForMemberCompletion( if (isAbstract) { requiredModifiers |= ModifierFlags.Abstract; } - if (isClassElement(node) - && checker.getMemberOverrideModifierStatus(classLikeDeclaration, node, symbol) === MemberOverrideStatus.NeedsOverride) { + if ( + isClassElement(node) + && checker.getMemberOverrideModifierStatus(classLikeDeclaration, node, symbol) + === MemberOverrideStatus.NeedsOverride + ) { requiredModifiers |= ModifierFlags.Override; } if (!completionNodes.length) { @@ -1953,7 +2226,8 @@ function getEntryForMemberCompletion( }, body, codefix.PreserveOptionalFlags.Property, - !!isAbstract); + !!isAbstract, + ); if (completionNodes.length) { const isMethod = symbol.flags & SymbolFlags.Method; @@ -1982,7 +2256,10 @@ function getEntryForMemberCompletion( if (presentDecorators?.length) { const lastNode = completionNodes[completionNodes.length - 1]; if (canHaveDecorators(lastNode)) { - completionNodes[completionNodes.length - 1] = factory.updateModifierLike(lastNode, (presentDecorators as ModifierLike[]).concat(getModifiers(lastNode) || [])); + completionNodes[completionNodes.length - 1] = factory.updateModifierLike( + lastNode, + (presentDecorators as ModifierLike[]).concat(getModifiers(lastNode) || []), + ); } } @@ -1994,13 +2271,15 @@ function getEntryForMemberCompletion( format, factory.createNodeArray(completionNodes), sourceFile, - formatContext); + formatContext, + ); } else { // Otherwise, just use emitter to print the new nodes. insertText = printer.printSnippetList( format, factory.createNodeArray(completionNodes), - sourceFile); + sourceFile, + ); } } @@ -2010,10 +2289,13 @@ function getEntryForMemberCompletion( function getPresentModifiers( contextToken: Node | undefined, sourceFile: SourceFile, - position: number): { modifiers: ModifierFlags, decorators?: Decorator[], range?: TextRange } { - if (!contextToken || - getLineAndCharacterOfPosition(sourceFile, position).line - > getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line) { + position: number, +): { modifiers: ModifierFlags; decorators?: Decorator[]; range?: TextRange; } { + if ( + !contextToken + || getLineAndCharacterOfPosition(sourceFile, position).line + > getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line + ) { return { modifiers: ModifierFlags.None }; } let modifiers = ModifierFlags.None; @@ -2076,7 +2358,7 @@ function getEntryForObjectLiteralMethodCompletion( options: CompilerOptions, preferences: UserPreferences, formatContext: formatting.FormatContext | undefined, -): { insertText: string, isSnippet?: true, labelDetails: CompletionEntryLabelDetails } | undefined { +): { insertText: string; isSnippet?: true; labelDetails: CompletionEntryLabelDetails; } | undefined { const isSnippet = preferences.includeCompletionsWithSnippetText || undefined; let insertText: string = name; @@ -2095,10 +2377,19 @@ function getEntryForObjectLiteralMethodCompletion( newLine: getNewLineKind(getNewLineOrDefaultFromHost(host, formatContext?.options)), }); if (formatContext) { - insertText = printer.printAndFormatSnippetList(ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, factory.createNodeArray([method], /*hasTrailingComma*/ true), sourceFile, formatContext); + insertText = printer.printAndFormatSnippetList( + ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, + factory.createNodeArray([method], /*hasTrailingComma*/ true), + sourceFile, + formatContext, + ); } else { - insertText = printer.printSnippetList(ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, factory.createNodeArray([method], /*hasTrailingComma*/ true), sourceFile); + insertText = printer.printSnippetList( + ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, + factory.createNodeArray([method], /*hasTrailingComma*/ true), + sourceFile, + ); } const signaturePrinter = createPrinter({ @@ -2115,11 +2406,11 @@ function getEntryForObjectLiteralMethodCompletion( method.questionToken, method.typeParameters, method.parameters, - method.type); + method.type, + ); const labelDetails = { detail: signaturePrinter.printNode(EmitHint.Unspecified, methodSignature, sourceFile) }; return { isSnippet, insertText, labelDetails }; - } function createObjectLiteralMethod( @@ -2139,7 +2430,9 @@ function createObjectLiteralMethod( const name = getSynthesizedDeepClone(getNameOfDeclaration(declaration), /*includeTrivia*/ false) as PropertyName; const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration)); const quotePreference = getQuotePreference(sourceFile, preferences); - const builderFlags = NodeBuilderFlags.OmitThisParameter | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType : NodeBuilderFlags.None); + const builderFlags = NodeBuilderFlags.OmitThisParameter + | (quotePreference === QuotePreference.Single ? NodeBuilderFlags.UseSingleQuotesForStringLiteralType + : NodeBuilderFlags.None); switch (declaration.kind) { case SyntaxKind.PropertySignature: @@ -2151,7 +2444,10 @@ function createObjectLiteralMethod( : type; if (effectiveType.flags & TypeFlags.Union) { // Only offer the completion if there's a single function type component. - const functionTypes = filter((effectiveType as UnionType).types, type => checker.getSignaturesOfType(type, SignatureKind.Call).length > 0); + const functionTypes = filter( + (effectiveType as UnionType).types, + type => checker.getSignaturesOfType(type, SignatureKind.Call).length > 0, + ); if (functionTypes.length === 1) { effectiveType = functionTypes[0]; } @@ -2164,7 +2460,12 @@ function createObjectLiteralMethod( // We don't support overloads in object literals. return undefined; } - const typeNode = checker.typeToTypeNode(effectiveType, enclosingDeclaration, builderFlags, codefix.getNoopSymbolTrackerWithResolver({ program, host })); + const typeNode = checker.typeToTypeNode( + effectiveType, + enclosingDeclaration, + builderFlags, + codefix.getNoopSymbolTrackerWithResolver({ program, host }), + ); if (!typeNode || !isFunctionTypeNode(typeNode)) { return undefined; } @@ -2187,7 +2488,8 @@ function createObjectLiteralMethod( /*questionToken*/ undefined, /*type*/ undefined, typedParam.initializer, - )); + ) + ); return factory.createMethodDeclaration( /*modifiers*/ undefined, /*asteriskToken*/ undefined, @@ -2196,8 +2498,9 @@ function createObjectLiteralMethod( /*typeParameters*/ undefined, parameters, /*type*/ undefined, - body); - } + body, + ); + } default: return undefined; } @@ -2276,7 +2579,8 @@ function createSnippetPrinter( text: printUnescapedSnippetList( format, list, - sourceFile), + sourceFile, + ), getLineAndCharacterOfPosition(pos: number) { return getLineAndCharacterOfPosition(this, pos); }, @@ -2291,7 +2595,8 @@ function createSnippetPrinter( sourceFile.languageVariant, /* indentation */ 0, /* delta */ 0, - { ...formatContext, options: formatOptions }); + { ...formatContext, options: formatOptions }, + ); }); const allChanges = escapes @@ -2317,12 +2622,14 @@ function createSnippetPrinter( hint: EmitHint, node: Node, sourceFile: SourceFile, - formatContext: formatting.FormatContext): string { + formatContext: formatting.FormatContext, + ): string { const syntheticFile = { text: printUnescapedNode( hint, node, - sourceFile), + sourceFile, + ), getLineAndCharacterOfPosition(pos: number) { return getLineAndCharacterOfPosition(this, pos); }, @@ -2336,7 +2643,8 @@ function createSnippetPrinter( sourceFile.languageVariant, /* indentation */ 0, /* delta */ 0, - { ...formatContext, options: formatOptions }); + { ...formatContext, options: formatOptions }, + ); const allChanges = escapes ? stableSort(concatenate(changes, escapes), (a, b) => compareTextSpans(a.span, b.span)) @@ -2345,7 +2653,9 @@ function createSnippetPrinter( } } -function originToCompletionEntryData(origin: SymbolOriginInfoExport | SymbolOriginInfoResolvedExport): CompletionEntryData | undefined { +function originToCompletionEntryData( + origin: SymbolOriginInfoExport | SymbolOriginInfoResolvedExport, +): CompletionEntryData | undefined { const ambientModuleName = origin.fileName ? undefined : stripQuotes(origin.moduleSymbol.name); const isPackageJsonImport = origin.isFromPackageJson ? true : undefined; if (originIsResolvedExport(origin)) { @@ -2369,7 +2679,11 @@ function originToCompletionEntryData(origin: SymbolOriginInfoExport | SymbolOrig return unresolvedData; } -function completionEntryDataToSymbolOriginInfo(data: CompletionEntryData, completionName: string, moduleSymbol: Symbol): SymbolOriginInfoExport | SymbolOriginInfoResolvedExport { +function completionEntryDataToSymbolOriginInfo( + data: CompletionEntryData, + completionName: string, + moduleSymbol: Symbol, +): SymbolOriginInfoExport | SymbolOriginInfoResolvedExport { const isDefaultExport = data.exportName === InternalSymbolName.Default; const isFromPackageJson = !!data.isPackageJsonImport; if (completionEntryDataIsResolved(data)) { @@ -2399,28 +2713,60 @@ function completionEntryDataToSymbolOriginInfo(data: CompletionEntryData, comple return unresolvedOrigin; } -function getInsertTextAndReplacementSpanForImportCompletion(name: string, importStatementCompletion: ImportStatementCompletionInfo, origin: SymbolOriginInfoResolvedExport, useSemicolons: boolean, sourceFile: SourceFile, options: CompilerOptions, preferences: UserPreferences) { +function getInsertTextAndReplacementSpanForImportCompletion( + name: string, + importStatementCompletion: ImportStatementCompletionInfo, + origin: SymbolOriginInfoResolvedExport, + useSemicolons: boolean, + sourceFile: SourceFile, + options: CompilerOptions, + preferences: UserPreferences, +) { const replacementSpan = importStatementCompletion.replacementSpan; const quotedModuleSpecifier = escapeSnippetText(quote(sourceFile, preferences, origin.moduleSpecifier)); - const exportKind = - origin.isDefaultExport ? ExportKind.Default : - origin.exportName === InternalSymbolName.ExportEquals ? ExportKind.ExportEquals : - ExportKind.Named; + const exportKind = origin.isDefaultExport ? ExportKind.Default + : origin.exportName === InternalSymbolName.ExportEquals ? ExportKind.ExportEquals + : ExportKind.Named; const tabStop = preferences.includeCompletionsWithSnippetText ? "$1" : ""; const importKind = codefix.getImportKind(sourceFile, exportKind, options, /*forceImportKeyword*/ true); const isImportSpecifierTypeOnly = importStatementCompletion.couldBeTypeOnlyImportSpecifier; - const topLevelTypeOnlyText = importStatementCompletion.isTopLevelTypeOnly ? ` ${tokenToString(SyntaxKind.TypeKeyword)} ` : " "; + const topLevelTypeOnlyText = importStatementCompletion.isTopLevelTypeOnly + ? ` ${tokenToString(SyntaxKind.TypeKeyword)} ` : " "; const importSpecifierTypeOnlyText = isImportSpecifierTypeOnly ? `${tokenToString(SyntaxKind.TypeKeyword)} ` : ""; const suffix = useSemicolons ? ";" : ""; switch (importKind) { - case ImportKind.CommonJS: return { replacementSpan, insertText: `import${topLevelTypeOnlyText}${escapeSnippetText(name)}${tabStop} = require(${quotedModuleSpecifier})${suffix}` }; - case ImportKind.Default: return { replacementSpan, insertText: `import${topLevelTypeOnlyText}${escapeSnippetText(name)}${tabStop} from ${quotedModuleSpecifier}${suffix}` }; - case ImportKind.Namespace: return { replacementSpan, insertText: `import${topLevelTypeOnlyText}* as ${escapeSnippetText(name)} from ${quotedModuleSpecifier}${suffix}` }; - case ImportKind.Named: return { replacementSpan, insertText: `import${topLevelTypeOnlyText}{ ${importSpecifierTypeOnlyText}${escapeSnippetText(name)}${tabStop} } from ${quotedModuleSpecifier}${suffix}` }; + case ImportKind.CommonJS: + return { + replacementSpan, + insertText: `import${topLevelTypeOnlyText}${ + escapeSnippetText(name) + }${tabStop} = require(${quotedModuleSpecifier})${suffix}`, + }; + case ImportKind.Default: + return { + replacementSpan, + insertText: `import${topLevelTypeOnlyText}${ + escapeSnippetText(name) + }${tabStop} from ${quotedModuleSpecifier}${suffix}`, + }; + case ImportKind.Namespace: + return { + replacementSpan, + insertText: `import${topLevelTypeOnlyText}* as ${ + escapeSnippetText(name) + } from ${quotedModuleSpecifier}${suffix}`, + }; + case ImportKind.Named: + return { + replacementSpan, + insertText: `import${topLevelTypeOnlyText}{ ${importSpecifierTypeOnlyText}${ + escapeSnippetText(name) + }${tabStop} } from ${quotedModuleSpecifier}${suffix}`, + }; } } -function quotePropertyName(sourceFile: SourceFile, preferences: UserPreferences, name: string,): string { +function quotePropertyName(sourceFile: SourceFile, preferences: UserPreferences, name: string): string { if (/^\d+$/.test(name)) { return name; } @@ -2428,9 +2774,14 @@ function quotePropertyName(sourceFile: SourceFile, preferences: UserPreferences, return quote(sourceFile, preferences, name); } -function isRecommendedCompletionMatch(localSymbol: Symbol, recommendedCompletion: Symbol | undefined, checker: TypeChecker): boolean { - return localSymbol === recommendedCompletion || - !!(localSymbol.flags & SymbolFlags.ExportValue) && checker.getExportSymbolOfSymbol(localSymbol) === recommendedCompletion; +function isRecommendedCompletionMatch( + localSymbol: Symbol, + recommendedCompletion: Symbol | undefined, + checker: TypeChecker, +): boolean { + return localSymbol === recommendedCompletion + || !!(localSymbol.flags & SymbolFlags.ExportValue) + && checker.getExportSymbolOfSymbol(localSymbol) === recommendedCompletion; } function getSourceFromOrigin(origin: SymbolOriginInfo | undefined): string | undefined { @@ -2475,7 +2826,7 @@ export function getCompletionEntriesFromSymbols( symbolToSortTextMap?: SymbolSortTextMap, isJsxIdentifierExpected?: boolean, isRightOfOpenTag?: boolean, - includeSymbol = false + includeSymbol = false, ): UniqueNameSet { const start = timestamp(); const variableOrParameterDeclaration = getVariableOrParameterDeclaration(contextToken, location); @@ -2490,13 +2841,17 @@ export function getCompletionEntriesFromSymbols( const symbol = symbols[i]; const origin = symbolToOriginInfoMap?.[i]; const info = getCompletionEntryDisplayNameForSymbol(symbol, target, origin, kind, !!jsxIdentifierExpected); - if (!info || (uniques.get(info.name) && (!origin || !originIsObjectLiteralMethod(origin))) || kind === CompletionKind.Global && symbolToSortTextMap && !shouldIncludeSymbol(symbol, symbolToSortTextMap)) { + if ( + !info || (uniques.get(info.name) && (!origin || !originIsObjectLiteralMethod(origin))) + || kind === CompletionKind.Global && symbolToSortTextMap + && !shouldIncludeSymbol(symbol, symbolToSortTextMap) + ) { continue; } const { name, needsConvertPropertyAccess } = info; const originalSortText = symbolToSortTextMap?.[getSymbolId(symbol)] ?? SortText.LocationPriority; - const sortText = (isDeprecated(symbol, typeChecker) ? SortText.Deprecated(originalSortText) : originalSortText); + const sortText = isDeprecated(symbol, typeChecker) ? SortText.Deprecated(originalSortText) : originalSortText; const entry = createCompletionEntry( symbol, sortText, @@ -2521,14 +2876,16 @@ export function getCompletionEntriesFromSymbols( formatContext, isJsxIdentifierExpected, isRightOfOpenTag, - includeSymbol + includeSymbol, ); if (!entry) { continue; } /** True for locals; false for globals, module exports from other files, `this.` completions. */ - const shouldShadowLaterSymbols = (!origin || originIsTypeOnlyAlias(origin)) && !(symbol.parent === undefined && !some(symbol.declarations, d => d.getSourceFile() === location.getSourceFile())); + const shouldShadowLaterSymbols = (!origin || originIsTypeOnlyAlias(origin)) + && !(symbol.parent === undefined + && !some(symbol.declarations, d => d.getSourceFile() === location.getSourceFile())); uniques.set(name, shouldShadowLaterSymbols); insertSorted(entries, entry, compareCompletionEntries, /*allowDuplicates*/ true); } @@ -2552,7 +2909,10 @@ export function getCompletionEntriesFromSymbols( } // Filter out variables from their own initializers // `const a = /* no 'a' here */` - if (tryCast(variableOrParameterDeclaration, isVariableDeclaration) && symbol.valueDeclaration === variableOrParameterDeclaration) { + if ( + tryCast(variableOrParameterDeclaration, isVariableDeclaration) + && symbol.valueDeclaration === variableOrParameterDeclaration + ) { return false; } @@ -2560,15 +2920,22 @@ export function getCompletionEntriesFromSymbols( // `function f(a = /* no 'a' and 'b' here */, b) { }` or // `function f(a: T) { }` const symbolDeclaration = symbol.valueDeclaration ?? symbol.declarations?.[0]; - if (variableOrParameterDeclaration && symbolDeclaration && ( - (isTypeParameterDeclaration(variableOrParameterDeclaration) && isTypeParameterDeclaration(symbolDeclaration)) || - (isParameter(variableOrParameterDeclaration) && isParameter(symbolDeclaration)) - )) { + if ( + variableOrParameterDeclaration && symbolDeclaration && ( + (isTypeParameterDeclaration(variableOrParameterDeclaration) + && isTypeParameterDeclaration(symbolDeclaration)) + || (isParameter(variableOrParameterDeclaration) && isParameter(symbolDeclaration)) + ) + ) { const symbolDeclarationPos = symbolDeclaration.pos; - const parameters = isParameter(variableOrParameterDeclaration) ? variableOrParameterDeclaration.parent.parameters : - isInferTypeNode(variableOrParameterDeclaration.parent) ? undefined : - variableOrParameterDeclaration.parent.typeParameters; - if (symbolDeclarationPos >= variableOrParameterDeclaration.pos && parameters && symbolDeclarationPos < parameters.end) { + const parameters = isParameter(variableOrParameterDeclaration) + ? variableOrParameterDeclaration.parent.parameters + : isInferTypeNode(variableOrParameterDeclaration.parent) ? undefined + : variableOrParameterDeclaration.parent.typeParameters; + if ( + symbolDeclarationPos >= variableOrParameterDeclaration.pos && parameters + && symbolDeclarationPos < parameters.end + ) { return false; } } @@ -2581,11 +2948,13 @@ export function getCompletionEntriesFromSymbols( const symbolOrigin = skipAlias(symbol, typeChecker); // We only want to filter out the global keywords // Auto Imports are not available for scripts so this conditional is always false - if (!!sourceFile.externalModuleIndicator + if ( + !!sourceFile.externalModuleIndicator && !compilerOptions.allowUmdGlobalAccess && symbolToSortTextMap[getSymbolId(symbol)] === SortText.GlobalsOrKeywords && (symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.AutoImportSuggestions - || symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.LocationPriority)) { + || symbolToSortTextMap[getSymbolId(symbolOrigin)] === SortText.LocationPriority) + ) { return false; } @@ -2631,7 +3000,7 @@ function getLabelStatementCompletions(node: Node): CompletionEntry[] { name, kindModifiers: ScriptElementKindModifier.none, kind: ScriptElementKind.label, - sortText: SortText.LocationPriority + sortText: SortText.LocationPriority, }); } } @@ -2658,7 +3027,13 @@ function getSymbolCompletionFromEntryId( entryId: CompletionEntryIdentifier, host: LanguageServiceHost, preferences: UserPreferences, -): SymbolCompletion | { type: "request", request: Request } | { type: "literal", literal: string | number | PseudoBigInt } | { type: "cases" } | { type: "none" } { +): + | SymbolCompletion + | { type: "request"; request: Request; } + | { type: "literal"; literal: string | number | PseudoBigInt; } + | { type: "cases"; } + | { type: "none"; } +{ if (entryId.source === CompletionSource.SwitchCases) { return { type: "cases" }; } @@ -2680,7 +3055,17 @@ function getSymbolCompletionFromEntryId( } const compilerOptions = program.getCompilerOptions(); - const completionData = getCompletionData(program, log, sourceFile, compilerOptions, position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, entryId, host, /*formatContext*/ undefined); + const completionData = getCompletionData( + program, + log, + sourceFile, + compilerOptions, + position, + { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, + entryId, + host, + /*formatContext*/ undefined, + ); if (!completionData) { return { type: "none" }; } @@ -2688,7 +3073,17 @@ function getSymbolCompletionFromEntryId( return { type: "request", request: completionData }; } - const { symbols, literals, location, completionKind, symbolToOriginInfoMap, contextToken, previousToken, isJsxInitializer, isTypeOnlyLocation } = completionData; + const { + symbols, + literals, + location, + completionKind, + symbolToOriginInfoMap, + contextToken, + previousToken, + isJsxInitializer, + isTypeOnlyLocation, + } = completionData; const literal = find(literals, l => completionNameForLiteral(sourceFile, preferences, l) === entryId.name); if (literal !== undefined) return { type: "literal", literal }; @@ -2699,13 +3094,30 @@ function getSymbolCompletionFromEntryId( // completion entry. return firstDefined(symbols, (symbol, index): SymbolCompletion | undefined => { const origin = symbolToOriginInfoMap[index]; - const info = getCompletionEntryDisplayNameForSymbol(symbol, getEmitScriptTarget(compilerOptions), origin, completionKind, completionData.isJsxIdentifierExpected); + const info = getCompletionEntryDisplayNameForSymbol( + symbol, + getEmitScriptTarget(compilerOptions), + origin, + completionKind, + completionData.isJsxIdentifierExpected, + ); return info && info.name === entryId.name && ( - entryId.source === CompletionSource.ClassMemberSnippet && symbol.flags & SymbolFlags.ClassMember - || entryId.source === CompletionSource.ObjectLiteralMethodSnippet && symbol.flags & (SymbolFlags.Property | SymbolFlags.Method) - || getSourceFromOrigin(origin) === entryId.source - || entryId.source === CompletionSource.ObjectLiteralMemberWithComma) - ? { type: "symbol" as const, symbol, location, origin, contextToken, previousToken, isJsxInitializer, isTypeOnlyLocation } + entryId.source === CompletionSource.ClassMemberSnippet && symbol.flags & SymbolFlags.ClassMember + || entryId.source === CompletionSource.ObjectLiteralMethodSnippet + && symbol.flags & (SymbolFlags.Property | SymbolFlags.Method) + || getSourceFromOrigin(origin) === entryId.source + || entryId.source === CompletionSource.ObjectLiteralMemberWithComma + ) + ? { + type: "symbol" as const, + symbol, + location, + origin, + contextToken, + previousToken, + isJsxInitializer, + isTypeOnlyLocation, + } : undefined; }) || { type: "none" }; } @@ -2735,11 +3147,29 @@ export function getCompletionEntryDetails( const { previousToken, contextToken } = getRelevantTokens(position, sourceFile); if (isInString(sourceFile, position, previousToken)) { - return StringCompletions.getStringLiteralCompletionDetails(name, sourceFile, position, previousToken, typeChecker, compilerOptions, host, cancellationToken, preferences); + return StringCompletions.getStringLiteralCompletionDetails( + name, + sourceFile, + position, + previousToken, + typeChecker, + compilerOptions, + host, + cancellationToken, + preferences, + ); } // Compute all the completion symbols again. - const symbolCompletion = getSymbolCompletionFromEntryId(program, log, sourceFile, position, entryId, host, preferences); + const symbolCompletion = getSymbolCompletionFromEntryId( + program, + log, + sourceFile, + position, + entryId, + host, + preferences, + ); switch (symbolCompletion.type) { case "request": { const { request } = symbolCompletion; @@ -2751,20 +3181,53 @@ export function getCompletionEntryDetails( case CompletionDataKind.JsDocParameterName: return JsDoc.getJSDocParameterNameCompletionDetails(name); case CompletionDataKind.Keywords: - return some(request.keywordCompletions, c => c.name === name) ? createSimpleDetails(name, ScriptElementKind.keyword, SymbolDisplayPartKind.keyword) : undefined; + return some(request.keywordCompletions, c => c.name === name) + ? createSimpleDetails(name, ScriptElementKind.keyword, SymbolDisplayPartKind.keyword) + : undefined; default: return Debug.assertNever(request); } } case "symbol": { const { symbol, location, contextToken, origin, previousToken } = symbolCompletion; - const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay(name, location, contextToken, origin, symbol, program, host, compilerOptions, sourceFile, position, previousToken, formatContext, preferences, data, source, cancellationToken); + const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay( + name, + location, + contextToken, + origin, + symbol, + program, + host, + compilerOptions, + sourceFile, + position, + previousToken, + formatContext, + preferences, + data, + source, + cancellationToken, + ); const symbolName = originIsComputedPropertyName(origin) ? origin.symbolName : symbol.name; - return createCompletionDetailsForSymbol(symbol, symbolName, typeChecker, sourceFile, location, cancellationToken, codeActions, sourceDisplay); // TODO: GH#18217 + return createCompletionDetailsForSymbol( + symbol, + symbolName, + typeChecker, + sourceFile, + location, + cancellationToken, + codeActions, + sourceDisplay, + ); // TODO: GH#18217 } case "literal": { const { literal } = symbolCompletion; - return createSimpleDetails(completionNameForLiteral(sourceFile, preferences, literal), ScriptElementKind.string, typeof literal === "string" ? SymbolDisplayPartKind.stringLiteral : SymbolDisplayPartKind.numericLiteral); + return createSimpleDetails( + completionNameForLiteral(sourceFile, preferences, literal), + ScriptElementKind.string, + typeof literal === "string" ? SymbolDisplayPartKind.stringLiteral + : SymbolDisplayPartKind.numericLiteral, + ); } case "cases": { const { entry, importAdder } = getExhaustiveCaseSnippets( @@ -2774,11 +3237,13 @@ export function getCompletionEntryDetails( program.getCompilerOptions(), host, program, - /*formatContext*/ undefined)!; + /*formatContext*/ undefined, + )!; if (importAdder.hasFixes()) { const changes = textChanges.ChangeTracker.with( { host, formatContext, preferences }, - importAdder.writeFixes); + importAdder.writeFixes, + ); return { name: entry.name, kind: ScriptElementKind.unknown, @@ -2801,27 +3266,67 @@ export function getCompletionEntryDetails( } case "none": // Didn't find a symbol with this name. See if we can find a keyword instead. - return allKeywordsCompletions().some(c => c.name === name) ? createSimpleDetails(name, ScriptElementKind.keyword, SymbolDisplayPartKind.keyword) : undefined; + return allKeywordsCompletions().some(c => c.name === name) + ? createSimpleDetails(name, ScriptElementKind.keyword, SymbolDisplayPartKind.keyword) : undefined; default: Debug.assertNever(symbolCompletion); } } -function createSimpleDetails(name: string, kind: ScriptElementKind, kind2: SymbolDisplayPartKind): CompletionEntryDetails { +function createSimpleDetails( + name: string, + kind: ScriptElementKind, + kind2: SymbolDisplayPartKind, +): CompletionEntryDetails { return createCompletionDetails(name, ScriptElementKindModifier.none, kind, [displayPart(name, kind2)]); } /** @internal */ -export function createCompletionDetailsForSymbol(symbol: Symbol, name: string, checker: TypeChecker, sourceFile: SourceFile, location: Node, cancellationToken: CancellationToken, codeActions?: CodeAction[], sourceDisplay?: SymbolDisplayPart[]): CompletionEntryDetails { - const { displayParts, documentation, symbolKind, tags } = - checker.runWithCancellationToken(cancellationToken, checker => - SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, sourceFile, location, location, SemanticMeaning.All) - ); - return createCompletionDetails(name, SymbolDisplay.getSymbolModifiers(checker, symbol), symbolKind, displayParts, documentation, tags, codeActions, sourceDisplay); +export function createCompletionDetailsForSymbol( + symbol: Symbol, + name: string, + checker: TypeChecker, + sourceFile: SourceFile, + location: Node, + cancellationToken: CancellationToken, + codeActions?: CodeAction[], + sourceDisplay?: SymbolDisplayPart[], +): CompletionEntryDetails { + const { displayParts, documentation, symbolKind, tags } = checker.runWithCancellationToken( + cancellationToken, + checker => + SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind( + checker, + symbol, + sourceFile, + location, + location, + SemanticMeaning.All, + ), + ); + return createCompletionDetails( + name, + SymbolDisplay.getSymbolModifiers(checker, symbol), + symbolKind, + displayParts, + documentation, + tags, + codeActions, + sourceDisplay, + ); } /** @internal */ -export function createCompletionDetails(name: string, kindModifiers: string, kind: ScriptElementKind, displayParts: SymbolDisplayPart[], documentation?: SymbolDisplayPart[], tags?: JSDocTagInfo[], codeActions?: CodeAction[], source?: SymbolDisplayPart[]): CompletionEntryDetails { +export function createCompletionDetails( + name: string, + kindModifiers: string, + kind: ScriptElementKind, + displayParts: SymbolDisplayPart[], + documentation?: SymbolDisplayPart[], + tags?: JSDocTagInfo[], + codeActions?: CodeAction[], + source?: SymbolDisplayPart[], +): CompletionEntryDetails { return { name, kindModifiers, kind, displayParts, documentation, tags, codeActions, source, sourceDisplay: source }; } @@ -2848,7 +3353,9 @@ function getCompletionEntryCodeActionsAndSourceDisplay( cancellationToken: CancellationToken, ): CodeActionsAndSourceDisplay { if (data?.moduleSpecifier) { - if (previousToken && getImportStatementCompletionInfo(contextToken || previousToken, sourceFile).replacementSpan) { + if ( + previousToken && getImportStatementCompletionInfo(contextToken || previousToken, sourceFile).replacementSpan + ) { // Import statement completion: 'import c|' return { codeActions: undefined, sourceDisplay: [textPart(data.moduleSpecifier)] }; } @@ -2865,7 +3372,8 @@ function getCompletionEntryCodeActionsAndSourceDisplay( location, position, contextToken, - formatContext)!; + formatContext, + )!; if (importAdder || eraseRange) { const changes = textChanges.ChangeTracker.with( { host, formatContext, preferences }, @@ -2876,7 +3384,8 @@ function getCompletionEntryCodeActionsAndSourceDisplay( if (eraseRange) { tracker.deleteRange(sourceFile, eraseRange); } - }); + }, + ); return { sourceDisplay: undefined, codeActions: [{ @@ -2894,7 +3403,8 @@ function getCompletionEntryCodeActionsAndSourceDisplay( program, host, formatContext, - preferences); + preferences, + ); Debug.assertIsDefined(codeAction, "Expected to have a code action for promoting type-only alias"); return { codeActions: [codeAction], sourceDisplay: undefined }; @@ -2903,7 +3413,7 @@ function getCompletionEntryCodeActionsAndSourceDisplay( if (source === CompletionSource.ObjectLiteralMemberWithComma && contextToken) { const changes = textChanges.ChangeTracker.with( { host, formatContext, preferences }, - tracker => tracker.insertText(sourceFile, contextToken.end, ",") + tracker => tracker.insertText(sourceFile, contextToken.end, ","), ); if (changes) { @@ -2911,7 +3421,10 @@ function getCompletionEntryCodeActionsAndSourceDisplay( sourceDisplay: undefined, codeActions: [{ changes, - description: diagnosticToString([Diagnostics.Add_missing_comma_for_object_member_completion_0, name]), + description: diagnosticToString([ + Diagnostics.Add_missing_comma_for_object_member_completion_0, + name, + ]), }], }; } @@ -2921,10 +3434,12 @@ function getCompletionEntryCodeActionsAndSourceDisplay( return { codeActions: undefined, sourceDisplay: undefined }; } - const checker = origin.isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() : program.getTypeChecker(); + const checker = origin.isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() + : program.getTypeChecker(); const { moduleSymbol } = origin; const targetSymbol = checker.getMergedSymbol(skipAlias(symbol.exportSymbol || symbol, checker)); - const isJsxOpeningTagName = contextToken?.kind === SyntaxKind.LessThanToken && isJsxOpeningLikeElement(contextToken.parent); + const isJsxOpeningTagName = contextToken?.kind === SyntaxKind.LessThanToken + && isJsxOpeningLikeElement(contextToken.parent); const { moduleSpecifier, codeAction } = codefix.getImportCompletionAction( targetSymbol, moduleSymbol, @@ -2937,7 +3452,8 @@ function getCompletionEntryCodeActionsAndSourceDisplay( formatContext, previousToken && isIdentifier(previousToken) ? previousToken.getStart(sourceFile) : position, preferences, - cancellationToken); + cancellationToken, + ); Debug.assert(!data?.moduleSpecifier || moduleSpecifier === data.moduleSpecifier); return { sourceDisplay: [textPart(moduleSpecifier)], codeActions: [codeAction] }; } @@ -2956,7 +3472,13 @@ export function getCompletionEntrySymbol( return completion.type === "symbol" ? completion.symbol : undefined; } -const enum CompletionDataKind { Data, JsDocTagName, JsDocTag, JsDocParameterName, Keywords } +const enum CompletionDataKind { + Data, + JsDocTagName, + JsDocTag, + JsDocParameterName, + Keywords, +} /** * true: after the `=` sign but no identifier has been typed yet. Else is the Identifier after the initializer. * @@ -2991,9 +3513,13 @@ interface CompletionData { readonly flags: CompletionInfoFlags; } type Request = - | { readonly kind: CompletionDataKind.JsDocTagName | CompletionDataKind.JsDocTag } - | { readonly kind: CompletionDataKind.JsDocParameterName, tag: JSDocParameterTag } - | { readonly kind: CompletionDataKind.Keywords, keywordCompletions: readonly CompletionEntry[], isNewIdentifierLocation: boolean }; + | { readonly kind: CompletionDataKind.JsDocTagName | CompletionDataKind.JsDocTag; } + | { readonly kind: CompletionDataKind.JsDocParameterName; tag: JSDocParameterTag; } + | { + readonly kind: CompletionDataKind.Keywords; + keywordCompletions: readonly CompletionEntry[]; + isNewIdentifierLocation: boolean; + }; /** @internal */ export const enum CompletionKind { @@ -3007,16 +3533,26 @@ export const enum CompletionKind { function getRecommendedCompletion(previousToken: Node, contextualType: Type, checker: TypeChecker): Symbol | undefined { // For a union, return the first one with a recommended completion. - return firstDefined(contextualType && (contextualType.isUnion() ? contextualType.types : [contextualType]), type => { - const symbol = type && type.symbol; - // Don't include make a recommended completion for an abstract class - return symbol && (symbol.flags & (SymbolFlags.EnumMember | SymbolFlags.Enum | SymbolFlags.Class) && !isAbstractConstructorSymbol(symbol)) - ? getFirstSymbolInChain(symbol, previousToken, checker) - : undefined; - }); + return firstDefined( + contextualType && (contextualType.isUnion() ? contextualType.types : [contextualType]), + type => { + const symbol = type && type.symbol; + // Don't include make a recommended completion for an abstract class + return symbol + && (symbol.flags & (SymbolFlags.EnumMember | SymbolFlags.Enum | SymbolFlags.Class) + && !isAbstractConstructorSymbol(symbol)) + ? getFirstSymbolInChain(symbol, previousToken, checker) + : undefined; + }, + ); } -function getContextualType(previousToken: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): Type | undefined { +function getContextualType( + previousToken: Node, + position: number, + sourceFile: SourceFile, + checker: TypeChecker, +): Type | undefined { const { parent } = previousToken; switch (previousToken.kind) { case SyntaxKind.Identifier: @@ -3038,23 +3574,36 @@ function getContextualType(previousToken: Node, position: number, sourceFile: So const caseClause = tryCast(parent, isCaseClause); return caseClause ? getSwitchedType(caseClause, checker) : undefined; case SyntaxKind.OpenBraceToken: - return isJsxExpression(parent) && !isJsxElement(parent.parent) && !isJsxFragment(parent.parent) ? checker.getContextualTypeForJsxAttribute(parent.parent) : undefined; + return isJsxExpression(parent) && !isJsxElement(parent.parent) && !isJsxFragment(parent.parent) + ? checker.getContextualTypeForJsxAttribute(parent.parent) : undefined; default: const argInfo = SignatureHelp.getArgumentInfoForCompletions(previousToken, position, sourceFile); - return argInfo ? + return argInfo // At `,`, treat this as the next argument after the comma. - checker.getContextualTypeForArgumentAtIndex(argInfo.invocation, argInfo.argumentIndex + (previousToken.kind === SyntaxKind.CommaToken ? 1 : 0)) : - isEqualityOperatorKind(previousToken.kind) && isBinaryExpression(parent) && isEqualityOperatorKind(parent.operatorToken.kind) ? - // completion at `x ===/**/` should be for the right side - checker.getTypeAtLocation(parent.left) : - checker.getContextualType(previousToken as Expression, ContextFlags.Completions) || checker.getContextualType(previousToken as Expression); + ? checker.getContextualTypeForArgumentAtIndex( + argInfo.invocation, + argInfo.argumentIndex + (previousToken.kind === SyntaxKind.CommaToken ? 1 : 0), + ) + : isEqualityOperatorKind(previousToken.kind) && isBinaryExpression(parent) + && isEqualityOperatorKind(parent.operatorToken.kind) + // completion at `x ===/**/` should be for the right side + ? checker.getTypeAtLocation(parent.left) + : checker.getContextualType(previousToken as Expression, ContextFlags.Completions) + || checker.getContextualType(previousToken as Expression); } } function getFirstSymbolInChain(symbol: Symbol, enclosingDeclaration: Node, checker: TypeChecker): Symbol | undefined { - const chain = checker.getAccessibleSymbolChain(symbol, enclosingDeclaration, /*meaning*/ SymbolFlags.All, /*useOnlyExternalAliasing*/ false); + const chain = checker.getAccessibleSymbolChain( + symbol, + enclosingDeclaration, + /*meaning*/ SymbolFlags.All, + /*useOnlyExternalAliasing*/ false, + ); if (chain) return first(chain); - return symbol.parent && (isModuleSymbol(symbol.parent) ? symbol : getFirstSymbolInChain(symbol.parent, enclosingDeclaration, checker)); + return symbol.parent + && (isModuleSymbol(symbol.parent) ? symbol + : getFirstSymbolInChain(symbol.parent, enclosingDeclaration, checker)); } function isModuleSymbol(symbol: Symbol): boolean { @@ -3129,15 +3678,20 @@ function getCompletionData( const typeExpression = tryGetTypeExpressionFromTag(tag); if (typeExpression) { currentToken = getTokenAtPosition(sourceFile, position); - if (!currentToken || - (!isDeclarationName(currentToken) && - (currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag || - (currentToken.parent as JSDocPropertyTag).name !== currentToken))) { + if ( + !currentToken + || (!isDeclarationName(currentToken) + && (currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag + || (currentToken.parent as JSDocPropertyTag).name !== currentToken)) + ) { // Use as type location if inside tag's type expression insideJsDocTagTypeExpression = isCurrentlyEditingNode(typeExpression); } } - if (!insideJsDocTagTypeExpression && isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) { + if ( + !insideJsDocTagTypeExpression && isJSDocParameterTag(tag) + && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end) + ) { return { kind: CompletionDataKind.JsDocParameterName, tag }; } } @@ -3188,7 +3742,10 @@ function getCompletionData( } keywordFilters = keywordFiltersFromSyntaxKind(importStatementCompletionInfo.keywordCompletion); } - if (importStatementCompletionInfo.replacementSpan && preferences.includeCompletionsForImportStatements && preferences.includeCompletionsWithInsertText) { + if ( + importStatementCompletionInfo.replacementSpan && preferences.includeCompletionsForImportStatements + && preferences.includeCompletionsWithInsertText + ) { // Import statement completions use `insertText`, and also require the `data` property of `CompletionEntryIdentifier` // added in TypeScript 4.3 to be sent back from the client during `getCompletionEntryDetails`. Since this feature // is not backward compatible with older clients, the language service defaults to disabling it, allowing newer clients @@ -3214,11 +3771,13 @@ function getCompletionData( propertyAccessToConvert = parent as PropertyAccessExpression; node = propertyAccessToConvert.expression; const leftmostAccessExpression = getLeftmostAccessExpression(propertyAccessToConvert); - if (nodeIsMissing(leftmostAccessExpression) || - ((isCallExpression(node) || isFunctionLike(node)) && - node.end === contextToken.pos && - node.getChildCount(sourceFile) && - last(node.getChildren(sourceFile)).kind !== SyntaxKind.CloseParenToken)) { + if ( + nodeIsMissing(leftmostAccessExpression) + || ((isCallExpression(node) || isFunctionLike(node)) + && node.end === contextToken.pos + && node.getChildCount(sourceFile) + && last(node.getChildren(sourceFile)).kind !== SyntaxKind.CloseParenToken) + ) { // This is likely dot from incorrectly parsed expression and user is starting to write spread // eg: Math.min(./**/) // const x = function (./**/) {} @@ -3258,7 +3817,10 @@ function getCompletionData( if (currentToken.parent === location) { switch (currentToken.kind) { case SyntaxKind.GreaterThanToken: - if (currentToken.parent.kind === SyntaxKind.JsxElement || currentToken.parent.kind === SyntaxKind.JsxOpeningElement) { + if ( + currentToken.parent.kind === SyntaxKind.JsxElement + || currentToken.parent.kind === SyntaxKind.JsxOpeningElement + ) { location = currentToken; } break; @@ -3301,15 +3863,21 @@ function getCompletionData( // `parent` will be `{true}` and `previousToken` will be `}` // Second case is for `
` // Second case must not match for `
` - if (previousToken.kind === SyntaxKind.CloseBraceToken || (previousToken.kind === SyntaxKind.Identifier && previousToken.parent.kind === SyntaxKind.JsxAttribute)) { + if ( + previousToken.kind === SyntaxKind.CloseBraceToken + || (previousToken.kind === SyntaxKind.Identifier + && previousToken.parent.kind === SyntaxKind.JsxAttribute) + ) { isJsxIdentifierExpected = true; } break; case SyntaxKind.JsxAttribute: // For `
`, `parent` will be JsxAttribute and `previousToken` will be its initializer - if ((parent as JsxAttribute).initializer === previousToken && - previousToken.end < position) { + if ( + (parent as JsxAttribute).initializer === previousToken + && previousToken.end < position + ) { isJsxIdentifierExpected = true; break; } @@ -3321,9 +3889,11 @@ function getCompletionData( isJsxIdentifierExpected = true; // For `
` we don't want to treat this as a jsx inializer, instead it's the attribute name. - if (parent !== previousToken.parent && - !(parent as JsxAttribute).initializer && - findChildOfKind(parent, SyntaxKind.EqualsToken, sourceFile)) { + if ( + parent !== previousToken.parent + && !(parent as JsxAttribute).initializer + && findChildOfKind(parent, SyntaxKind.EqualsToken, sourceFile) + ) { isJsxInitializer = previousToken as Identifier; } } @@ -3344,7 +3914,10 @@ function getCompletionData( const seenPropertySymbols = new Map(); const isTypeOnlyLocation = isTypeOnlyCompletion(); const getModuleSpecifierResolutionHost = memoizeOne((isFromPackageJson: boolean) => { - return createModuleSpecifierResolutionHost(isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, host); + return createModuleSpecifierResolutionHost( + isFromPackageJson ? host.getPackageJsonAutoImportProvider!()! : program, + host, + ); }); if (isRightOfDot || isRightOfQuestionDot) { @@ -3385,9 +3958,11 @@ function getCompletionData( const isLiteralExpected = !tryCast(previousToken, isStringLiteralLike) && !isJsxIdentifierExpected; const literals = !isLiteralExpected ? [] : mapDefined( contextualType && (contextualType.isUnion() ? contextualType.types : [contextualType]), - t => t.isLiteral() && !(t.flags & TypeFlags.EnumLiteral) ? t.value : undefined); + t => t.isLiteral() && !(t.flags & TypeFlags.EnumLiteral) ? t.value : undefined, + ); - const recommendedCompletion = previousToken && contextualType && getRecommendedCompletion(previousToken, contextualType, typeChecker); + const recommendedCompletion = previousToken && contextualType + && getRecommendedCompletion(previousToken, contextualType, typeChecker); return { kind: CompletionDataKind.Data, symbols, @@ -3444,7 +4019,8 @@ function getCompletionData( function tryGetTypeExpressionFromTag(tag: JSDocTag): JSDocTypeExpression | ExpressionWithTypeArguments | undefined { if (isTagWithTypeExpression(tag)) { const typeExpression = isJSDocTemplateTag(tag) ? tag.constraint : tag.typeExpression; - return typeExpression && typeExpression.kind === SyntaxKind.JSDocTypeExpression ? typeExpression : undefined; + return typeExpression && typeExpression.kind === SyntaxKind.JSDocTypeExpression ? typeExpression + : undefined; } if (isJSDocAugmentsTag(tag) || isJSDocImplementsTag(tag)) { return tag.class; @@ -3472,16 +4048,22 @@ function getCompletionData( // Extract module or enum members const exportedSymbols = typeChecker.getExportsOfModule(symbol); Debug.assertEachIsDefined(exportedSymbols, "getExportsOfModule() should all be defined"); - const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(isImportType ? node as ImportTypeNode : (node.parent as PropertyAccessExpression), symbol.name); - const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol, typeChecker); - const isValidAccess: (symbol: Symbol) => boolean = - isNamespaceName - // At `namespace N.M/**/`, if this is the only declaration of `M`, don't include `M` as a completion. - ? symbol => !!(symbol.flags & SymbolFlags.Namespace) && !symbol.declarations?.every(d => d.parent === node.parent) - : isRhsOfImportDeclaration ? - // Any kind is allowed when dotting off namespace in internal import equals declaration - symbol => isValidTypeAccess(symbol) || isValidValueAccess(symbol) : - isTypeLocation || insideJsDocTagTypeExpression ? isValidTypeAccess : isValidValueAccess; + const isValidValueAccess = (symbol: Symbol) => + typeChecker.isValidPropertyAccess( + isImportType ? node as ImportTypeNode : (node.parent as PropertyAccessExpression), + symbol.name, + ); + const isValidTypeAccess = (symbol: Symbol) => + symbolCanBeReferencedAtTypeLocation(symbol, typeChecker); + const isValidAccess: (symbol: Symbol) => boolean = isNamespaceName + // At `namespace N.M/**/`, if this is the only declaration of `M`, don't include `M` as a completion. + ? symbol => + !!(symbol.flags & SymbolFlags.Namespace) + && !symbol.declarations?.every(d => d.parent === node.parent) + : isRhsOfImportDeclaration + // Any kind is allowed when dotting off namespace in internal import equals declaration + ? symbol => isValidTypeAccess(symbol) || isValidValueAccess(symbol) + : isTypeLocation || insideJsDocTagTypeExpression ? isValidTypeAccess : isValidValueAccess; for (const exportedSymbol of exportedSymbols) { if (isValidAccess(exportedSymbol)) { symbols.push(exportedSymbol); @@ -3489,17 +4071,21 @@ function getCompletionData( } // If the module is merged with a value, we must get the type of the class and add its propertes (for inherited static methods). - if (!isTypeLocation && - !insideJsDocTagTypeExpression && - symbol.declarations && - symbol.declarations.some(d => d.kind !== SyntaxKind.SourceFile && d.kind !== SyntaxKind.ModuleDeclaration && d.kind !== SyntaxKind.EnumDeclaration)) { + if ( + !isTypeLocation + && !insideJsDocTagTypeExpression + && symbol.declarations + && symbol.declarations.some(d => + d.kind !== SyntaxKind.SourceFile && d.kind !== SyntaxKind.ModuleDeclaration + && d.kind !== SyntaxKind.EnumDeclaration + ) + ) { let type = typeChecker.getTypeOfSymbolAtLocation(symbol, node).getNonOptionalType(); let insertQuestionDot = false; if (type.isNullableType()) { - const canCorrectToQuestionDot = - isRightOfDot && - !isRightOfQuestionDot && - preferences.includeAutomaticOptionalChainCompletions !== false; + const canCorrectToQuestionDot = isRightOfDot + && !isRightOfQuestionDot + && preferences.includeAutomaticOptionalChainCompletions !== false; if (canCorrectToQuestionDot || isRightOfQuestionDot) { type = type.getNonNullableType(); @@ -3526,10 +4112,9 @@ function getCompletionData( if (!isTypeLocation) { let insertQuestionDot = false; if (type.isNullableType()) { - const canCorrectToQuestionDot = - isRightOfDot && - !isRightOfQuestionDot && - preferences.includeAutomaticOptionalChainCompletions !== false; + const canCorrectToQuestionDot = isRightOfDot + && !isRightOfQuestionDot + && preferences.includeAutomaticOptionalChainCompletions !== false; if (canCorrectToQuestionDot || isRightOfQuestionDot) { type = type.getNonNullableType(); @@ -3552,7 +4137,8 @@ function getCompletionData( isNewIdentifierLocation = true; } - const propertyAccess = node.kind === SyntaxKind.ImportType ? node as ImportTypeNode : node.parent as PropertyAccessExpression | QualifiedName; + const propertyAccess = node.kind === SyntaxKind.ImportType ? node as ImportTypeNode + : node.parent as PropertyAccessExpression | QualifiedName; if (inCheckedFile) { for (const symbol of type.getApparentProperties()) { if (typeChecker.isValidPropertyAccessForCompletions(propertyAccess, type, symbol)) { @@ -3566,7 +4152,12 @@ function getCompletionData( // each individual type has. This is because we're going to add all identifiers // anyways. So we might as well elevate the members that were at least part // of the individual types to a higher status since we know what they are. - symbols.push(...filter(getPropertiesForCompletion(type, typeChecker), s => typeChecker.isValidPropertyAccessForCompletions(propertyAccess, type, s))); + symbols.push( + ...filter( + getPropertiesForCompletion(type, typeChecker), + s => typeChecker.isValidPropertyAccessForCompletions(propertyAccess, type, s), + ), + ); } if (insertAwait && preferences.includeCompletionsWithInsertText) { @@ -3585,7 +4176,10 @@ function getCompletionData( // For a computed property with an accessible name like `Symbol.iterator`, // we'll add a completion for the *name* `Symbol` instead of for the property. // If this is e.g. [Symbol.iterator], add a completion for `Symbol`. - const computedPropertyName = firstDefined(symbol.declarations, decl => tryCast(getNameOfDeclaration(decl), isComputedPropertyName)); + const computedPropertyName = firstDefined( + symbol.declarations, + decl => tryCast(getNameOfDeclaration(decl), isComputedPropertyName), + ); if (computedPropertyName) { const leftMostName = getLeftMostName(computedPropertyName.expression); // The completion is for `Symbol`, not `iterator`. const nameSymbol = leftMostName && typeChecker.getSymbolAtLocation(leftMostName); @@ -3596,22 +4190,36 @@ function getCompletionData( const index = symbols.length; symbols.push(firstAccessibleSymbol); const moduleSymbol = firstAccessibleSymbol.parent; - if (!moduleSymbol || - !isExternalModuleSymbol(moduleSymbol) || - typeChecker.tryGetMemberInModuleExportsAndProperties(firstAccessibleSymbol.name, moduleSymbol) !== firstAccessibleSymbol + if ( + !moduleSymbol + || !isExternalModuleSymbol(moduleSymbol) + || typeChecker.tryGetMemberInModuleExportsAndProperties(firstAccessibleSymbol.name, moduleSymbol) + !== firstAccessibleSymbol ) { - symbolToOriginInfoMap[index] = { kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberNoExport) }; + symbolToOriginInfoMap[index] = { + kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberNoExport), + }; } else { - const fileName = isExternalModuleNameRelative(stripQuotes(moduleSymbol.name)) ? getSourceFileOfModule(moduleSymbol)?.fileName : undefined; - const { moduleSpecifier } = (importSpecifierResolver ||= codefix.createImportSpecifierResolver(sourceFile, program, host, preferences)).getModuleSpecifierForBestExportInfo([{ - exportKind: ExportKind.Named, - moduleFileName: fileName, - isFromPackageJson: false, - moduleSymbol, - symbol: firstAccessibleSymbol, - targetFlags: skipAlias(firstAccessibleSymbol, typeChecker).flags, - }], position, isValidTypeOnlyAliasUseSite(location)) || {}; + const fileName = isExternalModuleNameRelative(stripQuotes(moduleSymbol.name)) + ? getSourceFileOfModule(moduleSymbol)?.fileName : undefined; + const { moduleSpecifier } = (importSpecifierResolver ||= codefix.createImportSpecifierResolver( + sourceFile, + program, + host, + preferences, + )).getModuleSpecifierForBestExportInfo( + [{ + exportKind: ExportKind.Named, + moduleFileName: fileName, + isFromPackageJson: false, + moduleSymbol, + symbol: firstAccessibleSymbol, + targetFlags: skipAlias(firstAccessibleSymbol, typeChecker).flags, + }], + position, + isValidTypeOnlyAliasUseSite(location), + ) || {}; if (moduleSpecifier) { const origin: SymbolOriginInfoResolvedExport = { @@ -3651,7 +4259,9 @@ function getCompletionData( function addSymbolOriginInfo(symbol: Symbol) { if (preferences.includeCompletionsWithInsertText) { if (insertAwait && addToSeen(seenPropertySymbols, getSymbolId(symbol))) { - symbolToOriginInfoMap[symbols.length] = { kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.Promise) }; + symbolToOriginInfoMap[symbols.length] = { + kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.Promise), + }; } else if (insertQuestionDot) { symbolToOriginInfoMap[symbols.length] = { kind: SymbolOriginInfoKind.Nullable }; @@ -3698,8 +4308,15 @@ function getCompletionData( // Cursor is inside a JSX self-closing element or opening element const attrsType = jsxContainer && typeChecker.getContextualType(jsxContainer.attributes); if (!attrsType) return GlobalsSearch.Continue; - const completionsType = jsxContainer && typeChecker.getContextualType(jsxContainer.attributes, ContextFlags.Completions); - symbols = concatenate(symbols, filterJsxAttributes(getPropertiesForObjectExpression(attrsType, completionsType, jsxContainer.attributes, typeChecker), jsxContainer.attributes.properties)); + const completionsType = jsxContainer + && typeChecker.getContextualType(jsxContainer.attributes, ContextFlags.Completions); + symbols = concatenate( + symbols, + filterJsxAttributes( + getPropertiesForObjectExpression(attrsType, completionsType, jsxContainer.attributes, typeChecker), + jsxContainer.attributes.properties, + ), + ); setSortTextToOptionalMember(); completionKind = CompletionKind.MemberLike; isNewIdentifierLocation = false; @@ -3714,7 +4331,8 @@ function getCompletionData( } function getGlobalCompletions(): void { - keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All; + keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) + ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All; // Get all entities in the current scope. completionKind = CompletionKind.Global; @@ -3748,28 +4366,35 @@ function getCompletionData( // - 'contextToken' was adjusted to the token prior to 'previousToken' // because we were at the end of an identifier. // - 'previousToken' is defined. - const adjustedPosition = previousToken !== contextToken ? - previousToken.getStart() : - position; + const adjustedPosition = previousToken !== contextToken + ? previousToken.getStart() + : position; const scopeNode = getScopeNode(contextToken, adjustedPosition, sourceFile) || sourceFile; isInSnippetScope = isSnippetScope(scopeNode); - const symbolMeanings = (isTypeOnlyLocation ? SymbolFlags.None : SymbolFlags.Value) | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias; + const symbolMeanings = (isTypeOnlyLocation ? SymbolFlags.None : SymbolFlags.Value) | SymbolFlags.Type + | SymbolFlags.Namespace | SymbolFlags.Alias; const typeOnlyAliasNeedsPromotion = previousToken && !isValidTypeOnlyAliasUseSite(previousToken); symbols = concatenate(symbols, typeChecker.getSymbolsInScope(scopeNode, symbolMeanings)); Debug.assertEachIsDefined(symbols, "getSymbolsInScope() should all be defined"); for (let i = 0; i < symbols.length; i++) { const symbol = symbols[i]; - if (!typeChecker.isArgumentsSymbol(symbol) && - !some(symbol.declarations, d => d.getSourceFile() === sourceFile)) { + if ( + !typeChecker.isArgumentsSymbol(symbol) + && !some(symbol.declarations, d => d.getSourceFile() === sourceFile) + ) { symbolToSortTextMap[getSymbolId(symbol)] = SortText.GlobalsOrKeywords; } if (typeOnlyAliasNeedsPromotion && !(symbol.flags & SymbolFlags.Value)) { - const typeOnlyAliasDeclaration = symbol.declarations && find(symbol.declarations, isTypeOnlyImportDeclaration); + const typeOnlyAliasDeclaration = symbol.declarations + && find(symbol.declarations, isTypeOnlyImportDeclaration); if (typeOnlyAliasDeclaration) { - const origin: SymbolOriginInfoTypeOnlyImport = { kind: SymbolOriginInfoKind.TypeOnlyAlias, declaration: typeOnlyAliasDeclaration }; + const origin: SymbolOriginInfoTypeOnlyImport = { + kind: SymbolOriginInfoKind.TypeOnlyAlias, + declaration: typeOnlyAliasDeclaration, + }; symbolToOriginInfoMap[i] = origin; } } @@ -3777,7 +4402,11 @@ function getCompletionData( // Need to insert 'this.' before properties of `this` type, so only do that if `includeInsertTextCompletions` if (preferences.includeCompletionsWithInsertText && scopeNode.kind !== SyntaxKind.SourceFile) { - const thisType = typeChecker.tryGetThisTypeAt(scopeNode, /*includeGlobalThis*/ false, isClassLike(scopeNode.parent) ? scopeNode as ThisContainer : undefined); + const thisType = typeChecker.tryGetThisTypeAt( + scopeNode, + /*includeGlobalThis*/ false, + isClassLike(scopeNode.parent) ? scopeNode as ThisContainer : undefined, + ); if (thisType && !isProbablyGlobalType(thisType, sourceFile, typeChecker)) { for (const symbol of getPropertiesForCompletion(thisType, typeChecker)) { symbolToOriginInfoMap[symbols.length] = { kind: SymbolOriginInfoKind.ThisType }; @@ -3824,17 +4453,18 @@ function getCompletionData( function isTypeOnlyCompletion(): boolean { return insideJsDocTagTypeExpression || !!importStatementCompletion && isTypeOnlyImportOrExportDeclaration(location.parent) - || !isContextTokenValueLocation(contextToken) && - (isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker) - || isPartOfTypeNode(location) - || isContextTokenTypeLocation(contextToken)); + || !isContextTokenValueLocation(contextToken) + && (isPossiblyTypeArgumentPosition(contextToken, sourceFile, typeChecker) + || isPartOfTypeNode(location) + || isContextTokenTypeLocation(contextToken)); } function isContextTokenValueLocation(contextToken: Node) { - return contextToken && - ((contextToken.kind === SyntaxKind.TypeOfKeyword && - (contextToken.parent.kind === SyntaxKind.TypeQuery || isTypeOfExpression(contextToken.parent))) || - (contextToken.kind === SyntaxKind.AssertsKeyword && contextToken.parent.kind === SyntaxKind.TypePredicate)); + return contextToken + && ((contextToken.kind === SyntaxKind.TypeOfKeyword + && (contextToken.parent.kind === SyntaxKind.TypeQuery || isTypeOfExpression(contextToken.parent))) + || (contextToken.kind === SyntaxKind.AssertsKeyword + && contextToken.parent.kind === SyntaxKind.TypePredicate)); } function isContextTokenTypeLocation(contextToken: Node): boolean { @@ -3842,11 +4472,11 @@ function getCompletionData( const parentKind = contextToken.parent.kind; switch (contextToken.kind) { case SyntaxKind.ColonToken: - return parentKind === SyntaxKind.PropertyDeclaration || - parentKind === SyntaxKind.PropertySignature || - parentKind === SyntaxKind.Parameter || - parentKind === SyntaxKind.VariableDeclaration || - isFunctionLikeKind(parentKind); + return parentKind === SyntaxKind.PropertyDeclaration + || parentKind === SyntaxKind.PropertySignature + || parentKind === SyntaxKind.Parameter + || parentKind === SyntaxKind.VariableDeclaration + || isFunctionLikeKind(parentKind); case SyntaxKind.EqualsToken: return parentKind === SyntaxKind.TypeAliasDeclaration; @@ -3855,8 +4485,8 @@ function getCompletionData( return parentKind === SyntaxKind.AsExpression; case SyntaxKind.LessThanToken: - return parentKind === SyntaxKind.TypeReference || - parentKind === SyntaxKind.TypeAssertionExpression; + return parentKind === SyntaxKind.TypeReference + || parentKind === SyntaxKind.TypeAssertionExpression; case SyntaxKind.ExtendsKeyword: return parentKind === SyntaxKind.TypeParameter; @@ -3871,7 +4501,10 @@ function getCompletionData( /** Mutates `symbols`, `symbolToOriginInfoMap`, and `symbolToSortTextMap` */ function collectAutoImports() { if (!shouldOfferImportCompletions()) return; - Debug.assert(!detailsEntryId?.data, "Should not run 'collectAutoImports' when faster path is available via `data`"); + Debug.assert( + !detailsEntryId?.data, + "Should not run 'collectAutoImports' when faster path is available via `data`", + ); if (detailsEntryId && !detailsEntryId.source) { // Asking for completion details for an item that is not an auto-import return; @@ -3882,15 +4515,15 @@ function getCompletionData( const isAfterTypeOnlyImportSpecifierModifier = previousToken === contextToken && importStatementCompletion; - const lowerCaseTokenText = - isAfterTypeOnlyImportSpecifierModifier ? "" : - previousToken && isIdentifier(previousToken) ? previousToken.text.toLowerCase() : - ""; + const lowerCaseTokenText = isAfterTypeOnlyImportSpecifierModifier ? "" + : previousToken && isIdentifier(previousToken) ? previousToken.text.toLowerCase() + : ""; const moduleSpecifierCache = host.getModuleSpecifierCache?.(); const exportInfo = getExportInfoMap(sourceFile, host, program, preferences, cancellationToken); const packageJsonAutoImportProvider = host.getPackageJsonAutoImportProvider?.(); - const packageJsonFilter = detailsEntryId ? undefined : createPackageJsonImportFilter(sourceFile, preferences, host); + const packageJsonFilter = detailsEntryId ? undefined + : createPackageJsonImportFilter(sourceFile, preferences, host); resolvingModuleSpecifiers( "collectAutoImports", host, @@ -3905,19 +4538,30 @@ function getCompletionData( sourceFile.path, /*preferCapitalized*/ isRightOfOpenTag, (symbolName, targetFlags) => { - if (!isIdentifierText(symbolName, getEmitScriptTarget(host.getCompilationSettings()))) return false; + if (!isIdentifierText(symbolName, getEmitScriptTarget(host.getCompilationSettings()))) { + return false; + } if (!detailsEntryId && isStringANonContextualKeyword(symbolName)) return false; - if (!isTypeOnlyLocation && !importStatementCompletion && !(targetFlags & SymbolFlags.Value)) return false; - if (isTypeOnlyLocation && !(targetFlags & (SymbolFlags.Module | SymbolFlags.Type))) return false; + if (!isTypeOnlyLocation && !importStatementCompletion && !(targetFlags & SymbolFlags.Value)) { + return false; + } + if (isTypeOnlyLocation && !(targetFlags & (SymbolFlags.Module | SymbolFlags.Type))) { + return false; + } // Do not try to auto-import something with a lowercase first letter for a JSX tag const firstChar = symbolName.charCodeAt(0); - if (isRightOfOpenTag && (firstChar < CharacterCodes.A || firstChar > CharacterCodes.Z)) return false; + if (isRightOfOpenTag && (firstChar < CharacterCodes.A || firstChar > CharacterCodes.Z)) { + return false; + } if (detailsEntryId) return true; return charactersFuzzyMatchInString(symbolName, lowerCaseTokenText); }, (info, symbolName, isFromAmbientModule, exportMapKey) => { - if (detailsEntryId && !some(info, i => detailsEntryId.source === stripQuotes(i.moduleSymbol.name))) { + if ( + detailsEntryId + && !some(info, i => detailsEntryId.source === stripQuotes(i.moduleSymbol.name)) + ) { return; } @@ -3950,37 +4594,45 @@ function getCompletionData( } const isDefaultExport = exportInfo.exportKind === ExportKind.Default; - const symbol = isDefaultExport && getLocalSymbolForExportDefault(exportInfo.symbol) || exportInfo.symbol; + const symbol = isDefaultExport && getLocalSymbolForExportDefault(exportInfo.symbol) + || exportInfo.symbol; pushAutoImportSymbol(symbol, { kind: moduleSpecifier ? SymbolOriginInfoKind.ResolvedExport : SymbolOriginInfoKind.Export, moduleSpecifier, symbolName, exportMapKey, - exportName: exportInfo.exportKind === ExportKind.ExportEquals ? InternalSymbolName.ExportEquals : exportInfo.symbol.name, + exportName: exportInfo.exportKind === ExportKind.ExportEquals + ? InternalSymbolName.ExportEquals : exportInfo.symbol.name, fileName: exportInfo.moduleFileName, isDefaultExport, moduleSymbol: exportInfo.moduleSymbol, isFromPackageJson: exportInfo.isFromPackageJson, }); - } + }, ); hasUnresolvedAutoImports = context.skippedAny(); flags |= context.resolvedAny() ? CompletionInfoFlags.ResolvedModuleSpecifiers : 0; flags |= context.resolvedBeyondLimit() ? CompletionInfoFlags.ResolvedModuleSpecifiersBeyondLimit : 0; - } + }, ); function isImportableExportInfo(info: SymbolExportInfo) { const moduleFile = tryCast(info.moduleSymbol.valueDeclaration, isSourceFile); if (!moduleFile) { const moduleName = stripQuotes(info.moduleSymbol.name); - if (JsTyping.nodeCoreModules.has(moduleName) && startsWith(moduleName, "node:") !== shouldUseUriStyleNodeCoreModules(sourceFile, program)) { + if ( + JsTyping.nodeCoreModules.has(moduleName) + && startsWith(moduleName, "node:") !== shouldUseUriStyleNodeCoreModules(sourceFile, program) + ) { return false; } return packageJsonFilter - ? packageJsonFilter.allowsImportingAmbientModule(info.moduleSymbol, getModuleSpecifierResolutionHost(info.isFromPackageJson)) + ? packageJsonFilter.allowsImportingAmbientModule( + info.moduleSymbol, + getModuleSpecifierResolutionHost(info.isFromPackageJson), + ) : true; } return isImportableFile( @@ -3990,7 +4642,8 @@ function getCompletionData( preferences, packageJsonFilter, getModuleSpecifierResolutionHost(info.isFromPackageJson), - moduleSpecifierCache); + moduleSpecifierCache, + ); } } @@ -4001,7 +4654,8 @@ function getCompletionData( return; } symbolToOriginInfoMap[symbols.length] = origin; - symbolToSortTextMap[symbolId] = importStatementCompletion ? SortText.LocationPriority : SortText.AutoImportSuggestions; + symbolToSortTextMap[symbolId] = importStatementCompletion ? SortText.LocationPriority + : SortText.AutoImportSuggestions; symbols.push(symbol); } @@ -4020,7 +4674,8 @@ function getCompletionData( getEmitScriptTarget(compilerOptions), /*origin*/ undefined, CompletionKind.ObjectPropertyDeclaration, - /*jsxIdentifierExpected*/ false); + /*jsxIdentifierExpected*/ false, + ); if (!displayName) { return; } @@ -4033,11 +4688,15 @@ function getCompletionData( host, compilerOptions, preferences, - formatContext); + formatContext, + ); if (!entryProps) { return; } - const origin: SymbolOriginInfoObjectLiteralMethod = { kind: SymbolOriginInfoKind.ObjectLiteralMethod, ...entryProps }; + const origin: SymbolOriginInfoObjectLiteralMethod = { + kind: SymbolOriginInfoKind.ObjectLiteralMethod, + ...entryProps, + }; flags |= CompletionInfoFlags.MayIncludeMethodSnippets; symbolToOriginInfoMap[symbols.length] = origin; symbols.push(member); @@ -4074,11 +4733,11 @@ function getCompletionData( function isCompletionListBlocker(contextToken: Node): boolean { const start = timestamp(); - const result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) || - isSolelyIdentifierDefinitionLocation(contextToken) || - isDotOfNumericLiteral(contextToken) || - isInJsxText(contextToken) || - isBigIntLiteral(contextToken); + const result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) + || isSolelyIdentifierDefinitionLocation(contextToken) + || isDotOfNumericLiteral(contextToken) + || isInJsxText(contextToken) + || isBigIntLiteral(contextToken); log("getCompletionsAtPosition: isCompletionListBlocker: " + (timestamp() - start)); return result; } @@ -4094,7 +4753,11 @@ function getCompletionData( // - contextToken: GreaterThanToken (before cursor) // - location: JsxSelfClosingElement or JsxOpeningElement // - contextToken.parent === location - if (location === contextToken.parent && (location.kind === SyntaxKind.JsxOpeningElement || location.kind === SyntaxKind.JsxSelfClosingElement)) { + if ( + location === contextToken.parent + && (location.kind === SyntaxKind.JsxOpeningElement + || location.kind === SyntaxKind.JsxSelfClosingElement) + ) { return false; } @@ -4106,7 +4769,10 @@ function getCompletionData( return location.parent.kind !== SyntaxKind.JsxOpeningElement; } - if (contextToken.parent.kind === SyntaxKind.JsxClosingElement || contextToken.parent.kind === SyntaxKind.JsxSelfClosingElement) { + if ( + contextToken.parent.kind === SyntaxKind.JsxClosingElement + || contextToken.parent.kind === SyntaxKind.JsxSelfClosingElement + ) { return !!contextToken.parent.parent && contextToken.parent.parent.kind === SyntaxKind.JsxElement; } } @@ -4118,6 +4784,7 @@ function getCompletionData( const containingNodeKind = contextToken.parent.kind; const tokenKind = keywordForNode(contextToken); // Previous token may have been a keyword that was converted to an identifier. + // dprint-ignore switch (tokenKind) { case SyntaxKind.CommaToken: return containingNodeKind === SyntaxKind.CallExpression // func( a, | @@ -4184,15 +4851,18 @@ function getCompletionData( // 2. at the end position of an unterminated token. // 3. at the end of a regular expression (due to trailing flags like '/foo/g'). return (isRegularExpressionLiteral(contextToken) || isStringTextContainingNode(contextToken)) && ( - rangeContainsPositionExclusive(contextToken, position) || - position === contextToken.end && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken))); + rangeContainsPositionExclusive(contextToken, position) + || position === contextToken.end + && (!!contextToken.isUnterminated || isRegularExpressionLiteral(contextToken)) + ); } function tryGetObjectTypeLiteralInTypeArgumentCompletionSymbols(): GlobalsSearch | undefined { const typeLiteralNode = tryGetTypeLiteralNode(contextToken); if (!typeLiteralNode) return GlobalsSearch.Continue; - const intersectionTypeNode = isIntersectionTypeNode(typeLiteralNode.parent) ? typeLiteralNode.parent : undefined; + const intersectionTypeNode = isIntersectionTypeNode(typeLiteralNode.parent) ? typeLiteralNode.parent + : undefined; const containerTypeNode = intersectionTypeNode || typeLiteralNode; const containerExpectedType = getConstraintOfTypeArgumentProperty(containerTypeNode, typeChecker); @@ -4246,7 +4916,12 @@ function getCompletionData( const hasStringIndexType = (completionsType || instantiatedType).getStringIndexType(); const hasNumberIndextype = (completionsType || instantiatedType).getNumberIndexType(); isNewIdentifierLocation = !!hasStringIndexType || !!hasNumberIndextype; - typeMembers = getPropertiesForObjectExpression(instantiatedType, completionsType, objectLikeContainer, typeChecker); + typeMembers = getPropertiesForObjectExpression( + instantiatedType, + completionsType, + objectLikeContainer, + typeChecker, + ); existingMembers = objectLikeContainer.properties; if (typeMembers.length === 0) { @@ -4270,20 +4945,31 @@ function getCompletionData( // through type declaration or inference. // Also proceed if rootDeclaration is a parameter and if its containing function expression/arrow function is contextually typed - // type of parameter will flow in from the contextual type of the function - let canGetType = hasInitializer(rootDeclaration) || !!getEffectiveTypeAnnotationNode(rootDeclaration) || rootDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement; + let canGetType = hasInitializer(rootDeclaration) || !!getEffectiveTypeAnnotationNode(rootDeclaration) + || rootDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement; if (!canGetType && rootDeclaration.kind === SyntaxKind.Parameter) { if (isExpression(rootDeclaration.parent)) { canGetType = !!typeChecker.getContextualType(rootDeclaration.parent as Expression); } - else if (rootDeclaration.parent.kind === SyntaxKind.MethodDeclaration || rootDeclaration.parent.kind === SyntaxKind.SetAccessor) { - canGetType = isExpression(rootDeclaration.parent.parent) && !!typeChecker.getContextualType(rootDeclaration.parent.parent as Expression); + else if ( + rootDeclaration.parent.kind === SyntaxKind.MethodDeclaration + || rootDeclaration.parent.kind === SyntaxKind.SetAccessor + ) { + canGetType = isExpression(rootDeclaration.parent.parent) + && !!typeChecker.getContextualType(rootDeclaration.parent.parent as Expression); } } if (canGetType) { const typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer); if (!typeForObject) return GlobalsSearch.Fail; typeMembers = typeChecker.getPropertiesOfType(typeForObject).filter(propertySymbol => { - return typeChecker.isPropertyAccessible(objectLikeContainer, /*isSuper*/ false, /*isWrite*/ false, typeForObject, propertySymbol); + return typeChecker.isPropertyAccessible( + objectLikeContainer, + /*isSuper*/ false, + /*isWrite*/ false, + typeForObject, + propertySymbol, + ); }); existingMembers = objectLikeContainer.elements; } @@ -4294,9 +4980,11 @@ function getCompletionData( const filteredMembers = filterObjectMembersList(typeMembers, Debug.checkDefined(existingMembers)); symbols = concatenate(symbols, filteredMembers); setSortTextToOptionalMember(); - if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression + if ( + objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression && preferences.includeCompletionsWithObjectLiteralMethodSnippets - && preferences.includeCompletionsWithInsertText) { + && preferences.includeCompletionsWithInsertText + ) { transformObjectLiteralMembersSortText(symbolsStartIndex); collectObjectLiteralMethodSymbols(filteredMembers, objectLikeContainer); } @@ -4323,8 +5011,10 @@ function getCompletionData( // `import { |` or `import { a as 0, | }` or `import { type | }` const namedImportsOrExports = - contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken ? tryCast(contextToken.parent, isNamedImportsOrExports) : - isTypeKeywordTokenOrIdentifier(contextToken) ? tryCast(contextToken.parent.parent, isNamedImportsOrExports) : undefined; + contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken + ? tryCast(contextToken.parent, isNamedImportsOrExports) + : isTypeKeywordTokenOrIdentifier(contextToken) + ? tryCast(contextToken.parent.parent, isNamedImportsOrExports) : undefined; if (!namedImportsOrExports) return GlobalsSearch.Continue; @@ -4334,7 +5024,8 @@ function getCompletionData( } // try to show exported member for imported/re-exported module - const { moduleSpecifier } = namedImportsOrExports.kind === SyntaxKind.NamedImports ? namedImportsOrExports.parent.parent : namedImportsOrExports.parent; + const { moduleSpecifier } = namedImportsOrExports.kind === SyntaxKind.NamedImports + ? namedImportsOrExports.parent.parent : namedImportsOrExports.parent; if (!moduleSpecifier) { isNewIdentifierLocation = true; return namedImportsOrExports.kind === SyntaxKind.NamedImports ? GlobalsSearch.Fail : GlobalsSearch.Continue; @@ -4348,8 +5039,14 @@ function getCompletionData( completionKind = CompletionKind.MemberLike; isNewIdentifierLocation = false; const exports = typeChecker.getExportsAndPropertiesOfModule(moduleSpecifierSymbol); - const existing = new Set((namedImportsOrExports.elements as NodeArray).filter(n => !isCurrentlyEditingNode(n)).map(n => (n.propertyName || n.name).escapedText)); - const uniques = exports.filter(e => e.escapedName !== InternalSymbolName.Default && !existing.has(e.escapedName)); + const existing = new Set( + (namedImportsOrExports.elements as NodeArray).filter(n => + !isCurrentlyEditingNode(n) + ).map(n => (n.propertyName || n.name).escapedText), + ); + const uniques = exports.filter(e => + e.escapedName !== InternalSymbolName.Default && !existing.has(e.escapedName) + ); symbols = concatenate(symbols, uniques); if (!uniques.length) { // If there's nothing else to import, don't offer `type` either @@ -4368,7 +5065,8 @@ function getCompletionData( * preventing this function from running. */ function tryGetLocalNamedExportCompletionSymbols(): GlobalsSearch { - const namedExports = contextToken && (contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken) + const namedExports = contextToken + && (contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken) ? tryCast(contextToken.parent, isNamedExports) : undefined; @@ -4400,14 +5098,17 @@ function getCompletionData( completionKind = CompletionKind.MemberLike; // Declaring new property/method/accessor isNewIdentifierLocation = true; - keywordFilters = contextToken.kind === SyntaxKind.AsteriskToken ? KeywordCompletionFilters.None : - isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords; + keywordFilters = contextToken.kind === SyntaxKind.AsteriskToken ? KeywordCompletionFilters.None + : isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords + : KeywordCompletionFilters.InterfaceElementKeywords; // If you're in an interface you don't want to repeat things from super-interface. So just stop here. if (!isClassLike(decl)) return GlobalsSearch.Success; - const classElement = contextToken.kind === SyntaxKind.SemicolonToken ? contextToken.parent.parent : contextToken.parent; - let classElementModifierFlags = isClassElement(classElement) ? getEffectiveModifierFlags(classElement) : ModifierFlags.None; + const classElement = contextToken.kind === SyntaxKind.SemicolonToken ? contextToken.parent.parent + : contextToken.parent; + let classElementModifierFlags = isClassElement(classElement) ? getEffectiveModifierFlags(classElement) + : ModifierFlags.None; // If this is context token is not something we are editing now, consider if this would lead to be modifier if (contextToken.kind === SyntaxKind.Identifier && !isCurrentlyEditingNode(contextToken)) { switch (contextToken.getText()) { @@ -4429,17 +5130,25 @@ function getCompletionData( // No member list for private methods if (!(classElementModifierFlags & ModifierFlags.Private)) { // List of property symbols of base type that are not private and already implemented - const baseTypeNodes = isClassLike(decl) && classElementModifierFlags & ModifierFlags.Override ? singleElementArray(getEffectiveBaseTypeNode(decl)) : getAllSuperTypeNodes(decl); + const baseTypeNodes = isClassLike(decl) && classElementModifierFlags & ModifierFlags.Override + ? singleElementArray(getEffectiveBaseTypeNode(decl)) : getAllSuperTypeNodes(decl); const baseSymbols = flatMap(baseTypeNodes, baseTypeNode => { const type = typeChecker.getTypeAtLocation(baseTypeNode); - return classElementModifierFlags & ModifierFlags.Static ? - type?.symbol && typeChecker.getPropertiesOfType(typeChecker.getTypeOfSymbolAtLocation(type.symbol, decl)) : - type && typeChecker.getPropertiesOfType(type); + return classElementModifierFlags & ModifierFlags.Static + ? type?.symbol + && typeChecker.getPropertiesOfType(typeChecker.getTypeOfSymbolAtLocation(type.symbol, decl)) + : type && typeChecker.getPropertiesOfType(type); }); - symbols = concatenate(symbols, filterClassMembersList(baseSymbols, decl.members, classElementModifierFlags)); + symbols = concatenate( + symbols, + filterClassMembersList(baseSymbols, decl.members, classElementModifierFlags), + ); forEach(symbols, (symbol, index) => { const declaration = symbol?.valueDeclaration; - if (declaration && isClassElement(declaration) && declaration.name && isComputedPropertyName(declaration.name)) { + if ( + declaration && isClassElement(declaration) && declaration.name + && isComputedPropertyName(declaration.name) + ) { const origin: SymbolOriginInfoComputedPropertyName = { kind: SymbolOriginInfoKind.ComputedPropertyName, symbolName: typeChecker.symbolToString(symbol), @@ -4506,10 +5215,21 @@ function getCompletionData( case SyntaxKind.JsxAttributes: case SyntaxKind.JsxAttribute: case SyntaxKind.JsxSpreadAttribute: - if (parent && (parent.kind === SyntaxKind.JsxSelfClosingElement || parent.kind === SyntaxKind.JsxOpeningElement)) { + if ( + parent + && (parent.kind === SyntaxKind.JsxSelfClosingElement + || parent.kind === SyntaxKind.JsxOpeningElement) + ) { if (contextToken.kind === SyntaxKind.GreaterThanToken) { - const precedingToken = findPrecedingToken(contextToken.pos, sourceFile, /*startNode*/ undefined); - if (!(parent as JsxOpeningLikeElement).typeArguments || (precedingToken && precedingToken.kind === SyntaxKind.SlashToken)) break; + const precedingToken = findPrecedingToken( + contextToken.pos, + sourceFile, + /*startNode*/ undefined, + ); + if ( + !(parent as JsxOpeningLikeElement).typeArguments + || (precedingToken && precedingToken.kind === SyntaxKind.SlashToken) + ) break; } return parent as JsxOpeningLikeElement; } @@ -4526,7 +5246,11 @@ function getCompletionData( // its parent is a JsxExpression, whose parent is a JsxAttribute, // whose parent is a JsxOpeningLikeElement case SyntaxKind.StringLiteral: - if (parent && ((parent.kind === SyntaxKind.JsxAttribute) || (parent.kind === SyntaxKind.JsxSpreadAttribute))) { + if ( + parent + && ((parent.kind === SyntaxKind.JsxAttribute) + || (parent.kind === SyntaxKind.JsxSpreadAttribute)) + ) { // Currently we parse JsxOpeningLikeElement as: // JsxOpeningLikeElement // attributes: JsxAttributes @@ -4537,9 +5261,11 @@ function getCompletionData( break; case SyntaxKind.CloseBraceToken: - if (parent && - parent.kind === SyntaxKind.JsxExpression && - parent.parent && parent.parent.kind === SyntaxKind.JsxAttribute) { + if ( + parent + && parent.kind === SyntaxKind.JsxExpression + && parent.parent && parent.parent.kind === SyntaxKind.JsxAttribute + ) { // Currently we parse JsxOpeningLikeElement as: // JsxOpeningLikeElement // attributes: JsxAttributes @@ -4568,6 +5294,7 @@ function getCompletionData( function isSolelyIdentifierDefinitionLocation(contextToken: Node): boolean { const parent = contextToken.parent; const containingNodeKind = parent.kind; + // dprint-ignore switch (contextToken.kind) { case SyntaxKind.CommaToken: return containingNodeKind === SyntaxKind.VariableDeclaration || @@ -4668,9 +5395,11 @@ function getCompletionData( // - its modifier of the constructor parameter or // - its name of the parameter and not being edited // eg. constructor(a |<- this shouldnt show completion - if (!isIdentifier(contextToken) || - isParameterPropertyModifier(keywordForNode(contextToken)) || - isCurrentlyEditingNode(contextToken)) { + if ( + !isIdentifier(contextToken) + || isParameterPropertyModifier(keywordForNode(contextToken)) + || isCurrentlyEditingNode(contextToken) + ) { return false; } } @@ -4698,26 +5427,33 @@ function getCompletionData( // If we are inside a class declaration, and `constructor` is totally not present, // but we request a completion manually at a whitespace... const ancestorClassLike = findAncestor(contextToken.parent, isClassLike); - if (ancestorClassLike && contextToken === previousToken && isPreviousPropertyDeclarationTerminated(contextToken, position)) { + if ( + ancestorClassLike && contextToken === previousToken + && isPreviousPropertyDeclarationTerminated(contextToken, position) + ) { return false; // Don't block completions. } const ancestorPropertyDeclaraion = getAncestor(contextToken.parent, SyntaxKind.PropertyDeclaration); // If we are inside a class declaration and typing `constructor` after property declaration... - if (ancestorPropertyDeclaraion + if ( + ancestorPropertyDeclaraion && contextToken !== previousToken && isClassLike(previousToken.parent.parent) // And the cursor is at the token... - && position <= previousToken.end) { + && position <= previousToken.end + ) { // If we are sure that the previous property declaration is terminated according to newline or semicolon... if (isPreviousPropertyDeclarationTerminated(contextToken, previousToken.end)) { return false; // Don't block completions. } - else if (contextToken.kind !== SyntaxKind.EqualsToken + else if ( + contextToken.kind !== SyntaxKind.EqualsToken // Should not block: `class C { blah = c/**/ }` // But should block: `class C { blah = somewhat c/**/ }` and `class C { blah: SomeType c/**/ }` && (isInitializedProperty(ancestorPropertyDeclaraion as PropertyDeclaration) - || hasType(ancestorPropertyDeclaraion))) { + || hasType(ancestorPropertyDeclaraion)) + ) { return true; } } @@ -4727,13 +5463,15 @@ function getCompletionData( && !isJsxAttribute(contextToken.parent) // Don't block completions if we're in `class C /**/`, `interface I /**/` or `` , because we're *past* the end of the identifier and might want to complete `extends`. // If `contextToken !== previousToken`, this is `class C ex/**/`, `interface I ex/**/` or ``. - && !((isClassLike(contextToken.parent) || isInterfaceDeclaration(contextToken.parent) || isTypeParameterDeclaration(contextToken.parent)) && (contextToken !== previousToken || position > previousToken.end)); + && !((isClassLike(contextToken.parent) || isInterfaceDeclaration(contextToken.parent) + || isTypeParameterDeclaration(contextToken.parent)) + && (contextToken !== previousToken || position > previousToken.end)); } function isPreviousPropertyDeclarationTerminated(contextToken: Node, position: number) { - return contextToken.kind !== SyntaxKind.EqualsToken && - (contextToken.kind === SyntaxKind.SemicolonToken - || !positionsAreOnSameLine(contextToken.end, position, sourceFile)); + return contextToken.kind !== SyntaxKind.EqualsToken + && (contextToken.kind === SyntaxKind.SemicolonToken + || !positionsAreOnSameLine(contextToken.end, position, sourceFile)); } function isFunctionLikeButNotConstructor(kind: SyntaxKind) { @@ -4760,7 +5498,10 @@ function getCompletionData( * @returns Symbols to be suggested in an object binding pattern or object literal expression, barring those whose declarations * do not occur at the current position and have not otherwise been typed. */ - function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: readonly Declaration[]): Symbol[] { + function filterObjectMembersList( + contextualMemberSymbols: Symbol[], + existingMembers: readonly Declaration[], + ): Symbol[] { if (existingMembers.length === 0) { return contextualMemberSymbols; } @@ -4769,13 +5510,15 @@ function getCompletionData( const existingMemberNames = new Set<__String>(); for (const m of existingMembers) { // Ignore omitted expressions for missing members - if (m.kind !== SyntaxKind.PropertyAssignment && - m.kind !== SyntaxKind.ShorthandPropertyAssignment && - m.kind !== SyntaxKind.BindingElement && - m.kind !== SyntaxKind.MethodDeclaration && - m.kind !== SyntaxKind.GetAccessor && - m.kind !== SyntaxKind.SetAccessor && - m.kind !== SyntaxKind.SpreadAssignment) { + if ( + m.kind !== SyntaxKind.PropertyAssignment + && m.kind !== SyntaxKind.ShorthandPropertyAssignment + && m.kind !== SyntaxKind.BindingElement + && m.kind !== SyntaxKind.MethodDeclaration + && m.kind !== SyntaxKind.GetAccessor + && m.kind !== SyntaxKind.SetAccessor + && m.kind !== SyntaxKind.SpreadAssignment + ) { continue; } @@ -4800,7 +5543,8 @@ function getCompletionData( // NOTE: if one only performs this step when m.name is an identifier, // things like '__proto__' are not filtered out. const name = getNameOfDeclaration(m); - existingName = name && isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) : undefined; + existingName = name && isPropertyNameLiteral(name) ? getEscapedTextOfIdentifierOrLiteral(name) + : undefined; } if (existingName !== undefined) { @@ -4814,7 +5558,10 @@ function getCompletionData( return filteredSymbols; } - function setMembersDeclaredBySpreadAssignment(declaration: SpreadAssignment | JsxSpreadAttribute, membersDeclaredBySpreadAssignment: Set) { + function setMembersDeclaredBySpreadAssignment( + declaration: SpreadAssignment | JsxSpreadAttribute, + membersDeclaredBySpreadAssignment: Set, + ) { const expression = declaration.expression; const symbol = typeChecker.getSymbolAtLocation(expression); const type = symbol && typeChecker.getTypeOfSymbolAtLocation(symbol, expression); @@ -4837,7 +5584,10 @@ function getCompletionData( } // Set SortText to MemberDeclaredBySpreadAssignment if it is fulfilled by spread assignment - function setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment: Set, contextualMemberSymbols: Symbol[]): void { + function setSortTextToMemberDeclaredBySpreadAssignment( + membersDeclaredBySpreadAssignment: Set, + contextualMemberSymbols: Symbol[], + ): void { if (membersDeclaredBySpreadAssignment.size === 0) { return; } @@ -4859,7 +5609,8 @@ function getCompletionData( target, origin, CompletionKind.ObjectPropertyDeclaration, - /*jsxIdentifierExpected*/ false); + /*jsxIdentifierExpected*/ false, + ); if (displayName) { const originalSortText = symbolToSortTextMap[symbolId] ?? SortText.LocationPriority; const { name } = displayName; @@ -4873,14 +5624,20 @@ function getCompletionData( * * @returns Symbols to be suggested in an class element depending on existing memebers and symbol flags */ - function filterClassMembersList(baseSymbols: readonly Symbol[], existingMembers: readonly ClassElement[], currentClassElementModifierFlags: ModifierFlags): Symbol[] { + function filterClassMembersList( + baseSymbols: readonly Symbol[], + existingMembers: readonly ClassElement[], + currentClassElementModifierFlags: ModifierFlags, + ): Symbol[] { const existingMemberNames = new Set<__String>(); for (const m of existingMembers) { // Ignore omitted expressions for missing members - if (m.kind !== SyntaxKind.PropertyDeclaration && - m.kind !== SyntaxKind.MethodDeclaration && - m.kind !== SyntaxKind.GetAccessor && - m.kind !== SyntaxKind.SetAccessor) { + if ( + m.kind !== SyntaxKind.PropertyDeclaration + && m.kind !== SyntaxKind.MethodDeclaration + && m.kind !== SyntaxKind.GetAccessor + && m.kind !== SyntaxKind.SetAccessor + ) { continue; } @@ -4906,10 +5663,12 @@ function getCompletionData( } return baseSymbols.filter(propertySymbol => - !existingMemberNames.has(propertySymbol.escapedName) && - !!propertySymbol.declarations && - !(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private) && - !(propertySymbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(propertySymbol.valueDeclaration))); + !existingMemberNames.has(propertySymbol.escapedName) + && !!propertySymbol.declarations + && !(getDeclarationModifierFlagsFromSymbol(propertySymbol) & ModifierFlags.Private) + && !(propertySymbol.valueDeclaration + && isPrivateIdentifierClassElementDeclaration(propertySymbol.valueDeclaration)) + ); } /** @@ -4918,7 +5677,10 @@ function getCompletionData( * @returns Symbols to be suggested in a JSX element, barring those whose attributes * do not occur at the current position and have not otherwise been typed. */ - function filterJsxAttributes(symbols: Symbol[], attributes: NodeArray): Symbol[] { + function filterJsxAttributes( + symbols: Symbol[], + attributes: NodeArray, + ): Symbol[] { const seenNames = new Set<__String>(); const membersDeclaredBySpreadAssignment = new Set(); for (const attr of attributes) { @@ -4950,12 +5712,16 @@ function getCompletionData( * Returns the immediate owning object literal or binding pattern of a context token, * on the condition that one exists and that the context implies completion should be given. */ -function tryGetObjectLikeCompletionContainer(contextToken: Node | undefined, position: number, sourceFile: SourceFile): ObjectLiteralExpression | ObjectBindingPattern | undefined { +function tryGetObjectLikeCompletionContainer( + contextToken: Node | undefined, + position: number, + sourceFile: SourceFile, +): ObjectLiteralExpression | ObjectBindingPattern | undefined { if (contextToken) { const { parent } = contextToken; switch (contextToken.kind) { - case SyntaxKind.OpenBraceToken: // const x = { | - case SyntaxKind.CommaToken: // const x = { a: 0, | + case SyntaxKind.OpenBraceToken: // const x = { | + case SyntaxKind.CommaToken: // const x = { a: 0, | if (isObjectLiteralExpression(parent) || isObjectBindingPattern(parent)) { return parent; } @@ -4965,31 +5731,48 @@ function tryGetObjectLikeCompletionContainer(contextToken: Node | undefined, pos case SyntaxKind.AsyncKeyword: return tryCast(parent.parent, isObjectLiteralExpression); case SyntaxKind.Identifier: - if ((contextToken as Identifier).text === "async" && isShorthandPropertyAssignment(contextToken.parent)) { + if ( + (contextToken as Identifier).text === "async" && isShorthandPropertyAssignment(contextToken.parent) + ) { return contextToken.parent.parent; } else { - if (isObjectLiteralExpression(contextToken.parent.parent) && - (isSpreadAssignment(contextToken.parent) || isShorthandPropertyAssignment(contextToken.parent) && - (getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line !== getLineAndCharacterOfPosition(sourceFile, position).line))) { + if ( + isObjectLiteralExpression(contextToken.parent.parent) + && (isSpreadAssignment(contextToken.parent) + || isShorthandPropertyAssignment(contextToken.parent) + && (getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line + !== getLineAndCharacterOfPosition(sourceFile, position).line)) + ) { return contextToken.parent.parent; } const ancestorNode = findAncestor(parent, isPropertyAssignment); - if (ancestorNode?.getLastToken(sourceFile) === contextToken && isObjectLiteralExpression(ancestorNode.parent)) { + if ( + ancestorNode?.getLastToken(sourceFile) === contextToken + && isObjectLiteralExpression(ancestorNode.parent) + ) { return ancestorNode.parent; } } break; default: - if (parent.parent?.parent && (isMethodDeclaration(parent.parent) || isGetAccessorDeclaration(parent.parent) || isSetAccessorDeclaration(parent.parent)) && isObjectLiteralExpression(parent.parent.parent)) { + if ( + parent.parent?.parent + && (isMethodDeclaration(parent.parent) || isGetAccessorDeclaration(parent.parent) + || isSetAccessorDeclaration(parent.parent)) + && isObjectLiteralExpression(parent.parent.parent) + ) { return parent.parent.parent; } if (isSpreadAssignment(parent) && isObjectLiteralExpression(parent.parent)) { return parent.parent; } const ancestorNode = findAncestor(parent, isPropertyAssignment); - if (contextToken.kind !== SyntaxKind.ColonToken && ancestorNode?.getLastToken(sourceFile) === contextToken && - isObjectLiteralExpression(ancestorNode.parent)) { + if ( + contextToken.kind !== SyntaxKind.ColonToken + && ancestorNode?.getLastToken(sourceFile) === contextToken + && isObjectLiteralExpression(ancestorNode.parent) + ) { return ancestorNode.parent; } } @@ -4998,22 +5781,32 @@ function tryGetObjectLikeCompletionContainer(contextToken: Node | undefined, pos return undefined; } -function getRelevantTokens(position: number, sourceFile: SourceFile): { contextToken: Node, previousToken: Node } | { contextToken: undefined, previousToken: undefined } { +function getRelevantTokens( + position: number, + sourceFile: SourceFile, +): { contextToken: Node; previousToken: Node; } | { contextToken: undefined; previousToken: undefined; } { const previousToken = findPrecedingToken(position, sourceFile); - if (previousToken && position <= previousToken.end && (isMemberName(previousToken) || isKeyword(previousToken.kind))) { + if ( + previousToken && position <= previousToken.end && (isMemberName(previousToken) || isKeyword(previousToken.kind)) + ) { const contextToken = findPrecedingToken(previousToken.getFullStart(), sourceFile, /*startNode*/ undefined)!; // TODO: GH#18217 return { contextToken, previousToken }; } return { contextToken: previousToken as Node, previousToken: previousToken as Node }; } -function getAutoImportSymbolFromCompletionEntryData(name: string, data: CompletionEntryData, program: Program, host: LanguageServiceHost): { symbol: Symbol, origin: SymbolOriginInfoExport | SymbolOriginInfoResolvedExport } | undefined { +function getAutoImportSymbolFromCompletionEntryData( + name: string, + data: CompletionEntryData, + program: Program, + host: LanguageServiceHost, +): { symbol: Symbol; origin: SymbolOriginInfoExport | SymbolOriginInfoResolvedExport; } | undefined { const containingProgram = data.isPackageJsonImport ? host.getPackageJsonAutoImportProvider!()! : program; const checker = containingProgram.getTypeChecker(); - const moduleSymbol = - data.ambientModuleName ? checker.tryFindAmbientModule(data.ambientModuleName) : - data.fileName ? checker.getMergedSymbol(Debug.checkDefined(containingProgram.getSourceFile(data.fileName)).symbol) : - undefined; + const moduleSymbol = data.ambientModuleName ? checker.tryFindAmbientModule(data.ambientModuleName) + : data.fileName + ? checker.getMergedSymbol(Debug.checkDefined(containingProgram.getSourceFile(data.fileName)).symbol) + : undefined; if (!moduleSymbol) return undefined; let symbol = data.exportName === InternalSymbolName.ExportEquals @@ -5040,22 +5833,28 @@ function getCompletionEntryDisplayNameForSymbol( return undefined; } const name = originIncludesSymbolName(origin) ? origin.symbolName : symbol.name; - if (name === undefined + if ( + name === undefined // If the symbol is external module, don't show it in the completion list // (i.e declare module "http" { const x; } | // <= request completion here, "http" should not be there) || symbol.flags & SymbolFlags.Module && isSingleOrDoubleQuote(name.charCodeAt(0)) // If the symbol is the internal name of an ES symbol, it is not a valid entry. Internal names for ES symbols start with "__@" - || isKnownSymbol(symbol)) { + || isKnownSymbol(symbol) + ) { return undefined; } const validNameResult: CompletionEntryDisplayNameForSymbol = { name, needsConvertPropertyAccess: false }; - if (isIdentifierText(name, target, jsxIdentifierExpected ? LanguageVariant.JSX : LanguageVariant.Standard) || symbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(symbol.valueDeclaration)) { + if ( + isIdentifierText(name, target, jsxIdentifierExpected ? LanguageVariant.JSX : LanguageVariant.Standard) + || symbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(symbol.valueDeclaration) + ) { return validNameResult; } switch (kind) { case CompletionKind.MemberLike: - return originIsComputedPropertyName(origin) ? { name: origin.symbolName, needsConvertPropertyAccess: false } : undefined; + return originIsComputedPropertyName(origin) ? { name: origin.symbolName, needsConvertPropertyAccess: false } + : undefined; case CompletionKind.ObjectPropertyDeclaration: // TODO: GH#18169 return { name: JSON.stringify(name), needsConvertPropertyAccess: false }; @@ -5080,54 +5879,57 @@ const allKeywordsCompletions: () => readonly CompletionEntry[] = memoize(() => { name: tokenToString(i)!, kind: ScriptElementKind.keyword, kindModifiers: ScriptElementKindModifier.none, - sortText: SortText.GlobalsOrKeywords + sortText: SortText.GlobalsOrKeywords, }); } return res; }); -function getKeywordCompletions(keywordFilter: KeywordCompletionFilters, filterOutTsOnlyKeywords: boolean): readonly CompletionEntry[] { +function getKeywordCompletions( + keywordFilter: KeywordCompletionFilters, + filterOutTsOnlyKeywords: boolean, +): readonly CompletionEntry[] { if (!filterOutTsOnlyKeywords) return getTypescriptKeywordCompletions(keywordFilter); const index = keywordFilter + KeywordCompletionFilters.Last + 1; - return _keywordCompletions[index] || - (_keywordCompletions[index] = getTypescriptKeywordCompletions(keywordFilter) - .filter(entry => !isTypeScriptOnlyKeyword(stringToToken(entry.name)!)) - ); + return _keywordCompletions[index] + || (_keywordCompletions[index] = getTypescriptKeywordCompletions(keywordFilter) + .filter(entry => !isTypeScriptOnlyKeyword(stringToToken(entry.name)!))); } function getTypescriptKeywordCompletions(keywordFilter: KeywordCompletionFilters): readonly CompletionEntry[] { - return _keywordCompletions[keywordFilter] || (_keywordCompletions[keywordFilter] = allKeywordsCompletions().filter(entry => { - const kind = stringToToken(entry.name)!; - switch (keywordFilter) { - case KeywordCompletionFilters.None: - return false; - case KeywordCompletionFilters.All: - return isFunctionLikeBodyKeyword(kind) - || kind === SyntaxKind.DeclareKeyword - || kind === SyntaxKind.ModuleKeyword - || kind === SyntaxKind.TypeKeyword - || kind === SyntaxKind.NamespaceKeyword - || kind === SyntaxKind.AbstractKeyword - || isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword; - case KeywordCompletionFilters.FunctionLikeBodyKeywords: - return isFunctionLikeBodyKeyword(kind); - case KeywordCompletionFilters.ClassElementKeywords: - return isClassMemberCompletionKeyword(kind); - case KeywordCompletionFilters.InterfaceElementKeywords: - return isInterfaceOrTypeLiteralCompletionKeyword(kind); - case KeywordCompletionFilters.ConstructorParameterKeywords: - return isParameterPropertyModifier(kind); - case KeywordCompletionFilters.TypeAssertionKeywords: - return isTypeKeyword(kind) || kind === SyntaxKind.ConstKeyword; - case KeywordCompletionFilters.TypeKeywords: - return isTypeKeyword(kind); - case KeywordCompletionFilters.TypeKeyword: - return kind === SyntaxKind.TypeKeyword; - default: - return Debug.assertNever(keywordFilter); - } - })); + return _keywordCompletions[keywordFilter] + || (_keywordCompletions[keywordFilter] = allKeywordsCompletions().filter(entry => { + const kind = stringToToken(entry.name)!; + switch (keywordFilter) { + case KeywordCompletionFilters.None: + return false; + case KeywordCompletionFilters.All: + return isFunctionLikeBodyKeyword(kind) + || kind === SyntaxKind.DeclareKeyword + || kind === SyntaxKind.ModuleKeyword + || kind === SyntaxKind.TypeKeyword + || kind === SyntaxKind.NamespaceKeyword + || kind === SyntaxKind.AbstractKeyword + || isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword; + case KeywordCompletionFilters.FunctionLikeBodyKeywords: + return isFunctionLikeBodyKeyword(kind); + case KeywordCompletionFilters.ClassElementKeywords: + return isClassMemberCompletionKeyword(kind); + case KeywordCompletionFilters.InterfaceElementKeywords: + return isInterfaceOrTypeLiteralCompletionKeyword(kind); + case KeywordCompletionFilters.ConstructorParameterKeywords: + return isParameterPropertyModifier(kind); + case KeywordCompletionFilters.TypeAssertionKeywords: + return isTypeKeyword(kind) || kind === SyntaxKind.ConstKeyword; + case KeywordCompletionFilters.TypeKeywords: + return isTypeKeyword(kind); + case KeywordCompletionFilters.TypeKeyword: + return kind === SyntaxKind.TypeKeyword; + default: + return Debug.assertNever(keywordFilter); + } + })); } function isTypeScriptOnlyKeyword(kind: SyntaxKind) { @@ -5216,9 +6018,11 @@ function getContextualKeywords( const parent = contextToken.parent; const tokenLine = file.getLineAndCharacterOfPosition(contextToken.end).line; const currentLine = file.getLineAndCharacterOfPosition(position).line; - if ((isImportDeclaration(parent) || isExportDeclaration(parent) && parent.moduleSpecifier) + if ( + (isImportDeclaration(parent) || isExportDeclaration(parent) && parent.moduleSpecifier) && contextToken === parent.moduleSpecifier - && tokenLine === currentLine) { + && tokenLine === currentLine + ) { entries.push({ name: tokenToString(SyntaxKind.AssertKeyword)!, kind: ScriptElementKind.keyword, @@ -5233,20 +6037,25 @@ function getContextualKeywords( /** Get the corresponding JSDocTag node if the position is in a jsDoc comment */ function getJsDocTagAtPosition(node: Node, position: number): JSDocTag | undefined { return findAncestor(node, n => - isJSDocTag(n) && rangeContainsPosition(n, position) ? true : - isJSDoc(n) ? "quit" : false) as JSDocTag | undefined; + isJSDocTag(n) && rangeContainsPosition(n, position) ? true + : isJSDoc(n) ? "quit" : false) as JSDocTag | undefined; } /** @internal */ -export function getPropertiesForObjectExpression(contextualType: Type, completionsType: Type | undefined, obj: ObjectLiteralExpression | JsxAttributes, checker: TypeChecker): Symbol[] { +export function getPropertiesForObjectExpression( + contextualType: Type, + completionsType: Type | undefined, + obj: ObjectLiteralExpression | JsxAttributes, + checker: TypeChecker, +): Symbol[] { const hasCompletionsType = completionsType && completionsType !== contextualType; const type = hasCompletionsType && !(completionsType.flags & TypeFlags.AnyOrUnknown) ? checker.getUnionType([contextualType, completionsType]) : contextualType; const properties = getApparentProperties(type, obj, checker); - return type.isClass() && containsNonPublicProperties(properties) ? [] : - hasCompletionsType ? filter(properties, hasDeclarationOtherThanSelf) : properties; + return type.isClass() && containsNonPublicProperties(properties) ? [] + : hasCompletionsType ? filter(properties, hasDeclarationOtherThanSelf) : properties; // Filter out members whose only declaration is the object literal itself to avoid // self-fulfilling completions like: @@ -5261,16 +6070,21 @@ export function getPropertiesForObjectExpression(contextualType: Type, completio function getApparentProperties(type: Type, node: ObjectLiteralExpression | JsxAttributes, checker: TypeChecker) { if (!type.isUnion()) return type.getApparentProperties(); - return checker.getAllPossiblePropertiesOfTypes(filter(type.types, memberType => - !(memberType.flags & TypeFlags.Primitive - || checker.isArrayLikeType(memberType) - || checker.isTypeInvalidDueToUnionDiscriminant(memberType, node) - || checker.typeHasCallOrConstructSignatures(memberType) - || memberType.isClass() && containsNonPublicProperties(memberType.getApparentProperties())))); + return checker.getAllPossiblePropertiesOfTypes( + filter(type.types, memberType => + !(memberType.flags & TypeFlags.Primitive + || checker.isArrayLikeType(memberType) + || checker.isTypeInvalidDueToUnionDiscriminant(memberType, node) + || checker.typeHasCallOrConstructSignatures(memberType) + || memberType.isClass() && containsNonPublicProperties(memberType.getApparentProperties()))), + ); } function containsNonPublicProperties(props: Symbol[]) { - return some(props, p => !!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier)); + return some( + props, + p => !!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier), + ); } /** @@ -5279,7 +6093,10 @@ function containsNonPublicProperties(props: Symbol[]) { */ function getPropertiesForCompletion(type: Type, checker: TypeChecker): Symbol[] { return type.isUnion() - ? Debug.checkEachDefined(checker.getAllPossiblePropertiesOfTypes(type.types), "getAllPossiblePropertiesOfTypes() should all be defined") + ? Debug.checkEachDefined( + checker.getAllPossiblePropertiesOfTypes(type.types), + "getAllPossiblePropertiesOfTypes() should all be defined", + ) : Debug.checkEachDefined(type.getApparentProperties(), "getApparentProperties() should all be defined"); } @@ -5287,13 +6104,21 @@ function getPropertiesForCompletion(type: Type, checker: TypeChecker): Symbol[] * Returns the immediate owning class declaration of a context token, * on the condition that one exists and that the context implies completion should be given. */ -function tryGetObjectTypeDeclarationCompletionContainer(sourceFile: SourceFile, contextToken: Node | undefined, location: Node, position: number): ObjectTypeDeclaration | undefined { +function tryGetObjectTypeDeclarationCompletionContainer( + sourceFile: SourceFile, + contextToken: Node | undefined, + location: Node, + position: number, +): ObjectTypeDeclaration | undefined { // class c { method() { } | method2() { } } switch (location.kind) { case SyntaxKind.SyntaxList: return tryCast(location.parent, isObjectTypeDeclaration); case SyntaxKind.EndOfFileToken: - const cls = tryCast(lastOrUndefined(cast(location.parent, isSourceFile).statements), isObjectTypeDeclaration); + const cls = tryCast( + lastOrUndefined(cast(location.parent, isSourceFile).statements), + isObjectTypeDeclaration, + ); if (cls && !findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile)) { return cls; } @@ -5322,9 +6147,11 @@ function tryGetObjectTypeDeclarationCompletionContainer(sourceFile: SourceFile, if (!contextToken) return undefined; // class C { blah; constructor/**/ } and so on - if (location.kind === SyntaxKind.ConstructorKeyword + if ( + location.kind === SyntaxKind.ConstructorKeyword // class C { blah \n constructor/**/ } - || (isIdentifier(contextToken) && isPropertyDeclaration(contextToken.parent) && isClassLike(location))) { + || (isIdentifier(contextToken) && isPropertyDeclaration(contextToken.parent) && isClassLike(location)) + ) { return findAncestor(contextToken, isClassLike) as ObjectTypeDeclaration; } @@ -5335,7 +6162,8 @@ function tryGetObjectTypeDeclarationCompletionContainer(sourceFile: SourceFile, case SyntaxKind.SemicolonToken: // class c {getValue(): number; | } case SyntaxKind.CloseBraceToken: // class c { method() { } | } // class c { method() { } b| } - return isFromObjectTypeDeclaration(location) && (location.parent as ClassElement | TypeElement).name === location + return isFromObjectTypeDeclaration(location) + && (location.parent as ClassElement | TypeElement).name === location ? location.parent.parent as ObjectTypeDeclaration : tryCast(location, isObjectTypeDeclaration); case SyntaxKind.OpenBraceToken: // class c { | @@ -5345,11 +6173,17 @@ function tryGetObjectTypeDeclarationCompletionContainer(sourceFile: SourceFile, if (isObjectTypeDeclaration(location)) { // class C extends React.Component { a: () => 1\n| } // class C { prop = ""\n | } - if (getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line !== getLineAndCharacterOfPosition(sourceFile, position).line) { + if ( + getLineAndCharacterOfPosition(sourceFile, contextToken.getEnd()).line + !== getLineAndCharacterOfPosition(sourceFile, position).line + ) { return location; } - const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword; - return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken || isIdentifier(contextToken) && isValidKeyword(identifierToKeywordKind(contextToken) ?? SyntaxKind.Unknown)) + const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword + : isInterfaceOrTypeLiteralCompletionKeyword; + return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken + || isIdentifier(contextToken) + && isValidKeyword(identifierToKeywordKind(contextToken) ?? SyntaxKind.Unknown)) ? contextToken.parent.parent as ObjectTypeDeclaration : undefined; } return undefined; @@ -5404,7 +6238,12 @@ function isFromObjectTypeDeclaration(node: Node): boolean { return node.parent && isClassOrTypeElement(node.parent) && isObjectTypeDeclaration(node.parent.parent); } -function isValidTrigger(sourceFile: SourceFile, triggerCharacter: CompletionsTriggerCharacter, contextToken: Node | undefined, position: number): boolean { +function isValidTrigger( + sourceFile: SourceFile, + triggerCharacter: CompletionsTriggerCharacter, + contextToken: Node | undefined, + position: number, +): boolean { switch (triggerCharacter) { case ".": case "@": @@ -5413,18 +6252,21 @@ function isValidTrigger(sourceFile: SourceFile, triggerCharacter: CompletionsTri case "'": case "`": // Only automatically bring up completions if this is an opening quote. - return !!contextToken && isStringLiteralOrTemplate(contextToken) && position === contextToken.getStart(sourceFile) + 1; + return !!contextToken && isStringLiteralOrTemplate(contextToken) + && position === contextToken.getStart(sourceFile) + 1; case "#": return !!contextToken && isPrivateIdentifier(contextToken) && !!getContainingClass(contextToken); case "<": // Opening JSX tag - return !!contextToken && contextToken.kind === SyntaxKind.LessThanToken && (!isBinaryExpression(contextToken.parent) || binaryExpressionMayBeOpenTag(contextToken.parent)); + return !!contextToken && contextToken.kind === SyntaxKind.LessThanToken + && (!isBinaryExpression(contextToken.parent) || binaryExpressionMayBeOpenTag(contextToken.parent)); case "/": return !!contextToken && (isStringLiteralLike(contextToken) ? !!tryGetImportFromModuleSpecifier(contextToken) : contextToken.kind === SyntaxKind.SlashToken && isJsxClosingElement(contextToken.parent)); case " ": - return !!contextToken && isImportKeyword(contextToken) && contextToken.parent.kind === SyntaxKind.SourceFile; + return !!contextToken && isImportKeyword(contextToken) + && contextToken.parent.kind === SyntaxKind.SourceFile; default: return Debug.assertNever(triggerCharacter); } @@ -5442,11 +6284,21 @@ function isProbablyGlobalType(type: Type, sourceFile: SourceFile, checker: TypeC if (selfSymbol && checker.getTypeOfSymbolAtLocation(selfSymbol, sourceFile) === type) { return true; } - const globalSymbol = checker.resolveName("global", /*location*/ undefined, SymbolFlags.Value, /*excludeGlobals*/ false); + const globalSymbol = checker.resolveName( + "global", + /*location*/ undefined, + SymbolFlags.Value, + /*excludeGlobals*/ false, + ); if (globalSymbol && checker.getTypeOfSymbolAtLocation(globalSymbol, sourceFile) === type) { return true; } - const globalThisSymbol = checker.resolveName("globalThis", /*location*/ undefined, SymbolFlags.Value, /*excludeGlobals*/ false); + const globalThisSymbol = checker.resolveName( + "globalThis", + /*location*/ undefined, + SymbolFlags.Value, + /*excludeGlobals*/ false, + ); if (globalThisSymbol && checker.getTypeOfSymbolAtLocation(globalThisSymbol, sourceFile) === type) { return true; } @@ -5454,7 +6306,8 @@ function isProbablyGlobalType(type: Type, sourceFile: SourceFile, checker: TypeC } function isStaticProperty(symbol: Symbol) { - return !!(symbol.valueDeclaration && getEffectiveModifierFlags(symbol.valueDeclaration) & ModifierFlags.Static && isClassLike(symbol.valueDeclaration.parent)); + return !!(symbol.valueDeclaration && getEffectiveModifierFlags(symbol.valueDeclaration) & ModifierFlags.Static + && isClassLike(symbol.valueDeclaration.parent)); } function tryGetObjectLiteralContextualType(node: ObjectLiteralExpression, typeChecker: TypeChecker) { @@ -5492,7 +6345,8 @@ function getImportStatementCompletionInfo(contextToken: Node, sourceFile: Source isKeywordOnlyCompletion, keywordCompletion, isNewIdentifierLocation: !!(candidate || keywordCompletion === SyntaxKind.TypeKeyword), - isTopLevelTypeOnly: !!tryCast(candidate, isImportDeclaration)?.importClause?.isTypeOnly || !!tryCast(candidate, isImportEqualsDeclaration)?.isTypeOnly, + isTopLevelTypeOnly: !!tryCast(candidate, isImportDeclaration)?.importClause?.isTypeOnly + || !!tryCast(candidate, isImportEqualsDeclaration)?.isTypeOnly, couldBeTypeOnlyImportSpecifier: !!candidate && couldBeTypeOnlyImportSpecifier(candidate, contextToken), replacementSpan: getSingleLineReplacementSpanForImportCompletionNode(candidate), }; @@ -5516,11 +6370,13 @@ function getImportStatementCompletionInfo(contextToken: Node, sourceFile: Source return parent; } if (isNamedImports(parent) || isNamespaceImport(parent)) { - if (!parent.parent.isTypeOnly && ( - contextToken.kind === SyntaxKind.OpenBraceToken || - contextToken.kind === SyntaxKind.ImportKeyword || - contextToken.kind === SyntaxKind.CommaToken - )) { + if ( + !parent.parent.isTypeOnly && ( + contextToken.kind === SyntaxKind.OpenBraceToken + || contextToken.kind === SyntaxKind.ImportKeyword + || contextToken.kind === SyntaxKind.CommaToken + ) + ) { keywordCompletion = SyntaxKind.TypeKeyword; } @@ -5550,7 +6406,9 @@ function getImportStatementCompletionInfo(contextToken: Node, sourceFile: Source } } -function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclaration | ImportEqualsDeclaration | ImportSpecifier | Token | undefined) { +function getSingleLineReplacementSpanForImportCompletionNode( + node: ImportDeclaration | ImportEqualsDeclaration | ImportSpecifier | Token | undefined, +) { if (!node) return undefined; const top = findAncestor(node, or(isImportDeclaration, isImportEqualsDeclaration)) ?? node; const sourceFile = top.getSourceFile(); @@ -5591,14 +6449,20 @@ function getSingleLineReplacementSpanForImportCompletionNode(node: ImportDeclara function getPotentiallyInvalidImportSpecifier(namedBindings: NamedImportBindings | undefined) { return find( tryCast(namedBindings, isNamedImports)?.elements, - e => !e.propertyName && - isStringANonContextualKeyword(e.name.text) && - findPrecedingToken(e.name.pos, namedBindings!.getSourceFile(), namedBindings)?.kind !== SyntaxKind.CommaToken); + e => !e.propertyName + && isStringANonContextualKeyword(e.name.text) + && findPrecedingToken(e.name.pos, namedBindings!.getSourceFile(), namedBindings)?.kind + !== SyntaxKind.CommaToken, + ); } -function couldBeTypeOnlyImportSpecifier(importSpecifier: Node, contextToken: Node | undefined): importSpecifier is ImportSpecifier { +function couldBeTypeOnlyImportSpecifier( + importSpecifier: Node, + contextToken: Node | undefined, +): importSpecifier is ImportSpecifier { return isImportSpecifier(importSpecifier) - && (importSpecifier.isTypeOnly || contextToken === importSpecifier.name && isTypeKeywordTokenOrIdentifier(contextToken)); + && (importSpecifier.isTypeOnly + || contextToken === importSpecifier.name && isTypeKeywordTokenOrIdentifier(contextToken)); } function canCompleteFromNamedBindings(namedBindings: NamedImportBindings) { @@ -5610,7 +6474,8 @@ function canCompleteFromNamedBindings(namedBindings: NamedImportBindings) { // but parser recovery sometimes puts later statements in the named imports list, so // we try to only consider the probably-valid ones. const invalidNamedImport = getPotentiallyInvalidImportSpecifier(namedBindings); - const validImports = invalidNamedImport ? namedBindings.elements.indexOf(invalidNamedImport) : namedBindings.elements.length; + const validImports = invalidNamedImport ? namedBindings.elements.indexOf(invalidNamedImport) + : namedBindings.elements.length; return validImports < 2; } return true; @@ -5624,37 +6489,54 @@ function isModuleSpecifierMissingOrEmpty(specifier: ModuleReference | Expression function getVariableOrParameterDeclaration(contextToken: Node | undefined, location: Node) { if (!contextToken) return; - const possiblyParameterDeclaration = findAncestor(contextToken, node => - isFunctionBlock(node) || isArrowFunctionBody(node) || isBindingPattern(node) - ? "quit" - : ((isParameter(node) || isTypeParameterDeclaration(node)) && !isIndexSignatureDeclaration(node.parent))); + const possiblyParameterDeclaration = findAncestor( + contextToken, + node => + isFunctionBlock(node) || isArrowFunctionBody(node) || isBindingPattern(node) + ? "quit" + : ((isParameter(node) || isTypeParameterDeclaration(node)) + && !isIndexSignatureDeclaration(node.parent)), + ); - const possiblyVariableDeclaration = findAncestor(location, node => - isFunctionBlock(node) || isArrowFunctionBody(node) || isBindingPattern(node) - ? "quit" - : isVariableDeclaration(node)); + const possiblyVariableDeclaration = findAncestor( + location, + node => + isFunctionBlock(node) || isArrowFunctionBody(node) || isBindingPattern(node) + ? "quit" + : isVariableDeclaration(node), + ); - return (possiblyParameterDeclaration || possiblyVariableDeclaration) as ParameterDeclaration | TypeParameterDeclaration | VariableDeclaration | undefined; + return (possiblyParameterDeclaration || possiblyVariableDeclaration) as + | ParameterDeclaration + | TypeParameterDeclaration + | VariableDeclaration + | undefined; } function isArrowFunctionBody(node: Node) { - return node.parent && isArrowFunction(node.parent) && - (node.parent.body === node || - // const a = () => /**/; - node.kind === SyntaxKind.EqualsGreaterThanToken - ); + return node.parent && isArrowFunction(node.parent) + && (node.parent.body === node + // const a = () => /**/; + || node.kind === SyntaxKind.EqualsGreaterThanToken); } /** True if symbol is a type or a module containing at least one type. */ -function symbolCanBeReferencedAtTypeLocation(symbol: Symbol, checker: TypeChecker, seenModules = new Map()): boolean { +function symbolCanBeReferencedAtTypeLocation( + symbol: Symbol, + checker: TypeChecker, + seenModules = new Map(), +): boolean { // Since an alias can be merged with a local declaration, we need to test both the alias and its target. // This code used to just test the result of `skipAlias`, but that would ignore any locally introduced meanings. - return nonAliasCanBeReferencedAtTypeLocation(symbol) || nonAliasCanBeReferencedAtTypeLocation(skipAlias(symbol.exportSymbol || symbol, checker)); + return nonAliasCanBeReferencedAtTypeLocation(symbol) + || nonAliasCanBeReferencedAtTypeLocation(skipAlias(symbol.exportSymbol || symbol, checker)); function nonAliasCanBeReferencedAtTypeLocation(symbol: Symbol): boolean { - return !!(symbol.flags & SymbolFlags.Type) || checker.isUnknownSymbol(symbol) || - !!(symbol.flags & SymbolFlags.Module) && addToSeen(seenModules, getSymbolId(symbol)) && - checker.getExportsOfModule(symbol).some(e => symbolCanBeReferencedAtTypeLocation(e, checker, seenModules)); + return !!(symbol.flags & SymbolFlags.Type) || checker.isUnknownSymbol(symbol) + || !!(symbol.flags & SymbolFlags.Module) && addToSeen(seenModules, getSymbolId(symbol)) + && checker.getExportsOfModule(symbol).some(e => + symbolCanBeReferencedAtTypeLocation(e, checker, seenModules) + ); } } @@ -5679,7 +6561,7 @@ function isDeprecated(symbol: Symbol, checker: TypeChecker) { * 'tate' in 'useState' * 'ment' in 'ENVIRONMENT_VARIABLE' */ - function charactersFuzzyMatchInString(identifierString: string, lowercaseCharacters: string): boolean { +function charactersFuzzyMatchInString(identifierString: string, lowercaseCharacters: string): boolean { if (lowercaseCharacters.length === 0) { return true; } @@ -5692,10 +6574,10 @@ function isDeprecated(symbol: Symbol, checker: TypeChecker) { const strChar = identifierString.charCodeAt(strIndex); const testChar = lowercaseCharacters.charCodeAt(characterIndex); if (strChar === testChar || strChar === toUpperCharCode(testChar)) { - matchedFirstCharacter ||= - prevChar === undefined || // Beginning of word - CharacterCodes.a <= prevChar && prevChar <= CharacterCodes.z && CharacterCodes.A <= strChar && strChar <= CharacterCodes.Z || // camelCase transition - prevChar === CharacterCodes._ && strChar !== CharacterCodes._; // snake_case transition + matchedFirstCharacter ||= prevChar === undefined // Beginning of word + || CharacterCodes.a <= prevChar && prevChar <= CharacterCodes.z && CharacterCodes.A <= strChar + && strChar <= CharacterCodes.Z // camelCase transition + || prevChar === CharacterCodes._ && strChar !== CharacterCodes._; // snake_case transition if (matchedFirstCharacter) { characterIndex++; } diff --git a/src/services/documentHighlights.ts b/src/services/documentHighlights.ts index 1d4848c641851..ce5b0fd1afa39 100644 --- a/src/services/documentHighlights.ts +++ b/src/services/documentHighlights.ts @@ -90,40 +90,77 @@ export interface DocumentHighlights { /** @internal */ export namespace DocumentHighlights { - export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: readonly SourceFile[]): DocumentHighlights[] | undefined { + export function getDocumentHighlights( + program: Program, + cancellationToken: CancellationToken, + sourceFile: SourceFile, + position: number, + sourceFilesToSearch: readonly SourceFile[], + ): DocumentHighlights[] | undefined { const node = getTouchingPropertyName(sourceFile, position); - if (node.parent && (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent))) { + if ( + node.parent + && (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent)) + ) { // For a JSX element, just highlight the matching tag, not all references. const { openingElement, closingElement } = node.parent.parent; - const highlightSpans = [openingElement, closingElement].map(({ tagName }) => getHighlightSpanForNode(tagName, sourceFile)); + const highlightSpans = [openingElement, closingElement].map(({ tagName }) => + getHighlightSpanForNode(tagName, sourceFile) + ); return [{ fileName: sourceFile.fileName, highlightSpans }]; } - return getSemanticDocumentHighlights(position, node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile); + return getSemanticDocumentHighlights(position, node, program, cancellationToken, sourceFilesToSearch) + || getSyntacticDocumentHighlights(node, sourceFile); } function getHighlightSpanForNode(node: Node, sourceFile: SourceFile): HighlightSpan { return { fileName: sourceFile.fileName, textSpan: createTextSpanFromNode(node, sourceFile), - kind: HighlightSpanKind.none + kind: HighlightSpanKind.none, }; } - function getSemanticDocumentHighlights(position: number, node: Node, program: Program, cancellationToken: CancellationToken, sourceFilesToSearch: readonly SourceFile[]): DocumentHighlights[] | undefined { + function getSemanticDocumentHighlights( + position: number, + node: Node, + program: Program, + cancellationToken: CancellationToken, + sourceFilesToSearch: readonly SourceFile[], + ): DocumentHighlights[] | undefined { const sourceFilesSet = new Set(sourceFilesToSearch.map(f => f.fileName)); - const referenceEntries = FindAllReferences.getReferenceEntriesForNode(position, node, program, sourceFilesToSearch, cancellationToken, /*options*/ undefined, sourceFilesSet); + const referenceEntries = FindAllReferences.getReferenceEntriesForNode( + position, + node, + program, + sourceFilesToSearch, + cancellationToken, + /*options*/ undefined, + sourceFilesSet, + ); if (!referenceEntries) return undefined; - const map = arrayToMultiMap(referenceEntries.map(FindAllReferences.toHighlightSpan), e => e.fileName, e => e.span); + const map = arrayToMultiMap( + referenceEntries.map(FindAllReferences.toHighlightSpan), + e => e.fileName, + e => e.span, + ); const getCanonicalFileName = createGetCanonicalFileName(program.useCaseSensitiveFileNames()); return arrayFrom(mapDefinedIterator(map.entries(), ([fileName, highlightSpans]) => { if (!sourceFilesSet.has(fileName)) { - if (!program.redirectTargetsMap.has(toPath(fileName, program.getCurrentDirectory(), getCanonicalFileName))) { + if ( + !program.redirectTargetsMap.has( + toPath(fileName, program.getCurrentDirectory(), getCanonicalFileName), + ) + ) { return undefined; } const redirectTarget = program.getSourceFile(fileName); - const redirect = find(sourceFilesToSearch, f => !!f.redirectInfo && f.redirectInfo.redirectTarget === redirectTarget)!; + const redirect = find( + sourceFilesToSearch, + f => !!f.redirectInfo && f.redirectInfo.redirectTarget === redirectTarget, + )!; fileName = redirect.fileName; Debug.assert(sourceFilesSet.has(fileName)); } @@ -165,7 +202,11 @@ export namespace DocumentHighlights { case SyntaxKind.ForKeyword: case SyntaxKind.WhileKeyword: case SyntaxKind.DoKeyword: - return useParent(node.parent, (n): n is IterationStatement => isIterationStatement(n, /*lookInLabeledStatements*/ true), getLoopBreakContinueOccurrences); + return useParent( + node.parent, + (n): n is IterationStatement => isIterationStatement(n, /*lookInLabeledStatements*/ true), + getLoopBreakContinueOccurrences, + ); case SyntaxKind.ConstructorKeyword: return getFromAllDeclarations(isConstructorDeclaration, [SyntaxKind.ConstructorKeyword]); case SyntaxKind.GetKeyword: @@ -185,12 +226,26 @@ export namespace DocumentHighlights { : undefined; } - function getFromAllDeclarations(nodeTest: (node: Node) => node is T, keywords: readonly SyntaxKind[]): HighlightSpan[] | undefined { - return useParent(node.parent, nodeTest, decl => mapDefined(tryCast(decl, canHaveSymbol)?.symbol.declarations, d => - nodeTest(d) ? find(d.getChildren(sourceFile), c => contains(keywords, c.kind)) : undefined)); + function getFromAllDeclarations( + nodeTest: (node: Node) => node is T, + keywords: readonly SyntaxKind[], + ): HighlightSpan[] | undefined { + return useParent( + node.parent, + nodeTest, + decl => + mapDefined( + tryCast(decl, canHaveSymbol)?.symbol.declarations, + d => nodeTest(d) ? find(d.getChildren(sourceFile), c => contains(keywords, c.kind)) : undefined, + ), + ); } - function useParent(node: Node, nodeTest: (node: Node) => node is T, getNodes: (node: T, sourceFile: SourceFile) => readonly Node[] | undefined): HighlightSpan[] | undefined { + function useParent( + node: Node, + nodeTest: (node: Node) => node is T, + getNodes: (node: T, sourceFile: SourceFile) => readonly Node[] | undefined, + ): HighlightSpan[] | undefined { return nodeTest(node) ? highlightSpans(getNodes(node, sourceFile)) : undefined; } @@ -210,8 +265,10 @@ export namespace DocumentHighlights { else if (isTryStatement(node)) { // Exceptions thrown within a try block lacking a catch clause are "owned" in the current context. return concatenate( - node.catchClause ? aggregateOwnedThrowStatements(node.catchClause) : node.tryBlock && aggregateOwnedThrowStatements(node.tryBlock), - node.finallyBlock && aggregateOwnedThrowStatements(node.finallyBlock)); + node.catchClause ? aggregateOwnedThrowStatements(node.catchClause) + : node.tryBlock && aggregateOwnedThrowStatements(node.tryBlock), + node.finallyBlock && aggregateOwnedThrowStatements(node.finallyBlock), + ); } // Do not cross function boundaries. return isFunctionLike(node) ? undefined : flatMapChildren(node, aggregateOwnedThrowStatements); @@ -245,7 +302,8 @@ export namespace DocumentHighlights { } function aggregateAllBreakAndContinueStatements(node: Node): readonly BreakOrContinueStatement[] | undefined { - return isBreakOrContinueStatement(node) ? [node] : isFunctionLike(node) ? undefined : flatMapChildren(node, aggregateAllBreakAndContinueStatements); + return isBreakOrContinueStatement(node) ? [node] + : isFunctionLike(node) ? undefined : flatMapChildren(node, aggregateAllBreakAndContinueStatements); } function flatMapChildren(node: Node, cb: (child: Node) => readonly T[] | T | undefined): readonly T[] { @@ -288,12 +346,25 @@ export namespace DocumentHighlights { } function getModifierOccurrences(modifier: Modifier["kind"], declaration: Node): Node[] { - return mapDefined(getNodesToSearchForModifier(declaration, modifierToFlag(modifier)), node => findModifier(node, modifier)); + return mapDefined( + getNodesToSearchForModifier(declaration, modifierToFlag(modifier)), + node => findModifier(node, modifier), + ); } function getNodesToSearchForModifier(declaration: Node, modifierFlag: ModifierFlags): readonly Node[] | undefined { // Types of node whose children might have modifiers. - const container = declaration.parent as ModuleBlock | SourceFile | Block | CaseClause | DefaultClause | ConstructorDeclaration | MethodDeclaration | FunctionDeclaration | ObjectTypeDeclaration | ObjectLiteralExpression; + const container = declaration.parent as + | ModuleBlock + | SourceFile + | Block + | CaseClause + | DefaultClause + | ConstructorDeclaration + | MethodDeclaration + | FunctionDeclaration + | ObjectTypeDeclaration + | ObjectLiteralExpression; switch (container.kind) { case SyntaxKind.ModuleBlock: case SyntaxKind.SourceFile: @@ -351,7 +422,15 @@ export namespace DocumentHighlights { function getLoopBreakContinueOccurrences(loopNode: IterationStatement): Node[] { const keywords: Node[] = []; - if (pushKeywordIf(keywords, loopNode.getFirstToken(), SyntaxKind.ForKeyword, SyntaxKind.WhileKeyword, SyntaxKind.DoKeyword)) { + if ( + pushKeywordIf( + keywords, + loopNode.getFirstToken(), + SyntaxKind.ForKeyword, + SyntaxKind.WhileKeyword, + SyntaxKind.DoKeyword, + ) + ) { // If we succeeded and got a do-while loop, then start looking for a 'while' keyword. if (loopNode.kind === SyntaxKind.DoStatement) { const loopTokens = loopNode.getChildren(); @@ -373,7 +452,9 @@ export namespace DocumentHighlights { return keywords; } - function getBreakOrContinueStatementOccurrences(breakOrContinueStatement: BreakOrContinueStatement): Node[] | undefined { + function getBreakOrContinueStatementOccurrences( + breakOrContinueStatement: BreakOrContinueStatement, + ): Node[] | undefined { const owner = getBreakOrContinueOwner(breakOrContinueStatement); if (owner) { @@ -386,7 +467,6 @@ export namespace DocumentHighlights { return getLoopBreakContinueOccurrences(owner as IterationStatement); case SyntaxKind.SwitchStatement: return getSwitchCaseDefaultOccurrences(owner as SwitchStatement); - } } @@ -494,7 +574,6 @@ export namespace DocumentHighlights { }); }); - return keywords; } @@ -520,7 +599,10 @@ export namespace DocumentHighlights { // Do not cross function/class/interface/module/type boundaries. function traverseWithoutCrossingFunction(node: Node, cb: (node: Node) => void) { cb(node); - if (!isFunctionLike(node) && !isClassLike(node) && !isInterfaceDeclaration(node) && !isModuleDeclaration(node) && !isTypeAliasDeclaration(node) && !isTypeNode(node)) { + if ( + !isFunctionLike(node) && !isClassLike(node) && !isInterfaceDeclaration(node) && !isModuleDeclaration(node) + && !isTypeAliasDeclaration(node) && !isTypeNode(node) + ) { forEachChild(node, child => traverseWithoutCrossingFunction(child, cb)); } } @@ -550,7 +632,7 @@ export namespace DocumentHighlights { result.push({ fileName: sourceFile.fileName, textSpan: createTextSpanFromBounds(elseKeyword.getStart(), ifKeyword.end), - kind: HighlightSpanKind.reference + kind: HighlightSpanKind.reference, }); i++; // skip the next keyword continue; @@ -599,6 +681,9 @@ export namespace DocumentHighlights { * Note: 'node' cannot be a SourceFile. */ function isLabeledBy(node: Node, labelName: __String): boolean { - return !!findAncestor(node.parent, owner => !isLabeledStatement(owner) ? "quit" : owner.label.escapedText === labelName); + return !!findAncestor( + node.parent, + owner => !isLabeledStatement(owner) ? "quit" : owner.label.escapedText === labelName, + ); } } diff --git a/src/services/documentRegistry.ts b/src/services/documentRegistry.ts index b8ef0757b7700..b4f473d2d5dfa 100644 --- a/src/services/documentRegistry.ts +++ b/src/services/documentRegistry.ts @@ -118,7 +118,10 @@ export interface DocumentRegistry { getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey; /** @internal */ - getDocumentRegistryBucketKeyWithMode(key: DocumentRegistryBucketKey, mode: ResolutionMode): DocumentRegistryBucketKeyWithMode; + getDocumentRegistryBucketKeyWithMode( + key: DocumentRegistryBucketKey, + mode: ResolutionMode, + ): DocumentRegistryBucketKeyWithMode; /** * Informs the DocumentRegistry that a file is not needed any longer. * @@ -143,11 +146,21 @@ export interface DocumentRegistry { * @param scriptKind The script kind of the file to be released * @param impliedNodeFormat The implied source file format of the file to be released */ - releaseDocument(fileName: string, compilationSettings: CompilerOptions, scriptKind: ScriptKind, impliedNodeFormat: ResolutionMode): void; // eslint-disable-line @typescript-eslint/unified-signatures + releaseDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptKind: ScriptKind, + impliedNodeFormat: ResolutionMode, + ): void; // eslint-disable-line @typescript-eslint/unified-signatures /** * @deprecated pass scriptKind for and impliedNodeFormat correctness */ releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey, scriptKind?: ScriptKind): void; - releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey, scriptKind: ScriptKind, impliedNodeFormat: ResolutionMode): void; // eslint-disable-line @typescript-eslint/unified-signatures + releaseDocumentWithKey( + path: Path, + key: DocumentRegistryBucketKey, + scriptKind: ScriptKind, + impliedNodeFormat: ResolutionMode, + ): void; // eslint-disable-line @typescript-eslint/unified-signatures reportStats(): string; /** @internal */ getBuckets(): Map>; @@ -159,7 +172,7 @@ export interface ExternalDocumentCache { getDocument(key: DocumentRegistryBucketKeyWithMode, path: Path): SourceFile | undefined; } -export type DocumentRegistryBucketKey = string & { __bucketKey: any }; +export type DocumentRegistryBucketKey = string & { __bucketKey: any; }; /** @internal */ export interface DocumentRegistryEntry { @@ -178,14 +191,21 @@ export function isDocumentRegistryEntry(entry: BucketEntry): entry is DocumentRe return !!(entry as DocumentRegistryEntry).sourceFile; } -export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory?: string): DocumentRegistry { +export function createDocumentRegistry( + useCaseSensitiveFileNames?: boolean, + currentDirectory?: string, +): DocumentRegistry { return createDocumentRegistryInternal(useCaseSensitiveFileNames, currentDirectory); } /** @internal */ export type DocumentRegistryBucketKeyWithMode = string & { __documentRegistryBucketKeyWithMode: any; }; /** @internal */ -export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boolean, currentDirectory = "", externalCache?: ExternalDocumentCache): DocumentRegistry { +export function createDocumentRegistryInternal( + useCaseSensitiveFileNames?: boolean, + currentDirectory = "", + externalCache?: ExternalDocumentCache, +): DocumentRegistry { // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have // for those settings. const buckets = new Map>(); @@ -194,23 +214,25 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole function reportStats() { const bucketInfoArray = arrayFrom(buckets.keys()).filter(name => name && name.charAt(0) === "_").map(name => { const entries = buckets.get(name)!; - const sourceFiles: { name: string; scriptKind: ScriptKind, refCount: number; }[] = []; + const sourceFiles: { name: string; scriptKind: ScriptKind; refCount: number; }[] = []; entries.forEach((entry, name) => { if (isDocumentRegistryEntry(entry)) { sourceFiles.push({ name, scriptKind: entry.sourceFile.scriptKind, - refCount: entry.languageServiceRefCount + refCount: entry.languageServiceRefCount, }); } else { - entry.forEach((value, scriptKind) => sourceFiles.push({ name, scriptKind, refCount: value.languageServiceRefCount })); + entry.forEach((value, scriptKind) => + sourceFiles.push({ name, scriptKind, refCount: value.languageServiceRefCount }) + ); } }); sourceFiles.sort((x, y) => y.refCount - x.refCount); return { bucket: name, - sourceFiles + sourceFiles, }; }); return JSON.stringify(bucketInfoArray, undefined, 2); @@ -223,29 +245,108 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole return settingsOrHost as CompilerOptions; } - function acquireDocument(fileName: string, compilationSettings: CompilerOptions | MinimalResolutionCacheHost, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind, languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget): SourceFile { + function acquireDocument( + fileName: string, + compilationSettings: CompilerOptions | MinimalResolutionCacheHost, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind, + languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget, + ): SourceFile { const path = toPath(fileName, currentDirectory, getCanonicalFileName); const key = getKeyForCompilationSettings(getCompilationSettings(compilationSettings)); - return acquireDocumentWithKey(fileName, path, compilationSettings, key, scriptSnapshot, version, scriptKind, languageVersionOrOptions); + return acquireDocumentWithKey( + fileName, + path, + compilationSettings, + key, + scriptSnapshot, + version, + scriptKind, + languageVersionOrOptions, + ); } - function acquireDocumentWithKey(fileName: string, path: Path, compilationSettings: CompilerOptions | MinimalResolutionCacheHost, key: DocumentRegistryBucketKey, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind, languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget): SourceFile { - return acquireOrUpdateDocument(fileName, path, compilationSettings, key, scriptSnapshot, version, /*acquiring*/ true, scriptKind, languageVersionOrOptions); + function acquireDocumentWithKey( + fileName: string, + path: Path, + compilationSettings: CompilerOptions | MinimalResolutionCacheHost, + key: DocumentRegistryBucketKey, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind, + languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget, + ): SourceFile { + return acquireOrUpdateDocument( + fileName, + path, + compilationSettings, + key, + scriptSnapshot, + version, + /*acquiring*/ true, + scriptKind, + languageVersionOrOptions, + ); } - function updateDocument(fileName: string, compilationSettings: CompilerOptions | MinimalResolutionCacheHost, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind, languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget): SourceFile { + function updateDocument( + fileName: string, + compilationSettings: CompilerOptions | MinimalResolutionCacheHost, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind, + languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget, + ): SourceFile { const path = toPath(fileName, currentDirectory, getCanonicalFileName); const key = getKeyForCompilationSettings(getCompilationSettings(compilationSettings)); - return updateDocumentWithKey(fileName, path, compilationSettings, key, scriptSnapshot, version, scriptKind, languageVersionOrOptions); + return updateDocumentWithKey( + fileName, + path, + compilationSettings, + key, + scriptSnapshot, + version, + scriptKind, + languageVersionOrOptions, + ); } - function updateDocumentWithKey(fileName: string, path: Path, compilationSettings: CompilerOptions | MinimalResolutionCacheHost, key: DocumentRegistryBucketKey, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind, languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget): SourceFile { - return acquireOrUpdateDocument(fileName, path, getCompilationSettings(compilationSettings), key, scriptSnapshot, version, /*acquiring*/ false, scriptKind, languageVersionOrOptions); + function updateDocumentWithKey( + fileName: string, + path: Path, + compilationSettings: CompilerOptions | MinimalResolutionCacheHost, + key: DocumentRegistryBucketKey, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind, + languageVersionOrOptions?: CreateSourceFileOptions | ScriptTarget, + ): SourceFile { + return acquireOrUpdateDocument( + fileName, + path, + getCompilationSettings(compilationSettings), + key, + scriptSnapshot, + version, + /*acquiring*/ false, + scriptKind, + languageVersionOrOptions, + ); } function getDocumentRegistryEntry(bucketEntry: BucketEntry, scriptKind: ScriptKind | undefined) { - const entry = isDocumentRegistryEntry(bucketEntry) ? bucketEntry : bucketEntry.get(Debug.checkDefined(scriptKind, "If there are more than one scriptKind's for same document the scriptKind should be provided")); - Debug.assert(scriptKind === undefined || !entry || entry.sourceFile.scriptKind === scriptKind, `Script kind should match provided ScriptKind:${scriptKind} and sourceFile.scriptKind: ${entry?.sourceFile.scriptKind}, !entry: ${!entry}`); + const entry = isDocumentRegistryEntry(bucketEntry) ? bucketEntry + : bucketEntry.get( + Debug.checkDefined( + scriptKind, + "If there are more than one scriptKind's for same document the scriptKind should be provided", + ), + ); + Debug.assert( + scriptKind === undefined || !entry || entry.sourceFile.scriptKind === scriptKind, + `Script kind should match provided ScriptKind:${scriptKind} and sourceFile.scriptKind: ${entry?.sourceFile.scriptKind}, !entry: ${!entry}`, + ); return entry; } @@ -262,14 +363,22 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole ): SourceFile { scriptKind = ensureScriptKind(fileName, scriptKind); const compilationSettings = getCompilationSettings(compilationSettingsOrHost); - const host: MinimalResolutionCacheHost | undefined = compilationSettingsOrHost === compilationSettings ? undefined : compilationSettingsOrHost as MinimalResolutionCacheHost; - const scriptTarget = scriptKind === ScriptKind.JSON ? ScriptTarget.JSON : getEmitScriptTarget(compilationSettings); - const sourceFileOptions: CreateSourceFileOptions = typeof languageVersionOrOptions === "object" ? - languageVersionOrOptions : - { + const host: MinimalResolutionCacheHost | undefined = compilationSettingsOrHost === compilationSettings + ? undefined : compilationSettingsOrHost as MinimalResolutionCacheHost; + const scriptTarget = scriptKind === ScriptKind.JSON ? ScriptTarget.JSON + : getEmitScriptTarget(compilationSettings); + const sourceFileOptions: CreateSourceFileOptions = typeof languageVersionOrOptions === "object" + ? languageVersionOrOptions + : { languageVersion: scriptTarget, - impliedNodeFormat: host && getImpliedNodeFormatForFile(path, host.getCompilerHost?.()?.getModuleResolutionCache?.()?.getPackageJsonInfoCache(), host, compilationSettings), - setExternalModuleIndicator: getSetExternalModuleIndicator(compilationSettings) + impliedNodeFormat: host + && getImpliedNodeFormatForFile( + path, + host.getCompilerHost?.()?.getModuleResolutionCache?.()?.getPackageJsonInfoCache(), + host, + compilationSettings, + ), + setExternalModuleIndicator: getSetExternalModuleIndicator(compilationSettings), }; sourceFileOptions.languageVersion = scriptTarget; const oldBucketCount = buckets.size; @@ -280,16 +389,26 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole // It is interesting, but not definitively problematic if a build requires multiple document registry buckets - // perhaps they are for two projects that don't have any overlap. // Bonus: these events can help us interpret the more interesting event below. - tracing.instant(tracing.Phase.Session, "createdDocumentRegistryBucket", { configFilePath: compilationSettings.configFilePath, key: keyWithMode }); + tracing.instant(tracing.Phase.Session, "createdDocumentRegistryBucket", { + configFilePath: compilationSettings.configFilePath, + key: keyWithMode, + }); } // It is fairly suspicious to have one path in two buckets - you'd expect dependencies to have similar configurations. // If this occurs unexpectedly, the fix is likely to synchronize the project settings. // Skip .d.ts files to reduce noise (should also cover most of node_modules). - const otherBucketKey = !isDeclarationFileName(path) && - forEachEntry(buckets, (bucket, bucketKey) => bucketKey !== keyWithMode && bucket.has(path) && bucketKey); + const otherBucketKey = !isDeclarationFileName(path) + && forEachEntry( + buckets, + (bucket, bucketKey) => bucketKey !== keyWithMode && bucket.has(path) && bucketKey, + ); if (otherBucketKey) { - tracing.instant(tracing.Phase.Session, "documentRegistryBucketOverlap", { path, key1: otherBucketKey, key2: keyWithMode }); + tracing.instant(tracing.Phase.Session, "documentRegistryBucketOverlap", { + path, + key1: otherBucketKey, + key2: keyWithMode, + }); } } @@ -301,7 +420,7 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole Debug.assert(acquiring); entry = { sourceFile, - languageServiceRefCount: 0 + languageServiceRefCount: 0, }; setBucketEntry(); } @@ -309,7 +428,14 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole if (!entry) { // Have never seen this file with these settings. Create a new source file for it. - const sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, sourceFileOptions, version, /*setNodeParents*/ false, scriptKind); + const sourceFile = createLanguageServiceSourceFile( + fileName, + scriptSnapshot, + sourceFileOptions, + version, + /*setNodeParents*/ false, + scriptKind, + ); if (externalCache) { externalCache.setDocument(keyWithMode, path, sourceFile); } @@ -324,8 +450,12 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole // the script snapshot. If so, update it appropriately. Otherwise, we can just // return it as is. if (entry.sourceFile.version !== version) { - entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, - scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot!)); // TODO: GH#18217 + entry.sourceFile = updateLanguageServiceSourceFile( + entry.sourceFile, + scriptSnapshot, + version, + scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot!), + ); // TODO: GH#18217 if (externalCache) { externalCache.setDocument(keyWithMode, path, entry.sourceFile); } @@ -360,13 +490,23 @@ export function createDocumentRegistryInternal(useCaseSensitiveFileNames?: boole } } - function releaseDocument(fileName: string, compilationSettings: CompilerOptions, scriptKind?: ScriptKind, impliedNodeFormat?: ResolutionMode): void { + function releaseDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptKind?: ScriptKind, + impliedNodeFormat?: ResolutionMode, + ): void { const path = toPath(fileName, currentDirectory, getCanonicalFileName); const key = getKeyForCompilationSettings(compilationSettings); return releaseDocumentWithKey(path, key, scriptKind, impliedNodeFormat); } - function releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey, scriptKind?: ScriptKind, impliedNodeFormat?: ResolutionMode): void { + function releaseDocumentWithKey( + path: Path, + key: DocumentRegistryBucketKey, + scriptKind?: ScriptKind, + impliedNodeFormat?: ResolutionMode, + ): void { const bucket = Debug.checkDefined(buckets.get(getDocumentRegistryBucketKeyWithMode(key, impliedNodeFormat))); const bucketEntry = bucket.get(path)!; const entry = getDocumentRegistryEntry(bucketEntry, scriptKind)!; diff --git a/src/services/exportInfoMap.ts b/src/services/exportInfoMap.ts index 4651c1dac1c36..b9205a402615e 100644 --- a/src/services/exportInfoMap.ts +++ b/src/services/exportInfoMap.ts @@ -112,9 +112,28 @@ interface CachedSymbolExportInfo { export interface ExportInfoMap { isUsableByFile(importingFile: Path): boolean; clear(): void; - add(importingFile: Path, symbol: Symbol, key: __String, moduleSymbol: Symbol, moduleFile: SourceFile | undefined, exportKind: ExportKind, isFromPackageJson: boolean, checker: TypeChecker): void; + add( + importingFile: Path, + symbol: Symbol, + key: __String, + moduleSymbol: Symbol, + moduleFile: SourceFile | undefined, + exportKind: ExportKind, + isFromPackageJson: boolean, + checker: TypeChecker, + ): void; get(importingFile: Path, key: string): readonly SymbolExportInfo[] | undefined; - search(importingFile: Path, preferCapitalized: boolean, matches: (name: string, targetFlags: SymbolFlags) => boolean, action: (info: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean, key: string) => T | undefined): T | undefined; + search( + importingFile: Path, + preferCapitalized: boolean, + matches: (name: string, targetFlags: SymbolFlags) => boolean, + action: ( + info: readonly SymbolExportInfo[], + symbolName: string, + isFromAmbientModule: boolean, + key: string, + ) => T | undefined, + ): T | undefined; releaseSymbols(): void; isEmpty(): boolean; /** @returns Whether the change resulted in the cache being cleared */ @@ -153,7 +172,16 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): symbols.clear(); usableByFileName = undefined; }, - add: (importingFile, symbol, symbolTableKey, moduleSymbol, moduleFile, exportKind, isFromPackageJson, checker) => { + add: ( + importingFile, + symbol, + symbolTableKey, + moduleSymbol, + moduleFile, + exportKind, + isFromPackageJson, + checker, + ) => { if (importingFile !== usableByFileName) { cache.clear(); usableByFileName = importingFile; @@ -163,8 +191,13 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): if (moduleFile) { const nodeModulesPathParts = getNodeModulePathParts(moduleFile.fileName); if (nodeModulesPathParts) { - const { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex } = nodeModulesPathParts; - packageName = unmangleScopedPackageName(getPackageNameFromTypesPackageName(moduleFile.fileName.substring(topLevelPackageNameIndex + 1, packageRootIndex))); + const { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex } = + nodeModulesPathParts; + packageName = unmangleScopedPackageName( + getPackageNameFromTypesPackageName( + moduleFile.fileName.substring(topLevelPackageNameIndex + 1, packageRootIndex), + ), + ); if (startsWith(importingFile, moduleFile.path.substring(0, topLevelNodeModulesIndex))) { const prevDeepestNodeModulesPath = packages.get(packageName); const nodeModulesPath = moduleFile.fileName.substring(0, topLevelPackageNameIndex + 1); @@ -204,21 +237,24 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): const storedModuleSymbol = moduleSymbol.flags & SymbolFlags.Transient ? undefined : moduleSymbol; if (!storedSymbol || !storedModuleSymbol) symbols.set(id, [symbol, moduleSymbol]); - exportInfo.add(key(symbolName, symbol, isExternalModuleNameRelative(moduleName) ? undefined : moduleName, checker), { - id, - symbolTableKey, - symbolName, - capitalizedSymbolName, - moduleName, - moduleFile, - moduleFileName: moduleFile?.fileName, - packageName, - exportKind, - targetFlags: target.flags, - isFromPackageJson, - symbol: storedSymbol, - moduleSymbol: storedModuleSymbol, - }); + exportInfo.add( + key(symbolName, symbol, isExternalModuleNameRelative(moduleName) ? undefined : moduleName, checker), + { + id, + symbolTableKey, + symbolName, + capitalizedSymbolName, + moduleName, + moduleFile, + moduleFileName: moduleFile?.fileName, + packageName, + exportKind, + targetFlags: target.flags, + isFromPackageJson, + symbol: storedSymbol, + moduleSymbol: storedModuleSymbol, + }, + ); }, get: (importingFile, key) => { if (importingFile !== usableByFileName) return; @@ -232,7 +268,9 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): const name = preferCapitalized && info[0].capitalizedSymbolName || symbolName; if (matches(name, info[0].targetFlags)) { const rehydrated = info.map(rehydrateCachedInfo); - const filtered = rehydrated.filter((r, i) => isNotShadowedByDeeperNodeModulesPackage(r, info[i].packageName)); + const filtered = rehydrated.filter((r, i) => + isNotShadowedByDeeperNodeModulesPackage(r, info[i].packageName) + ); if (filtered.length) { const res = action(filtered, name, !!ambientModuleName, key); if (res !== undefined) return res; @@ -249,15 +287,16 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): return false; } if ( - usableByFileName && usableByFileName !== newSourceFile.path || + usableByFileName && usableByFileName !== newSourceFile.path // If ATA is enabled, auto-imports uses existing imports to guess whether you want auto-imports from node. // Adding or removing imports from node could change the outcome of that guess, so could change the suggestions list. - typeAcquisitionEnabled && consumesNodeCoreModules(oldSourceFile) !== consumesNodeCoreModules(newSourceFile) || + || typeAcquisitionEnabled + && consumesNodeCoreModules(oldSourceFile) !== consumesNodeCoreModules(newSourceFile) // Module agumentation and ambient module changes can add or remove exports available to be auto-imported. // Changes elsewhere in the file can change the *type* of an export in a module augmentation, // but type info is gathered in getCompletionEntryDetails, which doesn't use the cache. - !arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations) || - !ambientModuleDeclarationsAreEqual(oldSourceFile, newSourceFile) + || !arrayIsEqualTo(oldSourceFile.moduleAugmentations, newSourceFile.moduleAugmentations) + || !ambientModuleDeclarationsAreEqual(oldSourceFile, newSourceFile) ) { cache.clear(); return true; @@ -288,13 +327,20 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): const checker = (isFromPackageJson ? host.getPackageJsonAutoImportProvider()! : host.getCurrentProgram()!).getTypeChecker(); - const moduleSymbol = info.moduleSymbol || cachedModuleSymbol || Debug.checkDefined(info.moduleFile - ? checker.getMergedSymbol(info.moduleFile.symbol) - : checker.tryFindAmbientModule(info.moduleName)); - const symbol = info.symbol || cachedSymbol || Debug.checkDefined(exportKind === ExportKind.ExportEquals - ? checker.resolveExternalModuleSymbol(moduleSymbol) - : checker.tryGetMemberInModuleExportsAndProperties(unescapeLeadingUnderscores(info.symbolTableKey), moduleSymbol), - `Could not find symbol '${info.symbolName}' by key '${info.symbolTableKey}' in module ${moduleSymbol.name}`); + const moduleSymbol = info.moduleSymbol || cachedModuleSymbol || Debug.checkDefined( + info.moduleFile + ? checker.getMergedSymbol(info.moduleFile.symbol) + : checker.tryFindAmbientModule(info.moduleName), + ); + const symbol = info.symbol || cachedSymbol || Debug.checkDefined( + exportKind === ExportKind.ExportEquals + ? checker.resolveExternalModuleSymbol(moduleSymbol) + : checker.tryGetMemberInModuleExportsAndProperties( + unescapeLeadingUnderscores(info.symbolTableKey), + moduleSymbol, + ), + `Could not find symbol '${info.symbolName}' by key '${info.symbolTableKey}' in module ${moduleSymbol.name}`, + ); symbols.set(id, [symbol, moduleSymbol]); return { symbol, @@ -306,7 +352,12 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): }; } - function key(importedName: string, symbol: Symbol, ambientModuleName: string | undefined, checker: TypeChecker): string { + function key( + importedName: string, + symbol: Symbol, + ambientModuleName: string | undefined, + checker: TypeChecker, + ): string { const moduleKey = ambientModuleName || ""; return `${importedName}|${getSymbolId(skipAlias(symbol, checker))}|${moduleKey}`; } @@ -319,7 +370,8 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): } function fileIsGlobalOnly(file: SourceFile) { - return !file.commonJsModuleIndicator && !file.externalModuleIndicator && !file.moduleAugmentations && !file.ambientModuleNames; + return !file.commonJsModuleIndicator && !file.externalModuleIndicator && !file.moduleAugmentations + && !file.ambientModuleNames; } function ambientModuleDeclarationsAreEqual(oldSourceFile: SourceFile, newSourceFile: SourceFile) { @@ -329,9 +381,18 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost): let oldFileStatementIndex = -1; let newFileStatementIndex = -1; for (const ambientModuleName of newSourceFile.ambientModuleNames) { - const isMatchingModuleDeclaration = (node: Statement) => isNonGlobalAmbientModule(node) && node.name.text === ambientModuleName; - oldFileStatementIndex = findIndex(oldSourceFile.statements, isMatchingModuleDeclaration, oldFileStatementIndex + 1); - newFileStatementIndex = findIndex(newSourceFile.statements, isMatchingModuleDeclaration, newFileStatementIndex + 1); + const isMatchingModuleDeclaration = (node: Statement) => + isNonGlobalAmbientModule(node) && node.name.text === ambientModuleName; + oldFileStatementIndex = findIndex( + oldSourceFile.statements, + isMatchingModuleDeclaration, + oldFileStatementIndex + 1, + ); + newFileStatementIndex = findIndex( + newSourceFile.statements, + isMatchingModuleDeclaration, + newFileStatementIndex + 1, + ); if (oldSourceFile.statements[oldFileStatementIndex] !== newSourceFile.statements[newFileStatementIndex]) { return false; } @@ -375,14 +436,21 @@ export function isImportableFile( const toFile = program.getSourceFile(toPath); // Determine to import using toPath only if toPath is what we were looking at // or there doesnt exist the file in the program by the symlink - return (toFile === to || !toFile) && - isImportablePath(from.fileName, toPath, getCanonicalFileName, globalTypingsCache); - } + return (toFile === to || !toFile) + && isImportablePath(from.fileName, toPath, getCanonicalFileName, globalTypingsCache); + }, ); if (packageJsonFilter) { - const isAutoImportable = hasImportablePath && packageJsonFilter.allowsImportingSourceFile(to, moduleSpecifierResolutionHost); - moduleSpecifierCache?.setBlockedByPackageJsonDependencies(from.path, to.path, preferences, {}, !isAutoImportable); + const isAutoImportable = hasImportablePath + && packageJsonFilter.allowsImportingSourceFile(to, moduleSpecifierResolutionHost); + moduleSpecifierCache?.setBlockedByPackageJsonDependencies( + from.path, + to.path, + preferences, + {}, + !isAutoImportable, + ); return isAutoImportable; } @@ -393,9 +461,17 @@ export function isImportableFile( * Don't include something from a `node_modules` that isn't actually reachable by a global import. * A relative import to node_modules is usually a bad idea. */ -function isImportablePath(fromPath: string, toPath: string, getCanonicalFileName: GetCanonicalFileName, globalCachePath?: string): boolean { +function isImportablePath( + fromPath: string, + toPath: string, + getCanonicalFileName: GetCanonicalFileName, + globalCachePath?: string, +): boolean { // If it's in a `node_modules` but is not reachable from here via a global import, don't bother. - const toNodeModules = forEachAncestorDirectory(toPath, ancestor => getBaseFileName(ancestor) === "node_modules" ? ancestor : undefined); + const toNodeModules = forEachAncestorDirectory( + toPath, + ancestor => getBaseFileName(ancestor) === "node_modules" ? ancestor : undefined, + ); const toNodeModulesParent = toNodeModules && getDirectoryPath(getCanonicalFileName(toNodeModules)); return toNodeModulesParent === undefined || startsWith(getCanonicalFileName(fromPath), toNodeModulesParent) @@ -411,35 +487,63 @@ export function forEachExternalModuleToImportFrom( cb: (module: Symbol, moduleFile: SourceFile | undefined, program: Program, isFromPackageJson: boolean) => void, ) { const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host); - const excludePatterns = preferences.autoImportFileExcludePatterns && mapDefined(preferences.autoImportFileExcludePatterns, spec => { - // The client is expected to send rooted path specs since we don't know - // what directory a relative path is relative to. - const pattern = getPatternFromSpec(spec, "", "exclude"); - return pattern ? getRegexFromPattern(pattern, useCaseSensitiveFileNames) : undefined; - }); + const excludePatterns = preferences.autoImportFileExcludePatterns + && mapDefined(preferences.autoImportFileExcludePatterns, spec => { + // The client is expected to send rooted path specs since we don't know + // what directory a relative path is relative to. + const pattern = getPatternFromSpec(spec, "", "exclude"); + return pattern ? getRegexFromPattern(pattern, useCaseSensitiveFileNames) : undefined; + }); - forEachExternalModule(program.getTypeChecker(), program.getSourceFiles(), excludePatterns, (module, file) => cb(module, file, program, /*isFromPackageJson*/ false)); + forEachExternalModule( + program.getTypeChecker(), + program.getSourceFiles(), + excludePatterns, + (module, file) => cb(module, file, program, /*isFromPackageJson*/ false), + ); const autoImportProvider = useAutoImportProvider && host.getPackageJsonAutoImportProvider?.(); if (autoImportProvider) { const start = timestamp(); const checker = program.getTypeChecker(); - forEachExternalModule(autoImportProvider.getTypeChecker(), autoImportProvider.getSourceFiles(), excludePatterns, (module, file) => { - if (file && !program.getSourceFile(file.fileName) || !file && !checker.resolveName(module.name, /*location*/ undefined, SymbolFlags.Module, /*excludeGlobals*/ false)) { - // The AutoImportProvider filters files already in the main program out of its *root* files, - // but non-root files can still be present in both programs, and already in the export info map - // at this point. This doesn't create any incorrect behavior, but is a waste of time and memory, - // so we filter them out here. - cb(module, file, autoImportProvider, /*isFromPackageJson*/ true); - } - }); + forEachExternalModule( + autoImportProvider.getTypeChecker(), + autoImportProvider.getSourceFiles(), + excludePatterns, + (module, file) => { + if ( + file && !program.getSourceFile(file.fileName) + || !file + && !checker.resolveName( + module.name, + /*location*/ undefined, + SymbolFlags.Module, + /*excludeGlobals*/ false, + ) + ) { + // The AutoImportProvider filters files already in the main program out of its *root* files, + // but non-root files can still be present in both programs, and already in the export info map + // at this point. This doesn't create any incorrect behavior, but is a waste of time and memory, + // so we filter them out here. + cb(module, file, autoImportProvider, /*isFromPackageJson*/ true); + } + }, + ); host.log?.(`forEachExternalModuleToImportFrom autoImportProvider: ${timestamp() - start}`); } } -function forEachExternalModule(checker: TypeChecker, allSourceFiles: readonly SourceFile[], excludePatterns: readonly RegExp[] | undefined, cb: (module: Symbol, sourceFile: SourceFile | undefined) => void) { +function forEachExternalModule( + checker: TypeChecker, + allSourceFiles: readonly SourceFile[], + excludePatterns: readonly RegExp[] | undefined, + cb: (module: Symbol, sourceFile: SourceFile | undefined) => void, +) { const isExcluded = excludePatterns && ((fileName: string) => excludePatterns.some(p => p.test(fileName))); for (const ambient of checker.getAmbientModules()) { - if (!stringContains(ambient.name, "*") && !(excludePatterns && ambient.declarations?.every(d => isExcluded!(d.getSourceFile().fileName)))) { + if ( + !stringContains(ambient.name, "*") + && !(excludePatterns && ambient.declarations?.every(d => isExcluded!(d.getSourceFile().fileName))) + ) { cb(ambient, /*sourceFile*/ undefined); } } @@ -451,7 +555,13 @@ function forEachExternalModule(checker: TypeChecker, allSourceFiles: readonly So } /** @internal */ -export function getExportInfoMap(importingFile: SourceFile, host: LanguageServiceHost, program: Program, preferences: UserPreferences, cancellationToken: CancellationToken | undefined): ExportInfoMap { +export function getExportInfoMap( + importingFile: SourceFile, + host: LanguageServiceHost, + program: Program, + preferences: UserPreferences, + cancellationToken: CancellationToken | undefined, +): ExportInfoMap { const start = timestamp(); // Pulling the AutoImportProvider project will trigger its updateGraph if pending, // which will invalidate the export map cache if things change, so pull it before @@ -472,38 +582,50 @@ export function getExportInfoMap(importingFile: SourceFile, host: LanguageServic const compilerOptions = program.getCompilerOptions(); let moduleCount = 0; try { - forEachExternalModuleToImportFrom(program, host, preferences, /*useAutoImportProvider*/ true, (moduleSymbol, moduleFile, program, isFromPackageJson) => { - if (++moduleCount % 100 === 0) cancellationToken?.throwIfCancellationRequested(); - const seenExports = new Map<__String, true>(); - const checker = program.getTypeChecker(); - const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); - // Note: I think we shouldn't actually see resolved module symbols here, but weird merges - // can cause it to happen: see 'completionsImport_mergedReExport.ts' - if (defaultInfo && isImportableSymbol(defaultInfo.symbol, checker)) { - cache.add( - importingFile.path, - defaultInfo.symbol, - defaultInfo.exportKind === ExportKind.Default ? InternalSymbolName.Default : InternalSymbolName.ExportEquals, - moduleSymbol, - moduleFile, - defaultInfo.exportKind, - isFromPackageJson, - checker); - } - checker.forEachExportAndPropertyOfModule(moduleSymbol, (exported, key) => { - if (exported !== defaultInfo?.symbol && isImportableSymbol(exported, checker) && addToSeen(seenExports, key)) { + forEachExternalModuleToImportFrom( + program, + host, + preferences, + /*useAutoImportProvider*/ true, + (moduleSymbol, moduleFile, program, isFromPackageJson) => { + if (++moduleCount % 100 === 0) cancellationToken?.throwIfCancellationRequested(); + const seenExports = new Map<__String, true>(); + const checker = program.getTypeChecker(); + const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); + // Note: I think we shouldn't actually see resolved module symbols here, but weird merges + // can cause it to happen: see 'completionsImport_mergedReExport.ts' + if (defaultInfo && isImportableSymbol(defaultInfo.symbol, checker)) { cache.add( importingFile.path, - exported, - key, + defaultInfo.symbol, + defaultInfo.exportKind === ExportKind.Default ? InternalSymbolName.Default + : InternalSymbolName.ExportEquals, moduleSymbol, moduleFile, - ExportKind.Named, + defaultInfo.exportKind, isFromPackageJson, - checker); + checker, + ); } - }); - }); + checker.forEachExportAndPropertyOfModule(moduleSymbol, (exported, key) => { + if ( + exported !== defaultInfo?.symbol && isImportableSymbol(exported, checker) + && addToSeen(seenExports, key) + ) { + cache.add( + importingFile.path, + exported, + key, + moduleSymbol, + moduleFile, + ExportKind.Named, + isFromPackageJson, + checker, + ); + } + }); + }, + ); } catch (err) { // Ensure cache is reset if operation is cancelled @@ -525,10 +647,14 @@ export function getDefaultLikeExportInfo(moduleSymbol: Symbol, checker: TypeChec } function isImportableSymbol(symbol: Symbol, checker: TypeChecker) { - return !checker.isUndefinedSymbol(symbol) && !checker.isUnknownSymbol(symbol) && !isKnownSymbol(symbol) && !isPrivateIdentifierSymbol(symbol); + return !checker.isUndefinedSymbol(symbol) && !checker.isUnknownSymbol(symbol) && !isKnownSymbol(symbol) + && !isPrivateIdentifierSymbol(symbol); } -function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly exportKind: ExportKind } | undefined { +function getDefaultLikeExportWorker( + moduleSymbol: Symbol, + checker: TypeChecker, +): { readonly symbol: Symbol; readonly exportKind: ExportKind; } | undefined { const exportEquals = checker.resolveExternalModuleSymbol(moduleSymbol); if (exportEquals !== moduleSymbol) return { symbol: exportEquals, exportKind: ExportKind.ExportEquals }; const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol); @@ -536,7 +662,11 @@ function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): } /** @internal */ -export function getDefaultExportInfoWorker(defaultExport: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly resolvedSymbol: Symbol, readonly name: string } | undefined { +export function getDefaultExportInfoWorker( + defaultExport: Symbol, + checker: TypeChecker, + compilerOptions: CompilerOptions, +): { readonly resolvedSymbol: Symbol; readonly name: string; } | undefined { const localSymbol = getLocalSymbolForExportDefault(defaultExport); if (localSymbol) return { resolvedSymbol: localSymbol, name: localSymbol.name }; @@ -554,8 +684,10 @@ export function getDefaultExportInfoWorker(defaultExport: Symbol, checker: TypeC } } - if (defaultExport.escapedName !== InternalSymbolName.Default && - defaultExport.escapedName !== InternalSymbolName.ExportEquals) { + if ( + defaultExport.escapedName !== InternalSymbolName.Default + && defaultExport.escapedName !== InternalSymbolName.ExportEquals + ) { return { resolvedSymbol: defaultExport, name: defaultExport.getName() }; } return { resolvedSymbol: defaultExport, name: getNameForExportedSymbol(defaultExport, compilerOptions.target) }; @@ -567,7 +699,10 @@ function getNameForExportDefault(symbol: Symbol): string | undefined { return tryCast(skipOuterExpressions(declaration.expression), isIdentifier)?.text; } else if (isExportSpecifier(declaration)) { - Debug.assert(declaration.name.text === InternalSymbolName.Default, "Expected the specifier to be a default export"); + Debug.assert( + declaration.name.text === InternalSymbolName.Default, + "Expected the specifier to be a default export", + ); return declaration.propertyName && declaration.propertyName.text; } }); diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 1aa55a6cbc2cf..a5e9867e6e655 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -268,20 +268,41 @@ export interface SymbolAndEntries { } /** @internal */ -export const enum DefinitionKind { Symbol, Label, Keyword, This, String, TripleSlashReference } +export const enum DefinitionKind { + Symbol, + Label, + Keyword, + This, + String, + TripleSlashReference, +} /** @internal */ export type Definition = - | { readonly type: DefinitionKind.Symbol; readonly symbol: Symbol } - | { readonly type: DefinitionKind.Label; readonly node: Identifier } - | { readonly type: DefinitionKind.Keyword; readonly node: Node } - | { readonly type: DefinitionKind.This; readonly node: Node } - | { readonly type: DefinitionKind.String; readonly node: StringLiteralLike } - | { readonly type: DefinitionKind.TripleSlashReference; readonly reference: FileReference, readonly file: SourceFile }; + | { readonly type: DefinitionKind.Symbol; readonly symbol: Symbol; } + | { readonly type: DefinitionKind.Label; readonly node: Identifier; } + | { readonly type: DefinitionKind.Keyword; readonly node: Node; } + | { readonly type: DefinitionKind.This; readonly node: Node; } + | { readonly type: DefinitionKind.String; readonly node: StringLiteralLike; } + | { + readonly type: DefinitionKind.TripleSlashReference; + readonly reference: FileReference; + readonly file: SourceFile; + }; /** @internal */ -export const enum EntryKind { Span, Node, StringLiteral, SearchedLocalFoundProperty, SearchedPropertyFoundLocal } +export const enum EntryKind { + Span, + Node, + StringLiteral, + SearchedLocalFoundProperty, + SearchedPropertyFoundLocal, +} /** @internal */ -export type NodeEntryKind = EntryKind.Node | EntryKind.StringLiteral | EntryKind.SearchedLocalFoundProperty | EntryKind.SearchedPropertyFoundLocal; +export type NodeEntryKind = + | EntryKind.Node + | EntryKind.StringLiteral + | EntryKind.SearchedLocalFoundProperty + | EntryKind.SearchedPropertyFoundLocal; /** @internal */ export type Entry = NodeEntry | SpanEntry; /** @internal */ @@ -308,7 +329,7 @@ export function nodeEntry(node: Node, kind: NodeEntryKind = EntryKind.Node): Nod return { kind, node: (node as NamedDeclaration).name || node, - context: getContextNodeForNodeEntry(node) + context: getContextNodeForNodeEntry(node), }; } @@ -327,13 +348,13 @@ function getContextNodeForNodeEntry(node: Node): ContextNode | undefined { if (!isDeclaration(node.parent) && !isExportAssignment(node.parent)) { // Special property assignment in javascript if (isInJSFile(node)) { - const binaryExpression = isBinaryExpression(node.parent) ? - node.parent : - isAccessExpression(node.parent) && - isBinaryExpression(node.parent.parent) && - node.parent.parent.left === node.parent ? - node.parent.parent : - undefined; + const binaryExpression = isBinaryExpression(node.parent) + ? node.parent + : isAccessExpression(node.parent) + && isBinaryExpression(node.parent.parent) + && node.parent.parent.left === node.parent + ? node.parent.parent + : undefined; if (binaryExpression && getAssignmentDeclarationKind(binaryExpression) !== AssignmentDeclarationKind.None) { return getContextNode(binaryExpression); } @@ -343,40 +364,43 @@ function getContextNodeForNodeEntry(node: Node): ContextNode | undefined { if (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) { return node.parent.parent; } - else if (isJsxSelfClosingElement(node.parent) || - isLabeledStatement(node.parent) || - isBreakOrContinueStatement(node.parent)) { + else if ( + isJsxSelfClosingElement(node.parent) + || isLabeledStatement(node.parent) + || isBreakOrContinueStatement(node.parent) + ) { return node.parent; } else if (isStringLiteralLike(node)) { const validImport = tryGetImportFromModuleSpecifier(node); if (validImport) { const declOrStatement = findAncestor(validImport, node => - isDeclaration(node) || - isStatement(node) || - isJSDocTag(node) - )! as NamedDeclaration | Statement | JSDocTag; - return isDeclaration(declOrStatement) ? - getContextNode(declOrStatement) : - declOrStatement; + isDeclaration(node) + || isStatement(node) + || isJSDocTag(node))! as NamedDeclaration | Statement | JSDocTag; + return isDeclaration(declOrStatement) + ? getContextNode(declOrStatement) + : declOrStatement; } } // Handle computed property name const propertyName = findAncestor(node, isComputedPropertyName); - return propertyName ? - getContextNode(propertyName.parent) : - undefined; + return propertyName + ? getContextNode(propertyName.parent) + : undefined; } - if (node.parent.name === node || // node is name of declaration, use parent - isConstructorDeclaration(node.parent) || - isExportAssignment(node.parent) || + if ( + node.parent.name === node // node is name of declaration, use parent + || isConstructorDeclaration(node.parent) + || isExportAssignment(node.parent) // Property name of the import export specifier or binding pattern, use parent - ((isImportOrExportSpecifier(node.parent) || isBindingElement(node.parent)) - && node.parent.propertyName === node) || + || ((isImportOrExportSpecifier(node.parent) || isBindingElement(node.parent)) + && node.parent.propertyName === node) // Is default export - (node.kind === SyntaxKind.DefaultKeyword && hasSyntacticModifier(node.parent, ModifierFlags.ExportDefault))) { + || (node.kind === SyntaxKind.DefaultKeyword && hasSyntacticModifier(node.parent, ModifierFlags.ExportDefault)) + ) { return getContextNode(node.parent); } @@ -384,17 +408,19 @@ function getContextNodeForNodeEntry(node: Node): ContextNode | undefined { } /** @internal */ -export function getContextNode(node: NamedDeclaration | BinaryExpression | ForInOrOfStatement | undefined): ContextNode | undefined { +export function getContextNode( + node: NamedDeclaration | BinaryExpression | ForInOrOfStatement | undefined, +): ContextNode | undefined { if (!node) return undefined; switch (node.kind) { case SyntaxKind.VariableDeclaration: - return !isVariableDeclarationList(node.parent) || node.parent.declarations.length !== 1 ? - node : - isVariableStatement(node.parent.parent) ? - node.parent.parent : - isForInOrOfStatement(node.parent.parent) ? - getContextNode(node.parent.parent) : - node.parent; + return !isVariableDeclarationList(node.parent) || node.parent.declarations.length !== 1 + ? node + : isVariableStatement(node.parent.parent) + ? node.parent.parent + : isForInOrOfStatement(node.parent.parent) + ? getContextNode(node.parent.parent) + : node.parent; case SyntaxKind.BindingElement: return getContextNode(node.parent.parent as NamedDeclaration); @@ -411,26 +437,26 @@ export function getContextNode(node: NamedDeclaration | BinaryExpression | ForIn return node.parent; case SyntaxKind.BinaryExpression: - return isExpressionStatement(node.parent) ? - node.parent : - node; + return isExpressionStatement(node.parent) + ? node.parent + : node; case SyntaxKind.ForOfStatement: case SyntaxKind.ForInStatement: return { start: (node as ForInOrOfStatement).initializer, - end: (node as ForInOrOfStatement).expression + end: (node as ForInOrOfStatement).expression, }; case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: - return isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent) ? - getContextNode( - findAncestor(node.parent, node => - isBinaryExpression(node) || isForInOrOfStatement(node) - ) as BinaryExpression | ForInOrOfStatement - ) : - node; + return isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent) + ? getContextNode( + findAncestor(node.parent, node => isBinaryExpression(node) || isForInOrOfStatement(node)) as + | BinaryExpression + | ForInOrOfStatement, + ) + : node; default: return node; @@ -438,14 +464,18 @@ export function getContextNode(node: NamedDeclaration | BinaryExpression | ForIn } /** @internal */ -export function toContextSpan(textSpan: TextSpan, sourceFile: SourceFile, context?: ContextNode): { contextSpan: TextSpan } | undefined { +export function toContextSpan( + textSpan: TextSpan, + sourceFile: SourceFile, + context?: ContextNode, +): { contextSpan: TextSpan; } | undefined { if (!context) return undefined; - const contextSpan = isContextWithStartAndEndNode(context) ? - getTextSpan(context.start, sourceFile, context.end) : - getTextSpan(context, sourceFile); - return contextSpan.start !== textSpan.start || contextSpan.length !== textSpan.length ? - { contextSpan } : - undefined; + const contextSpan = isContextWithStartAndEndNode(context) + ? getTextSpan(context.start, sourceFile, context.end) + : getTextSpan(context, sourceFile); + return contextSpan.start !== textSpan.start || contextSpan.length !== textSpan.length + ? { contextSpan } + : undefined; } /** @internal */ @@ -482,20 +512,37 @@ export interface Options { } /** @internal */ -export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined { +export function findReferencedSymbols( + program: Program, + cancellationToken: CancellationToken, + sourceFiles: readonly SourceFile[], + sourceFile: SourceFile, + position: number, +): ReferencedSymbol[] | undefined { const node = getTouchingPropertyName(sourceFile, position); const options = { use: FindReferencesUse.References }; - const referencedSymbols = Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options); + const referencedSymbols = Core.getReferencedSymbolsForNode( + position, + node, + program, + sourceFiles, + cancellationToken, + options, + ); const checker = program.getTypeChecker(); // Unless the starting node is a declaration (vs e.g. JSDoc), don't attempt to compute isDefinition const adjustedNode = Core.getAdjustedNode(node, options); const symbol = isDefinitionForReference(adjustedNode) ? checker.getSymbolAtLocation(adjustedNode) : undefined; - return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined(referencedSymbols, ({ definition, references }) => - // Only include referenced symbols that have a valid definition. - definition && { - definition: checker.runWithCancellationToken(cancellationToken, checker => definitionToReferencedSymbolDefinitionInfo(definition, checker, node)), - references: references.map(r => toReferencedSymbolEntry(r, symbol)) - }); + return !referencedSymbols || !referencedSymbols.length ? undefined + : mapDefined(referencedSymbols, ({ definition, references }) => + // Only include referenced symbols that have a valid definition. + definition && { + definition: checker.runWithCancellationToken(cancellationToken, checker => + definitionToReferencedSymbolDefinitionInfo(definition, checker, node)), + references: references.map(r => + toReferencedSymbolEntry(r, symbol) + ), + }); } function isDefinitionForReference(node: Node): boolean { @@ -506,7 +553,13 @@ function isDefinitionForReference(node: Node): boolean { } /** @internal */ -export function getImplementationsAtPosition(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], sourceFile: SourceFile, position: number): ImplementationLocation[] | undefined { +export function getImplementationsAtPosition( + program: Program, + cancellationToken: CancellationToken, + sourceFiles: readonly SourceFile[], + sourceFile: SourceFile, + position: number, +): ImplementationLocation[] | undefined { const node = getTouchingPropertyName(sourceFile, position); let referenceEntries: Entry[] | undefined; const entries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, node, position); @@ -528,7 +581,13 @@ export function getImplementationsAtPosition(program: Program, cancellationToken continue; } referenceEntries = append(referenceEntries, entry); - const entries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, entry.node, entry.node.pos); + const entries = getImplementationReferenceEntries( + program, + cancellationToken, + sourceFiles, + entry.node, + entry.node.pos, + ); if (entries) { queue.enqueue(...entries); } @@ -538,7 +597,13 @@ export function getImplementationsAtPosition(program: Program, cancellationToken return map(referenceEntries, entry => toImplementationLocation(entry, checker)); } -function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], node: Node, position: number): readonly Entry[] | undefined { +function getImplementationReferenceEntries( + program: Program, + cancellationToken: CancellationToken, + sourceFiles: readonly SourceFile[], + node: Node, + position: number, +): readonly Entry[] | undefined { if (node.kind === SyntaxKind.SourceFile) { return undefined; } @@ -559,16 +624,29 @@ function getImplementationReferenceEntries(program: Program, cancellationToken: } else { // Perform "Find all References" and retrieve only those that are implementations - return getReferenceEntriesForNode(position, node, program, sourceFiles, cancellationToken, { implementations: true, use: FindReferencesUse.References }); + return getReferenceEntriesForNode(position, node, program, sourceFiles, cancellationToken, { + implementations: true, + use: FindReferencesUse.References, + }); } } /** @internal */ export function findReferenceOrRenameEntries( - program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], node: Node, position: number, options: Options | undefined, + program: Program, + cancellationToken: CancellationToken, + sourceFiles: readonly SourceFile[], + node: Node, + position: number, + options: Options | undefined, convertEntry: ToReferenceOrRenameEntry, ): T[] | undefined { - return map(flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options)), entry => convertEntry(entry, node, program.getTypeChecker())); + return map( + flattenEntries( + Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options), + ), + entry => convertEntry(entry, node, program.getTypeChecker()), + ); } /** @internal */ @@ -584,15 +662,36 @@ export function getReferenceEntriesForNode( options: Options = {}, sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName)), ): readonly Entry[] | undefined { - return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options, sourceFilesSet)); + return flattenEntries( + Core.getReferencedSymbolsForNode( + position, + node, + program, + sourceFiles, + cancellationToken, + options, + sourceFilesSet, + ), + ); } function flattenEntries(referenceSymbols: readonly SymbolAndEntries[] | undefined): readonly Entry[] | undefined { return referenceSymbols && flatMap(referenceSymbols, r => r.references); } -function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: TypeChecker, originalNode: Node): ReferencedSymbolDefinitionInfo { - const info = ((): { sourceFile: SourceFile, textSpan: TextSpan, name: string, kind: ScriptElementKind, displayParts: SymbolDisplayPart[], context?: Node | ContextWithStartAndEndNode } => { +function definitionToReferencedSymbolDefinitionInfo( + def: Definition, + checker: TypeChecker, + originalNode: Node, +): ReferencedSymbolDefinitionInfo { + const info = ((): { + sourceFile: SourceFile; + textSpan: TextSpan; + name: string; + kind: ScriptElementKind; + displayParts: SymbolDisplayPart[]; + context?: Node | ContextWithStartAndEndNode; + } => { switch (def.type) { case DefinitionKind.Symbol: { const { symbol } = def; @@ -605,24 +704,44 @@ function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: Ty name, kind, displayParts, - context: getContextNode(declaration) + context: getContextNode(declaration), }; } case DefinitionKind.Label: { const { node } = def; - return { ...getFileAndTextSpanFromNode(node), name: node.text, kind: ScriptElementKind.label, displayParts: [displayPart(node.text, SymbolDisplayPartKind.text)] }; + return { + ...getFileAndTextSpanFromNode(node), + name: node.text, + kind: ScriptElementKind.label, + displayParts: [displayPart(node.text, SymbolDisplayPartKind.text)], + }; } case DefinitionKind.Keyword: { const { node } = def; const name = tokenToString(node.kind)!; - return { ...getFileAndTextSpanFromNode(node), name, kind: ScriptElementKind.keyword, displayParts: [{ text: name, kind: ScriptElementKind.keyword }] }; + return { + ...getFileAndTextSpanFromNode(node), + name, + kind: ScriptElementKind.keyword, + displayParts: [{ text: name, kind: ScriptElementKind.keyword }], + }; } case DefinitionKind.This: { const { node } = def; const symbol = checker.getSymbolAtLocation(node); const displayParts = symbol && SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind( - checker, symbol, node.getSourceFile(), getContainerNode(node), node).displayParts || [textPart("this")]; - return { ...getFileAndTextSpanFromNode(node), name: "this", kind: ScriptElementKind.variableElement, displayParts }; + checker, + symbol, + node.getSourceFile(), + getContainerNode(node), + node, + ).displayParts || [textPart("this")]; + return { + ...getFileAndTextSpanFromNode(node), + name: "this", + kind: ScriptElementKind.variableElement, + displayParts, + }; } case DefinitionKind.String: { const { node } = def; @@ -630,7 +749,7 @@ function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: Ty ...getFileAndTextSpanFromNode(node), name: node.text, kind: ScriptElementKind.variableElement, - displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)] + displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)], }; } case DefinitionKind.TripleSlashReference: { @@ -639,7 +758,7 @@ function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: Ty sourceFile: def.file, name: def.reference.fileName, kind: ScriptElementKind.string, - displayParts: [displayPart(`"${def.reference.fileName}"`, SymbolDisplayPartKind.stringLiteral)] + displayParts: [displayPart(`"${def.reference.fileName}"`, SymbolDisplayPartKind.stringLiteral)], }; } default: @@ -656,7 +775,7 @@ function definitionToReferencedSymbolDefinitionInfo(def: Definition, checker: Ty name, textSpan, displayParts, - ...toContextSpan(textSpan, sourceFile, context) + ...toContextSpan(textSpan, sourceFile, context), }; } @@ -664,21 +783,40 @@ function getFileAndTextSpanFromNode(node: Node) { const sourceFile = node.getSourceFile(); return { sourceFile, - textSpan: getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile) + textSpan: getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile), }; } -function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } { +function getDefinitionKindAndDisplayParts( + symbol: Symbol, + checker: TypeChecker, + node: Node, +): { displayParts: SymbolDisplayPart[]; kind: ScriptElementKind; } { const meaning = Core.getIntersectingMeaningFromDeclarations(node, symbol); const enclosingDeclaration = symbol.declarations && firstOrUndefined(symbol.declarations) || node; - const { displayParts, symbolKind } = - SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(checker, symbol, enclosingDeclaration.getSourceFile(), enclosingDeclaration, enclosingDeclaration, meaning); + const { displayParts, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind( + checker, + symbol, + enclosingDeclaration.getSourceFile(), + enclosingDeclaration, + enclosingDeclaration, + meaning, + ); return { displayParts, kind: symbolKind }; } /** @internal */ -export function toRenameLocation(entry: Entry, originalNode: Node, checker: TypeChecker, providePrefixAndSuffixText: boolean, quotePreference: QuotePreference): RenameLocation { - return { ...entryToDocumentSpan(entry), ...(providePrefixAndSuffixText && getPrefixAndSuffixText(entry, originalNode, checker, quotePreference)) }; +export function toRenameLocation( + entry: Entry, + originalNode: Node, + checker: TypeChecker, + providePrefixAndSuffixText: boolean, + quotePreference: QuotePreference, +): RenameLocation { + return { + ...entryToDocumentSpan(entry), + ...(providePrefixAndSuffixText && getPrefixAndSuffixText(entry, originalNode, checker, quotePreference)), + }; } function toReferencedSymbolEntry(entry: Entry, symbol: Symbol | undefined): ReferencedSymbolEntry { @@ -686,7 +824,7 @@ function toReferencedSymbolEntry(entry: Entry, symbol: Symbol | undefined): Refe if (!symbol) return referenceEntry; return { ...referenceEntry, - isDefinition: entry.kind !== EntryKind.Span && isDeclarationOfSymbol(entry.node, symbol) + isDefinition: entry.kind !== EntryKind.Span && isDeclarationOfSymbol(entry.node, symbol), }; } @@ -714,19 +852,31 @@ function entryToDocumentSpan(entry: Entry): DocumentSpan { return { textSpan, fileName: sourceFile.fileName, - ...toContextSpan(textSpan, sourceFile, entry.context) + ...toContextSpan(textSpan, sourceFile, entry.context), }; } } -interface PrefixAndSuffix { readonly prefixText?: string; readonly suffixText?: string; } -function getPrefixAndSuffixText(entry: Entry, originalNode: Node, checker: TypeChecker, quotePreference: QuotePreference): PrefixAndSuffix { +interface PrefixAndSuffix { + readonly prefixText?: string; + readonly suffixText?: string; +} +function getPrefixAndSuffixText( + entry: Entry, + originalNode: Node, + checker: TypeChecker, + quotePreference: QuotePreference, +): PrefixAndSuffix { if (entry.kind !== EntryKind.Span && isIdentifier(originalNode)) { const { node, kind } = entry; const parent = node.parent; const name = originalNode.text; const isShorthandAssignment = isShorthandPropertyAssignment(parent); - if (isShorthandAssignment || (isObjectBindingElementWithoutPropertyName(parent) && parent.name === node && parent.dotDotDotToken === undefined)) { + if ( + isShorthandAssignment + || (isObjectBindingElementWithoutPropertyName(parent) && parent.name === node + && parent.dotDotDotToken === undefined) + ) { const prefixColon: PrefixAndSuffix = { prefixText: name + ": " }; const suffixColon: PrefixAndSuffix = { suffixText: ": " + name }; if (kind === EntryKind.SearchedLocalFoundProperty) { @@ -740,9 +890,11 @@ function getPrefixAndSuffixText(entry: Entry, originalNode: Node, checker: TypeC // For a binding element `const { x } = o;`, symbolAtLocation at `x` is the property symbol. if (isShorthandAssignment) { const grandParent = parent.parent; - if (isObjectLiteralExpression(grandParent) && - isBinaryExpression(grandParent.parent) && - isModuleExportsAccessExpression(grandParent.parent.left)) { + if ( + isObjectLiteralExpression(grandParent) + && isBinaryExpression(grandParent.parent) + && isModuleExportsAccessExpression(grandParent.parent.left) + ) { return prefixColon; } return suffixColon; @@ -753,14 +905,17 @@ function getPrefixAndSuffixText(entry: Entry, originalNode: Node, checker: TypeC } else if (isImportSpecifier(parent) && !parent.propertyName) { // If the original symbol was using this alias, just rename the alias. - const originalSymbol = isExportSpecifier(originalNode.parent) ? checker.getExportSpecifierLocalTargetSymbol(originalNode.parent) : checker.getSymbolAtLocation(originalNode); + const originalSymbol = isExportSpecifier(originalNode.parent) + ? checker.getExportSpecifierLocalTargetSymbol(originalNode.parent) + : checker.getSymbolAtLocation(originalNode); return contains(originalSymbol!.declarations, parent) ? { prefixText: name + " as " } : emptyOptions; } else if (isExportSpecifier(parent) && !parent.propertyName) { // If the symbol for the node is same as declared node symbol use prefix text - return originalNode === entry.node || checker.getSymbolAtLocation(originalNode) === checker.getSymbolAtLocation(entry.node) ? - { prefixText: name + " as " } : - { suffixText: " as " + name }; + return originalNode === entry.node + || checker.getSymbolAtLocation(originalNode) === checker.getSymbolAtLocation(entry.node) + ? { prefixText: name + " as " } + : { suffixText: " as " + name }; } } @@ -779,7 +934,7 @@ function toImplementationLocation(entry: Entry, checker: TypeChecker): Implement const { node } = entry; return { ...documentSpan, - ...implementationKindDisplayParts(node, checker) + ...implementationKindDisplayParts(node, checker), }; } else { @@ -787,7 +942,10 @@ function toImplementationLocation(entry: Entry, checker: TypeChecker): Implement } } -function implementationKindDisplayParts(node: Node, checker: TypeChecker): { kind: ScriptElementKind, displayParts: SymbolDisplayPart[] } { +function implementationKindDisplayParts( + node: Node, + checker: TypeChecker, +): { kind: ScriptElementKind; displayParts: SymbolDisplayPart[]; } { const symbol = checker.getSymbolAtLocation(isDeclaration(node) && node.name ? node.name : node); if (symbol) { return getDefinitionKindAndDisplayParts(symbol, checker, node); @@ -795,13 +953,21 @@ function implementationKindDisplayParts(node: Node, checker: TypeChecker): { kin else if (node.kind === SyntaxKind.ObjectLiteralExpression) { return { kind: ScriptElementKind.interfaceElement, - displayParts: [punctuationPart(SyntaxKind.OpenParenToken), textPart("object literal"), punctuationPart(SyntaxKind.CloseParenToken)] + displayParts: [ + punctuationPart(SyntaxKind.OpenParenToken), + textPart("object literal"), + punctuationPart(SyntaxKind.CloseParenToken), + ], }; } else if (node.kind === SyntaxKind.ClassExpression) { return { kind: ScriptElementKind.localClassElement, - displayParts: [punctuationPart(SyntaxKind.OpenParenToken), textPart("anonymous local class"), punctuationPart(SyntaxKind.CloseParenToken)] + displayParts: [ + punctuationPart(SyntaxKind.OpenParenToken), + textPart("anonymous local class"), + punctuationPart(SyntaxKind.CloseParenToken), + ], }; } else { @@ -810,15 +976,15 @@ function implementationKindDisplayParts(node: Node, checker: TypeChecker): { kin } /** @internal */ -export function toHighlightSpan(entry: Entry): { fileName: string, span: HighlightSpan } { +export function toHighlightSpan(entry: Entry): { fileName: string; span: HighlightSpan; } { const documentSpan = entryToDocumentSpan(entry); if (entry.kind === EntryKind.Span) { return { fileName: documentSpan.fileName, span: { textSpan: documentSpan.textSpan, - kind: HighlightSpanKind.reference - } + kind: HighlightSpanKind.reference, + }, }; } @@ -827,7 +993,7 @@ export function toHighlightSpan(entry: Entry): { fileName: string, span: Highlig textSpan: documentSpan.textSpan, kind: writeAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference, isInString: entry.kind === EntryKind.StringLiteral ? true : undefined, - ...documentSpan.contextSpan && { contextSpan: documentSpan.contextSpan } + ...documentSpan.contextSpan && { contextSpan: documentSpan.contextSpan }, }; return { fileName: documentSpan.fileName, span }; } @@ -845,8 +1011,8 @@ function getTextSpan(node: Node, sourceFile: SourceFile, endNode?: Node): TextSp /** @internal */ export function getTextSpanOfEntry(entry: Entry) { - return entry.kind === EntryKind.Span ? entry.textSpan : - getTextSpan(entry.node, entry.node.getSourceFile()); + return entry.kind === EntryKind.Span ? entry.textSpan + : getTextSpan(entry.node, entry.node.getSourceFile()); } /** @@ -866,11 +1032,11 @@ export function isWriteAccessForReference(node: Node): boolean { */ export function isDeclarationOfSymbol(node: Node, target: Symbol | undefined): boolean { if (!target) return false; - const source = getDeclarationFromName(node) || - (node.kind === SyntaxKind.DefaultKeyword ? node.parent - : isLiteralComputedPropertyDeclarationName(node) ? node.parent.parent - : node.kind === SyntaxKind.ConstructorKeyword && isConstructorDeclaration(node.parent) ? node.parent.parent - : undefined); + const source = getDeclarationFromName(node) + || (node.kind === SyntaxKind.DefaultKeyword ? node.parent + : isLiteralComputedPropertyDeclarationName(node) ? node.parent.parent + : node.kind === SyntaxKind.ConstructorKeyword && isConstructorDeclaration(node.parent) ? node.parent.parent + : undefined); const commonjsSource = source && isBinaryExpression(source) ? source.left as unknown as Declaration : undefined; return !!(source && target.declarations?.some(d => d === source || d === commonjsSource)); } @@ -919,7 +1085,13 @@ function declarationIsWriteAccess(decl: Declaration): boolean { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - return !!(decl as FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration).body; + return !!(decl as + | FunctionDeclaration + | FunctionExpression + | ConstructorDeclaration + | MethodDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration).body; case SyntaxKind.VariableDeclaration: case SyntaxKind.PropertyDeclaration: @@ -943,7 +1115,15 @@ function declarationIsWriteAccess(decl: Declaration): boolean { */ export namespace Core { /** Core find-all-references algorithm. Handles special cases before delegating to `getReferencedSymbolsForSymbol`. */ - export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName))): readonly SymbolAndEntries[] | undefined { + export function getReferencedSymbolsForNode( + position: number, + node: Node, + program: Program, + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + options: Options = {}, + sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName)), + ): readonly SymbolAndEntries[] | undefined { node = getAdjustedNode(node, options); if (isSourceFile(node)) { const resolvedRef = GoToDefinition.getReferenceAtPosition(node, position, program); @@ -952,7 +1132,13 @@ export namespace Core { } const moduleSymbol = program.getTypeChecker().getMergedSymbol(resolvedRef.file.symbol); if (moduleSymbol) { - return getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet); + return getReferencedSymbolsForModule( + program, + moduleSymbol, + /*excludeImportTypeOfExportEquals*/ false, + sourceFiles, + sourceFilesSet, + ); } const fileIncludeReasons = program.getFileIncludeReasons(); if (!fileIncludeReasons) { @@ -960,7 +1146,7 @@ export namespace Core { } return [{ definition: { type: DefinitionKind.TripleSlashReference, reference: resolvedRef.reference, file: node }, - references: getReferencesForNonModule(resolvedRef.file, fileIncludeReasons, program) || emptyArray + references: getReferencesForNonModule(resolvedRef.file, fileIncludeReasons, program) || emptyArray, }]; } @@ -981,10 +1167,17 @@ export namespace Core { if (!options.implementations && isStringLiteralLike(node)) { if (isModuleSpecifierLike(node)) { const fileIncludeReasons = program.getFileIncludeReasons(); - const referencedFileName = node.getSourceFile().resolvedModules?.get(node.text, getModeForUsageLocation(node.getSourceFile(), node))?.resolvedModule?.resolvedFileName; + const referencedFileName = node.getSourceFile().resolvedModules?.get( + node.text, + getModeForUsageLocation(node.getSourceFile(), node), + )?.resolvedModule?.resolvedFileName; const referencedFile = referencedFileName ? program.getSourceFile(referencedFileName) : undefined; if (referencedFile) { - return [{ definition: { type: DefinitionKind.String, node }, references: getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray }]; + return [{ + definition: { type: DefinitionKind.String, node }, + references: getReferencesForNonModule(referencedFile, fileIncludeReasons, program) + || emptyArray, + }]; } // Fall through to string literal references. This is not very likely to return // anything useful, but I guess it's better than nothing, and there's an existing @@ -996,19 +1189,47 @@ export namespace Core { } if (symbol.escapedName === InternalSymbolName.ExportEquals) { - return getReferencedSymbolsForModule(program, symbol.parent!, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet); + return getReferencedSymbolsForModule( + program, + symbol.parent!, + /*excludeImportTypeOfExportEquals*/ false, + sourceFiles, + sourceFilesSet, + ); } - const moduleReferences = getReferencedSymbolsForModuleIfDeclaredBySourceFile(symbol, program, sourceFiles, cancellationToken, options, sourceFilesSet); + const moduleReferences = getReferencedSymbolsForModuleIfDeclaredBySourceFile( + symbol, + program, + sourceFiles, + cancellationToken, + options, + sourceFilesSet, + ); if (moduleReferences && !(symbol.flags & SymbolFlags.Transient)) { return moduleReferences; } const aliasedSymbol = getMergedAliasedSymbolOfNamespaceExportDeclaration(node, symbol, checker); - const moduleReferencesOfExportTarget = aliasedSymbol && - getReferencedSymbolsForModuleIfDeclaredBySourceFile(aliasedSymbol, program, sourceFiles, cancellationToken, options, sourceFilesSet); - - const references = getReferencedSymbolsForSymbol(symbol, node, sourceFiles, sourceFilesSet, checker, cancellationToken, options); + const moduleReferencesOfExportTarget = aliasedSymbol + && getReferencedSymbolsForModuleIfDeclaredBySourceFile( + aliasedSymbol, + program, + sourceFiles, + cancellationToken, + options, + sourceFilesSet, + ); + + const references = getReferencedSymbolsForSymbol( + symbol, + node, + sourceFiles, + sourceFilesSet, + checker, + cancellationToken, + options, + ); return mergeReferences(program, moduleReferences, references, moduleReferencesOfExportTarget); } @@ -1022,17 +1243,33 @@ export namespace Core { return node; } - export function getReferencesForFileName(fileName: string, program: Program, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName))): readonly Entry[] { + export function getReferencesForFileName( + fileName: string, + program: Program, + sourceFiles: readonly SourceFile[], + sourceFilesSet: ReadonlySet = new Set(sourceFiles.map(f => f.fileName)), + ): readonly Entry[] { const moduleSymbol = program.getSourceFile(fileName)?.symbol; if (moduleSymbol) { - return getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet)[0]?.references || emptyArray; + return getReferencedSymbolsForModule( + program, + moduleSymbol, + /*excludeImportTypeOfExportEquals*/ false, + sourceFiles, + sourceFilesSet, + )[0]?.references || emptyArray; } const fileIncludeReasons = program.getFileIncludeReasons(); const referencedFile = program.getSourceFile(fileName); - return referencedFile && fileIncludeReasons && getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray; + return referencedFile && fileIncludeReasons + && getReferencesForNonModule(referencedFile, fileIncludeReasons, program) || emptyArray; } - function getReferencesForNonModule(referencedFile: SourceFile, refFileMap: MultiMap, program: Program): readonly SpanEntry[] | undefined { + function getReferencesForNonModule( + referencedFile: SourceFile, + refFileMap: MultiMap, + program: Program, + ): readonly SpanEntry[] | undefined { let entries: SpanEntry[] | undefined; const references = refFileMap.get(referencedFile.path) || emptyArray; for (const ref of references) { @@ -1043,7 +1280,7 @@ export namespace Core { entries = append(entries, { kind: EntryKind.Span, fileName: referencingFile.fileName, - textSpan: createTextSpanFromRange(location) + textSpan: createTextSpanFromRange(location), }); } } @@ -1062,23 +1299,52 @@ export namespace Core { return undefined; } - function getReferencedSymbolsForModuleIfDeclaredBySourceFile(symbol: Symbol, program: Program, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken, options: Options, sourceFilesSet: ReadonlySet) { - const moduleSourceFile = (symbol.flags & SymbolFlags.Module) && symbol.declarations && find(symbol.declarations, isSourceFile); + function getReferencedSymbolsForModuleIfDeclaredBySourceFile( + symbol: Symbol, + program: Program, + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + options: Options, + sourceFilesSet: ReadonlySet, + ) { + const moduleSourceFile = (symbol.flags & SymbolFlags.Module) && symbol.declarations + && find(symbol.declarations, isSourceFile); if (!moduleSourceFile) return undefined; const exportEquals = symbol.exports!.get(InternalSymbolName.ExportEquals); // If !!exportEquals, we're about to add references to `import("mod")` anyway, so don't double-count them. - const moduleReferences = getReferencedSymbolsForModule(program, symbol, !!exportEquals, sourceFiles, sourceFilesSet); + const moduleReferences = getReferencedSymbolsForModule( + program, + symbol, + !!exportEquals, + sourceFiles, + sourceFilesSet, + ); if (!exportEquals || !sourceFilesSet.has(moduleSourceFile.fileName)) return moduleReferences; // Continue to get references to 'export ='. const checker = program.getTypeChecker(); symbol = skipAlias(exportEquals, checker); - return mergeReferences(program, moduleReferences, getReferencedSymbolsForSymbol(symbol, /*node*/ undefined, sourceFiles, sourceFilesSet, checker, cancellationToken, options)); + return mergeReferences( + program, + moduleReferences, + getReferencedSymbolsForSymbol( + symbol, + /*node*/ undefined, + sourceFiles, + sourceFilesSet, + checker, + cancellationToken, + options, + ), + ); } /** * Merges the references by sorting them (by file index in sourceFiles and their location in it) that point to same definition symbol */ - function mergeReferences(program: Program, ...referencesToMerge: (SymbolAndEntries[] | undefined)[]): SymbolAndEntries[] | undefined { + function mergeReferences( + program: Program, + ...referencesToMerge: (SymbolAndEntries[] | undefined)[] + ): SymbolAndEntries[] | undefined { let result: SymbolAndEntries[] | undefined; for (const references of referencesToMerge) { if (!references || !references.length) continue; @@ -1092,9 +1358,10 @@ export namespace Core { continue; } const symbol = entry.definition.symbol; - const refIndex = findIndex(result, ref => !!ref.definition && - ref.definition.type === DefinitionKind.Symbol && - ref.definition.symbol === symbol); + const refIndex = findIndex(result, ref => + !!ref.definition + && ref.definition.type === DefinitionKind.Symbol + && ref.definition.symbol === symbol); if (refIndex === -1) { result.push(entry); continue; @@ -1112,10 +1379,10 @@ export namespace Core { const entry1Span = getTextSpanOfEntry(entry1); const entry2Span = getTextSpanOfEntry(entry2); - return entry1Span.start !== entry2Span.start ? - compareValues(entry1Span.start, entry2Span.start) : - compareValues(entry1Span.length, entry2Span.length); - }) + return entry1Span.start !== entry2Span.start + ? compareValues(entry1Span.start, entry2Span.start) + : compareValues(entry1Span.length, entry2Span.length); + }), }; } } @@ -1123,43 +1390,53 @@ export namespace Core { } function getSourceFileIndexOfEntry(program: Program, entry: Entry) { - const sourceFile = entry.kind === EntryKind.Span ? - program.getSourceFile(entry.fileName)! : - entry.node.getSourceFile(); + const sourceFile = entry.kind === EntryKind.Span + ? program.getSourceFile(entry.fileName)! + : entry.node.getSourceFile(); return program.getSourceFiles().indexOf(sourceFile); } - function getReferencedSymbolsForModule(program: Program, symbol: Symbol, excludeImportTypeOfExportEquals: boolean, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet): SymbolAndEntries[] { + function getReferencedSymbolsForModule( + program: Program, + symbol: Symbol, + excludeImportTypeOfExportEquals: boolean, + sourceFiles: readonly SourceFile[], + sourceFilesSet: ReadonlySet, + ): SymbolAndEntries[] { Debug.assert(!!symbol.valueDeclaration); - const references = mapDefined(findModuleReferences(program, sourceFiles, symbol), reference => { - if (reference.kind === "import") { - const parent = reference.literal.parent; - if (isLiteralTypeNode(parent)) { - const importType = cast(parent.parent, isImportTypeNode); - if (excludeImportTypeOfExportEquals && !importType.qualifier) { - return undefined; + const references = mapDefined( + findModuleReferences(program, sourceFiles, symbol), + reference => { + if (reference.kind === "import") { + const parent = reference.literal.parent; + if (isLiteralTypeNode(parent)) { + const importType = cast(parent.parent, isImportTypeNode); + if (excludeImportTypeOfExportEquals && !importType.qualifier) { + return undefined; + } } + // import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway. + return nodeEntry(reference.literal); } - // import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway. - return nodeEntry(reference.literal); - } - else if (reference.kind === "implicit") { - // Return either: The first JSX node in the (if not a tslib import), the first statement of the file, or the whole file if neither of those exist - const range = reference.literal.text !== externalHelpersModuleNameText && forEachChildRecursively( - reference.referencingFile, - n => !(n.transformFlags & TransformFlags.ContainsJsx) ? "skip" : isJsxElement(n) || isJsxSelfClosingElement(n) || isJsxFragment(n) ? n : undefined - ) || reference.referencingFile.statements[0] || reference.referencingFile; - return nodeEntry(range); - } - else { - return { - kind: EntryKind.Span, - fileName: reference.referencingFile.fileName, - textSpan: createTextSpanFromRange(reference.ref), - }; - } - }); + else if (reference.kind === "implicit") { + // Return either: The first JSX node in the (if not a tslib import), the first statement of the file, or the whole file if neither of those exist + const range = reference.literal.text !== externalHelpersModuleNameText && forEachChildRecursively( + reference.referencingFile, + n => !(n.transformFlags & TransformFlags.ContainsJsx) ? "skip" + : isJsxElement(n) || isJsxSelfClosingElement(n) || isJsxFragment(n) ? n : undefined, + ) || reference.referencingFile.statements[0] || reference.referencingFile; + return nodeEntry(range); + } + else { + return { + kind: EntryKind.Span, + fileName: reference.referencingFile.fileName, + textSpan: createTextSpanFromRange(reference.ref), + }; + } + }, + ); if (symbol.declarations) { for (const decl of symbol.declarations) { @@ -1174,7 +1451,10 @@ export namespace Core { break; default: // This may be merged with something. - Debug.assert(!!(symbol.flags & SymbolFlags.Transient), "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration."); + Debug.assert( + !!(symbol.flags & SymbolFlags.Transient), + "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration.", + ); } } } @@ -1185,9 +1465,11 @@ export namespace Core { const sourceFile = decl.getSourceFile(); if (sourceFilesSet.has(sourceFile.fileName)) { // At `module.exports = ...`, reference node is `module` - const node = isBinaryExpression(decl) && isPropertyAccessExpression(decl.left) ? decl.left.expression : - isExportAssignment(decl) ? Debug.checkDefined(findChildOfKind(decl, SyntaxKind.ExportKeyword, sourceFile)) : - getNameOfDeclaration(decl) || decl; + const node = isBinaryExpression(decl) && isPropertyAccessExpression(decl.left) + ? decl.left.expression + : isExportAssignment(decl) + ? Debug.checkDefined(findChildOfKind(decl, SyntaxKind.ExportKeyword, sourceFile)) + : getNameOfDeclaration(decl) || decl; references.push(nodeEntry(node)); } } @@ -1204,7 +1486,11 @@ export namespace Core { } /** getReferencedSymbols for special node kinds. */ - function getReferencedSymbolsSpecial(node: Node, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined { + function getReferencedSymbolsSpecial( + node: Node, + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + ): SymbolAndEntries[] | undefined { if (isTypeKeyword(node.kind)) { // A void expression (i.e., `void foo()`) is not special, but the `void` type is. if (node.kind === SyntaxKind.VoidKeyword && isVoidExpression(node.parent)) { @@ -1222,7 +1508,8 @@ export namespace Core { sourceFiles, node.kind, cancellationToken, - node.kind === SyntaxKind.ReadonlyKeyword ? isReadonlyTypeOperator : undefined); + node.kind === SyntaxKind.ReadonlyKeyword ? isReadonlyTypeOperator : undefined, + ); } if (isImportMeta(node.parent) && node.parent.name === node) { @@ -1257,25 +1544,73 @@ export namespace Core { } /** Core find-all-references algorithm for a normal symbol. */ - function getReferencedSymbolsForSymbol(originalSymbol: Symbol, node: Node | undefined, sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] { - const symbol = node && skipPastExportOrImportSpecifierOrUnion(originalSymbol, node, checker, /*useLocalSymbolForExportSpecifier*/ !isForRenameWithPrefixAndSuffixText(options)) || originalSymbol; + function getReferencedSymbolsForSymbol( + originalSymbol: Symbol, + node: Node | undefined, + sourceFiles: readonly SourceFile[], + sourceFilesSet: ReadonlySet, + checker: TypeChecker, + cancellationToken: CancellationToken, + options: Options, + ): SymbolAndEntries[] { + const symbol = node + && skipPastExportOrImportSpecifierOrUnion( + originalSymbol, + node, + checker, + /*useLocalSymbolForExportSpecifier*/ !isForRenameWithPrefixAndSuffixText(options), + ) || originalSymbol; // Compute the meaning from the location and the symbol it references const searchMeaning = node ? getIntersectingMeaningFromDeclarations(node, symbol) : SemanticMeaning.All; const result: SymbolAndEntries[] = []; - const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result); + const state = new State( + sourceFiles, + sourceFilesSet, + node ? getSpecialSearchKind(node) : SpecialSearchKind.None, + checker, + cancellationToken, + searchMeaning, + options, + result, + ); - const exportSpecifier = !isForRenameWithPrefixAndSuffixText(options) || !symbol.declarations ? undefined : find(symbol.declarations, isExportSpecifier); + const exportSpecifier = !isForRenameWithPrefixAndSuffixText(options) || !symbol.declarations ? undefined + : find(symbol.declarations, isExportSpecifier); if (exportSpecifier) { // When renaming at an export specifier, rename the export and not the thing being exported. - getReferencesAtExportSpecifier(exportSpecifier.name, symbol, exportSpecifier, state.createSearch(node, originalSymbol, /*comingFrom*/ undefined), state, /*addReferencesHere*/ true, /*alwaysGetReferences*/ true); - } - else if (node && node.kind === SyntaxKind.DefaultKeyword && symbol.escapedName === InternalSymbolName.Default && symbol.parent) { + getReferencesAtExportSpecifier( + exportSpecifier.name, + symbol, + exportSpecifier, + state.createSearch(node, originalSymbol, /*comingFrom*/ undefined), + state, + /*addReferencesHere*/ true, + /*alwaysGetReferences*/ true, + ); + } + else if ( + node && node.kind === SyntaxKind.DefaultKeyword && symbol.escapedName === InternalSymbolName.Default + && symbol.parent + ) { addReference(node, symbol, state); - searchForImportsOfExport(node, symbol, { exportingModuleSymbol: symbol.parent, exportKind: ExportKind.Default }, state); + searchForImportsOfExport(node, symbol, { + exportingModuleSymbol: symbol.parent, + exportKind: ExportKind.Default, + }, state); } else { - const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, options.use === FindReferencesUse.Rename, !!options.providePrefixAndSuffixTextForRename, !!options.implementations) : [symbol] }); + const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { + allSearchSymbols: node + ? populateSearchSymbolSet( + symbol, + node, + checker, + options.use === FindReferencesUse.Rename, + !!options.providePrefixAndSuffixTextForRename, + !!options.implementations, + ) : [symbol], + }); getReferencesInContainerOrFiles(symbol, state, search); } @@ -1287,7 +1622,13 @@ export namespace Core { // otherwise we'll need to search globally (i.e. include each file). const scope = getSymbolScope(symbol); if (scope) { - getReferencesInContainer(scope, scope.getSourceFile(), search, state, /*addReferencesHere*/ !(isSourceFile(scope) && !contains(state.sourceFiles, scope))); + getReferencesInContainer( + scope, + scope.getSourceFile(), + search, + state, + /*addReferencesHere*/ !(isSourceFile(scope) && !contains(state.sourceFiles, scope)), + ); } else { // Global search @@ -1315,7 +1656,12 @@ export namespace Core { } /** Handle a few special cases relating to export/import specifiers. */ - function skipPastExportOrImportSpecifierOrUnion(symbol: Symbol, node: Node, checker: TypeChecker, useLocalSymbolForExportSpecifier: boolean): Symbol | undefined { + function skipPastExportOrImportSpecifierOrUnion( + symbol: Symbol, + node: Node, + checker: TypeChecker, + useLocalSymbolForExportSpecifier: boolean, + ): Symbol | undefined { const { parent } = node; if (isExportSpecifier(parent) && useLocalSymbolForExportSpecifier) { return getLocalSymbolForExportSpecifier(node as Identifier, symbol, parent, checker); @@ -1406,7 +1752,8 @@ export namespace Core { readonly cancellationToken: CancellationToken, readonly searchMeaning: SemanticMeaning, readonly options: Options, - private readonly result: SymbolAndEntries[]) { + private readonly result: SymbolAndEntries[], + ) { } includesSourceFile(sourceFile: SourceFile): boolean { @@ -1416,23 +1763,49 @@ export namespace Core { private importTracker: ImportTracker | undefined; /** Gets every place to look for references of an exported symbols. See `ImportsResult` in `importTracker.ts` for more documentation. */ getImportSearches(exportSymbol: Symbol, exportInfo: ExportInfo): ImportsResult { - if (!this.importTracker) this.importTracker = createImportTracker(this.sourceFiles, this.sourceFilesSet, this.checker, this.cancellationToken); + if (!this.importTracker) { + this.importTracker = createImportTracker( + this.sourceFiles, + this.sourceFilesSet, + this.checker, + this.cancellationToken, + ); + } return this.importTracker(exportSymbol, exportInfo, this.options.use === FindReferencesUse.Rename); } /** @param allSearchSymbols set of additional symbols for use by `includes`. */ - createSearch(location: Node | undefined, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search { + createSearch( + location: Node | undefined, + symbol: Symbol, + comingFrom: ImportExport | undefined, + searchOptions: { text?: string; allSearchSymbols?: Symbol[]; } = {}, + ): Search { // Note: if this is an external module symbol, the name doesn't include quotes. // Note: getLocalSymbolForExportDefault handles `export default class C {}`, but not `export default C` or `export { C as default }`. // The other two forms seem to be handled downstream (e.g. in `skipPastExportOrImportSpecifier`), so special-casing the first form // here appears to be intentional). const { - text = stripQuotes(symbolName(getLocalSymbolForExportDefault(symbol) || getNonModuleSymbolOfMergedModuleSymbol(symbol) || symbol)), + text = stripQuotes( + symbolName( + getLocalSymbolForExportDefault(symbol) || getNonModuleSymbolOfMergedModuleSymbol(symbol) + || symbol, + ), + ), allSearchSymbols = [symbol], } = searchOptions; const escapedText = escapeLeadingUnderscores(text); - const parents = this.options.implementations && location ? getParentSymbolsOfPropertyAccess(location, symbol, this.checker) : undefined; - return { symbol, comingFrom, text, escapedText, parents, allSearchSymbols, includes: sym => contains(allSearchSymbols, sym) }; + const parents = this.options.implementations && location + ? getParentSymbolsOfPropertyAccess(location, symbol, this.checker) : undefined; + return { + symbol, + comingFrom, + text, + escapedText, + parents, + allSearchSymbols, + includes: sym => contains(allSearchSymbols, sym), + }; } private readonly symbolIdToReferences: Entry[][] = []; @@ -1454,7 +1827,7 @@ export namespace Core { addStringOrCommentReference(fileName: string, textSpan: TextSpan): void { this.result.push({ definition: undefined, - references: [{ kind: EntryKind.Span, fileName, textSpan }] + references: [{ kind: EntryKind.Span, fileName, textSpan }], }); } @@ -1463,7 +1836,8 @@ export namespace Core { /** Returns `true` the first time we search for a symbol in a file and `false` afterwards. */ markSearchedSymbols(sourceFile: SourceFile, symbols: readonly Symbol[]): boolean { const sourceId = getNodeId(sourceFile); - const seenSymbols = this.sourceFileToSeenSymbols[sourceId] || (this.sourceFileToSeenSymbols[sourceId] = new Set()); + const seenSymbols = this.sourceFileToSeenSymbols[sourceId] + || (this.sourceFileToSeenSymbols[sourceId] = new Set()); let anyNewSymbols = false; for (const sym of symbols) { @@ -1474,7 +1848,12 @@ export namespace Core { } /** Search for all imports of a given exported symbol using `State.getImportSearches`. */ - function searchForImportsOfExport(exportLocation: Node, exportSymbol: Symbol, exportInfo: ExportInfo, state: State): void { + function searchForImportsOfExport( + exportLocation: Node, + exportSymbol: Symbol, + exportInfo: ExportInfo, + state: State, + ): void { const { importSearches, singleReferences, indirectUsers } = state.getImportSearches(exportSymbol, exportInfo); // For `import { foo as bar }` just add the reference to `foo`, and don't otherwise search in the file. @@ -1487,7 +1866,11 @@ export namespace Core { // For each import, find all references to that import in its source file. for (const [importLocation, importSymbol] of importSearches) { - getReferencesInSourceFile(importLocation.getSourceFile(), state.createSearch(importLocation, importSymbol, ImportExport.Export), state); + getReferencesInSourceFile( + importLocation.getSourceFile(), + state.createSearch(importLocation, importSymbol, ImportExport.Export), + state, + ); } if (indirectUsers.length) { @@ -1498,7 +1881,8 @@ export namespace Core { break; case ExportKind.Default: // Search for a property access to '.default'. This can't be renamed. - indirectSearch = state.options.use === FindReferencesUse.Rename ? undefined : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { text: "default" }); + indirectSearch = state.options.use === FindReferencesUse.Rename ? undefined + : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { text: "default" }); break; case ExportKind.ExportEquals: break; @@ -1521,8 +1905,16 @@ export namespace Core { isDefaultExport: boolean, cb: (ref: Identifier) => void, ): void { - const importTracker = createImportTracker(sourceFiles, new Set(sourceFiles.map(f => f.fileName)), checker, cancellationToken); - const { importSearches, indirectUsers, singleReferences } = importTracker(exportSymbol, { exportKind: isDefaultExport ? ExportKind.Default : ExportKind.Named, exportingModuleSymbol }, /*isForRename*/ false); + const importTracker = createImportTracker( + sourceFiles, + new Set(sourceFiles.map(f => f.fileName)), + checker, + cancellationToken, + ); + const { importSearches, indirectUsers, singleReferences } = importTracker(exportSymbol, { + exportKind: isDefaultExport ? ExportKind.Default : ExportKind.Named, + exportingModuleSymbol, + }, /*isForRename*/ false); for (const [importLocation] of importSearches) { cb(importLocation); } @@ -1532,11 +1924,19 @@ export namespace Core { } } for (const indirectUser of indirectUsers) { - for (const node of getPossibleSymbolReferenceNodes(indirectUser, isDefaultExport ? "default" : exportName)) { + for ( + const node of getPossibleSymbolReferenceNodes(indirectUser, isDefaultExport ? "default" : exportName) + ) { // Import specifiers should be handled by importSearches const symbol = checker.getSymbolAtLocation(node); - const hasExportAssignmentDeclaration = some(symbol?.declarations, d => tryCast(d, isExportAssignment) ? true : false); - if (isIdentifier(node) && !isImportOrExportSpecifier(node.parent) && (symbol === exportSymbol || hasExportAssignmentDeclaration)) { + const hasExportAssignmentDeclaration = some( + symbol?.declarations, + d => tryCast(d, isExportAssignment) ? true : false, + ); + if ( + isIdentifier(node) && !isImportOrExportSpecifier(node.parent) + && (symbol === exportSymbol || hasExportAssignmentDeclaration) + ) { cb(node); } } @@ -1559,7 +1959,12 @@ export namespace Core { for (const declaration of symbol.declarations) { const exportingFile = declaration.getSourceFile(); // Need to search in the file even if it's not in the search-file set, because it might export the symbol. - getReferencesInSourceFile(exportingFile, state.createSearch(declaration, symbol, ImportExport.Import), state, state.includesSourceFile(exportingFile)); + getReferencesInSourceFile( + exportingFile, + state.createSearch(declaration, symbol, ImportExport.Import), + state, + state.includesSourceFile(exportingFile), + ); } } @@ -1588,7 +1993,11 @@ export namespace Core { // If this is the symbol of a named function expression or named class expression, // then named references are limited to its own scope. const { declarations, flags, parent, valueDeclaration } = symbol; - if (valueDeclaration && (valueDeclaration.kind === SyntaxKind.FunctionExpression || valueDeclaration.kind === SyntaxKind.ClassExpression)) { + if ( + valueDeclaration + && (valueDeclaration.kind === SyntaxKind.FunctionExpression + || valueDeclaration.kind === SyntaxKind.ClassExpression) + ) { return valueDeclaration; } @@ -1598,7 +2007,10 @@ export namespace Core { // If this is private property or method, the scope is the containing class if (flags & (SymbolFlags.Property | SymbolFlags.Method)) { - const privateDeclaration = find(declarations, d => hasEffectiveModifier(d, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(d)); + const privateDeclaration = find( + declarations, + d => hasEffectiveModifier(d, ModifierFlags.Private) || isPrivateIdentifierClassElementDeclaration(d), + ); if (privateDeclaration) { return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration); } @@ -1632,7 +2044,10 @@ export namespace Core { return undefined; } - if (!container || container.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(container as SourceFile)) { + if ( + !container + || container.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(container as SourceFile) + ) { // This is a global variable and not an external module, any declaration defined // within this scope is visible outside the file return undefined; @@ -1656,11 +2071,22 @@ export namespace Core { } /** Used as a quick check for whether a symbol is used at all in a file (besides its definition). */ - export function isSymbolReferencedInFile(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile, searchContainer: Node = sourceFile): boolean { + export function isSymbolReferencedInFile( + definition: Identifier, + checker: TypeChecker, + sourceFile: SourceFile, + searchContainer: Node = sourceFile, + ): boolean { return eachSymbolReferenceInFile(definition, checker, sourceFile, () => true, searchContainer) || false; } - export function eachSymbolReferenceInFile(definition: Identifier, checker: TypeChecker, sourceFile: SourceFile, cb: (token: Identifier) => T, searchContainer: Node = sourceFile): T | undefined { + export function eachSymbolReferenceInFile( + definition: Identifier, + checker: TypeChecker, + sourceFile: SourceFile, + cb: (token: Identifier) => T, + searchContainer: Node = sourceFile, + ): T | undefined { const symbol = isParameterPropertyDeclaration(definition.parent, definition.parent.parent) ? first(checker.getSymbolsOfParameterPropertyDeclaration(definition.parent, definition.text)) : checker.getSymbolAtLocation(definition); @@ -1668,9 +2094,12 @@ export namespace Core { for (const token of getPossibleSymbolReferenceNodes(sourceFile, symbol.name, searchContainer)) { if (!isIdentifier(token) || token === definition || token.escapedText !== definition.escapedText) continue; const referenceSymbol = checker.getSymbolAtLocation(token)!; - if (referenceSymbol === symbol + if ( + referenceSymbol === symbol || checker.getShorthandAssignmentValueSymbol(token.parent) === symbol - || isExportSpecifier(token.parent) && getLocalSymbolForExportSpecifier(token, referenceSymbol, token.parent, checker) === symbol) { + || isExportSpecifier(token.parent) + && getLocalSymbolForExportSpecifier(token, referenceSymbol, token.parent, checker) === symbol + ) { const res = cb(token); if (res) return res; } @@ -1678,7 +2107,10 @@ export namespace Core { } export function getTopMostDeclarationNamesInFile(declarationName: string, sourceFile: SourceFile): readonly Node[] { - const candidates = filter(getPossibleSymbolReferenceNodes(sourceFile, declarationName), name => !!getDeclarationFromName(name)); + const candidates = filter( + getPossibleSymbolReferenceNodes(sourceFile, declarationName), + name => !!getDeclarationFromName(name), + ); return candidates.reduce((topMost, decl) => { const depth = getDepth(decl); if (!some(topMost.declarationNames) || depth === topMost.depth) { @@ -1706,7 +2138,7 @@ export namespace Core { signature: SignatureDeclaration, sourceFiles: readonly SourceFile[], checker: TypeChecker, - cb: (name: Identifier, call?: CallExpression) => boolean + cb: (name: Identifier, call?: CallExpression) => boolean, ): boolean { if (!signature.name || !isIdentifier(signature.name)) return false; @@ -1714,9 +2146,12 @@ export namespace Core { for (const sourceFile of sourceFiles) { for (const name of getPossibleSymbolReferenceNodes(sourceFile, symbol.name)) { - if (!isIdentifier(name) || name === signature.name || name.escapedText !== signature.name.escapedText) continue; + if (!isIdentifier(name) || name === signature.name || name.escapedText !== signature.name.escapedText) { + continue; + } const called = climbPastPropertyAccess(name); - const call = isCallExpression(called.parent) && called.parent.expression === called ? called.parent : undefined; + const call = isCallExpression(called.parent) && called.parent.expression === called ? called.parent + : undefined; const referenceSymbol = checker.getSymbolAtLocation(name); if (referenceSymbol && checker.getRootSymbols(referenceSymbol).some(s => s === symbol)) { if (cb(name, call)) { @@ -1728,14 +2163,22 @@ export namespace Core { return false; } - function getPossibleSymbolReferenceNodes(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): readonly Node[] { + function getPossibleSymbolReferenceNodes( + sourceFile: SourceFile, + symbolName: string, + container: Node = sourceFile, + ): readonly Node[] { return mapDefined(getPossibleSymbolReferencePositions(sourceFile, symbolName, container), pos => { const referenceLocation = getTouchingPropertyName(sourceFile, pos); return referenceLocation === sourceFile ? undefined : referenceLocation; }); } - function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): readonly number[] { + function getPossibleSymbolReferencePositions( + sourceFile: SourceFile, + symbolName: string, + container: Node = sourceFile, + ): readonly number[] { const positions: number[] = []; /// TODO: Cache symbol existence for files to save text search @@ -1759,8 +2202,11 @@ export namespace Core { // before and after it have to be a non-identifier char). const endPosition = position + symbolNameLength; - if ((position === 0 || !isIdentifierPart(text.charCodeAt(position - 1), ScriptTarget.Latest)) && - (endPosition === sourceLength || !isIdentifierPart(text.charCodeAt(endPosition), ScriptTarget.Latest))) { + if ( + (position === 0 || !isIdentifierPart(text.charCodeAt(position - 1), ScriptTarget.Latest)) + && (endPosition === sourceLength + || !isIdentifierPart(text.charCodeAt(endPosition), ScriptTarget.Latest)) + ) { // Found a real match. Keep searching. positions.push(position); } @@ -1775,7 +2221,8 @@ export namespace Core { const labelName = targetLabel.text; const references = mapDefined(getPossibleSymbolReferenceNodes(sourceFile, labelName, container), node => // Only pick labels that are either the target label, or have a target that is the target label - node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel) ? nodeEntry(node) : undefined); + node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel) + ? nodeEntry(node) : undefined); return [{ definition: { type: DefinitionKind.Label, node: targetLabel }, references }]; } @@ -1792,12 +2239,16 @@ export namespace Core { case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.StringLiteral: { const str = node as StringLiteralLike; - return (isLiteralNameOfPropertyDeclarationOrIndexAccess(str) || isNameOfModuleDeclaration(node) || isExpressionOfExternalModuleImportEqualsDeclaration(node) || (isCallExpression(node.parent) && isBindableObjectDefinePropertyCall(node.parent) && node.parent.arguments[1] === node)) && - str.text.length === searchSymbolName.length; + return (isLiteralNameOfPropertyDeclarationOrIndexAccess(str) || isNameOfModuleDeclaration(node) + || isExpressionOfExternalModuleImportEqualsDeclaration(node) + || (isCallExpression(node.parent) && isBindableObjectDefinePropertyCall(node.parent) + && node.parent.arguments[1] === node)) + && str.text.length === searchSymbolName.length; } case SyntaxKind.NumericLiteral: - return isLiteralNameOfPropertyDeclarationOrIndexAccess(node as NumericLiteral) && (node as NumericLiteral).text.length === searchSymbolName.length; + return isLiteralNameOfPropertyDeclarationOrIndexAccess(node as NumericLiteral) + && (node as NumericLiteral).text.length === searchSymbolName.length; case SyntaxKind.DefaultKeyword: return "default".length === searchSymbolName.length; @@ -1807,7 +2258,10 @@ export namespace Core { } } - function getAllReferencesForImportMeta(sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined { + function getAllReferencesForImportMeta( + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + ): SymbolAndEntries[] | undefined { const references = flatMap(sourceFiles, sourceFile => { cancellationToken.throwIfCancellationRequested(); return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, "meta", sourceFile), node => { @@ -1817,22 +2271,37 @@ export namespace Core { } }); }); - return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined; + return references.length + ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined; } - function getAllReferencesForKeyword(sourceFiles: readonly SourceFile[], keywordKind: SyntaxKind, cancellationToken: CancellationToken, filter?: (node: Node) => boolean): SymbolAndEntries[] | undefined { + function getAllReferencesForKeyword( + sourceFiles: readonly SourceFile[], + keywordKind: SyntaxKind, + cancellationToken: CancellationToken, + filter?: (node: Node) => boolean, + ): SymbolAndEntries[] | undefined { const references = flatMap(sourceFiles, sourceFile => { cancellationToken.throwIfCancellationRequested(); - return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), referenceLocation => { - if (referenceLocation.kind === keywordKind && (!filter || filter(referenceLocation))) { - return nodeEntry(referenceLocation); - } - }); + return mapDefined( + getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), + referenceLocation => { + if (referenceLocation.kind === keywordKind && (!filter || filter(referenceLocation))) { + return nodeEntry(referenceLocation); + } + }, + ); }); - return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined; + return references.length + ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined; } - function getReferencesInSourceFile(sourceFile: SourceFile, search: Search, state: State, addReferencesHere = true): void { + function getReferencesInSourceFile( + sourceFile: SourceFile, + search: Search, + state: State, + addReferencesHere = true, + ): void { state.cancellationToken.throwIfCancellationRequested(); return getReferencesInContainer(sourceFile, sourceFile, search, state, addReferencesHere); } @@ -1842,7 +2311,13 @@ export namespace Core { * tuple of(searchSymbol, searchText, searchLocation, and searchMeaning). * searchLocation: a node where the search value */ - function getReferencesInContainer(container: Node, sourceFile: SourceFile, search: Search, state: State, addReferencesHere: boolean): void { + function getReferencesInContainer( + container: Node, + sourceFile: SourceFile, + search: Search, + state: State, + addReferencesHere: boolean, + ): void { if (!state.markSearchedSymbols(sourceFile, search.allSearchSymbols)) { return; } @@ -1856,14 +2331,24 @@ export namespace Core { return !!(getMeaningFromLocation(referenceLocation) & state.searchMeaning); } - function getReferencesAtLocation(sourceFile: SourceFile, position: number, search: Search, state: State, addReferencesHere: boolean): void { + function getReferencesAtLocation( + sourceFile: SourceFile, + position: number, + search: Search, + state: State, + addReferencesHere: boolean, + ): void { const referenceLocation = getTouchingPropertyName(sourceFile, position); if (!isValidReferencePosition(referenceLocation, search.text)) { // This wasn't the start of a token. Check to see if it might be a // match in a comment or string if that's what the caller is asking // for. - if (!state.options.implementations && (state.options.findInStrings && isInString(sourceFile, position) || state.options.findInComments && isInNonReferenceComment(sourceFile, position))) { + if ( + !state.options.implementations + && (state.options.findInStrings && isInString(sourceFile, position) + || state.options.findInComments && isInNonReferenceComment(sourceFile, position)) + ) { // In the case where we're looking inside comments/strings, we don't have // an actual definition. So just use 'undefined' here. Features like // 'Rename' won't care (as they ignore the definitions), and features like @@ -1889,7 +2374,14 @@ export namespace Core { if (isExportSpecifier(parent)) { Debug.assert(referenceLocation.kind === SyntaxKind.Identifier); - getReferencesAtExportSpecifier(referenceLocation as Identifier, referenceSymbol, parent, search, state, addReferencesHere); + getReferencesAtExportSpecifier( + referenceLocation as Identifier, + referenceSymbol, + parent, + search, + state, + addReferencesHere, + ); return; } @@ -1914,9 +2406,11 @@ export namespace Core { } // Use the parent symbol if the location is commonjs require syntax on javascript files only. - if (isInJSFile(referenceLocation) + if ( + isInJSFile(referenceLocation) && isBindingElement(referenceLocation.parent) - && isVariableDeclarationInitializedToBareOrAccessedRequire(referenceLocation.parent.parent.parent)) { + && isVariableDeclarationInitializedToBareOrAccessedRequire(referenceLocation.parent.parent.parent) + ) { referenceSymbol = referenceLocation.parent.symbol; // The parent will not have a symbol if it's an ObjectBindingPattern (when destructuring is used). In // this case, just skip it, since the bound identifiers are not an alias of the import. @@ -1935,18 +2429,28 @@ export namespace Core { addReferencesHere: boolean, alwaysGetReferences?: boolean, ): void { - Debug.assert(!alwaysGetReferences || !!state.options.providePrefixAndSuffixTextForRename, "If alwaysGetReferences is true, then prefix/suffix text must be enabled"); + Debug.assert( + !alwaysGetReferences || !!state.options.providePrefixAndSuffixTextForRename, + "If alwaysGetReferences is true, then prefix/suffix text must be enabled", + ); const { parent, propertyName, name } = exportSpecifier; const exportDeclaration = parent.parent; - const localSymbol = getLocalSymbolForExportSpecifier(referenceLocation, referenceSymbol, exportSpecifier, state.checker); + const localSymbol = getLocalSymbolForExportSpecifier( + referenceLocation, + referenceSymbol, + exportSpecifier, + state.checker, + ); if (!alwaysGetReferences && !search.includes(localSymbol)) { return; } if (!propertyName) { // Don't rename at `export { default } from "m";`. (but do continue to search for imports of the re-export) - if (!(state.options.use === FindReferencesUse.Rename && (name.escapedText === InternalSymbolName.Default))) { + if ( + !(state.options.use === FindReferencesUse.Rename && (name.escapedText === InternalSymbolName.Default)) + ) { addRef(); } } @@ -1957,7 +2461,9 @@ export namespace Core { addRef(); } - if (addReferencesHere && state.options.use !== FindReferencesUse.Rename && state.markSeenReExportRHS(name)) { + if ( + addReferencesHere && state.options.use !== FindReferencesUse.Rename && state.markSeenReExportRHS(name) + ) { addReference(name, Debug.checkDefined(exportSpecifier.symbol), state); } } @@ -1980,7 +2486,10 @@ export namespace Core { } // At `export { x } from "foo"`, also search for the imported symbol `"foo".x`. - if (search.comingFrom !== ImportExport.Export && exportDeclaration.moduleSpecifier && !propertyName && !isForRenameWithPrefixAndSuffixText(state.options)) { + if ( + search.comingFrom !== ImportExport.Export && exportDeclaration.moduleSpecifier && !propertyName + && !isForRenameWithPrefixAndSuffixText(state.options) + ) { const imported = state.checker.getExportSpecifierLocalTargetSymbol(exportSpecifier); if (imported) searchForImportedSymbol(imported, state); } @@ -1990,8 +2499,14 @@ export namespace Core { } } - function getLocalSymbolForExportSpecifier(referenceLocation: Identifier, referenceSymbol: Symbol, exportSpecifier: ExportSpecifier, checker: TypeChecker): Symbol { - return isExportSpecifierAlias(referenceLocation, exportSpecifier) && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier) || referenceSymbol; + function getLocalSymbolForExportSpecifier( + referenceLocation: Identifier, + referenceSymbol: Symbol, + exportSpecifier: ExportSpecifier, + checker: TypeChecker, + ): Symbol { + return isExportSpecifierAlias(referenceLocation, exportSpecifier) + && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier) || referenceSymbol; } function isExportSpecifierAlias(referenceLocation: Identifier, exportSpecifier: ExportSpecifier): boolean { @@ -2008,8 +2523,18 @@ export namespace Core { } } - function getImportOrExportReferences(referenceLocation: Node, referenceSymbol: Symbol, search: Search, state: State): void { - const importOrExport = getImportOrExportSymbol(referenceLocation, referenceSymbol, state.checker, search.comingFrom === ImportExport.Export); + function getImportOrExportReferences( + referenceLocation: Node, + referenceSymbol: Symbol, + search: Search, + state: State, + ): void { + const importOrExport = getImportOrExportSymbol( + referenceLocation, + referenceSymbol, + state.checker, + search.comingFrom === ImportExport.Export, + ); if (!importOrExport) return; const { symbol } = importOrExport; @@ -2028,12 +2553,12 @@ export namespace Core { const shorthandValueSymbol = state.checker.getShorthandAssignmentValueSymbol(valueDeclaration)!; const name = valueDeclaration && getNameOfDeclaration(valueDeclaration); /* - * Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment - * has two meanings: property name and property value. Therefore when we do findAllReference at the position where - * an identifier is declared, the language service should return the position of the variable declaration as well as - * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the - * position of property accessing, the referenceEntry of such position will be handled in the first case. - */ + * Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment + * has two meanings: property name and property value. Therefore when we do findAllReference at the position where + * an identifier is declared, the language service should return the position of the variable declaration as well as + * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the + * position of property accessing, the referenceEntry of such position will be handled in the first case. + */ if (!(flags & SymbolFlags.Transient) && name && search.includes(shorthandValueSymbol)) { addReference(name, shorthandValueSymbol, state); } @@ -2057,7 +2582,12 @@ export namespace Core { } /** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */ - function addConstructorReferences(referenceLocation: Node, sourceFile: SourceFile, search: Search, state: State): void { + function addConstructorReferences( + referenceLocation: Node, + sourceFile: SourceFile, + search: Search, + state: State, + ): void { if (isNewExpressionTarget(referenceLocation)) { addReference(referenceLocation, search.symbol, state); } @@ -2065,7 +2595,10 @@ export namespace Core { const pusher = () => state.referenceAdder(search.symbol); if (isClassLike(referenceLocation.parent)) { - Debug.assert(referenceLocation.kind === SyntaxKind.DefaultKeyword || referenceLocation.parent.name === referenceLocation); + Debug.assert( + referenceLocation.kind === SyntaxKind.DefaultKeyword + || referenceLocation.parent.name === referenceLocation, + ); // This is the class declaration containing the constructor. findOwnConstructorReferences(search.symbol, sourceFile, pusher()); } @@ -2106,7 +2639,11 @@ export namespace Core { * `classSymbol` is the class where the constructor was defined. * Reference the constructor and all calls to `new this()`. */ - function findOwnConstructorReferences(classSymbol: Symbol, sourceFile: SourceFile, addNode: (node: Node) => void): void { + function findOwnConstructorReferences( + classSymbol: Symbol, + sourceFile: SourceFile, + addNode: (node: Node) => void, + ): void { const constructorSymbol = getClassConstructorSymbol(classSymbol); if (constructorSymbol && constructorSymbol.declarations) { for (const decl of constructorSymbol.declarations) { @@ -2193,9 +2730,15 @@ export namespace Core { // If we got a type reference, try and see if the reference applies to any expressions that can implement an interface // Find the first node whose parent isn't a type node -- i.e., the highest type node. - const typeNode = findAncestor(refNode, a => !isQualifiedName(a.parent) && !isTypeNode(a.parent) && !isTypeElement(a.parent))!; + const typeNode = findAncestor( + refNode, + a => !isQualifiedName(a.parent) && !isTypeNode(a.parent) && !isTypeElement(a.parent), + )!; const typeHavingNode = typeNode.parent; - if (hasType(typeHavingNode) && typeHavingNode.type === typeNode && state.markSeenContainingTypeReference(typeHavingNode)) { + if ( + hasType(typeHavingNode) && typeHavingNode.type === typeNode + && state.markSeenContainingTypeReference(typeHavingNode) + ) { if (hasInitializer(typeHavingNode)) { addIfImplementation(typeHavingNode.initializer!); } @@ -2222,7 +2765,8 @@ export namespace Core { function getContainingNodeIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration | undefined { return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingNodeIfInHeritageClause(node.parent) - : isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, or(isClassLike, isInterfaceDeclaration)) : undefined; + : isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, or(isClassLike, isInterfaceDeclaration)) + : undefined; } /** @@ -2262,7 +2806,12 @@ export namespace Core { * @param parent Another class or interface Symbol * @param cachedResults A map of symbol id pairs (i.e. "child,parent") to booleans indicating previous results */ - function explicitlyInheritsFrom(symbol: Symbol, parent: Symbol, cachedResults: Map, checker: TypeChecker): boolean { + function explicitlyInheritsFrom( + symbol: Symbol, + parent: Symbol, + cachedResults: Map, + checker: TypeChecker, + ): boolean { if (symbol === parent) { return true; } @@ -2276,17 +2825,26 @@ export namespace Core { // Set the key so that we don't infinitely recurse cachedResults.set(key, false); - const inherits = !!symbol.declarations && symbol.declarations.some(declaration => - getAllSuperTypeNodes(declaration).some(typeReference => { - const type = checker.getTypeAtLocation(typeReference); - return !!type && !!type.symbol && explicitlyInheritsFrom(type.symbol, parent, cachedResults, checker); - })); + const inherits = !!symbol.declarations + && symbol.declarations.some(declaration => + getAllSuperTypeNodes(declaration).some(typeReference => { + const type = checker.getTypeAtLocation(typeReference); + return !!type && !!type.symbol + && explicitlyInheritsFrom(type.symbol, parent, cachedResults, checker); + }) + ); cachedResults.set(key, inherits); return inherits; } function getReferencesForSuperKeyword(superKeyword: Node): SymbolAndEntries[] | undefined { - let searchSpaceNode: SuperContainer | ClassLikeDeclaration | TypeLiteralNode | InterfaceDeclaration | ObjectLiteralExpression | undefined = getSuperContainer(superKeyword, /*stopOnFunctions*/ false); + let searchSpaceNode: + | SuperContainer + | ClassLikeDeclaration + | TypeLiteralNode + | InterfaceDeclaration + | ObjectLiteralExpression + | undefined = getSuperContainer(superKeyword, /*stopOnFunctions*/ false); if (!searchSpaceNode) { return undefined; } @@ -2319,18 +2877,28 @@ export namespace Core { // If we have a 'super' container, we must have an enclosing class. // Now make sure the owning class is the same as the search-space // and has the same static qualifier as the original 'super's owner. - return container && isStatic(container) === !!staticFlag && container.parent.symbol === searchSpaceNode!.symbol ? nodeEntry(node) : undefined; + return container && isStatic(container) === !!staticFlag + && container.parent.symbol === searchSpaceNode!.symbol ? nodeEntry(node) : undefined; }); return [{ definition: { type: DefinitionKind.Symbol, symbol: searchSpaceNode.symbol }, references }]; } function isParameterName(node: Node) { - return node.kind === SyntaxKind.Identifier && node.parent.kind === SyntaxKind.Parameter && (node.parent as ParameterDeclaration).name === node; + return node.kind === SyntaxKind.Identifier && node.parent.kind === SyntaxKind.Parameter + && (node.parent as ParameterDeclaration).name === node; } - function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined { - let searchSpaceNode: Node = getThisContainer(thisOrSuperKeyword, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + function getReferencesForThisKeyword( + thisOrSuperKeyword: Node, + sourceFiles: readonly SourceFile[], + cancellationToken: CancellationToken, + ): SymbolAndEntries[] | undefined { + let searchSpaceNode: Node = getThisContainer( + thisOrSuperKeyword, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); // Whether 'this' occurs in a static context within a class. let staticFlag = ModifierFlags.Static; @@ -2366,41 +2934,63 @@ export namespace Core { return undefined; } - const references = flatMap(searchSpaceNode.kind === SyntaxKind.SourceFile ? sourceFiles : [searchSpaceNode.getSourceFile()], sourceFile => { - cancellationToken.throwIfCancellationRequested(); - return getPossibleSymbolReferenceNodes(sourceFile, "this", isSourceFile(searchSpaceNode) ? sourceFile : searchSpaceNode).filter(node => { - if (!isThis(node)) { - return false; - } - const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); - if (!canHaveSymbol(container)) return false; - switch (searchSpaceNode.kind) { - case SyntaxKind.FunctionExpression: - case SyntaxKind.FunctionDeclaration: - return (searchSpaceNode as FunctionExpression | FunctionDeclaration).symbol === container.symbol; - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - return isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol; - case SyntaxKind.ClassExpression: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ObjectLiteralExpression: - // Make sure the container belongs to the same class/object literals - // and has the appropriate static modifier from the original container. - return container.parent && canHaveSymbol(container.parent) && (searchSpaceNode as ClassLikeDeclaration | ObjectLiteralExpression).symbol === container.parent.symbol && isStatic(container) === !!staticFlag; - case SyntaxKind.SourceFile: - return container.kind === SyntaxKind.SourceFile && !isExternalModule(container) && !isParameterName(node); - } - }); - }).map(n => nodeEntry(n)); + const references = flatMap( + searchSpaceNode.kind === SyntaxKind.SourceFile ? sourceFiles : [searchSpaceNode.getSourceFile()], + sourceFile => { + cancellationToken.throwIfCancellationRequested(); + return getPossibleSymbolReferenceNodes( + sourceFile, + "this", + isSourceFile(searchSpaceNode) ? sourceFile : searchSpaceNode, + ).filter(node => { + if (!isThis(node)) { + return false; + } + const container = getThisContainer( + node, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); + if (!canHaveSymbol(container)) return false; + switch (searchSpaceNode.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + return (searchSpaceNode as FunctionExpression | FunctionDeclaration).symbol + === container.symbol; + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + return isObjectLiteralMethod(searchSpaceNode) + && searchSpaceNode.symbol === container.symbol; + case SyntaxKind.ClassExpression: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ObjectLiteralExpression: + // Make sure the container belongs to the same class/object literals + // and has the appropriate static modifier from the original container. + return container.parent && canHaveSymbol(container.parent) + && (searchSpaceNode as ClassLikeDeclaration | ObjectLiteralExpression).symbol + === container.parent.symbol + && isStatic(container) === !!staticFlag; + case SyntaxKind.SourceFile: + return container.kind === SyntaxKind.SourceFile && !isExternalModule(container) + && !isParameterName(node); + } + }); + }, + ).map(n => nodeEntry(n)); const thisParameter = firstDefined(references, r => isParameter(r.node.parent) ? r.node : undefined); return [{ definition: { type: DefinitionKind.This, node: thisParameter || thisOrSuperKeyword }, - references + references, }]; } - function getReferencesForStringLiteral(node: StringLiteralLike, sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken): SymbolAndEntries[] { + function getReferencesForStringLiteral( + node: StringLiteralLike, + sourceFiles: readonly SourceFile[], + checker: TypeChecker, + cancellationToken: CancellationToken, + ): SymbolAndEntries[] { const type = getContextualTypeFromParentOrAncestorTypeNode(node, checker); const references = flatMap(sourceFiles, sourceFile => { cancellationToken.throwIfCancellationRequested(); @@ -2413,8 +3003,8 @@ export namespace Core { } } else { - return isNoSubstitutionTemplateLiteral(ref) && !rangeIsOnSingleLine(ref, sourceFile) ? undefined : - nodeEntry(ref, EntryKind.StringLiteral); + return isNoSubstitutionTemplateLiteral(ref) && !rangeIsOnSingleLine(ref, sourceFile) ? undefined + : nodeEntry(ref, EntryKind.StringLiteral); } } }); @@ -2422,15 +3012,27 @@ export namespace Core { return [{ definition: { type: DefinitionKind.String, node }, - references + references, }]; } // For certain symbol kinds, we need to include other symbols in the search set. // This is not needed when searching for re-exports. - function populateSearchSymbolSet(symbol: Symbol, location: Node, checker: TypeChecker, isForRename: boolean, providePrefixAndSuffixText: boolean, implementations: boolean): Symbol[] { + function populateSearchSymbolSet( + symbol: Symbol, + location: Node, + checker: TypeChecker, + isForRename: boolean, + providePrefixAndSuffixText: boolean, + implementations: boolean, + ): Symbol[] { const result: Symbol[] = []; - forEachRelatedSymbol(symbol, location, checker, isForRename, !(isForRename && providePrefixAndSuffixText), + forEachRelatedSymbol( + symbol, + location, + checker, + isForRename, + !(isForRename && providePrefixAndSuffixText), (sym, root, base) => { // static method/property and instance method/property might have the same name. Only include static or only include instance. if (base) { @@ -2439,9 +3041,9 @@ export namespace Core { } } result.push(base || root || sym); - }, - // when try to find implementation, implementations is true, and not allowed to find base class - /*allowBaseTypes*/() => !implementations); + }, // when try to find implementation, implementations is true, and not allowed to find base class + /*allowBaseTypes*/ () => !implementations, + ); return result; } @@ -2449,7 +3051,11 @@ export namespace Core { * @param allowBaseTypes return true means it would try to find in base class or interface. */ function forEachRelatedSymbol( - symbol: Symbol, location: Node, checker: TypeChecker, isForRenamePopulateSearchSymbolSet: boolean, onlyIncludeBindingElementAtReferenceLocation: boolean, + symbol: Symbol, + location: Node, + checker: TypeChecker, + isForRenamePopulateSearchSymbolSet: boolean, + onlyIncludeBindingElementAtReferenceLocation: boolean, /** * @param baseSymbol This symbol means one property/mehtod from base class or interface when it is not null or undefined, */ @@ -2472,7 +3078,12 @@ export namespace Core { const shorthandValueSymbol = checker.getShorthandAssignmentValueSymbol(location.parent); // gets the local symbol if (shorthandValueSymbol && isForRenamePopulateSearchSymbolSet) { // When renaming 'x' in `const o = { x }`, just rename the local variable, not the property. - return cbSymbol(shorthandValueSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedLocalFoundProperty); + return cbSymbol( + shorthandValueSymbol, + /*rootSymbol*/ undefined, + /*baseSymbol*/ undefined, + EntryKind.SearchedLocalFoundProperty, + ); } // If the location is in a context sensitive location (i.e. in an object literal) try @@ -2480,18 +3091,36 @@ export namespace Core { // type to the search set const contextualType = checker.getContextualType(containingObjectLiteralElement.parent); const res = contextualType && firstDefined( - getPropertySymbolsFromContextualType(containingObjectLiteralElement, checker, contextualType, /*unionSymbolOk*/ true), - sym => fromRoot(sym, EntryKind.SearchedPropertyFoundLocal)); + getPropertySymbolsFromContextualType( + containingObjectLiteralElement, + checker, + contextualType, + /*unionSymbolOk*/ true, + ), + sym => fromRoot(sym, EntryKind.SearchedPropertyFoundLocal), + ); if (res) return res; // If the location is name of property symbol from object literal destructuring pattern // Search the property symbol // for ( { property: p2 } of elems) { } const propertySymbol = getPropertySymbolOfDestructuringAssignment(location, checker); - const res1 = propertySymbol && cbSymbol(propertySymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedPropertyFoundLocal); + const res1 = propertySymbol + && cbSymbol( + propertySymbol, + /*rootSymbol*/ undefined, + /*baseSymbol*/ undefined, + EntryKind.SearchedPropertyFoundLocal, + ); if (res1) return res1; - const res2 = shorthandValueSymbol && cbSymbol(shorthandValueSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedLocalFoundProperty); + const res2 = shorthandValueSymbol + && cbSymbol( + shorthandValueSymbol, + /*rootSymbol*/ undefined, + /*baseSymbol*/ undefined, + EntryKind.SearchedLocalFoundProperty, + ); if (res2) return res2; } @@ -2505,10 +3134,19 @@ export namespace Core { const res = fromRoot(symbol); if (res) return res; - if (symbol.valueDeclaration && isParameterPropertyDeclaration(symbol.valueDeclaration, symbol.valueDeclaration.parent)) { + if ( + symbol.valueDeclaration + && isParameterPropertyDeclaration(symbol.valueDeclaration, symbol.valueDeclaration.parent) + ) { // For a parameter property, now try on the other symbol (property if this was a parameter, parameter if this was a property). - const paramProps = checker.getSymbolsOfParameterPropertyDeclaration(cast(symbol.valueDeclaration, isParameter), symbol.name); - Debug.assert(paramProps.length === 2 && !!(paramProps[0].flags & SymbolFlags.FunctionScopedVariable) && !!(paramProps[1].flags & SymbolFlags.Property)); // is [parameter, property] + const paramProps = checker.getSymbolsOfParameterPropertyDeclaration( + cast(symbol.valueDeclaration, isParameter), + symbol.name, + ); + Debug.assert( + paramProps.length === 2 && !!(paramProps[0].flags & SymbolFlags.FunctionScopedVariable) + && !!(paramProps[1].flags & SymbolFlags.Property), + ); // is [parameter, property] return fromRoot(symbol.flags & SymbolFlags.FunctionScopedVariable ? paramProps[1] : paramProps[0]); } @@ -2526,12 +3164,17 @@ export namespace Core { if (!isForRenamePopulateSearchSymbolSet) { let bindingElementPropertySymbol: Symbol | undefined; if (onlyIncludeBindingElementAtReferenceLocation) { - bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName(location.parent) ? getPropertySymbolFromBindingElement(checker, location.parent) : undefined; + bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName(location.parent) + ? getPropertySymbolFromBindingElement(checker, location.parent) : undefined; } else { - bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker); + bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName( + symbol, + checker, + ); } - return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal); + return bindingElementPropertySymbol + && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal); } Debug.assert(isForRenamePopulateSearchSymbolSet); @@ -2540,8 +3183,12 @@ export namespace Core { const includeOriginalSymbolOfBindingElement = onlyIncludeBindingElementAtReferenceLocation; if (includeOriginalSymbolOfBindingElement) { - const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker); - return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal); + const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName( + symbol, + checker, + ); + return bindingElementPropertySymbol + && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal); } function fromRoot(sym: Symbol, kind?: NodeEntryKind): T | undefined { @@ -2551,15 +3198,27 @@ export namespace Core { // If the symbol is an instantiation from a another symbol (e.g. widened symbol): // - In populateSearchSymbolsSet, add the root the list // - In findRelatedSymbol, return the source symbol if that is in the search. (Do not return the instantiation symbol.) - return firstDefined(checker.getRootSymbols(sym), rootSymbol => - cbSymbol(sym, rootSymbol, /*baseSymbol*/ undefined, kind) - // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions - || (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface) && allowBaseTypes(rootSymbol) - ? getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker, base => cbSymbol(sym, rootSymbol, base, kind)) - : undefined)); - } - - function getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol: Symbol, checker: TypeChecker): Symbol | undefined { + return firstDefined( + checker.getRootSymbols(sym), + rootSymbol => + cbSymbol(sym, rootSymbol, /*baseSymbol*/ undefined, kind) + // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions + || (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface) + && allowBaseTypes(rootSymbol) + ? getPropertySymbolsFromBaseTypes( + rootSymbol.parent, + rootSymbol.name, + checker, + base => cbSymbol(sym, rootSymbol, base, kind), + ) + : undefined), + ); + } + + function getPropertySymbolOfObjectBindingPatternWithoutPropertyName( + symbol: Symbol, + checker: TypeChecker, + ): Symbol | undefined { const bindingElement = getDeclarationOfKind(symbol, SyntaxKind.BindingElement); if (bindingElement && isObjectBindingElementWithoutPropertyName(bindingElement)) { return getPropertySymbolFromBindingElement(checker, bindingElement); @@ -2575,7 +3234,12 @@ export namespace Core { * @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol. * The value of previousIterationSymbol is undefined when the function is first called. */ - function getPropertySymbolsFromBaseTypes(symbol: Symbol, propertyName: string, checker: TypeChecker, cb: (symbol: Symbol) => T | undefined): T | undefined { + function getPropertySymbolsFromBaseTypes( + symbol: Symbol, + propertyName: string, + checker: TypeChecker, + cb: (symbol: Symbol) => T | undefined, + ): T | undefined { const seen = new Map(); return recur(symbol); @@ -2584,14 +3248,21 @@ export namespace Core { // interface C extends C { // /*findRef*/propName: string; // } - if (!(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol))) return; + if ( + !(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol)) + ) return; - return firstDefined(symbol.declarations, declaration => firstDefined(getAllSuperTypeNodes(declaration), typeReference => { - const type = checker.getTypeAtLocation(typeReference); - const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName); - // Visit the typeReference as well to see if it directly or indirectly uses that property - return type && propertySymbol && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type.symbol)); - })); + return firstDefined( + symbol.declarations, + declaration => + firstDefined(getAllSuperTypeNodes(declaration), typeReference => { + const type = checker.getTypeAtLocation(typeReference); + const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName); + // Visit the typeReference as well to see if it directly or indirectly uses that property + return type && propertySymbol + && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type.symbol)); + }), + ); } } @@ -2606,10 +3277,20 @@ export namespace Core { return !!(modifierFlags & ModifierFlags.Static); } - function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): RelatedSymbol | undefined { + function getRelatedSymbol( + search: Search, + referenceSymbol: Symbol, + referenceLocation: Node, + state: State, + ): RelatedSymbol | undefined { const { checker } = state; - return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker, /*isForRenamePopulateSearchSymbolSet*/ false, - /*onlyIncludeBindingElementAtReferenceLocation*/ state.options.use !== FindReferencesUse.Rename || !!state.options.providePrefixAndSuffixTextForRename, + return forEachRelatedSymbol( + referenceSymbol, + referenceLocation, + checker, + /*isForRenamePopulateSearchSymbolSet*/ false, + /*onlyIncludeBindingElementAtReferenceLocation*/ state.options.use !== FindReferencesUse.Rename + || !!state.options.providePrefixAndSuffixTextForRename, (sym, rootSymbol, baseSymbol, kind): RelatedSymbol | undefined => { // check whether the symbol used to search itself is just the searched one. if (baseSymbol) { @@ -2624,7 +3305,10 @@ export namespace Core { : undefined; }, /*allowBaseTypes*/ rootSymbol => - !(search.parents && !search.parents.some(parent => explicitlyInheritsFrom(rootSymbol.parent!, parent, state.inheritsFromCache, checker))) + !(search.parents + && !search.parents.some(parent => + explicitlyInheritsFrom(rootSymbol.parent!, parent, state.inheritsFromCache, checker) + )), ); } @@ -2664,13 +3348,17 @@ export namespace Core { } function isImplementation(node: Node): boolean { - return !!(node.flags & NodeFlags.Ambient) ? !(isInterfaceDeclaration(node) || isTypeAliasDeclaration(node)) : - (isVariableLike(node) ? hasInitializer(node) : - isFunctionLikeDeclaration(node) ? !!node.body : - isClassLike(node) || isModuleOrEnumDeclaration(node)); + return !!(node.flags & NodeFlags.Ambient) ? !(isInterfaceDeclaration(node) || isTypeAliasDeclaration(node)) + : (isVariableLike(node) ? hasInitializer(node) + : isFunctionLikeDeclaration(node) ? !!node.body + : isClassLike(node) || isModuleOrEnumDeclaration(node)); } - export function getReferenceEntriesForShorthandPropertyAssignment(node: Node, checker: TypeChecker, addReference: (node: Node) => void): void { + export function getReferenceEntriesForShorthandPropertyAssignment( + node: Node, + checker: TypeChecker, + addReference: (node: Node) => void, + ): void { const refSymbol = checker.getSymbolAtLocation(node)!; const shorthandSymbol = checker.getShorthandAssignmentValueSymbol(refSymbol.valueDeclaration); @@ -2703,11 +3391,20 @@ export namespace Core { * symbol may have a different parent symbol if the local type's symbol does not declare the property * being accessed (i.e. it is declared in some parent class or interface) */ - function getParentSymbolsOfPropertyAccess(location: Node, symbol: Symbol, checker: TypeChecker): readonly Symbol[] | undefined { - const propertyAccessExpression = isRightSideOfPropertyAccess(location) ? location.parent as PropertyAccessExpression : undefined; + function getParentSymbolsOfPropertyAccess( + location: Node, + symbol: Symbol, + checker: TypeChecker, + ): readonly Symbol[] | undefined { + const propertyAccessExpression = isRightSideOfPropertyAccess(location) + ? location.parent as PropertyAccessExpression : undefined; const lhsType = propertyAccessExpression && checker.getTypeAtLocation(propertyAccessExpression.expression); - const res = mapDefined(lhsType && (lhsType.isUnionOrIntersection() ? lhsType.types : lhsType.symbol === symbol.parent ? undefined : [lhsType]), t => - t.symbol && t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? t.symbol : undefined); + const res = mapDefined( + lhsType + && (lhsType.isUnionOrIntersection() ? lhsType.types + : lhsType.symbol === symbol.parent ? undefined : [lhsType]), + t => t.symbol && t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? t.symbol : undefined, + ); return res.length === 0 ? undefined : res; } diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 0f066e4807ebe..846cc4be16fc6 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -112,7 +112,7 @@ export function createTextRangeWithKind(pos: number, end: } const enum Constants { - Unknown = -1 + Unknown = -1, } /* @@ -147,7 +147,6 @@ interface DynamicIndentation { * foo: { indentation: 0, delta: 4 } * bar: { indentation: foo.indentation + foo.delta = 4, delta: 4} however 'foo' and 'bar' are on the same line * so bar inherits indentation from foo and bar.delta will be 4 - * */ getDelta(child: TextRangeWithKind): number; /** @@ -182,19 +181,32 @@ export function formatOnEnter(position: number, sourceFile: SourceFile, formatCo // get start position for the previous line pos: getStartPositionOfLine(line - 1, sourceFile), // end value is exclusive so add 1 to the result - end: endOfFormatSpan + 1 + end: endOfFormatSpan + 1, }; return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatOnEnter); } /** @internal */ -export function formatOnSemicolon(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { +export function formatOnSemicolon( + position: number, + sourceFile: SourceFile, + formatContext: FormatContext, +): TextChange[] { const semicolon = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.SemicolonToken, sourceFile); - return formatNodeLines(findOutermostNodeWithinListLevel(semicolon), sourceFile, formatContext, FormattingRequestKind.FormatOnSemicolon); + return formatNodeLines( + findOutermostNodeWithinListLevel(semicolon), + sourceFile, + formatContext, + FormattingRequestKind.FormatOnSemicolon, + ); } /** @internal */ -export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { +export function formatOnOpeningCurly( + position: number, + sourceFile: SourceFile, + formatContext: FormatContext, +): TextChange[] { const openingCurly = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.OpenBraceToken, sourceFile); if (!openingCurly) { return []; @@ -216,29 +228,43 @@ export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, f */ const textRange: TextRange = { pos: getLineStartPositionForPosition(outermostNode!.getStart(sourceFile), sourceFile), // TODO: GH#18217 - end: position + end: position, }; return formatSpan(textRange, sourceFile, formatContext, FormattingRequestKind.FormatOnOpeningCurlyBrace); } /** @internal */ -export function formatOnClosingCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { +export function formatOnClosingCurly( + position: number, + sourceFile: SourceFile, + formatContext: FormatContext, +): TextChange[] { const precedingToken = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.CloseBraceToken, sourceFile); - return formatNodeLines(findOutermostNodeWithinListLevel(precedingToken), sourceFile, formatContext, FormattingRequestKind.FormatOnClosingCurlyBrace); + return formatNodeLines( + findOutermostNodeWithinListLevel(precedingToken), + sourceFile, + formatContext, + FormattingRequestKind.FormatOnClosingCurlyBrace, + ); } /** @internal */ export function formatDocument(sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { const span = { pos: 0, - end: sourceFile.text.length + end: sourceFile.text.length, }; return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatDocument); } /** @internal */ -export function formatSelection(start: number, end: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] { +export function formatSelection( + start: number, + end: number, + sourceFile: SourceFile, + formatContext: FormatContext, +): TextChange[] { // format from the beginning of the line const span = { pos: getLineStartPositionForPosition(start, sourceFile), @@ -251,12 +277,16 @@ export function formatSelection(start: number, end: number, sourceFile: SourceFi * Validating `expectedTokenKind` ensures the token was typed in the context we expect (eg: not a comment). * @param expectedTokenKind The kind of the last token constituting the desired parent node. */ -function findImmediatelyPrecedingTokenOfKind(end: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node | undefined { +function findImmediatelyPrecedingTokenOfKind( + end: number, + expectedTokenKind: SyntaxKind, + sourceFile: SourceFile, +): Node | undefined { const precedingToken = findPrecedingToken(end, sourceFile); - return precedingToken && precedingToken.kind === expectedTokenKind && end === precedingToken.getEnd() ? - precedingToken : - undefined; + return precedingToken && precedingToken.kind === expectedTokenKind && end === precedingToken.getEnd() + ? precedingToken + : undefined; } /** @@ -274,10 +304,12 @@ function findImmediatelyPrecedingTokenOfKind(end: number, expectedTokenKind: Syn */ function findOutermostNodeWithinListLevel(node: Node | undefined) { let current = node; - while (current && - current.parent && - current.parent.end === node!.end && - !isListElement(current.parent, current)) { + while ( + current + && current.parent + && current.parent.end === node!.end + && !isListElement(current.parent, current) + ) { current = current.parent; } @@ -326,7 +358,10 @@ function findEnclosingNode(range: TextRange, sourceFile: SourceFile): Node { * This function will return a predicate that for a given text range will tell * if there are any parse errors that overlap with the range. */ -function prepareRangeContainsErrorFunction(errors: readonly Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean { +function prepareRangeContainsErrorFunction( + errors: readonly Diagnostic[], + originalRange: TextRange, +): (r: TextRange) => boolean { if (!errors.length) { return rangeHasNoErrors; } @@ -433,34 +468,53 @@ function getOwnOrInheritedDelta(n: Node, options: FormatCodeSettings, sourceFile } /** @internal */ -export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, formatContext: FormatContext): TextChange[] { +export function formatNodeGivenIndentation( + node: Node, + sourceFileLike: SourceFileLike, + languageVariant: LanguageVariant, + initialIndentation: number, + delta: number, + formatContext: FormatContext, +): TextChange[] { const range = { pos: node.pos, end: node.end }; - return getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end, scanner => formatSpanWorker( - range, - node, - initialIndentation, - delta, - scanner, - formatContext, - FormattingRequestKind.FormatSelection, - _ => false, // assume that node does not have any errors - sourceFileLike)); + return getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end, scanner => + formatSpanWorker( + range, + node, + initialIndentation, + delta, + scanner, + formatContext, + FormattingRequestKind.FormatSelection, + _ => false, // assume that node does not have any errors + sourceFileLike, + )); } -function formatNodeLines(node: Node | undefined, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] { +function formatNodeLines( + node: Node | undefined, + sourceFile: SourceFile, + formatContext: FormatContext, + requestKind: FormattingRequestKind, +): TextChange[] { if (!node) { return []; } const span = { pos: getLineStartPositionForPosition(node.getStart(sourceFile), sourceFile), - end: node.end + end: node.end, }; return formatSpan(span, sourceFile, formatContext, requestKind); } -function formatSpan(originalRange: TextRange, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] { +function formatSpan( + originalRange: TextRange, + sourceFile: SourceFile, + formatContext: FormatContext, + requestKind: FormattingRequestKind, +): TextChange[] { // find the smallest node that fully wraps the range and compute the initial indentation for the node const enclosingNode = findEnclosingNode(originalRange, sourceFile); return getFormattingScanner( @@ -468,16 +522,19 @@ function formatSpan(originalRange: TextRange, sourceFile: SourceFile, formatCont sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, - scanner => formatSpanWorker( - originalRange, - enclosingNode, - SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options), - getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile), - scanner, - formatContext, - requestKind, - prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange), - sourceFile)); + scanner => + formatSpanWorker( + originalRange, + enclosingNode, + SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options), + getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile), + scanner, + formatContext, + requestKind, + prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange), + sourceFile, + ), + ); } function formatSpanWorker( @@ -489,8 +546,8 @@ function formatSpanWorker( { options, getRules, host }: FormatContext, requestKind: FormattingRequestKind, rangeContainsError: (r: TextRange) => boolean, - sourceFile: SourceFileLike): TextChange[] { - + sourceFile: SourceFileLike, +): TextChange[] { // formatting context is used by rules provider const formattingContext = new FormattingContext(sourceFile, requestKind, options); let previousRangeTriviaEnd: number; @@ -509,7 +566,8 @@ function formatSpanWorker( const startLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile)).line; let undecoratedStartLine = startLine; if (hasDecorators(enclosingNode)) { - undecoratedStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(enclosingNode, sourceFile)).line; + undecoratedStartLine = + sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(enclosingNode, sourceFile)).line; } processNode(enclosingNode, enclosingNode, startLine, undecoratedStartLine, initialIndentation, delta); @@ -520,15 +578,25 @@ function formatSpanWorker( // range and thus won't get processed. So we process those remaining trivia items here. const remainingTrivia = formattingScanner.getCurrentLeadingTrivia(); if (remainingTrivia) { - const indentation = SmartIndenter.nodeWillIndentChild(options, enclosingNode, /*child*/ undefined, sourceFile, /*indentByDefault*/ false) + const indentation = SmartIndenter.nodeWillIndentChild( + options, + enclosingNode, + /*child*/ undefined, + sourceFile, + /*indentByDefault*/ false, + ) ? initialIndentation + options.indentSize! : initialIndentation; - indentTriviaItems(remainingTrivia, indentation, /*indentNextTokenOrTrivia*/ true, - item => { - processRange(item, sourceFile.getLineAndCharacterOfPosition(item.pos), enclosingNode, enclosingNode, /*dynamicIndentation*/ undefined!); - insertIndentation(item.pos, indentation, /*lineAdded*/ false); - } - ); + indentTriviaItems(remainingTrivia, indentation, /*indentNextTokenOrTrivia*/ true, item => { + processRange( + item, + sourceFile.getLineAndCharacterOfPosition(item.pos), + enclosingNode, + enclosingNode, + /*dynamicIndentation*/ undefined!, + ); + insertIndentation(item.pos, indentation, /*lineAdded*/ false); + }); if (options.trimTrailingWhitespace !== false) { trimTrailingWhitespacesForRemainingRange(remainingTrivia); } @@ -545,10 +613,9 @@ function formatSpanWorker( // inclusive. We would expect a format-selection would delete the space (if rules apply), // but in order to do that, we need to process the pair ["{", "}"], but we stopped processing // just before getting there. This block handles this trailing edit. - const tokenInfo = - formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() : - formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token : - undefined; + const tokenInfo = formattingScanner.isOnEOF() ? formattingScanner.readEOFTokenRange() + : formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(enclosingNode).token + : undefined; if (tokenInfo && tokenInfo.pos === previousRangeTriviaEnd!) { // We need to check that tokenInfo and previousRange are contiguous: the `originalRange` @@ -570,7 +637,8 @@ function formatSpanWorker( previousRangeStartLine!, previousParent!, parent, - /*dynamicIndentation*/ undefined); + /*dynamicIndentation*/ undefined, + ); } } @@ -585,15 +653,17 @@ function formatSpanWorker( * If list element is in the range - its indentation will be equal * to inherited indentation from its predecessors. */ - function tryComputeIndentationForListItem(startPos: number, + function tryComputeIndentationForListItem( + startPos: number, endPos: number, parentStartLine: number, range: TextRange, - inheritedIndentation: number): number { - - if (rangeOverlapsWithStartEnd(range, startPos, endPos) || - rangeContainsStartEnd(range, startPos, endPos) /* Not to miss zero-range nodes e.g. JsxText */) { - + inheritedIndentation: number, + ): number { + if ( + rangeOverlapsWithStartEnd(range, startPos, endPos) + || rangeContainsStartEnd(range, startPos, endPos) /* Not to miss zero-range nodes e.g. JsxText */ + ) { if (inheritedIndentation !== Constants.Unknown) { return inheritedIndentation; } @@ -619,8 +689,8 @@ function formatSpanWorker( inheritedIndentation: number, parent: Node, parentDynamicIndentation: DynamicIndentation, - effectiveParentStartLine: number - ): { indentation: number, delta: number; } { + effectiveParentStartLine: number, + ): { indentation: number; delta: number; } { const delta = SmartIndenter.shouldIndentChildNode(options, node) ? options.indentSize! : 0; if (effectiveParentStartLine === startLine) { @@ -628,8 +698,9 @@ function formatSpanWorker( // - inherit indentation from the parent // - push children if either parent of node itself has non-zero delta return { - indentation: startLine === lastIndentedLine ? indentationOnLastIndentedLine : parentDynamicIndentation.getIndentation(), - delta: Math.min(options.indentSize!, parentDynamicIndentation.getDelta(node) + delta) + indentation: startLine === lastIndentedLine ? indentationOnLastIndentedLine + : parentDynamicIndentation.getIndentation(), + delta: Math.min(options.indentSize!, parentDynamicIndentation.getDelta(node) + delta), }; } else if (inheritedIndentation === Constants.Unknown) { @@ -639,14 +710,17 @@ function formatSpanWorker( return { indentation: indentationOnLastIndentedLine, delta: parentDynamicIndentation.getDelta(node) }; } else if ( - SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile) || - SmartIndenter.childIsUnindentedBranchOfConditionalExpression(parent, node, startLine, sourceFile) || - SmartIndenter.argumentStartsOnSameLineAsPreviousArgument(parent, node, startLine, sourceFile) + SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile) + || SmartIndenter.childIsUnindentedBranchOfConditionalExpression(parent, node, startLine, sourceFile) + || SmartIndenter.argumentStartsOnSameLineAsPreviousArgument(parent, node, startLine, sourceFile) ) { return { indentation: parentDynamicIndentation.getIndentation(), delta }; } else { - return { indentation: parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta(node), delta }; + return { + indentation: parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta(node), + delta, + }; } } else { @@ -661,12 +735,18 @@ function formatSpanWorker( } switch (node.kind) { - case SyntaxKind.ClassDeclaration: return SyntaxKind.ClassKeyword; - case SyntaxKind.InterfaceDeclaration: return SyntaxKind.InterfaceKeyword; - case SyntaxKind.FunctionDeclaration: return SyntaxKind.FunctionKeyword; - case SyntaxKind.EnumDeclaration: return SyntaxKind.EnumDeclaration; - case SyntaxKind.GetAccessor: return SyntaxKind.GetKeyword; - case SyntaxKind.SetAccessor: return SyntaxKind.SetKeyword; + case SyntaxKind.ClassDeclaration: + return SyntaxKind.ClassKeyword; + case SyntaxKind.InterfaceDeclaration: + return SyntaxKind.InterfaceKeyword; + case SyntaxKind.FunctionDeclaration: + return SyntaxKind.FunctionKeyword; + case SyntaxKind.EnumDeclaration: + return SyntaxKind.EnumDeclaration; + case SyntaxKind.GetAccessor: + return SyntaxKind.GetKeyword; + case SyntaxKind.SetAccessor: + return SyntaxKind.SetKeyword; case SyntaxKind.MethodDeclaration: if ((node as MethodDeclaration).asteriskToken) { return SyntaxKind.AsteriskToken; @@ -682,7 +762,12 @@ function formatSpanWorker( } } - function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, delta: number): DynamicIndentation { + function getDynamicIndentation( + node: Node, + nodeStartLine: number, + indentation: number, + delta: number, + ): DynamicIndentation { return { getIndentationForComment: (kind, tokenIndentation, container) => { switch (kind) { @@ -708,7 +793,8 @@ function formatSpanWorker( // var a = xValue // > yValue; getIndentationForToken: (line, kind, container, suppressDelta) => - !suppressDelta && shouldAddDelta(line, kind, container) ? indentation + getDelta(container) : indentation, + !suppressDelta && shouldAddDelta(line, kind, container) ? indentation + getDelta(container) + : indentation, getIndentation: () => indentation, getDelta, recomputeIndentation: (lineAdded, parent) => { @@ -716,7 +802,7 @@ function formatSpanWorker( indentation += lineAdded ? options.indentSize! : -options.indentSize!; delta = SmartIndenter.shouldIndentChildNode(options, node) ? options.indentSize! : 0; } - } + }, }; function shouldAddDelta(line: number, kind: SyntaxKind, container: Node): boolean { @@ -753,11 +839,19 @@ function formatSpanWorker( function getDelta(child: TextRangeWithKind) { // Delta value should be zero when the node explicitly prevents indentation of the child node - return SmartIndenter.nodeWillIndentChild(options, node, child, sourceFile, /*indentByDefault*/ true) ? delta : 0; + return SmartIndenter.nodeWillIndentChild(options, node, child, sourceFile, /*indentByDefault*/ true) ? delta + : 0; } } - function processNode(node: Node, contextNode: Node, nodeStartLine: number, undecoratedNodeStartLine: number, indentation: number, delta: number) { + function processNode( + node: Node, + contextNode: Node, + nodeStartLine: number, + undecoratedNodeStartLine: number, + indentation: number, + delta: number, + ) { if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) { return; } @@ -783,11 +877,20 @@ function formatSpanWorker( forEachChild( node, child => { - processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, undecoratedNodeStartLine, /*isListItem*/ false); + processChildNode( + child, + /*inheritedIndentation*/ Constants.Unknown, + node, + nodeDynamicIndentation, + nodeStartLine, + undecoratedNodeStartLine, + /*isListItem*/ false, + ); }, nodes => { processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation); - }); + }, + ); // proceed any tokens in the node that are located after child nodes while (formattingScanner.isOnToken() && formattingScanner.getTokenFullStart() < originalRange.end) { @@ -806,7 +909,8 @@ function formatSpanWorker( parentStartLine: number, undecoratedParentStartLine: number, isListItem: boolean, - isFirstListItem?: boolean): number { + isFirstListItem?: boolean, + ): number { Debug.assert(!nodeIsSynthesized(child)); if (nodeIsMissing(child) || isGrammarError(parent, child)) { @@ -819,14 +923,21 @@ function formatSpanWorker( let undecoratedChildStartLine = childStartLine; if (hasDecorators(child)) { - undecoratedChildStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(child, sourceFile)).line; + undecoratedChildStartLine = + sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(child, sourceFile)).line; } // if child is a list item - try to get its indentation, only if parent is within the original range. let childIndentationAmount = Constants.Unknown; if (isListItem && rangeContainsRange(originalRange, parent)) { - childIndentationAmount = tryComputeIndentationForListItem(childStartPos, child.end, parentStartLine, originalRange, inheritedIndentation); + childIndentationAmount = tryComputeIndentationForListItem( + childStartPos, + child.end, + parentStartLine, + originalRange, + inheritedIndentation, + ); if (childIndentationAmount !== Constants.Unknown) { inheritedIndentation = childIndentationAmount; } @@ -876,24 +987,44 @@ function formatSpanWorker( } } - const effectiveParentStartLine = child.kind === SyntaxKind.Decorator ? childStartLine : undecoratedParentStartLine; - const childIndentation = computeIndentation(child, childStartLine, childIndentationAmount, node, parentDynamicIndentation, effectiveParentStartLine); - - processNode(child, childContextNode, childStartLine, undecoratedChildStartLine, childIndentation.indentation, childIndentation.delta); + const effectiveParentStartLine = child.kind === SyntaxKind.Decorator ? childStartLine + : undecoratedParentStartLine; + const childIndentation = computeIndentation( + child, + childStartLine, + childIndentationAmount, + node, + parentDynamicIndentation, + effectiveParentStartLine, + ); + + processNode( + child, + childContextNode, + childStartLine, + undecoratedChildStartLine, + childIndentation.indentation, + childIndentation.delta, + ); childContextNode = node; - if (isFirstListItem && parent.kind === SyntaxKind.ArrayLiteralExpression && inheritedIndentation === Constants.Unknown) { + if ( + isFirstListItem && parent.kind === SyntaxKind.ArrayLiteralExpression + && inheritedIndentation === Constants.Unknown + ) { inheritedIndentation = childIndentation.indentation; } return inheritedIndentation; } - function processChildNodes(nodes: NodeArray, + function processChildNodes( + nodes: NodeArray, parent: Node, parentStartLine: number, - parentDynamicIndentation: DynamicIndentation): void { + parentDynamicIndentation: DynamicIndentation, + ): void { Debug.assert(isNodeArray(nodes)); Debug.assert(!nodeIsSynthesized(nodes)); @@ -933,10 +1064,20 @@ function formatSpanWorker( } else { const startLinePosition = getLineStartPositionForPosition(tokenInfo.token.pos, sourceFile); - indentationOnListStartToken = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, tokenInfo.token.pos, sourceFile, options); + indentationOnListStartToken = SmartIndenter.findFirstNonWhitespaceColumn( + startLinePosition, + tokenInfo.token.pos, + sourceFile, + options, + ); } - listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentationOnListStartToken, options.indentSize!); // TODO: GH#18217 + listDynamicIndentation = getDynamicIndentation( + parent, + parentStartLine, + indentationOnListStartToken, + options.indentSize!, + ); // TODO: GH#18217 } else { // consume any tokens that precede the list as child elements of 'node' using its indentation scope @@ -948,11 +1089,23 @@ function formatSpanWorker( let inheritedIndentation = Constants.Unknown; for (let i = 0; i < nodes.length; i++) { const child = nodes[i]; - inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, startLine, /*isListItem*/ true, /*isFirstListItem*/ i === 0); + inheritedIndentation = processChildNode( + child, + inheritedIndentation, + node, + listDynamicIndentation, + startLine, + startLine, + /*isListItem*/ true, + /*isFirstListItem*/ i === 0, + ); } const listEndToken = getCloseTokenForOpenToken(listStartToken); - if (listEndToken !== SyntaxKind.Unknown && formattingScanner.isOnToken() && formattingScanner.getTokenFullStart() < originalRange.end) { + if ( + listEndToken !== SyntaxKind.Unknown && formattingScanner.isOnToken() + && formattingScanner.getTokenFullStart() < originalRange.end + ) { let tokenInfo: TokenInfo | undefined = formattingScanner.readTokenInfo(parent); if (tokenInfo.token.kind === SyntaxKind.CommaToken) { // consume the comma @@ -966,12 +1119,24 @@ function formatSpanWorker( // without this check close paren will be interpreted as list end token for function expression which is wrong if (tokenInfo && tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) { // consume list end token - consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent, /*isListEndToken*/ true); + consumeTokenAndAdvanceScanner( + tokenInfo, + parent, + listDynamicIndentation, + parent, + /*isListEndToken*/ true, + ); } } } - function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container: Node, isListEndToken?: boolean): void { + function consumeTokenAndAdvanceScanner( + currentTokenInfo: TokenInfo, + parent: Node, + dynamicIndentation: DynamicIndentation, + container: Node, + isListEndToken?: boolean, + ): void { Debug.assert(rangeContainsRange(parent, currentTokenInfo.token)); const lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine(); @@ -989,12 +1154,19 @@ function formatSpanWorker( const rangeHasError = rangeContainsError(currentTokenInfo.token); // save previousRange since processRange will overwrite this value with current one const savePreviousRange = previousRange; - lineAction = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation); + lineAction = processRange( + currentTokenInfo.token, + tokenStart, + parent, + childContextNode, + dynamicIndentation, + ); // do not indent comments\token if token range overlaps with some error if (!rangeHasError) { if (lineAction === LineAction.None) { // indent token only if end line of previous range does not match start line of the token - const prevEndLine = savePreviousRange && sourceFile.getLineAndCharacterOfPosition(savePreviousRange.end).line; + const prevEndLine = savePreviousRange + && sourceFile.getLineAndCharacterOfPosition(savePreviousRange.end).line; indentToken = lastTriviaWasNewLine && tokenStart.line !== prevEndLine; } else { @@ -1009,20 +1181,37 @@ function formatSpanWorker( } if (indentToken) { - const tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) ? - dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container, !!isListEndToken) : - Constants.Unknown; + const tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) + ? dynamicIndentation.getIndentationForToken( + tokenStart.line, + currentTokenInfo.token.kind, + container, + !!isListEndToken, + ) + : Constants.Unknown; let indentNextTokenOrTrivia = true; if (currentTokenInfo.leadingTrivia) { - const commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind, tokenIndentation, container); - indentNextTokenOrTrivia = indentTriviaItems(currentTokenInfo.leadingTrivia, commentIndentation, indentNextTokenOrTrivia, - item => insertIndentation(item.pos, commentIndentation, /*lineAdded*/ false)); + const commentIndentation = dynamicIndentation.getIndentationForComment( + currentTokenInfo.token.kind, + tokenIndentation, + container, + ); + indentNextTokenOrTrivia = indentTriviaItems( + currentTokenInfo.leadingTrivia, + commentIndentation, + indentNextTokenOrTrivia, + item => insertIndentation(item.pos, commentIndentation, /*lineAdded*/ false), + ); } // indent token only if is it is in target range and does not overlap with any error ranges if (tokenIndentation !== Constants.Unknown && indentNextTokenOrTrivia) { - insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAction === LineAction.LineAdded); + insertIndentation( + currentTokenInfo.token.pos, + tokenIndentation, + lineAction === LineAction.LineAdded, + ); lastIndentedLine = tokenStart.line; indentationOnLastIndentedLine = tokenIndentation; @@ -1039,13 +1228,18 @@ function formatSpanWorker( trivia: TextRangeWithKind[], commentIndentation: number, indentNextTokenOrTrivia: boolean, - indentSingleLine: (item: TextRangeWithKind) => void) { + indentSingleLine: (item: TextRangeWithKind) => void, + ) { for (const triviaItem of trivia) { const triviaInRange = rangeContainsRange(originalRange, triviaItem); switch (triviaItem.kind) { case SyntaxKind.MultiLineCommentTrivia: if (triviaInRange) { - indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia); + indentMultilineComment( + triviaItem, + commentIndentation, + /*firstLineIsIndented*/ !indentNextTokenOrTrivia, + ); } indentNextTokenOrTrivia = false; break; @@ -1063,7 +1257,12 @@ function formatSpanWorker( return indentNextTokenOrTrivia; } - function processTrivia(trivia: TextRangeWithKind[], parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): void { + function processTrivia( + trivia: TextRangeWithKind[], + parent: Node, + contextNode: Node, + dynamicIndentation: DynamicIndentation, + ): void { for (const triviaItem of trivia) { if (isComment(triviaItem.kind) && rangeContainsRange(originalRange, triviaItem)) { const triviaItemStart = sourceFile.getLineAndCharacterOfPosition(triviaItem.pos); @@ -1072,12 +1271,13 @@ function formatSpanWorker( } } - function processRange(range: TextRangeWithKind, + function processRange( + range: TextRangeWithKind, rangeStart: LineAndCharacter, parent: Node, contextNode: Node, - dynamicIndentation: DynamicIndentation): LineAction { - + dynamicIndentation: DynamicIndentation, + ): LineAction { const rangeHasError = rangeContainsError(range); let lineAction = LineAction.None; if (!rangeHasError) { @@ -1087,8 +1287,16 @@ function formatSpanWorker( trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line); } else { - lineAction = - processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation); + lineAction = processPair( + range, + rangeStart.line, + parent, + previousRange, + previousRangeStartLine, + previousParent, + contextNode, + dynamicIndentation, + ); } } @@ -1100,15 +1308,16 @@ function formatSpanWorker( return lineAction; } - function processPair(currentItem: TextRangeWithKind, + function processPair( + currentItem: TextRangeWithKind, currentStartLine: number, currentParent: Node, previousItem: TextRangeWithKind, previousStartLine: number, previousParent: Node, contextNode: Node, - dynamicIndentation: DynamicIndentation | undefined): LineAction { - + dynamicIndentation: DynamicIndentation | undefined, + ): LineAction { formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode); const rules = getRules(formattingContext); @@ -1143,7 +1352,8 @@ function formatSpanWorker( } // We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line - trimTrailingWhitespaces = trimTrailingWhitespaces && !(rule.action & RuleAction.DeleteSpace) && rule.flags !== RuleFlags.CanDeleteNewLines; + trimTrailingWhitespaces = trimTrailingWhitespaces && !(rule.action & RuleAction.DeleteSpace) + && rule.flags !== RuleFlags.CanDeleteNewLines; }); } else { @@ -1168,7 +1378,10 @@ function formatSpanWorker( else { const tokenStart = sourceFile.getLineAndCharacterOfPosition(pos); const startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile); - if (indentation !== characterToColumn(startLinePosition, tokenStart.character) || indentationIsDifferent(indentationString, startLinePosition)) { + if ( + indentation !== characterToColumn(startLinePosition, tokenStart.character) + || indentationIsDifferent(indentationString, startLinePosition) + ) { recordReplace(startLinePosition, tokenStart.character, indentationString); } } @@ -1191,7 +1404,12 @@ function formatSpanWorker( return indentationString !== sourceFile.text.substr(startLinePosition, indentationString.length); } - function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean, indentFinalLine = true) { + function indentMultilineComment( + commentRange: TextRange, + indentation: number, + firstLineIsIndented: boolean, + indentFinalLine = true, + ) { // split comment in lines let startLine = sourceFile.getLineAndCharacterOfPosition(commentRange.pos).line; const endLine = sourceFile.getLineAndCharacterOfPosition(commentRange.end).line; @@ -1219,8 +1437,12 @@ function formatSpanWorker( const startLinePos = getStartPositionOfLine(startLine, sourceFile); - const nonWhitespaceColumnInFirstPart = - SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(startLinePos, parts[0].pos, sourceFile, options); + const nonWhitespaceColumnInFirstPart = SmartIndenter.findFirstNonWhitespaceCharacterAndColumn( + startLinePos, + parts[0].pos, + sourceFile, + options, + ); let startIndex = 0; if (firstLineIsIndented) { @@ -1230,12 +1452,16 @@ function formatSpanWorker( // shift all parts on the delta size const delta = indentation - nonWhitespaceColumnInFirstPart.column; - for (let i = startIndex; i < parts.length; i++ , startLine++) { + for (let i = startIndex; i < parts.length; i++, startLine++) { const startLinePos = getStartPositionOfLine(startLine, sourceFile); - const nonWhitespaceCharacterAndColumn = - i === 0 - ? nonWhitespaceColumnInFirstPart - : SmartIndenter.findFirstNonWhitespaceCharacterAndColumn(parts[i].pos, parts[i].end, sourceFile, options); + const nonWhitespaceCharacterAndColumn = i === 0 + ? nonWhitespaceColumnInFirstPart + : SmartIndenter.findFirstNonWhitespaceCharacterAndColumn( + parts[i].pos, + parts[i].end, + sourceFile, + options, + ); const newIndentation = nonWhitespaceCharacterAndColumn.column + delta; if (newIndentation > 0) { const indentationString = getIndentationString(newIndentation, options); @@ -1253,13 +1479,19 @@ function formatSpanWorker( const lineEndPosition = getEndLinePosition(line, sourceFile); // do not trim whitespaces in comments or template expression - if (range && (isComment(range.kind) || isStringOrRegularExpressionOrTemplateLiteral(range.kind)) && range.pos <= lineEndPosition && range.end > lineEndPosition) { + if ( + range && (isComment(range.kind) || isStringOrRegularExpressionOrTemplateLiteral(range.kind)) + && range.pos <= lineEndPosition && range.end > lineEndPosition + ) { continue; } const whitespaceStart = getTrailingWhitespaceStartPosition(lineStartPosition, lineEndPosition); if (whitespaceStart !== -1) { - Debug.assert(whitespaceStart === lineStartPosition || !isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(whitespaceStart - 1))); + Debug.assert( + whitespaceStart === lineStartPosition + || !isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(whitespaceStart - 1)), + ); recordDelete(whitespaceStart, lineEndPosition + 1 - whitespaceStart); } } @@ -1326,11 +1558,12 @@ function formatSpanWorker( } } - function applyRuleEdits(rule: Rule, + function applyRuleEdits( + rule: Rule, previousRange: TextRangeWithKind, previousStartLine: number, currentRange: TextRangeWithKind, - currentStartLine: number + currentStartLine: number, ): LineAction { const onLaterLine = currentStartLine !== previousStartLine; switch (rule.action) { @@ -1358,7 +1591,11 @@ function formatSpanWorker( // edit should not be applied if we have one line feed between elements const lineDelta = currentStartLine - previousStartLine; if (lineDelta !== 1) { - recordReplace(previousRange.end, currentRange.pos - previousRange.end, getNewLineOrDefaultFromHost(host, options)); + recordReplace( + previousRange.end, + currentRange.pos - previousRange.end, + getNewLineOrDefaultFromHost(host, options), + ); return onLaterLine ? LineAction.None : LineAction.LineAdded; } break; @@ -1381,10 +1618,13 @@ function formatSpanWorker( } } -const enum LineAction { None, LineAdded, LineRemoved } +const enum LineAction { + None, + LineAdded, + LineRemoved, +} /** - * * @internal */ export function getRangeOfEnclosingComment( @@ -1401,14 +1641,17 @@ export function getRangeOfEnclosingComment( } // eslint-disable-next-line no-null/no-null - precedingToken = precedingToken === null ? undefined : precedingToken === undefined ? findPrecedingToken(position, sourceFile) : precedingToken; + precedingToken = precedingToken === null ? undefined + : precedingToken === undefined ? findPrecedingToken(position, sourceFile) : precedingToken; // Between two consecutive tokens, all comments are either trailing on the former // or leading on the latter (and none are in both lists). - const trailingRangesOfPreviousToken = precedingToken && getTrailingCommentRanges(sourceFile.text, precedingToken.end); + const trailingRangesOfPreviousToken = precedingToken + && getTrailingCommentRanges(sourceFile.text, precedingToken.end); const leadingCommentRangesOfNextToken = getLeadingCommentRangesOfNode(tokenAtPosition, sourceFile); const commentRanges = concatenate(trailingRangesOfPreviousToken, leadingCommentRangesOfNextToken); - return commentRanges && find(commentRanges, range => rangeContainsPositionExclusive(range, position) || + return commentRanges && find(commentRanges, range => + rangeContainsPositionExclusive(range, position) // The end marker of a single-line comment does not include the newline character. // With caret at `^`, in the following case, we are inside a comment (^ denotes the cursor position): // @@ -1422,7 +1665,8 @@ export function getRangeOfEnclosingComment( // // Internally, we represent the end of the comment at the newline and closing '/', respectively. // - position === range.end && (range.kind === SyntaxKind.SingleLineCommentTrivia || position === sourceFile.getFullWidth())); + || position === range.end + && (range.kind === SyntaxKind.SingleLineCommentTrivia || position === sourceFile.getFullWidth())); } function getOpenTokenForList(node: Node, list: readonly Node[]) { @@ -1499,8 +1743,8 @@ let internedSpacesIndentation: string[] | undefined; /** @internal */ export function getIndentationString(indentation: number, options: EditorSettings): string { // reset interned strings if FormatCodeOptions were changed - const resetInternedStrings = - !internedSizes || (internedSizes.tabSize !== options.tabSize || internedSizes.indentSize !== options.indentSize); + const resetInternedStrings = !internedSizes + || (internedSizes.tabSize !== options.tabSize || internedSizes.indentSize !== options.indentSize); if (resetInternedStrings) { internedSizes = { tabSize: options.tabSize!, indentSize: options.indentSize! }; diff --git a/src/services/formatting/formattingContext.ts b/src/services/formatting/formattingContext.ts index 435b2dec686e1..22d62f8d9aff8 100644 --- a/src/services/formatting/formattingContext.ts +++ b/src/services/formatting/formattingContext.ts @@ -6,7 +6,9 @@ import { SourceFileLike, SyntaxKind, } from "../_namespaces/ts"; -import { TextRangeWithKind } from "../_namespaces/ts.formatting"; +import { + TextRangeWithKind, +} from "../_namespaces/ts.formatting"; /** @internal */ export const enum FormattingRequestKind { @@ -15,7 +17,7 @@ export const enum FormattingRequestKind { FormatOnEnter, FormatOnSemicolon, FormatOnOpeningCurlyBrace, - FormatOnClosingCurlyBrace + FormatOnClosingCurlyBrace, } /** @internal */ @@ -32,10 +34,20 @@ export class FormattingContext { private contextNodeBlockIsOnOneLine: boolean | undefined; private nextNodeBlockIsOnOneLine: boolean | undefined; - constructor(public readonly sourceFile: SourceFileLike, public formattingRequestKind: FormattingRequestKind, public options: FormatCodeSettings) { + constructor( + public readonly sourceFile: SourceFileLike, + public formattingRequestKind: FormattingRequestKind, + public options: FormatCodeSettings, + ) { } - public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) { + public updateContext( + currentRange: TextRangeWithKind, + currentTokenParent: Node, + nextRange: TextRangeWithKind, + nextTokenParent: Node, + commonParent: Node, + ) { this.currentTokenSpan = Debug.checkDefined(currentRange); this.currentTokenParent = Debug.checkDefined(currentTokenParent); this.nextTokenSpan = Debug.checkDefined(nextRange); @@ -70,7 +82,7 @@ export class FormattingContext { if (this.tokensAreOnSameLine === undefined) { const startLine = this.sourceFile.getLineAndCharacterOfPosition(this.currentTokenSpan.pos).line; const endLine = this.sourceFile.getLineAndCharacterOfPosition(this.nextTokenSpan.pos).line; - this.tokensAreOnSameLine = (startLine === endLine); + this.tokensAreOnSameLine = startLine === endLine; } return this.tokensAreOnSameLine; diff --git a/src/services/formatting/formattingScanner.ts b/src/services/formatting/formattingScanner.ts index 6a8087390461d..b4000c6690081 100644 --- a/src/services/formatting/formattingScanner.ts +++ b/src/services/formatting/formattingScanner.ts @@ -52,7 +52,13 @@ const enum ScanAction { } /** @internal */ -export function getFormattingScanner(text: string, languageVariant: LanguageVariant, startPos: number, endPos: number, cb: (scanner: FormattingScanner) => T): T { +export function getFormattingScanner( + text: string, + languageVariant: LanguageVariant, + startPos: number, + endPos: number, + cb: (scanner: FormattingScanner) => T, +): T { const scanner = languageVariant === LanguageVariant.JSX ? jsxScanner : standardScanner; scanner.setText(text); @@ -113,7 +119,7 @@ export function getFormattingScanner(text: string, languageVariant: LanguageV const item: TextRangeWithTriviaKind = { pos, end: scanner.getTokenFullStart(), - kind: t + kind: t, }; pos = scanner.getTokenFullStart(); @@ -161,8 +167,8 @@ export function getFormattingScanner(text: string, languageVariant: LanguageV } function shouldRescanTemplateToken(container: Node): boolean { - return container.kind === SyntaxKind.TemplateMiddle || - container.kind === SyntaxKind.TemplateTail; + return container.kind === SyntaxKind.TemplateMiddle + || container.kind === SyntaxKind.TemplateTail; } function shouldRescanJsxAttributeValue(node: Node): boolean { @@ -178,13 +184,13 @@ export function getFormattingScanner(text: string, languageVariant: LanguageV // normally scanner returns the smallest available token // check the kind of context node to determine if scanner should have more greedy behavior and consume more text. - const expectedScanAction = shouldRescanGreaterThanToken(n) ? ScanAction.RescanGreaterThanToken : - shouldRescanSlashToken(n) ? ScanAction.RescanSlashToken : - shouldRescanTemplateToken(n) ? ScanAction.RescanTemplateToken : - shouldRescanJsxIdentifier(n) ? ScanAction.RescanJsxIdentifier : - shouldRescanJsxText(n) ? ScanAction.RescanJsxText : - shouldRescanJsxAttributeValue(n) ? ScanAction.RescanJsxAttributeValue : - ScanAction.Scan; + const expectedScanAction = shouldRescanGreaterThanToken(n) ? ScanAction.RescanGreaterThanToken + : shouldRescanSlashToken(n) ? ScanAction.RescanSlashToken + : shouldRescanTemplateToken(n) ? ScanAction.RescanTemplateToken + : shouldRescanJsxIdentifier(n) ? ScanAction.RescanJsxIdentifier + : shouldRescanJsxText(n) ? ScanAction.RescanJsxText + : shouldRescanJsxAttributeValue(n) ? ScanAction.RescanJsxAttributeValue + : ScanAction.Scan; if (lastTokenInfo && expectedScanAction === lastScanAction) { // readTokenInfo was called before with the same expected scan action. diff --git a/src/services/formatting/rule.ts b/src/services/formatting/rule.ts index 99c7c08e1d904..176c0774c2cd4 100644 --- a/src/services/formatting/rule.ts +++ b/src/services/formatting/rule.ts @@ -2,7 +2,9 @@ import { emptyArray, SyntaxKind, } from "../_namespaces/ts"; -import { FormattingContext } from "../_namespaces/ts.formatting"; +import { + FormattingContext, +} from "../_namespaces/ts.formatting"; /** @internal */ export interface Rule { @@ -18,6 +20,7 @@ export type ContextPredicate = (context: FormattingContext) => boolean; /** @internal */ export const anyContext: readonly ContextPredicate[] = emptyArray; +// dprint-ignore /** @internal */ export const enum RuleAction { None = 0, diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 3d9c201a5050b..e66d76a92e928 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -58,18 +58,53 @@ export function getAllRules(): RuleSpec[] { const keywords = tokenRangeFromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword); const binaryOperators = tokenRangeFromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator); const binaryKeywordOperators = [ - SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword, - SyntaxKind.OfKeyword, SyntaxKind.AsKeyword, - SyntaxKind.IsKeyword, SyntaxKind.SatisfiesKeyword, + SyntaxKind.InKeyword, + SyntaxKind.InstanceOfKeyword, + SyntaxKind.OfKeyword, + SyntaxKind.AsKeyword, + SyntaxKind.IsKeyword, + SyntaxKind.SatisfiesKeyword, + ]; + const unaryPrefixOperators = [ + SyntaxKind.PlusPlusToken, + SyntaxKind.MinusMinusToken, + SyntaxKind.TildeToken, + SyntaxKind.ExclamationToken, ]; - const unaryPrefixOperators = [SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]; const unaryPrefixExpressions = [ - SyntaxKind.NumericLiteral, SyntaxKind.BigIntLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, - SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]; - const unaryPreincrementExpressions = [SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]; - const unaryPostincrementExpressions = [SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]; - const unaryPredecrementExpressions = [SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]; - const unaryPostdecrementExpressions = [SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]; + SyntaxKind.NumericLiteral, + SyntaxKind.BigIntLiteral, + SyntaxKind.Identifier, + SyntaxKind.OpenParenToken, + SyntaxKind.OpenBracketToken, + SyntaxKind.OpenBraceToken, + SyntaxKind.ThisKeyword, + SyntaxKind.NewKeyword, + ]; + const unaryPreincrementExpressions = [ + SyntaxKind.Identifier, + SyntaxKind.OpenParenToken, + SyntaxKind.ThisKeyword, + SyntaxKind.NewKeyword, + ]; + const unaryPostincrementExpressions = [ + SyntaxKind.Identifier, + SyntaxKind.CloseParenToken, + SyntaxKind.CloseBracketToken, + SyntaxKind.NewKeyword, + ]; + const unaryPredecrementExpressions = [ + SyntaxKind.Identifier, + SyntaxKind.OpenParenToken, + SyntaxKind.ThisKeyword, + SyntaxKind.NewKeyword, + ]; + const unaryPostdecrementExpressions = [ + SyntaxKind.Identifier, + SyntaxKind.CloseParenToken, + SyntaxKind.CloseBracketToken, + SyntaxKind.NewKeyword, + ]; const comments = [SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]; const typeNames = [SyntaxKind.Identifier, ...typeKeywords]; @@ -78,113 +113,304 @@ export function getAllRules(): RuleSpec[] { const functionOpenBraceLeftTokenRange = anyTokenIncludingMultilineComments; // Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc) - const typeScriptOpenBraceLeftTokenRange = tokenRangeFrom([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ImportKeyword]); + const typeScriptOpenBraceLeftTokenRange = tokenRangeFrom([ + SyntaxKind.Identifier, + SyntaxKind.MultiLineCommentTrivia, + SyntaxKind.ClassKeyword, + SyntaxKind.ExportKeyword, + SyntaxKind.ImportKeyword, + ]); // Place a space before open brace in a control flow construct - const controlOpenBraceLeftTokenRange = tokenRangeFrom([SyntaxKind.CloseParenToken, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.DoKeyword, SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ElseKeyword]); + const controlOpenBraceLeftTokenRange = tokenRangeFrom([ + SyntaxKind.CloseParenToken, + SyntaxKind.MultiLineCommentTrivia, + SyntaxKind.DoKeyword, + SyntaxKind.TryKeyword, + SyntaxKind.FinallyKeyword, + SyntaxKind.ElseKeyword, + ]); // These rules are higher in priority than user-configurable const highPriorityCommonRules = [ // Leave comments alone rule("IgnoreBeforeComment", anyToken, comments, anyContext, RuleAction.StopProcessingSpaceActions), - rule("IgnoreAfterLineComment", SyntaxKind.SingleLineCommentTrivia, anyToken, anyContext, RuleAction.StopProcessingSpaceActions), + rule( + "IgnoreAfterLineComment", + SyntaxKind.SingleLineCommentTrivia, + anyToken, + anyContext, + RuleAction.StopProcessingSpaceActions, + ), - rule("NotSpaceBeforeColon", anyToken, SyntaxKind.ColonToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext, isNotTypeAnnotationContext], RuleAction.DeleteSpace), - rule("SpaceAfterColon", SyntaxKind.ColonToken, anyToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext, isNextTokenParentNotJsxNamespacedName], RuleAction.InsertSpace), - rule("NoSpaceBeforeQuestionMark", anyToken, SyntaxKind.QuestionToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext, isNotTypeAnnotationContext], RuleAction.DeleteSpace), + rule("NotSpaceBeforeColon", anyToken, SyntaxKind.ColonToken, [ + isNonJsxSameLineTokenContext, + isNotBinaryOpContext, + isNotTypeAnnotationContext, + ], RuleAction.DeleteSpace), + rule("SpaceAfterColon", SyntaxKind.ColonToken, anyToken, [ + isNonJsxSameLineTokenContext, + isNotBinaryOpContext, + isNextTokenParentNotJsxNamespacedName, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeQuestionMark", anyToken, SyntaxKind.QuestionToken, [ + isNonJsxSameLineTokenContext, + isNotBinaryOpContext, + isNotTypeAnnotationContext, + ], RuleAction.DeleteSpace), // insert space after '?' only when it is used in conditional operator - rule("SpaceAfterQuestionMarkInConditionalOperator", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext, isConditionalOperatorContext], RuleAction.InsertSpace), + rule("SpaceAfterQuestionMarkInConditionalOperator", SyntaxKind.QuestionToken, anyToken, [ + isNonJsxSameLineTokenContext, + isConditionalOperatorContext, + ], RuleAction.InsertSpace), // in other cases there should be no space between '?' and next token - rule("NoSpaceAfterQuestionMark", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceAfterQuestionMark", + SyntaxKind.QuestionToken, + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), - rule("NoSpaceBeforeDot", anyToken, [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], [isNonJsxSameLineTokenContext, isNotPropertyAccessOnIntegerLiteral], RuleAction.DeleteSpace), - rule("NoSpaceAfterDot", [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], anyToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("NoSpaceBeforeDot", anyToken, [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], [ + isNonJsxSameLineTokenContext, + isNotPropertyAccessOnIntegerLiteral, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterDot", [SyntaxKind.DotToken, SyntaxKind.QuestionDotToken], anyToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), - rule("NoSpaceBetweenImportParenInImportType", SyntaxKind.ImportKeyword, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isImportTypeContext], RuleAction.DeleteSpace), + rule("NoSpaceBetweenImportParenInImportType", SyntaxKind.ImportKeyword, SyntaxKind.OpenParenToken, [ + isNonJsxSameLineTokenContext, + isImportTypeContext, + ], RuleAction.DeleteSpace), // Special handling of unary operators. // Prefix operators generally shouldn't have a space between // them and their target unary expression. - rule("NoSpaceAfterUnaryPrefixOperator", unaryPrefixOperators, unaryPrefixExpressions, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterUnaryPreincrementOperator", SyntaxKind.PlusPlusToken, unaryPreincrementExpressions, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterUnaryPredecrementOperator", SyntaxKind.MinusMinusToken, unaryPredecrementExpressions, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeUnaryPostincrementOperator", unaryPostincrementExpressions, SyntaxKind.PlusPlusToken, [isNonJsxSameLineTokenContext, isNotStatementConditionContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeUnaryPostdecrementOperator", unaryPostdecrementExpressions, SyntaxKind.MinusMinusToken, [isNonJsxSameLineTokenContext, isNotStatementConditionContext], RuleAction.DeleteSpace), + rule("NoSpaceAfterUnaryPrefixOperator", unaryPrefixOperators, unaryPrefixExpressions, [ + isNonJsxSameLineTokenContext, + isNotBinaryOpContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterUnaryPreincrementOperator", SyntaxKind.PlusPlusToken, unaryPreincrementExpressions, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterUnaryPredecrementOperator", SyntaxKind.MinusMinusToken, unaryPredecrementExpressions, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeUnaryPostincrementOperator", unaryPostincrementExpressions, SyntaxKind.PlusPlusToken, [ + isNonJsxSameLineTokenContext, + isNotStatementConditionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeUnaryPostdecrementOperator", unaryPostdecrementExpressions, SyntaxKind.MinusMinusToken, [ + isNonJsxSameLineTokenContext, + isNotStatementConditionContext, + ], RuleAction.DeleteSpace), // More unary operator special-casing. // DevDiv 181814: Be careful when removing leading whitespace // around unary operators. Examples: // 1 - -2 --X--> 1--2 // a + ++b --X--> a+++b - rule("SpaceAfterPostincrementWhenFollowedByAdd", SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterAddWhenFollowedByUnaryPlus", SyntaxKind.PlusToken, SyntaxKind.PlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterAddWhenFollowedByPreincrement", SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterPostdecrementWhenFollowedBySubtract", SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterSubtractWhenFollowedByUnaryMinus", SyntaxKind.MinusToken, SyntaxKind.MinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterSubtractWhenFollowedByPredecrement", SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - - rule("NoSpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, [SyntaxKind.CommaToken, SyntaxKind.SemicolonToken], [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterPostincrementWhenFollowedByAdd", SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterAddWhenFollowedByUnaryPlus", SyntaxKind.PlusToken, SyntaxKind.PlusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterAddWhenFollowedByPreincrement", SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterPostdecrementWhenFollowedBySubtract", SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterSubtractWhenFollowedByUnaryMinus", SyntaxKind.MinusToken, SyntaxKind.MinusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterSubtractWhenFollowedByPredecrement", SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + + rule("NoSpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, [SyntaxKind.CommaToken, SyntaxKind.SemicolonToken], [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // For functions and control block place } on a new line [multi-line rule] - rule("NewLineBeforeCloseBraceInBlockContext", anyTokenIncludingMultilineComments, SyntaxKind.CloseBraceToken, [isMultilineBlockContext], RuleAction.InsertNewLine), + rule("NewLineBeforeCloseBraceInBlockContext", anyTokenIncludingMultilineComments, SyntaxKind.CloseBraceToken, [ + isMultilineBlockContext, + ], RuleAction.InsertNewLine), // Space/new line after }. - rule("SpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, anyTokenExcept(SyntaxKind.CloseParenToken), [isNonJsxSameLineTokenContext, isAfterCodeBlockContext], RuleAction.InsertSpace), + rule("SpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, anyTokenExcept(SyntaxKind.CloseParenToken), [ + isNonJsxSameLineTokenContext, + isAfterCodeBlockContext, + ], RuleAction.InsertSpace), // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied // Also should not apply to }) - rule("SpaceBetweenCloseBraceAndElse", SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBetweenCloseBraceAndWhile", SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.DeleteSpace), + rule("SpaceBetweenCloseBraceAndElse", SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBetweenCloseBraceAndWhile", SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isNonJsxSameLineTokenContext, + isObjectContext, + ], RuleAction.DeleteSpace), // Add a space after control dec context if the next character is an open bracket ex: 'if (false)[a, b] = [1, 2];' -> 'if (false) [a, b] = [1, 2];' - rule("SpaceAfterConditionalClosingParen", SyntaxKind.CloseParenToken, SyntaxKind.OpenBracketToken, [isControlDeclContext], RuleAction.InsertSpace), + rule("SpaceAfterConditionalClosingParen", SyntaxKind.CloseParenToken, SyntaxKind.OpenBracketToken, [ + isControlDeclContext, + ], RuleAction.InsertSpace), - rule("NoSpaceBetweenFunctionKeywordAndStar", SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken, [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.DeleteSpace), - rule("SpaceAfterStarInGeneratorDeclaration", SyntaxKind.AsteriskToken, SyntaxKind.Identifier, [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.InsertSpace), + rule("NoSpaceBetweenFunctionKeywordAndStar", SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken, [ + isFunctionDeclarationOrFunctionExpressionContext, + ], RuleAction.DeleteSpace), + rule("SpaceAfterStarInGeneratorDeclaration", SyntaxKind.AsteriskToken, SyntaxKind.Identifier, [ + isFunctionDeclarationOrFunctionExpressionContext, + ], RuleAction.InsertSpace), - rule("SpaceAfterFunctionInFuncDecl", SyntaxKind.FunctionKeyword, anyToken, [isFunctionDeclContext], RuleAction.InsertSpace), + rule( + "SpaceAfterFunctionInFuncDecl", + SyntaxKind.FunctionKeyword, + anyToken, + [isFunctionDeclContext], + RuleAction.InsertSpace, + ), // Insert new line after { and before } in multi-line contexts. - rule("NewLineAfterOpenBraceInBlockContext", SyntaxKind.OpenBraceToken, anyToken, [isMultilineBlockContext], RuleAction.InsertNewLine), + rule( + "NewLineAfterOpenBraceInBlockContext", + SyntaxKind.OpenBraceToken, + anyToken, + [isMultilineBlockContext], + RuleAction.InsertNewLine, + ), // For get/set members, we check for (identifier,identifier) since get/set don't have tokens and they are represented as just an identifier token. // Though, we do extra check on the context to make sure we are dealing with get/set node. Example: // get x() {} // set x(val) {} - rule("SpaceAfterGetSetInMember", [SyntaxKind.GetKeyword, SyntaxKind.SetKeyword], SyntaxKind.Identifier, [isFunctionDeclContext], RuleAction.InsertSpace), + rule("SpaceAfterGetSetInMember", [SyntaxKind.GetKeyword, SyntaxKind.SetKeyword], SyntaxKind.Identifier, [ + isFunctionDeclContext, + ], RuleAction.InsertSpace), - rule("NoSpaceBetweenYieldKeywordAndStar", SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken, [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], RuleAction.DeleteSpace), - rule("SpaceBetweenYieldOrYieldStarAndOperand", [SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken], anyToken, [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], RuleAction.InsertSpace), + rule("NoSpaceBetweenYieldKeywordAndStar", SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken, [ + isNonJsxSameLineTokenContext, + isYieldOrYieldStarWithOperand, + ], RuleAction.DeleteSpace), + rule("SpaceBetweenYieldOrYieldStarAndOperand", [SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken], anyToken, [ + isNonJsxSameLineTokenContext, + isYieldOrYieldStarWithOperand, + ], RuleAction.InsertSpace), - rule("NoSpaceBetweenReturnAndSemicolon", SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("SpaceAfterCertainKeywords", [SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword, SyntaxKind.AwaitKeyword], anyToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceAfterLetConstInVariableDeclaration", [SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword], anyToken, [isNonJsxSameLineTokenContext, isStartOfVariableDeclarationList], RuleAction.InsertSpace), - rule("NoSpaceBeforeOpenParenInFuncCall", anyToken, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isFunctionCallOrNewContext, isPreviousTokenNotComma], RuleAction.DeleteSpace), + rule("NoSpaceBetweenReturnAndSemicolon", SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule( + "SpaceAfterCertainKeywords", + [ + SyntaxKind.VarKeyword, + SyntaxKind.ThrowKeyword, + SyntaxKind.NewKeyword, + SyntaxKind.DeleteKeyword, + SyntaxKind.ReturnKeyword, + SyntaxKind.TypeOfKeyword, + SyntaxKind.AwaitKeyword, + ], + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), + rule("SpaceAfterLetConstInVariableDeclaration", [SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword], anyToken, [ + isNonJsxSameLineTokenContext, + isStartOfVariableDeclarationList, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeOpenParenInFuncCall", anyToken, SyntaxKind.OpenParenToken, [ + isNonJsxSameLineTokenContext, + isFunctionCallOrNewContext, + isPreviousTokenNotComma, + ], RuleAction.DeleteSpace), // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options. - rule("SpaceBeforeBinaryKeywordOperator", anyToken, binaryKeywordOperators, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterBinaryKeywordOperator", binaryKeywordOperators, anyToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), + rule("SpaceBeforeBinaryKeywordOperator", anyToken, binaryKeywordOperators, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterBinaryKeywordOperator", binaryKeywordOperators, anyToken, [ + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), - rule("SpaceAfterVoidOperator", SyntaxKind.VoidKeyword, anyToken, [isNonJsxSameLineTokenContext, isVoidOpContext], RuleAction.InsertSpace), + rule("SpaceAfterVoidOperator", SyntaxKind.VoidKeyword, anyToken, [ + isNonJsxSameLineTokenContext, + isVoidOpContext, + ], RuleAction.InsertSpace), // Async-await - rule("SpaceBetweenAsyncAndOpenParen", SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken, [isArrowFunctionContext, isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBetweenAsyncAndFunctionKeyword", SyntaxKind.AsyncKeyword, [SyntaxKind.FunctionKeyword, SyntaxKind.Identifier], [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule("SpaceBetweenAsyncAndOpenParen", SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken, [ + isArrowFunctionContext, + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule( + "SpaceBetweenAsyncAndFunctionKeyword", + SyntaxKind.AsyncKeyword, + [SyntaxKind.FunctionKeyword, SyntaxKind.Identifier], + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), // Template string - rule("NoSpaceBetweenTagAndTemplateString", [SyntaxKind.Identifier, SyntaxKind.CloseParenToken], [SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead], [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceBetweenTagAndTemplateString", + [SyntaxKind.Identifier, SyntaxKind.CloseParenToken], + [SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead], + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), // JSX opening elements - rule("SpaceBeforeJsxAttribute", anyToken, SyntaxKind.Identifier, [isNextTokenParentJsxAttribute, isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBeforeSlashInJsxOpeningElement", anyToken, SyntaxKind.SlashToken, [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeGreaterThanTokenInJsxOpeningElement", SyntaxKind.SlashToken, SyntaxKind.GreaterThanToken, [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeEqualInJsxAttribute", anyToken, SyntaxKind.EqualsToken, [isJsxAttributeContext, isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterEqualInJsxAttribute", SyntaxKind.EqualsToken, anyToken, [isJsxAttributeContext, isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeJsxNamespaceColon", SyntaxKind.Identifier, SyntaxKind.ColonToken, [isNextTokenParentJsxNamespacedName], RuleAction.DeleteSpace), - rule("NoSpaceAfterJsxNamespaceColon", SyntaxKind.ColonToken, SyntaxKind.Identifier, [isNextTokenParentJsxNamespacedName], RuleAction.DeleteSpace), + rule("SpaceBeforeJsxAttribute", anyToken, SyntaxKind.Identifier, [ + isNextTokenParentJsxAttribute, + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeSlashInJsxOpeningElement", anyToken, SyntaxKind.SlashToken, [ + isJsxSelfClosingElementContext, + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeGreaterThanTokenInJsxOpeningElement", SyntaxKind.SlashToken, SyntaxKind.GreaterThanToken, [ + isJsxSelfClosingElementContext, + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeEqualInJsxAttribute", anyToken, SyntaxKind.EqualsToken, [ + isJsxAttributeContext, + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterEqualInJsxAttribute", SyntaxKind.EqualsToken, anyToken, [ + isJsxAttributeContext, + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeJsxNamespaceColon", SyntaxKind.Identifier, SyntaxKind.ColonToken, [ + isNextTokenParentJsxNamespacedName, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterJsxNamespaceColon", SyntaxKind.ColonToken, SyntaxKind.Identifier, [ + isNextTokenParentJsxNamespacedName, + ], RuleAction.DeleteSpace), // TypeScript-specific rules // Use of module as a function call. e.g.: import m2 = module("m2"); - rule("NoSpaceAfterModuleImport", [SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword], SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceAfterModuleImport", + [SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword], + SyntaxKind.OpenParenToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), // Add a space around certain TypeScript keywords rule( "SpaceAfterCertainTypeScriptKeywords", @@ -216,44 +442,99 @@ export function getAllRules(): RuleSpec[] { ], anyToken, [isNonJsxSameLineTokenContext], - RuleAction.InsertSpace), + RuleAction.InsertSpace, + ), rule( "SpaceBeforeCertainTypeScriptKeywords", anyToken, [SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.FromKeyword], [isNonJsxSameLineTokenContext], - RuleAction.InsertSpace), + RuleAction.InsertSpace, + ), // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { - rule("SpaceAfterModuleName", SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken, [isModuleDeclContext], RuleAction.InsertSpace), + rule( + "SpaceAfterModuleName", + SyntaxKind.StringLiteral, + SyntaxKind.OpenBraceToken, + [isModuleDeclContext], + RuleAction.InsertSpace, + ), // Lambda expressions - rule("SpaceBeforeArrow", anyToken, SyntaxKind.EqualsGreaterThanToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceAfterArrow", SyntaxKind.EqualsGreaterThanToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule( + "SpaceBeforeArrow", + anyToken, + SyntaxKind.EqualsGreaterThanToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), + rule( + "SpaceAfterArrow", + SyntaxKind.EqualsGreaterThanToken, + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), // Optional parameters and let args - rule("NoSpaceAfterEllipsis", SyntaxKind.DotDotDotToken, SyntaxKind.Identifier, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOptionalParameters", SyntaxKind.QuestionToken, [SyntaxKind.CloseParenToken, SyntaxKind.CommaToken], [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.DeleteSpace), + rule( + "NoSpaceAfterEllipsis", + SyntaxKind.DotDotDotToken, + SyntaxKind.Identifier, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), + rule( + "NoSpaceAfterOptionalParameters", + SyntaxKind.QuestionToken, + [SyntaxKind.CloseParenToken, SyntaxKind.CommaToken], + [isNonJsxSameLineTokenContext, isNotBinaryOpContext], + RuleAction.DeleteSpace, + ), // Remove spaces in empty interface literals. e.g.: x: {} - rule("NoSpaceBetweenEmptyInterfaceBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectTypeContext], RuleAction.DeleteSpace), + rule("NoSpaceBetweenEmptyInterfaceBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isNonJsxSameLineTokenContext, + isObjectTypeContext, + ], RuleAction.DeleteSpace), // generics and type assertions - rule("NoSpaceBeforeOpenAngularBracket", typeNames, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceBetweenCloseParenAndAngularBracket", SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOpenAngularBracket", SyntaxKind.LessThanToken, anyToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseAngularBracket", anyToken, SyntaxKind.GreaterThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterCloseAngularBracket", SyntaxKind.GreaterThanToken, [SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken], [ + rule("NoSpaceBeforeOpenAngularBracket", typeNames, SyntaxKind.LessThanToken, [ isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext, - isNotFunctionDeclContext /*To prevent an interference with the SpaceBeforeOpenParenInFuncDecl rule*/, - isNonTypeAssertionContext + ], RuleAction.DeleteSpace), + rule("NoSpaceBetweenCloseParenAndAngularBracket", SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken, [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterOpenAngularBracket", SyntaxKind.LessThanToken, anyToken, [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseAngularBracket", anyToken, SyntaxKind.GreaterThanToken, [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterCloseAngularBracket", SyntaxKind.GreaterThanToken, [ + SyntaxKind.OpenParenToken, + SyntaxKind.OpenBracketToken, + SyntaxKind.GreaterThanToken, + SyntaxKind.CommaToken, + ], [ + isNonJsxSameLineTokenContext, + isTypeArgumentOrParameterOrAssertionContext, + isNotFunctionDeclContext, /*To prevent an interference with the SpaceBeforeOpenParenInFuncDecl rule*/ + isNonTypeAssertionContext, ], RuleAction.DeleteSpace), // decorators - rule("SpaceBeforeAt", [SyntaxKind.CloseParenToken, SyntaxKind.Identifier], SyntaxKind.AtToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule("SpaceBeforeAt", [SyntaxKind.CloseParenToken, SyntaxKind.Identifier], SyntaxKind.AtToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), rule("NoSpaceAfterAt", SyntaxKind.AtToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), // Insert space after @ in decorator - rule("SpaceAfterDecorator", + rule( + "SpaceAfterDecorator", anyToken, [ SyntaxKind.AbstractKeyword, @@ -271,118 +552,407 @@ export function getAllRules(): RuleSpec[] { SyntaxKind.AsteriskToken, ], [isEndOfDecoratorContextOnSameLine], - RuleAction.InsertSpace), + RuleAction.InsertSpace, + ), - rule("NoSpaceBeforeNonNullAssertionOperator", anyToken, SyntaxKind.ExclamationToken, [isNonJsxSameLineTokenContext, isNonNullAssertionContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterNewKeywordOnConstructorSignature", SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isConstructorSignatureContext], RuleAction.DeleteSpace), - rule("SpaceLessThanAndNonJSXTypeAnnotation", SyntaxKind.LessThanToken, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule("NoSpaceBeforeNonNullAssertionOperator", anyToken, SyntaxKind.ExclamationToken, [ + isNonJsxSameLineTokenContext, + isNonNullAssertionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterNewKeywordOnConstructorSignature", SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken, [ + isNonJsxSameLineTokenContext, + isConstructorSignatureContext, + ], RuleAction.DeleteSpace), + rule("SpaceLessThanAndNonJSXTypeAnnotation", SyntaxKind.LessThanToken, SyntaxKind.LessThanToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), ]; // These rules are applied after high priority const userConfigurableRules = [ // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses - rule("SpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterConstructor"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterConstructor"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [ + isOptionEnabled("insertSpaceAfterConstructor"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterConstructor"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), - rule("SpaceAfterComma", SyntaxKind.CommaToken, anyToken, [isOptionEnabled("insertSpaceAfterCommaDelimiter"), isNonJsxSameLineTokenContext, isNonJsxElementOrFragmentContext, isNextTokenNotCloseBracket, isNextTokenNotCloseParen], RuleAction.InsertSpace), - rule("NoSpaceAfterComma", SyntaxKind.CommaToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterCommaDelimiter"), isNonJsxSameLineTokenContext, isNonJsxElementOrFragmentContext], RuleAction.DeleteSpace), + rule("SpaceAfterComma", SyntaxKind.CommaToken, anyToken, [ + isOptionEnabled("insertSpaceAfterCommaDelimiter"), + isNonJsxSameLineTokenContext, + isNonJsxElementOrFragmentContext, + isNextTokenNotCloseBracket, + isNextTokenNotCloseParen, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterComma", SyntaxKind.CommaToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterCommaDelimiter"), + isNonJsxSameLineTokenContext, + isNonJsxElementOrFragmentContext, + ], RuleAction.DeleteSpace), // Insert space after function keyword for anonymous functions - rule("SpaceAfterAnonymousFunctionKeyword", [SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken], SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], RuleAction.InsertSpace), - rule("NoSpaceAfterAnonymousFunctionKeyword", [SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken], SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], RuleAction.DeleteSpace), + rule( + "SpaceAfterAnonymousFunctionKeyword", + [SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken], + SyntaxKind.OpenParenToken, + [isOptionEnabled("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], + RuleAction.InsertSpace, + ), + rule( + "NoSpaceAfterAnonymousFunctionKeyword", + [SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken], + SyntaxKind.OpenParenToken, + [ + isOptionDisabledOrUndefined("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), + isFunctionDeclContext, + ], + RuleAction.DeleteSpace, + ), // Insert space after keywords in control flow statements - rule("SpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterKeywordsInControlFlowStatements"), isControlDeclContext], RuleAction.InsertSpace), - rule("NoSpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterKeywordsInControlFlowStatements"), isControlDeclContext], RuleAction.DeleteSpace), + rule("SpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [ + isOptionEnabled("insertSpaceAfterKeywordsInControlFlowStatements"), + isControlDeclContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterKeywordsInControlFlowStatements"), + isControlDeclContext, + ], RuleAction.DeleteSpace), // Insert space after opening and before closing nonempty parenthesis - rule("SpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBetweenOpenParens", SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceBetweenParens", SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBetweenOpenParens", SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenParens", SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // Insert space after opening and before closing nonempty brackets - rule("SpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("SpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceBetweenBrackets", SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenBrackets", SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, [ + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}. - rule("SpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isBraceWrappedContext], RuleAction.InsertSpace), - rule("SpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isBraceWrappedContext], RuleAction.InsertSpace), - rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [ + isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), + isBraceWrappedContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [ + isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), + isBraceWrappedContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isNonJsxSameLineTokenContext, + isObjectContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [ + isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [ + isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // Insert a space after opening and before closing empty brace brackets - rule("SpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingEmptyBraces")], RuleAction.InsertSpace), - rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingEmptyBraces"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule("SpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingEmptyBraces"), + ], RuleAction.InsertSpace), + rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [ + isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingEmptyBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // Insert space after opening and before closing template string braces - rule("SpaceAfterTemplateHeadAndMiddle", [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxTextContext], RuleAction.InsertSpace, RuleFlags.CanDeleteNewLines), - rule("SpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.InsertSpace), - rule("NoSpaceAfterTemplateHeadAndMiddle", [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxTextContext], RuleAction.DeleteSpace, RuleFlags.CanDeleteNewLines), - rule("NoSpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "SpaceAfterTemplateHeadAndMiddle", + [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], + anyToken, + [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxTextContext], + RuleAction.InsertSpace, + RuleFlags.CanDeleteNewLines, + ), + rule("SpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), + rule( + "NoSpaceAfterTemplateHeadAndMiddle", + [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], + anyToken, + [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), + isNonJsxTextContext, + ], + RuleAction.DeleteSpace, + RuleFlags.CanDeleteNewLines, + ), + rule("NoSpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), + isNonJsxSameLineTokenContext, + ], RuleAction.DeleteSpace), // No space after { and before } in JSX expression - rule("SpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.InsertSpace), - rule("SpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.InsertSpace), - rule("NoSpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.DeleteSpace), - rule("NoSpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.DeleteSpace), + rule("SpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), + isNonJsxSameLineTokenContext, + isJsxExpressionContext, + ], RuleAction.InsertSpace), + rule("SpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [ + isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), + isNonJsxSameLineTokenContext, + isJsxExpressionContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), + isNonJsxSameLineTokenContext, + isJsxExpressionContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), + isNonJsxSameLineTokenContext, + isJsxExpressionContext, + ], RuleAction.DeleteSpace), // Insert space after semicolon in for statement - rule("SpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [isOptionEnabled("insertSpaceAfterSemicolonInForStatements"), isNonJsxSameLineTokenContext, isForContext], RuleAction.InsertSpace), - rule("NoSpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterSemicolonInForStatements"), isNonJsxSameLineTokenContext, isForContext], RuleAction.DeleteSpace), + rule("SpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [ + isOptionEnabled("insertSpaceAfterSemicolonInForStatements"), + isNonJsxSameLineTokenContext, + isForContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterSemicolonInForStatements"), + isNonJsxSameLineTokenContext, + isForContext, + ], RuleAction.DeleteSpace), // Insert space before and after binary operators - rule("SpaceBeforeBinaryOperator", anyToken, binaryOperators, [isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("SpaceAfterBinaryOperator", binaryOperators, anyToken, [isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeBinaryOperator", anyToken, binaryOperators, [isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterBinaryOperator", binaryOperators, anyToken, [isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.DeleteSpace), + rule("SpaceBeforeBinaryOperator", anyToken, binaryOperators, [ + isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("SpaceAfterBinaryOperator", binaryOperators, anyToken, [ + isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeBinaryOperator", anyToken, binaryOperators, [ + isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.DeleteSpace), + rule("NoSpaceAfterBinaryOperator", binaryOperators, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), + isNonJsxSameLineTokenContext, + isBinaryOpContext, + ], RuleAction.DeleteSpace), - rule("SpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceBeforeFunctionParenthesis"), isNonJsxSameLineTokenContext, isFunctionDeclContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceBeforeFunctionParenthesis"), isNonJsxSameLineTokenContext, isFunctionDeclContext], RuleAction.DeleteSpace), + rule("SpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [ + isOptionEnabled("insertSpaceBeforeFunctionParenthesis"), + isNonJsxSameLineTokenContext, + isFunctionDeclContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [ + isOptionDisabledOrUndefined("insertSpaceBeforeFunctionParenthesis"), + isNonJsxSameLineTokenContext, + isFunctionDeclContext, + ], RuleAction.DeleteSpace), // Open Brace braces after control block - rule("NewLineBeforeOpenBraceInControl", controlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForControlBlocks"), isControlDeclContext, isBeforeMultilineBlockContext], RuleAction.InsertNewLine, RuleFlags.CanDeleteNewLines), + rule( + "NewLineBeforeOpenBraceInControl", + controlOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionEnabled("placeOpenBraceOnNewLineForControlBlocks"), + isControlDeclContext, + isBeforeMultilineBlockContext, + ], + RuleAction.InsertNewLine, + RuleFlags.CanDeleteNewLines, + ), // Open Brace braces after function // TypeScript: Function can have return types, which can be made of tons of different token kinds - rule("NewLineBeforeOpenBraceInFunction", functionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), isFunctionDeclContext, isBeforeMultilineBlockContext], RuleAction.InsertNewLine, RuleFlags.CanDeleteNewLines), + rule( + "NewLineBeforeOpenBraceInFunction", + functionOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), + isFunctionDeclContext, + isBeforeMultilineBlockContext, + ], + RuleAction.InsertNewLine, + RuleFlags.CanDeleteNewLines, + ), // Open Brace braces after TypeScript module/class/interface - rule("NewLineBeforeOpenBraceInTypeScriptDeclWithBlock", typeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), isTypeScriptDeclWithBlockContext, isBeforeMultilineBlockContext], RuleAction.InsertNewLine, RuleFlags.CanDeleteNewLines), + rule( + "NewLineBeforeOpenBraceInTypeScriptDeclWithBlock", + typeScriptOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), + isTypeScriptDeclWithBlockContext, + isBeforeMultilineBlockContext, + ], + RuleAction.InsertNewLine, + RuleFlags.CanDeleteNewLines, + ), - rule("SpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [isOptionEnabled("insertSpaceAfterTypeAssertion"), isNonJsxSameLineTokenContext, isTypeAssertionContext], RuleAction.InsertSpace), - rule("NoSpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterTypeAssertion"), isNonJsxSameLineTokenContext, isTypeAssertionContext], RuleAction.DeleteSpace), + rule("SpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [ + isOptionEnabled("insertSpaceAfterTypeAssertion"), + isNonJsxSameLineTokenContext, + isTypeAssertionContext, + ], RuleAction.InsertSpace), + rule("NoSpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [ + isOptionDisabledOrUndefined("insertSpaceAfterTypeAssertion"), + isNonJsxSameLineTokenContext, + isTypeAssertionContext, + ], RuleAction.DeleteSpace), - rule("SpaceBeforeTypeAnnotation", anyToken, [SyntaxKind.QuestionToken, SyntaxKind.ColonToken], [isOptionEnabled("insertSpaceBeforeTypeAnnotation"), isNonJsxSameLineTokenContext, isTypeAnnotationContext], RuleAction.InsertSpace), - rule("NoSpaceBeforeTypeAnnotation", anyToken, [SyntaxKind.QuestionToken, SyntaxKind.ColonToken], [isOptionDisabledOrUndefined("insertSpaceBeforeTypeAnnotation"), isNonJsxSameLineTokenContext, isTypeAnnotationContext], RuleAction.DeleteSpace), + rule("SpaceBeforeTypeAnnotation", anyToken, [SyntaxKind.QuestionToken, SyntaxKind.ColonToken], [ + isOptionEnabled("insertSpaceBeforeTypeAnnotation"), + isNonJsxSameLineTokenContext, + isTypeAnnotationContext, + ], RuleAction.InsertSpace), + rule("NoSpaceBeforeTypeAnnotation", anyToken, [SyntaxKind.QuestionToken, SyntaxKind.ColonToken], [ + isOptionDisabledOrUndefined("insertSpaceBeforeTypeAnnotation"), + isNonJsxSameLineTokenContext, + isTypeAnnotationContext, + ], RuleAction.DeleteSpace), - rule("NoOptionalSemicolon", SyntaxKind.SemicolonToken, anyTokenIncludingEOF, [optionEquals("semicolons", SemicolonPreference.Remove), isSemicolonDeletionContext], RuleAction.DeleteToken), - rule("OptionalSemicolon", anyToken, anyTokenIncludingEOF, [optionEquals("semicolons", SemicolonPreference.Insert), isSemicolonInsertionContext], RuleAction.InsertTrailingSemicolon), + rule("NoOptionalSemicolon", SyntaxKind.SemicolonToken, anyTokenIncludingEOF, [ + optionEquals("semicolons", SemicolonPreference.Remove), + isSemicolonDeletionContext, + ], RuleAction.DeleteToken), + rule("OptionalSemicolon", anyToken, anyTokenIncludingEOF, [ + optionEquals("semicolons", SemicolonPreference.Insert), + isSemicolonInsertionContext, + ], RuleAction.InsertTrailingSemicolon), ]; // These rules are lower in priority than user-configurable. Rules earlier in this list have priority over rules later in the list. const lowPriorityCommonRules = [ // Space after keyword but not before ; or : or ? - rule("NoSpaceBeforeSemicolon", anyToken, SyntaxKind.SemicolonToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceBeforeSemicolon", + anyToken, + SyntaxKind.SemicolonToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), - rule("SpaceBeforeOpenBraceInControl", controlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForControlBlocks"), isControlDeclContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.InsertSpace, RuleFlags.CanDeleteNewLines), - rule("SpaceBeforeOpenBraceInFunction", functionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), isFunctionDeclContext, isBeforeBlockContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.InsertSpace, RuleFlags.CanDeleteNewLines), - rule("SpaceBeforeOpenBraceInTypeScriptDeclWithBlock", typeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), isTypeScriptDeclWithBlockContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.InsertSpace, RuleFlags.CanDeleteNewLines), + rule( + "SpaceBeforeOpenBraceInControl", + controlOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForControlBlocks"), + isControlDeclContext, + isNotFormatOnEnter, + isSameLineTokenOrBeforeBlockContext, + ], + RuleAction.InsertSpace, + RuleFlags.CanDeleteNewLines, + ), + rule( + "SpaceBeforeOpenBraceInFunction", + functionOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), + isFunctionDeclContext, + isBeforeBlockContext, + isNotFormatOnEnter, + isSameLineTokenOrBeforeBlockContext, + ], + RuleAction.InsertSpace, + RuleFlags.CanDeleteNewLines, + ), + rule( + "SpaceBeforeOpenBraceInTypeScriptDeclWithBlock", + typeScriptOpenBraceLeftTokenRange, + SyntaxKind.OpenBraceToken, + [ + isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), + isTypeScriptDeclWithBlockContext, + isNotFormatOnEnter, + isSameLineTokenOrBeforeBlockContext, + ], + RuleAction.InsertSpace, + RuleFlags.CanDeleteNewLines, + ), - rule("NoSpaceBeforeComma", anyToken, SyntaxKind.CommaToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), + rule( + "NoSpaceBeforeComma", + anyToken, + SyntaxKind.CommaToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), // No space before and after indexer `x[]` - rule("NoSpaceBeforeOpenBracket", anyTokenExcept(SyntaxKind.AsyncKeyword, SyntaxKind.CaseKeyword), SyntaxKind.OpenBracketToken, [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace), - rule("NoSpaceAfterCloseBracket", SyntaxKind.CloseBracketToken, anyToken, [isNonJsxSameLineTokenContext, isNotBeforeBlockInFunctionDeclarationContext], RuleAction.DeleteSpace), - rule("SpaceAfterSemicolon", SyntaxKind.SemicolonToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule( + "NoSpaceBeforeOpenBracket", + anyTokenExcept(SyntaxKind.AsyncKeyword, SyntaxKind.CaseKeyword), + SyntaxKind.OpenBracketToken, + [isNonJsxSameLineTokenContext], + RuleAction.DeleteSpace, + ), + rule("NoSpaceAfterCloseBracket", SyntaxKind.CloseBracketToken, anyToken, [ + isNonJsxSameLineTokenContext, + isNotBeforeBlockInFunctionDeclarationContext, + ], RuleAction.DeleteSpace), + rule( + "SpaceAfterSemicolon", + SyntaxKind.SemicolonToken, + anyToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), // Remove extra space between for and await - rule("SpaceBetweenForAndAwaitKeyword", SyntaxKind.ForKeyword, SyntaxKind.AwaitKeyword, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule("SpaceBetweenForAndAwaitKeyword", SyntaxKind.ForKeyword, SyntaxKind.AwaitKeyword, [ + isNonJsxSameLineTokenContext, + ], RuleAction.InsertSpace), // Add a space between statements. All keywords except (do,else,case) has open/close parens after them. // So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any] @@ -391,9 +961,16 @@ export function getAllRules(): RuleSpec[] { [SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword], anyToken, [isNonJsxSameLineTokenContext, isNonJsxElementOrFragmentContext, isNotForContext], - RuleAction.InsertSpace), + RuleAction.InsertSpace, + ), // This low-pri rule takes care of "try {", "catch {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter. - rule("SpaceAfterTryCatchFinally", [SyntaxKind.TryKeyword, SyntaxKind.CatchKeyword, SyntaxKind.FinallyKeyword], SyntaxKind.OpenBraceToken, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace), + rule( + "SpaceAfterTryCatchFinally", + [SyntaxKind.TryKeyword, SyntaxKind.CatchKeyword, SyntaxKind.FinallyKeyword], + SyntaxKind.OpenBraceToken, + [isNonJsxSameLineTokenContext], + RuleAction.InsertSpace, + ), ]; return [ @@ -423,7 +1000,11 @@ function rule( action: RuleAction, flags: RuleFlags = RuleFlags.None, ): RuleSpec { - return { leftTokenRange: toTokenRange(left), rightTokenRange: toTokenRange(right), rule: { debugName, context, action, flags } }; + return { + leftTokenRange: toTokenRange(left), + rightTokenRange: toTokenRange(right), + rule: { debugName, context, action, flags }, + }; } function tokenRangeFrom(tokens: readonly SyntaxKind[]): TokenRange { @@ -448,28 +1029,35 @@ function tokenRangeFromRange(from: SyntaxKind, to: SyntaxKind, except: readonly /// Contexts /// -function optionEquals(optionName: K, optionValue: FormatCodeSettings[K]): (context: FormattingContext) => boolean { - return (context) => context.options && context.options[optionName] === optionValue; +function optionEquals( + optionName: K, + optionValue: FormatCodeSettings[K], +): (context: FormattingContext) => boolean { + return context => context.options && context.options[optionName] === optionValue; } function isOptionEnabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => context.options && hasProperty(context.options, optionName) && !!context.options[optionName]; + return context => context.options && hasProperty(context.options, optionName) && !!context.options[optionName]; } function isOptionDisabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => context.options && hasProperty(context.options, optionName) && !context.options[optionName]; + return context => context.options && hasProperty(context.options, optionName) && !context.options[optionName]; } function isOptionDisabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !hasProperty(context.options, optionName) || !context.options[optionName]; + return context => !context.options || !hasProperty(context.options, optionName) || !context.options[optionName]; } -function isOptionDisabledOrUndefinedOrTokensOnSameLine(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !hasProperty(context.options, optionName) || !context.options[optionName] || context.TokensAreOnSameLine(); +function isOptionDisabledOrUndefinedOrTokensOnSameLine( + optionName: keyof FormatCodeSettings, +): (context: FormattingContext) => boolean { + return context => + !context.options || !hasProperty(context.options, optionName) || !context.options[optionName] + || context.TokensAreOnSameLine(); } function isOptionEnabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean { - return (context) => !context.options || !hasProperty(context.options, optionName) || !!context.options[optionName]; + return context => !context.options || !hasProperty(context.options, optionName) || !!context.options[optionName]; } function isForContext(context: FormattingContext): boolean { @@ -515,16 +1103,21 @@ function isBinaryOpContext(context: FormattingContext): boolean { case SyntaxKind.EnumMember: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; + return context.currentTokenSpan.kind === SyntaxKind.EqualsToken + || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; // "in" keyword in for (let x in []) { } case SyntaxKind.ForInStatement: // "in" keyword in [P in keyof T]: T[P] // falls through case SyntaxKind.TypeParameter: - return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword || context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; + return context.currentTokenSpan.kind === SyntaxKind.InKeyword + || context.nextTokenSpan.kind === SyntaxKind.InKeyword + || context.currentTokenSpan.kind === SyntaxKind.EqualsToken + || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; // Technically, "of" is not a binary operator, but format it the same way as "in" case SyntaxKind.ForOfStatement: - return context.currentTokenSpan.kind === SyntaxKind.OfKeyword || context.nextTokenSpan.kind === SyntaxKind.OfKeyword; + return context.currentTokenSpan.kind === SyntaxKind.OfKeyword + || context.nextTokenSpan.kind === SyntaxKind.OfKeyword; } return false; } @@ -539,16 +1132,16 @@ function isNotTypeAnnotationContext(context: FormattingContext): boolean { function isTypeAnnotationContext(context: FormattingContext): boolean { const contextKind = context.contextNode.kind; - return contextKind === SyntaxKind.PropertyDeclaration || - contextKind === SyntaxKind.PropertySignature || - contextKind === SyntaxKind.Parameter || - contextKind === SyntaxKind.VariableDeclaration || - isFunctionLikeKind(contextKind); + return contextKind === SyntaxKind.PropertyDeclaration + || contextKind === SyntaxKind.PropertySignature + || contextKind === SyntaxKind.Parameter + || contextKind === SyntaxKind.VariableDeclaration + || isFunctionLikeKind(contextKind); } function isConditionalOperatorContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ConditionalExpression || - context.contextNode.kind === SyntaxKind.ConditionalType; + return context.contextNode.kind === SyntaxKind.ConditionalExpression + || context.contextNode.kind === SyntaxKind.ConditionalType; } function isSameLineTokenOrBeforeBlockContext(context: FormattingContext): boolean { @@ -556,9 +1149,9 @@ function isSameLineTokenOrBeforeBlockContext(context: FormattingContext): boolea } function isBraceWrappedContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.ObjectBindingPattern || - context.contextNode.kind === SyntaxKind.MappedType || - isSingleLineBlockContext(context); + return context.contextNode.kind === SyntaxKind.ObjectBindingPattern + || context.contextNode.kind === SyntaxKind.MappedType + || isSingleLineBlockContext(context); } // This check is done before an open brace in a control construct, a function, or a typescript block declaration @@ -631,7 +1224,8 @@ function isNotFunctionDeclContext(context: FormattingContext): boolean { } function isFunctionDeclarationOrFunctionExpressionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.FunctionDeclaration || context.contextNode.kind === SyntaxKind.FunctionExpression; + return context.contextNode.kind === SyntaxKind.FunctionDeclaration + || context.contextNode.kind === SyntaxKind.FunctionExpression; } function isTypeScriptDeclWithBlockContext(context: FormattingContext): boolean { @@ -668,7 +1262,10 @@ function isAfterCodeBlockContext(context: FormattingContext): boolean { case SyntaxKind.Block: { const blockParent = context.currentTokenParent.parent; // In a codefix scenario, we can't rely on parents being set. So just always return true. - if (!blockParent || blockParent.kind !== SyntaxKind.ArrowFunction && blockParent.kind !== SyntaxKind.FunctionExpression) { + if ( + !blockParent + || blockParent.kind !== SyntaxKind.ArrowFunction && blockParent.kind !== SyntaxKind.FunctionExpression + ) { return true; } } @@ -747,12 +1344,14 @@ function isNonJsxElementOrFragmentContext(context: FormattingContext): boolean { } function isJsxExpressionContext(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.JsxExpression || context.contextNode.kind === SyntaxKind.JsxSpreadAttribute; + return context.contextNode.kind === SyntaxKind.JsxExpression + || context.contextNode.kind === SyntaxKind.JsxSpreadAttribute; } function isNextTokenParentJsxAttribute(context: FormattingContext): boolean { return context.nextTokenParent.kind === SyntaxKind.JsxAttribute || ( - context.nextTokenParent.kind === SyntaxKind.JsxNamespacedName && context.nextTokenParent.parent.kind === SyntaxKind.JsxAttribute + context.nextTokenParent.kind === SyntaxKind.JsxNamespacedName + && context.nextTokenParent.parent.kind === SyntaxKind.JsxAttribute ); } @@ -777,10 +1376,10 @@ function isNotBeforeBlockInFunctionDeclarationContext(context: FormattingContext } function isEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean { - return context.TokensAreOnSameLine() && - hasDecorators(context.contextNode) && - nodeIsInDecoratorContext(context.currentTokenParent) && - !nodeIsInDecoratorContext(context.nextTokenParent); + return context.TokensAreOnSameLine() + && hasDecorators(context.contextNode) + && nodeIsInDecoratorContext(context.currentTokenParent) + && !nodeIsInDecoratorContext(context.nextTokenParent); } function nodeIsInDecoratorContext(node: Node): boolean { @@ -791,8 +1390,8 @@ function nodeIsInDecoratorContext(node: Node): boolean { } function isStartOfVariableDeclarationList(context: FormattingContext): boolean { - return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList && - context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; + return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList + && context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; } function isNotFormatOnEnter(context: FormattingContext): boolean { @@ -835,13 +1434,12 @@ function isTypeArgumentOrParameterOrAssertion(token: TextRangeWithKind, parent: return true; default: return false; - } } function isTypeArgumentOrParameterOrAssertionContext(context: FormattingContext): boolean { - return isTypeArgumentOrParameterOrAssertion(context.currentTokenSpan, context.currentTokenParent) || - isTypeArgumentOrParameterOrAssertion(context.nextTokenSpan, context.nextTokenParent); + return isTypeArgumentOrParameterOrAssertion(context.currentTokenSpan, context.currentTokenParent) + || isTypeArgumentOrParameterOrAssertion(context.nextTokenSpan, context.nextTokenParent); } function isTypeAssertionContext(context: FormattingContext): boolean { @@ -853,11 +1451,13 @@ function isNonTypeAssertionContext(context: FormattingContext): boolean { } function isVoidOpContext(context: FormattingContext): boolean { - return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.VoidExpression; + return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword + && context.currentTokenParent.kind === SyntaxKind.VoidExpression; } function isYieldOrYieldStarWithOperand(context: FormattingContext): boolean { - return context.contextNode.kind === SyntaxKind.YieldExpression && (context.contextNode as YieldExpression).expression !== undefined; + return context.contextNode.kind === SyntaxKind.YieldExpression + && (context.contextNode as YieldExpression).expression !== undefined; } function isNonNullAssertionContext(context: FormattingContext): boolean { @@ -891,7 +1491,8 @@ function isSemicolonDeletionContext(context: FormattingContext): boolean { ? findNextToken( context.currentTokenParent, findAncestor(context.currentTokenParent, a => !a.parent)!, - context.sourceFile) + context.sourceFile, + ) : context.nextTokenParent.getFirstToken(context.sourceFile); if (!nextRealToken) { return true; @@ -907,14 +1508,16 @@ function isSemicolonDeletionContext(context: FormattingContext): boolean { || nextTokenKind === SyntaxKind.EndOfFileToken; } - if (nextTokenKind === SyntaxKind.SemicolonClassElement || - nextTokenKind === SyntaxKind.SemicolonToken + if ( + nextTokenKind === SyntaxKind.SemicolonClassElement + || nextTokenKind === SyntaxKind.SemicolonToken ) { return false; } - if (context.contextNode.kind === SyntaxKind.InterfaceDeclaration || - context.contextNode.kind === SyntaxKind.TypeAliasDeclaration + if ( + context.contextNode.kind === SyntaxKind.InterfaceDeclaration + || context.contextNode.kind === SyntaxKind.TypeAliasDeclaration ) { // Can't remove semicolon after `foo`; it would parse as a method declaration: // diff --git a/src/services/formatting/rulesMap.ts b/src/services/formatting/rulesMap.ts index 8970be77c18a5..9f13381cdbbdc 100644 --- a/src/services/formatting/rulesMap.ts +++ b/src/services/formatting/rulesMap.ts @@ -96,7 +96,10 @@ function buildMap(rules: readonly RuleSpec[]): readonly (readonly Rule[])[] { } function getRuleBucketIndex(row: number, column: number): number { - Debug.assert(row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, "Must compute formatting context from tokens"); + Debug.assert( + row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, + "Must compute formatting context from tokens", + ); return (row * mapRowLength) + column; } @@ -110,7 +113,7 @@ enum RulesPosition { ContextRulesSpecific = maskBitSize * 2, ContextRulesAny = maskBitSize * 3, NoContextRulesSpecific = maskBitSize * 4, - NoContextRulesAny = maskBitSize * 5 + NoContextRulesAny = maskBitSize * 5, } // The Rules list contains all the inserted rules into a rulebucket in the following order: @@ -128,12 +131,18 @@ enum RulesPosition { // Example: // In order to insert a rule to the end of sub-bucket (3), we get the index by adding // the values in the bitmap segments 3rd, 2nd, and 1st. -function addRule(rules: Rule[], rule: Rule, specificTokens: boolean, constructionState: number[], rulesBucketIndex: number): void { - const position = rule.action & RuleAction.StopAction ? - specificTokens ? RulesPosition.StopRulesSpecific : RulesPosition.StopRulesAny : - rule.context !== anyContext ? - specificTokens ? RulesPosition.ContextRulesSpecific : RulesPosition.ContextRulesAny : - specificTokens ? RulesPosition.NoContextRulesSpecific : RulesPosition.NoContextRulesAny; +function addRule( + rules: Rule[], + rule: Rule, + specificTokens: boolean, + constructionState: number[], + rulesBucketIndex: number, +): void { + const position = rule.action & RuleAction.StopAction + ? specificTokens ? RulesPosition.StopRulesSpecific : RulesPosition.StopRulesAny + : rule.context !== anyContext + ? specificTokens ? RulesPosition.ContextRulesSpecific : RulesPosition.ContextRulesAny + : specificTokens ? RulesPosition.NoContextRulesSpecific : RulesPosition.NoContextRulesAny; const state = constructionState[rulesBucketIndex] || 0; rules.splice(getInsertionIndex(state, position), 0, rule); @@ -151,6 +160,9 @@ function getInsertionIndex(indexBitmap: number, maskPosition: RulesPosition) { function increaseInsertionIndex(indexBitmap: number, maskPosition: RulesPosition): number { const value = ((indexBitmap >> maskPosition) & mask) + 1; - Debug.assert((value & mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules."); + Debug.assert( + (value & mask) === value, + "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules.", + ); return (indexBitmap & ~(mask << maskPosition)) | (value << maskPosition); } diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 1ab72e8c99bb2..a7a747cba48b3 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -60,9 +60,8 @@ import { /** @internal */ export namespace SmartIndenter { - const enum Value { - Unknown = -1 + Unknown = -1, } /** @@ -80,7 +79,12 @@ export namespace SmartIndenter { * When inserting some text after an open brace, we would like to get indentation as if a newline was already there. * By default indentation at `position` will be 0 so 'assumeNewLineBeforeCloseBrace' overrides this behavior. */ - export function getIndentation(position: number, sourceFile: SourceFile, options: EditorSettings, assumeNewLineBeforeCloseBrace = false): number { + export function getIndentation( + position: number, + sourceFile: SourceFile, + options: EditorSettings, + assumeNewLineBeforeCloseBrace = false, + ): number { if (position > sourceFile.text.length) { return getBaseIndentation(options); // past EOF } @@ -105,7 +109,9 @@ export namespace SmartIndenter { // no indentation in string \regex\template literals const precedingTokenIsLiteral = isStringOrRegularExpressionOrTemplateLiteral(precedingToken.kind); - if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && position < precedingToken.end) { + if ( + precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && position < precedingToken.end + ) { return 0; } @@ -135,12 +141,15 @@ export namespace SmartIndenter { // y: undefined, // } // ``` - const isObjectLiteral = currentToken.kind === SyntaxKind.OpenBraceToken && currentToken.parent.kind === SyntaxKind.ObjectLiteralExpression; + const isObjectLiteral = currentToken.kind === SyntaxKind.OpenBraceToken + && currentToken.parent.kind === SyntaxKind.ObjectLiteralExpression; if (options.indentStyle === IndentStyle.Block || isObjectLiteral) { return getBlockIndent(sourceFile, position, options); } - if (precedingToken.kind === SyntaxKind.CommaToken && precedingToken.parent.kind !== SyntaxKind.BinaryExpression) { + if ( + precedingToken.kind === SyntaxKind.CommaToken && precedingToken.parent.kind !== SyntaxKind.BinaryExpression + ) { // previous token is comma that separates items in list - find the previous item and try to derive indentation from it const actualIndentation = getActualIndentationForListItemBeforeComma(precedingToken, sourceFile, options); if (actualIndentation !== Value.Unknown) { @@ -151,26 +160,49 @@ export namespace SmartIndenter { const containerList = getListByPosition(position, precedingToken.parent, sourceFile); // use list position if the preceding token is before any list items if (containerList && !rangeContainsRange(containerList, precedingToken)) { - const useTheSameBaseIndentation = [SyntaxKind.FunctionExpression, SyntaxKind.ArrowFunction].indexOf(currentToken.parent.kind) !== -1; + const useTheSameBaseIndentation = + [SyntaxKind.FunctionExpression, SyntaxKind.ArrowFunction].indexOf(currentToken.parent.kind) !== -1; const indentSize = useTheSameBaseIndentation ? 0 : options.indentSize!; return getActualIndentationForListStartLine(containerList, sourceFile, options) + indentSize; // TODO: GH#18217 } - return getSmartIndent(sourceFile, position, precedingToken, lineAtPosition, assumeNewLineBeforeCloseBrace, options); + return getSmartIndent( + sourceFile, + position, + precedingToken, + lineAtPosition, + assumeNewLineBeforeCloseBrace, + options, + ); } - function getCommentIndent(sourceFile: SourceFile, position: number, options: EditorSettings, enclosingCommentRange: CommentRange): number { + function getCommentIndent( + sourceFile: SourceFile, + position: number, + options: EditorSettings, + enclosingCommentRange: CommentRange, + ): number { const previousLine = getLineAndCharacterOfPosition(sourceFile, position).line - 1; const commentStartLine = getLineAndCharacterOfPosition(sourceFile, enclosingCommentRange.pos).line; Debug.assert(commentStartLine >= 0); if (previousLine <= commentStartLine) { - return findFirstNonWhitespaceColumn(getStartPositionOfLine(commentStartLine, sourceFile), position, sourceFile, options); + return findFirstNonWhitespaceColumn( + getStartPositionOfLine(commentStartLine, sourceFile), + position, + sourceFile, + options, + ); } const startPositionOfLine = getStartPositionOfLine(previousLine, sourceFile); - const { column, character } = findFirstNonWhitespaceCharacterAndColumn(startPositionOfLine, position, sourceFile, options); + const { column, character } = findFirstNonWhitespaceCharacterAndColumn( + startPositionOfLine, + position, + sourceFile, + options, + ); if (column === 0) { return column; @@ -196,28 +228,57 @@ export namespace SmartIndenter { return findFirstNonWhitespaceColumn(lineStart, current, sourceFile, options); } - function getSmartIndent(sourceFile: SourceFile, position: number, precedingToken: Node, lineAtPosition: number, assumeNewLineBeforeCloseBrace: boolean, options: EditorSettings): number { + function getSmartIndent( + sourceFile: SourceFile, + position: number, + precedingToken: Node, + lineAtPosition: number, + assumeNewLineBeforeCloseBrace: boolean, + options: EditorSettings, + ): number { // try to find node that can contribute to indentation and includes 'position' starting from 'precedingToken' // if such node is found - compute initial indentation for 'position' inside this node let previous: Node | undefined; let current = precedingToken; while (current) { - if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(options, current, previous, sourceFile, /*isNextChild*/ true)) { + if ( + positionBelongsToNode(current, position, sourceFile) + && shouldIndentChildNode(options, current, previous, sourceFile, /*isNextChild*/ true) + ) { const currentStart = getStartLineAndCharacterForNode(current, sourceFile); - const nextTokenKind = nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile); + const nextTokenKind = nextTokenIsCurlyBraceOnSameLineAsCursor( + precedingToken, + current, + lineAtPosition, + sourceFile, + ); const indentationDelta = nextTokenKind !== NextTokenKind.Unknown // handle cases when codefix is about to be inserted before the close brace - ? assumeNewLineBeforeCloseBrace && nextTokenKind === NextTokenKind.CloseBrace ? options.indentSize : 0 + ? assumeNewLineBeforeCloseBrace && nextTokenKind === NextTokenKind.CloseBrace ? options.indentSize + : 0 : lineAtPosition !== currentStart.line ? options.indentSize : 0; - return getIndentationForNodeWorker(current, currentStart, /*ignoreActualIndentationRange*/ undefined, indentationDelta!, sourceFile, /*isNextChild*/ true, options); // TODO: GH#18217 + return getIndentationForNodeWorker( + current, + currentStart, + /*ignoreActualIndentationRange*/ undefined, + indentationDelta!, + sourceFile, + /*isNextChild*/ true, + options, + ); // TODO: GH#18217 } // check if current node is a list item - if yes, take indentation from it // do not consider parent-child line sharing yet: // function foo(a // | preceding node 'a' does share line with its parent but indentation is expected - const actualIndentation = getActualIndentationForListItem(current, sourceFile, options, /*listIndentsChild*/ true); + const actualIndentation = getActualIndentationForListItem( + current, + sourceFile, + options, + /*listIndentsChild*/ true, + ); if (actualIndentation !== Value.Unknown) { return actualIndentation; } @@ -229,9 +290,22 @@ export namespace SmartIndenter { return getBaseIndentation(options); } - export function getIndentationForNode(n: Node, ignoreActualIndentationRange: TextRange, sourceFile: SourceFile, options: EditorSettings): number { + export function getIndentationForNode( + n: Node, + ignoreActualIndentationRange: TextRange, + sourceFile: SourceFile, + options: EditorSettings, + ): number { const start = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); - return getIndentationForNodeWorker(n, start, ignoreActualIndentationRange, /*indentationDelta*/ 0, sourceFile, /*isNextChild*/ false, options); + return getIndentationForNodeWorker( + n, + start, + ignoreActualIndentationRange, + /*indentationDelta*/ 0, + sourceFile, + /*isNextChild*/ false, + options, + ); } export function getBaseIndentation(options: EditorSettings) { @@ -245,7 +319,8 @@ export namespace SmartIndenter { indentationDelta: number, sourceFile: SourceFile, isNextChild: boolean, - options: EditorSettings): number { + options: EditorSettings, + ): number { let parent = current.parent; // Walk up the tree and collect indentation for parent-child node pairs. Indentation is not added if @@ -255,13 +330,13 @@ export namespace SmartIndenter { let useActualIndentation = true; if (ignoreActualIndentationRange) { const start = current.getStart(sourceFile); - useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end; + useActualIndentation = start < ignoreActualIndentationRange.pos + || start > ignoreActualIndentationRange.end; } const containingListOrParentStart = getContainingListOrParentStart(parent, current, sourceFile); - const parentAndChildShareLine = - containingListOrParentStart.line === currentStart.line || - childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); + const parentAndChildShareLine = containingListOrParentStart.line === currentStart.line + || childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); if (useActualIndentation) { // check if current node is a list item - if yes, take indentation from it @@ -282,14 +357,23 @@ export namespace SmartIndenter { // }, { itself contributes nothing. // prop: 1 L3 - The indentation of the second object literal is best understood by // }) looking at the relationship between the list and *first* list item. - const listIndentsChild = !!firstListChild && getStartLineAndCharacterForNode(firstListChild, sourceFile).line > containingListOrParentStart.line; + const listIndentsChild = !!firstListChild + && getStartLineAndCharacterForNode(firstListChild, sourceFile).line + > containingListOrParentStart.line; let actualIndentation = getActualIndentationForListItem(current, sourceFile, options, listIndentsChild); if (actualIndentation !== Value.Unknown) { return actualIndentation + indentationDelta; } // try to fetch actual indentation for current node from source text - actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options); + actualIndentation = getActualIndentationForNode( + current, + parent, + currentStart, + parentAndChildShareLine, + sourceFile, + options, + ); if (actualIndentation !== Value.Unknown) { return actualIndentation + indentationDelta; } @@ -309,12 +393,17 @@ export namespace SmartIndenter { // Instead, when at an argument, we unspoof the starting position of the enclosing call expression // *after* applying indentation for the argument. - const useTrueStart = - isArgumentAndStartLineOverlapsExpressionBeingCalled(parent, current, currentStart.line, sourceFile); + const useTrueStart = isArgumentAndStartLineOverlapsExpressionBeingCalled( + parent, + current, + currentStart.line, + sourceFile, + ); current = parent; parent = current.parent; - currentStart = useTrueStart ? sourceFile.getLineAndCharacterOfPosition(current.getStart(sourceFile)) : containingListOrParentStart; + currentStart = useTrueStart ? sourceFile.getLineAndCharacterOfPosition(current.getStart(sourceFile)) + : containingListOrParentStart; } return indentationDelta + getBaseIndentation(options); @@ -329,11 +418,20 @@ export namespace SmartIndenter { /* * Function returns Value.Unknown if indentation cannot be determined */ - function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorSettings): number { + function getActualIndentationForListItemBeforeComma( + commaToken: Node, + sourceFile: SourceFile, + options: EditorSettings, + ): number { // previous token is comma that separates items in list - find the previous item and try to derive indentation from it const commaItemInfo = findListItemInfo(commaToken); if (commaItemInfo && commaItemInfo.listItemIndex > 0) { - return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options); + return deriveActualIndentationFromList( + commaItemInfo.list.getChildren(), + commaItemInfo.listItemIndex - 1, + sourceFile, + options, + ); } else { // handle broken code gracefully @@ -344,19 +442,19 @@ export namespace SmartIndenter { /* * Function returns Value.Unknown if actual indentation for node should not be used (i.e because node is nested expression) */ - function getActualIndentationForNode(current: Node, + function getActualIndentationForNode( + current: Node, parent: Node, currentLineAndChar: LineAndCharacter, parentAndChildShareLine: boolean, sourceFile: SourceFile, - options: EditorSettings): number { - + options: EditorSettings, + ): number { // actual indentation is used for statements\declarations if one of cases below is true: // - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually // - parent and child are not on the same line - const useActualIndentation = - (isDeclaration(current) || isStatementButNotDeclaration(current)) && - (parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine); + const useActualIndentation = (isDeclaration(current) || isStatementButNotDeclaration(current)) + && (parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine); if (!useActualIndentation) { return Value.Unknown; @@ -368,10 +466,15 @@ export namespace SmartIndenter { const enum NextTokenKind { Unknown, OpenBrace, - CloseBrace + CloseBrace, } - function nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken: Node, current: Node, lineAtPosition: number, sourceFile: SourceFile): NextTokenKind { + function nextTokenIsCurlyBraceOnSameLineAsCursor( + precedingToken: Node, + current: Node, + lineAtPosition: number, + sourceFile: SourceFile, + ): NextTokenKind { const nextToken = findNextToken(precedingToken, current, sourceFile); if (!nextToken) { return NextTokenKind.Unknown; @@ -402,17 +505,28 @@ export namespace SmartIndenter { return sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); } - export function isArgumentAndStartLineOverlapsExpressionBeingCalled(parent: Node, child: Node, childStartLine: number, sourceFile: SourceFileLike): boolean { + export function isArgumentAndStartLineOverlapsExpressionBeingCalled( + parent: Node, + child: Node, + childStartLine: number, + sourceFile: SourceFileLike, + ): boolean { if (!(isCallExpression(parent) && contains(parent.arguments, child))) { return false; } const expressionOfCallExpressionEnd = parent.expression.getEnd(); - const expressionOfCallExpressionEndLine = getLineAndCharacterOfPosition(sourceFile, expressionOfCallExpressionEnd).line; + const expressionOfCallExpressionEndLine = + getLineAndCharacterOfPosition(sourceFile, expressionOfCallExpressionEnd).line; return expressionOfCallExpressionEndLine === childStartLine; } - export function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFileLike): boolean { + export function childStartsOnTheSameLineWithElseInIfStatement( + parent: Node, + child: TextRangeWithKind, + childStartLine: number, + sourceFile: SourceFileLike, + ): boolean { if (parent.kind === SyntaxKind.IfStatement && (parent as IfStatement).elseStatement === child) { const elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile)!; Debug.assert(elseKeyword !== undefined); @@ -445,7 +559,12 @@ export namespace SmartIndenter { // whenTrue and whenFalse children to avoid double-indenting their contents. To identify this scenario, // we check for the whenTrue branch beginning on the line that the condition ends, and the whenFalse // branch beginning on the line that the whenTrue branch ends. - export function childIsUnindentedBranchOfConditionalExpression(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFileLike): boolean { + export function childIsUnindentedBranchOfConditionalExpression( + parent: Node, + child: TextRangeWithKind, + childStartLine: number, + sourceFile: SourceFileLike, + ): boolean { if (isConditionalExpression(parent) && (child === parent.whenTrue || child === parent.whenFalse)) { const conditionEndLine = getLineAndCharacterOfPosition(sourceFile, parent.condition.end).line; if (child === parent.whenTrue) { @@ -467,7 +586,12 @@ export namespace SmartIndenter { return false; } - export function argumentStartsOnSameLineAsPreviousArgument(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFileLike): boolean { + export function argumentStartsOnSameLineAsPreviousArgument( + parent: Node, + child: TextRangeWithKind, + childStartLine: number, + sourceFile: SourceFileLike, + ): boolean { if (isCallOrNewExpression(parent)) { if (!parent.arguments) return false; const currentNode = find(parent.arguments, arg => arg.pos === child.pos); @@ -495,7 +619,12 @@ export namespace SmartIndenter { return node && getListByRange(pos, pos, node, sourceFile); } - function getListByRange(start: number, end: number, node: Node, sourceFile: SourceFile): NodeArray | undefined { + function getListByRange( + start: number, + end: number, + node: Node, + sourceFile: SourceFile, + ): NodeArray | undefined { switch (node.kind) { case SyntaxKind.TypeReference: return getList((node as TypeReferenceNode).typeArguments); @@ -514,7 +643,8 @@ export namespace SmartIndenter { case SyntaxKind.Constructor: case SyntaxKind.ConstructorType: case SyntaxKind.ConstructSignature: - return getList((node as SignatureDeclaration).typeParameters) || getList((node as SignatureDeclaration).parameters); + return getList((node as SignatureDeclaration).typeParameters) + || getList((node as SignatureDeclaration).parameters); case SyntaxKind.GetAccessor: return getList((node as GetAccessorDeclaration).parameters); case SyntaxKind.ClassDeclaration: @@ -522,7 +652,14 @@ export namespace SmartIndenter { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.JSDocTemplateTag: - return getList((node as ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag).typeParameters); + return getList( + (node as + | ClassDeclaration + | ClassExpression + | InterfaceDeclaration + | TypeAliasDeclaration + | JSDocTemplateTag).typeParameters, + ); case SyntaxKind.NewExpression: case SyntaxKind.CallExpression: return getList((node as CallExpression).typeArguments) || getList((node as CallExpression).arguments); @@ -537,7 +674,8 @@ export namespace SmartIndenter { } function getList(list: NodeArray | undefined): NodeArray | undefined { - return list && rangeContainsStartEnd(getVisualListRange(node, list, sourceFile), start, end) ? list : undefined; + return list && rangeContainsStartEnd(getVisualListRange(node, list, sourceFile), start, end) ? list + : undefined; } } @@ -551,14 +689,27 @@ export namespace SmartIndenter { return list; } - function getActualIndentationForListStartLine(list: NodeArray, sourceFile: SourceFile, options: EditorSettings): number { + function getActualIndentationForListStartLine( + list: NodeArray, + sourceFile: SourceFile, + options: EditorSettings, + ): number { if (!list) { return Value.Unknown; } - return findColumnForFirstNonWhitespaceCharacterInLine(sourceFile.getLineAndCharacterOfPosition(list.pos), sourceFile, options); + return findColumnForFirstNonWhitespaceCharacterInLine( + sourceFile.getLineAndCharacterOfPosition(list.pos), + sourceFile, + options, + ); } - function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings, listIndentsChild: boolean): number { + function getActualIndentationForListItem( + node: Node, + sourceFile: SourceFile, + options: EditorSettings, + listIndentsChild: boolean, + ): number { if (node.parent && node.parent.kind === SyntaxKind.VariableDeclarationList) { // VariableDeclarationList has no wrapping tokens return Value.Unknown; @@ -572,12 +723,18 @@ export namespace SmartIndenter { return result; } } - return getActualIndentationForListStartLine(containingList, sourceFile, options) + (listIndentsChild ? options.indentSize! : 0); // TODO: GH#18217 + return getActualIndentationForListStartLine(containingList, sourceFile, options) + + (listIndentsChild ? options.indentSize! : 0); // TODO: GH#18217 } return Value.Unknown; } - function deriveActualIndentationFromList(list: readonly Node[], index: number, sourceFile: SourceFile, options: EditorSettings): number { + function deriveActualIndentationFromList( + list: readonly Node[], + index: number, + sourceFile: SourceFile, + options: EditorSettings, + ): number { Debug.assert(index >= 0 && index < list.length); const node = list[index]; @@ -599,7 +756,11 @@ export namespace SmartIndenter { return Value.Unknown; } - function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: EditorSettings): number { + function findColumnForFirstNonWhitespaceCharacterInLine( + lineAndCharacter: LineAndCharacter, + sourceFile: SourceFile, + options: EditorSettings, + ): number { const lineStart = sourceFile.getPositionOfLineAndCharacter(lineAndCharacter.line, 0); return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options); } @@ -611,7 +772,12 @@ export namespace SmartIndenter { * value of 'character' for '$' is 3 * value of 'column' for '$' is 6 (assuming that tab size is 4) */ - export function findFirstNonWhitespaceCharacterAndColumn(startPos: number, endPos: number, sourceFile: SourceFileLike, options: EditorSettings) { + export function findFirstNonWhitespaceCharacterAndColumn( + startPos: number, + endPos: number, + sourceFile: SourceFileLike, + options: EditorSettings, + ) { let character = 0; let column = 0; for (let pos = startPos; pos < endPos; pos++) { @@ -632,11 +798,22 @@ export namespace SmartIndenter { return { column, character }; } - export function findFirstNonWhitespaceColumn(startPos: number, endPos: number, sourceFile: SourceFileLike, options: EditorSettings): number { + export function findFirstNonWhitespaceColumn( + startPos: number, + endPos: number, + sourceFile: SourceFileLike, + options: EditorSettings, + ): number { return findFirstNonWhitespaceCharacterAndColumn(startPos, endPos, sourceFile, options).column; } - export function nodeWillIndentChild(settings: FormatCodeSettings, parent: TextRangeWithKind, child: TextRangeWithKind | undefined, sourceFile: SourceFileLike | undefined, indentByDefault: boolean): boolean { + export function nodeWillIndentChild( + settings: FormatCodeSettings, + parent: TextRangeWithKind, + child: TextRangeWithKind | undefined, + sourceFile: SourceFileLike | undefined, + indentByDefault: boolean, + ): boolean { const childKind = child ? child.kind : SyntaxKind.Unknown; switch (parent.kind) { @@ -689,12 +866,20 @@ export namespace SmartIndenter { case SyntaxKind.VariableDeclaration: case SyntaxKind.PropertyAssignment: case SyntaxKind.BinaryExpression: - if (!settings.indentMultiLineObjectLiteralBeginningOnBlankLine && sourceFile && childKind === SyntaxKind.ObjectLiteralExpression) { // TODO: GH#18217 + if ( + !settings.indentMultiLineObjectLiteralBeginningOnBlankLine && sourceFile + && childKind === SyntaxKind.ObjectLiteralExpression + ) { // TODO: GH#18217 return rangeIsOnOneLine(sourceFile, child!); } - if (parent.kind === SyntaxKind.BinaryExpression && sourceFile && child && childKind === SyntaxKind.JsxElement) { - const parentStartLine = sourceFile.getLineAndCharacterOfPosition(skipTrivia(sourceFile.text, parent.pos)).line; - const childStartLine = sourceFile.getLineAndCharacterOfPosition(skipTrivia(sourceFile.text, child.pos)).line; + if ( + parent.kind === SyntaxKind.BinaryExpression && sourceFile && child + && childKind === SyntaxKind.JsxElement + ) { + const parentStartLine = + sourceFile.getLineAndCharacterOfPosition(skipTrivia(sourceFile.text, parent.pos)).line; + const childStartLine = + sourceFile.getLineAndCharacterOfPosition(skipTrivia(sourceFile.text, child.pos)).line; return parentStartLine !== childStartLine; } if (parent.kind !== SyntaxKind.BinaryExpression) { @@ -722,8 +907,9 @@ export namespace SmartIndenter { case SyntaxKind.ExportDeclaration: return childKind !== SyntaxKind.NamedExports; case SyntaxKind.ImportDeclaration: - return childKind !== SyntaxKind.ImportClause || - (!!(child as ImportClause).namedBindings && (child as ImportClause).namedBindings!.kind !== SyntaxKind.NamedImports); + return childKind !== SyntaxKind.ImportClause + || (!!(child as ImportClause).namedBindings + && (child as ImportClause).namedBindings!.kind !== SyntaxKind.NamedImports); case SyntaxKind.JsxElement: return childKind !== SyntaxKind.JsxClosingElement; case SyntaxKind.JsxFragment: @@ -755,7 +941,13 @@ export namespace SmartIndenter { * True when the parent node should indent the given child by an explicit rule. * @param isNextChild If true, we are judging indent of a hypothetical child *after* this one, not the current child. */ - export function shouldIndentChildNode(settings: FormatCodeSettings, parent: TextRangeWithKind, child?: Node, sourceFile?: SourceFileLike, isNextChild = false): boolean { + export function shouldIndentChildNode( + settings: FormatCodeSettings, + parent: TextRangeWithKind, + child?: Node, + sourceFile?: SourceFileLike, + isNextChild = false, + ): boolean { return nodeWillIndentChild(settings, parent, child, sourceFile, /*indentByDefault*/ false) && !(isNextChild && child && isControlFlowEndingStatement(child.kind, parent)); } diff --git a/src/services/getEditsForFileRename.ts b/src/services/getEditsForFileRename.ts index ef3a1107fca0b..791541fd3f009 100644 --- a/src/services/getEditsForFileRename.ts +++ b/src/services/getEditsForFileRename.ts @@ -67,7 +67,15 @@ export function getEditsForFileRename( const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName, sourceMapper); const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper); return textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => { - updateTsconfigFiles(program, changeTracker, oldToNew, oldFileOrDirPath, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames); + updateTsconfigFiles( + program, + changeTracker, + oldToNew, + oldFileOrDirPath, + newFileOrDirPath, + host.getCurrentDirectory(), + useCaseSensitiveFileNames, + ); updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName); }); } @@ -80,13 +88,19 @@ export function getEditsForFileRename( export type PathUpdater = (path: string) => string | undefined; // exported for tests /** @internal */ -export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName, sourceMapper: SourceMapper | undefined): PathUpdater { +export function getPathUpdater( + oldFileOrDirPath: string, + newFileOrDirPath: string, + getCanonicalFileName: GetCanonicalFileName, + sourceMapper: SourceMapper | undefined, +): PathUpdater { const canonicalOldPath = getCanonicalFileName(oldFileOrDirPath); return path => { const originalPath = sourceMapper && sourceMapper.tryGetSourcePosition({ fileName: path, pos: 0 }); const updatedPath = getUpdatedPath(originalPath ? originalPath.fileName : path); return originalPath - ? updatedPath === undefined ? undefined : makeCorrespondingRelativeChange(originalPath.fileName, updatedPath, path, getCanonicalFileName) + ? updatedPath === undefined ? undefined + : makeCorrespondingRelativeChange(originalPath.fileName, updatedPath, path, getCanonicalFileName) : updatedPath; }; @@ -98,12 +112,25 @@ export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: strin } // Relative path from a0 to b0 should be same as relative path from a1 to b1. Returns b1. -function makeCorrespondingRelativeChange(a0: string, b0: string, a1: string, getCanonicalFileName: GetCanonicalFileName): string { +function makeCorrespondingRelativeChange( + a0: string, + b0: string, + a1: string, + getCanonicalFileName: GetCanonicalFileName, +): string { const rel = getRelativePathFromFile(a0, b0, getCanonicalFileName); return combinePathsSafe(getDirectoryPath(a1), rel); } -function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, oldFileOrDirPath: string, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void { +function updateTsconfigFiles( + program: Program, + changeTracker: textChanges.ChangeTracker, + oldToNew: PathUpdater, + oldFileOrDirPath: string, + newFileOrDirPath: string, + currentDirectory: string, + useCaseSensitiveFileNames: boolean, +): void { const { configFile } = program.getCompilerOptions(); if (!configFile) return; const configDir = getDirectoryPath(configFile.fileName); @@ -117,14 +144,33 @@ function updateTsconfigFiles(program: Program, changeTracker: textChanges.Change case "include": case "exclude": { const foundExactMatch = updatePaths(property); - if (foundExactMatch || propertyName !== "include" || !isArrayLiteralExpression(property.initializer)) return; - const includes = mapDefined(property.initializer.elements, e => isStringLiteral(e) ? e.text : undefined); + if (foundExactMatch || propertyName !== "include" || !isArrayLiteralExpression(property.initializer)) { + return; + } + const includes = mapDefined( + property.initializer.elements, + e => isStringLiteral(e) ? e.text : undefined, + ); if (includes.length === 0) return; - const matchers = getFileMatcherPatterns(configDir, /*excludes*/[], includes, useCaseSensitiveFileNames, currentDirectory); + const matchers = getFileMatcherPatterns( + configDir, + /*excludes*/ [], + includes, + useCaseSensitiveFileNames, + currentDirectory, + ); // If there isn't some include for this, add a new one. - if (getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(oldFileOrDirPath) && - !getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(newFileOrDirPath)) { - changeTracker.insertNodeAfter(configFile, last(property.initializer.elements), factory.createStringLiteral(relativePath(newFileOrDirPath))); + if ( + getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames) + .test(oldFileOrDirPath) + && !getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames) + .test(newFileOrDirPath) + ) { + changeTracker.insertNodeAfter( + configFile, + last(property.initializer.elements), + factory.createStringLiteral(relativePath(newFileOrDirPath)), + ); } return; } @@ -136,7 +182,7 @@ function updateTsconfigFiles(program: Program, changeTracker: textChanges.Change updatePaths(property); } else if (propertyName === "paths") { - forEachProperty(property.initializer, (pathsProperty) => { + forEachProperty(property.initializer, pathsProperty => { if (!isArrayLiteralExpression(pathsProperty.initializer)) return; for (const e of pathsProperty.initializer.elements) { tryUpdateString(e); @@ -149,7 +195,8 @@ function updateTsconfigFiles(program: Program, changeTracker: textChanges.Change }); function updatePaths(property: PropertyAssignment): boolean { - const elements = isArrayLiteralExpression(property.initializer) ? property.initializer.elements : [property.initializer]; + const elements = isArrayLiteralExpression(property.initializer) ? property.initializer.elements + : [property.initializer]; let foundExactMatch = false; for (const element of elements) { foundExactMatch = tryUpdateString(element) || foundExactMatch; @@ -163,7 +210,11 @@ function updateTsconfigFiles(program: Program, changeTracker: textChanges.Change const updated = oldToNew(elementFileName); if (updated !== undefined) { - changeTracker.replaceRangeWithText(configFile!, createStringRange(element, configFile!), relativePath(updated)); + changeTracker.replaceRangeWithText( + configFile!, + createStringRange(element, configFile!), + relativePath(updated), + ); return true; } return false; @@ -194,30 +245,50 @@ function updateImports( const importingSourceFileMoved = newFromOld !== undefined || oldFromNew !== undefined; - updateImportsWorker(sourceFile, changeTracker, - referenceText => { - if (!pathIsRelative(referenceText)) return undefined; - const oldAbsolute = combinePathsSafe(oldImportFromDirectory, referenceText); - const newAbsolute = oldToNew(oldAbsolute); - return newAbsolute === undefined ? undefined : ensurePathIsNonModuleName(getRelativePathFromDirectory(newImportFromDirectory, newAbsolute, getCanonicalFileName)); - }, - importLiteral => { - const importedModuleSymbol = program.getTypeChecker().getSymbolAtLocation(importLiteral); - // No need to update if it's an ambient module^M - if (importedModuleSymbol?.declarations && importedModuleSymbol.declarations.some(d => isAmbientModule(d))) return undefined; + updateImportsWorker(sourceFile, changeTracker, referenceText => { + if (!pathIsRelative(referenceText)) return undefined; + const oldAbsolute = combinePathsSafe(oldImportFromDirectory, referenceText); + const newAbsolute = oldToNew(oldAbsolute); + return newAbsolute === undefined ? undefined + : ensurePathIsNonModuleName( + getRelativePathFromDirectory(newImportFromDirectory, newAbsolute, getCanonicalFileName), + ); + }, importLiteral => { + const importedModuleSymbol = program.getTypeChecker().getSymbolAtLocation(importLiteral); + // No need to update if it's an ambient module^M + if (importedModuleSymbol?.declarations && importedModuleSymbol.declarations.some(d => isAmbientModule(d))) { + return undefined; + } - const toImport = oldFromNew !== undefined - // If we're at the new location (file was already renamed), need to redo module resolution starting from the old location. - // TODO:GH#18217 - ? getSourceFileToImportFromResolved(importLiteral, resolveModuleName(importLiteral.text, oldImportFromPath, program.getCompilerOptions(), host as ModuleResolutionHost), - oldToNew, allFiles) - : getSourceFileToImport(importedModuleSymbol, importLiteral, sourceFile, program, host, oldToNew); + const toImport = oldFromNew !== undefined + // If we're at the new location (file was already renamed), need to redo module resolution starting from the old location. + // TODO:GH#18217 + ? getSourceFileToImportFromResolved( + importLiteral, + resolveModuleName( + importLiteral.text, + oldImportFromPath, + program.getCompilerOptions(), + host as ModuleResolutionHost, + ), + oldToNew, + allFiles, + ) + : getSourceFileToImport(importedModuleSymbol, importLiteral, sourceFile, program, host, oldToNew); - // Need an update if the imported file moved, or the importing file moved and was using a relative path. - return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text))) - ? moduleSpecifiers.updateModuleSpecifier(program.getCompilerOptions(), sourceFile, getCanonicalFileName(newImportFromPath) as Path, toImport.newFileName, createModuleSpecifierResolutionHost(program, host), importLiteral.text) - : undefined; - }); + // Need an update if the imported file moved, or the importing file moved and was using a relative path. + return toImport !== undefined + && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text))) + ? moduleSpecifiers.updateModuleSpecifier( + program.getCompilerOptions(), + sourceFile, + getCanonicalFileName(newImportFromPath) as Path, + toImport.newFileName, + createModuleSpecifierResolutionHost(program, host), + importLiteral.text, + ) + : undefined; + }); } } @@ -245,18 +316,29 @@ function getSourceFileToImport( // `find` should succeed because we checked for ambient modules before calling this function. const oldFileName = find(importedModuleSymbol.declarations, isSourceFile)!.fileName; const newFileName = oldToNew(oldFileName); - return newFileName === undefined ? { newFileName: oldFileName, updated: false } : { newFileName, updated: true }; + return newFileName === undefined ? { newFileName: oldFileName, updated: false } + : { newFileName, updated: true }; } else { const mode = getModeForUsageLocation(importingSourceFile, importLiteral); - const resolved = host.resolveModuleNameLiterals || !host.resolveModuleNames ? - importingSourceFile.resolvedModules?.get(importLiteral.text, mode) : - host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName, mode); + const resolved = host.resolveModuleNameLiterals || !host.resolveModuleNames + ? importingSourceFile.resolvedModules?.get(importLiteral.text, mode) + : host.getResolvedModuleWithFailedLookupLocationsFromCache + && host.getResolvedModuleWithFailedLookupLocationsFromCache( + importLiteral.text, + importingSourceFile.fileName, + mode, + ); return getSourceFileToImportFromResolved(importLiteral, resolved, oldToNew, program.getSourceFiles()); } } -function getSourceFileToImportFromResolved(importLiteral: StringLiteralLike, resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, sourceFiles: readonly SourceFile[]): ToImport | undefined { +function getSourceFileToImportFromResolved( + importLiteral: StringLiteralLike, + resolved: ResolvedModuleWithFailedLookupLocations | undefined, + oldToNew: PathUpdater, + sourceFiles: readonly SourceFile[], +): ToImport | undefined { // Search through all locations looking for a moved file, and only then test already existing files. // This is because if `a.ts` is compiled to `a.js` and `a.ts` is moved, we don't want to resolve anything to `a.js`, but to `a.ts`'s new location. if (!resolved) return undefined; @@ -271,7 +353,8 @@ function getSourceFileToImportFromResolved(importLiteral: StringLiteralLike, res const result = forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJsonExisting) // Then failed lookups except package.json since we dont want to touch them (only included ts/js files). // At this point, the confidence level of this fix being correct is too low to change bare specifiers or absolute paths. - || pathIsRelative(importLiteral.text) && forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJson); + || pathIsRelative(importLiteral.text) + && forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJson); if (result) return result; // If nothing changed, then result is resolved module file thats not updated @@ -293,15 +376,24 @@ function getSourceFileToImportFromResolved(importLiteral: StringLiteralLike, res } } -function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined) { +function updateImportsWorker( + sourceFile: SourceFile, + changeTracker: textChanges.ChangeTracker, + updateRef: (refText: string) => string | undefined, + updateImport: (importLiteral: StringLiteralLike) => string | undefined, +) { for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162 const updated = updateRef(ref.fileName); - if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated); + if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) { + changeTracker.replaceRangeWithText(sourceFile, ref, updated); + } } for (const importStringLiteral of sourceFile.imports) { const updated = updateImport(importStringLiteral); - if (updated !== undefined && updated !== importStringLiteral.text) changeTracker.replaceRangeWithText(sourceFile, createStringRange(importStringLiteral, sourceFile), updated); + if (updated !== undefined && updated !== importStringLiteral.text) { + changeTracker.replaceRangeWithText(sourceFile, createStringRange(importStringLiteral, sourceFile), updated); + } } } diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index 3688a688c53d8..8e715092fc23d 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -3,7 +3,8 @@ import { AssignmentExpression, AssignmentOperatorToken, CallLikeExpression, - canHaveSymbol, concatenate, + canHaveSymbol, + concatenate, createTextSpan, createTextSpanFromBounds, createTextSpanFromNode, @@ -105,9 +106,20 @@ import { } from "./_namespaces/ts"; /** @internal */ -export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number, searchOtherFilesOnly?: boolean, stopAtAlias?: boolean): readonly DefinitionInfo[] | undefined { +export function getDefinitionAtPosition( + program: Program, + sourceFile: SourceFile, + position: number, + searchOtherFilesOnly?: boolean, + stopAtAlias?: boolean, +): readonly DefinitionInfo[] | undefined { const resolvedRef = getReferenceAtPosition(sourceFile, position, program); - const fileReferenceDefinition = resolvedRef && [getDefinitionInfoForFileReference(resolvedRef.reference.fileName, resolvedRef.fileName, resolvedRef.unverified)] || emptyArray; + const fileReferenceDefinition = resolvedRef + && [getDefinitionInfoForFileReference( + resolvedRef.reference.fileName, + resolvedRef.fileName, + resolvedRef.unverified, + )] || emptyArray; if (resolvedRef?.file) { // If `file` is missing, do a symbol-based lookup as well return fileReferenceDefinition; @@ -121,32 +133,52 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile const { parent } = node; const typeChecker = program.getTypeChecker(); - if (node.kind === SyntaxKind.OverrideKeyword || (isIdentifier(node) && isJSDocOverrideTag(parent) && parent.tagName === node)) { + if ( + node.kind === SyntaxKind.OverrideKeyword + || (isIdentifier(node) && isJSDocOverrideTag(parent) && parent.tagName === node) + ) { return getDefinitionFromOverriddenMember(typeChecker, node) || emptyArray; } // Labels if (isJumpStatementTarget(node)) { const label = getTargetLabel(node.parent, node.text); - return label ? [createDefinitionInfoFromName(typeChecker, label, ScriptElementKind.label, node.text, /*containerName*/ undefined!)] : undefined; // TODO: GH#18217 + return label + ? [createDefinitionInfoFromName( + typeChecker, + label, + ScriptElementKind.label, + node.text, + /*containerName*/ undefined!, + )] : undefined; // TODO: GH#18217 } if (node.kind === SyntaxKind.ReturnKeyword) { - const functionDeclaration = findAncestor(node.parent, n => - isClassStaticBlockDeclaration(n) ? "quit" : isFunctionLikeDeclaration(n)) as FunctionLikeDeclaration | undefined; - return functionDeclaration ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined; + const functionDeclaration = findAncestor( + node.parent, + n => isClassStaticBlockDeclaration(n) ? "quit" : isFunctionLikeDeclaration(n), + ) as FunctionLikeDeclaration | undefined; + return functionDeclaration ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] + : undefined; } if (node.kind === SyntaxKind.AwaitKeyword) { - const functionDeclaration = findAncestor(node, n => isFunctionLikeDeclaration(n)) as FunctionLikeDeclaration | undefined; - const isAsyncFunction = functionDeclaration && some(functionDeclaration.modifiers, (node) => node.kind === SyntaxKind.AsyncKeyword); - return isAsyncFunction ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined; + const functionDeclaration = findAncestor(node, n => isFunctionLikeDeclaration(n)) as + | FunctionLikeDeclaration + | undefined; + 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)) as + | FunctionLikeDeclaration + | undefined; const isGeneratorFunction = functionDeclaration && functionDeclaration.asteriskToken; - return isGeneratorFunction ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined; + return isGeneratorFunction ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] + : undefined; } if (isStaticModifier(node) && isClassStaticBlockDeclaration(node.parent)) { @@ -159,7 +191,16 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile return map(staticBlocks, staticBlock => { let { pos } = moveRangePastModifiers(staticBlock); pos = skipTrivia(sourceFile.text, pos); - return createDefinitionInfoFromName(typeChecker, staticBlock, ScriptElementKind.constructorImplementationElement, "static {}", containerName, /*unverified*/ false, failedAliasResolution, { start: pos, length: "static".length }); + return createDefinitionInfoFromName( + typeChecker, + staticBlock, + ScriptElementKind.constructorImplementationElement, + "static {}", + containerName, + /*unverified*/ false, + failedAliasResolution, + { start: pos, length: "static".length }, + ); }); } @@ -168,7 +209,10 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile if (searchOtherFilesOnly && failedAliasResolution) { // We couldn't resolve the specific import, try on the module specifier. - const importDeclaration = forEach([node, ...symbol?.declarations || emptyArray], n => findAncestor(n, isAnyImportOrBareOrAccessedRequire)); + const importDeclaration = forEach( + [node, ...symbol?.declarations || emptyArray], + n => findAncestor(n, isAnyImportOrBareOrAccessedRequire), + ); const moduleSpecifier = importDeclaration && tryGetModuleSpecifierFromDeclaration(importDeclaration); if (moduleSpecifier) { ({ symbol, failedAliasResolution } = getSymbol(moduleSpecifier, typeChecker, stopAtAlias)); @@ -179,7 +223,10 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile if (!symbol && isModuleSpecifierLike(fallbackNode)) { // We couldn't resolve the module specifier as an external module, but it could // be that module resolution succeeded but the target was not a module. - const ref = sourceFile.resolvedModules?.get(fallbackNode.text, getModeForUsageLocation(sourceFile, fallbackNode))?.resolvedModule; + const ref = sourceFile.resolvedModules?.get( + fallbackNode.text, + getModeForUsageLocation(sourceFile, fallbackNode), + )?.resolvedModule; if (ref) { return [{ name: fallbackNode.text, @@ -201,7 +248,9 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile return concatenate(fileReferenceDefinition, getDefinitionInfoForIndexSignatures(node, typeChecker)); } - if (searchOtherFilesOnly && every(symbol.declarations, d => d.getSourceFile().fileName === sourceFile.fileName)) return undefined; + if (searchOtherFilesOnly && every(symbol.declarations, d => d.getSourceFile().fileName === sourceFile.fileName)) { + return undefined; + } const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node); // Don't go to the component constructor definition for a JSX element, just go to the component definition. @@ -213,7 +262,8 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile return [sigInfo]; } else { - const defs = getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution, calledDeclaration) || emptyArray; + const defs = getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution, calledDeclaration) + || emptyArray; // For a 'super()' call, put the signature first, else put the variable first. return node.kind === SyntaxKind.SuperKeyword ? [sigInfo, ...defs] : [...defs, sigInfo]; } @@ -226,7 +276,9 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile // assignment. This case and others are handled by the following code. if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { const shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); - const definitions = shorthandSymbol?.declarations ? shorthandSymbol.declarations.map(decl => createDefinitionInfo(decl, typeChecker, shorthandSymbol, node, /*unverified*/ false, failedAliasResolution)) : emptyArray; + const definitions = shorthandSymbol?.declarations ? shorthandSymbol.declarations.map(decl => + createDefinitionInfo(decl, typeChecker, shorthandSymbol, node, /*unverified*/ false, failedAliasResolution) + ) : emptyArray; return concatenate(definitions, getDefinitionFromObjectLiteralElement(typeChecker, node)); } @@ -241,8 +293,10 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile // pr/*destination*/op1: number // } // bar(({pr/*goto*/op1})=>{}); - if (isPropertyName(node) && isBindingElement(parent) && isObjectBindingPattern(parent.parent) && - (node === (parent.propertyName || parent.name))) { + if ( + isPropertyName(node) && isBindingElement(parent) && isObjectBindingPattern(parent.parent) + && (node === (parent.propertyName || parent.name)) + ) { const name = getNameFromPropertyName(node); const type = typeChecker.getTypeAtLocation(parent.parent); return name === undefined ? emptyArray : flatMap(type.isUnion() ? type.types : [type], t => { @@ -252,7 +306,11 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile } const objectLiteralElementDefinition = getDefinitionFromObjectLiteralElement(typeChecker, node); - return concatenate(fileReferenceDefinition, objectLiteralElementDefinition.length ? objectLiteralElementDefinition : getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution)); + return concatenate( + fileReferenceDefinition, + objectLiteralElementDefinition.length ? objectLiteralElementDefinition + : getDefinitionFromSymbol(typeChecker, symbol, node, failedAliasResolution), + ); } /** @@ -264,7 +322,8 @@ function symbolMatchesSignature(s: Symbol, calledDeclaration: SignatureDeclarati return s === calledDeclaration.symbol || s === calledDeclaration.symbol.parent || isAssignmentExpression(calledDeclaration.parent) - || (!isCallLikeExpression(calledDeclaration.parent) && s === tryCast(calledDeclaration.parent, canHaveSymbol)?.symbol); + || (!isCallLikeExpression(calledDeclaration.parent) + && s === tryCast(calledDeclaration.parent, canHaveSymbol)?.symbol); } // If the current location we want to find its definition is in an object literal, try to get the contextual type for the @@ -281,8 +340,10 @@ function getDefinitionFromObjectLiteralElement(typeChecker: TypeChecker, node: N if (element) { const contextualType = element && typeChecker.getContextualType(element.parent); if (contextualType) { - return flatMap(getPropertySymbolsFromContextualType(element, typeChecker, contextualType, /*unionSymbolOk*/ false), propertySymbol => - getDefinitionFromSymbol(typeChecker, propertySymbol, node)); + return flatMap( + getPropertySymbolsFromContextualType(element, typeChecker, contextualType, /*unionSymbolOk*/ false), + propertySymbol => getDefinitionFromSymbol(typeChecker, propertySymbol, node), + ); } } return emptyArray; @@ -311,7 +372,11 @@ function getDefinitionFromOverriddenMember(typeChecker: TypeChecker, node: Node) } /** @internal */ -export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { reference: FileReference, fileName: string, unverified: boolean, file?: SourceFile } | undefined { +export function getReferenceAtPosition( + sourceFile: SourceFile, + position: number, + program: Program, +): { reference: FileReference; fileName: string; unverified: boolean; file?: SourceFile; } | undefined { const referencePath = findReferenceInPosition(sourceFile.referencedFiles, position); if (referencePath) { const file = program.getSourceFileFromReference(sourceFile, referencePath); @@ -320,7 +385,10 @@ export function getReferenceAtPosition(sourceFile: SourceFile, position: number, const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position); if (typeReferenceDirective) { - const reference = program.getResolvedTypeReferenceDirectives().get(typeReferenceDirective.fileName, typeReferenceDirective.resolutionMode || sourceFile.impliedNodeFormat)?.resolvedTypeReferenceDirective; + const reference = program.getResolvedTypeReferenceDirectives().get( + typeReferenceDirective.fileName, + typeReferenceDirective.resolutionMode || sourceFile.impliedNodeFormat, + )?.resolvedTypeReferenceDirective; const file = reference && program.getSourceFile(reference.resolvedFileName!); // TODO:GH#18217 return file && { reference: typeReferenceDirective, fileName: file.fileName, file, unverified: false }; } @@ -333,8 +401,14 @@ export function getReferenceAtPosition(sourceFile: SourceFile, position: number, if (sourceFile.resolvedModules?.size()) { const node = getTouchingToken(sourceFile, position); - if (isModuleSpecifierLike(node) && isExternalModuleNameRelative(node.text) && sourceFile.resolvedModules.has(node.text, getModeForUsageLocation(sourceFile, node))) { - const verifiedFileName = sourceFile.resolvedModules.get(node.text, getModeForUsageLocation(sourceFile, node))?.resolvedModule?.resolvedFileName; + if ( + isModuleSpecifierLike(node) && isExternalModuleNameRelative(node.text) + && sourceFile.resolvedModules.has(node.text, getModeForUsageLocation(sourceFile, node)) + ) { + const verifiedFileName = sourceFile.resolvedModules.get( + node.text, + getModeForUsageLocation(sourceFile, node), + )?.resolvedModule?.resolvedFileName; const fileName = verifiedFileName || resolvePath(getDirectoryPath(sourceFile.fileName), node.text); return { file: program.getSourceFile(fileName), @@ -342,7 +416,7 @@ export function getReferenceAtPosition(sourceFile: SourceFile, position: number, reference: { pos: node.getStart(), end: node.getEnd(), - fileName: node.text + fileName: node.text, }, unverified: !verifiedFileName, }; @@ -374,12 +448,20 @@ const typesWithUnwrappedTypeArguments = new Set([ "Omit", ]); -function shouldUnwrapFirstTypeArgumentTypeDefinitionFromTypeReference(typeChecker: TypeChecker, type: TypeReference): boolean { +function shouldUnwrapFirstTypeArgumentTypeDefinitionFromTypeReference( + typeChecker: TypeChecker, + type: TypeReference, +): boolean { const referenceName = type.symbol.name; if (!typesWithUnwrappedTypeArguments.has(referenceName)) { return false; } - const globalType = typeChecker.resolveName(referenceName, /*location*/ undefined, SymbolFlags.Type, /*excludeGlobals*/ false); + const globalType = typeChecker.resolveName( + referenceName, + /*location*/ undefined, + SymbolFlags.Type, + /*excludeGlobals*/ false, + ); return !!globalType && globalType === type.target.symbol; } @@ -391,27 +473,53 @@ function shouldUnwrapFirstTypeArgumentTypeDefinitionFromAlias(typeChecker: TypeC if (!typesWithUnwrappedTypeArguments.has(referenceName)) { return false; } - const globalType = typeChecker.resolveName(referenceName, /*location*/ undefined, SymbolFlags.Type, /*excludeGlobals*/ false); + const globalType = typeChecker.resolveName( + referenceName, + /*location*/ undefined, + SymbolFlags.Type, + /*excludeGlobals*/ false, + ); return !!globalType && globalType === type.aliasSymbol; } -function getFirstTypeArgumentDefinitions(typeChecker: TypeChecker, type: Type, node: Node, failedAliasResolution: boolean | undefined): readonly DefinitionInfo[] { - if (!!(getObjectFlags(type) & ObjectFlags.Reference) && shouldUnwrapFirstTypeArgumentTypeDefinitionFromTypeReference(typeChecker, type as TypeReference)) { - return definitionFromType(typeChecker.getTypeArguments(type as TypeReference)[0], typeChecker, node, failedAliasResolution); +function getFirstTypeArgumentDefinitions( + typeChecker: TypeChecker, + type: Type, + node: Node, + failedAliasResolution: boolean | undefined, +): readonly DefinitionInfo[] { + if ( + !!(getObjectFlags(type) & ObjectFlags.Reference) + && shouldUnwrapFirstTypeArgumentTypeDefinitionFromTypeReference(typeChecker, type as TypeReference) + ) { + return definitionFromType( + typeChecker.getTypeArguments(type as TypeReference)[0], + typeChecker, + node, + failedAliasResolution, + ); } if (shouldUnwrapFirstTypeArgumentTypeDefinitionFromAlias(typeChecker, type) && type.aliasTypeArguments) { return definitionFromType(type.aliasTypeArguments[0], typeChecker, node, failedAliasResolution); } if ( - (getObjectFlags(type) & ObjectFlags.Mapped) && - (type as MappedType).target && - shouldUnwrapFirstTypeArgumentTypeDefinitionFromAlias(typeChecker, (type as MappedType).target!) + (getObjectFlags(type) & ObjectFlags.Mapped) + && (type as MappedType).target + && shouldUnwrapFirstTypeArgumentTypeDefinitionFromAlias(typeChecker, (type as MappedType).target!) ) { const declaration = type.aliasSymbol?.declarations?.[0]; - if (declaration && isTypeAliasDeclaration(declaration) && isTypeReferenceNode(declaration.type) && declaration.type.typeArguments) { - return definitionFromType(typeChecker.getTypeAtLocation(declaration.type.typeArguments[0]), typeChecker, node, failedAliasResolution); + if ( + declaration && isTypeAliasDeclaration(declaration) && isTypeReferenceNode(declaration.type) + && declaration.type.typeArguments + ) { + return definitionFromType( + typeChecker.getTypeAtLocation(declaration.type.typeArguments[0]), + typeChecker, + node, + failedAliasResolution, + ); } } @@ -420,14 +528,23 @@ function getFirstTypeArgumentDefinitions(typeChecker: TypeChecker, type: Type, n /// Goto type /** @internal */ -export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile: SourceFile, position: number): readonly DefinitionInfo[] | undefined { +export function getTypeDefinitionAtPosition( + typeChecker: TypeChecker, + sourceFile: SourceFile, + position: number, +): readonly DefinitionInfo[] | undefined { const node = getTouchingPropertyName(sourceFile, position); if (node === sourceFile) { return undefined; } if (isImportMeta(node.parent) && node.parent.name === node) { - return definitionFromType(typeChecker.getTypeAtLocation(node.parent), typeChecker, node.parent, /*failedAliasResolution*/ false); + return definitionFromType( + typeChecker.getTypeAtLocation(node.parent), + typeChecker, + node.parent, + /*failedAliasResolution*/ false, + ); } const { symbol, failedAliasResolution } = getSymbol(node, typeChecker, /*stopAtAlias*/ false); if (!symbol) return undefined; @@ -437,26 +554,41 @@ export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile const fromReturnType = returnType && definitionFromType(returnType, typeChecker, node, failedAliasResolution); // If a function returns 'void' or some other type with no definition, just return the function definition. - const [resolvedType, typeDefinitions] = fromReturnType && fromReturnType.length !== 0 ? - [returnType, fromReturnType] : - [typeAtLocation, definitionFromType(typeAtLocation, typeChecker, node, failedAliasResolution)]; - - return typeDefinitions.length ? [...getFirstTypeArgumentDefinitions(typeChecker, resolvedType, node, failedAliasResolution), ...typeDefinitions] - : !(symbol.flags & SymbolFlags.Value) && symbol.flags & SymbolFlags.Type ? getDefinitionFromSymbol(typeChecker, skipAlias(symbol, typeChecker), node, failedAliasResolution) - : undefined; + const [resolvedType, typeDefinitions] = fromReturnType && fromReturnType.length !== 0 + ? [returnType, fromReturnType] + : [typeAtLocation, definitionFromType(typeAtLocation, typeChecker, node, failedAliasResolution)]; + + return typeDefinitions.length + ? [ + ...getFirstTypeArgumentDefinitions(typeChecker, resolvedType, node, failedAliasResolution), + ...typeDefinitions, + ] + : !(symbol.flags & SymbolFlags.Value) && symbol.flags & SymbolFlags.Type + ? getDefinitionFromSymbol(typeChecker, skipAlias(symbol, typeChecker), node, failedAliasResolution) + : undefined; } -function definitionFromType(type: Type, checker: TypeChecker, node: Node, failedAliasResolution: boolean | undefined): readonly DefinitionInfo[] { - return flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t => - t.symbol && getDefinitionFromSymbol(checker, t.symbol, node, failedAliasResolution)); +function definitionFromType( + type: Type, + checker: TypeChecker, + node: Node, + failedAliasResolution: boolean | undefined, +): readonly DefinitionInfo[] { + return flatMap( + type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], + t => t.symbol && getDefinitionFromSymbol(checker, t.symbol, node, failedAliasResolution), + ); } function tryGetReturnTypeOfFunction(symbol: Symbol, type: Type, checker: TypeChecker): Type | undefined { // If the type is just a function's inferred type, // go-to-type should go to the return type instead, since go-to-definition takes you to the function anyway. - if (type.symbol === symbol || + if ( + type.symbol === symbol // At `const f = () => {}`, the symbol is `f` and the type symbol is at `() => {}` - symbol.valueDeclaration && type.symbol && isVariableDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.initializer === type.symbol.valueDeclaration as Node) { + || symbol.valueDeclaration && type.symbol && isVariableDeclaration(symbol.valueDeclaration) + && symbol.valueDeclaration.initializer === type.symbol.valueDeclaration as Node + ) { const sigs = type.getCallSignatures(); if (sigs.length === 1) return checker.getReturnTypeOfSignature(first(sigs)); } @@ -464,7 +596,11 @@ function tryGetReturnTypeOfFunction(symbol: Symbol, type: Type, checker: TypeChe } /** @internal */ -export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFile, position: number): DefinitionInfoAndBoundSpan | undefined { +export function getDefinitionAndBoundSpan( + program: Program, + sourceFile: SourceFile, + position: number, +): DefinitionInfoAndBoundSpan | undefined { const definitions = getDefinitionAtPosition(program, sourceFile, position); if (!definitions || definitions.length === 0) { @@ -472,9 +608,9 @@ export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFi } // Check if position is on triple slash reference. - const comment = findReferenceInPosition(sourceFile.referencedFiles, position) || - findReferenceInPosition(sourceFile.typeReferenceDirectives, position) || - findReferenceInPosition(sourceFile.libReferenceDirectives, position); + const comment = findReferenceInPosition(sourceFile.referencedFiles, position) + || findReferenceInPosition(sourceFile.typeReferenceDirectives, position) + || findReferenceInPosition(sourceFile.libReferenceDirectives, position); if (comment) { return { definitions, textSpan: createTextSpanFromRange(comment) }; @@ -488,7 +624,10 @@ export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFi // At 'x.foo', see if the type of 'x' has an index signature, and if so find its declarations. function getDefinitionInfoForIndexSignatures(node: Node, checker: TypeChecker): DefinitionInfo[] | undefined { - return mapDefined(checker.getIndexInfosAtLocation(node), info => info.declaration && createDefinitionFromSignatureDeclaration(checker, info.declaration)); + return mapDefined( + checker.getIndexInfosAtLocation(node), + info => info.declaration && createDefinitionFromSignatureDeclaration(checker, info.declaration), + ); } function getSymbol(node: Node, checker: TypeChecker, stopAtAlias: boolean | undefined) { @@ -498,7 +637,10 @@ function getSymbol(node: Node, checker: TypeChecker, stopAtAlias: boolean | unde // import {A, B} from "mod"; // to jump to the implementation directly. let failedAliasResolution = false; - if (symbol?.declarations && symbol.flags & SymbolFlags.Alias && !stopAtAlias && shouldSkipAlias(node, symbol.declarations[0])) { + if ( + symbol?.declarations && symbol.flags & SymbolFlags.Alias && !stopAtAlias + && shouldSkipAlias(node, symbol.declarations[0]) + ) { const aliased = checker.getAliasedSymbol(symbol); if (aliased.declarations) { return { symbol: aliased }; @@ -552,20 +694,43 @@ function isExpandoDeclaration(node: Declaration): boolean { if (!isAssignmentDeclaration(p as Declaration)) return "quit"; return false; }) as AssignmentExpression | undefined; - return !!containingAssignment && getAssignmentDeclarationKind(containingAssignment) === AssignmentDeclarationKind.Property; + return !!containingAssignment + && getAssignmentDeclarationKind(containingAssignment) === AssignmentDeclarationKind.Property; } -function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node, failedAliasResolution?: boolean, excludeDeclaration?: Node): DefinitionInfo[] | undefined { +function getDefinitionFromSymbol( + typeChecker: TypeChecker, + symbol: Symbol, + node: Node, + failedAliasResolution?: boolean, + excludeDeclaration?: Node, +): DefinitionInfo[] | undefined { const filteredDeclarations = filter(symbol.declarations, d => d !== excludeDeclaration); const withoutExpandos = filter(filteredDeclarations, d => !isExpandoDeclaration(d)); const results = some(withoutExpandos) ? withoutExpandos : filteredDeclarations; - return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(results, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node, /*unverified*/ false, failedAliasResolution)); + return getConstructSignatureDefinition() || getCallSignatureDefinition() + || map( + results, + declaration => + createDefinitionInfo( + declaration, + typeChecker, + symbol, + node, + /*unverified*/ false, + failedAliasResolution, + ), + ); function getConstructSignatureDefinition(): DefinitionInfo[] | undefined { // Applicable only if we are in a new expression, or we are on a constructor declaration // and in either case the symbol has a construct signature definition, i.e. class - if (symbol.flags & SymbolFlags.Class && !(symbol.flags & (SymbolFlags.Function | SymbolFlags.Variable)) && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword)) { - const cls = find(filteredDeclarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration"); + if ( + symbol.flags & SymbolFlags.Class && !(symbol.flags & (SymbolFlags.Function | SymbolFlags.Variable)) + && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword) + ) { + const cls = find(filteredDeclarations, isClassLike) + || Debug.fail("Expected declaration to have at least one class-like declaration"); return getSignatureDefinition(cls.members, /*selectConstructors*/ true); } } @@ -576,18 +741,30 @@ function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: : undefined; } - function getSignatureDefinition(signatureDeclarations: readonly Declaration[] | undefined, selectConstructors: boolean): DefinitionInfo[] | undefined { + function getSignatureDefinition( + signatureDeclarations: readonly Declaration[] | undefined, + selectConstructors: boolean, + ): DefinitionInfo[] | undefined { if (!signatureDeclarations) { return undefined; } - const declarations = signatureDeclarations.filter(selectConstructors ? isConstructorDeclaration : isFunctionLike); + const declarations = signatureDeclarations.filter( + selectConstructors ? isConstructorDeclaration : isFunctionLike, + ); const declarationsWithBody = declarations.filter(d => !!(d as FunctionLikeDeclaration).body); // declarations defined on the global scope can be defined on multiple files. Get all of them. return declarations.length ? declarationsWithBody.length !== 0 ? declarationsWithBody.map(x => createDefinitionInfo(x, typeChecker, symbol, node)) - : [createDefinitionInfo(last(declarations), typeChecker, symbol, node, /*unverified*/ false, failedAliasResolution)] + : [createDefinitionInfo( + last(declarations), + typeChecker, + symbol, + node, + /*unverified*/ false, + failedAliasResolution, + )] : undefined; } } @@ -597,15 +774,39 @@ function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: * * @internal */ -export function createDefinitionInfo(declaration: Declaration, checker: TypeChecker, symbol: Symbol, node: Node, unverified?: boolean, failedAliasResolution?: boolean): DefinitionInfo { +export function createDefinitionInfo( + declaration: Declaration, + checker: TypeChecker, + symbol: Symbol, + node: Node, + unverified?: boolean, + failedAliasResolution?: boolean, +): DefinitionInfo { const symbolName = checker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol const symbolKind = SymbolDisplay.getSymbolKind(checker, symbol, node); const containerName = symbol.parent ? checker.symbolToString(symbol.parent, node) : ""; - return createDefinitionInfoFromName(checker, declaration, symbolKind, symbolName, containerName, unverified, failedAliasResolution); + return createDefinitionInfoFromName( + checker, + declaration, + symbolKind, + symbolName, + containerName, + unverified, + failedAliasResolution, + ); } /** Creates a DefinitionInfo directly from the name of a declaration. */ -function createDefinitionInfoFromName(checker: TypeChecker, declaration: Declaration, symbolKind: ScriptElementKind, symbolName: string, containerName: string, unverified?: boolean, failedAliasResolution?: boolean, textSpan?: TextSpan): DefinitionInfo { +function createDefinitionInfoFromName( + checker: TypeChecker, + declaration: Declaration, + symbolKind: ScriptElementKind, + symbolName: string, + containerName: string, + unverified?: boolean, + failedAliasResolution?: boolean, + textSpan?: TextSpan, +): DefinitionInfo { const sourceFile = declaration.getSourceFile(); if (!textSpan) { const name = getNameOfDeclaration(declaration) || declaration; @@ -621,7 +822,7 @@ function createDefinitionInfoFromName(checker: TypeChecker, declaration: Declara ...FindAllReferences.toContextSpan( textSpan, sourceFile, - FindAllReferences.getContextNode(declaration) + FindAllReferences.getContextNode(declaration), ), isLocal: !isDefinitionVisible(checker, declaration), isAmbient: !!(declaration.flags & NodeFlags.Ambient), @@ -635,7 +836,9 @@ function isDefinitionVisible(checker: TypeChecker, declaration: Declaration): bo if (!declaration.parent) return false; // Variable initializers are visible if variable is visible - if (hasInitializer(declaration.parent) && declaration.parent.initializer === declaration) return isDefinitionVisible(checker, declaration.parent as Declaration); + if (hasInitializer(declaration.parent) && declaration.parent.initializer === declaration) { + return isDefinitionVisible(checker, declaration.parent as Declaration); + } // Handle some exceptions here like arrow function, members of class and object literal expression which are technically not visible but we want the definition to be determined by its parent switch (declaration.kind) { @@ -661,7 +864,11 @@ function isDefinitionVisible(checker: TypeChecker, declaration: Declaration): bo } } -function createDefinitionFromSignatureDeclaration(typeChecker: TypeChecker, decl: SignatureDeclaration, failedAliasResolution?: boolean): DefinitionInfo { +function createDefinitionFromSignatureDeclaration( + typeChecker: TypeChecker, + decl: SignatureDeclaration, + failedAliasResolution?: boolean, +): DefinitionInfo { return createDefinitionInfo(decl, typeChecker, decl.symbol, decl, /*unverified*/ false, failedAliasResolution); } @@ -686,14 +893,18 @@ function getDefinitionInfoForFileReference(name: string, targetFileName: string, function getAncestorCallLikeExpression(node: Node): CallLikeExpression | undefined { const target = findAncestor(node, n => !isRightSideOfPropertyAccess(n)); const callLike = target?.parent; - return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target ? callLike : undefined; + return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target ? callLike + : undefined; } function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined { const callLike = getAncestorCallLikeExpression(node); const signature = callLike && typeChecker.getResolvedSignature(callLike); // Don't go to a function type, go to the value having that type. - return tryCast(signature && signature.declaration, (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d)); + return tryCast( + signature && signature.declaration, + (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d), + ); } function isConstructorLike(node: Node): boolean { diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index f79eb63627f3c..64ef963978d49 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -102,11 +102,26 @@ export type ImportTracker = (exportSymbol: Symbol, exportInfo: ExportInfo, isFor * * @internal */ -export function createImportTracker(sourceFiles: readonly SourceFile[], sourceFilesSet: ReadonlySet, checker: TypeChecker, cancellationToken: CancellationToken | undefined): ImportTracker { +export function createImportTracker( + sourceFiles: readonly SourceFile[], + sourceFilesSet: ReadonlySet, + checker: TypeChecker, + cancellationToken: CancellationToken | undefined, +): ImportTracker { const allDirectImports = getDirectImportsMap(sourceFiles, checker, cancellationToken); return (exportSymbol, exportInfo, isForRename) => { - const { directImports, indirectUsers } = getImportersForExport(sourceFiles, sourceFilesSet, allDirectImports, exportInfo, checker, cancellationToken); - return { indirectUsers, ...getSearchesFromDirectImports(directImports, exportSymbol, exportInfo.exportKind, checker, isForRename) }; + const { directImports, indirectUsers } = getImportersForExport( + sourceFiles, + sourceFilesSet, + allDirectImports, + exportInfo, + checker, + cancellationToken, + ); + return { + indirectUsers, + ...getSearchesFromDirectImports(directImports, exportSymbol, exportInfo.exportKind, checker, isForRename), + }; }; } @@ -121,12 +136,21 @@ export interface ExportInfo { } /** @internal */ -export const enum ExportKind { Named, Default, ExportEquals } +export const enum ExportKind { + Named, + Default, + ExportEquals, +} /** @internal */ -export const enum ImportExport { Import, Export } +export const enum ImportExport { + Import, + Export, +} -interface AmbientModuleDeclaration extends ModuleDeclaration { body?: ModuleBlock; } +interface AmbientModuleDeclaration extends ModuleDeclaration { + body?: ModuleBlock; +} type SourceFileLike = SourceFile | AmbientModuleDeclaration; // Identifier for the case of `const x = require("y")`. type Importer = AnyImportOrReExport | ValidImportTypeNode | Identifier; @@ -140,7 +164,7 @@ function getImportersForExport( { exportingModuleSymbol, exportKind }: ExportInfo, checker: TypeChecker, cancellationToken: CancellationToken | undefined, -): { directImports: Importer[], indirectUsers: readonly SourceFile[] } { +): { directImports: Importer[]; indirectUsers: readonly SourceFile[]; } { const markSeenDirectImport = nodeSeenTracker(); const markSeenIndirectUser = nodeSeenTracker(); const directImports: Importer[] = []; @@ -188,7 +212,9 @@ function getImportersForExport( } if (!isAvailableThroughGlobal) { const parent = direct.parent; - if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) { + if ( + exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration + ) { const { name } = parent as VariableDeclaration; if (name.kind === SyntaxKind.Identifier) { directImports.push(name); @@ -202,14 +228,24 @@ function getImportersForExport( break; // TODO: GH#23879 case SyntaxKind.ImportEqualsDeclaration: - handleNamespaceImport(direct, direct.name, hasSyntacticModifier(direct, ModifierFlags.Export), /*alreadyAddedDirect*/ false); + handleNamespaceImport( + direct, + direct.name, + hasSyntacticModifier(direct, ModifierFlags.Export), + /*alreadyAddedDirect*/ false, + ); break; case SyntaxKind.ImportDeclaration: directImports.push(direct); const namedBindings = direct.importClause && direct.importClause.namedBindings; if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) { - handleNamespaceImport(direct, namedBindings.name, /*isReExport*/ false, /*alreadyAddedDirect*/ true); + handleNamespaceImport( + direct, + namedBindings.name, + /*isReExport*/ false, + /*alreadyAddedDirect*/ true, + ); } else if (!isAvailableThroughGlobal && isDefaultImport(direct)) { addIndirectUser(getSourceFileLikeForImportDeclaration(direct)); // Add a check for indirect uses to handle synthetic default imports @@ -223,7 +259,10 @@ function getImportersForExport( } else if (direct.exportClause.kind === SyntaxKind.NamespaceExport) { // `export * as foo from "foo"` add to indirect uses - addIndirectUser(getSourceFileLikeForImportDeclaration(direct), /*addTransitiveDependencies*/ true); + addIndirectUser( + getSourceFileLikeForImportDeclaration(direct), + /*addTransitiveDependencies*/ true, + ); } else { // This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports. @@ -258,14 +297,21 @@ function getImportersForExport( }); } - function handleNamespaceImport(importDeclaration: ImportEqualsDeclaration | ImportDeclaration, name: Identifier, isReExport: boolean, alreadyAddedDirect: boolean): void { + function handleNamespaceImport( + importDeclaration: ImportEqualsDeclaration | ImportDeclaration, + name: Identifier, + isReExport: boolean, + alreadyAddedDirect: boolean, + ): void { if (exportKind === ExportKind.ExportEquals) { // This is a direct import, not import-as-namespace. if (!alreadyAddedDirect) directImports.push(importDeclaration); } else if (!isAvailableThroughGlobal) { const sourceFileLike = getSourceFileLikeForImportDeclaration(importDeclaration); - Debug.assert(sourceFileLike.kind === SyntaxKind.SourceFile || sourceFileLike.kind === SyntaxKind.ModuleDeclaration); + Debug.assert( + sourceFileLike.kind === SyntaxKind.SourceFile || sourceFileLike.kind === SyntaxKind.ModuleDeclaration, + ); if (isReExport || findNamespaceReExports(sourceFileLike, name, checker)) { addIndirectUser(sourceFileLike, /*addTransitiveDependencies*/ true); } @@ -290,7 +336,10 @@ function getImportersForExport( if (directImports) { for (const directImport of directImports) { if (!isImportTypeNode(directImport)) { - addIndirectUser(getSourceFileLikeForImportDeclaration(directImport), /*addTransitiveDependencies*/ true); + addIndirectUser( + getSourceFileLikeForImportDeclaration(directImport), + /*addTransitiveDependencies*/ true, + ); } } } @@ -306,7 +355,13 @@ function getImportersForExport( * The returned `importSearches` will result in the entire source file being searched. * But re-exports will be placed in 'singleReferences' since they cannot be locally referenced. */ -function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker, isForRename: boolean): Pick { +function getSearchesFromDirectImports( + directImports: Importer[], + exportSymbol: Symbol, + exportKind: ExportKind, + checker: TypeChecker, + isForRename: boolean, +): Pick { const importSearches: [Identifier, Symbol][] = []; const singleReferences: (Identifier | StringLiteral)[] = []; function addSearch(location: Identifier, symbol: Symbol): void { @@ -380,7 +435,10 @@ function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: S // `export =` might be imported by a default import if `--allowSyntheticDefaultImports` is on, so this handles both ExportKind.Default and ExportKind.ExportEquals. // If a default import has the same name as the default export, allow to rename it. // Given `import f` and `export default function f`, we will rename both, but for `import g` we will rename just that. - if (name && (exportKind === ExportKind.Default || exportKind === ExportKind.ExportEquals) && (!isForRename || name.escapedText === symbolEscapedNameNoDefault(exportSymbol))) { + if ( + name && (exportKind === ExportKind.Default || exportKind === ExportKind.ExportEquals) + && (!isForRename || name.escapedText === symbolEscapedNameNoDefault(exportSymbol)) + ) { const defaultImportAlias = checker.getSymbolAtLocation(name)!; addSearch(name, defaultImportAlias); } @@ -430,7 +488,8 @@ function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: S function isNameMatch(name: __String): boolean { // Use name of "default" even in `export =` case because we may have allowSyntheticDefaultImports - return name === exportSymbol.escapedName || exportKind !== ExportKind.Named && name === InternalSymbolName.Default; + return name === exportSymbol.escapedName + || exportKind !== ExportKind.Named && name === InternalSymbolName.Default; } } @@ -441,22 +500,28 @@ function findNamespaceReExports(sourceFileLike: SourceFileLike, name: Identifier return !!forEachPossibleImportOrExportStatement(sourceFileLike, statement => { if (!isExportDeclaration(statement)) return; const { exportClause, moduleSpecifier } = statement; - return !moduleSpecifier && exportClause && isNamedExports(exportClause) && - exportClause.elements.some(element => checker.getExportSpecifierLocalTargetSymbol(element) === namespaceImportSymbol); + return !moduleSpecifier && exportClause && isNamedExports(exportClause) + && exportClause.elements.some(element => + checker.getExportSpecifierLocalTargetSymbol(element) === namespaceImportSymbol + ); }); } /** @internal */ export type ModuleReference = /** "import" also includes require() calls. */ - | { kind: "import", literal: StringLiteralLike } + | { kind: "import"; literal: StringLiteralLike; } /** or */ - | { kind: "reference", referencingFile: SourceFile, ref: FileReference } + | { kind: "reference"; referencingFile: SourceFile; ref: FileReference; } /** Containing file implicitly references the module (eg, via implicit jsx runtime import) */ - | { kind: "implicit", literal: StringLiteralLike, referencingFile: SourceFile }; + | { kind: "implicit"; literal: StringLiteralLike; referencingFile: SourceFile; }; /** @internal */ -export function findModuleReferences(program: Program, sourceFiles: readonly SourceFile[], searchModuleSymbol: Symbol): ModuleReference[] { +export function findModuleReferences( + program: Program, + sourceFiles: readonly SourceFile[], + searchModuleSymbol: Symbol, +): ModuleReference[] { const refs: ModuleReference[] = []; const checker = program.getTypeChecker(); for (const referencingFile of sourceFiles) { @@ -468,8 +533,14 @@ export function findModuleReferences(program: Program, sourceFiles: readonly Sou } } for (const ref of referencingFile.typeReferenceDirectives) { - const referenced = program.getResolvedTypeReferenceDirectives().get(ref.fileName, ref.resolutionMode || referencingFile.impliedNodeFormat)?.resolvedTypeReferenceDirective; - if (referenced !== undefined && referenced.resolvedFileName === (searchSourceFile as SourceFile).fileName) { + const referenced = program.getResolvedTypeReferenceDirectives().get( + ref.fileName, + ref.resolutionMode || referencingFile.impliedNodeFormat, + )?.resolvedTypeReferenceDirective; + if ( + referenced !== undefined + && referenced.resolvedFileName === (searchSourceFile as SourceFile).fileName + ) { refs.push({ kind: "reference", referencingFile, ref }); } } @@ -478,7 +549,10 @@ export function findModuleReferences(program: Program, sourceFiles: readonly Sou forEachImport(referencingFile, (importDecl, moduleSpecifier) => { const moduleSymbol = checker.getSymbolAtLocation(moduleSpecifier); if (moduleSymbol === searchModuleSymbol) { - refs.push(nodeIsSynthesized(importDecl) ? { kind: "implicit", literal: moduleSpecifier, referencingFile } : { kind: "import", literal: moduleSpecifier }); + refs.push( + nodeIsSynthesized(importDecl) ? { kind: "implicit", literal: moduleSpecifier, referencingFile } + : { kind: "import", literal: moduleSpecifier }, + ); } }); } @@ -486,7 +560,11 @@ export function findModuleReferences(program: Program, sourceFiles: readonly Sou } /** Returns a map from a module symbol Id to all import statements that directly reference the module. */ -function getDirectImportsMap(sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken | undefined): Map { +function getDirectImportsMap( + sourceFiles: readonly SourceFile[], + checker: TypeChecker, + cancellationToken: CancellationToken | undefined, +): Map { const map = new Map(); for (const sourceFile of sourceFiles) { @@ -508,13 +586,24 @@ function getDirectImportsMap(sourceFiles: readonly SourceFile[], checker: TypeCh } /** Iterates over all statements at the top level or in module declarations. Returns the first truthy result. */ -function forEachPossibleImportOrExportStatement(sourceFileLike: SourceFileLike, action: (statement: Statement) => T) { - return forEach(sourceFileLike.kind === SyntaxKind.SourceFile ? sourceFileLike.statements : sourceFileLike.body!.statements, statement => // TODO: GH#18217 - action(statement) || (isAmbientModuleDeclaration(statement) && forEach(statement.body && statement.body.statements, action))); +function forEachPossibleImportOrExportStatement( + sourceFileLike: SourceFileLike, + action: (statement: Statement) => T, +) { + return forEach( + sourceFileLike.kind === SyntaxKind.SourceFile ? sourceFileLike.statements : sourceFileLike.body!.statements, + statement => + // TODO: GH#18217 + action(statement) + || (isAmbientModuleDeclaration(statement) && forEach(statement.body && statement.body.statements, action)), + ); } /** Calls `action` for each import, re-export, or require() in a file. */ -function forEachImport(sourceFile: SourceFile, action: (importStatement: ImporterOrCallExpression, imported: StringLiteralLike) => void): void { +function forEachImport( + sourceFile: SourceFile, + action: (importStatement: ImporterOrCallExpression, imported: StringLiteralLike) => void, +): void { if (sourceFile.externalModuleIndicator || sourceFile.imports !== undefined) { for (const i of sourceFile.imports) { action(importFromModuleSpecifier(i), i); @@ -565,7 +654,12 @@ export interface ExportedSymbol { * * @internal */ -export function getImportOrExportSymbol(node: Node, symbol: Symbol, checker: TypeChecker, comingFromExport: boolean): ImportedSymbol | ExportedSymbol | undefined { +export function getImportOrExportSymbol( + node: Node, + symbol: Symbol, + checker: TypeChecker, + comingFromExport: boolean, +): ImportedSymbol | ExportedSymbol | undefined { return comingFromExport ? getExport() : getExport() || getImport(); function getExport(): ExportedSymbol | ImportedSymbol | undefined { @@ -626,7 +720,11 @@ export function getImportOrExportSymbol(node: Node, symbol: Symbol, checker: Typ // Get the symbol for the `export =` node; its parent is the module it's the export of. if (!ex.symbol.parent) return undefined; const exportKind = ex.isExportEquals ? ExportKind.ExportEquals : ExportKind.Default; - return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol: ex.symbol.parent, exportKind } }; + return { + kind: ImportExport.Export, + symbol, + exportInfo: { exportingModuleSymbol: ex.symbol.parent, exportKind }, + }; } function getSpecialPropertyExport(node: BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined { @@ -642,7 +740,8 @@ export function getImportOrExportSymbol(node: Node, symbol: Symbol, checker: Typ return undefined; } - const sym = useLhsSymbol ? checker.getSymbolAtLocation(getNameOfAccessExpression(cast(node.left, isAccessExpression))) : symbol; + const sym = useLhsSymbol + ? checker.getSymbolAtLocation(getNameOfAccessExpression(cast(node.left, isAccessExpression))) : symbol; return sym && exportInfo(sym, kind); } } @@ -668,7 +767,10 @@ export function getImportOrExportSymbol(node: Node, symbol: Symbol, checker: Typ // If `importedName` is undefined, do continue searching as the export is anonymous. // (All imports returned from this function will be ignored anyway if we are in rename and this is a not a named export.) const importedName = symbolEscapedNameNoDefault(importedSymbol); - if (importedName === undefined || importedName === InternalSymbolName.Default || importedName === symbol.escapedName) { + if ( + importedName === undefined || importedName === InternalSymbolName.Default + || importedName === symbol.escapedName + ) { return { kind: ImportExport.Import, symbol: importedSymbol }; } } @@ -705,10 +807,12 @@ function getExportEqualsLocalSymbol(importedSymbol: Symbol, checker: TypeChecker // If a reference is a class expression, the exported node would be its parent. // If a reference is a variable declaration, the exported node would be the variable statement. function getExportNode(parent: Node, node: Node): Node | undefined { - const declaration = isVariableDeclaration(parent) ? parent : isBindingElement(parent) ? walkUpBindingElementsAndPatterns(parent) : undefined; + const declaration = isVariableDeclaration(parent) ? parent + : isBindingElement(parent) ? walkUpBindingElementsAndPatterns(parent) : undefined; if (declaration) { - return (parent as VariableDeclaration | BindingElement).name !== node ? undefined : - isCatchClause(declaration.parent) ? undefined : isVariableStatement(declaration.parent.parent) ? declaration.parent.parent : undefined; + return (parent as VariableDeclaration | BindingElement).name !== node ? undefined + : isCatchClause(declaration.parent) ? undefined + : isVariableStatement(declaration.parent.parent) ? declaration.parent.parent : undefined; } else { return parent; @@ -719,7 +823,8 @@ function isNodeImport(node: Node): boolean { const { parent } = node; switch (parent.kind) { case SyntaxKind.ImportEqualsDeclaration: - return (parent as ImportEqualsDeclaration).name === node && isExternalModuleImportEquals(parent as ImportEqualsDeclaration); + return (parent as ImportEqualsDeclaration).name === node + && isExternalModuleImportEquals(parent as ImportEqualsDeclaration); case SyntaxKind.ImportSpecifier: // For a rename import `{ foo as bar }`, don't search for the imported symbol. Just find local uses of `bar`. return !(parent as ImportSpecifier).propertyName; @@ -735,7 +840,11 @@ function isNodeImport(node: Node): boolean { } /** @internal */ -export function getExportInfo(exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker): ExportInfo | undefined { +export function getExportInfo( + exportSymbol: Symbol, + exportKind: ExportKind, + checker: TypeChecker, +): ExportInfo | undefined { const moduleSymbol = exportSymbol.parent; if (!moduleSymbol) return undefined; // This can happen if an `export` is not at the top-level (which is a compile error). const exportingModuleSymbol = checker.getMergedSymbol(moduleSymbol); // Need to get merged symbol in case there's an augmentation. @@ -748,16 +857,24 @@ function skipExportSpecifierSymbol(symbol: Symbol, checker: TypeChecker): Symbol // For `export { foo } from './bar", there's nothing to skip, because it does not create a new alias. But `export { foo } does. if (symbol.declarations) { for (const declaration of symbol.declarations) { - if (isExportSpecifier(declaration) && !declaration.propertyName && !declaration.parent.parent.moduleSpecifier) { + if ( + isExportSpecifier(declaration) && !declaration.propertyName + && !declaration.parent.parent.moduleSpecifier + ) { return checker.getExportSpecifierLocalTargetSymbol(declaration) || symbol; } - else if (isPropertyAccessExpression(declaration) && isModuleExportsAccessExpression(declaration.expression) && !isPrivateIdentifier(declaration.name)) { + else if ( + isPropertyAccessExpression(declaration) && isModuleExportsAccessExpression(declaration.expression) + && !isPrivateIdentifier(declaration.name) + ) { // Export of form 'module.exports.propName = expr'; return checker.getSymbolAtLocation(declaration)!; } - else if (isShorthandPropertyAssignment(declaration) + else if ( + isShorthandPropertyAssignment(declaration) && isBinaryExpression(declaration.parent.parent) - && getAssignmentDeclarationKind(declaration.parent.parent) === AssignmentDeclarationKind.ModuleExports) { + && getAssignmentDeclarationKind(declaration.parent.parent) === AssignmentDeclarationKind.ModuleExports + ) { return checker.getExportSpecifierLocalTargetSymbol(declaration.name)!; } } @@ -783,9 +900,13 @@ function getSourceFileLikeForImportDeclaration(node: ImporterOrCallExpression): } function isAmbientModuleDeclaration(node: Node): node is AmbientModuleDeclaration { - return node.kind === SyntaxKind.ModuleDeclaration && (node as ModuleDeclaration).name.kind === SyntaxKind.StringLiteral; + return node.kind === SyntaxKind.ModuleDeclaration + && (node as ModuleDeclaration).name.kind === SyntaxKind.StringLiteral; } -function isExternalModuleImportEquals(eq: ImportEqualsDeclaration): eq is ImportEqualsDeclaration & { moduleReference: { expression: StringLiteral } } { - return eq.moduleReference.kind === SyntaxKind.ExternalModuleReference && eq.moduleReference.expression.kind === SyntaxKind.StringLiteral; +function isExternalModuleImportEquals( + eq: ImportEqualsDeclaration, +): eq is ImportEqualsDeclaration & { moduleReference: { expression: StringLiteral; }; } { + return eq.moduleReference.kind === SyntaxKind.ExternalModuleReference + && eq.moduleReference.expression.kind === SyntaxKind.StringLiteral; } diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index b7c8f87b7250a..246900c909904 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -82,7 +82,8 @@ const leadingParameterNameCommentRegexFactory = (name: string) => { }; function shouldShowParameterNameHints(preferences: UserPreferences) { - return preferences.includeInlayParameterNameHints === "literals" || preferences.includeInlayParameterNameHints === "all"; + return preferences.includeInlayParameterNameHints === "literals" + || preferences.includeInlayParameterNameHints === "all"; } function shouldShowLiteralParameterNameHintsOnly(preferences: UserPreferences) { @@ -143,7 +144,10 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { visitCallOrNewExpression(node); } else { - if (preferences.includeInlayFunctionParameterTypeHints && isFunctionLikeDeclaration(node) && hasContextSensitiveParameters(node)) { + if ( + preferences.includeInlayFunctionParameterTypeHints && isFunctionLikeDeclaration(node) + && hasContextSensitiveParameters(node) + ) { visitFunctionLikeForParameterType(node); } if (preferences.includeInlayFunctionLikeReturnTypeHints && isSignatureSupportingReturnAnnotation(node)) { @@ -153,11 +157,20 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { return forEachChild(node, visitor); } - function isSignatureSupportingReturnAnnotation(node: Node): node is FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration { - return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) || isMethodDeclaration(node) || isGetAccessorDeclaration(node); + function isSignatureSupportingReturnAnnotation( + node: Node, + ): node is FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration { + return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) + || isMethodDeclaration(node) || isGetAccessorDeclaration(node); } - function addParameterHints(text: string, parameter: Identifier, position: number, isFirstVariadicArgument: boolean, sourceFile: SourceFile | undefined) { + function addParameterHints( + text: string, + parameter: Identifier, + position: number, + isFirstVariadicArgument: boolean, + sourceFile: SourceFile | undefined, + ) { let hintText = `${isFirstVariadicArgument ? "..." : ""}${text}`; let displayParts: InlayHintDisplayPart[] | undefined; if (shouldUseInteractiveInlayHints(preferences)) { @@ -179,7 +192,9 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { function addTypeHints(text: string, position: number) { result.push({ - text: `: ${text.length > maxTypeHintLength ? text.substr(0, maxTypeHintLength - "...".length) + "..." : text}`, + text: `: ${ + text.length > maxTypeHintLength ? text.substr(0, maxTypeHintLength - "...".length) + "..." : text + }`, position, kind: InlayHintKind.Type, whitespaceBefore: true, @@ -211,7 +226,10 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { } function visitVariableLikeDeclaration(decl: VariableDeclaration | PropertyDeclaration) { - if (!decl.initializer || isBindingPattern(decl.name) || isVariableDeclaration(decl) && !isHintableDeclaration(decl)) { + if ( + !decl.initializer || isBindingPattern(decl.name) + || isVariableDeclaration(decl) && !isHintableDeclaration(decl) + ) { return; } @@ -227,7 +245,8 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { const typeDisplayString = printTypeInSingleLine(declarationType); if (typeDisplayString) { - const isVariableNameMatchesType = preferences.includeInlayVariableTypeHintsWhenTypeMatchesName === false && equateStringsCaseInsensitive(decl.name.getText(), typeDisplayString); + const isVariableNameMatchesType = preferences.includeInlayVariableTypeHintsWhenTypeMatchesName === false + && equateStringsCaseInsensitive(decl.name.getText(), typeDisplayString); if (isVariableNameMatchesType) { return; } @@ -277,7 +296,9 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { signatureParamPos = signatureParamPos + (spreadArgs || 1); if (identifierInfo) { const { parameter, parameterName, isRestParameter: isFirstVariadicArgument } = identifierInfo; - const isParameterNameNotSameAsArgument = preferences.includeInlayParameterNameHintsWhenArgumentMatchesName || !identifierOrAccessExpressionPostfixMatchesParameterName(arg, parameterName); + const isParameterNameNotSameAsArgument = + preferences.includeInlayParameterNameHintsWhenArgumentMatchesName + || !identifierOrAccessExpressionPostfixMatchesParameterName(arg, parameterName); if (!isParameterNameNotSameAsArgument && !isFirstVariadicArgument) { continue; } @@ -320,7 +341,8 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { switch (node.kind) { case SyntaxKind.PrefixUnaryExpression: { const operand = (node as PrefixUnaryExpression).operand; - return isLiteralExpression(operand) || isIdentifier(operand) && isInfinityOrNaNString(operand.escapedText); + return isLiteralExpression(operand) + || isIdentifier(operand) && isInfinityOrNaNString(operand.escapedText); } case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: @@ -336,7 +358,9 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { return isLiteralExpression(node); } - function visitFunctionDeclarationLikeForReturnType(decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration) { + function visitFunctionDeclarationLikeForReturnType( + decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration, + ) { if (isArrowFunction(decl)) { if (!findChildOfKind(decl, SyntaxKind.OpenParenToken, file)) { return; @@ -366,7 +390,9 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { addTypeHints(typeDisplayString, getTypeAnnotationPosition(decl)); } - function getTypeAnnotationPosition(decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration) { + function getTypeAnnotationPosition( + decl: FunctionDeclaration | ArrowFunction | FunctionExpression | MethodDeclaration | GetAccessorDeclaration, + ) { const closeParenToken = findChildOfKind(decl, SyntaxKind.CloseParenToken, file); if (closeParenToken) { return closeParenToken.end; @@ -415,7 +441,8 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { } function printTypeInSingleLine(type: Type) { - const flags = NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; + const flags = NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.AllowUniqueESSymbolType + | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; const printer = createPrinterWithRemoveComments(); return usingSingleLineStringWriter(writer => { @@ -432,7 +459,8 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { function isHintableDeclaration(node: VariableDeclaration | ParameterDeclaration) { if ((isParameterDeclaration(node) || isVariableDeclaration(node) && isVarConst(node)) && node.initializer) { const initializer = skipParentheses(node.initializer); - return !(isHintableLiteral(initializer) || isNewExpression(initializer) || isObjectLiteralExpression(initializer) || isAssertionExpression(initializer)); + return !(isHintableLiteral(initializer) || isNewExpression(initializer) + || isObjectLiteralExpression(initializer) || isAssertionExpression(initializer)); } return true; } @@ -441,7 +469,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { return { text, span: createTextSpanFromNode(node, sourceFile), - file: sourceFile.fileName + file: sourceFile.fileName, }; } } diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 6d23f64be662a..a8eb30f8ea4ef 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -173,13 +173,16 @@ const jsDocTagNames = [ "variation", "version", "virtual", - "yields" + "yields", ]; let jsDocTagNameCompletionEntries: CompletionEntry[]; let jsDocTagCompletionEntries: CompletionEntry[]; /** @internal */ -export function getJsDocCommentsFromDeclarations(declarations: readonly Declaration[], checker?: TypeChecker): SymbolDisplayPart[] { +export function getJsDocCommentsFromDeclarations( + declarations: readonly Declaration[], + checker?: TypeChecker, +): SymbolDisplayPart[] { // Only collect doc comments from duplicate declarations once: // In case of a union property there might be same declaration multiple times // which only varies in type parameter @@ -189,17 +192,29 @@ export function getJsDocCommentsFromDeclarations(declarations: readonly Declarat const parts: SymbolDisplayPart[][] = []; forEachUnique(declarations, declaration => { for (const jsdoc of getCommentHavingNodes(declaration)) { - const inheritDoc = isJSDoc(jsdoc) && jsdoc.tags && find(jsdoc.tags, t => t.kind === SyntaxKind.JSDocTag && (t.tagName.escapedText === "inheritDoc" || t.tagName.escapedText === "inheritdoc")); + const inheritDoc = isJSDoc(jsdoc) && jsdoc.tags + && find( + jsdoc.tags, + t => t.kind === SyntaxKind.JSDocTag + && (t.tagName.escapedText === "inheritDoc" || t.tagName.escapedText === "inheritdoc"), + ); // skip comments containing @typedefs since they're not associated with particular declarations // Exceptions: // - @typedefs are themselves declarations with associated comments // - @param or @return indicate that the author thinks of it as a 'local' @typedef that's part of the function documentation - if (jsdoc.comment === undefined && !inheritDoc + if ( + jsdoc.comment === undefined && !inheritDoc || isJSDoc(jsdoc) - && declaration.kind !== SyntaxKind.JSDocTypedefTag && declaration.kind !== SyntaxKind.JSDocCallbackTag - && jsdoc.tags - && jsdoc.tags.some(t => t.kind === SyntaxKind.JSDocTypedefTag || t.kind === SyntaxKind.JSDocCallbackTag) - && !jsdoc.tags.some(t => t.kind === SyntaxKind.JSDocParameterTag || t.kind === SyntaxKind.JSDocReturnTag)) { + && declaration.kind !== SyntaxKind.JSDocTypedefTag + && declaration.kind !== SyntaxKind.JSDocCallbackTag + && jsdoc.tags + && jsdoc.tags.some(t => + t.kind === SyntaxKind.JSDocTypedefTag || t.kind === SyntaxKind.JSDocCallbackTag + ) + && !jsdoc.tags.some(t => + t.kind === SyntaxKind.JSDocParameterTag || t.kind === SyntaxKind.JSDocReturnTag + ) + ) { continue; } let newparts = jsdoc.comment ? getDisplayPartsFromComment(jsdoc.comment, checker) : []; @@ -225,7 +240,7 @@ function getCommentHavingNodes(declaration: Declaration): readonly (JSDoc | JSDo return [declaration as JSDocPropertyTag]; case SyntaxKind.JSDocCallbackTag: case SyntaxKind.JSDocTypedefTag: - return [(declaration as JSDocTypedefTag), (declaration as JSDocTypedefTag).parent]; + return [declaration as JSDocTypedefTag, (declaration as JSDocTypedefTag).parent]; default: return getJSDocCommentsAndTags(declaration); } @@ -240,8 +255,10 @@ export function getJsDocTagsFromDeclarations(declarations?: Declaration[], check // skip comments containing @typedefs since they're not associated with particular declarations // Exceptions: // - @param or @return indicate that the author thinks of it as a 'local' @typedef that's part of the function documentation - if (tags.some(t => t.kind === SyntaxKind.JSDocTypedefTag || t.kind === SyntaxKind.JSDocCallbackTag) - && !tags.some(t => t.kind === SyntaxKind.JSDocParameterTag || t.kind === SyntaxKind.JSDocReturnTag)) { + if ( + tags.some(t => t.kind === SyntaxKind.JSDocTypedefTag || t.kind === SyntaxKind.JSDocCallbackTag) + && !tags.some(t => t.kind === SyntaxKind.JSDocParameterTag || t.kind === SyntaxKind.JSDocReturnTag) + ) { return; } for (const tag of tags) { @@ -251,13 +268,16 @@ export function getJsDocTagsFromDeclarations(declarations?: Declaration[], check return infos; } -function getDisplayPartsFromComment(comment: string | readonly JSDocComment[], checker: TypeChecker | undefined): SymbolDisplayPart[] { +function getDisplayPartsFromComment( + comment: string | readonly JSDocComment[], + checker: TypeChecker | undefined, +): SymbolDisplayPart[] { if (typeof comment === "string") { return [textPart(comment)]; } return flatMap( comment, - node => node.kind === SyntaxKind.JSDocText ? [textPart(node.text)] : buildLinkParts(node, checker) + node => node.kind === SyntaxKind.JSDocText ? [textPart(node.text)] : buildLinkParts(node, checker), ) as SymbolDisplayPart[]; } @@ -267,8 +287,8 @@ function getCommentDisplayParts(tag: JSDocTag, checker?: TypeChecker): SymbolDis switch (kind) { case SyntaxKind.JSDocThrowsTag: const typeExpression = (tag as JSDocThrowsTag).typeExpression; - return typeExpression ? withNode(typeExpression) : - comment === undefined ? undefined : getDisplayPartsFromComment(comment, checker); + return typeExpression ? withNode(typeExpression) + : comment === undefined ? undefined : getDisplayPartsFromComment(comment, checker); case SyntaxKind.JSDocImplementsTag: return withNode((tag as JSDocImplementsTag).class); case SyntaxKind.JSDocAugmentsTag: @@ -303,7 +323,12 @@ function getCommentDisplayParts(tag: JSDocTag, checker?: TypeChecker): SymbolDis case SyntaxKind.JSDocPropertyTag: case SyntaxKind.JSDocParameterTag: case SyntaxKind.JSDocSeeTag: - const { name } = tag as JSDocTypedefTag | JSDocCallbackTag | JSDocPropertyTag | JSDocParameterTag | JSDocSeeTag; + const { name } = tag as + | JSDocTypedefTag + | JSDocCallbackTag + | JSDocPropertyTag + | JSDocParameterTag + | JSDocSeeTag; return name ? withNode(name) : comment === undefined ? undefined : getDisplayPartsFromComment(comment, checker); @@ -368,7 +393,7 @@ export function getJSDocTagCompletions(): CompletionEntry[] { name: `@${tagName}`, kind: ScriptElementKind.keyword, kindModifiers: "", - sortText: Completions.SortText.LocationPriority + sortText: Completions.SortText.LocationPriority, }; })); } @@ -400,12 +425,21 @@ export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): Comple if (!isIdentifier(param.name)) return undefined; const name = param.name.text; - if (jsdoc.tags!.some(t => t !== tag && isJSDocParameterTag(t) && isIdentifier(t.name) && t.name.escapedText === name) // TODO: GH#18217 - || nameThusFar !== undefined && !startsWith(name, nameThusFar)) { + if ( + jsdoc.tags!.some(t => + t !== tag && isJSDocParameterTag(t) && isIdentifier(t.name) && t.name.escapedText === name + ) // TODO: GH#18217 + || nameThusFar !== undefined && !startsWith(name, nameThusFar) + ) { return undefined; } - return { name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: Completions.SortText.LocationPriority }; + return { + name, + kind: ScriptElementKind.parameterElement, + kindModifiers: "", + sortText: Completions.SortText.LocationPriority, + }; }); } @@ -447,7 +481,12 @@ export function getJSDocParameterNameCompletionDetails(name: string): Completion * * @internal */ -export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number, options?: DocCommentTemplateOptions): TextInsertion | undefined { +export function getDocCommentTemplateAtPosition( + newLine: string, + sourceFile: SourceFile, + position: number, + options?: DocCommentTemplateOptions, +): TextInsertion | undefined { const tokenAtPos = getTokenAtPosition(sourceFile, position); const existingDocComment = findAncestor(tokenAtPos, isJSDoc); if (existingDocComment && (existingDocComment.comment !== undefined || length(existingDocComment.tags))) { @@ -469,18 +508,19 @@ export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: Sou const { commentOwner, parameters, hasReturn } = commentOwnerInfo; const commentOwnerJsDoc = hasJSDocNodes(commentOwner) && commentOwner.jsDoc ? commentOwner.jsDoc : undefined; const lastJsDoc = lastOrUndefined(commentOwnerJsDoc); - if (commentOwner.getStart(sourceFile) < position + if ( + commentOwner.getStart(sourceFile) < position || lastJsDoc && existingDocComment - && lastJsDoc !== existingDocComment) { + && lastJsDoc !== existingDocComment + ) { return undefined; } const indentationStr = getIndentationStringAtPosition(sourceFile, position); const isJavaScriptFile = hasJSFileExtension(sourceFile.fileName); - const tags = - (parameters ? parameterDocComments(parameters || [], isJavaScriptFile, indentationStr, newLine) : "") + - (hasReturn ? returnsDocComment(indentationStr, newLine) : ""); + const tags = (parameters ? parameterDocComments(parameters || [], isJavaScriptFile, indentationStr, newLine) : "") + + (hasReturn ? returnsDocComment(indentationStr, newLine) : ""); // A doc comment consists of the following // * The opening comment line @@ -511,7 +551,12 @@ function getIndentationStringAtPosition(sourceFile: SourceFile, position: number return text.slice(lineStart, pos); } -function parameterDocComments(parameters: readonly ParameterDeclaration[], isJavaScriptFile: boolean, indentationStr: string, newLine: string): string { +function parameterDocComments( + parameters: readonly ParameterDeclaration[], + isJavaScriptFile: boolean, + indentationStr: string, + newLine: string, +): string { return parameters.map(({ name, dotDotDotToken }, i) => { const paramName = name.kind === SyntaxKind.Identifier ? name.text : "param" + i; const type = isJavaScriptFile ? (dotDotDotToken ? "{...any} " : "{any} ") : ""; @@ -528,10 +573,16 @@ interface CommentOwnerInfo { readonly parameters?: readonly ParameterDeclaration[]; readonly hasReturn?: boolean; } -function getCommentOwnerInfo(tokenAtPos: Node, options: DocCommentTemplateOptions | undefined): CommentOwnerInfo | undefined { +function getCommentOwnerInfo( + tokenAtPos: Node, + options: DocCommentTemplateOptions | undefined, +): CommentOwnerInfo | undefined { return forEachAncestor(tokenAtPos, n => getCommentOwnerInfoWorker(n, options)); } -function getCommentOwnerInfoWorker(commentOwner: Node, options: DocCommentTemplateOptions | undefined): CommentOwnerInfo | undefined | "quit" { +function getCommentOwnerInfoWorker( + commentOwner: Node, + options: DocCommentTemplateOptions | undefined, +): CommentOwnerInfo | undefined | "quit" { switch (commentOwner.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: @@ -539,7 +590,12 @@ function getCommentOwnerInfoWorker(commentOwner: Node, options: DocCommentTempla case SyntaxKind.Constructor: case SyntaxKind.MethodSignature: case SyntaxKind.ArrowFunction: - const host = commentOwner as ArrowFunction | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature; + const host = commentOwner as + | ArrowFunction + | FunctionDeclaration + | MethodDeclaration + | ConstructorDeclaration + | MethodSignature; return { commentOwner, parameters: host.parameters, hasReturn: hasReturn(host, options) }; case SyntaxKind.PropertyAssignment: @@ -599,12 +655,15 @@ function getCommentOwnerInfoWorker(commentOwner: Node, options: DocCommentTempla } function hasReturn(node: Node, options: DocCommentTemplateOptions | undefined) { - return !!options?.generateReturnInDocTemplate && - (isFunctionTypeNode(node) || isArrowFunction(node) && isExpression(node.body) - || isFunctionLikeDeclaration(node) && node.body && isBlock(node.body) && !!forEachReturnStatement(node.body, n => n)); + return !!options?.generateReturnInDocTemplate + && (isFunctionTypeNode(node) || isArrowFunction(node) && isExpression(node.body) + || isFunctionLikeDeclaration(node) && node.body && isBlock(node.body) + && !!forEachReturnStatement(node.body, n => n)); } -function getRightHandSideOfAssignment(rightHandSide: Expression): FunctionExpression | ArrowFunction | ConstructorDeclaration | undefined { +function getRightHandSideOfAssignment( + rightHandSide: Expression, +): FunctionExpression | ArrowFunction | ConstructorDeclaration | undefined { while (rightHandSide.kind === SyntaxKind.ParenthesizedExpression) { rightHandSide = (rightHandSide as ParenthesizedExpression).expression; } diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 873bba76e9278..a496ee5c24a33 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -37,7 +37,14 @@ interface RawNavigateToItem { } /** @internal */ -export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number | undefined, excludeDtsFiles: boolean): NavigateToItem[] { +export function getNavigateToItems( + sourceFiles: readonly SourceFile[], + checker: TypeChecker, + cancellationToken: CancellationToken, + searchValue: string, + maxResultCount: number | undefined, + excludeDtsFiles: boolean, +): NavigateToItem[] { const patternMatcher = createPatternMatcher(searchValue); if (!patternMatcher) return emptyArray; const rawItems: RawNavigateToItem[] = []; @@ -59,7 +66,14 @@ export function getNavigateToItems(sourceFiles: readonly SourceFile[], checker: return (maxResultCount === undefined ? rawItems : rawItems.slice(0, maxResultCount)).map(createNavigateToItem); } -function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: string, declarations: readonly Declaration[], checker: TypeChecker, fileName: string, rawItems: RawNavigateToItem[]): void { +function getItemsFromNamedDeclaration( + patternMatcher: PatternMatcher, + name: string, + declarations: readonly Declaration[], + checker: TypeChecker, + fileName: string, + rawItems: RawNavigateToItem[], +): void { // First do a quick check to see if the name of the declaration matches the // last portion of the (possibly) dotted name they're searching for. const match = patternMatcher.getMatchForLastSegmentOfPattern(name); @@ -74,11 +88,23 @@ function getItemsFromNamedDeclaration(patternMatcher: PatternMatcher, name: stri // If the pattern has dots in it, then also see if the declaration container matches as well. const fullMatch = patternMatcher.getFullMatch(getContainers(declaration), name); if (fullMatch) { - rawItems.push({ name, fileName, matchKind: fullMatch.kind, isCaseSensitive: fullMatch.isCaseSensitive, declaration }); + rawItems.push({ + name, + fileName, + matchKind: fullMatch.kind, + isCaseSensitive: fullMatch.isCaseSensitive, + declaration, + }); } } else { - rawItems.push({ name, fileName, matchKind: match.kind, isCaseSensitive: match.isCaseSensitive, declaration }); + rawItems.push({ + name, + fileName, + matchKind: match.kind, + isCaseSensitive: match.isCaseSensitive, + declaration, + }); } } } @@ -88,7 +114,9 @@ function shouldKeepItem(declaration: Declaration, checker: TypeChecker): boolean case SyntaxKind.ImportClause: case SyntaxKind.ImportSpecifier: case SyntaxKind.ImportEqualsDeclaration: - const importer = checker.getSymbolAtLocation((declaration as ImportClause | ImportSpecifier | ImportEqualsDeclaration).name!)!; // TODO: GH#18217 + const importer = checker.getSymbolAtLocation( + (declaration as ImportClause | ImportSpecifier | ImportEqualsDeclaration).name!, + )!; // TODO: GH#18217 const imported = checker.getAliasedSymbol(importer); return importer.escapedName !== imported.escapedName; default: @@ -98,7 +126,10 @@ function shouldKeepItem(declaration: Declaration, checker: TypeChecker): boolean function tryAddSingleDeclarationName(declaration: Declaration, containers: string[]): boolean { const name = getNameOfDeclaration(declaration); - return !!name && (pushLiteral(name, containers) || name.kind === SyntaxKind.ComputedPropertyName && tryAddComputedPropertyName(name.expression, containers)); + return !!name + && (pushLiteral(name, containers) + || name.kind === SyntaxKind.ComputedPropertyName + && tryAddComputedPropertyName(name.expression, containers)); } // Only added the names of computed properties if they're simple dotted expressions, like: @@ -106,7 +137,8 @@ function tryAddSingleDeclarationName(declaration: Declaration, containers: strin // [X.Y.Z]() { } function tryAddComputedPropertyName(expression: Expression, containers: string[]): boolean { return pushLiteral(expression, containers) - || isPropertyAccessExpression(expression) && (containers.push(expression.name.text), true) && tryAddComputedPropertyName(expression.expression, containers); + || isPropertyAccessExpression(expression) && (containers.push(expression.name.text), true) + && tryAddComputedPropertyName(expression.expression, containers); } function pushLiteral(node: Node, containers: string[]): boolean { @@ -119,7 +151,10 @@ function getContainers(declaration: Declaration): readonly string[] { // First, if we started with a computed property name, then add all but the last // portion into the container array. const name = getNameOfDeclaration(declaration); - if (name && name.kind === SyntaxKind.ComputedPropertyName && !tryAddComputedPropertyName(name.expression, containers)) { + if ( + name && name.kind === SyntaxKind.ComputedPropertyName + && !tryAddComputedPropertyName(name.expression, containers) + ) { return emptyArray; } // Don't include the last portion. diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index c0dae08dd2b34..eed7f6278baa7 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -163,7 +163,10 @@ interface NavigationBarNode { } /** @internal */ -export function getNavigationBarItems(sourceFile: SourceFile, cancellationToken: CancellationToken): NavigationBarItem[] { +export function getNavigationBarItems( + sourceFile: SourceFile, + cancellationToken: CancellationToken, +): NavigationBarItem[] { curCancellationToken = cancellationToken; curSourceFile = sourceFile; try { @@ -213,7 +216,14 @@ function pushChild(parent: NavigationBarNode, child: NavigationBarNode): void { function rootNavigationBarNode(sourceFile: SourceFile): NavigationBarNode { Debug.assert(!parentsStack.length); - const root: NavigationBarNode = { node: sourceFile, name: undefined, additionalNodes: undefined, parent: undefined, children: undefined, indent: 0 }; + const root: NavigationBarNode = { + node: sourceFile, + name: undefined, + additionalNodes: undefined, + parent: undefined, + children: undefined, + indent: 0, + }; parent = root; for (const statement of sourceFile.statements) { addChildrenRecursively(statement); @@ -234,7 +244,7 @@ function emptyNavigationBarNode(node: Node, name?: DeclarationName): NavigationB additionalNodes: undefined, parent, children: undefined, - indent: parent.indent + 1 + indent: parent.indent + 1, }; } @@ -295,7 +305,9 @@ function addNodeWithRecursiveChild(node: Node, child: Node | undefined, name?: D endNode(); } -function addNodeWithRecursiveInitializer(node: VariableDeclaration | PropertyAssignment | BindingElement | PropertyDeclaration): void { +function addNodeWithRecursiveInitializer( + node: VariableDeclaration | PropertyAssignment | BindingElement | PropertyDeclaration, +): void { if (node.initializer && isFunctionOrClassExpression(node.initializer)) { startNode(node); forEachChild(node.initializer, addChildrenRecursively); @@ -312,12 +324,12 @@ function addNodeWithRecursiveInitializer(node: VariableDeclaration | PropertyAss * symbols from other unique symbols, we do the below to retain those members in the nav tree. */ function hasNavigationBarName(node: Declaration) { - return !hasDynamicName(node) || - ( - node.kind !== SyntaxKind.BinaryExpression && - isPropertyAccessExpression(node.name.expression) && - isIdentifier(node.name.expression.expression) && - idText(node.name.expression.expression) === "Symbol" + return !hasDynamicName(node) + || ( + node.kind !== SyntaxKind.BinaryExpression + && isPropertyAccessExpression(node.name.expression) + && isIdentifier(node.name.expression.expression) + && idText(node.name.expression.expression) === "Symbol" ); } @@ -446,8 +458,8 @@ function addChildrenRecursively(node: Node | undefined): void { case SyntaxKind.ExportAssignment: { const expression = (node as ExportAssignment).expression; - const child = isObjectLiteralExpression(expression) || isCallExpression(expression) ? expression : - isArrowFunction(expression) || isFunctionExpression(expression) ? expression.body : undefined; + const child = isObjectLiteralExpression(expression) || isCallExpression(expression) ? expression + : isArrowFunction(expression) || isFunctionExpression(expression) ? expression.body : undefined; if (child) { startNode(node); addChildrenRecursively(child); @@ -477,12 +489,12 @@ function addChildrenRecursively(node: Node | undefined): void { return; case AssignmentDeclarationKind.Prototype: case AssignmentDeclarationKind.PrototypeProperty: { - const binaryExpression = (node as BinaryExpression); + const binaryExpression = node as BinaryExpression; const assignmentTarget = binaryExpression.left as PropertyAccessExpression; - const prototypeAccess = special === AssignmentDeclarationKind.PrototypeProperty ? - assignmentTarget.expression as PropertyAccessExpression : - assignmentTarget; + const prototypeAccess = special === AssignmentDeclarationKind.PrototypeProperty + ? assignmentTarget.expression as PropertyAccessExpression + : assignmentTarget; let depth = 0; let className: PropertyNameLiteral; @@ -493,25 +505,26 @@ function addChildrenRecursively(node: Node | undefined): void { className = prototypeAccess.expression; } else { - [depth, className] = startNestedNodes(binaryExpression, prototypeAccess.expression as EntityNameExpression); + [depth, className] = startNestedNodes( + binaryExpression, + prototypeAccess.expression as EntityNameExpression, + ); } if (special === AssignmentDeclarationKind.Prototype) { if (isObjectLiteralExpression(binaryExpression.right)) { if (binaryExpression.right.properties.length > 0) { startNode(binaryExpression, className); - forEachChild(binaryExpression.right, addChildrenRecursively); + forEachChild(binaryExpression.right, addChildrenRecursively); endNode(); } } } else if (isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right)) { - addNodeWithRecursiveChild(node, - binaryExpression.right, - className); + addNodeWithRecursiveChild(node, binaryExpression.right, className); } else { startNode(binaryExpression, className); - addNodeWithRecursiveChild(node, binaryExpression.right, assignmentTarget.name); + addNodeWithRecursiveChild(node, binaryExpression.right, assignmentTarget.name); endNode(); } endNestedNodes(depth); @@ -520,32 +533,40 @@ function addChildrenRecursively(node: Node | undefined): void { case AssignmentDeclarationKind.ObjectDefinePropertyValue: case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: { const defineCall = node as BindableObjectDefinePropertyCall; - const className = special === AssignmentDeclarationKind.ObjectDefinePropertyValue ? - defineCall.arguments[0] : - (defineCall.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression; + const className = special === AssignmentDeclarationKind.ObjectDefinePropertyValue + ? defineCall.arguments[0] + : (defineCall.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression; const memberName = defineCall.arguments[1]; const [depth, classNameIdentifier] = startNestedNodes(node, className); - startNode(node, classNameIdentifier); - startNode(node, setTextRange(factory.createIdentifier(memberName.text), memberName)); - addChildrenRecursively((node as CallExpression).arguments[2]); - endNode(); - endNode(); + startNode(node, classNameIdentifier); + startNode(node, setTextRange(factory.createIdentifier(memberName.text), memberName)); + addChildrenRecursively((node as CallExpression).arguments[2]); + endNode(); + endNode(); endNestedNodes(depth); return; } case AssignmentDeclarationKind.Property: { - const binaryExpression = (node as BinaryExpression); - const assignmentTarget = binaryExpression.left as PropertyAccessExpression | BindableElementAccessExpression; + const binaryExpression = node as BinaryExpression; + const assignmentTarget = binaryExpression.left as + | PropertyAccessExpression + | BindableElementAccessExpression; const targetFunction = assignmentTarget.expression; - if (isIdentifier(targetFunction) && getElementOrPropertyAccessName(assignmentTarget) !== "prototype" && - trackedEs5Classes && trackedEs5Classes.has(targetFunction.text)) { + if ( + isIdentifier(targetFunction) && getElementOrPropertyAccessName(assignmentTarget) !== "prototype" + && trackedEs5Classes && trackedEs5Classes.has(targetFunction.text) + ) { if (isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right)) { addNodeWithRecursiveChild(node, binaryExpression.right, targetFunction); } else if (isBindableStaticAccessExpression(assignmentTarget)) { startNode(binaryExpression, targetFunction); - addNodeWithRecursiveChild(binaryExpression.left, binaryExpression.right, getNameOrArgument(assignmentTarget)); + addNodeWithRecursiveChild( + binaryExpression.left, + binaryExpression.right, + getNameOrArgument(assignmentTarget), + ); endNode(); } return; @@ -625,45 +646,53 @@ const isEs5ClassMember: Record = { [AssignmentDeclarationKind.Prototype]: true, [AssignmentDeclarationKind.ThisProperty]: false, }; -function tryMergeEs5Class(a: NavigationBarNode, b: NavigationBarNode, bIndex: number, parent: NavigationBarNode): boolean | undefined { +function tryMergeEs5Class( + a: NavigationBarNode, + b: NavigationBarNode, + bIndex: number, + parent: NavigationBarNode, +): boolean | undefined { function isPossibleConstructor(node: Node) { return isFunctionExpression(node) || isFunctionDeclaration(node) || isVariableDeclaration(node); } - const bAssignmentDeclarationKind = isBinaryExpression(b.node) || isCallExpression(b.node) ? - getAssignmentDeclarationKind(b.node) : - AssignmentDeclarationKind.None; + const bAssignmentDeclarationKind = isBinaryExpression(b.node) || isCallExpression(b.node) + ? getAssignmentDeclarationKind(b.node) + : AssignmentDeclarationKind.None; - const aAssignmentDeclarationKind = isBinaryExpression(a.node) || isCallExpression(a.node) ? - getAssignmentDeclarationKind(a.node) : - AssignmentDeclarationKind.None; + const aAssignmentDeclarationKind = isBinaryExpression(a.node) || isCallExpression(a.node) + ? getAssignmentDeclarationKind(a.node) + : AssignmentDeclarationKind.None; // We treat this as an es5 class and merge the nodes in in one of several cases - if ((isEs5ClassMember[bAssignmentDeclarationKind] && isEs5ClassMember[aAssignmentDeclarationKind]) // merge two class elements + if ( + (isEs5ClassMember[bAssignmentDeclarationKind] && isEs5ClassMember[aAssignmentDeclarationKind]) // merge two class elements || (isPossibleConstructor(a.node) && isEs5ClassMember[bAssignmentDeclarationKind]) // ctor function & member || (isPossibleConstructor(b.node) && isEs5ClassMember[aAssignmentDeclarationKind]) // member & ctor function || (isClassDeclaration(a.node) && isSynthesized(a.node) && isEs5ClassMember[bAssignmentDeclarationKind]) // class (generated) & member || (isClassDeclaration(b.node) && isEs5ClassMember[aAssignmentDeclarationKind]) // member & class (generated) || (isClassDeclaration(a.node) && isSynthesized(a.node) && isPossibleConstructor(b.node)) // class (generated) & ctor || (isClassDeclaration(b.node) && isPossibleConstructor(a.node) && isSynthesized(a.node)) // ctor & class (generated) - ) { - + ) { let lastANode = a.additionalNodes && lastOrUndefined(a.additionalNodes) || a.node; - if ((!isClassDeclaration(a.node) && !isClassDeclaration(b.node)) // If neither outline node is a class + if ( + (!isClassDeclaration(a.node) && !isClassDeclaration(b.node)) // If neither outline node is a class || isPossibleConstructor(a.node) || isPossibleConstructor(b.node) // If either function is a constructor function - ) { - const ctorFunction = isPossibleConstructor(a.node) ? a.node : - isPossibleConstructor(b.node) ? b.node : - undefined; + ) { + const ctorFunction = isPossibleConstructor(a.node) ? a.node + : isPossibleConstructor(b.node) ? b.node + : undefined; if (ctorFunction !== undefined) { const ctorNode = setTextRange( factory.createConstructorDeclaration(/*modifiers*/ undefined, [], /*body*/ undefined), - ctorFunction); + ctorFunction, + ); const ctor = emptyNavigationBarNode(ctorNode); ctor.indent = a.indent + 1; ctor.children = a.node === ctorFunction ? a.children : b.children; - a.children = a.node === ctorFunction ? concatenate([ctor], b.children || [b]) : concatenate(a.children || [{ ...a }], [ctor]); + a.children = a.node === ctorFunction ? concatenate([ctor], b.children || [b]) + : concatenate(a.children || [{ ...a }], [ctor]); } else { if (a.children || b.children) { @@ -675,13 +704,16 @@ function tryMergeEs5Class(a: NavigationBarNode, b: NavigationBarNode, bIndex: nu } } - lastANode = a.node = setTextRange(factory.createClassDeclaration( - /*modifiers*/ undefined, - a.name as Identifier || factory.createIdentifier("__class__"), - /*typeParameters*/ undefined, - /*heritageClauses*/ undefined, - [] - ), a.node); + lastANode = a.node = setTextRange( + factory.createClassDeclaration( + /*modifiers*/ undefined, + a.name as Identifier || factory.createIdentifier("__class__"), + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [], + ), + a.node, + ); } else { a.children = concatenate(a.children, b.children); @@ -702,13 +734,16 @@ function tryMergeEs5Class(a: NavigationBarNode, b: NavigationBarNode, bIndex: nu } else { if (!a.additionalNodes) a.additionalNodes = []; - a.additionalNodes.push(setTextRange(factory.createClassDeclaration( - /*modifiers*/ undefined, - a.name as Identifier || factory.createIdentifier("__class__"), - /*typeParameters*/ undefined, - /*heritageClauses*/ undefined, - [] - ), b.node)); + a.additionalNodes.push(setTextRange( + factory.createClassDeclaration( + /*modifiers*/ undefined, + a.name as Identifier || factory.createIdentifier("__class__"), + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [], + ), + b.node, + )); } return true; } @@ -740,7 +775,8 @@ function shouldReallyMerge(a: Node, b: Node, parent: NavigationBarNode): boolean return isStatic(a) === isStatic(b); case SyntaxKind.ModuleDeclaration: return areSameModule(a as ModuleDeclaration, b as ModuleDeclaration) - && getFullyQualifiedModuleName(a as ModuleDeclaration) === getFullyQualifiedModuleName(b as ModuleDeclaration); + && getFullyQualifiedModuleName(a as ModuleDeclaration) + === getFullyQualifiedModuleName(b as ModuleDeclaration); default: return true; } @@ -763,7 +799,9 @@ function areSameModule(a: ModuleDeclaration, b: ModuleDeclaration): boolean { if (!a.body || !b.body) { return a.body === b.body; } - return a.body.kind === b.body.kind && (a.body.kind !== SyntaxKind.ModuleDeclaration || areSameModule(a.body as ModuleDeclaration, b.body as ModuleDeclaration)); + return a.body.kind === b.body.kind + && (a.body.kind !== SyntaxKind.ModuleDeclaration + || areSameModule(a.body as ModuleDeclaration, b.body as ModuleDeclaration)); } /** Merge source into target. Source should be thrown away after this is called. */ @@ -837,7 +875,8 @@ function getItemName(node: Node, name: Node | undefined): string { ? `"${escapeString(getBaseFileName(removeFileExtension(normalizePath(sourceFile.fileName))))}"` : ""; case SyntaxKind.ExportAssignment: - return isExportAssignment(node) && node.isExportEquals ? InternalSymbolName.ExportEquals : InternalSymbolName.Default; + return isExportAssignment(node) && node.isExportEquals ? InternalSymbolName.ExportEquals + : InternalSymbolName.Default; case SyntaxKind.ArrowFunction: case SyntaxKind.FunctionDeclaration: @@ -936,7 +975,7 @@ function convertToTree(n: NavigationBarNode): NavigationTree { kindModifiers: getModifiers(n.node), spans: getSpans(n), nameSpan: n.name && getNodeSpan(n.name), - childItems: map(n.children, convertToTree) + childItems: map(n.children, convertToTree), }; } @@ -949,7 +988,7 @@ function convertToPrimaryNavBarMenuItem(n: NavigationBarNode): NavigationBarItem childItems: map(n.children, convertToSecondaryNavBarMenuItem) || emptyChildItemArray, indent: n.indent, bolded: false, - grayed: false + grayed: false, }; function convertToSecondaryNavBarMenuItem(n: NavigationBarNode): NavigationBarItem { @@ -961,7 +1000,7 @@ function convertToPrimaryNavBarMenuItem(n: NavigationBarNode): NavigationBarItem childItems: emptyChildItemArray, indent: 0, bolded: false, - grayed: false + grayed: false, }; } } @@ -1008,7 +1047,8 @@ function isComputedProperty(member: EnumMember): boolean { } function getNodeSpan(node: Node): TextSpan { - return node.kind === SyntaxKind.SourceFile ? createTextSpanFromRange(node) : createTextSpanFromNode(node, curSourceFile); + return node.kind === SyntaxKind.SourceFile ? createTextSpanFromRange(node) + : createTextSpanFromNode(node, curSourceFile); } function getModifiers(node: Node): string { @@ -1018,7 +1058,9 @@ function getModifiers(node: Node): string { return getNodeModifiers(node); } -function getFunctionOrClassName(node: FunctionExpression | FunctionDeclaration | ArrowFunction | ClassLikeDeclaration): string { +function getFunctionOrClassName( + node: FunctionExpression | FunctionDeclaration | ArrowFunction | ClassLikeDeclaration, +): string { const { parent } = node; if (node.name && getFullWidth(node.name) > 0) { return cleanText(declarationNameToString(node.name)); @@ -1051,7 +1093,11 @@ function getFunctionOrClassName(node: FunctionExpression | FunctionDeclaration | return `${name} callback`; } - const args = cleanText(mapDefined(parent.arguments, a => isStringLiteralLike(a) ? a.getText(curSourceFile) : undefined).join(", ")); + const args = cleanText( + mapDefined(parent.arguments, a => isStringLiteralLike(a) ? a.getText(curSourceFile) : undefined).join( + ", ", + ), + ); return `${name}(${args}) callback`; } } diff --git a/src/services/organizeImports.ts b/src/services/organizeImports.ts index 573f908abf974..b62b2ef752829 100644 --- a/src/services/organizeImports.ts +++ b/src/services/organizeImports.ts @@ -88,31 +88,48 @@ export function organizeImports( const shouldCombine = shouldSort; // These are currently inseparable, but I draw a distinction for clarity and in case we add modes in the future. const shouldRemove = mode === OrganizeImportsMode.RemoveUnused || mode === OrganizeImportsMode.All; // All of the old ImportDeclarations in the file, in syntactic order. - const topLevelImportGroupDecls = groupByNewlineContiguous(sourceFile, sourceFile.statements.filter(isImportDeclaration)); + const topLevelImportGroupDecls = groupByNewlineContiguous( + sourceFile, + sourceFile.statements.filter(isImportDeclaration), + ); - const comparer = getOrganizeImportsComparerWithDetection(preferences, shouldSort ? () => detectSortingWorker(topLevelImportGroupDecls, preferences) === SortKind.CaseInsensitive : undefined); + const comparer = getOrganizeImportsComparerWithDetection( + preferences, + shouldSort ? () => detectSortingWorker(topLevelImportGroupDecls, preferences) === SortKind.CaseInsensitive + : undefined, + ); const processImportsOfSameModuleSpecifier = (importGroup: readonly ImportDeclaration[]) => { if (shouldRemove) importGroup = removeUnusedImports(importGroup, sourceFile, program); if (shouldCombine) importGroup = coalesceImportsWorker(importGroup, comparer, sourceFile); - if (shouldSort) importGroup = stableSort(importGroup, (s1, s2) => compareImportsOrRequireStatements(s1, s2, comparer)); + if (shouldSort) { + importGroup = stableSort(importGroup, (s1, s2) => compareImportsOrRequireStatements(s1, s2, comparer)); + } return importGroup; }; - topLevelImportGroupDecls.forEach(importGroupDecl => organizeImportsWorker(importGroupDecl, processImportsOfSameModuleSpecifier)); + topLevelImportGroupDecls.forEach(importGroupDecl => + organizeImportsWorker(importGroupDecl, processImportsOfSameModuleSpecifier) + ); // Exports are always used if (mode !== OrganizeImportsMode.RemoveUnused) { // All of the old ExportDeclarations in the file, in syntactic order. getTopLevelExportGroups(sourceFile).forEach(exportGroupDecl => - organizeImportsWorker(exportGroupDecl, group => coalesceExportsWorker(group, comparer))); + organizeImportsWorker(exportGroupDecl, group => coalesceExportsWorker(group, comparer)) + ); } for (const ambientModule of sourceFile.statements.filter(isAmbientModule)) { if (!ambientModule.body) continue; - const ambientModuleImportGroupDecls = groupByNewlineContiguous(sourceFile, ambientModule.body.statements.filter(isImportDeclaration)); - ambientModuleImportGroupDecls.forEach(importGroupDecl => organizeImportsWorker(importGroupDecl, processImportsOfSameModuleSpecifier)); + const ambientModuleImportGroupDecls = groupByNewlineContiguous( + sourceFile, + ambientModule.body.statements.filter(isImportDeclaration), + ); + ambientModuleImportGroupDecls.forEach(importGroupDecl => + organizeImportsWorker(importGroupDecl, processImportsOfSameModuleSpecifier) + ); // Exports are always used if (mode !== OrganizeImportsMode.RemoveUnused) { @@ -142,12 +159,19 @@ export function organizeImports( ? group(oldImportDecls, importDecl => getExternalModuleName(importDecl.moduleSpecifier)!) : [oldImportDecls]; const sortedImportGroups = shouldSort - ? stableSort(oldImportGroups, (group1, group2) => compareModuleSpecifiersWorker(group1[0].moduleSpecifier, group2[0].moduleSpecifier, comparer)) + ? stableSort( + oldImportGroups, + (group1, group2) => + compareModuleSpecifiersWorker(group1[0].moduleSpecifier, group2[0].moduleSpecifier, comparer), + ) : oldImportGroups; - const newImportDecls = flatMap(sortedImportGroups, importGroup => - getExternalModuleName(importGroup[0].moduleSpecifier) || importGroup[0].moduleSpecifier === undefined - ? coalesce(importGroup) - : importGroup); + const newImportDecls = flatMap( + sortedImportGroups, + importGroup => + getExternalModuleName(importGroup[0].moduleSpecifier) || importGroup[0].moduleSpecifier === undefined + ? coalesce(importGroup) + : importGroup, + ); // Delete all nodes if there are no imports. if (newImportDecls.length === 0) { @@ -166,7 +190,11 @@ export function organizeImports( suffix: getNewLineOrDefaultFromHost(host, formatContext.options), }; changeTracker.replaceNodeWithNodes(sourceFile, oldImportDecls[0], newImportDecls, replaceOptions); - const hasTrailingComment = changeTracker.nodeHasTrailingComment(sourceFile, oldImportDecls[0], replaceOptions); + const hasTrailingComment = changeTracker.nodeHasTrailingComment( + sourceFile, + oldImportDecls[0], + replaceOptions, + ); changeTracker.deleteNodes(sourceFile, oldImportDecls.slice(1), { trailingTriviaOption: textChanges.TrailingTriviaOption.Include, }, hasTrailingComment); @@ -174,7 +202,10 @@ export function organizeImports( } } -function groupByNewlineContiguous(sourceFile: SourceFile, decls: T[]): T[][] { +function groupByNewlineContiguous( + sourceFile: SourceFile, + decls: T[], +): T[][] { const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ false, sourceFile.languageVariant); const group: T[][] = []; let groupIndex = 0; @@ -270,7 +301,8 @@ function removeUnusedImports(oldImports: readonly ImportDeclaration[], sourceFil importDecl.modifiers, /*importClause*/ undefined, moduleSpecifier, - /*assertClause*/ undefined)); + /*assertClause*/ undefined, + )); } // If we're not in a declaration file, we can't remove the import clause even though // the imported symbols are unused, because removing them makes it look like the import @@ -285,16 +317,19 @@ function removeUnusedImports(oldImports: readonly ImportDeclaration[], sourceFil function isDeclarationUsed(identifier: Identifier) { // The JSX factory symbol is always used if JSX elements are present - even if they are not allowed. - return jsxElementsPresent && (identifier.text === jsxNamespace || jsxFragmentFactory && identifier.text === jsxFragmentFactory) && jsxModeNeedsExplicitImport(compilerOptions.jsx) || - FindAllReferences.Core.isSymbolReferencedInFile(identifier, typeChecker, sourceFile); + return jsxElementsPresent + && (identifier.text === jsxNamespace || jsxFragmentFactory && identifier.text === jsxFragmentFactory) + && jsxModeNeedsExplicitImport(compilerOptions.jsx) + || FindAllReferences.Core.isSymbolReferencedInFile(identifier, typeChecker, sourceFile); } } function hasModuleDeclarationMatchingSpecifier(sourceFile: SourceFile, moduleSpecifier: Expression) { const moduleSpecifierText = isStringLiteral(moduleSpecifier) && moduleSpecifier.text; - return isString(moduleSpecifierText) && some(sourceFile.moduleAugmentations, moduleName => - isStringLiteral(moduleName) - && moduleName.text === moduleSpecifierText); + return isString(moduleSpecifierText) + && some(sourceFile.moduleAugmentations, moduleName => + isStringLiteral(moduleName) + && moduleName.text === moduleSpecifierText); } function getExternalModuleName(specifier: Expression | undefined) { @@ -310,12 +345,20 @@ function getExternalModuleName(specifier: Expression | undefined) { * @deprecated Only used for testing * @internal */ -export function coalesceImports(importGroup: readonly ImportDeclaration[], ignoreCase: boolean, sourceFile?: SourceFile): readonly ImportDeclaration[] { +export function coalesceImports( + importGroup: readonly ImportDeclaration[], + ignoreCase: boolean, + sourceFile?: SourceFile, +): readonly ImportDeclaration[] { const comparer = getOrganizeImportsOrdinalStringComparer(ignoreCase); return coalesceImportsWorker(importGroup, comparer, sourceFile); } -function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], comparer: Comparer, sourceFile?: SourceFile): readonly ImportDeclaration[] { +function coalesceImportsWorker( + importGroup: readonly ImportDeclaration[], + comparer: Comparer, + sourceFile?: SourceFile, +): readonly ImportDeclaration[] { if (importGroup.length === 0) { return importGroup; } @@ -336,18 +379,30 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar // Add the namespace import to the existing default ImportDeclaration. const defaultImport = defaultImports[0]; coalescedImports.push( - updateImportDeclarationAndClause(defaultImport, defaultImport.importClause.name, namespaceImports[0].importClause.namedBindings)); + updateImportDeclarationAndClause( + defaultImport, + defaultImport.importClause.name, + namespaceImports[0].importClause.namedBindings, + ), + ); continue; } - const sortedNamespaceImports = stableSort(namespaceImports, (i1, i2) => - comparer(i1.importClause.namedBindings.name.text, i2.importClause.namedBindings.name.text)); + const sortedNamespaceImports = stableSort( + namespaceImports, + (i1, i2) => comparer(i1.importClause.namedBindings.name.text, i2.importClause.namedBindings.name.text), + ); for (const namespaceImport of sortedNamespaceImports) { // Drop the name, if any coalescedImports.push( - updateImportDeclarationAndClause(namespaceImport, /*name*/ undefined, namespaceImport.importClause.namedBindings)); + updateImportDeclarationAndClause( + namespaceImport, + /*name*/ undefined, + namespaceImport.importClause.namedBindings, + ), + ); } const firstDefaultImport = firstOrUndefined(defaultImports); @@ -365,7 +420,12 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar else { for (const defaultImport of defaultImports) { newImportSpecifiers.push( - factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("default"), defaultImport.importClause.name)); + factory.createImportSpecifier( + /*isTypeOnly*/ false, + factory.createIdentifier("default"), + defaultImport.importClause.name, + ), + ); } } @@ -373,7 +433,7 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar const sortedImportSpecifiers = factory.createNodeArray( sortSpecifiers(newImportSpecifiers, comparer), - firstNamedImport?.importClause.namedBindings.elements.hasTrailingComma + firstNamedImport?.importClause.namedBindings.elements.hasTrailingComma, ); const newNamedImports = sortedImportSpecifiers.length === 0 @@ -381,13 +441,14 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar ? undefined : factory.createNamedImports(emptyArray) : firstNamedImport - ? factory.updateNamedImports(firstNamedImport.importClause.namedBindings, sortedImportSpecifiers) - : factory.createNamedImports(sortedImportSpecifiers); - - if (sourceFile && - newNamedImports && - firstNamedImport?.importClause.namedBindings && - !rangeIsOnSingleLine(firstNamedImport.importClause.namedBindings, sourceFile) + ? factory.updateNamedImports(firstNamedImport.importClause.namedBindings, sortedImportSpecifiers) + : factory.createNamedImports(sortedImportSpecifiers); + + if ( + sourceFile + && newNamedImports + && firstNamedImport?.importClause.namedBindings + && !rangeIsOnSingleLine(firstNamedImport.importClause.namedBindings, sourceFile) ) { setEmitFlags(newNamedImports, EmitFlags.MultiLine); } @@ -397,13 +458,16 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar // choose not to as a stylistic preference. if (isTypeOnly && newDefaultImport && newNamedImports) { coalescedImports.push( - updateImportDeclarationAndClause(importDecl, newDefaultImport, /*namedBindings*/ undefined)); + updateImportDeclarationAndClause(importDecl, newDefaultImport, /*namedBindings*/ undefined), + ); coalescedImports.push( - updateImportDeclarationAndClause(firstNamedImport ?? importDecl, /*name*/ undefined, newNamedImports)); + updateImportDeclarationAndClause(firstNamedImport ?? importDecl, /*name*/ undefined, newNamedImports), + ); } else { coalescedImports.push( - updateImportDeclarationAndClause(importDecl, newDefaultImport, newNamedImports)); + updateImportDeclarationAndClause(importDecl, newDefaultImport, newNamedImports), + ); } } @@ -508,7 +572,12 @@ function coalesceExportsWorker(exportGroup: readonly ExportDeclaration[], compar continue; } const newExportSpecifiers: ExportSpecifier[] = []; - newExportSpecifiers.push(...flatMap(exportGroup, i => i.exportClause && isNamedExports(i.exportClause) ? i.exportClause.elements : emptyArray)); + newExportSpecifiers.push( + ...flatMap( + exportGroup, + i => i.exportClause && isNamedExports(i.exportClause) ? i.exportClause.elements : emptyArray, + ), + ); const sortedExportSpecifiers = sortSpecifiers(newExportSpecifiers, comparer); @@ -519,12 +588,14 @@ function coalesceExportsWorker(exportGroup: readonly ExportDeclaration[], compar exportDecl.modifiers, exportDecl.isTypeOnly, exportDecl.exportClause && ( - isNamedExports(exportDecl.exportClause) ? - factory.updateNamedExports(exportDecl.exportClause, sortedExportSpecifiers) : - factory.updateNamespaceExport(exportDecl.exportClause, exportDecl.exportClause.name) + isNamedExports(exportDecl.exportClause) + ? factory.updateNamedExports(exportDecl.exportClause, sortedExportSpecifiers) + : factory.updateNamespaceExport(exportDecl.exportClause, exportDecl.exportClause.name) ), exportDecl.moduleSpecifier, - exportDecl.assertClause)); + exportDecl.assertClause, + ), + ); } return coalescedExports; @@ -564,14 +635,20 @@ function coalesceExportsWorker(exportGroup: readonly ExportDeclaration[], compar function updateImportDeclarationAndClause( importDeclaration: ImportDeclaration, name: Identifier | undefined, - namedBindings: NamedImportBindings | undefined) { - + namedBindings: NamedImportBindings | undefined, +) { return factory.updateImportDeclaration( importDeclaration, importDeclaration.modifiers, - factory.updateImportClause(importDeclaration.importClause!, importDeclaration.importClause!.isTypeOnly, name, namedBindings), // TODO: GH#18217 + factory.updateImportClause( + importDeclaration.importClause!, + importDeclaration.importClause!.isTypeOnly, + name, + namedBindings, + ), // TODO: GH#18217 importDeclaration.moduleSpecifier, - importDeclaration.assertClause); + importDeclaration.assertClause, + ); } function sortSpecifiers(specifiers: readonly T[], comparer: Comparer) { @@ -579,7 +656,11 @@ function sortSpecifiers(specifiers: readonly } /** @internal */ -export function compareImportOrExportSpecifiers(s1: T, s2: T, comparer: Comparer): Comparison { +export function compareImportOrExportSpecifiers( + s1: T, + s2: T, + comparer: Comparer, +): Comparison { return compareBooleans(s1.isTypeOnly, s2.isTypeOnly) || comparer(s1.name.text, s2.name.text); } @@ -594,12 +675,16 @@ export function compareModuleSpecifiers(m1: Expression | undefined, m2: Expressi return compareModuleSpecifiersWorker(m1, m2, comparer); } -function compareModuleSpecifiersWorker(m1: Expression | undefined, m2: Expression | undefined, comparer: Comparer) { +function compareModuleSpecifiersWorker( + m1: Expression | undefined, + m2: Expression | undefined, + comparer: Comparer, +) { const name1 = m1 === undefined ? undefined : getExternalModuleName(m1); const name2 = m2 === undefined ? undefined : getExternalModuleName(m2); - return compareBooleans(name1 === undefined, name2 === undefined) || - compareBooleans(isExternalModuleNameRelative(name1!), isExternalModuleNameRelative(name2!)) || - comparer(name1!, name2!); + return compareBooleans(name1 === undefined, name2 === undefined) + || compareBooleans(isExternalModuleNameRelative(name1!), isExternalModuleNameRelative(name2!)) + || comparer(name1!, name2!); } function getModuleSpecifierExpression(declaration: AnyImportOrRequireStatement): Expression | undefined { @@ -617,7 +702,8 @@ function getModuleSpecifierExpression(declaration: AnyImportOrRequireStatement): export function detectSorting(sourceFile: SourceFile, preferences: UserPreferences): SortKind { return detectSortingWorker( groupByNewlineContiguous(sourceFile, sourceFile.statements.filter(isImportDeclaration)), - preferences); + preferences, + ); } function detectSortingWorker(importGroups: ImportDeclaration[][], preferences: UserPreferences): SortKind { @@ -632,7 +718,8 @@ function detectSortingWorker(importGroups: ImportDeclaration[][], preferences: U importGroup, i => tryCast(i.moduleSpecifier, isStringLiteral)?.text ?? "", collateCaseSensitive, - collateCaseInsensitive); + collateCaseInsensitive, + ); if (moduleSpecifierSort) { // Don't let a single unsorted group of module specifiers make the whole algorithm detect unsorted. // If other things are sorted consistently, that's a stronger indicator than unsorted module specifiers. @@ -647,9 +734,13 @@ function detectSortingWorker(importGroups: ImportDeclaration[][], preferences: U // Check import specifiers const declarationWithNamedImports = find( importGroup, - i => tryCast(i.importClause?.namedBindings, isNamedImports)?.elements.length! > 1); + i => tryCast(i.importClause?.namedBindings, isNamedImports)?.elements.length! > 1, + ); if (declarationWithNamedImports) { - const namedImportSort = detectImportSpecifierSorting((declarationWithNamedImports.importClause!.namedBindings as NamedImports).elements, preferences); + const namedImportSort = detectImportSpecifierSorting( + (declarationWithNamedImports.importClause!.namedBindings as NamedImports).elements, + preferences, + ); if (namedImportSort) { // Don't let a single unsorted group of named imports make the whole algorithm detect unsorted. // If other things are sorted consistently, that's a stronger indicator than unsorted named imports. @@ -672,14 +763,17 @@ function detectSortingWorker(importGroups: ImportDeclaration[][], preferences: U } /** @internal */ -export function detectImportDeclarationSorting(imports: readonly AnyImportOrRequireStatement[], preferences: UserPreferences): SortKind { +export function detectImportDeclarationSorting( + imports: readonly AnyImportOrRequireStatement[], + preferences: UserPreferences, +): SortKind { const collateCaseSensitive = getOrganizeImportsComparer(preferences, /*ignoreCase*/ false); const collateCaseInsensitive = getOrganizeImportsComparer(preferences, /*ignoreCase*/ true); return detectSortCaseSensitivity( imports, s => getExternalModuleName(getModuleSpecifierExpression(s)) || "", collateCaseSensitive, - collateCaseInsensitive + collateCaseInsensitive, ); } @@ -708,30 +802,61 @@ class ImportSpecifierSortingCache implements MemoizeCache<[readonly ImportSpecif } /** @internal */ -export const detectImportSpecifierSorting = memoizeCached((specifiers: readonly ImportSpecifier[], preferences: UserPreferences): SortKind => { - if (!arrayIsSorted(specifiers, (s1, s2) => compareBooleans(s1.isTypeOnly, s2.isTypeOnly))) { - return SortKind.None; - } - const collateCaseSensitive = getOrganizeImportsComparer(preferences, /*ignoreCase*/ false); - const collateCaseInsensitive = getOrganizeImportsComparer(preferences, /*ignoreCase*/ true); - return detectSortCaseSensitivity(specifiers, specifier => specifier.name.text, collateCaseSensitive, collateCaseInsensitive); -}, new ImportSpecifierSortingCache()); +export const detectImportSpecifierSorting = memoizeCached( + (specifiers: readonly ImportSpecifier[], preferences: UserPreferences): SortKind => { + if (!arrayIsSorted(specifiers, (s1, s2) => compareBooleans(s1.isTypeOnly, s2.isTypeOnly))) { + return SortKind.None; + } + const collateCaseSensitive = getOrganizeImportsComparer(preferences, /*ignoreCase*/ false); + const collateCaseInsensitive = getOrganizeImportsComparer(preferences, /*ignoreCase*/ true); + return detectSortCaseSensitivity( + specifiers, + specifier => specifier.name.text, + collateCaseSensitive, + collateCaseInsensitive, + ); + }, + new ImportSpecifierSortingCache(), +); /** @internal */ -export function getImportDeclarationInsertionIndex(sortedImports: readonly AnyImportOrRequireStatement[], newImport: AnyImportOrRequireStatement, comparer: Comparer) { - const index = binarySearch(sortedImports, newImport, identity, (a, b) => compareImportsOrRequireStatements(a, b, comparer)); +export function getImportDeclarationInsertionIndex( + sortedImports: readonly AnyImportOrRequireStatement[], + newImport: AnyImportOrRequireStatement, + comparer: Comparer, +) { + const index = binarySearch( + sortedImports, + newImport, + identity, + (a, b) => compareImportsOrRequireStatements(a, b, comparer), + ); return index < 0 ? ~index : index; } /** @internal */ -export function getImportSpecifierInsertionIndex(sortedImports: readonly ImportSpecifier[], newImport: ImportSpecifier, comparer: Comparer) { - const index = binarySearch(sortedImports, newImport, identity, (s1, s2) => compareImportOrExportSpecifiers(s1, s2, comparer)); +export function getImportSpecifierInsertionIndex( + sortedImports: readonly ImportSpecifier[], + newImport: ImportSpecifier, + comparer: Comparer, +) { + const index = binarySearch( + sortedImports, + newImport, + identity, + (s1, s2) => compareImportOrExportSpecifiers(s1, s2, comparer), + ); return index < 0 ? ~index : index; } /** @internal */ -export function compareImportsOrRequireStatements(s1: AnyImportOrRequireStatement, s2: AnyImportOrRequireStatement, comparer: Comparer) { - return compareModuleSpecifiersWorker(getModuleSpecifierExpression(s1), getModuleSpecifierExpression(s2), comparer) || compareImportKind(s1, s2); +export function compareImportsOrRequireStatements( + s1: AnyImportOrRequireStatement, + s2: AnyImportOrRequireStatement, + comparer: Comparer, +) { + return compareModuleSpecifiersWorker(getModuleSpecifierExpression(s1), getModuleSpecifierExpression(s2), comparer) + || compareImportKind(s1, s2); } function compareImportKind(s1: AnyImportOrRequireStatement, s2: AnyImportOrRequireStatement) { @@ -761,12 +886,22 @@ function getImportKindOrder(s1: AnyImportOrRequireStatement) { } function getNewImportSpecifiers(namedImports: ImportDeclaration[]) { - return flatMap(namedImports, namedImport => - map(tryGetNamedBindingElements(namedImport), importSpecifier => - importSpecifier.name && importSpecifier.propertyName && importSpecifier.name.escapedText === importSpecifier.propertyName.escapedText - ? factory.updateImportSpecifier(importSpecifier, importSpecifier.isTypeOnly, /*propertyName*/ undefined, importSpecifier.name) - : importSpecifier - ) + return flatMap( + namedImports, + namedImport => + map( + tryGetNamedBindingElements(namedImport), + importSpecifier => + importSpecifier.name && importSpecifier.propertyName + && importSpecifier.name.escapedText === importSpecifier.propertyName.escapedText + ? factory.updateImportSpecifier( + importSpecifier, + importSpecifier.isTypeOnly, + /*propertyName*/ undefined, + importSpecifier.name, + ) + : importSpecifier, + ), ); } @@ -785,10 +920,9 @@ function getOrganizeImportsUnicodeStringComparer(ignoreCase: boolean, preference const caseFirst = preferences.organizeImportsCaseFirst ?? false; const numeric = preferences.organizeImportsNumericCollation ?? false; const accents = preferences.organizeImportsAccentCollation ?? true; - const sensitivity = - ignoreCase ? - accents ? "accent" : "base" : - accents ? "variant" : "case"; + const sensitivity = ignoreCase + ? accents ? "accent" : "base" + : accents ? "variant" : "case"; const collator = new Intl.Collator(resolvedLocale, { usage: "sort", @@ -814,13 +948,17 @@ function getOrganizeImportsLocale(preferences: UserPreferences): string { /** @internal */ export function getOrganizeImportsComparer(preferences: UserPreferences, ignoreCase: boolean): Comparer { const collation = preferences.organizeImportsCollation ?? "ordinal"; - return collation === "unicode" ? - getOrganizeImportsUnicodeStringComparer(ignoreCase, preferences) : - getOrganizeImportsOrdinalStringComparer(ignoreCase); + return collation === "unicode" + ? getOrganizeImportsUnicodeStringComparer(ignoreCase, preferences) + : getOrganizeImportsOrdinalStringComparer(ignoreCase); } -function getOrganizeImportsComparerWithDetection(preferences: UserPreferences, detectIgnoreCase?: () => boolean): Comparer { - const ignoreCase = typeof preferences.organizeImportsIgnoreCase === "boolean" ? preferences.organizeImportsIgnoreCase : detectIgnoreCase?.() ?? false; +function getOrganizeImportsComparerWithDetection( + preferences: UserPreferences, + detectIgnoreCase?: () => boolean, +): Comparer { + const ignoreCase = typeof preferences.organizeImportsIgnoreCase === "boolean" + ? preferences.organizeImportsIgnoreCase : detectIgnoreCase?.() ?? false; return getOrganizeImportsComparer(preferences, ignoreCase); } diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index 91e0573993e08..eed1c39d3192f 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -65,7 +65,11 @@ export function collectElements(sourceFile: SourceFile, cancellationToken: Cance return res.sort((span1, span2) => span1.textSpan.start - span2.textSpan.start); } -function addNodeOutliningSpans(sourceFile: SourceFile, cancellationToken: CancellationToken, out: OutliningSpan[]): void { +function addNodeOutliningSpans( + sourceFile: SourceFile, + cancellationToken: CancellationToken, + out: OutliningSpan[], +): void { let depthRemaining = 40; let current = 0; // Includes the EOF Token so that comments which aren't attached to statements are included @@ -84,7 +88,15 @@ function addNodeOutliningSpans(sourceFile: SourceFile, cancellationToken: Cancel } const lastImport = current - 1; if (lastImport !== firstImport) { - out.push(createOutliningSpanFromBounds(findChildOfKind(statements[firstImport], SyntaxKind.ImportKeyword, sourceFile)!.getStart(sourceFile), statements[lastImport].getEnd(), OutliningSpanKind.Imports)); + out.push( + createOutliningSpanFromBounds( + findChildOfKind(statements[firstImport], SyntaxKind.ImportKeyword, sourceFile)!.getStart( + sourceFile, + ), + statements[lastImport].getEnd(), + OutliningSpanKind.Imports, + ), + ); } } @@ -92,7 +104,10 @@ function addNodeOutliningSpans(sourceFile: SourceFile, cancellationToken: Cancel if (depthRemaining === 0) return; cancellationToken.throwIfCancellationRequested(); - if (isDeclaration(n) || isVariableStatement(n) || isReturnStatement(n) || isCallOrNewExpression(n) || n.kind === SyntaxKind.EndOfFileToken) { + if ( + isDeclaration(n) || isVariableStatement(n) || isReturnStatement(n) || isCallOrNewExpression(n) + || n.kind === SyntaxKind.EndOfFileToken + ) { addOutliningForLeadingCommentsForNode(n, sourceFile, cancellationToken, out); } @@ -147,7 +162,15 @@ function addRegionOutliningSpans(sourceFile: SourceFile, out: OutliningSpan[]): if (!result[1]) { const span = createTextSpanFromBounds(sourceFile.text.indexOf("//", currentLineStart), lineEnd); - regions.push(createOutliningSpan(span, OutliningSpanKind.Region, span, /*autoCollapse*/ false, result[2] || "#region")); + regions.push( + createOutliningSpan( + span, + OutliningSpanKind.Region, + span, + /*autoCollapse*/ false, + result[2] || "#region", + ), + ); } else { const region = regions.pop(); @@ -172,7 +195,12 @@ function isRegionDelimiter(lineText: string) { return regionDelimiterRegExp.exec(lineText); } -function addOutliningForLeadingCommentsForPos(pos: number, sourceFile: SourceFile, cancellationToken: CancellationToken, out: OutliningSpan[]): void { +function addOutliningForLeadingCommentsForPos( + pos: number, + sourceFile: SourceFile, + cancellationToken: CancellationToken, + out: OutliningSpan[], +): void { const comments = getLeadingCommentRanges(sourceFile.text, pos); if (!comments) return; @@ -214,12 +242,23 @@ function addOutliningForLeadingCommentsForPos(pos: number, sourceFile: SourceFil function combineAndAddMultipleSingleLineComments(): void { // Only outline spans of two or more consecutive single line comments if (singleLineCommentCount > 1) { - out.push(createOutliningSpanFromBounds(firstSingleLineCommentStart, lastSingleLineCommentEnd, OutliningSpanKind.Comment)); + out.push( + createOutliningSpanFromBounds( + firstSingleLineCommentStart, + lastSingleLineCommentEnd, + OutliningSpanKind.Comment, + ), + ); } } } -function addOutliningForLeadingCommentsForNode(n: Node, sourceFile: SourceFile, cancellationToken: CancellationToken, out: OutliningSpan[]): void { +function addOutliningForLeadingCommentsForNode( + n: Node, + sourceFile: SourceFile, + cancellationToken: CancellationToken, + out: OutliningSpan[], +): void { if (isJsxText(n)) return; addOutliningForLeadingCommentsForPos(n.pos, sourceFile, cancellationToken, out); } @@ -274,7 +313,12 @@ function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan case SyntaxKind.ObjectBindingPattern: return spanForNode(n); case SyntaxKind.TupleType: - return spanForNode(n, /*autoCollapse*/ false, /*useFullStart*/ !isTupleTypeNode(n.parent), SyntaxKind.OpenBracketToken); + return spanForNode( + n, + /*autoCollapse*/ false, + /*useFullStart*/ !isTupleTypeNode(n.parent), + SyntaxKind.OpenBracketToken, + ); case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: return spanForNodeArray((n as CaseClause | DefaultClause).statements); @@ -293,7 +337,12 @@ function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan case SyntaxKind.NoSubstitutionTemplateLiteral: return spanForTemplateLiteral(n as TemplateExpression | NoSubstitutionTemplateLiteral); case SyntaxKind.ArrayBindingPattern: - return spanForNode(n, /*autoCollapse*/ false, /*useFullStart*/ !isBindingElement(n.parent), SyntaxKind.OpenBracketToken); + return spanForNode( + n, + /*autoCollapse*/ false, + /*useFullStart*/ !isBindingElement(n.parent), + SyntaxKind.OpenBracketToken, + ); case SyntaxKind.ArrowFunction: return spanForArrowFunction(n as ArrowFunction); case SyntaxKind.CallExpression: @@ -316,7 +365,14 @@ function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan return undefined; } - return spanBetweenTokens(openToken, closeToken, node, sourceFile, /*autoCollapse*/ false, /*useFullStart*/ false); + return spanBetweenTokens( + openToken, + closeToken, + node, + sourceFile, + /*autoCollapse*/ false, + /*useFullStart*/ false, + ); } function spanForCallExpression(node: CallExpression): OutliningSpan | undefined { @@ -329,11 +385,21 @@ function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan return undefined; } - return spanBetweenTokens(openToken, closeToken, node, sourceFile, /*autoCollapse*/ false, /*useFullStart*/ true); + return spanBetweenTokens( + openToken, + closeToken, + node, + sourceFile, + /*autoCollapse*/ false, + /*useFullStart*/ true, + ); } function spanForArrowFunction(node: ArrowFunction): OutliningSpan | undefined { - if (isBlock(node.body) || isParenthesizedExpression(node.body) || positionsAreOnSameLine(node.body.getFullStart(), node.body.getEnd(), sourceFile)) { + if ( + isBlock(node.body) || isParenthesizedExpression(node.body) + || positionsAreOnSameLine(node.body.getFullStart(), node.body.getEnd(), sourceFile) + ) { return undefined; } const textSpan = createTextSpanFromBounds(node.body.getFullStart(), node.body.getEnd()); @@ -341,14 +407,20 @@ function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan } function spanForJSXElement(node: JsxElement): OutliningSpan | undefined { - const textSpan = createTextSpanFromBounds(node.openingElement.getStart(sourceFile), node.closingElement.getEnd()); + const textSpan = createTextSpanFromBounds( + node.openingElement.getStart(sourceFile), + node.closingElement.getEnd(), + ); const tagName = node.openingElement.tagName.getText(sourceFile); const bannerText = "<" + tagName + ">..."; return createOutliningSpan(textSpan, OutliningSpanKind.Code, textSpan, /*autoCollapse*/ false, bannerText); } function spanForJSXFragment(node: JsxFragment): OutliningSpan | undefined { - const textSpan = createTextSpanFromBounds(node.openingFragment.getStart(sourceFile), node.closingFragment.getEnd()); + const textSpan = createTextSpanFromBounds( + node.openingFragment.getStart(sourceFile), + node.closingFragment.getEnd(), + ); const bannerText = "<>..."; return createOutliningSpan(textSpan, OutliningSpanKind.Code, textSpan, /*autoCollapse*/ false, bannerText); } @@ -368,21 +440,38 @@ function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan return createOutliningSpanFromBounds(node.getStart(sourceFile), node.getEnd(), OutliningSpanKind.Code); } - function spanForObjectOrArrayLiteral(node: Node, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken): OutliningSpan | undefined { + function spanForObjectOrArrayLiteral( + node: Node, + open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken, + ): OutliningSpan | undefined { // If the block has no leading keywords and is inside an array literal or call expression, // we only want to collapse the span of the block. // Otherwise, the collapsed section will include the end of the previous line. - return spanForNode(node, /*autoCollapse*/ false, /*useFullStart*/ !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), open); + return spanForNode( + node, + /*autoCollapse*/ false, + /*useFullStart*/ !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), + open, + ); } - function spanForNode(hintSpanNode: Node, autoCollapse = false, useFullStart = true, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken, close: SyntaxKind = open === SyntaxKind.OpenBraceToken ? SyntaxKind.CloseBraceToken : SyntaxKind.CloseBracketToken): OutliningSpan | undefined { + function spanForNode( + hintSpanNode: Node, + autoCollapse = false, + useFullStart = true, + open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken, + close: SyntaxKind = open === SyntaxKind.OpenBraceToken ? SyntaxKind.CloseBraceToken + : SyntaxKind.CloseBracketToken, + ): OutliningSpan | undefined { const openToken = findChildOfKind(n, open, sourceFile); const closeToken = findChildOfKind(n, close, sourceFile); - return openToken && closeToken && spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile, autoCollapse, useFullStart); + return openToken && closeToken + && spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile, autoCollapse, useFullStart); } function spanForNodeArray(nodeArray: NodeArray): OutliningSpan | undefined { - return nodeArray.length ? createOutliningSpan(createTextSpanFromRange(nodeArray), OutliningSpanKind.Code) : undefined; + return nodeArray.length ? createOutliningSpan(createTextSpanFromRange(nodeArray), OutliningSpanKind.Code) + : undefined; } function spanForParenthesizedExpression(node: ParenthesizedExpression): OutliningSpan | undefined { @@ -395,15 +484,43 @@ function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan function functionSpan(node: SignatureDeclaration, body: Block, sourceFile: SourceFile): OutliningSpan | undefined { const openToken = tryGetFunctionOpenToken(node, body, sourceFile); const closeToken = findChildOfKind(body, SyntaxKind.CloseBraceToken, sourceFile); - return openToken && closeToken && spanBetweenTokens(openToken, closeToken, node, sourceFile, /*autoCollapse*/ node.kind !== SyntaxKind.ArrowFunction); + return openToken && closeToken + && spanBetweenTokens( + openToken, + closeToken, + node, + sourceFile, + /*autoCollapse*/ node.kind !== SyntaxKind.ArrowFunction, + ); } -function spanBetweenTokens(openToken: Node, closeToken: Node, hintSpanNode: Node, sourceFile: SourceFile, autoCollapse = false, useFullStart = true): OutliningSpan { - const textSpan = createTextSpanFromBounds(useFullStart ? openToken.getFullStart() : openToken.getStart(sourceFile), closeToken.getEnd()); - return createOutliningSpan(textSpan, OutliningSpanKind.Code, createTextSpanFromNode(hintSpanNode, sourceFile), autoCollapse); +function spanBetweenTokens( + openToken: Node, + closeToken: Node, + hintSpanNode: Node, + sourceFile: SourceFile, + autoCollapse = false, + useFullStart = true, +): OutliningSpan { + const textSpan = createTextSpanFromBounds( + useFullStart ? openToken.getFullStart() : openToken.getStart(sourceFile), + closeToken.getEnd(), + ); + return createOutliningSpan( + textSpan, + OutliningSpanKind.Code, + createTextSpanFromNode(hintSpanNode, sourceFile), + autoCollapse, + ); } -function createOutliningSpan(textSpan: TextSpan, kind: OutliningSpanKind, hintSpan: TextSpan = textSpan, autoCollapse = false, bannerText = "..."): OutliningSpan { +function createOutliningSpan( + textSpan: TextSpan, + kind: OutliningSpanKind, + hintSpan: TextSpan = textSpan, + autoCollapse = false, + bannerText = "...", +): OutliningSpan { return { textSpan, kind, hintSpan, bannerText, autoCollapse }; } diff --git a/src/services/patternMatcher.ts b/src/services/patternMatcher.ts index 212369a9df165..6a197f0eeee26 100644 --- a/src/services/patternMatcher.ts +++ b/src/services/patternMatcher.ts @@ -18,7 +18,7 @@ export enum PatternMatchKind { exact, prefix, substring, - camelCase + camelCase, } // Information about a match made by the pattern matcher between a candidate and the @@ -108,7 +108,7 @@ interface TextChunk { function createPatternMatch(kind: PatternMatchKind, isCaseSensitive: boolean): PatternMatch { return { kind, - isCaseSensitive + isCaseSensitive, }; } @@ -125,13 +125,20 @@ export function createPatternMatcher(pattern: string): PatternMatcher | undefine if (dotSeparatedSegments.some(segment => !segment.subWordTextChunks.length)) return undefined; return { - getFullMatch: (containers, candidate) => getFullMatch(containers, candidate, dotSeparatedSegments, stringToWordSpans), - getMatchForLastSegmentOfPattern: candidate => matchSegment(candidate, last(dotSeparatedSegments), stringToWordSpans), - patternContainsDots: dotSeparatedSegments.length > 1 + getFullMatch: (containers, candidate) => + getFullMatch(containers, candidate, dotSeparatedSegments, stringToWordSpans), + getMatchForLastSegmentOfPattern: candidate => + matchSegment(candidate, last(dotSeparatedSegments), stringToWordSpans), + patternContainsDots: dotSeparatedSegments.length > 1, }; } -function getFullMatch(candidateContainers: readonly string[], candidate: string, dotSeparatedSegments: readonly Segment[], stringToWordSpans: Map): PatternMatch | undefined { +function getFullMatch( + candidateContainers: readonly string[], + candidate: string, + dotSeparatedSegments: readonly Segment[], + stringToWordSpans: Map, +): PatternMatch | undefined { // First, check that the last part of the dot separated pattern matches the name of the // candidate. If not, then there's no point in proceeding and doing the more // expensive work. @@ -149,10 +156,11 @@ function getFullMatch(candidateContainers: readonly string[], candidate: string, } let bestMatch: PatternMatch | undefined; - for (let i = dotSeparatedSegments.length - 2, j = candidateContainers.length - 1; - i >= 0; - i -= 1, j -= 1) { - bestMatch = betterMatch(bestMatch, matchSegment(candidateContainers[j], dotSeparatedSegments[i], stringToWordSpans)); + for (let i = dotSeparatedSegments.length - 2, j = candidateContainers.length - 1; i >= 0; i -= 1, j -= 1) { + bestMatch = betterMatch( + bestMatch, + matchSegment(candidateContainers[j], dotSeparatedSegments[i], stringToWordSpans), + ); } return bestMatch; } @@ -165,12 +173,19 @@ function getWordSpans(word: string, stringToWordSpans: Map): return spans; } -function matchTextChunk(candidate: string, chunk: TextChunk, stringToWordSpans: Map): PatternMatch | undefined { +function matchTextChunk( + candidate: string, + chunk: TextChunk, + stringToWordSpans: Map, +): PatternMatch | undefined { const index = indexOfIgnoringCase(candidate, chunk.textLowerCase); if (index === 0) { // a) Check if the word is a prefix of the candidate, in a case insensitive or // sensitive manner. If it does, return that there was an exact match if the word and candidate are the same length, else a prefix match. - return createPatternMatch(chunk.text.length === candidate.length ? PatternMatchKind.exact : PatternMatchKind.prefix, /*isCaseSensitive:*/ startsWith(candidate, chunk.text)); + return createPatternMatch( + chunk.text.length === candidate.length ? PatternMatchKind.exact : PatternMatchKind.prefix, + /*isCaseSensitive:*/ startsWith(candidate, chunk.text), + ); } if (chunk.isLowerCase) { @@ -185,7 +200,10 @@ function matchTextChunk(candidate: string, chunk: TextChunk, stringToWordSpans: const wordSpans = getWordSpans(candidate, stringToWordSpans); for (const span of wordSpans) { if (partStartsWith(candidate, span, chunk.text, /*ignoreCase*/ true)) { - return createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase*/ false)); + return createPatternMatch( + PatternMatchKind.substring, + /*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase*/ false), + ); } } // c) Is the pattern a substring of the candidate starting on one of the candidate's word boundaries? @@ -217,7 +235,11 @@ function matchTextChunk(candidate: string, chunk: TextChunk, stringToWordSpans: } } -function matchSegment(candidate: string, segment: Segment, stringToWordSpans: Map): PatternMatch | undefined { +function matchSegment( + candidate: string, + segment: Segment, + stringToWordSpans: Map, +): PatternMatch | undefined { // First check if the segment matches as is. This is also useful if the segment contains // characters we would normally strip when splitting into parts that we also may want to // match in the candidate. For example if the segment is "@int" and the candidate is @@ -282,16 +304,35 @@ function compareMatches(a: PatternMatch | undefined, b: PatternMatch | undefined : compareValues(a.kind, b.kind) || compareBooleans(!a.isCaseSensitive, !b.isCaseSensitive); } -function partStartsWith(candidate: string, candidateSpan: TextSpan, pattern: string, ignoreCase: boolean, patternSpan: TextSpan = { start: 0, length: pattern.length }): boolean { +function partStartsWith( + candidate: string, + candidateSpan: TextSpan, + pattern: string, + ignoreCase: boolean, + patternSpan: TextSpan = { start: 0, length: pattern.length }, +): boolean { return patternSpan.length <= candidateSpan.length // If pattern part is longer than the candidate part there can never be a match. - && everyInRange(0, patternSpan.length, i => equalChars(pattern.charCodeAt(patternSpan.start + i), candidate.charCodeAt(candidateSpan.start + i), ignoreCase)); + && everyInRange( + 0, + patternSpan.length, + i => equalChars( + pattern.charCodeAt(patternSpan.start + i), + candidate.charCodeAt(candidateSpan.start + i), + ignoreCase, + ), + ); } function equalChars(ch1: number, ch2: number, ignoreCase: boolean): boolean { return ignoreCase ? toLowerCase(ch1) === toLowerCase(ch2) : ch1 === ch2; } -function tryCamelCaseMatch(candidate: string, candidateParts: TextSpan[], chunk: TextChunk, ignoreCase: boolean): boolean { +function tryCamelCaseMatch( + candidate: string, + candidateParts: TextSpan[], + chunk: TextChunk, + ignoreCase: boolean, +): boolean { const chunkCharacterSpans = chunk.characterSpans; // Note: we may have more pattern parts than candidate parts. This is because multiple @@ -328,8 +369,10 @@ function tryCamelCaseMatch(candidate: string, candidateParts: TextSpan[], chunk: // We've already gotten one pattern part match in this candidate. We will // only continue trying to consumer pattern parts if the last part and this // part are both upper case. - if (!isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan - 1].start)) || - !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan].start))) { + if ( + !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan - 1].start)) + || !isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan].start)) + ) { break; } } @@ -347,7 +390,10 @@ function tryCamelCaseMatch(candidate: string, candidateParts: TextSpan[], chunk: // obviously contiguous. contiguous = contiguous === undefined ? true : contiguous; - candidatePart = createTextSpan(candidatePart.start + chunkCharacterSpan.length, candidatePart.length - chunkCharacterSpan.length); + candidatePart = createTextSpan( + candidatePart.start + chunkCharacterSpan.length, + candidatePart.length - chunkCharacterSpan.length, + ); } // Check if we matched anything at all. If we didn't, then we need to unset the @@ -366,7 +412,7 @@ function tryCamelCaseMatch(candidate: string, candidateParts: TextSpan[], chunk: function createSegment(text: string): Segment { return { totalTextChunk: createTextChunk(text), - subWordTextChunks: breakPatternIntoTextChunks(text) + subWordTextChunks: breakPatternIntoTextChunks(text), }; } @@ -396,7 +442,6 @@ function isLowerCaseLetter(ch: number) { return false; } - // TODO: find a way to determine this for any unicode characters in a // non-allocating manner. const str = String.fromCharCode(ch); @@ -436,7 +481,8 @@ function isDigit(ch: number) { } function isWordChar(ch: number) { - return isUpperCaseLetter(ch) || isLowerCaseLetter(ch) || isDigit(ch) || ch === CharacterCodes._ || ch === CharacterCodes.$; + return isUpperCaseLetter(ch) || isLowerCaseLetter(ch) || isDigit(ch) || ch === CharacterCodes._ + || ch === CharacterCodes.$; } function breakPatternIntoTextChunks(pattern: string): TextChunk[] { @@ -473,7 +519,7 @@ function createTextChunk(text: string): TextChunk { text, textLowerCase, isLowerCase: text === textLowerCase, - characterSpans: breakIntoCharacterSpans(text) + characterSpans: breakIntoCharacterSpans(text), }; } @@ -498,12 +544,13 @@ function breakIntoSpans(identifier: string, word: boolean): TextSpan[] { const hasTransitionFromLowerToUpper = transitionFromLowerToUpper(identifier, word, i); const hasTransitionFromUpperToLower = word && transitionFromUpperToLower(identifier, i, wordStart); - if (charIsPunctuation(identifier.charCodeAt(i - 1)) || - charIsPunctuation(identifier.charCodeAt(i)) || - lastIsDigit !== currentIsDigit || - hasTransitionFromLowerToUpper || - hasTransitionFromUpperToLower) { - + if ( + charIsPunctuation(identifier.charCodeAt(i - 1)) + || charIsPunctuation(identifier.charCodeAt(i)) + || lastIsDigit !== currentIsDigit + || hasTransitionFromLowerToUpper + || hasTransitionFromUpperToLower + ) { if (!isAllPunctuation(identifier, wordStart, i)) { result.push(createTextSpan(wordStart, i - wordStart)); } diff --git a/src/services/preProcess.ts b/src/services/preProcess.ts index 91bbe396a2fd6..7293654da70cf 100644 --- a/src/services/preProcess.ts +++ b/src/services/preProcess.ts @@ -13,7 +13,11 @@ import { SyntaxKind, } from "./_namespaces/ts"; -export function preProcessFile(sourceText: string, readImportFiles = true, detectJavaScriptImports = false): PreProcessedFileInfo { +export function preProcessFile( + sourceText: string, + readImportFiles = true, + detectJavaScriptImports = false, +): PreProcessedFileInfo { const pragmaContext: PragmaContext = { languageVersion: ScriptTarget.ES5, // controls whether the token scanner considers unicode identifiers or not - shouldn't matter, since we're only using it for trivia pragmas: undefined, @@ -23,10 +27,10 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec libReferenceDirectives: [], amdDependencies: [], hasNoDefaultLib: undefined, - moduleName: undefined + moduleName: undefined, }; const importedFiles: FileReference[] = []; - let ambientExternalModules: { ref: FileReference, depth: number }[] | undefined; + let ambientExternalModules: { ref: FileReference; depth: number; }[] | undefined; let lastToken: SyntaxKind; let currentToken: SyntaxKind; let braceNesting = 0; @@ -119,10 +123,10 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec const skipTypeKeyword = scanner.lookAhead(() => { const token = scanner.scan(); return token !== SyntaxKind.FromKeyword && ( - token === SyntaxKind.AsteriskToken || - token === SyntaxKind.OpenBraceToken || - token === SyntaxKind.Identifier || - isKeyword(token) + token === SyntaxKind.AsteriskToken + || token === SyntaxKind.OpenBraceToken + || token === SyntaxKind.Identifier + || isKeyword(token) ); }); if (skipTypeKeyword) { @@ -208,8 +212,8 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec if (token === SyntaxKind.TypeKeyword) { const skipTypeKeyword = scanner.lookAhead(() => { const token = scanner.scan(); - return token === SyntaxKind.AsteriskToken || - token === SyntaxKind.OpenBraceToken; + return token === SyntaxKind.AsteriskToken + || token === SyntaxKind.OpenBraceToken; }); if (skipTypeKeyword) { token = nextToken(); @@ -250,8 +254,8 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec if (token === SyntaxKind.TypeKeyword) { const skipTypeKeyword = scanner.lookAhead(() => { const token = scanner.scan(); - return token === SyntaxKind.Identifier || - isKeyword(token); + return token === SyntaxKind.Identifier + || isKeyword(token); }); if (skipTypeKeyword) { token = nextToken(); @@ -279,8 +283,10 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec token = nextToken(); if (token === SyntaxKind.OpenParenToken) { token = nextToken(); - if (token === SyntaxKind.StringLiteral || - allowTemplateLiterals && token === SyntaxKind.NoSubstitutionTemplateLiteral) { + if ( + token === SyntaxKind.StringLiteral + || allowTemplateLiterals && token === SyntaxKind.NoSubstitutionTemplateLiteral + ) { // require("mod"); recordModuleName(); } @@ -328,7 +334,6 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec token = nextToken(); } return true; - } return false; } @@ -361,7 +366,8 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec if (scanner.getToken() === SyntaxKind.TemplateHead) { const stack = [scanner.getToken()]; - loop: while (length(stack)) { + loop: + while (length(stack)) { const token = scanner.scan(); switch (token) { case SyntaxKind.EndOfFileToken: @@ -380,7 +386,10 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec case SyntaxKind.CloseBraceToken: if (length(stack)) { if (lastOrUndefined(stack) === SyntaxKind.TemplateHead) { - if (scanner.reScanTemplateToken(/*isTaggedTemplate*/ false) === SyntaxKind.TemplateTail) { + if ( + scanner.reScanTemplateToken(/*isTaggedTemplate*/ false) + === SyntaxKind.TemplateTail + ) { stack.pop(); } } @@ -395,13 +404,15 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec } // check if at least one of alternative have moved scanner forward - if (tryConsumeDeclare() || - tryConsumeImport() || - tryConsumeExport() || - (detectJavaScriptImports && ( - tryConsumeRequireCall(/*skipCurrentToken*/ false, /*allowTemplateLiterals*/ true) || - tryConsumeDefine() - ))) { + if ( + tryConsumeDeclare() + || tryConsumeImport() + || tryConsumeExport() + || (detectJavaScriptImports && ( + tryConsumeRequireCall(/*skipCurrentToken*/ false, /*allowTemplateLiterals*/ true) + || tryConsumeDefine() + )) + ) { continue; } else { @@ -425,7 +436,14 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec importedFiles.push(decl.ref); } } - return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, libReferenceDirectives: pragmaContext.libReferenceDirectives, importedFiles, isLibFile: !!pragmaContext.hasNoDefaultLib, ambientExternalModules: undefined }; + return { + referencedFiles: pragmaContext.referencedFiles, + typeReferenceDirectives: pragmaContext.typeReferenceDirectives, + libReferenceDirectives: pragmaContext.libReferenceDirectives, + importedFiles, + isLibFile: !!pragmaContext.hasNoDefaultLib, + ambientExternalModules: undefined, + }; } else { // for global scripts ambient modules still can have augmentations - look for ambient modules with depth > 0 @@ -443,6 +461,13 @@ export function preProcessFile(sourceText: string, readImportFiles = true, detec } } } - return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, libReferenceDirectives: pragmaContext.libReferenceDirectives, importedFiles, isLibFile: !!pragmaContext.hasNoDefaultLib, ambientExternalModules: ambientModuleNames }; + return { + referencedFiles: pragmaContext.referencedFiles, + typeReferenceDirectives: pragmaContext.typeReferenceDirectives, + libReferenceDirectives: pragmaContext.libReferenceDirectives, + importedFiles, + isLibFile: !!pragmaContext.hasNoDefaultLib, + ambientExternalModules: ambientModuleNames, + }; } } diff --git a/src/services/refactorProvider.ts b/src/services/refactorProvider.ts index a540be35b511b..392c79c8618ca 100644 --- a/src/services/refactorProvider.ts +++ b/src/services/refactorProvider.ts @@ -7,7 +7,9 @@ import { RefactorContext, RefactorEditInfo, } from "./_namespaces/ts"; -import { refactorKindBeginsWith } from "./_namespaces/ts.refactor"; +import { + refactorKindBeginsWith, +} from "./_namespaces/ts.refactor"; // A map with the refactor code as key, the refactor itself as value // e.g. nonSuggestableRefactors[refactorCode] -> the refactor you want @@ -23,15 +25,28 @@ export function registerRefactor(name: string, refactor: Refactor) { } /** @internal */ -export function getApplicableRefactors(context: RefactorContext, includeInteractiveActions?: boolean): ApplicableRefactorInfo[] { - return arrayFrom(flatMapIterator(refactors.values(), refactor => - context.cancellationToken && context.cancellationToken.isCancellationRequested() || - !refactor.kinds?.some(kind => refactorKindBeginsWith(kind, context.kind)) ? undefined : - refactor.getAvailableActions(context, includeInteractiveActions))); +export function getApplicableRefactors( + context: RefactorContext, + includeInteractiveActions?: boolean, +): ApplicableRefactorInfo[] { + return arrayFrom( + flatMapIterator( + refactors.values(), + refactor => + context.cancellationToken && context.cancellationToken.isCancellationRequested() + || !refactor.kinds?.some(kind => refactorKindBeginsWith(kind, context.kind)) ? undefined + : refactor.getAvailableActions(context, includeInteractiveActions), + ), + ); } /** @internal */ -export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string, interactiveRefactorArguments?: InteractiveRefactorArguments): RefactorEditInfo | undefined { +export function getEditsForRefactor( + context: RefactorContext, + refactorName: string, + actionName: string, + interactiveRefactorArguments?: InteractiveRefactorArguments, +): RefactorEditInfo | undefined { const refactor = refactors.get(refactorName); return refactor && refactor.getEditsForAction(context, actionName, interactiveRefactorArguments); } diff --git a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts index 40640dc73ef55..588fa065561c7 100644 --- a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts +++ b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts @@ -45,12 +45,12 @@ const addBracesAction = { const removeBracesAction = { name: "Remove braces from arrow function", description: getLocaleSpecificMessage(Diagnostics.Remove_braces_from_arrow_function), - kind: "refactor.rewrite.arrow.braces.remove" + kind: "refactor.rewrite.arrow.braces.remove", }; registerRefactor(refactorName, { kinds: [removeBracesAction.kind], getEditsForAction: getRefactorEditsToRemoveFunctionBraces, - getAvailableActions: getRefactorActionsToRemoveFunctionBraces + getAvailableActions: getRefactorActionsToRemoveFunctionBraces, }); interface FunctionBracesInfo { @@ -70,8 +70,8 @@ function getRefactorActionsToRemoveFunctionBraces(context: RefactorContext): rea name: refactorName, description: refactorDescription, actions: [ - info.addBraces ? addBracesAction : removeBracesAction - ] + info.addBraces ? addBracesAction : removeBracesAction, + ], }]; } @@ -82,14 +82,17 @@ function getRefactorActionsToRemoveFunctionBraces(context: RefactorContext): rea actions: [ { ...addBracesAction, notApplicableReason: info.error }, { ...removeBracesAction, notApplicableReason: info.error }, - ] + ], }]; } return emptyArray; } -function getRefactorEditsToRemoveFunctionBraces(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { +function getRefactorEditsToRemoveFunctionBraces( + context: RefactorContext, + actionName: string, +): RefactorEditInfo | undefined { const { file, startPosition } = context; const info = getConvertibleArrowFunctionAtPosition(file, startPosition); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); @@ -101,14 +104,39 @@ function getRefactorEditsToRemoveFunctionBraces(context: RefactorContext, action if (actionName === addBracesAction.name) { const returnStatement = factory.createReturnStatement(expression); body = factory.createBlock([returnStatement], /*multiLine*/ true); - copyLeadingComments(expression!, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /*hasTrailingNewLine*/ true); + copyLeadingComments( + expression!, + returnStatement, + file, + SyntaxKind.MultiLineCommentTrivia, + /*hasTrailingNewLine*/ true, + ); } else if (actionName === removeBracesAction.name && returnStatement) { const actualExpression = expression || factory.createVoidZero(); - body = needsParentheses(actualExpression) ? factory.createParenthesizedExpression(actualExpression) : actualExpression; - copyTrailingAsLeadingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /*hasTrailingNewLine*/ false); - copyLeadingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /*hasTrailingNewLine*/ false); - copyTrailingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /*hasTrailingNewLine*/ false); + body = needsParentheses(actualExpression) ? factory.createParenthesizedExpression(actualExpression) + : actualExpression; + copyTrailingAsLeadingComments( + returnStatement, + body, + file, + SyntaxKind.MultiLineCommentTrivia, + /*hasTrailingNewLine*/ false, + ); + copyLeadingComments( + returnStatement, + body, + file, + SyntaxKind.MultiLineCommentTrivia, + /*hasTrailingNewLine*/ false, + ); + copyTrailingComments( + returnStatement, + body, + file, + SyntaxKind.MultiLineCommentTrivia, + /*hasTrailingNewLine*/ false, + ); } else { Debug.fail("invalid action"); @@ -121,19 +149,24 @@ function getRefactorEditsToRemoveFunctionBraces(context: RefactorContext, action return { renameFilename: undefined, renameLocation: undefined, edits }; } -function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number, considerFunctionBodies = true, kind?: string): FunctionBracesInfo | RefactorErrorInfo | undefined { +function getConvertibleArrowFunctionAtPosition( + file: SourceFile, + startPosition: number, + considerFunctionBodies = true, + kind?: string, +): FunctionBracesInfo | RefactorErrorInfo | undefined { const node = getTokenAtPosition(file, startPosition); const func = getContainingFunction(node); if (!func) { return { - error: getLocaleSpecificMessage(Diagnostics.Could_not_find_a_containing_arrow_function) + error: getLocaleSpecificMessage(Diagnostics.Could_not_find_a_containing_arrow_function), }; } if (!isArrowFunction(func)) { return { - error: getLocaleSpecificMessage(Diagnostics.Containing_function_is_not_an_arrow_function) + error: getLocaleSpecificMessage(Diagnostics.Containing_function_is_not_an_arrow_function), }; } @@ -144,7 +177,9 @@ function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: if (refactorKindBeginsWith(addBracesAction.kind, kind) && isExpression(func.body)) { return { func, addBraces: true, expression: func.body }; } - else if (refactorKindBeginsWith(removeBracesAction.kind, kind) && isBlock(func.body) && func.body.statements.length === 1) { + else if ( + refactorKindBeginsWith(removeBracesAction.kind, kind) && isBlock(func.body) && func.body.statements.length === 1 + ) { const firstStatement = first(func.body.statements); if (isReturnStatement(firstStatement)) { return { func, addBraces: false, expression: firstStatement.expression, returnStatement: firstStatement }; diff --git a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts index 414ef006bc926..e15423f2ea44d 100644 --- a/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts +++ b/src/services/refactors/convertArrowFunctionOrFunctionExpression.ts @@ -80,10 +80,10 @@ registerRefactor(refactorName, { kinds: [ toAnonymousFunctionAction.kind, toNamedFunctionAction.kind, - toArrowFunctionAction.kind + toArrowFunctionAction.kind, ], getEditsForAction: getRefactorEditsToConvertFunctionExpressions, - getAvailableActions: getRefactorActionsToConvertFunctionExpressions + getAvailableActions: getRefactorActionsToConvertFunctionExpressions, }); interface FunctionInfo { @@ -107,8 +107,8 @@ function getRefactorActionsToConvertFunctionExpressions(context: RefactorContext const possibleActions: RefactorActionInfo[] = []; const errors: RefactorActionInfo[] = []; if (refactorKindBeginsWith(toNamedFunctionAction.kind, kind)) { - const error = selectedVariableDeclaration || (isArrowFunction(func) && isVariableDeclaration(func.parent)) ? - undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_named_function); + const error = selectedVariableDeclaration || (isArrowFunction(func) && isVariableDeclaration(func.parent)) + ? undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_named_function); if (error) { errors.push({ ...toNamedFunctionAction, notApplicableReason: error }); } @@ -118,8 +118,8 @@ function getRefactorActionsToConvertFunctionExpressions(context: RefactorContext } if (refactorKindBeginsWith(toAnonymousFunctionAction.kind, kind)) { - const error = !selectedVariableDeclaration && isArrowFunction(func) ? - undefined: getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_anonymous_function); + const error = !selectedVariableDeclaration && isArrowFunction(func) + ? undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_anonymous_function); if (error) { errors.push({ ...toAnonymousFunctionAction, notApplicableReason: error }); } @@ -129,7 +129,8 @@ function getRefactorActionsToConvertFunctionExpressions(context: RefactorContext } if (refactorKindBeginsWith(toArrowFunctionAction.kind, kind)) { - const error = isFunctionExpression(func) ? undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_arrow_function); + const error = isFunctionExpression(func) ? undefined + : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_arrow_function); if (error) { errors.push({ ...toArrowFunctionAction, notApplicableReason: error }); } @@ -141,12 +142,15 @@ function getRefactorActionsToConvertFunctionExpressions(context: RefactorContext return [{ name: refactorName, description: refactorDescription, - actions: possibleActions.length === 0 && context.preferences.provideRefactorNotApplicableReason ? - errors : possibleActions + actions: possibleActions.length === 0 && context.preferences.provideRefactorNotApplicableReason + ? errors : possibleActions, }]; } -function getRefactorEditsToConvertFunctionExpressions(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { +function getRefactorEditsToConvertFunctionExpressions( + context: RefactorContext, + actionName: string, +): RefactorEditInfo | undefined { const { file, startPosition, program } = context; const info = getFunctionInfo(file, startPosition, program); @@ -181,7 +185,6 @@ function getRefactorEditsToConvertFunctionExpressions(context: RefactorContext, function containingThis(node: Node): boolean { let containsThis = false; node.forEachChild(function checkThis(child) { - if (isThis(child)) { containsThis = true; return; @@ -205,13 +208,15 @@ function getFunctionInfo(file: SourceFile, startPosition: number, program: Progr const maybeFunc = getContainingFunction(token); if ( - maybeFunc && - (isFunctionExpression(maybeFunc) || isArrowFunction(maybeFunc)) && - !rangeContainsRange(maybeFunc.body, token) && - !containingThis(maybeFunc.body) && - !typeChecker.containsArgumentsReference(maybeFunc) + maybeFunc + && (isFunctionExpression(maybeFunc) || isArrowFunction(maybeFunc)) + && !rangeContainsRange(maybeFunc.body, token) + && !containingThis(maybeFunc.body) + && !typeChecker.containsArgumentsReference(maybeFunc) ) { - if (isFunctionExpression(maybeFunc) && isFunctionReferencedInFile(file, typeChecker, maybeFunc)) return undefined; + if (isFunctionExpression(maybeFunc) && isFunctionReferencedInFile(file, typeChecker, maybeFunc)) { + return undefined; + } return { selectedVariableDeclaration: false, func: maybeFunc }; } @@ -222,13 +227,21 @@ function isSingleVariableDeclaration(parent: Node): parent is VariableDeclaratio return isVariableDeclaration(parent) || (isVariableDeclarationList(parent) && parent.declarations.length === 1); } -function tryGetFunctionFromVariableDeclaration(sourceFile: SourceFile, typeChecker: TypeChecker, parent: Node): ArrowFunction | FunctionExpression | undefined { +function tryGetFunctionFromVariableDeclaration( + sourceFile: SourceFile, + typeChecker: TypeChecker, + parent: Node, +): ArrowFunction | FunctionExpression | undefined { if (!isSingleVariableDeclaration(parent)) { return undefined; } const variableDeclaration = isVariableDeclaration(parent) ? parent : first(parent.declarations); const initializer = variableDeclaration.initializer; - if (initializer && (isArrowFunction(initializer) || isFunctionExpression(initializer) && !isFunctionReferencedInFile(sourceFile, typeChecker, initializer))) { + if ( + initializer + && (isArrowFunction(initializer) + || isFunctionExpression(initializer) && !isFunctionReferencedInFile(sourceFile, typeChecker, initializer)) + ) { return initializer; } return undefined; @@ -240,7 +253,13 @@ function convertToBlock(body: ConciseBody): Block { const file = body.getSourceFile(); setTextRange(returnStatement, body); suppressLeadingAndTrailingTrivia(returnStatement); - copyTrailingAsLeadingComments(body, returnStatement, file, /*commentKind*/ undefined, /*hasTrailingNewLine*/ true); + copyTrailingAsLeadingComments( + body, + returnStatement, + file, + /*commentKind*/ undefined, + /*hasTrailingNewLine*/ true, + ); return factory.createBlock([returnStatement], /*multiLine*/ true); } else { @@ -250,32 +269,61 @@ function convertToBlock(body: ConciseBody): Block { function getVariableInfo(func: FunctionExpression | ArrowFunction): VariableInfo | undefined { const variableDeclaration = func.parent; - if (!isVariableDeclaration(variableDeclaration) || !isVariableDeclarationInVariableStatement(variableDeclaration)) return undefined; + if (!isVariableDeclaration(variableDeclaration) || !isVariableDeclarationInVariableStatement(variableDeclaration)) { + return undefined; + } const variableDeclarationList = variableDeclaration.parent; const statement = variableDeclarationList.parent; - if (!isVariableDeclarationList(variableDeclarationList) || !isVariableStatement(statement) || !isIdentifier(variableDeclaration.name)) return undefined; + if ( + !isVariableDeclarationList(variableDeclarationList) || !isVariableStatement(statement) + || !isIdentifier(variableDeclaration.name) + ) return undefined; return { variableDeclaration, variableDeclarationList, statement, name: variableDeclaration.name }; } -function getEditInfoForConvertToAnonymousFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction): FileTextChanges[] { +function getEditInfoForConvertToAnonymousFunction( + context: RefactorContext, + func: FunctionExpression | ArrowFunction, +): FileTextChanges[] { const { file } = context; const body = convertToBlock(func.body); - const newNode = factory.createFunctionExpression(func.modifiers, func.asteriskToken, /*name*/ undefined, func.typeParameters, func.parameters, func.type, body); + const newNode = factory.createFunctionExpression( + func.modifiers, + func.asteriskToken, + /*name*/ undefined, + func.typeParameters, + func.parameters, + func.type, + body, + ); return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode)); } -function getEditInfoForConvertToNamedFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction, variableInfo: VariableInfo): FileTextChanges[] { +function getEditInfoForConvertToNamedFunction( + context: RefactorContext, + func: FunctionExpression | ArrowFunction, + variableInfo: VariableInfo, +): FileTextChanges[] { const { file } = context; const body = convertToBlock(func.body); const { variableDeclaration, variableDeclarationList, statement, name } = variableInfo; suppressLeadingTrivia(statement); - const modifiersFlags = (getCombinedModifierFlags(variableDeclaration) & ModifierFlags.Export) | getEffectiveModifierFlags(func); + const modifiersFlags = (getCombinedModifierFlags(variableDeclaration) & ModifierFlags.Export) + | getEffectiveModifierFlags(func); const modifiers = factory.createModifiersFromModifierFlags(modifiersFlags); - const newNode = factory.createFunctionDeclaration(length(modifiers) ? modifiers : undefined, func.asteriskToken, name, func.typeParameters, func.parameters, func.type, body); + const newNode = factory.createFunctionDeclaration( + length(modifiers) ? modifiers : undefined, + func.asteriskToken, + name, + func.typeParameters, + func.parameters, + func.type, + body, + ); if (variableDeclarationList.declarations.length === 1) { return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, statement, newNode)); @@ -303,14 +351,25 @@ function getEditInfoForConvertToArrowFunction(context: RefactorContext, func: Fu body = func.body; } - const newNode = factory.createArrowFunction(func.modifiers, func.typeParameters, func.parameters, func.type, factory.createToken(SyntaxKind.EqualsGreaterThanToken), body); + const newNode = factory.createArrowFunction( + func.modifiers, + func.typeParameters, + func.parameters, + func.type, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + body, + ); return textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode)); } function canBeConvertedToExpression(body: Block, head: Statement): head is ReturnStatement { - return body.statements.length === 1 && ((isReturnStatement(head) && !!head.expression)); + return body.statements.length === 1 && (isReturnStatement(head) && !!head.expression); } -function isFunctionReferencedInFile(sourceFile: SourceFile, typeChecker: TypeChecker, node: FunctionExpression): boolean { +function isFunctionReferencedInFile( + sourceFile: SourceFile, + typeChecker: TypeChecker, + node: FunctionExpression, +): boolean { return !!node.name && FindAllReferences.Core.isSymbolReferencedInFile(node.name, typeChecker, sourceFile); } diff --git a/src/services/refactors/convertExport.ts b/src/services/refactors/convertExport.ts index 0509e1e0c512b..0c94751233c05 100644 --- a/src/services/refactors/convertExport.ts +++ b/src/services/refactors/convertExport.ts @@ -62,20 +62,22 @@ const refactorName = "Convert export"; const defaultToNamedAction = { name: "Convert default export to named export", description: getLocaleSpecificMessage(Diagnostics.Convert_default_export_to_named_export), - kind: "refactor.rewrite.export.named" + kind: "refactor.rewrite.export.named", }; const namedToDefaultAction = { name: "Convert named export to default export", description: getLocaleSpecificMessage(Diagnostics.Convert_named_export_to_default_export), - kind: "refactor.rewrite.export.default" + kind: "refactor.rewrite.export.default", }; registerRefactor(refactorName, { kinds: [ defaultToNamedAction.kind, - namedToDefaultAction.kind + namedToDefaultAction.kind, ], - getAvailableActions: function getRefactorActionsToConvertBetweenNamedAndDefaultExports(context): readonly ApplicableRefactorInfo[] { + getAvailableActions: function getRefactorActionsToConvertBetweenNamedAndDefaultExports( + context, + ): readonly ApplicableRefactorInfo[] { const info = getInfo(context, context.triggerReason === "invoked"); if (!info) return emptyArray; @@ -86,26 +88,47 @@ registerRefactor(refactorName, { if (context.preferences.provideRefactorNotApplicableReason) { return [ - { name: refactorName, description: getLocaleSpecificMessage(Diagnostics.Convert_default_export_to_named_export), actions: [ - { ...defaultToNamedAction, notApplicableReason: info.error }, - { ...namedToDefaultAction, notApplicableReason: info.error }, - ]} + { + name: refactorName, + description: getLocaleSpecificMessage(Diagnostics.Convert_default_export_to_named_export), + actions: [ + { ...defaultToNamedAction, notApplicableReason: info.error }, + { ...namedToDefaultAction, notApplicableReason: info.error }, + ], + }, ]; } return emptyArray; }, - getEditsForAction: function getRefactorEditsToConvertBetweenNamedAndDefaultExports(context, actionName): RefactorEditInfo { - Debug.assert(actionName === defaultToNamedAction.name || actionName === namedToDefaultAction.name, "Unexpected action name"); + getEditsForAction: function getRefactorEditsToConvertBetweenNamedAndDefaultExports( + context, + actionName, + ): RefactorEditInfo { + Debug.assert( + actionName === defaultToNamedAction.name || actionName === namedToDefaultAction.name, + "Unexpected action name", + ); const info = getInfo(context); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, info, t, context.cancellationToken)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, context.program, info, t, context.cancellationToken), + ); return { edits, renameFilename: undefined, renameLocation: undefined }; }, }); // If a VariableStatement, will have exactly one VariableDeclaration, with an Identifier for a name. -type ExportToConvert = FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | NamespaceDeclaration | TypeAliasDeclaration | VariableStatement | ExportAssignment; +type ExportToConvert = + | FunctionDeclaration + | ClassDeclaration + | InterfaceDeclaration + | EnumDeclaration + | NamespaceDeclaration + | TypeAliasDeclaration + | VariableStatement + | ExportAssignment; interface ExportInfo { readonly exportNode: ExportToConvert; readonly exportName: Identifier; // This is exportNode.name except for VariableStatement_s. @@ -117,24 +140,34 @@ function getInfo(context: RefactorContext, considerPartialSpans = true): ExportI const { file, program } = context; const span = getRefactorContextSpan(context); const token = getTokenAtPosition(file, span.start); - const exportNode = !!(token.parent && getSyntacticModifierFlags(token.parent) & ModifierFlags.Export) && considerPartialSpans ? token.parent : getParentNodeInSpan(token, file, span); - if (!exportNode || (!isSourceFile(exportNode.parent) && !(isModuleBlock(exportNode.parent) && isAmbientModule(exportNode.parent.parent)))) { + const exportNode = + !!(token.parent && getSyntacticModifierFlags(token.parent) & ModifierFlags.Export) && considerPartialSpans + ? token.parent : getParentNodeInSpan(token, file, span); + if ( + !exportNode + || (!isSourceFile(exportNode.parent) + && !(isModuleBlock(exportNode.parent) && isAmbientModule(exportNode.parent.parent))) + ) { return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_export_statement) }; } const checker = program.getTypeChecker(); const exportingModuleSymbol = getExportingModuleSymbol(exportNode.parent, checker); - const flags = getSyntacticModifierFlags(exportNode) || ((isExportAssignment(exportNode) && !exportNode.isExportEquals) ? ModifierFlags.ExportDefault : ModifierFlags.None); + const flags = getSyntacticModifierFlags(exportNode) + || ((isExportAssignment(exportNode) && !exportNode.isExportEquals) ? ModifierFlags.ExportDefault + : ModifierFlags.None); const wasDefault = !!(flags & ModifierFlags.Default); // If source file already has a default export, don't offer refactor. - if (!(flags & ModifierFlags.Export) || !wasDefault && exportingModuleSymbol.exports!.has(InternalSymbolName.Default)) { + if ( + !(flags & ModifierFlags.Export) || !wasDefault && exportingModuleSymbol.exports!.has(InternalSymbolName.Default) + ) { return { error: getLocaleSpecificMessage(Diagnostics.This_file_already_has_a_default_export) }; } const noSymbolError = (id: Node) => (isIdentifier(id) && checker.getSymbolAtLocation(id)) ? undefined - : { error: getLocaleSpecificMessage(Diagnostics.Can_only_convert_named_export) }; + : { error: getLocaleSpecificMessage(Diagnostics.Can_only_convert_named_export) }; switch (exportNode.kind) { case SyntaxKind.FunctionDeclaration: @@ -143,7 +176,13 @@ function getInfo(context: RefactorContext, considerPartialSpans = true): ExportI case SyntaxKind.EnumDeclaration: case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.ModuleDeclaration: { - const node = exportNode as FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | TypeAliasDeclaration | NamespaceDeclaration; + const node = exportNode as + | FunctionDeclaration + | ClassDeclaration + | InterfaceDeclaration + | EnumDeclaration + | TypeAliasDeclaration + | NamespaceDeclaration; if (!node.name) return undefined; return noSymbolError(node.name) || { exportNode: node, exportName: node.name, wasDefault, exportingModuleSymbol }; @@ -171,36 +210,77 @@ function getInfo(context: RefactorContext, considerPartialSpans = true): ExportI } } -function doChange(exportingSourceFile: SourceFile, program: Program, info: ExportInfo, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void { +function doChange( + exportingSourceFile: SourceFile, + program: Program, + info: ExportInfo, + changes: textChanges.ChangeTracker, + cancellationToken: CancellationToken | undefined, +): void { changeExport(exportingSourceFile, info, changes, program.getTypeChecker()); changeImports(program, info, changes, cancellationToken); } -function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, exportName }: ExportInfo, changes: textChanges.ChangeTracker, checker: TypeChecker): void { +function changeExport( + exportingSourceFile: SourceFile, + { wasDefault, exportNode, exportName }: ExportInfo, + changes: textChanges.ChangeTracker, + checker: TypeChecker, +): void { if (wasDefault) { if (isExportAssignment(exportNode) && !exportNode.isExportEquals) { const exp = exportNode.expression as Identifier; const spec = makeExportSpecifier(exp.text, exp.text); - changes.replaceNode(exportingSourceFile, exportNode, factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports([spec]))); + changes.replaceNode( + exportingSourceFile, + exportNode, + factory.createExportDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + factory.createNamedExports([spec]), + ), + ); } else { - changes.delete(exportingSourceFile, Debug.checkDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword), "Should find a default keyword in modifier list")); + changes.delete( + exportingSourceFile, + Debug.checkDefined( + findModifier(exportNode, SyntaxKind.DefaultKeyword), + "Should find a default keyword in modifier list", + ), + ); } } else { - const exportKeyword = Debug.checkDefined(findModifier(exportNode, SyntaxKind.ExportKeyword), "Should find an export keyword in modifier list"); + const exportKeyword = Debug.checkDefined( + findModifier(exportNode, SyntaxKind.ExportKeyword), + "Should find an export keyword in modifier list", + ); switch (exportNode.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: - changes.insertNodeAfter(exportingSourceFile, exportKeyword, factory.createToken(SyntaxKind.DefaultKeyword)); + changes.insertNodeAfter( + exportingSourceFile, + exportKeyword, + factory.createToken(SyntaxKind.DefaultKeyword), + ); break; case SyntaxKind.VariableStatement: // If 'x' isn't used in this file and doesn't have type definition, `export const x = 0;` --> `export default 0;` const decl = first(exportNode.declarationList.declarations); - if (!FindAllReferences.Core.isSymbolReferencedInFile(exportName, checker, exportingSourceFile) && !decl.type) { + if ( + !FindAllReferences.Core.isSymbolReferencedInFile(exportName, checker, exportingSourceFile) + && !decl.type + ) { // We checked in `getInfo` that an initializer exists. - changes.replaceNode(exportingSourceFile, exportNode, factory.createExportDefault(Debug.checkDefined(decl.initializer, "Initializer was previously known to be present"))); + changes.replaceNode( + exportingSourceFile, + exportNode, + factory.createExportDefault( + Debug.checkDefined(decl.initializer, "Initializer was previously known to be present"), + ), + ); break; } // falls through @@ -209,7 +289,11 @@ function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, case SyntaxKind.ModuleDeclaration: // `export type T = number;` -> `type T = number; export default T;` changes.deleteModifier(exportingSourceFile, exportKeyword); - changes.insertNodeAfter(exportingSourceFile, exportNode, factory.createExportDefault(factory.createIdentifier(exportName.text))); + changes.insertNodeAfter( + exportingSourceFile, + exportNode, + factory.createExportDefault(factory.createIdentifier(exportName.text)), + ); break; default: Debug.fail(`Unexpected exportNode kind ${(exportNode as ExportToConvert).kind}`); @@ -217,22 +301,44 @@ function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, } } -function changeImports(program: Program, { wasDefault, exportName, exportingModuleSymbol }: ExportInfo, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void { +function changeImports( + program: Program, + { wasDefault, exportName, exportingModuleSymbol }: ExportInfo, + changes: textChanges.ChangeTracker, + cancellationToken: CancellationToken | undefined, +): void { const checker = program.getTypeChecker(); - const exportSymbol = Debug.checkDefined(checker.getSymbolAtLocation(exportName), "Export name should resolve to a symbol"); - FindAllReferences.Core.eachExportReference(program.getSourceFiles(), checker, cancellationToken, exportSymbol, exportingModuleSymbol, exportName.text, wasDefault, ref => { - if (exportName === ref) return; - const importingSourceFile = ref.getSourceFile(); - if (wasDefault) { - changeDefaultToNamedImport(importingSourceFile, ref, changes, exportName.text); - } - else { - changeNamedToDefaultImport(importingSourceFile, ref, changes); - } - }); + const exportSymbol = Debug.checkDefined( + checker.getSymbolAtLocation(exportName), + "Export name should resolve to a symbol", + ); + FindAllReferences.Core.eachExportReference( + program.getSourceFiles(), + checker, + cancellationToken, + exportSymbol, + exportingModuleSymbol, + exportName.text, + wasDefault, + ref => { + if (exportName === ref) return; + const importingSourceFile = ref.getSourceFile(); + if (wasDefault) { + changeDefaultToNamedImport(importingSourceFile, ref, changes, exportName.text); + } + else { + changeNamedToDefaultImport(importingSourceFile, ref, changes); + } + }, + ); } -function changeDefaultToNamedImport(importingSourceFile: SourceFile, ref: Identifier, changes: textChanges.ChangeTracker, exportName: string): void { +function changeDefaultToNamedImport( + importingSourceFile: SourceFile, + ref: Identifier, + changes: textChanges.ChangeTracker, + exportName: string, +): void { const { parent } = ref; switch (parent.kind) { case SyntaxKind.PropertyAccessExpression: @@ -257,9 +363,19 @@ function changeDefaultToNamedImport(importingSourceFile: SourceFile, ref: Identi } else if (namedBindings.kind === SyntaxKind.NamespaceImport) { // `import foo, * as a from "./a";` --> `import * as a from ".a/"; import { foo } from "./a";` - changes.deleteRange(importingSourceFile, { pos: ref.getStart(importingSourceFile), end: namedBindings.getStart(importingSourceFile) }); - const quotePreference = isStringLiteral(clause.parent.moduleSpecifier) ? quotePreferenceFromString(clause.parent.moduleSpecifier, importingSourceFile) : QuotePreference.Double; - const newImport = makeImport(/*defaultImport*/ undefined, [makeImportSpecifier(exportName, ref.text)], clause.parent.moduleSpecifier, quotePreference); + changes.deleteRange(importingSourceFile, { + pos: ref.getStart(importingSourceFile), + end: namedBindings.getStart(importingSourceFile), + }); + const quotePreference = isStringLiteral(clause.parent.moduleSpecifier) + ? quotePreferenceFromString(clause.parent.moduleSpecifier, importingSourceFile) + : QuotePreference.Double; + const newImport = makeImport( + /*defaultImport*/ undefined, + [makeImportSpecifier(exportName, ref.text)], + clause.parent.moduleSpecifier, + quotePreference, + ); changes.insertNodeAfter(importingSourceFile, clause.parent, newImport); } else { @@ -271,14 +387,28 @@ function changeDefaultToNamedImport(importingSourceFile: SourceFile, ref: Identi } case SyntaxKind.ImportType: const importTypeNode = parent as ImportTypeNode; - changes.replaceNode(importingSourceFile, parent, factory.createImportTypeNode(importTypeNode.argument, importTypeNode.assertions, factory.createIdentifier(exportName), importTypeNode.typeArguments, importTypeNode.isTypeOf)); + changes.replaceNode( + importingSourceFile, + parent, + factory.createImportTypeNode( + importTypeNode.argument, + importTypeNode.assertions, + factory.createIdentifier(exportName), + importTypeNode.typeArguments, + importTypeNode.isTypeOf, + ), + ); break; default: Debug.failBadSyntaxKind(parent); } } -function changeNamedToDefaultImport(importingSourceFile: SourceFile, ref: Identifier, changes: textChanges.ChangeTracker): void { +function changeNamedToDefaultImport( + importingSourceFile: SourceFile, + ref: Identifier, + changes: textChanges.ChangeTracker, +): void { const parent = ref.parent as PropertyAccessExpression | ImportSpecifier | ExportSpecifier; switch (parent.kind) { case SyntaxKind.PropertyAccessExpression: @@ -309,15 +439,22 @@ function changeNamedToDefaultImport(importingSourceFile: SourceFile, ref: Identi default: Debug.assertNever(parent, `Unexpected parent kind ${(parent as Node).kind}`); } - } function makeImportSpecifier(propertyName: string, name: string): ImportSpecifier { - return factory.createImportSpecifier(/*isTypeOnly*/ false, propertyName === name ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(name)); + return factory.createImportSpecifier( + /*isTypeOnly*/ false, + propertyName === name ? undefined : factory.createIdentifier(propertyName), + factory.createIdentifier(name), + ); } function makeExportSpecifier(propertyName: string, name: string): ExportSpecifier { - return factory.createExportSpecifier(/*isTypeOnly*/ false, propertyName === name ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(name)); + return factory.createExportSpecifier( + /*isTypeOnly*/ false, + propertyName === name ? undefined : factory.createIdentifier(propertyName), + factory.createIdentifier(name), + ); } function getExportingModuleSymbol(parent: SourceFile | ModuleBlock, checker: TypeChecker) { diff --git a/src/services/refactors/convertImport.ts b/src/services/refactors/convertImport.ts index 319487ddb1968..dfa5e7ff8c660 100644 --- a/src/services/refactors/convertImport.ts +++ b/src/services/refactors/convertImport.ts @@ -72,7 +72,9 @@ const actions = { registerRefactor(refactorName, { kinds: getOwnValues(actions).map(a => a.kind), - getAvailableActions: function getRefactorActionsToConvertBetweenNamedAndNamespacedImports(context): readonly ApplicableRefactorInfo[] { + getAvailableActions: function getRefactorActionsToConvertBetweenNamedAndNamespacedImports( + context, + ): readonly ApplicableRefactorInfo[] { const info = getImportConversionInfo(context, context.triggerReason === "invoked"); if (!info) return emptyArray; @@ -85,32 +87,39 @@ registerRefactor(refactorName, { return getOwnValues(actions).map(action => ({ name: refactorName, description: action.description, - actions: [{ ...action, notApplicableReason: info.error }] + actions: [{ ...action, notApplicableReason: info.error }], })); } return emptyArray; }, - getEditsForAction: function getRefactorEditsToConvertBetweenNamedAndNamespacedImports(context, actionName): RefactorEditInfo { + getEditsForAction: function getRefactorEditsToConvertBetweenNamedAndNamespacedImports( + context, + actionName, + ): RefactorEditInfo { Debug.assert(some(getOwnValues(actions), action => action.name === actionName), "Unexpected action name"); const info = getImportConversionInfo(context); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, t, info)); return { edits, renameFilename: undefined, renameLocation: undefined }; - } + }, }); // Can convert imports of the form `import * as m from "m";` or `import d, { x, y } from "m";`. type ImportConversionInfo = - | { convertTo: ImportKind.Default, import: NamedImports } - | { convertTo: ImportKind.Namespace, import: NamedImports } - | { convertTo: ImportKind.Named, import: NamespaceImport }; + | { convertTo: ImportKind.Default; import: NamedImports; } + | { convertTo: ImportKind.Namespace; import: NamedImports; } + | { convertTo: ImportKind.Named; import: NamespaceImport; }; -function getImportConversionInfo(context: RefactorContext, considerPartialSpans = true): ImportConversionInfo | RefactorErrorInfo | undefined { +function getImportConversionInfo( + context: RefactorContext, + considerPartialSpans = true, +): ImportConversionInfo | RefactorErrorInfo | undefined { const { file } = context; const span = getRefactorContextSpan(context); const token = getTokenAtPosition(file, span.start); - const importDecl = considerPartialSpans ? findAncestor(token, isImportDeclaration) : getParentNodeInSpan(token, file, span); + const importDecl = considerPartialSpans ? findAncestor(token, isImportDeclaration) + : getParentNodeInSpan(token, file, span); if (!importDecl || !isImportDeclaration(importDecl)) return { error: "Selection is not an import declaration." }; const end = span.start + span.length; @@ -141,17 +150,40 @@ function getShouldUseDefault(program: Program, importClause: ImportClause) { && isExportEqualsModule(importClause.parent.moduleSpecifier, program.getTypeChecker()); } -function doChange(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, info: ImportConversionInfo): void { +function doChange( + sourceFile: SourceFile, + program: Program, + changes: textChanges.ChangeTracker, + info: ImportConversionInfo, +): void { const checker = program.getTypeChecker(); if (info.convertTo === ImportKind.Named) { - doChangeNamespaceToNamed(sourceFile, checker, changes, info.import, getAllowSyntheticDefaultImports(program.getCompilerOptions())); + doChangeNamespaceToNamed( + sourceFile, + checker, + changes, + info.import, + getAllowSyntheticDefaultImports(program.getCompilerOptions()), + ); } else { - doChangeNamedToNamespaceOrDefault(sourceFile, program, changes, info.import, info.convertTo === ImportKind.Default); + doChangeNamedToNamespaceOrDefault( + sourceFile, + program, + changes, + info.import, + info.convertTo === ImportKind.Default, + ); } } -function doChangeNamespaceToNamed(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, toConvert: NamespaceImport, allowSyntheticDefaultImports: boolean): void { +function doChangeNamespaceToNamed( + sourceFile: SourceFile, + checker: TypeChecker, + changes: textChanges.ChangeTracker, + toConvert: NamespaceImport, + allowSyntheticDefaultImports: boolean, +): void { let usedAsNamespaceOrDefault = false; const nodesToReplace: (PropertyAccessExpression | QualifiedName)[] = []; @@ -178,36 +210,69 @@ function doChangeNamespaceToNamed(sourceFile: SourceFile, checker: TypeChecker, const exportName = getRightOfPropertyAccessOrQualifiedName(propertyAccessOrQualifiedName).text; let importName = exportNameToImportName.get(exportName); if (importName === undefined) { - exportNameToImportName.set(exportName, importName = conflictingNames.has(exportName) ? getUniqueName(exportName, sourceFile) : exportName); + exportNameToImportName.set( + exportName, + importName = conflictingNames.has(exportName) ? getUniqueName(exportName, sourceFile) : exportName, + ); } changes.replaceNode(sourceFile, propertyAccessOrQualifiedName, factory.createIdentifier(importName)); } const importSpecifiers: ImportSpecifier[] = []; exportNameToImportName.forEach((name, propertyName) => { - importSpecifiers.push(factory.createImportSpecifier(/*isTypeOnly*/ false, name === propertyName ? undefined : factory.createIdentifier(propertyName), factory.createIdentifier(name))); + importSpecifiers.push( + factory.createImportSpecifier( + /*isTypeOnly*/ false, + name === propertyName ? undefined : factory.createIdentifier(propertyName), + factory.createIdentifier(name), + ), + ); }); const importDecl = toConvert.parent.parent; if (usedAsNamespaceOrDefault && !allowSyntheticDefaultImports) { // Need to leave the namespace import alone - changes.insertNodeAfter(sourceFile, importDecl, updateImport(importDecl, /*defaultImportName*/ undefined, importSpecifiers)); + changes.insertNodeAfter( + sourceFile, + importDecl, + updateImport(importDecl, /*defaultImportName*/ undefined, importSpecifiers), + ); } else { - changes.replaceNode(sourceFile, importDecl, updateImport(importDecl, usedAsNamespaceOrDefault ? factory.createIdentifier(toConvert.name.text) : undefined, importSpecifiers)); + changes.replaceNode( + sourceFile, + importDecl, + updateImport( + importDecl, + usedAsNamespaceOrDefault ? factory.createIdentifier(toConvert.name.text) : undefined, + importSpecifiers, + ), + ); } } -function getRightOfPropertyAccessOrQualifiedName(propertyAccessOrQualifiedName: PropertyAccessExpression | QualifiedName) { - return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.name : propertyAccessOrQualifiedName.right; +function getRightOfPropertyAccessOrQualifiedName( + propertyAccessOrQualifiedName: PropertyAccessExpression | QualifiedName, +) { + return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.name + : propertyAccessOrQualifiedName.right; } -function getLeftOfPropertyAccessOrQualifiedName(propertyAccessOrQualifiedName: PropertyAccessExpression | QualifiedName) { - return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.expression : propertyAccessOrQualifiedName.left; +function getLeftOfPropertyAccessOrQualifiedName( + propertyAccessOrQualifiedName: PropertyAccessExpression | QualifiedName, +) { + return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.expression + : propertyAccessOrQualifiedName.left; } /** @internal */ -export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, toConvert: NamedImports, shouldUseDefault = getShouldUseDefault(program, toConvert.parent)): void { +export function doChangeNamedToNamespaceOrDefault( + sourceFile: SourceFile, + program: Program, + changes: textChanges.ChangeTracker, + toConvert: NamedImports, + shouldUseDefault = getShouldUseDefault(program, toConvert.parent), +): void { const checker = program.getTypeChecker(); const importDecl = toConvert.parent.parent; const { moduleSpecifier } = importDecl; @@ -219,7 +284,8 @@ export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, progra toConvertSymbols.add(symbol); } }); - const preferredName = moduleSpecifier && isStringLiteral(moduleSpecifier) ? codefix.moduleSpecifierToValidIdentifier(moduleSpecifier.text, ScriptTarget.ESNext) : "module"; + const preferredName = moduleSpecifier && isStringLiteral(moduleSpecifier) + ? codefix.moduleSpecifierToValidIdentifier(moduleSpecifier.text, ScriptTarget.ESNext) : "module"; function hasNamespaceNameConflict(namedImport: ImportSpecifier): boolean { // We need to check if the preferred namespace name (`preferredName`) we'd like to use in the refactored code will present a name conflict. // A name conflict means that, in a scope where we would like to use the preferred namespace name, there already exists a symbol with that name in that scope. @@ -246,7 +312,10 @@ export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, progra for (const element of toConvert.elements) { const propertyName = (element.propertyName || element.name).text; FindAllReferences.Core.eachSymbolReferenceInFile(element.name, checker, sourceFile, id => { - const access = factory.createPropertyAccessExpression(factory.createIdentifier(namespaceImportName), propertyName); + const access = factory.createPropertyAccessExpression( + factory.createIdentifier(namespaceImportName), + propertyName, + ); if (isShorthandPropertyAssignment(id.parent)) { changes.replaceNode(sourceFile, id.parent, factory.createPropertyAssignment(id.text, access)); } @@ -259,13 +328,28 @@ export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, progra }); } - changes.replaceNode(sourceFile, toConvert, shouldUseDefault - ? factory.createIdentifier(namespaceImportName) - : factory.createNamespaceImport(factory.createIdentifier(namespaceImportName))); + changes.replaceNode( + sourceFile, + toConvert, + shouldUseDefault + ? factory.createIdentifier(namespaceImportName) + : factory.createNamespaceImport(factory.createIdentifier(namespaceImportName)), + ); if (neededNamedImports.size) { - const newNamedImports: ImportSpecifier[] = arrayFrom(neededNamedImports.values(), element => - factory.createImportSpecifier(element.isTypeOnly, element.propertyName && factory.createIdentifier(element.propertyName.text), factory.createIdentifier(element.name.text))); - changes.insertNodeAfter(sourceFile, toConvert.parent.parent, updateImport(importDecl, /*defaultImportName*/ undefined, newNamedImports)); + const newNamedImports: ImportSpecifier[] = arrayFrom( + neededNamedImports.values(), + element => + factory.createImportSpecifier( + element.isTypeOnly, + element.propertyName && factory.createIdentifier(element.propertyName.text), + factory.createIdentifier(element.name.text), + ), + ); + changes.insertNodeAfter( + sourceFile, + toConvert.parent.parent, + updateImport(importDecl, /*defaultImportName*/ undefined, newNamedImports), + ); } } @@ -276,7 +360,19 @@ function isExportEqualsModule(moduleSpecifier: Expression, checker: TypeChecker) return externalModule !== exportEquals; } -function updateImport(old: ImportDeclaration, defaultImportName: Identifier | undefined, elements: readonly ImportSpecifier[] | undefined): ImportDeclaration { - return factory.createImportDeclaration(/*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, elements && elements.length ? factory.createNamedImports(elements) : undefined), old.moduleSpecifier, /*assertClause*/ undefined); +function updateImport( + old: ImportDeclaration, + defaultImportName: Identifier | undefined, + elements: readonly ImportSpecifier[] | undefined, +): ImportDeclaration { + return factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause( + /*isTypeOnly*/ false, + defaultImportName, + elements && elements.length ? factory.createNamedImports(elements) : undefined, + ), + old.moduleSpecifier, + /*assertClause*/ undefined, + ); } diff --git a/src/services/refactors/convertOverloadListToSingleSignature.ts b/src/services/refactors/convertOverloadListToSingleSignature.ts index 1a54a297eb772..78b6cb6f29645 100644 --- a/src/services/refactors/convertOverloadListToSingleSignature.ts +++ b/src/services/refactors/convertOverloadListToSingleSignature.ts @@ -40,7 +40,9 @@ import { textChanges, TupleTypeNode, } from "../_namespaces/ts"; -import { registerRefactor } from "../_namespaces/ts.refactor"; +import { + registerRefactor, +} from "../_namespaces/ts.refactor"; const refactorName = "Convert overload list to single signature"; const refactorDescription = getLocaleSpecificMessage(Diagnostics.Convert_overload_list_to_single_signature); @@ -53,10 +55,12 @@ const functionOverloadAction = { registerRefactor(refactorName, { kinds: [functionOverloadAction.kind], getEditsForAction: getRefactorEditsToConvertOverloadsToOneSignature, - getAvailableActions: getRefactorActionsToConvertOverloadsToOneSignature + getAvailableActions: getRefactorActionsToConvertOverloadsToOneSignature, }); -function getRefactorActionsToConvertOverloadsToOneSignature(context: RefactorContext): readonly ApplicableRefactorInfo[] { +function getRefactorActionsToConvertOverloadsToOneSignature( + context: RefactorContext, +): readonly ApplicableRefactorInfo[] { const { file, startPosition, program } = context; const info = getConvertableOverloadListAtPosition(file, startPosition, program); if (!info) return emptyArray; @@ -64,7 +68,7 @@ function getRefactorActionsToConvertOverloadsToOneSignature(context: RefactorCon return [{ name: refactorName, description: refactorDescription, - actions: [functionOverloadAction] + actions: [functionOverloadAction], }]; } @@ -100,7 +104,7 @@ function getRefactorEditsToConvertOverloadsToOneSignature(context: RefactorConte lastDeclaration.typeParameters, getNewParametersForCombinedSignature(signatureDecls), lastDeclaration.type, - lastDeclaration.body + lastDeclaration.body, ); break; } @@ -118,7 +122,7 @@ function getRefactorEditsToConvertOverloadsToOneSignature(context: RefactorConte lastDeclaration, lastDeclaration.modifiers, getNewParametersForCombinedSignature(signatureDecls), - lastDeclaration.body + lastDeclaration.body, ); break; } @@ -140,11 +144,15 @@ function getRefactorEditsToConvertOverloadsToOneSignature(context: RefactorConte lastDeclaration.typeParameters, getNewParametersForCombinedSignature(signatureDecls), lastDeclaration.type, - lastDeclaration.body + lastDeclaration.body, ); break; } - default: return Debug.failBadSyntaxKind(lastDeclaration, "Unhandled signature kind in overload list conversion refactoring"); + default: + return Debug.failBadSyntaxKind( + lastDeclaration, + "Unhandled signature kind in overload list conversion refactoring", + ); } if (updated === lastDeclaration) { @@ -157,7 +165,16 @@ function getRefactorEditsToConvertOverloadsToOneSignature(context: RefactorConte return { renameFilename: undefined, renameLocation: undefined, edits }; - function getNewParametersForCombinedSignature(signatureDeclarations: (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[]): NodeArray { + function getNewParametersForCombinedSignature( + signatureDeclarations: ( + | MethodSignature + | MethodDeclaration + | CallSignatureDeclaration + | ConstructorDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration + )[], + ): NodeArray { const lastSig = signatureDeclarations[signatureDeclarations.length - 1]; if (isFunctionLikeDeclaration(lastSig) && lastSig.body) { // Trim away implementation signature arguments (they should already be compatible with overloads, but are likely less precise to guarantee compatability with the overloads) @@ -169,24 +186,38 @@ function getRefactorEditsToConvertOverloadsToOneSignature(context: RefactorConte factory.createToken(SyntaxKind.DotDotDotToken), "args", /*questionToken*/ undefined, - factory.createUnionTypeNode(map(signatureDeclarations, convertSignatureParametersToTuple)) - ) + factory.createUnionTypeNode(map(signatureDeclarations, convertSignatureParametersToTuple)), + ), ]); } - function convertSignatureParametersToTuple(decl: MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration): TupleTypeNode { + function convertSignatureParametersToTuple( + decl: + | MethodSignature + | MethodDeclaration + | CallSignatureDeclaration + | ConstructorDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration, + ): TupleTypeNode { const members = map(decl.parameters, convertParameterToNamedTupleMember); - return setEmitFlags(factory.createTupleTypeNode(members), some(members, m => !!length(getSyntheticLeadingComments(m))) ? EmitFlags.None : EmitFlags.SingleLine); + return setEmitFlags( + factory.createTupleTypeNode(members), + some(members, m => !!length(getSyntheticLeadingComments(m))) ? EmitFlags.None : EmitFlags.SingleLine, + ); } function convertParameterToNamedTupleMember(p: ParameterDeclaration): NamedTupleMember { Debug.assert(isIdentifier(p.name)); // This is checked during refactoring applicability checking - const result = setTextRange(factory.createNamedTupleMember( - p.dotDotDotToken, - p.name, - p.questionToken, - p.type || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) - ), p); + const result = setTextRange( + factory.createNamedTupleMember( + p.dotDotDotToken, + p.name, + p.questionToken, + p.type || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword), + ), + p, + ); const parameterDocComment = p.symbol && p.symbol.getDocumentationComment(checker); if (parameterDocComment) { const newComment = displayPartsToString(parameterDocComment); @@ -205,10 +236,18 @@ ${newComment.split("\n").map(c => ` * ${c}`).join("\n")} } return result; } - } -function isConvertableSignatureDeclaration(d: Node): d is MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration { +function isConvertableSignatureDeclaration( + d: Node, +): d is + | MethodSignature + | MethodDeclaration + | CallSignatureDeclaration + | ConstructorDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration +{ switch (d.kind) { case SyntaxKind.MethodSignature: case SyntaxKind.MethodDeclaration: @@ -227,7 +266,10 @@ function getConvertableOverloadListAtPosition(file: SourceFile, startPosition: n if (!containingDecl) { return; } - if (isFunctionLikeDeclaration(containingDecl) && containingDecl.body && rangeContainsPosition(containingDecl.body, startPosition)) { + if ( + isFunctionLikeDeclaration(containingDecl) && containingDecl.body + && rangeContainsPosition(containingDecl.body, startPosition) + ) { return; } @@ -250,8 +292,17 @@ function getConvertableOverloadListAtPosition(file: SourceFile, startPosition: n if (!every(decls, d => d.kind === kindOne)) { return; } - const signatureDecls = decls as (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[]; - if (some(signatureDecls, d => !!d.typeParameters || some(d.parameters, p => !!p.modifiers || !isIdentifier(p.name)))) { + const signatureDecls = decls as ( + | MethodSignature + | MethodDeclaration + | CallSignatureDeclaration + | ConstructorDeclaration + | ConstructSignatureDeclaration + | FunctionDeclaration + )[]; + if ( + some(signatureDecls, d => !!d.typeParameters || some(d.parameters, p => !!p.modifiers || !isIdentifier(p.name))) + ) { return; } const signatures = mapDefined(signatureDecls, d => checker.getSignatureFromDeclaration(d)); diff --git a/src/services/refactors/convertParamsToDestructuredObject.ts b/src/services/refactors/convertParamsToDestructuredObject.ts index a86e190d2d8cd..597226c555203 100644 --- a/src/services/refactors/convertParamsToDestructuredObject.ts +++ b/src/services/refactors/convertParamsToDestructuredObject.ts @@ -104,7 +104,9 @@ import { TypeNode, VariableDeclaration, } from "../_namespaces/ts"; -import { registerRefactor } from "../_namespaces/ts.refactor"; +import { + registerRefactor, +} from "../_namespaces/ts.refactor"; const refactorName = "Convert parameters to destructured object"; const minimumParameterLength = 1; @@ -113,15 +115,17 @@ const refactorDescription = getLocaleSpecificMessage(Diagnostics.Convert_paramet const toDestructuredAction = { name: refactorName, description: refactorDescription, - kind: "refactor.rewrite.parameters.toDestructured" + kind: "refactor.rewrite.parameters.toDestructured", }; registerRefactor(refactorName, { kinds: [toDestructuredAction.kind], getEditsForAction: getRefactorEditsToConvertParametersToDestructuredObject, - getAvailableActions: getRefactorActionsToConvertParametersToDestructuredObject + getAvailableActions: getRefactorActionsToConvertParametersToDestructuredObject, }); -function getRefactorActionsToConvertParametersToDestructuredObject(context: RefactorContext): readonly ApplicableRefactorInfo[] { +function getRefactorActionsToConvertParametersToDestructuredObject( + context: RefactorContext, +): readonly ApplicableRefactorInfo[] { const { file, startPosition } = context; const isJSFile = isSourceFileJS(file); if (isJSFile) return emptyArray; // TODO: GH#30113 @@ -131,11 +135,14 @@ function getRefactorActionsToConvertParametersToDestructuredObject(context: Refa return [{ name: refactorName, description: refactorDescription, - actions: [toDestructuredAction] + actions: [toDestructuredAction], }]; } -function getRefactorEditsToConvertParametersToDestructuredObject(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { +function getRefactorEditsToConvertParametersToDestructuredObject( + context: RefactorContext, + actionName: string, +): RefactorEditInfo | undefined { Debug.assert(actionName === refactorName, "Unexpected action name"); const { file, startPosition, program, cancellationToken, host } = context; const functionDeclaration = getFunctionDeclarationAtPosition(file, startPosition, program.getTypeChecker()); @@ -143,7 +150,10 @@ function getRefactorEditsToConvertParametersToDestructuredObject(context: Refact const groupedReferences = getGroupedReferences(functionDeclaration, program, cancellationToken); if (groupedReferences.valid) { - const edits = textChanges.ChangeTracker.with(context, t => doChange(file, program, host, t, functionDeclaration, groupedReferences)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(file, program, host, t, functionDeclaration, groupedReferences), + ); return { renameFilename: undefined, renameLocation: undefined, edits }; } @@ -156,30 +166,50 @@ function doChange( host: LanguageServiceHost, changes: textChanges.ChangeTracker, functionDeclaration: ValidFunctionDeclaration, - groupedReferences: GroupedReferences): void { + groupedReferences: GroupedReferences, +): void { const signature = groupedReferences.signature; - const newFunctionDeclarationParams = map(createNewParameters(functionDeclaration, program, host), param => getSynthesizedDeepClone(param)); + const newFunctionDeclarationParams = map( + createNewParameters(functionDeclaration, program, host), + param => getSynthesizedDeepClone(param), + ); if (signature) { - const newSignatureParams = map(createNewParameters(signature, program, host), param => getSynthesizedDeepClone(param)); + const newSignatureParams = map( + createNewParameters(signature, program, host), + param => getSynthesizedDeepClone(param), + ); replaceParameters(signature, newSignatureParams); } replaceParameters(functionDeclaration, newFunctionDeclarationParams); - const functionCalls = sortAndDeduplicate(groupedReferences.functionCalls, /*comparer*/ (a, b) => compareValues(a.pos, b.pos)); + const functionCalls = sortAndDeduplicate( + groupedReferences.functionCalls, + /*comparer*/ (a, b) => compareValues(a.pos, b.pos), + ); for (const call of functionCalls) { if (call.arguments && call.arguments.length) { - const newArgument = getSynthesizedDeepClone(createNewArgument(functionDeclaration, call.arguments), /*includeTrivia*/ true); + const newArgument = getSynthesizedDeepClone( + createNewArgument(functionDeclaration, call.arguments), + /*includeTrivia*/ true, + ); changes.replaceNodeRange( getSourceFileOfNode(call), first(call.arguments), last(call.arguments), newArgument, - { leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, trailingTriviaOption: textChanges.TrailingTriviaOption.Include }); + { + leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, + trailingTriviaOption: textChanges.TrailingTriviaOption.Include, + }, + ); } } - function replaceParameters(declarationOrSignature: ValidFunctionDeclaration | ValidMethodSignature, parameterDeclarations: ParameterDeclaration[]) { + function replaceParameters( + declarationOrSignature: ValidFunctionDeclaration | ValidMethodSignature, + parameterDeclarations: ParameterDeclaration[], + ) { changes.replaceNodeRangeWithNodes( sourceFile, first(declarationOrSignature.parameters), @@ -190,18 +220,33 @@ function doChange( // indentation is set to 0 because otherwise the object parameter will be indented if there is a `this` parameter indentation: 0, leadingTriviaOption: textChanges.LeadingTriviaOption.IncludeAll, - trailingTriviaOption: textChanges.TrailingTriviaOption.Include - }); + trailingTriviaOption: textChanges.TrailingTriviaOption.Include, + }, + ); } } -function getGroupedReferences(functionDeclaration: ValidFunctionDeclaration, program: Program, cancellationToken: CancellationToken): GroupedReferences { +function getGroupedReferences( + functionDeclaration: ValidFunctionDeclaration, + program: Program, + cancellationToken: CancellationToken, +): GroupedReferences { const functionNames = getFunctionNames(functionDeclaration); const classNames = isConstructorDeclaration(functionDeclaration) ? getClassNames(functionDeclaration) : []; const names = deduplicate([...functionNames, ...classNames], equateValues); const checker = program.getTypeChecker(); - const references = flatMap(names, /*mapfn*/ name => FindAllReferences.getReferenceEntriesForNode(-1, name, program, program.getSourceFiles(), cancellationToken)); + const references = flatMap( + names, + /*mapfn*/ name => + FindAllReferences.getReferenceEntriesForNode( + -1, + name, + program, + program.getSourceFiles(), + cancellationToken, + ), + ); const groupedReferences = groupReferences(references); if (!every(groupedReferences.declarations, /*callback*/ decl => contains(names, decl))) { @@ -212,7 +257,12 @@ function getGroupedReferences(functionDeclaration: ValidFunctionDeclaration, pro function groupReferences(referenceEntries: readonly FindAllReferences.Entry[]): GroupedReferences { const classReferences: ClassReferences = { accessExpressions: [], typeUsages: [] }; - const groupedReferences: GroupedReferences = { functionCalls: [], declarations: [], classReferences, valid: true }; + const groupedReferences: GroupedReferences = { + functionCalls: [], + declarations: [], + classReferences, + valid: true, + }; const functionSymbols = map(functionNames, getSymbolTargetAtLocation); const classSymbols = map(classNames, getSymbolTargetAtLocation); const isConstructor = isConstructorDeclaration(functionDeclaration); @@ -337,10 +387,12 @@ function getSymbolForContextualType(node: Node, checker: TypeChecker): Symbol | function entryToImportOrExport(entry: FindAllReferences.NodeEntry): Node | undefined { const node = entry.node; - if (isImportSpecifier(node.parent) + if ( + isImportSpecifier(node.parent) || isImportClause(node.parent) || isImportEqualsDeclaration(node.parent) - || isNamespaceImport(node.parent)) { + || isNamespaceImport(node.parent) + ) { return node; } @@ -373,7 +425,10 @@ function entryToFunctionCall(entry: FindAllReferences.NodeEntry): CallExpression // x.foo(...) case SyntaxKind.PropertyAccessExpression: const propertyAccessExpression = tryCast(parent, isPropertyAccessExpression); - if (propertyAccessExpression && propertyAccessExpression.parent && propertyAccessExpression.name === functionReference) { + if ( + propertyAccessExpression && propertyAccessExpression.parent + && propertyAccessExpression.name === functionReference + ) { const callOrNewExpression = tryCast(propertyAccessExpression.parent, isCallOrNewExpression); if (callOrNewExpression && callOrNewExpression.expression === propertyAccessExpression) { return callOrNewExpression; @@ -383,7 +438,10 @@ function entryToFunctionCall(entry: FindAllReferences.NodeEntry): CallExpression // x["foo"](...) case SyntaxKind.ElementAccessExpression: const elementAccessExpression = tryCast(parent, isElementAccessExpression); - if (elementAccessExpression && elementAccessExpression.parent && elementAccessExpression.argumentExpression === functionReference) { + if ( + elementAccessExpression && elementAccessExpression.parent + && elementAccessExpression.argumentExpression === functionReference + ) { const callOrNewExpression = tryCast(elementAccessExpression.parent, isCallOrNewExpression); if (callOrNewExpression && callOrNewExpression.expression === elementAccessExpression) { return callOrNewExpression; @@ -395,7 +453,9 @@ function entryToFunctionCall(entry: FindAllReferences.NodeEntry): CallExpression return undefined; } -function entryToAccessExpression(entry: FindAllReferences.NodeEntry): ElementAccessExpression | PropertyAccessExpression | undefined { +function entryToAccessExpression( + entry: FindAllReferences.NodeEntry, +): ElementAccessExpression | PropertyAccessExpression | undefined { if (entry.node.parent) { const reference = entry.node; const parent = reference.parent; @@ -421,23 +481,32 @@ function entryToAccessExpression(entry: FindAllReferences.NodeEntry): ElementAcc function entryToType(entry: FindAllReferences.NodeEntry): Node | undefined { const reference = entry.node; - if (getMeaningFromLocation(reference) === SemanticMeaning.Type || isExpressionWithTypeArgumentsInClassExtendsClause(reference.parent)) { + if ( + getMeaningFromLocation(reference) === SemanticMeaning.Type + || isExpressionWithTypeArgumentsInClassExtendsClause(reference.parent) + ) { return reference; } return undefined; } -function getFunctionDeclarationAtPosition(file: SourceFile, startPosition: number, checker: TypeChecker): ValidFunctionDeclaration | undefined { +function getFunctionDeclarationAtPosition( + file: SourceFile, + startPosition: number, + checker: TypeChecker, +): ValidFunctionDeclaration | undefined { const node = getTouchingToken(file, startPosition); const functionDeclaration = getContainingFunctionDeclaration(node); // don't offer refactor on top-level JSDoc if (isTopLevelJSDoc(node)) return undefined; - if (functionDeclaration + if ( + functionDeclaration && isValidFunctionDeclaration(functionDeclaration, checker) && rangeContainsRange(functionDeclaration, node) - && !(functionDeclaration.body && rangeContainsRange(functionDeclaration.body, node))) return functionDeclaration; + && !(functionDeclaration.body && rangeContainsRange(functionDeclaration.body, node)) + ) return functionDeclaration; return undefined; } @@ -457,7 +526,8 @@ function isValidMethodSignature(node: Node): node is ValidMethodSignature { function isValidFunctionDeclaration( functionDeclaration: FunctionLikeDeclaration, - checker: TypeChecker): functionDeclaration is ValidFunctionDeclaration { + checker: TypeChecker, +): functionDeclaration is ValidFunctionDeclaration { if (!isValidParameterNodeArray(functionDeclaration.parameters, checker)) return false; switch (functionDeclaration.kind) { case SyntaxKind.FunctionDeclaration: @@ -466,12 +536,14 @@ function isValidFunctionDeclaration( if (isObjectLiteralExpression(functionDeclaration.parent)) { const contextualSymbol = getSymbolForContextualType(functionDeclaration.name, checker); // don't offer the refactor when there are multiple signatures since we won't know which ones the user wants to change - return contextualSymbol?.declarations?.length === 1 && isSingleImplementation(functionDeclaration, checker); + return contextualSymbol?.declarations?.length === 1 + && isSingleImplementation(functionDeclaration, checker); } return isSingleImplementation(functionDeclaration, checker); case SyntaxKind.Constructor: if (isClassDeclaration(functionDeclaration.parent)) { - return hasNameOrDefault(functionDeclaration.parent) && isSingleImplementation(functionDeclaration, checker); + return hasNameOrDefault(functionDeclaration.parent) + && isSingleImplementation(functionDeclaration, checker); } else { return isValidVariableDeclaration(functionDeclaration.parent.parent) @@ -498,14 +570,16 @@ function hasNameOrDefault(functionOrClassDeclaration: FunctionDeclaration | Clas function isValidParameterNodeArray( parameters: NodeArray, - checker: TypeChecker): parameters is ValidParameterNodeArray { + checker: TypeChecker, +): parameters is ValidParameterNodeArray { return getRefactorableParametersLength(parameters) >= minimumParameterLength && every(parameters, /*callback*/ paramDecl => isValidParameterDeclaration(paramDecl, checker)); } function isValidParameterDeclaration( parameterDeclaration: ParameterDeclaration, - checker: TypeChecker): parameterDeclaration is ValidParameterDeclaration { + checker: TypeChecker, +): parameterDeclaration is ValidParameterDeclaration { if (isRestParameter(parameterDeclaration)) { const type = checker.getTypeAtLocation(parameterDeclaration); if (!checker.isArrayType(type) && !checker.isTupleType(type)) return false; @@ -528,21 +602,29 @@ function getRefactorableParametersLength(parameters: NodeArray): NodeArray { +function getRefactorableParameters( + parameters: NodeArray, +): NodeArray { if (hasThisParameter(parameters)) { parameters = factory.createNodeArray(parameters.slice(1), parameters.hasTrailingComma); } return parameters; } -function createPropertyOrShorthandAssignment(name: string, initializer: Expression): PropertyAssignment | ShorthandPropertyAssignment { +function createPropertyOrShorthandAssignment( + name: string, + initializer: Expression, +): PropertyAssignment | ShorthandPropertyAssignment { if (isIdentifier(initializer) && getTextOfIdentifierOrLiteral(initializer) === name) { return factory.createShorthandPropertyAssignment(name); } return factory.createPropertyAssignment(name, initializer); } -function createNewArgument(functionDeclaration: ValidFunctionDeclaration, functionArguments: NodeArray): ObjectLiteralExpression { +function createNewArgument( + functionDeclaration: ValidFunctionDeclaration, + functionArguments: NodeArray, +): ObjectLiteralExpression { const parameters = getRefactorableParameters(functionDeclaration.parameters); const hasRestParameter = isRestParameter(last(parameters)); const nonRestArguments = hasRestParameter ? functionArguments.slice(0, parameters.length - 1) : functionArguments; @@ -558,7 +640,10 @@ function createNewArgument(functionDeclaration: ValidFunctionDeclaration, functi if (hasRestParameter && functionArguments.length >= parameters.length) { const restArguments = functionArguments.slice(parameters.length - 1); - const restProperty = factory.createPropertyAssignment(getParameterName(last(parameters)), factory.createArrayLiteralExpression(restArguments)); + const restProperty = factory.createPropertyAssignment( + getParameterName(last(parameters)), + factory.createArrayLiteralExpression(restArguments), + ); properties.push(restProperty); } @@ -566,7 +651,11 @@ function createNewArgument(functionDeclaration: ValidFunctionDeclaration, functi return objectLiteral; } -function createNewParameters(functionDeclaration: ValidFunctionDeclaration | ValidMethodSignature, program: Program, host: LanguageServiceHost): NodeArray { +function createNewParameters( + functionDeclaration: ValidFunctionDeclaration | ValidMethodSignature, + program: Program, + host: LanguageServiceHost, +): NodeArray { const checker = program.getTypeChecker(); const refactorableParameters = getRefactorableParameters(functionDeclaration.parameters); const bindingElements = map(refactorableParameters, createBindingElementFromParameterDeclaration); @@ -585,7 +674,8 @@ function createNewParameters(functionDeclaration: ValidFunctionDeclaration | Val objectParameterName, /*questionToken*/ undefined, objectParameterType, - objectInitializer); + objectInitializer, + ); if (hasThisParameter(functionDeclaration.parameters)) { const thisParameter = functionDeclaration.parameters[0]; @@ -594,7 +684,8 @@ function createNewParameters(functionDeclaration: ValidFunctionDeclaration | Val /*dotDotDotToken*/ undefined, thisParameter.name, /*questionToken*/ undefined, - thisParameter.type); + thisParameter.type, + ); suppressLeadingAndTrailingTrivia(newThisParameter.name); copyComments(thisParameter.name, newThisParameter.name); @@ -607,12 +698,16 @@ function createNewParameters(functionDeclaration: ValidFunctionDeclaration | Val } return factory.createNodeArray([objectParameter]); - function createBindingElementFromParameterDeclaration(parameterDeclaration: ValidParameterDeclaration): BindingElement { + function createBindingElementFromParameterDeclaration( + parameterDeclaration: ValidParameterDeclaration, + ): BindingElement { const element = factory.createBindingElement( /*dotDotDotToken*/ undefined, /*propertyName*/ undefined, getParameterName(parameterDeclaration), - isRestParameter(parameterDeclaration) && isOptionalParameter(parameterDeclaration) ? factory.createArrayLiteralExpression() : parameterDeclaration.initializer); + isRestParameter(parameterDeclaration) && isOptionalParameter(parameterDeclaration) + ? factory.createArrayLiteralExpression() : parameterDeclaration.initializer, + ); suppressLeadingAndTrailingTrivia(element); if (parameterDeclaration.initializer && element.initializer) { @@ -627,7 +722,9 @@ function createNewParameters(functionDeclaration: ValidFunctionDeclaration | Val return typeNode; } - function createPropertySignatureFromParameterDeclaration(parameterDeclaration: ValidParameterDeclaration): PropertySignature { + function createPropertySignatureFromParameterDeclaration( + parameterDeclaration: ValidParameterDeclaration, + ): PropertySignature { let parameterType = parameterDeclaration.type; if (!parameterType && (parameterDeclaration.initializer || isRestParameter(parameterDeclaration))) { parameterType = getTypeNode(parameterDeclaration); @@ -636,8 +733,10 @@ function createNewParameters(functionDeclaration: ValidFunctionDeclaration | Val const propertySignature = factory.createPropertySignature( /*modifiers*/ undefined, getParameterName(parameterDeclaration), - isOptionalParameter(parameterDeclaration) ? factory.createToken(SyntaxKind.QuestionToken) : parameterDeclaration.questionToken, - parameterType); + isOptionalParameter(parameterDeclaration) ? factory.createToken(SyntaxKind.QuestionToken) + : parameterDeclaration.questionToken, + parameterType, + ); suppressLeadingAndTrailingTrivia(propertySignature); copyComments(parameterDeclaration.name, propertySignature.name); @@ -675,7 +774,8 @@ function getClassNames(constructorDeclaration: ValidConstructor): (Identifier | // We validated this in `isValidFunctionDeclaration` through `hasNameOrDefault` const defaultModifier = Debug.checkDefined( findModifier(classDeclaration, SyntaxKind.DefaultKeyword), - "Nameless class declaration should be a default export"); + "Nameless class declaration should be a default export", + ); return [defaultModifier]; case SyntaxKind.ClassExpression: const classExpression = constructorDeclaration.parent; @@ -694,14 +794,20 @@ function getFunctionNames(functionDeclaration: ValidFunctionDeclaration): Node[] // We validated this in `isValidFunctionDeclaration` through `hasNameOrDefault` const defaultModifier = Debug.checkDefined( findModifier(functionDeclaration, SyntaxKind.DefaultKeyword), - "Nameless function declaration should be a default export"); + "Nameless function declaration should be a default export", + ); return [defaultModifier]; case SyntaxKind.MethodDeclaration: return [functionDeclaration.name]; case SyntaxKind.Constructor: const ctrKeyword = Debug.checkDefined( - findChildOfKind(functionDeclaration, SyntaxKind.ConstructorKeyword, functionDeclaration.getSourceFile()), - "Constructor declaration should have constructor keyword"); + findChildOfKind( + functionDeclaration, + SyntaxKind.ConstructorKeyword, + functionDeclaration.getSourceFile(), + ), + "Constructor declaration should have constructor keyword", + ); if (functionDeclaration.parent.kind === SyntaxKind.ClassExpression) { const variableDeclaration = functionDeclaration.parent.parent; return [variableDeclaration.name, ctrKeyword]; @@ -713,7 +819,10 @@ function getFunctionNames(functionDeclaration: ValidFunctionDeclaration): Node[] if (functionDeclaration.name) return [functionDeclaration.name, functionDeclaration.parent.name]; return [functionDeclaration.parent.name]; default: - return Debug.assertNever(functionDeclaration, `Unexpected function declaration kind ${(functionDeclaration as ValidFunctionDeclaration).kind}`); + return Debug.assertNever( + functionDeclaration, + `Unexpected function declaration kind ${(functionDeclaration as ValidFunctionDeclaration).kind}`, + ); } } @@ -725,7 +834,7 @@ interface ValidVariableDeclaration extends VariableDeclaration { } interface ValidConstructor extends ConstructorDeclaration { - parent: ClassDeclaration | (ClassExpression & { parent: ValidVariableDeclaration }); + parent: ClassDeclaration | (ClassExpression & { parent: ValidVariableDeclaration; }); parameters: NodeArray; body: FunctionBody; } @@ -754,7 +863,12 @@ interface ValidMethodSignature extends MethodSignature { parameters: NodeArray; } -type ValidFunctionDeclaration = ValidConstructor | ValidFunction | ValidMethod | ValidArrowFunction | ValidFunctionExpression; +type ValidFunctionDeclaration = + | ValidConstructor + | ValidFunction + | ValidMethod + | ValidArrowFunction + | ValidFunctionExpression; interface ValidParameterDeclaration extends ParameterDeclaration { name: Identifier; diff --git a/src/services/refactors/convertStringOrTemplateLiteral.ts b/src/services/refactors/convertStringOrTemplateLiteral.ts index 9611151953769..c2c9c978cd054 100644 --- a/src/services/refactors/convertStringOrTemplateLiteral.ts +++ b/src/services/refactors/convertStringOrTemplateLiteral.ts @@ -36,7 +36,9 @@ import { textChanges, Token, } from "../_namespaces/ts"; -import { registerRefactor } from "../_namespaces/ts.refactor"; +import { + registerRefactor, +} from "../_namespaces/ts.refactor"; const refactorName = "Convert to template string"; const refactorDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_template_string); @@ -44,12 +46,12 @@ const refactorDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_temp const convertStringAction = { name: refactorName, description: refactorDescription, - kind: "refactor.rewrite.string" + kind: "refactor.rewrite.string", }; registerRefactor(refactorName, { kinds: [convertStringAction.kind], getEditsForAction: getRefactorEditsToConvertToTemplateString, - getAvailableActions: getRefactorActionsToConvertToTemplateString + getAvailableActions: getRefactorActionsToConvertToTemplateString, }); function getRefactorActionsToConvertToTemplateString(context: RefactorContext): readonly ApplicableRefactorInfo[] { @@ -63,8 +65,9 @@ function getRefactorActionsToConvertToTemplateString(context: RefactorContext): return [refactorInfo]; } else if (context.preferences.provideRefactorNotApplicableReason) { - refactorInfo.actions.push({ ...convertStringAction, - notApplicableReason: getLocaleSpecificMessage(Diagnostics.Can_only_convert_string_concatenation) + refactorInfo.actions.push({ + ...convertStringAction, + notApplicableReason: getLocaleSpecificMessage(Diagnostics.Can_only_convert_string_concatenation), }); return [refactorInfo]; } @@ -77,16 +80,19 @@ function getNodeOrParentOfParentheses(file: SourceFile, startPosition: number) { const isNonStringBinary = !treeToArray(nestedBinary).isValidConcatenation; if ( - isNonStringBinary && - isParenthesizedExpression(nestedBinary.parent) && - isBinaryExpression(nestedBinary.parent.parent) + isNonStringBinary + && isParenthesizedExpression(nestedBinary.parent) + && isBinaryExpression(nestedBinary.parent.parent) ) { return nestedBinary.parent.parent; } return node; } -function getRefactorEditsToConvertToTemplateString(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { +function getRefactorEditsToConvertToTemplateString( + context: RefactorContext, + actionName: string, +): RefactorEditInfo | undefined { const { file, startPosition } = context; const node = getNodeOrParentOfParentheses(file, startPosition); @@ -122,7 +128,8 @@ function getEditsForToTemplateLiteral(context: RefactorContext, node: Node) { } function isNotEqualsOperator(node: BinaryExpression) { - return !(node.operatorToken.kind === SyntaxKind.EqualsToken || node.operatorToken.kind === SyntaxKind.PlusEqualsToken); + return !(node.operatorToken.kind === SyntaxKind.EqualsToken + || node.operatorToken.kind === SyntaxKind.PlusEqualsToken); } function getParentBinaryExpression(expr: Node) { @@ -143,10 +150,16 @@ function getParentBinaryExpression(expr: Node) { } function treeToArray(current: Expression) { - const loop = (current: Node): { nodes: Expression[], operators: Token[], hasString: boolean, validOperators: boolean} => { + const loop = ( + current: Node, + ): { nodes: Expression[]; operators: Token[]; hasString: boolean; validOperators: boolean; } => { if (!isBinaryExpression(current)) { - return { nodes: [current as Expression], operators: [], validOperators: true, - hasString: isStringLiteral(current) || isNoSubstitutionTemplateLiteral(current) }; + return { + nodes: [current as Expression], + operators: [], + validOperators: true, + hasString: isStringLiteral(current) || isNoSubstitutionTemplateLiteral(current), + }; } const { nodes, operators, hasString: leftHasString, validOperators: leftOperatorValid } = loop(current.left); @@ -168,22 +181,36 @@ function treeToArray(current: Expression) { // to copy comments following the operator // "foo" + /* comment */ "bar" -const copyTrailingOperatorComments = (operators: Token[], file: SourceFile) => (index: number, targetNode: Node) => { - if (index < operators.length) { - copyTrailingComments(operators[index], targetNode, file, SyntaxKind.MultiLineCommentTrivia, /*hasTrailingNewLine*/ false); - } -}; +const copyTrailingOperatorComments = + (operators: Token[], file: SourceFile) => (index: number, targetNode: Node) => { + if (index < operators.length) { + copyTrailingComments( + operators[index], + targetNode, + file, + SyntaxKind.MultiLineCommentTrivia, + /*hasTrailingNewLine*/ false, + ); + } + }; // to copy comments following the string // "foo" /* comment */ + "bar" /* comment */ + "bar2" -const copyCommentFromMultiNode = (nodes: readonly Expression[], file: SourceFile, copyOperatorComments: (index: number, targetNode: Node) => void) => -(indexes: number[], targetNode: Node) => { - while (indexes.length > 0) { - const index = indexes.shift()!; - copyTrailingComments(nodes[index], targetNode, file, SyntaxKind.MultiLineCommentTrivia, /*hasTrailingNewLine*/ false); - copyOperatorComments(index, targetNode); - } -}; +const copyCommentFromMultiNode = + (nodes: readonly Expression[], file: SourceFile, copyOperatorComments: (index: number, targetNode: Node) => void) => + (indexes: number[], targetNode: Node) => { + while (indexes.length > 0) { + const index = indexes.shift()!; + copyTrailingComments( + nodes[index], + targetNode, + file, + SyntaxKind.MultiLineCommentTrivia, + /*hasTrailingNewLine*/ false, + ); + copyOperatorComments(index, targetNode); + } + }; function escapeRawStringForTemplate(s: string) { // Escaping for $s in strings that are to be used in template strings @@ -201,7 +228,10 @@ function getRawTextOfTemplate(node: TemplateHead | TemplateMiddle | TemplateTail return getTextOfNode(node).slice(1, rightShaving); } -function concatConsecutiveString(index: number, nodes: readonly Expression[]): [nextIndex: number, text: string, rawText: string, usedIndexes: number[]] { +function concatConsecutiveString( + index: number, + nodes: readonly Expression[], +): [nextIndex: number, text: string, rawText: string, usedIndexes: number[]] { const indexes = []; let text = "", rawText = ""; while (index < nodes.length) { @@ -224,7 +254,10 @@ function concatConsecutiveString(index: number, nodes: readonly Expression[]): [ return [index, text, rawText, indexes]; } -function nodesToTemplate({ nodes, operators }: { nodes: readonly Expression[], operators: Token[] }, file: SourceFile) { +function nodesToTemplate( + { nodes, operators }: { nodes: readonly Expression[]; operators: Token[]; }, + file: SourceFile, +) { const copyOperatorComments = copyTrailingOperatorComments(operators, file); const copyCommentFromStringLiterals = copyCommentFromMultiNode(nodes, file, copyOperatorComments); const [begin, headText, rawHeadText, headIndexes] = concatConsecutiveString(0, nodes); @@ -253,9 +286,12 @@ function nodesToTemplate({ nodes, operators }: { nodes: readonly Expression[], o const isLastSpan = index === currentNode.templateSpans.length - 1; const text = span.literal.text + (isLastSpan ? subsequentText : ""); const rawText = getRawTextOfTemplate(span.literal) + (isLastSpan ? rawSubsequentText : ""); - return factory.createTemplateSpan(span.expression, isLast && isLastSpan - ? factory.createTemplateTail(text, rawText) - : factory.createTemplateMiddle(text, rawText)); + return factory.createTemplateSpan( + span.expression, + isLast && isLastSpan + ? factory.createTemplateTail(text, rawText) + : factory.createTemplateMiddle(text, rawText), + ); }); templateSpans.push(...spans); } @@ -276,7 +312,13 @@ function nodesToTemplate({ nodes, operators }: { nodes: readonly Expression[], o function copyExpressionComments(node: ParenthesizedExpression | TemplateSpan) { const file = node.getSourceFile(); copyTrailingComments(node, node.expression, file, SyntaxKind.MultiLineCommentTrivia, /*hasTrailingNewLine*/ false); - copyTrailingAsLeadingComments(node.expression, node.expression, file, SyntaxKind.MultiLineCommentTrivia, /*hasTrailingNewLine*/ false); + copyTrailingAsLeadingComments( + node.expression, + node.expression, + file, + SyntaxKind.MultiLineCommentTrivia, + /*hasTrailingNewLine*/ false, + ); } function getExpressionFromParenthesesOrExpression(node: Expression) { diff --git a/src/services/refactors/convertToOptionalChainExpression.ts b/src/services/refactors/convertToOptionalChainExpression.ts index a86777e97dd63..eb57af68ca8ec 100644 --- a/src/services/refactors/convertToOptionalChainExpression.ts +++ b/src/services/refactors/convertToOptionalChainExpression.ts @@ -48,7 +48,9 @@ import { } from "../_namespaces/ts.refactor"; const refactorName = "Convert to optional chain expression"; -const convertToOptionalChainExpressionMessage = getLocaleSpecificMessage(Diagnostics.Convert_to_optional_chain_expression); +const convertToOptionalChainExpressionMessage = getLocaleSpecificMessage( + Diagnostics.Convert_to_optional_chain_expression, +); const toOptionalChainAction = { name: refactorName, @@ -83,11 +85,15 @@ function getRefactorActionsToConvertToOptionalChain(context: RefactorContext): r return emptyArray; } -function getRefactorEditsToConvertToOptionalChain(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { +function getRefactorEditsToConvertToOptionalChain( + context: RefactorContext, + actionName: string, +): RefactorEditInfo | undefined { const info = getInfo(context); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); - const edits = textChanges.ChangeTracker.with(context, t => - doChange(context.file, context.program.getTypeChecker(), t, info, actionName) + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, context.program.getTypeChecker(), t, info, actionName), ); return { edits, renameFilename: undefined, renameLocation: undefined }; } @@ -95,9 +101,9 @@ function getRefactorEditsToConvertToOptionalChain(context: RefactorContext, acti type Occurrence = PropertyAccessExpression | ElementAccessExpression | Identifier; interface OptionalChainInfo { - finalExpression: PropertyAccessExpression | ElementAccessExpression | CallExpression, - occurrences: Occurrence[], - expression: ValidExpression, + finalExpression: PropertyAccessExpression | ElementAccessExpression | CallExpression; + occurrences: Occurrence[]; + expression: ValidExpression; } type ValidExpressionOrStatement = ValidExpression | ValidStatement; @@ -124,7 +130,10 @@ function isValidExpressionOrStatement(node: Node): node is ValidExpressionOrStat return isValidExpression(node) || isValidStatement(node); } -function getInfo(context: RefactorContext, considerEmptySpans = true): OptionalChainInfo | RefactorErrorInfo | undefined { +function getInfo( + context: RefactorContext, + considerEmptySpans = true, +): OptionalChainInfo | RefactorErrorInfo | undefined { const { file, program } = context; const span = getRefactorContextSpan(context); @@ -134,17 +143,26 @@ function getInfo(context: RefactorContext, considerEmptySpans = true): OptionalC // selecting fo[|o && foo.ba|]r should be valid, so adjust span to fit start and end tokens const startToken = getTokenAtPosition(file, span.start); const endToken = findTokenOnLeftOfPosition(file, span.start + span.length); - const adjustedSpan = createTextSpanFromBounds(startToken.pos, endToken && endToken.end >= startToken.pos ? endToken.getEnd() : startToken.getEnd()); + const adjustedSpan = createTextSpanFromBounds( + startToken.pos, + endToken && endToken.end >= startToken.pos ? endToken.getEnd() : startToken.getEnd(), + ); - const parent = forEmptySpan ? getValidParentNodeOfEmptySpan(startToken) : getValidParentNodeContainingSpan(startToken, adjustedSpan); + const parent = forEmptySpan ? getValidParentNodeOfEmptySpan(startToken) + : getValidParentNodeContainingSpan(startToken, adjustedSpan); const expression = parent && isValidExpressionOrStatement(parent) ? getExpression(parent) : undefined; - if (!expression) return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; + if (!expression) { + return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; + } const checker = program.getTypeChecker(); return isConditionalExpression(expression) ? getConditionalInfo(expression, checker) : getBinaryInfo(expression); } -function getConditionalInfo(expression: ConditionalExpression, checker: TypeChecker): OptionalChainInfo | RefactorErrorInfo | undefined { +function getConditionalInfo( + expression: ConditionalExpression, + checker: TypeChecker, +): OptionalChainInfo | RefactorErrorInfo | undefined { const condition = expression.condition; const finalExpression = getFinalExpressionInChain(expression.whenTrue); @@ -152,14 +170,16 @@ function getConditionalInfo(expression: ConditionalExpression, checker: TypeChec return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; } - if ((isPropertyAccessExpression(condition) || isIdentifier(condition)) - && getMatchingStart(condition, finalExpression.expression)) { + if ( + (isPropertyAccessExpression(condition) || isIdentifier(condition)) + && getMatchingStart(condition, finalExpression.expression) + ) { return { finalExpression, occurrences: [condition], expression }; } else if (isBinaryExpression(condition)) { const occurrences = getOccurrencesInExpression(finalExpression.expression, condition); - return occurrences ? { finalExpression, occurrences, expression } : - { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) }; + return occurrences ? { finalExpression, occurrences, expression } + : { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) }; } } @@ -169,11 +189,13 @@ function getBinaryInfo(expression: BinaryExpression): OptionalChainInfo | Refact } const finalExpression = getFinalExpressionInChain(expression.right); - if (!finalExpression) return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; + if (!finalExpression) { + return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) }; + } const occurrences = getOccurrencesInExpression(finalExpression.expression, expression.left); - return occurrences ? { finalExpression, occurrences, expression } : - { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) }; + return occurrences ? { finalExpression, occurrences, expression } + : { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) }; } /** @@ -194,13 +216,16 @@ function getOccurrencesInExpression(matchTo: Expression, expression: Expression) if (finalMatch) { occurrences.push(finalMatch); } - return occurrences.length > 0 ? occurrences: undefined; + return occurrences.length > 0 ? occurrences : undefined; } /** * Returns subchain if chain begins with subchain syntactically. */ -function getMatchingStart(chain: Expression, subchain: Expression): PropertyAccessExpression | ElementAccessExpression | Identifier | undefined { +function getMatchingStart( + chain: Expression, + subchain: Expression, +): PropertyAccessExpression | ElementAccessExpression | Identifier | undefined { if (!isIdentifier(subchain) && !isPropertyAccessExpression(subchain) && !isElementAccessExpression(subchain)) { return undefined; } @@ -217,8 +242,10 @@ function chainStartsWith(chain: Node, subchain: Node): boolean { chain = chain.expression; } // check that the chains match at each access. Call chains in subchain are not valid. - while ((isPropertyAccessExpression(chain) && isPropertyAccessExpression(subchain)) || - (isElementAccessExpression(chain) && isElementAccessExpression(subchain))) { + while ( + (isPropertyAccessExpression(chain) && isPropertyAccessExpression(subchain)) + || (isElementAccessExpression(chain) && isElementAccessExpression(subchain)) + ) { if (getTextOfChainNode(chain) !== getTextOfChainNode(subchain)) return false; chain = chain.expression; subchain = subchain.expression; @@ -287,7 +314,9 @@ function getExpression(node: ValidExpressionOrStatement): ValidExpression | unde * it is followed by a different binary operator. * @param node the right child of a binary expression or a call expression. */ -function getFinalExpressionInChain(node: Expression): CallExpression | PropertyAccessExpression | ElementAccessExpression | undefined { +function getFinalExpressionInChain( + node: Expression, +): CallExpression | PropertyAccessExpression | ElementAccessExpression | undefined { // foo && |foo.bar === 1|; - here the right child of the && binary expression is another binary expression. // the rightmost member of the && chain should be the leftmost child of that expression. node = skipParentheses(node); @@ -295,7 +324,10 @@ function getFinalExpressionInChain(node: Expression): CallExpression | PropertyA return getFinalExpressionInChain(node.left); } // foo && |foo.bar()()| - nested calls are treated like further accesses. - else if ((isPropertyAccessExpression(node) || isElementAccessExpression(node) || isCallExpression(node)) && !isOptionalChain(node)) { + else if ( + (isPropertyAccessExpression(node) || isElementAccessExpression(node) || isCallExpression(node)) + && !isOptionalChain(node) + ) { return node; } return undefined; @@ -311,35 +343,69 @@ function convertOccurrences(checker: TypeChecker, toConvert: Expression, occurre const isOccurrence = lastOccurrence?.getText() === toConvert.expression.getText(); if (isOccurrence) occurrences.pop(); if (isCallExpression(toConvert)) { - return isOccurrence ? - factory.createCallChain(chain, factory.createToken(SyntaxKind.QuestionDotToken), toConvert.typeArguments, toConvert.arguments) : - factory.createCallChain(chain, toConvert.questionDotToken, toConvert.typeArguments, toConvert.arguments); + return isOccurrence + ? factory.createCallChain( + chain, + factory.createToken(SyntaxKind.QuestionDotToken), + toConvert.typeArguments, + toConvert.arguments, + ) + : factory.createCallChain( + chain, + toConvert.questionDotToken, + toConvert.typeArguments, + toConvert.arguments, + ); } else if (isPropertyAccessExpression(toConvert)) { - return isOccurrence ? - factory.createPropertyAccessChain(chain, factory.createToken(SyntaxKind.QuestionDotToken), toConvert.name) : - factory.createPropertyAccessChain(chain, toConvert.questionDotToken, toConvert.name); + return isOccurrence + ? factory.createPropertyAccessChain( + chain, + factory.createToken(SyntaxKind.QuestionDotToken), + toConvert.name, + ) + : factory.createPropertyAccessChain(chain, toConvert.questionDotToken, toConvert.name); } else if (isElementAccessExpression(toConvert)) { - return isOccurrence ? - factory.createElementAccessChain(chain, factory.createToken(SyntaxKind.QuestionDotToken), toConvert.argumentExpression) : - factory.createElementAccessChain(chain, toConvert.questionDotToken, toConvert.argumentExpression); + return isOccurrence + ? factory.createElementAccessChain( + chain, + factory.createToken(SyntaxKind.QuestionDotToken), + toConvert.argumentExpression, + ) + : factory.createElementAccessChain(chain, toConvert.questionDotToken, toConvert.argumentExpression); } } return toConvert; } -function doChange(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, info: OptionalChainInfo, _actionName: string): void { +function doChange( + sourceFile: SourceFile, + checker: TypeChecker, + changes: textChanges.ChangeTracker, + info: OptionalChainInfo, + _actionName: string, +): void { const { finalExpression, occurrences, expression } = info; const firstOccurrence = occurrences[occurrences.length - 1]; const convertedChain = convertOccurrences(checker, finalExpression, occurrences); - if (convertedChain && (isPropertyAccessExpression(convertedChain) || isElementAccessExpression(convertedChain) || isCallExpression(convertedChain))) { + if ( + convertedChain + && (isPropertyAccessExpression(convertedChain) || isElementAccessExpression(convertedChain) + || isCallExpression(convertedChain)) + ) { if (isBinaryExpression(expression)) { changes.replaceNodeRange(sourceFile, firstOccurrence, finalExpression, convertedChain); } else if (isConditionalExpression(expression)) { - changes.replaceNode(sourceFile, expression, - factory.createBinaryExpression(convertedChain, factory.createToken(SyntaxKind.QuestionQuestionToken), expression.whenFalse) + changes.replaceNode( + sourceFile, + expression, + factory.createBinaryExpression( + convertedChain, + factory.createToken(SyntaxKind.QuestionQuestionToken), + expression.whenFalse, + ), ); } } diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 9efcce3006624..553441cb031e9 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -180,7 +180,7 @@ const extractFunctionAction = { registerRefactor(refactorName, { kinds: [ extractConstantAction.kind, - extractFunctionAction.kind + extractFunctionAction.kind, ], getEditsForAction: getRefactorEditsToExtractSymbol, getAvailableActions: getRefactorActionsToExtractSymbol, @@ -194,11 +194,18 @@ registerRefactor(refactorName, { */ export function getRefactorActionsToExtractSymbol(context: RefactorContext): readonly ApplicableRefactorInfo[] { const requestedRefactor = context.kind; - const rangeToExtract = getRangeToExtract(context.file, getRefactorContextSpan(context), context.triggerReason === "invoked"); + const rangeToExtract = getRangeToExtract( + context.file, + getRefactorContextSpan(context), + context.triggerReason === "invoked", + ); const targetRange = rangeToExtract.targetRange; if (targetRange === undefined) { - if (!rangeToExtract.errors || rangeToExtract.errors.length === 0 || !context.preferences.provideRefactorNotApplicableReason) { + if ( + !rangeToExtract.errors || rangeToExtract.errors.length === 0 + || !context.preferences.provideRefactorNotApplicableReason + ) { return emptyArray; } @@ -207,14 +214,14 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea errors.push({ name: refactorName, description: extractFunctionAction.description, - actions: [{ ...extractFunctionAction, notApplicableReason: getStringError(rangeToExtract.errors) }] + actions: [{ ...extractFunctionAction, notApplicableReason: getStringError(rangeToExtract.errors) }], }); } if (refactorKindBeginsWith(extractConstantAction.kind, requestedRefactor)) { errors.push({ name: refactorName, description: extractConstantAction.description, - actions: [{ ...extractConstantAction, notApplicableReason: getStringError(rangeToExtract.errors) }] + actions: [{ ...extractConstantAction, notApplicableReason: getStringError(rangeToExtract.errors) }], }); } return errors; @@ -247,7 +254,7 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea functionActions.push({ description, name: `function_scope_${i}`, - kind: extractFunctionAction.kind + kind: extractFunctionAction.kind, }); } } @@ -256,7 +263,7 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea description, name: `function_scope_${i}`, notApplicableReason: getStringError(functionExtraction.errors), - kind: extractFunctionAction.kind + kind: extractFunctionAction.kind, }; } } @@ -272,7 +279,7 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea constantActions.push({ description, name: `constant_scope_${i}`, - kind: extractConstantAction.kind + kind: extractConstantAction.kind, }); } } @@ -281,7 +288,7 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea description, name: `constant_scope_${i}`, notApplicableReason: getStringError(constantExtraction.errors), - kind: extractConstantAction.kind + kind: extractConstantAction.kind, }; } } @@ -304,7 +311,7 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea infos.push({ name: refactorName, description: getLocaleSpecificMessage(Diagnostics.Extract_function), - actions: [ innermostErrorFunctionAction ] + actions: [innermostErrorFunctionAction], }); } @@ -312,14 +319,14 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea infos.push({ name: refactorName, description: getLocaleSpecificMessage(Diagnostics.Extract_constant), - actions: constantActions + actions: constantActions, }); } else if (context.preferences.provideRefactorNotApplicableReason && innermostErrorConstantAction) { infos.push({ name: refactorName, description: getLocaleSpecificMessage(Diagnostics.Extract_constant), - actions: [ innermostErrorConstantAction ] + actions: [innermostErrorConstantAction], }); } @@ -339,7 +346,10 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea * * @internal */ -export function getRefactorEditsToExtractSymbol(context: RefactorContext, actionName: string): RefactorEditInfo | undefined { +export function getRefactorEditsToExtractSymbol( + context: RefactorContext, + actionName: string, +): RefactorEditInfo | undefined { const rangeToExtract = getRangeToExtract(context.file, getRefactorContextSpan(context)); const targetRange = rangeToExtract.targetRange!; // TODO:GH#18217 @@ -375,21 +385,39 @@ export namespace Messages { export const expressionExpected: DiagnosticMessage = createMessage("expression expected."); export const uselessConstantType: DiagnosticMessage = createMessage("No reason to extract constant of type."); export const statementOrExpressionExpected: DiagnosticMessage = createMessage("Statement or expression expected."); - export const cannotExtractRangeContainingConditionalBreakOrContinueStatements: DiagnosticMessage = createMessage("Cannot extract range containing conditional break or continue statements."); - export const cannotExtractRangeContainingConditionalReturnStatement: DiagnosticMessage = createMessage("Cannot extract range containing conditional return statement."); - export const cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange: DiagnosticMessage = createMessage("Cannot extract range containing labeled break or continue with target outside of the range."); - export const cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators: DiagnosticMessage = createMessage("Cannot extract range containing writes to references located outside of the target range in generators."); + export const cannotExtractRangeContainingConditionalBreakOrContinueStatements: DiagnosticMessage = createMessage( + "Cannot extract range containing conditional break or continue statements.", + ); + export const cannotExtractRangeContainingConditionalReturnStatement: DiagnosticMessage = createMessage( + "Cannot extract range containing conditional return statement.", + ); + export const cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange: + DiagnosticMessage = createMessage( + "Cannot extract range containing labeled break or continue with target outside of the range.", + ); + export const cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators: + DiagnosticMessage = createMessage( + "Cannot extract range containing writes to references located outside of the target range in generators.", + ); export const typeWillNotBeVisibleInTheNewScope = createMessage("Type will not visible in the new scope."); export const functionWillNotBeVisibleInTheNewScope = createMessage("Function will not visible in the new scope."); export const cannotExtractIdentifier = createMessage("Select more than a single identifier."); export const cannotExtractExportedEntity = createMessage("Cannot extract exported declaration"); - export const cannotWriteInExpression = createMessage("Cannot write back side-effects when extracting an expression"); - export const cannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage("Cannot move initialization of read-only class property outside of the constructor"); + export const cannotWriteInExpression = createMessage( + "Cannot write back side-effects when extracting an expression", + ); + export const cannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage( + "Cannot move initialization of read-only class property outside of the constructor", + ); export const cannotExtractAmbientBlock = createMessage("Cannot extract code from ambient contexts"); export const cannotAccessVariablesFromNestedScopes = createMessage("Cannot access variables from nested scopes"); export const cannotExtractToJSClass = createMessage("Cannot extract constant to a class scope in JS"); - export const cannotExtractToExpressionArrowFunction = createMessage("Cannot extract constant to an arrow function without a block"); - export const cannotExtractFunctionsContainingThisToMethod = createMessage("Cannot extract functions containing this to method"); + export const cannotExtractToExpressionArrowFunction = createMessage( + "Cannot extract constant to an arrow function without a block", + ); + export const cannotExtractFunctionsContainingThisToMethod = createMessage( + "Cannot extract functions containing this to method", + ); } /** @internal */ @@ -459,11 +487,13 @@ export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan, invoke /* If the refactoring command is invoked through a keyboard action it's safe to assume that the user is actively looking for refactoring actions at the span location. As they may not know the exact range that will trigger a refactoring, we expand the searched span to cover a real node range making it more likely that something useful will show up. */ - const adjustedSpan = startToken && endToken && invoked ? getAdjustedSpanFromNodes(startToken, endToken, sourceFile) : span; + const adjustedSpan = startToken && endToken && invoked ? getAdjustedSpanFromNodes(startToken, endToken, sourceFile) + : span; // Walk up starting from the the start position until we find a non-SourceFile node that subsumes the selected span. // This may fail (e.g. you select two statements in the root of a source file) - const start = cursorRequest ? getExtractableParent(startToken) : getParentNodeInSpan(startToken, sourceFile, adjustedSpan); + const start = cursorRequest ? getExtractableParent(startToken) + : getParentNodeInSpan(startToken, sourceFile, adjustedSpan); // Do the same for the ending position const end = cursorRequest ? start : getParentNodeInSpan(endToken, sourceFile, adjustedSpan); @@ -604,16 +634,25 @@ export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan, invoke None = 0, Break = 1 << 0, Continue = 1 << 1, - Return = 1 << 2 + Return = 1 << 2, } // We believe it's true because the node is from the (unmodified) tree. - Debug.assert(nodeToCheck.pos <= nodeToCheck.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (1)"); + Debug.assert( + nodeToCheck.pos <= nodeToCheck.end, + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (1)", + ); // For understanding how skipTrivia functioned: - Debug.assert(!positionIsSynthesized(nodeToCheck.pos), "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (2)"); + Debug.assert( + !positionIsSynthesized(nodeToCheck.pos), + "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (2)", + ); - if (!isStatement(nodeToCheck) && !(isExpressionNode(nodeToCheck) && isExtractableExpression(nodeToCheck)) && !isStringLiteralJsxAttribute(nodeToCheck)) { + if ( + !isStatement(nodeToCheck) && !(isExpressionNode(nodeToCheck) && isExtractableExpression(nodeToCheck)) + && !isStringLiteralJsxAttribute(nodeToCheck) + ) { return [createDiagnosticForNode(nodeToCheck, Messages.statementOrExpressionExpected)]; } @@ -634,11 +673,16 @@ export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan, invoke visit(nodeToCheck); if (rangeFacts & RangeFacts.UsesThis) { - const container = getThisContainer(nodeToCheck, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false); + const container = getThisContainer( + nodeToCheck, + /*includeArrowFunctions*/ false, + /*includeClassComputedPropertyName*/ false, + ); if ( - container.kind === SyntaxKind.FunctionDeclaration || - (container.kind === SyntaxKind.MethodDeclaration && container.parent.kind === SyntaxKind.ObjectLiteralExpression) || - container.kind === SyntaxKind.FunctionExpression + container.kind === SyntaxKind.FunctionDeclaration + || (container.kind === SyntaxKind.MethodDeclaration + && container.parent.kind === SyntaxKind.ObjectLiteralExpression) + || container.kind === SyntaxKind.FunctionExpression ) { rangeFacts |= RangeFacts.UsesThisInFunction; } @@ -677,7 +721,10 @@ export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan, invoke if (node.parent.kind === SyntaxKind.CallExpression) { // Super constructor call const containingClass = getContainingClass(node); - if (containingClass === undefined || containingClass.pos < span.start || containingClass.end >= (span.start + span.length)) { + if ( + containingClass === undefined || containingClass.pos < span.start + || containingClass.end >= (span.start + span.length) + ) { (errors ||= []).push(createDiagnosticForNode(node, Messages.cannotExtractSuper)); return true; } @@ -706,7 +753,9 @@ export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan, invoke case SyntaxKind.FunctionDeclaration: if (isSourceFile(node.parent) && node.parent.externalModuleIndicator === undefined) { // You cannot extract global declarations - (errors ||= []).push(createDiagnosticForNode(node, Messages.functionWillNotBeVisibleInTheNewScope)); + (errors ||= []).push( + createDiagnosticForNode(node, Messages.functionWillNotBeVisibleInTheNewScope), + ); } // falls through case SyntaxKind.ClassExpression: @@ -729,7 +778,10 @@ export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan, invoke permittedJumps = PermittedJumps.None; break; case SyntaxKind.Block: - if (node.parent && node.parent.kind === SyntaxKind.TryStatement && (node.parent as TryStatement).finallyBlock === node) { + if ( + node.parent && node.parent.kind === SyntaxKind.TryStatement + && (node.parent as TryStatement).finallyBlock === node + ) { // allow unconditional returns from finally blocks permittedJumps = PermittedJumps.Return; } @@ -766,13 +818,28 @@ export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan, invoke if (label) { if (!contains(seenLabels, label.escapedText)) { // attempts to jump to label that is not in range to be extracted - (errors ||= []).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange)); + (errors ||= []).push( + createDiagnosticForNode( + node, + Messages + .cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange, + ), + ); } } else { - if (!(permittedJumps & (node.kind === SyntaxKind.BreakStatement ? PermittedJumps.Break : PermittedJumps.Continue))) { + if ( + !(permittedJumps + & (node.kind === SyntaxKind.BreakStatement ? PermittedJumps.Break + : PermittedJumps.Continue)) + ) { // attempt to break or continue in a forbidden context - (errors ||= []).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements)); + (errors ||= []).push( + createDiagnosticForNode( + node, + Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements, + ), + ); } } break; @@ -788,7 +855,12 @@ export function getRangeToExtract(sourceFile: SourceFile, span: TextSpan, invoke rangeFacts |= RangeFacts.HasReturn; } else { - (errors ||= []).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalReturnStatement)); + (errors ||= []).push( + createDiagnosticForNode( + node, + Messages.cannotExtractRangeContainingConditionalReturnStatement, + ), + ); } break; default: @@ -832,8 +904,8 @@ function getStatementOrExpressionRange(node: Node): Statement[] | Expression | u } function isScope(node: Node): node is Scope { - return isArrowFunction(node) ? isFunctionBody(node.body) : - isFunctionLikeDeclaration(node) || isSourceFile(node) || isModuleBlock(node) || isClassLike(node); + return isArrowFunction(node) ? isFunctionBody(node.body) + : isFunctionLikeDeclaration(node) || isSourceFile(node) || isModuleBlock(node) || isClassLike(node); } /** @@ -877,22 +949,48 @@ function collectEnclosingScopes(range: TargetRange): Scope[] { } } -function getFunctionExtractionAtIndex(targetRange: TargetRange, context: RefactorContext, requestedChangesIndex: number): RefactorEditInfo { - const { scopes, readsAndWrites: { target, usagesPerScope, functionErrorsPerScope, exposedVariableDeclarations } } = getPossibleExtractionsWorker(targetRange, context); +function getFunctionExtractionAtIndex( + targetRange: TargetRange, + context: RefactorContext, + requestedChangesIndex: number, +): RefactorEditInfo { + const { scopes, readsAndWrites: { target, usagesPerScope, functionErrorsPerScope, exposedVariableDeclarations } } = + getPossibleExtractionsWorker(targetRange, context); Debug.assert(!functionErrorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?"); context.cancellationToken!.throwIfCancellationRequested(); // TODO: GH#18217 - return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], exposedVariableDeclarations, targetRange, context); + return extractFunctionInScope( + target, + scopes[requestedChangesIndex], + usagesPerScope[requestedChangesIndex], + exposedVariableDeclarations, + targetRange, + context, + ); } -function getConstantExtractionAtIndex(targetRange: TargetRange, context: RefactorContext, requestedChangesIndex: number): RefactorEditInfo { - const { scopes, readsAndWrites: { target, usagesPerScope, constantErrorsPerScope, exposedVariableDeclarations } } = getPossibleExtractionsWorker(targetRange, context); +function getConstantExtractionAtIndex( + targetRange: TargetRange, + context: RefactorContext, + requestedChangesIndex: number, +): RefactorEditInfo { + const { scopes, readsAndWrites: { target, usagesPerScope, constantErrorsPerScope, exposedVariableDeclarations } } = + getPossibleExtractionsWorker(targetRange, context); Debug.assert(!constantErrorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?"); - Debug.assert(exposedVariableDeclarations.length === 0, "Extract constant accepted a range containing a variable declaration?"); + Debug.assert( + exposedVariableDeclarations.length === 0, + "Extract constant accepted a range containing a variable declaration?", + ); context.cancellationToken!.throwIfCancellationRequested(); const expression = isExpression(target) ? target : (target.statements[0] as ExpressionStatement).expression; - return extractConstantInScope(expression, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange.facts, context); + return extractConstantInScope( + expression, + scopes[requestedChangesIndex], + usagesPerScope[requestedChangesIndex], + targetRange.facts, + context, + ); } interface Extraction { @@ -910,8 +1008,14 @@ interface ScopeExtractions { * Each returned ExtractResultForScope corresponds to a possible target scope and is either a set of changes * or an error explaining why we can't extract into that scope. */ -function getPossibleExtractions(targetRange: TargetRange, context: RefactorContext): readonly ScopeExtractions[] | undefined { - const { scopes, readsAndWrites: { functionErrorsPerScope, constantErrorsPerScope } } = getPossibleExtractionsWorker(targetRange, context); +function getPossibleExtractions( + targetRange: TargetRange, + context: RefactorContext, +): readonly ScopeExtractions[] | undefined { + const { scopes, readsAndWrites: { functionErrorsPerScope, constantErrorsPerScope } } = getPossibleExtractionsWorker( + targetRange, + context, + ); // Need the inner type annotation to avoid https://github.com/Microsoft/TypeScript/issues/7547 const extractions = scopes.map((scope, i): ScopeExtractions => { const functionDescriptionPart = getDescriptionForFunctionInScope(scope); @@ -920,27 +1024,48 @@ function getPossibleExtractions(targetRange: TargetRange, context: RefactorConte const scopeDescription = isFunctionLikeDeclaration(scope) ? getDescriptionForFunctionLikeDeclaration(scope) : isClassLike(scope) - ? getDescriptionForClassLikeDeclaration(scope) - : getDescriptionForModuleLikeDeclaration(scope); + ? getDescriptionForClassLikeDeclaration(scope) + : getDescriptionForModuleLikeDeclaration(scope); let functionDescription: string; let constantDescription: string; if (scopeDescription === SpecialScope.Global) { - functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [functionDescriptionPart, "global"]); - constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [constantDescriptionPart, "global"]); + functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [ + functionDescriptionPart, + "global", + ]); + constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [ + constantDescriptionPart, + "global", + ]); } else if (scopeDescription === SpecialScope.Module) { - functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [functionDescriptionPart, "module"]); - constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [constantDescriptionPart, "module"]); + functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [ + functionDescriptionPart, + "module", + ]); + constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [ + constantDescriptionPart, + "module", + ]); } else { - functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [functionDescriptionPart, scopeDescription]); - constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [constantDescriptionPart, scopeDescription]); + functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [ + functionDescriptionPart, + scopeDescription, + ]); + constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [ + constantDescriptionPart, + scopeDescription, + ]); } // Customize the phrasing for the innermost scope to increase clarity. if (i === 0 && !isClassLike(scope)) { - constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_enclosing_scope), [constantDescriptionPart]); + constantDescription = formatStringFromArgs( + getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_enclosing_scope), + [constantDescriptionPart], + ); } return { @@ -957,7 +1082,10 @@ function getPossibleExtractions(targetRange: TargetRange, context: RefactorConte return extractions; } -function getPossibleExtractionsWorker(targetRange: TargetRange, context: RefactorContext): { readonly scopes: Scope[], readonly readsAndWrites: ReadsAndWrites } { +function getPossibleExtractionsWorker( + targetRange: TargetRange, + context: RefactorContext, +): { readonly scopes: Scope[]; readonly readsAndWrites: ReadsAndWrites; } { const { file: sourceFile } = context; const scopes = collectEnclosingScopes(targetRange); @@ -968,7 +1096,8 @@ function getPossibleExtractionsWorker(targetRange: TargetRange, context: Refacto enclosingTextRange, sourceFile, context.program.getTypeChecker(), - context.cancellationToken!); + context.cancellationToken!, + ); return { scopes, readsAndWrites }; } @@ -976,8 +1105,8 @@ function getDescriptionForFunctionInScope(scope: Scope): string { return isFunctionLikeDeclaration(scope) ? "inner function" : isClassLike(scope) - ? "method" - : "function"; + ? "method" + : "function"; } function getDescriptionForConstantInScope(scope: Scope): string { return isClassLike(scope) @@ -1031,8 +1160,8 @@ function extractFunctionInScope( { usages: usagesInScope, typeParameterUsages, substitutions }: ScopeUsages, exposedVariableDeclarations: readonly VariableDeclaration[], range: TargetRange, - context: RefactorContext): RefactorEditInfo { - + context: RefactorContext, +): RefactorEditInfo { const checker = context.program.getTypeChecker(); const scriptTarget = getEmitScriptTarget(context.program.getCompilerOptions()); const importAdder = codefix.createImportAdder(context.file, context.program, context.preferences, context.host); @@ -1054,7 +1183,14 @@ function extractFunctionInScope( let type = checker.getTypeOfSymbolAtLocation(usage.symbol, usage.node); // Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {" type = checker.getBaseTypeOfLiteralType(type); - typeNode = codefix.typeToAutoImportableTypeNode(checker, importAdder, type, scope, scriptTarget, NodeBuilderFlags.NoTruncation); + typeNode = codefix.typeToAutoImportableTypeNode( + checker, + importAdder, + type, + scope, + scriptTarget, + NodeBuilderFlags.NoTruncation, + ); } const paramDecl = factory.createParameterDeclaration( @@ -1062,7 +1198,7 @@ function extractFunctionInScope( /*dotDotDotToken*/ undefined, /*name*/ name, /*questionToken*/ undefined, - typeNode + typeNode, ); parameters.push(paramDecl); if (usage.usage === Usage.Write) { @@ -1071,12 +1207,19 @@ function extractFunctionInScope( callArguments.push(factory.createIdentifier(name)); }); - const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values(), type => ({ type, declaration: getFirstDeclarationBeforePosition(type, context.startPosition) })); + const typeParametersAndDeclarations = arrayFrom( + typeParameterUsages.values(), + type => ({ type, declaration: getFirstDeclarationBeforePosition(type, context.startPosition) }), + ); const sortedTypeParametersAndDeclarations = typeParametersAndDeclarations.sort(compareTypesByDeclarationOrder); - const typeParameters: readonly TypeParameterDeclaration[] | undefined = sortedTypeParametersAndDeclarations.length === 0 - ? undefined - : mapDefined(sortedTypeParametersAndDeclarations, ({ declaration }) => declaration as TypeParameterDeclaration); + const typeParameters: readonly TypeParameterDeclaration[] | undefined = + sortedTypeParametersAndDeclarations.length === 0 + ? undefined + : mapDefined( + sortedTypeParametersAndDeclarations, + ({ declaration }) => declaration as TypeParameterDeclaration, + ); // Strictly speaking, we should check whether each name actually binds to the appropriate type // parameter. In cases of shadowing, they may not. @@ -1091,7 +1234,13 @@ function extractFunctionInScope( returnType = checker.typeToTypeNode(contextualType!, scope, NodeBuilderFlags.NoTruncation); // TODO: GH#18217 } - const { body, returnValueProperty } = transformFunctionBody(node, exposedVariableDeclarations, writes, substitutions, !!(range.facts & RangeFacts.HasReturn)); + const { body, returnValueProperty } = transformFunctionBody( + node, + exposedVariableDeclarations, + writes, + substitutions, + !!(range.facts & RangeFacts.HasReturn), + ); suppressLeadingAndTrailingTrivia(body); let newFunction: MethodDeclaration | FunctionDeclaration; @@ -1115,7 +1264,7 @@ function extractFunctionInScope( typeParameters, parameters, returnType, - body + body, ); } else { @@ -1129,10 +1278,10 @@ function extractFunctionInScope( checker.typeToTypeNode( checker.getTypeAtLocation(range.thisNode!), scope, - NodeBuilderFlags.NoTruncation + NodeBuilderFlags.NoTruncation, ), /*initializer*/ undefined, - ) + ), ); } newFunction = factory.createFunctionDeclaration( @@ -1142,7 +1291,7 @@ function extractFunctionInScope( typeParameters, parameters, returnType, - body + body, ); } @@ -1168,10 +1317,11 @@ function extractFunctionInScope( let call: Expression = factory.createCallExpression( callThis ? factory.createPropertyAccessExpression( called, - "call" + "call", ) : called, callTypeArguments, // Note that no attempt is made to take advantage of type argument inference - callArguments); + callArguments, + ); if (range.facts & RangeFacts.IsGenerator) { call = factory.createYieldExpression(factory.createToken(SyntaxKind.AsteriskToken), call); } @@ -1195,8 +1345,15 @@ function extractFunctionInScope( newNodes.push(factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration(getSynthesizedDeepClone(variableDeclaration.name), /*exclamationToken*/ undefined, /*type*/ getSynthesizedDeepClone(variableDeclaration.type), /*initializer*/ call)], - variableDeclaration.parent.flags))); + [factory.createVariableDeclaration( + getSynthesizedDeepClone(variableDeclaration.name), + /*exclamationToken*/ undefined, + /*type*/ getSynthesizedDeepClone(variableDeclaration.type), + /*initializer*/ call, + )], + variableDeclaration.parent.flags, + ), + )); } else { // Declaring multiple variables / return properties: @@ -1209,24 +1366,28 @@ function extractFunctionInScope( bindingElements.push(factory.createBindingElement( /*dotDotDotToken*/ undefined, /*propertyName*/ undefined, - /*name*/ getSynthesizedDeepClone(variableDeclaration.name))); + /*name*/ getSynthesizedDeepClone(variableDeclaration.name), + )); // Being returned through an object literal will have widened the type. const variableType: TypeNode | undefined = checker.typeToTypeNode( checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(variableDeclaration)), scope, - NodeBuilderFlags.NoTruncation); + NodeBuilderFlags.NoTruncation, + ); typeElements.push(factory.createPropertySignature( /*modifiers*/ undefined, /*name*/ variableDeclaration.symbol.name, /*questionToken*/ undefined, - /*type*/ variableType)); + /*type*/ variableType, + )); sawExplicitType = sawExplicitType || variableDeclaration.type !== undefined; commonNodeFlags = commonNodeFlags & variableDeclaration.parent.flags; } - const typeLiteral: TypeLiteralNode | undefined = sawExplicitType ? factory.createTypeLiteralNode(typeElements) : undefined; + const typeLiteral: TypeLiteralNode | undefined = sawExplicitType + ? factory.createTypeLiteralNode(typeElements) : undefined; if (typeLiteral) { setEmitFlags(typeLiteral, EmitFlags.SingleLine); } @@ -1238,8 +1399,11 @@ function extractFunctionInScope( factory.createObjectBindingPattern(bindingElements), /*exclamationToken*/ undefined, /*type*/ typeLiteral, - /*initializer*/call)], - commonNodeFlags))); + /*initializer*/ call, + )], + commonNodeFlags, + ), + )); } } else if (exposedVariableDeclarations.length || writes) { @@ -1254,8 +1418,14 @@ function extractFunctionInScope( newNodes.push(factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration(variableDeclaration.symbol.name, /*exclamationToken*/ undefined, getTypeDeepCloneUnionUndefined(variableDeclaration.type))], - flags))); + [factory.createVariableDeclaration( + variableDeclaration.symbol.name, + /*exclamationToken*/ undefined, + getTypeDeepCloneUnionUndefined(variableDeclaration.type), + )], + flags, + ), + )); } } @@ -1264,8 +1434,14 @@ function extractFunctionInScope( newNodes.push(factory.createVariableStatement( /*modifiers*/ undefined, factory.createVariableDeclarationList( - [factory.createVariableDeclaration(returnValueProperty, /*exclamationToken*/ undefined, getTypeDeepCloneUnionUndefined(returnType))], - NodeFlags.Let))); + [factory.createVariableDeclaration( + returnValueProperty, + /*exclamationToken*/ undefined, + getTypeDeepCloneUnionUndefined(returnType), + )], + NodeFlags.Let, + ), + )); } const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); @@ -1289,7 +1465,11 @@ function extractFunctionInScope( // emit e.g. // { a, b, __return } = newFunction(a, b); // return __return; - newNodes.push(factory.createExpressionStatement(factory.createAssignment(factory.createObjectLiteralExpression(assignments), call))); + newNodes.push( + factory.createExpressionStatement( + factory.createAssignment(factory.createObjectLiteralExpression(assignments), call), + ), + ); if (returnValueProperty) { newNodes.push(factory.createReturnStatement(factory.createIdentifier(returnValueProperty))); } @@ -1346,13 +1526,15 @@ function extractConstantInScope( scope: Scope, { substitutions }: ScopeUsages, rangeFacts: RangeFacts, - context: RefactorContext): RefactorEditInfo { - + context: RefactorContext, +): RefactorEditInfo { const checker = context.program.getTypeChecker(); // Make a unique name for the extracted variable const file = scope.getSourceFile(); - const localNameText = isPropertyAccessExpression(node) && !isClassLike(scope) && !checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ false) && !isPrivateIdentifier(node.name) && !identifierToKeywordKind(node.name) + const localNameText = isPropertyAccessExpression(node) && !isClassLike(scope) + && !checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ false) + && !isPrivateIdentifier(node.name) && !identifierToKeywordKind(node.name) ? node.name.text : getUniqueName(isClassLike(scope) ? "newProperty" : "newLocal", file); const isJS = isInJSFile(scope); @@ -1383,13 +1565,15 @@ function extractConstantInScope( localNameText, /*questionOrExclamationToken*/ undefined, variableType, - initializer); + initializer, + ); let localReference: Expression = factory.createPropertyAccessExpression( rangeFacts & RangeFacts.InStaticRegion ? factory.createIdentifier(scope.name!.getText()) // TODO: GH#18217 : factory.createThis(), - factory.createIdentifier(localNameText)); + factory.createIdentifier(localNameText), + ); if (isInJSXContent(node)) { localReference = factory.createJsxExpression(/*dotDotDotToken*/ undefined, localReference); @@ -1404,7 +1588,12 @@ function extractConstantInScope( changeTracker.replaceNode(context.file, node, localReference); } else { - const newVariableDeclaration = factory.createVariableDeclaration(localNameText, /*exclamationToken*/ undefined, variableType, initializer); + const newVariableDeclaration = factory.createVariableDeclaration( + localNameText, + /*exclamationToken*/ undefined, + variableType, + initializer, + ); // If the node is part of an initializer in a list of variable declarations, insert a new // variable declaration into the list (in case it depends on earlier ones). @@ -1425,13 +1614,15 @@ function extractConstantInScope( // replace the statement with the declaration. const newVariableStatement = factory.createVariableStatement( /*modifiers*/ undefined, - factory.createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const)); + factory.createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const), + ); changeTracker.replaceNode(context.file, node.parent, newVariableStatement); } else { const newVariableStatement = factory.createVariableStatement( /*modifiers*/ undefined, - factory.createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const)); + factory.createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const), + ); // Declare const nodeToInsertBefore = getNodeToInsertConstantBefore(node, scope); @@ -1439,7 +1630,12 @@ function extractConstantInScope( changeTracker.insertNodeAtTopOfFile(context.file, newVariableStatement, /*blankLineBetween*/ false); } else { - changeTracker.insertNodeBefore(context.file, nodeToInsertBefore, newVariableStatement, /*blankLineBetween*/ false); + changeTracker.insertNodeBefore( + context.file, + nodeToInsertBefore, + newVariableStatement, + /*blankLineBetween*/ false, + ); } // Consume @@ -1465,11 +1661,16 @@ function extractConstantInScope( const renameLocation = getRenameLocation(edits, renameFilename, localNameText, /*preferLastLocation*/ true); return { renameFilename, renameLocation, edits }; - function transformFunctionInitializerAndType(variableType: TypeNode | undefined, initializer: Expression): { variableType: TypeNode | undefined, initializer: Expression } { + function transformFunctionInitializerAndType( + variableType: TypeNode | undefined, + initializer: Expression, + ): { variableType: TypeNode | undefined; initializer: Expression; } { // If no contextual type exists there is nothing to transfer to the function signature if (variableType === undefined) return { variableType, initializer }; // Only do this for function expressions and arrow functions that are not generic - if (!isFunctionExpression(initializer) && !isArrowFunction(initializer) || !!initializer.typeParameters) return { variableType, initializer }; + if (!isFunctionExpression(initializer) && !isArrowFunction(initializer) || !!initializer.typeParameters) { + return { variableType, initializer }; + } const functionType = checker.getTypeAtLocation(node); const functionSignature = singleOrUndefined(checker.getSignaturesOfType(functionType, SignatureKind.Call)); @@ -1489,9 +1690,17 @@ function extractConstantInScope( const paramType = checker.getTypeAtLocation(p); if (paramType === checker.getAnyType()) hasAny = true; - parameters.push(factory.updateParameterDeclaration(p, - p.modifiers, p.dotDotDotToken, - p.name, p.questionToken, p.type || checker.typeToTypeNode(paramType, scope, NodeBuilderFlags.NoTruncation), p.initializer)); + parameters.push( + factory.updateParameterDeclaration( + p, + p.modifiers, + p.dotDotDotToken, + p.name, + p.questionToken, + p.type || checker.typeToTypeNode(paramType, scope, NodeBuilderFlags.NoTruncation), + p.initializer, + ), + ); } } // If a parameter was inferred as any we skip adding function parameters at all. @@ -1500,33 +1709,51 @@ function extractConstantInScope( if (hasAny) return { variableType, initializer }; variableType = undefined; if (isArrowFunction(initializer)) { - initializer = factory.updateArrowFunction(initializer, canHaveModifiers(node) ? getModifiers(node) : undefined, initializer.typeParameters, + initializer = factory.updateArrowFunction( + initializer, + canHaveModifiers(node) ? getModifiers(node) : undefined, + initializer.typeParameters, parameters, - initializer.type || checker.typeToTypeNode(functionSignature.getReturnType(), scope, NodeBuilderFlags.NoTruncation), + initializer.type + || checker.typeToTypeNode(functionSignature.getReturnType(), scope, NodeBuilderFlags.NoTruncation), initializer.equalsGreaterThanToken, - initializer.body); + initializer.body, + ); } else { if (functionSignature && !!functionSignature.thisParameter) { const firstParameter = firstOrUndefined(parameters); // If the function signature has a this parameter and if the first defined parameter is not the this parameter, we must add it // Note: If this parameter was already there, it would have been previously updated with the type if not type was present - if ((!firstParameter || (isIdentifier(firstParameter.name) && firstParameter.name.escapedText !== "this"))) { + if ( + (!firstParameter + || (isIdentifier(firstParameter.name) && firstParameter.name.escapedText !== "this")) + ) { const thisType = checker.getTypeOfSymbolAtLocation(functionSignature.thisParameter, node); - parameters.splice(0, 0, factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - "this", - /*questionToken*/ undefined, - checker.typeToTypeNode(thisType, scope, NodeBuilderFlags.NoTruncation) - )); + parameters.splice( + 0, + 0, + factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + "this", + /*questionToken*/ undefined, + checker.typeToTypeNode(thisType, scope, NodeBuilderFlags.NoTruncation), + ), + ); } } - initializer = factory.updateFunctionExpression(initializer, canHaveModifiers(node) ? getModifiers(node) : undefined, initializer.asteriskToken, - initializer.name, initializer.typeParameters, + initializer = factory.updateFunctionExpression( + initializer, + canHaveModifiers(node) ? getModifiers(node) : undefined, + initializer.asteriskToken, + initializer.name, + initializer.typeParameters, parameters, - initializer.type || checker.typeToTypeNode(functionSignature.getReturnType(), scope, NodeBuilderFlags.NoTruncation), - initializer.body); + initializer.type + || checker.typeToTypeNode(functionSignature.getReturnType(), scope, NodeBuilderFlags.NoTruncation), + initializer.body, + ); } return { variableType, initializer }; } @@ -1535,11 +1762,12 @@ function extractConstantInScope( function getContainingVariableDeclarationIfInList(node: Node, scope: Scope) { let prevNode; while (node !== undefined && node !== scope) { - if (isVariableDeclaration(node) && - node.initializer === prevNode && - isVariableDeclarationList(node.parent) && - node.parent.declarations.length > 1) { - + if ( + isVariableDeclaration(node) + && node.initializer === prevNode + && isVariableDeclarationList(node.parent) + && node.parent.declarations.length > 1 + ) { return node; } @@ -1554,7 +1782,9 @@ function getFirstDeclarationBeforePosition(type: Type, position: number): Declar const symbol = type.symbol; if (symbol && symbol.declarations) { for (const declaration of symbol.declarations) { - if ((firstDeclaration === undefined || declaration.pos < firstDeclaration.pos) && declaration.pos < position) { + if ( + (firstDeclaration === undefined || declaration.pos < firstDeclaration.pos) && declaration.pos < position + ) { firstDeclaration = declaration; } } @@ -1564,20 +1794,22 @@ function getFirstDeclarationBeforePosition(type: Type, position: number): Declar } function compareTypesByDeclarationOrder( - { type: type1, declaration: declaration1 }: { type: Type, declaration?: Declaration }, - { type: type2, declaration: declaration2 }: { type: Type, declaration?: Declaration }) { - + { type: type1, declaration: declaration1 }: { type: Type; declaration?: Declaration; }, + { type: type2, declaration: declaration2 }: { type: Type; declaration?: Declaration; }, +) { return compareProperties(declaration1, declaration2, "pos", compareValues) || compareStringsCaseSensitive( type1.symbol ? type1.symbol.getName() : "", - type2.symbol ? type2.symbol.getName() : "") + type2.symbol ? type2.symbol.getName() : "", + ) || compareValues(type1.id, type2.id); } function getCalledExpression(scope: Node, range: TargetRange, functionNameText: string): Expression { const functionReference = factory.createIdentifier(functionNameText); if (isClassLike(scope)) { - const lhs = range.facts & RangeFacts.InStaticRegion ? factory.createIdentifier(scope.name!.text) : factory.createThis(); // TODO: GH#18217 + const lhs = range.facts & RangeFacts.InStaticRegion ? factory.createIdentifier(scope.name!.text) + : factory.createThis(); // TODO: GH#18217 return factory.createPropertyAccessExpression(lhs, functionReference); } else { @@ -1585,7 +1817,13 @@ function getCalledExpression(scope: Node, range: TargetRange, functionNameText: } } -function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly VariableDeclaration[], writes: readonly UsageEntry[] | undefined, substitutions: ReadonlyMap, hasReturn: boolean): { body: Block, returnValueProperty: string | undefined } { +function transformFunctionBody( + body: Node, + exposedVariableDeclarations: readonly VariableDeclaration[], + writes: readonly UsageEntry[] | undefined, + substitutions: ReadonlyMap, + hasReturn: boolean, +): { body: Block; returnValueProperty: string | undefined; } { const hasWritesOrVariableDeclarations = writes !== undefined || exposedVariableDeclarations.length > 0; if (isBlock(body) && !hasWritesOrVariableDeclarations && substitutions.size === 0) { // already block, no declarations or writes to propagate back, no substitutions - can use node as is @@ -1593,19 +1831,27 @@ function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly } let returnValueProperty: string | undefined; let ignoreReturns = false; - const statements = factory.createNodeArray(isBlock(body) ? body.statements.slice(0) : [isStatement(body) ? body : factory.createReturnStatement(skipParentheses(body as Expression))]); + const statements = factory.createNodeArray( + isBlock(body) ? body.statements.slice(0) + : [isStatement(body) ? body : factory.createReturnStatement(skipParentheses(body as Expression))], + ); // rewrite body if either there are writes that should be propagated back via return statements or there are substitutions if (hasWritesOrVariableDeclarations || substitutions.size) { const rewrittenStatements = visitNodes(statements, visitor, isStatement).slice(); if (hasWritesOrVariableDeclarations && !hasReturn && isStatement(body)) { // add return at the end to propagate writes back in case if control flow falls out of the function body // it is ok to know that range has at least one return since it we only allow unconditional returns - const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); + const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations( + exposedVariableDeclarations, + writes, + ); if (assignments.length === 1) { rewrittenStatements.push(factory.createReturnStatement(assignments[0].name)); } else { - rewrittenStatements.push(factory.createReturnStatement(factory.createObjectLiteralExpression(assignments))); + rewrittenStatements.push( + factory.createReturnStatement(factory.createObjectLiteralExpression(assignments)), + ); } } return { body: factory.createBlock(rewrittenStatements, /*multiLine*/ true), returnValueProperty }; @@ -1616,12 +1862,20 @@ function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly function visitor(node: Node): VisitResult { if (!ignoreReturns && isReturnStatement(node) && hasWritesOrVariableDeclarations) { - const assignments: ObjectLiteralElementLike[] = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes); + const assignments: ObjectLiteralElementLike[] = getPropertyAssignmentsForWritesAndVariableDeclarations( + exposedVariableDeclarations, + writes, + ); if (node.expression) { if (!returnValueProperty) { returnValueProperty = "__return"; } - assignments.unshift(factory.createPropertyAssignment(returnValueProperty, visitNode(node.expression, visitor, isExpression))); + assignments.unshift( + factory.createPropertyAssignment( + returnValueProperty, + visitNode(node.expression, visitor, isExpression), + ), + ); } if (assignments.length === 1) { return factory.createReturnStatement(assignments[0].name as Expression); @@ -1634,7 +1888,8 @@ function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly const oldIgnoreReturns = ignoreReturns; ignoreReturns = ignoreReturns || isFunctionLikeDeclaration(node) || isClassLike(node); const substitution = substitutions.get(getNodeId(node).toString()); - const result = substitution ? getSynthesizedDeepClone(substitution) : visitEachChild(node, visitor, nullTransformationContext); + const result = substitution ? getSynthesizedDeepClone(substitution) + : visitEachChild(node, visitor, nullTransformationContext); ignoreReturns = oldIgnoreReturns; return result; } @@ -1648,7 +1903,8 @@ function transformConstantInitializer(initializer: Expression, substitutions: Re function visitor(node: Node): VisitResult { const substitution = substitutions.get(getNodeId(node).toString()); - return substitution ? getSynthesizedDeepClone(substitution) : visitEachChild(node, visitor, nullTransformationContext); + return substitution ? getSynthesizedDeepClone(substitution) + : visitEachChild(node, visitor, nullTransformationContext); } } @@ -1677,8 +1933,10 @@ function getStatementsOrClassElements(scope: Scope): readonly Statement[] | read * Otherwise, return `undefined`. */ function getNodeToInsertFunctionBefore(minPos: number, scope: Scope): Statement | ClassElement | undefined { - return find(getStatementsOrClassElements(scope), child => - child.pos >= minPos && isFunctionLikeDeclaration(child) && !isConstructorDeclaration(child)); + return find( + getStatementsOrClassElements(scope), + child => child.pos >= minPos && isFunctionLikeDeclaration(child) && !isConstructorDeclaration(child), + ); } function getNodeToInsertPropertyBefore(maxPos: number, scope: ClassLikeDeclaration): ClassElement { @@ -1717,7 +1975,7 @@ function getNodeToInsertConstantBefore(node: Node, scope: Scope): Statement { } } - for (let curr = (prevScope || node).parent; ; curr = curr.parent) { + for (let curr = (prevScope || node).parent;; curr = curr.parent) { if (isBlockLike(curr)) { let prevStatement: Statement | undefined; for (const statement of curr.statements) { @@ -1743,17 +2001,20 @@ function getNodeToInsertConstantBefore(node: Node, scope: Scope): Statement { function getPropertyAssignmentsForWritesAndVariableDeclarations( exposedVariableDeclarations: readonly VariableDeclaration[], - writes: readonly UsageEntry[] | undefined + writes: readonly UsageEntry[] | undefined, ): ShorthandPropertyAssignment[] { - const variableAssignments = map(exposedVariableDeclarations, v => factory.createShorthandPropertyAssignment(v.symbol.name)); + const variableAssignments = map( + exposedVariableDeclarations, + v => factory.createShorthandPropertyAssignment(v.symbol.name), + ); const writeAssignments = map(writes, w => factory.createShorthandPropertyAssignment(w.symbol.name)); // TODO: GH#18217 `variableAssignments` not possibly undefined! return variableAssignments === undefined ? writeAssignments! : writeAssignments === undefined - ? variableAssignments - : variableAssignments.concat(writeAssignments); + ? variableAssignments + : variableAssignments.concat(writeAssignments); } function isReadonlyArray(v: any): v is readonly any[] { @@ -1779,7 +2040,7 @@ const enum Usage { // value should be passed to extracted method Read = 1, // value should be passed to extracted method and propagated back - Write = 2 + Write = 2, } interface UsageEntry { @@ -1807,8 +2068,8 @@ function collectReadsAndWrites( enclosingTextRange: TextRange, sourceFile: SourceFile, checker: TypeChecker, - cancellationToken: CancellationToken): ReadsAndWrites { - + cancellationToken: CancellationToken, +): ReadsAndWrites { const allTypeParameterUsages = new Map(); // Key is type ID const usagesPerScope: ScopeUsages[] = []; const substitutionsPerScope: Map[] = []; @@ -1822,8 +2083,8 @@ function collectReadsAndWrites( const expression = !isReadonlyArray(targetRange.range) ? targetRange.range : targetRange.range.length === 1 && isExpressionStatement(targetRange.range[0]) - ? targetRange.range[0].expression - : undefined; + ? targetRange.range[0].expression + : undefined; let expressionDiagnostic: Diagnostic | undefined; if (expression === undefined) { @@ -1838,7 +2099,11 @@ function collectReadsAndWrites( // initialize results for (const scope of scopes) { - usagesPerScope.push({ usages: new Map(), typeParameterUsages: new Map(), substitutions: new Map() }); + usagesPerScope.push({ + usages: new Map(), + typeParameterUsages: new Map(), + substitutions: new Map(), + }); substitutionsPerScope.push(new Map()); functionErrorsPerScope.push([]); @@ -1920,11 +2185,15 @@ function collectReadsAndWrites( // local will actually be declared at the same level as the extracted expression). if (i > 0 && (scopeUsages.usages.size > 0 || scopeUsages.typeParameterUsages.size > 0)) { const errorNode = isReadonlyArray(targetRange.range) ? targetRange.range[0] : targetRange.range; - constantErrorsPerScope[i].push(createDiagnosticForNode(errorNode, Messages.cannotAccessVariablesFromNestedScopes)); + constantErrorsPerScope[i].push( + createDiagnosticForNode(errorNode, Messages.cannotAccessVariablesFromNestedScopes), + ); } if (targetRange.facts & RangeFacts.UsesThisInFunction && isClassLike(scopes[i])) { - functionErrorsPerScope[i].push(createDiagnosticForNode(targetRange.thisNode!, Messages.cannotExtractFunctionsContainingThisToMethod)); + functionErrorsPerScope[i].push( + createDiagnosticForNode(targetRange.thisNode!, Messages.cannotExtractFunctionsContainingThisToMethod), + ); } let hasWrite = false; @@ -1932,16 +2201,21 @@ function collectReadsAndWrites( usagesPerScope[i].usages.forEach(value => { if (value.usage === Usage.Write) { hasWrite = true; - if (value.symbol.flags & SymbolFlags.ClassMember && - value.symbol.valueDeclaration && - hasEffectiveModifier(value.symbol.valueDeclaration, ModifierFlags.Readonly)) { + if ( + value.symbol.flags & SymbolFlags.ClassMember + && value.symbol.valueDeclaration + && hasEffectiveModifier(value.symbol.valueDeclaration, ModifierFlags.Readonly) + ) { readonlyClassPropertyWrite = value.symbol.valueDeclaration; } } }); // If an expression was extracted, then there shouldn't have been any variable declarations. - Debug.assert(isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0, "No variable declarations expected if something was extracted"); + Debug.assert( + isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0, + "No variable declarations expected if something was extracted", + ); if (hasWrite && !isReadonlyArray(targetRange.range)) { const diag = createDiagnosticForNode(targetRange.range, Messages.cannotWriteInExpression); @@ -1949,12 +2223,18 @@ function collectReadsAndWrites( constantErrorsPerScope[i].push(diag); } else if (readonlyClassPropertyWrite && i > 0) { - const diag = createDiagnosticForNode(readonlyClassPropertyWrite, Messages.cannotExtractReadonlyPropertyInitializerOutsideConstructor); + const diag = createDiagnosticForNode( + readonlyClassPropertyWrite, + Messages.cannotExtractReadonlyPropertyInitializerOutsideConstructor, + ); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } else if (firstExposedNonVariableDeclaration) { - const diag = createDiagnosticForNode(firstExposedNonVariableDeclaration, Messages.cannotExtractExportedEntity); + const diag = createDiagnosticForNode( + firstExposedNonVariableDeclaration, + Messages.cannotExtractExportedEntity, + ); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } @@ -1963,7 +2243,10 @@ function collectReadsAndWrites( return { target, usagesPerScope, functionErrorsPerScope, constantErrorsPerScope, exposedVariableDeclarations }; function isInGenericContext(node: Node) { - return !!findAncestor(node, n => isDeclarationWithTypeParameters(n) && getEffectiveTypeParameterDeclarations(n).length !== 0); + return !!findAncestor( + node, + n => isDeclarationWithTypeParameters(n) && getEffectiveTypeParameterDeclarations(n).length !== 0, + ); } function recordTypeParameterUsages(type: Type) { @@ -2075,7 +2358,10 @@ function collectReadsAndWrites( if (targetRange.facts & RangeFacts.IsGenerator && usage === Usage.Write) { // this is write to a reference located outside of the target scope and range is extracted into generator // currently this is unsupported scenario - const diag = createDiagnosticForNode(identifier, Messages.cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators); + const diag = createDiagnosticForNode( + identifier, + Messages.cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators, + ); for (const errors of functionErrorsPerScope) { errors.push(diag); } @@ -2090,7 +2376,11 @@ function collectReadsAndWrites( continue; } if (!substitutionsPerScope[i].has(symbolId)) { - const substitution = tryReplaceWithQualifiedNameOrPropertyAccess(symbol.exportSymbol || symbol, scope, isTypeName); + const substitution = tryReplaceWithQualifiedNameOrPropertyAccess( + symbol.exportSymbol || symbol, + scope, + isTypeName, + ); if (substitution) { substitutionsPerScope[i].set(symbolId, substitution); } @@ -2113,7 +2403,10 @@ function collectReadsAndWrites( function checkForUsedDeclarations(node: Node) { // If this node is entirely within the original extraction range, we don't need to do anything. - if (node === targetRange.range || (isReadonlyArray(targetRange.range) && targetRange.range.indexOf(node as Statement) >= 0)) { + if ( + node === targetRange.range + || (isReadonlyArray(targetRange.range) && targetRange.range.indexOf(node as Statement) >= 0) + ) { return; } @@ -2148,12 +2441,17 @@ function collectReadsAndWrites( function getSymbolReferencedByIdentifier(identifier: Identifier) { // If the identifier is both a property name and its value, we're only interested in its value // (since the name is a declaration and will be included in the extracted range). - return identifier.parent && isShorthandPropertyAssignment(identifier.parent) && identifier.parent.name === identifier + return identifier.parent && isShorthandPropertyAssignment(identifier.parent) + && identifier.parent.name === identifier ? checker.getShorthandAssignmentValueSymbol(identifier.parent) : checker.getSymbolAtLocation(identifier); } - function tryReplaceWithQualifiedNameOrPropertyAccess(symbol: Symbol | undefined, scopeDecl: Node, isTypeNode: boolean): PropertyAccessExpression | EntityName | undefined { + function tryReplaceWithQualifiedNameOrPropertyAccess( + symbol: Symbol | undefined, + scopeDecl: Node, + isTypeNode: boolean, + ): PropertyAccessExpression | EntityName | undefined { if (!symbol) { return undefined; } @@ -2191,8 +2489,8 @@ function isExtractableExpression(node: Node): boolean { switch (node.kind) { case SyntaxKind.StringLiteral: - return parent.kind !== SyntaxKind.ImportDeclaration && - parent.kind !== SyntaxKind.ImportSpecifier; + return parent.kind !== SyntaxKind.ImportDeclaration + && parent.kind !== SyntaxKind.ImportSpecifier; case SyntaxKind.SpreadElement: case SyntaxKind.ObjectBindingPattern: @@ -2200,9 +2498,9 @@ function isExtractableExpression(node: Node): boolean { return false; case SyntaxKind.Identifier: - return parent.kind !== SyntaxKind.BindingElement && - parent.kind !== SyntaxKind.ImportSpecifier && - parent.kind !== SyntaxKind.ExportSpecifier; + return parent.kind !== SyntaxKind.BindingElement + && parent.kind !== SyntaxKind.ImportSpecifier + && parent.kind !== SyntaxKind.ExportSpecifier; } return true; } @@ -2220,8 +2518,9 @@ function isBlockLike(node: Node): node is BlockLike { } function isInJSXContent(node: Node) { - return isStringLiteralJsxAttribute(node) || - (isJsxElement(node) || isJsxSelfClosingElement(node) || isJsxFragment(node)) && (isJsxElement(node.parent) || isJsxFragment(node.parent)); + return isStringLiteralJsxAttribute(node) + || (isJsxElement(node) || isJsxSelfClosingElement(node) || isJsxFragment(node)) + && (isJsxElement(node.parent) || isJsxFragment(node.parent)); } function isStringLiteralJsxAttribute(node: Node): node is StringLiteral { diff --git a/src/services/refactors/extractType.ts b/src/services/refactors/extractType.ts index 02e5f10ba22d9..fcff952d12c05 100644 --- a/src/services/refactors/extractType.ts +++ b/src/services/refactors/extractType.ts @@ -85,14 +85,14 @@ const extractToInterfaceAction = { const extractToTypeDefAction = { name: "Extract to typedef", description: getLocaleSpecificMessage(Diagnostics.Extract_to_typedef), - kind: "refactor.extract.typedef" + kind: "refactor.extract.typedef", }; registerRefactor(refactorName, { kinds: [ extractToTypeAliasAction.kind, extractToInterfaceAction.kind, - extractToTypeDefAction.kind + extractToTypeDefAction.kind, ], getAvailableActions: function getRefactorActionsToExtractType(context): readonly ApplicableRefactorInfo[] { const info = getRangeToExtract(context, context.triggerReason === "invoked"); @@ -102,8 +102,9 @@ registerRefactor(refactorName, { return [{ name: refactorName, description: getLocaleSpecificMessage(Diagnostics.Extract_type), - actions: info.isJS ? - [extractToTypeDefAction] : append([extractToTypeAliasAction], info.typeElements && extractToInterfaceAction) + actions: info.isJS + ? [extractToTypeDefAction] + : append([extractToTypeAliasAction], info.typeElements && extractToInterfaceAction), }]; } @@ -115,7 +116,7 @@ registerRefactor(refactorName, { { ...extractToTypeDefAction, notApplicableReason: info.error }, { ...extractToTypeAliasAction, notApplicableReason: info.error }, { ...extractToInterfaceAction, notApplicableReason: info.error }, - ] + ], }]; } @@ -146,49 +147,78 @@ registerRefactor(refactorName, { const renameFilename = file.fileName; const renameLocation = getRenameLocation(edits, renameFilename, name, /*preferLastLocation*/ false); return { edits, renameFilename, renameLocation }; - } + }, }); interface TypeAliasInfo { - isJS: boolean; selection: TypeNode; enclosingNode: Node; typeParameters: readonly TypeParameterDeclaration[]; typeElements?: readonly TypeElement[]; + isJS: boolean; + selection: TypeNode; + enclosingNode: Node; + typeParameters: readonly TypeParameterDeclaration[]; + typeElements?: readonly TypeElement[]; } interface InterfaceInfo { - isJS: boolean; selection: TypeNode; enclosingNode: Node; typeParameters: readonly TypeParameterDeclaration[]; typeElements: readonly TypeElement[]; + isJS: boolean; + selection: TypeNode; + enclosingNode: Node; + typeParameters: readonly TypeParameterDeclaration[]; + typeElements: readonly TypeElement[]; } type ExtractInfo = TypeAliasInfo | InterfaceInfo; -function getRangeToExtract(context: RefactorContext, considerEmptySpans = true): ExtractInfo | RefactorErrorInfo | undefined { +function getRangeToExtract( + context: RefactorContext, + considerEmptySpans = true, +): ExtractInfo | RefactorErrorInfo | undefined { const { file, startPosition } = context; const isJS = isSourceFileJS(file); const current = getTokenAtPosition(file, startPosition); const range = createTextRangeFromSpan(getRefactorContextSpan(context)); const cursorRequest = range.pos === range.end && considerEmptySpans; - const selection = findAncestor(current, (node => node.parent && isTypeNode(node) && !rangeContainsSkipTrivia(range, node.parent, file) && - (cursorRequest || nodeOverlapsWithStartEnd(current, file, range.pos, range.end)))); - if (!selection || !isTypeNode(selection)) return { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) }; + const selection = findAncestor( + current, + node => + node.parent && isTypeNode(node) && !rangeContainsSkipTrivia(range, node.parent, file) + && (cursorRequest || nodeOverlapsWithStartEnd(current, file, range.pos, range.end)), + ); + if (!selection || !isTypeNode(selection)) { + return { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) }; + } const checker = context.program.getTypeChecker(); const enclosingNode = getEnclosingNode(selection, isJS); - if (enclosingNode === undefined) return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }; + if (enclosingNode === undefined) { + return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }; + } const typeParameters = collectTypeParameters(checker, selection, enclosingNode, file); - if (!typeParameters) return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }; + if (!typeParameters) { + return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }; + } const typeElements = flattenTypeLiteralNodeReference(checker, selection); return { isJS, selection, enclosingNode, typeParameters, typeElements }; } -function flattenTypeLiteralNodeReference(checker: TypeChecker, node: TypeNode | undefined): readonly TypeElement[] | undefined { +function flattenTypeLiteralNodeReference( + checker: TypeChecker, + node: TypeNode | undefined, +): readonly TypeElement[] | undefined { if (!node) return undefined; if (isIntersectionTypeNode(node)) { const result: TypeElement[] = []; const seen = new Map(); for (const type of node.types) { const flattenedTypeMembers = flattenTypeLiteralNodeReference(checker, type); - if (!flattenedTypeMembers || !flattenedTypeMembers.every(type => type.name && addToSeen(seen, getNameFromPropertyName(type.name) as string))) { + if ( + !flattenedTypeMembers + || !flattenedTypeMembers.every(type => + type.name && addToSeen(seen, getNameFromPropertyName(type.name) as string) + ) + ) { return undefined; } @@ -209,7 +239,12 @@ function rangeContainsSkipTrivia(r1: TextRange, node: Node, file: SourceFile): b return rangeContainsStartEnd(r1, skipTrivia(file.text, node.pos), node.end); } -function collectTypeParameters(checker: TypeChecker, selection: TypeNode, enclosingNode: Node, file: SourceFile): TypeParameterDeclaration[] | undefined { +function collectTypeParameters( + checker: TypeChecker, + selection: TypeNode, + enclosingNode: Node, + file: SourceFile, +): TypeParameterDeclaration[] | undefined { const result: TypeParameterDeclaration[] = []; return visitor(selection) ? undefined : result; @@ -217,16 +252,27 @@ function collectTypeParameters(checker: TypeChecker, selection: TypeNode, enclos if (isTypeReferenceNode(node)) { if (isIdentifier(node.typeName)) { const typeName = node.typeName; - const symbol = checker.resolveName(typeName.text, typeName, SymbolFlags.TypeParameter, /*excludeGlobals*/ true); + const symbol = checker.resolveName( + typeName.text, + typeName, + SymbolFlags.TypeParameter, + /*excludeGlobals*/ true, + ); for (const decl of symbol?.declarations || emptyArray) { if (isTypeParameterDeclaration(decl) && decl.getSourceFile() === file) { // skip extraction if the type node is in the range of the type parameter declaration. // function foo(): void; - if (decl.name.escapedText === typeName.escapedText && rangeContainsSkipTrivia(decl, selection, file)) { + if ( + decl.name.escapedText === typeName.escapedText + && rangeContainsSkipTrivia(decl, selection, file) + ) { return true; } - if (rangeContainsSkipTrivia(enclosingNode, decl, file) && !rangeContainsSkipTrivia(selection, decl, file)) { + if ( + rangeContainsSkipTrivia(enclosingNode, decl, file) + && !rangeContainsSkipTrivia(selection, decl, file) + ) { pushIfUnique(result, decl); break; } @@ -235,21 +281,35 @@ function collectTypeParameters(checker: TypeChecker, selection: TypeNode, enclos } } else if (isInferTypeNode(node)) { - const conditionalTypeNode = findAncestor(node, n => isConditionalTypeNode(n) && rangeContainsSkipTrivia(n.extendsType, node, file)); + const conditionalTypeNode = findAncestor( + node, + n => isConditionalTypeNode(n) && rangeContainsSkipTrivia(n.extendsType, node, file), + ); if (!conditionalTypeNode || !rangeContainsSkipTrivia(selection, conditionalTypeNode, file)) { return true; } } else if ((isTypePredicateNode(node) || isThisTypeNode(node))) { const functionLikeNode = findAncestor(node.parent, isFunctionLike); - if (functionLikeNode && functionLikeNode.type && rangeContainsSkipTrivia(functionLikeNode.type, node, file) && !rangeContainsSkipTrivia(selection, functionLikeNode, file)) { + if ( + functionLikeNode && functionLikeNode.type && rangeContainsSkipTrivia(functionLikeNode.type, node, file) + && !rangeContainsSkipTrivia(selection, functionLikeNode, file) + ) { return true; } } else if (isTypeQueryNode(node)) { if (isIdentifier(node.exprName)) { - const symbol = checker.resolveName(node.exprName.text, node.exprName, SymbolFlags.Value, /*excludeGlobals*/ false); - if (symbol?.valueDeclaration && rangeContainsSkipTrivia(enclosingNode, symbol.valueDeclaration, file) && !rangeContainsSkipTrivia(selection, symbol.valueDeclaration, file)) { + const symbol = checker.resolveName( + node.exprName.text, + node.exprName, + SymbolFlags.Value, + /*excludeGlobals*/ false, + ); + if ( + symbol?.valueDeclaration && rangeContainsSkipTrivia(enclosingNode, symbol.valueDeclaration, file) + && !rangeContainsSkipTrivia(selection, symbol.valueDeclaration, file) + ) { return true; } } @@ -260,7 +320,11 @@ function collectTypeParameters(checker: TypeChecker, selection: TypeNode, enclos } } - if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) { + if ( + file && isTupleTypeNode(node) + && (getLineAndCharacterOfPosition(file, node.pos).line + === getLineAndCharacterOfPosition(file, node.end).line) + ) { setEmitFlags(node, EmitFlags.SingleLine); } @@ -274,11 +338,24 @@ function doTypeAliasChange(changes: textChanges.ChangeTracker, file: SourceFile, const newTypeNode = factory.createTypeAliasDeclaration( /*modifiers*/ undefined, name, - typeParameters.map(id => factory.updateTypeParameterDeclaration(id, id.modifiers, id.name, id.constraint, /*defaultType*/ undefined)), - selection + typeParameters.map(id => + factory.updateTypeParameterDeclaration(id, id.modifiers, id.name, id.constraint, /*defaultType*/ undefined) + ), + selection, ); changes.insertNodeBefore(file, enclosingNode, ignoreSourceNewlines(newTypeNode), /*blankLineBetween*/ true); - changes.replaceNode(file, selection, factory.createTypeReferenceNode(name, typeParameters.map(id => factory.createTypeReferenceNode(id.name, /*typeArguments*/ undefined))), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace }); + changes.replaceNode( + file, + selection, + factory.createTypeReferenceNode( + name, + typeParameters.map(id => factory.createTypeReferenceNode(id.name, /*typeArguments*/ undefined)), + ), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace, + }, + ); } function doInterfaceChange(changes: textChanges.ChangeTracker, file: SourceFile, name: string, info: InterfaceInfo) { @@ -289,14 +366,31 @@ function doInterfaceChange(changes: textChanges.ChangeTracker, file: SourceFile, name, typeParameters, /*heritageClauses*/ undefined, - typeElements + typeElements, ); setTextRange(newTypeNode, typeElements[0]?.parent); changes.insertNodeBefore(file, enclosingNode, ignoreSourceNewlines(newTypeNode), /*blankLineBetween*/ true); - changes.replaceNode(file, selection, factory.createTypeReferenceNode(name, typeParameters.map(id => factory.createTypeReferenceNode(id.name, /*typeArguments*/ undefined))), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace }); + changes.replaceNode( + file, + selection, + factory.createTypeReferenceNode( + name, + typeParameters.map(id => factory.createTypeReferenceNode(id.name, /*typeArguments*/ undefined)), + ), + { + leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace, + }, + ); } -function doTypedefChange(changes: textChanges.ChangeTracker, context: RefactorContext, file: SourceFile, name: string, info: ExtractInfo) { +function doTypedefChange( + changes: textChanges.ChangeTracker, + context: RefactorContext, + file: SourceFile, + name: string, + info: ExtractInfo, +) { const { enclosingNode, selection, typeParameters } = info; setEmitFlags(selection, EmitFlags.NoComments | EmitFlags.NoNestedComments); @@ -304,7 +398,8 @@ function doTypedefChange(changes: textChanges.ChangeTracker, context: RefactorCo const node = factory.createJSDocTypedefTag( factory.createIdentifier("typedef"), factory.createJSDocTypeExpression(selection), - factory.createIdentifier(name)); + factory.createIdentifier(name), + ); const templates: JSDocTemplateTag[] = []; forEach(typeParameters, typeParameter => { @@ -313,23 +408,34 @@ function doTypedefChange(changes: textChanges.ChangeTracker, context: RefactorCo const template = factory.createJSDocTemplateTag( factory.createIdentifier("template"), constraint && cast(constraint, isJSDocTypeExpression), - [parameter] + [parameter], ); templates.push(template); }); - const jsDoc = factory.createJSDocComment(/*comment*/ undefined, factory.createNodeArray(concatenate(templates, [node]))); + const jsDoc = factory.createJSDocComment( + /*comment*/ undefined, + factory.createNodeArray(concatenate(templates, [node])), + ); if (isJSDoc(enclosingNode)) { const pos = enclosingNode.getStart(file); const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext?.options); changes.insertNodeAt(file, enclosingNode.getStart(file), jsDoc, { - suffix: newLineCharacter + newLineCharacter + file.text.slice(getPrecedingNonSpaceCharacterPosition(file.text, pos - 1), pos) + suffix: newLineCharacter + newLineCharacter + + file.text.slice(getPrecedingNonSpaceCharacterPosition(file.text, pos - 1), pos), }); } else { changes.insertNodeBefore(file, enclosingNode, jsDoc, /*blankLineBetween*/ true); } - changes.replaceNode(file, selection, factory.createTypeReferenceNode(name, typeParameters.map(id => factory.createTypeReferenceNode(id.name, /*typeArguments*/ undefined)))); + changes.replaceNode( + file, + selection, + factory.createTypeReferenceNode( + name, + typeParameters.map(id => factory.createTypeReferenceNode(id.name, /*typeArguments*/ undefined)), + ), + ); } function getEnclosingNode(node: Node, isJS: boolean) { diff --git a/src/services/refactors/generateGetAccessorAndSetAccessor.ts b/src/services/refactors/generateGetAccessorAndSetAccessor.ts index 86ca118d2c935..efd9e74f0bc51 100644 --- a/src/services/refactors/generateGetAccessorAndSetAccessor.ts +++ b/src/services/refactors/generateGetAccessorAndSetAccessor.ts @@ -27,21 +27,45 @@ registerRefactor(actionName, { kinds: [generateGetSetAction.kind], getEditsForAction: function getRefactorActionsToGenerateGetAndSetAccessors(context, actionName) { if (!context.endPosition) return undefined; - const info = codefix.getAccessorConvertiblePropertyAtPosition(context.file, context.program, context.startPosition, context.endPosition); + const info = codefix.getAccessorConvertiblePropertyAtPosition( + context.file, + context.program, + context.startPosition, + context.endPosition, + ); Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info"); - const edits = codefix.generateAccessorFromProperty(context.file, context.program, context.startPosition, context.endPosition, context, actionName); + const edits = codefix.generateAccessorFromProperty( + context.file, + context.program, + context.startPosition, + context.endPosition, + context, + actionName, + ); if (!edits) return undefined; const renameFilename = context.file.fileName; const nameNeedRename = info.renameAccessor ? info.accessorName : info.fieldName; const renameLocationOffset = isIdentifier(nameNeedRename) ? 0 : -1; - const renameLocation = renameLocationOffset + getRenameLocation(edits, renameFilename, nameNeedRename.text, /*preferLastLocation*/ isParameter(info.declaration)); + const renameLocation = renameLocationOffset + + getRenameLocation( + edits, + renameFilename, + nameNeedRename.text, + /*preferLastLocation*/ isParameter(info.declaration), + ); return { renameFilename, renameLocation, edits }; }, getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] { if (!context.endPosition) return emptyArray; - const info = codefix.getAccessorConvertiblePropertyAtPosition(context.file, context.program, context.startPosition, context.endPosition, context.triggerReason === "invoked"); + const info = codefix.getAccessorConvertiblePropertyAtPosition( + context.file, + context.program, + context.startPosition, + context.endPosition, + context.triggerReason === "invoked", + ); if (!info) return emptyArray; if (!isRefactorErrorInfo(info)) { @@ -61,5 +85,5 @@ registerRefactor(actionName, { } return emptyArray; - } + }, }); diff --git a/src/services/refactors/helpers.ts b/src/services/refactors/helpers.ts index acafb54f1e36a..ce50f672d23b8 100644 --- a/src/services/refactors/helpers.ts +++ b/src/services/refactors/helpers.ts @@ -1,4 +1,3 @@ - /** * Returned by refactor functions when some error message needs to be surfaced to users. * @@ -24,6 +23,6 @@ export function isRefactorErrorInfo(info: unknown): info is RefactorErrorInfo { * @internal */ export function refactorKindBeginsWith(known: string, requested: string | undefined): boolean { - if(!requested) return true; + if (!requested) return true; return known.substr(0, requested.length) === requested; } diff --git a/src/services/refactors/inferFunctionReturnType.ts b/src/services/refactors/inferFunctionReturnType.ts index 1e54133c1ff61..2cf7acdec57be 100644 --- a/src/services/refactors/inferFunctionReturnType.ts +++ b/src/services/refactors/inferFunctionReturnType.ts @@ -40,18 +40,21 @@ const refactorDescription = getLocaleSpecificMessage(Diagnostics.Infer_function_ const inferReturnTypeAction = { name: refactorName, description: refactorDescription, - kind: "refactor.rewrite.function.returnType" + kind: "refactor.rewrite.function.returnType", }; registerRefactor(refactorName, { kinds: [inferReturnTypeAction.kind], getEditsForAction: getRefactorEditsToInferReturnType, - getAvailableActions: getRefactorActionsToInferReturnType + getAvailableActions: getRefactorActionsToInferReturnType, }); function getRefactorEditsToInferReturnType(context: RefactorContext): RefactorEditInfo | undefined { const info = getInfo(context); if (info && !isRefactorErrorInfo(info)) { - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, t, info.declaration, info.returnTypeNode)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, t, info.declaration, info.returnTypeNode), + ); return { renameFilename: undefined, renameLocation: undefined, edits }; } return undefined; @@ -64,14 +67,14 @@ function getRefactorActionsToInferReturnType(context: RefactorContext): readonly return [{ name: refactorName, description: refactorDescription, - actions: [inferReturnTypeAction] + actions: [inferReturnTypeAction], }]; } if (context.preferences.provideRefactorNotApplicableReason) { return [{ name: refactorName, description: refactorDescription, - actions: [{ ...inferReturnTypeAction, notApplicableReason: info.error }] + actions: [{ ...inferReturnTypeAction, notApplicableReason: info.error }], }]; } return emptyArray; @@ -88,7 +91,12 @@ interface FunctionInfo { returnTypeNode: TypeNode; } -function doChange(sourceFile: SourceFile, changes: textChanges.ChangeTracker, declaration: ConvertibleDeclaration, typeNode: TypeNode) { +function doChange( + sourceFile: SourceFile, + changes: textChanges.ChangeTracker, + declaration: ConvertibleDeclaration, + typeNode: TypeNode, +) { const closeParen = findChildOfKind(declaration, SyntaxKind.CloseParenToken, sourceFile); const needParens = isArrowFunction(declaration) && closeParen === undefined; const endNode = needParens ? first(declaration.parameters) : closeParen; @@ -105,9 +113,13 @@ function getInfo(context: RefactorContext): FunctionInfo | RefactorErrorInfo | u if (isInJSFile(context.file) || !refactorKindBeginsWith(inferReturnTypeAction.kind, context.kind)) return; const token = getTokenAtPosition(context.file, context.startPosition); - const declaration = findAncestor(token, n => - isBlock(n) || n.parent && isArrowFunction(n.parent) && (n.kind === SyntaxKind.EqualsGreaterThanToken || n.parent.body === n) ? "quit" : - isConvertibleDeclaration(n)) as ConvertibleDeclaration | undefined; + const declaration = findAncestor( + token, + n => isBlock(n) + || n.parent && isArrowFunction(n.parent) + && (n.kind === SyntaxKind.EqualsGreaterThanToken || n.parent.body === n) ? "quit" + : isConvertibleDeclaration(n), + ) as ConvertibleDeclaration | undefined; if (!declaration || !declaration.body || declaration.type) { return { error: getLocaleSpecificMessage(Diagnostics.Return_type_must_be_inferred_from_a_function) }; } diff --git a/src/services/refactors/inlineVariable.ts b/src/services/refactors/inlineVariable.ts index c5e8660462eba..71493ec08fc8d 100644 --- a/src/services/refactors/inlineVariable.ts +++ b/src/services/refactors/inlineVariable.ts @@ -38,7 +38,10 @@ import { TypeChecker, VariableDeclaration, } from "../_namespaces/ts"; -import { RefactorErrorInfo, registerRefactor } from "../_namespaces/ts.refactor"; +import { + RefactorErrorInfo, + registerRefactor, +} from "../_namespaces/ts.refactor"; const refactorName = "Inline variable"; const refactorDescription = getLocaleSpecificMessage(Diagnostics.Inline_variable); @@ -46,7 +49,7 @@ const refactorDescription = getLocaleSpecificMessage(Diagnostics.Inline_variable const inlineVariableAction = { name: refactorName, description: refactorDescription, - kind: "refactor.inline.variable" + kind: "refactor.inline.variable", }; interface InliningInfo { @@ -64,7 +67,7 @@ registerRefactor(refactorName, { program, preferences, startPosition, - triggerReason + triggerReason, } = context; // tryWithReferenceToken is true below when triggerReason === "invoked", since we want to @@ -79,7 +82,7 @@ registerRefactor(refactorName, { return [{ name: refactorName, description: refactorDescription, - actions: [inlineVariableAction] + actions: [inlineVariableAction], }]; } @@ -89,8 +92,8 @@ registerRefactor(refactorName, { description: refactorDescription, actions: [{ ...inlineVariableAction, - notApplicableReason: info.error - }] + notApplicableReason: info.error, + }], }]; } @@ -118,10 +121,15 @@ registerRefactor(refactorName, { }); return { edits }; - } + }, }); -function getInliningInfo(file: SourceFile, startPosition: number, tryWithReferenceToken: boolean, program: Program): InliningInfo | RefactorErrorInfo | undefined { +function getInliningInfo( + file: SourceFile, + startPosition: number, + tryWithReferenceToken: boolean, + program: Program, +): InliningInfo | RefactorErrorInfo | undefined { const checker = program.getTypeChecker(); const token = getTouchingPropertyName(file, startPosition); const parent = token.parent; @@ -132,10 +140,14 @@ function getInliningInfo(file: SourceFile, startPosition: number, tryWithReferen // If triggered in a variable declaration, make sure it's not in a catch clause or for-loop // and that it has a value. - if (isInitializedVariable(parent) && isVariableDeclarationInVariableStatement(parent) && isIdentifier(parent.name)) { + if ( + isInitializedVariable(parent) && isVariableDeclarationInVariableStatement(parent) && isIdentifier(parent.name) + ) { // Don't inline the variable if it has multiple declarations. if (checker.getMergedSymbol(parent.symbol).declarations?.length !== 1) { - return { error: getLocaleSpecificMessage(Diagnostics.Variables_with_multiple_declarations_cannot_be_inlined) }; + return { + error: getLocaleSpecificMessage(Diagnostics.Variables_with_multiple_declarations_cannot_be_inlined), + }; } // Do not inline if the variable is exported. @@ -155,12 +167,17 @@ function getInliningInfo(file: SourceFile, startPosition: number, tryWithReferen // Don't inline the variable if it has multiple declarations. if (definition?.declarations?.length !== 1) { - return { error: getLocaleSpecificMessage(Diagnostics.Variables_with_multiple_declarations_cannot_be_inlined) }; + return { + error: getLocaleSpecificMessage(Diagnostics.Variables_with_multiple_declarations_cannot_be_inlined), + }; } // Make sure we're not inlining something like "let foo;" or "for (let i = 0; i < 5; i++) {}". const declaration = definition.declarations[0]; - if (!isInitializedVariable(declaration) || !isVariableDeclarationInVariableStatement(declaration) || !isIdentifier(declaration.name)) { + if ( + !isInitializedVariable(declaration) || !isVariableDeclarationInVariableStatement(declaration) + || !isIdentifier(declaration.name) + ) { return undefined; } @@ -183,32 +200,41 @@ function isDeclarationExported(declaration: InitializedVariableDeclaration): boo return some(variableStatement.modifiers, isExportModifier); } -function getReferenceNodes(declaration: InitializedVariableDeclaration, checker: TypeChecker, file: SourceFile): Identifier[] | undefined { +function getReferenceNodes( + declaration: InitializedVariableDeclaration, + checker: TypeChecker, + file: SourceFile, +): Identifier[] | undefined { const references: Identifier[] = []; - const cannotInline = FindAllReferences.Core.eachSymbolReferenceInFile(declaration.name as Identifier, checker, file, ref => { - // Only inline if all references are reads. Else we might end up with an invalid scenario like: - // const y = x++ + 1 -> const y = 2++ + 1 - if (FindAllReferences.isWriteAccessForReference(ref)) { - return true; - } + const cannotInline = FindAllReferences.Core.eachSymbolReferenceInFile( + declaration.name as Identifier, + checker, + file, + ref => { + // Only inline if all references are reads. Else we might end up with an invalid scenario like: + // const y = x++ + 1 -> const y = 2++ + 1 + if (FindAllReferences.isWriteAccessForReference(ref)) { + return true; + } - // We cannot inline exported variables like "export { x as y }" or "export default foo". - if (isExportSpecifier(ref.parent) || isExportAssignment(ref.parent)) { - return true; - } + // We cannot inline exported variables like "export { x as y }" or "export default foo". + if (isExportSpecifier(ref.parent) || isExportAssignment(ref.parent)) { + return true; + } - // typeof needs an identifier, so we can't inline a value in there. - if (isTypeQueryNode(ref.parent)) { - return true; - } + // typeof needs an identifier, so we can't inline a value in there. + if (isTypeQueryNode(ref.parent)) { + return true; + } - // Cannot inline recursive declarations (e.g. const foo = () => foo();) - if (textRangeContainsPositionInclusive(declaration, ref.pos)) { - return true; - } + // Cannot inline recursive declarations (e.g. const foo = () => foo();) + if (textRangeContainsPositionInclusive(declaration, ref.pos)) { + return true; + } - references.push(ref); - }); + references.push(ref); + }, + ); return references.length === 0 || cannotInline ? undefined : references; } @@ -225,7 +251,10 @@ function getReplacementExpression(reference: Node, replacement: Expression): Exp // Note that binaryOperandNeedsParentheses has further logic when the precedences // are equal, but for the purposes of this refactor we keep things simple and // instead just check for special cases with needsParentheses. - if (isExpression(parent) && (getExpressionPrecedence(replacement) < getExpressionPrecedence(parent) || needsParentheses(parent))) { + if ( + isExpression(parent) + && (getExpressionPrecedence(replacement) < getExpressionPrecedence(parent) || needsParentheses(parent)) + ) { return factory.createParenthesizedExpression(replacement); } @@ -237,7 +266,9 @@ function getReplacementExpression(reference: Node, replacement: Expression): Exp // Property access of numeric literals and objects need parentheses. // E.g.: const x = 1; x.toString(); -> (1).toString(); - if (isPropertyAccessExpression(parent) && (isNumericLiteral(replacement) || isObjectLiteralExpression(replacement))) { + if ( + isPropertyAccessExpression(parent) && (isNumericLiteral(replacement) || isObjectLiteralExpression(replacement)) + ) { return factory.createParenthesizedExpression(replacement); } diff --git a/src/services/refactors/moveToFile.ts b/src/services/refactors/moveToFile.ts index b0b02a3484278..bf0d6fff7f2be 100644 --- a/src/services/refactors/moveToFile.ts +++ b/src/services/refactors/moveToFile.ts @@ -1,4 +1,6 @@ -import { getModuleSpecifier } from "../../compiler/moduleSpecifiers"; +import { + getModuleSpecifier, +} from "../../compiler/moduleSpecifiers"; import { __String, AnyImportOrRequireStatement, @@ -142,7 +144,9 @@ import { VariableDeclarationList, VariableStatement, } from "../_namespaces/ts"; -import { registerRefactor } from "../refactorProvider"; +import { + registerRefactor, +} from "../refactorProvider"; const refactorNameForMoveToFile = "Move to file"; const description = getLocaleSpecificMessage(Diagnostics.Move_to_file); @@ -154,7 +158,10 @@ const moveToFileAction = { }; registerRefactor(refactorNameForMoveToFile, { kinds: [moveToFileAction.kind], - getAvailableActions: function getRefactorActionsToMoveToFile(context, interactiveRefactorArguments): readonly ApplicableRefactorInfo[] { + getAvailableActions: function getRefactorActionsToMoveToFile( + context, + interactiveRefactorArguments, + ): readonly ApplicableRefactorInfo[] { const statements = getStatementsToMove(context); if (!interactiveRefactorArguments) { return emptyArray; @@ -163,13 +170,24 @@ registerRefactor(refactorNameForMoveToFile, { return [{ name: refactorNameForMoveToFile, description, actions: [moveToFileAction] }]; } if (context.preferences.provideRefactorNotApplicableReason) { - return [{ name: refactorNameForMoveToFile, description, actions: - [{ ...moveToFileAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_statement_or_statements) }] + return [{ + name: refactorNameForMoveToFile, + description, + actions: [{ + ...moveToFileAction, + notApplicableReason: getLocaleSpecificMessage( + Diagnostics.Selection_is_not_a_valid_statement_or_statements, + ), + }], }]; } return emptyArray; }, - getEditsForAction: function getRefactorEditsToMoveToFile(context, actionName, interactiveRefactorArguments): RefactorEditInfo | undefined { + getEditsForAction: function getRefactorEditsToMoveToFile( + context, + actionName, + interactiveRefactorArguments, + ): RefactorEditInfo | undefined { Debug.assert(actionName === refactorNameForMoveToFile, "Wrong refactor invoked"); const statements = Debug.checkDefined(getStatementsToMove(context)); const { host, program } = context; @@ -179,29 +197,78 @@ registerRefactor(refactorNameForMoveToFile, { if (host.fileExists(targetFile) && program.getSourceFile(targetFile) === undefined) { return error(getLocaleSpecificMessage(Diagnostics.Cannot_move_statements_to_the_selected_file)); } - const edits = textChanges.ChangeTracker.with(context, t => doChange(context, context.file, interactiveRefactorArguments.targetFile, context.program, statements, t, context.host, context.preferences)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange( + context, + context.file, + interactiveRefactorArguments.targetFile, + context.program, + statements, + t, + context.host, + context.preferences, + ), + ); return { edits, renameFilename: undefined, renameLocation: undefined }; } return error(getLocaleSpecificMessage(Diagnostics.Cannot_move_to_file_selected_file_is_invalid)); - } + }, }); function error(notApplicableReason: string) { return { edits: [], renameFilename: undefined, renameLocation: undefined, notApplicableReason }; } -function doChange(context: RefactorContext, oldFile: SourceFile, targetFile: string, program: Program, toMove: ToMove, changes: textChanges.ChangeTracker, host: LanguageServiceHost, preferences: UserPreferences): void { +function doChange( + context: RefactorContext, + oldFile: SourceFile, + targetFile: string, + program: Program, + toMove: ToMove, + changes: textChanges.ChangeTracker, + host: LanguageServiceHost, + preferences: UserPreferences, +): void { const checker = program.getTypeChecker(); const usage = getUsageInfo(oldFile, toMove.all, checker); - //For a new file + // For a new file if (!host.fileExists(targetFile)) { - changes.createNewFile(oldFile, targetFile, getNewStatementsAndRemoveFromOldFile(oldFile, targetFile, usage, changes, toMove, program, host, preferences)); + changes.createNewFile( + oldFile, + targetFile, + getNewStatementsAndRemoveFromOldFile( + oldFile, + targetFile, + usage, + changes, + toMove, + program, + host, + preferences, + ), + ); addNewFileToTsconfig(program, changes, oldFile.fileName, targetFile, hostGetCanonicalFileName(host)); } else { const targetSourceFile = Debug.checkDefined(program.getSourceFile(targetFile)); - const importAdder = codefix.createImportAdder(targetSourceFile, context.program, context.preferences, context.host); - getNewStatementsAndRemoveFromOldFile(oldFile, targetSourceFile, usage, changes, toMove, program, host, preferences, importAdder); + const importAdder = codefix.createImportAdder( + targetSourceFile, + context.program, + context.preferences, + context.host, + ); + getNewStatementsAndRemoveFromOldFile( + oldFile, + targetSourceFile, + usage, + changes, + toMove, + program, + host, + preferences, + importAdder, + ); } } @@ -214,21 +281,38 @@ function getNewStatementsAndRemoveFromOldFile( program: Program, host: LanguageServiceHost, preferences: UserPreferences, - importAdder?: codefix.ImportAdder + importAdder?: codefix.ImportAdder, ) { const checker = program.getTypeChecker(); const prologueDirectives = takeWhile(oldFile.statements, isPrologueDirective); - if (oldFile.externalModuleIndicator === undefined && oldFile.commonJsModuleIndicator === undefined && usage.oldImportsNeededByTargetFile.size === 0 && usage.targetFileImportsFromOldFile.size === 0 && typeof targetFile === "string") { + if ( + oldFile.externalModuleIndicator === undefined && oldFile.commonJsModuleIndicator === undefined + && usage.oldImportsNeededByTargetFile.size === 0 && usage.targetFileImportsFromOldFile.size === 0 + && typeof targetFile === "string" + ) { deleteMovedStatements(oldFile, toMove.ranges, changes); return [...prologueDirectives, ...toMove.all]; } - //If the targetFile is a string, it’s the file name for a new file, if it’s a SourceFile, it’s the existing target file. + // If the targetFile is a string, it’s the file name for a new file, if it’s a SourceFile, it’s the existing target file. const targetFileName = typeof targetFile === "string" ? targetFile : targetFile.fileName; - const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(targetFileName, program, host, !!oldFile.commonJsModuleIndicator); + const useEsModuleSyntax = !fileShouldUseJavaScriptRequire( + targetFileName, + program, + host, + !!oldFile.commonJsModuleIndicator, + ); const quotePreference = getQuotePreference(oldFile, preferences); - const importsFromTargetFile = createOldFileImportsFromTargetFile(oldFile, usage.oldFileImportsFromTargetFile, targetFileName, program, host, useEsModuleSyntax, quotePreference); + const importsFromTargetFile = createOldFileImportsFromTargetFile( + oldFile, + usage.oldFileImportsFromTargetFile, + targetFileName, + program, + host, + useEsModuleSyntax, + quotePreference, + ); if (importsFromTargetFile) { insertImports(changes, oldFile, importsFromTargetFile, /*blankLineBetween*/ true, preferences); } @@ -237,7 +321,19 @@ function getNewStatementsAndRemoveFromOldFile( deleteMovedStatements(oldFile, toMove.ranges, changes); updateImportsInOtherFiles(changes, program, host, oldFile, usage.movedSymbols, targetFileName, quotePreference); - const imports = getTargetFileImportsAndAddExportInOldFile(oldFile, targetFileName, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, checker, program, host, useEsModuleSyntax, quotePreference, importAdder); + const imports = getTargetFileImportsAndAddExportInOldFile( + oldFile, + targetFileName, + usage.oldImportsNeededByTargetFile, + usage.targetFileImportsFromOldFile, + changes, + checker, + program, + host, + useEsModuleSyntax, + quotePreference, + importAdder, + ); const body = addExports(oldFile, toMove.all, usage.oldFileImportsFromTargetFile, useEsModuleSyntax); if (typeof targetFile !== "string") { if (targetFile.statements.length > 0) { @@ -258,7 +354,7 @@ function getNewStatementsAndRemoveFromOldFile( ...prologueDirectives, ...imports, SyntaxKind.NewLineTrivia as const, - ...body + ...body, ]; } @@ -296,7 +392,14 @@ function getTargetFileImportsAndAddExportInOldFile( catch { for (const oldStatement of oldFile.statements) { forEachImportInStatement(oldStatement, i => { - append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + append( + copiedOldImports, + filterImport( + i, + factory.createStringLiteral(moduleSpecifierFromImport(i).text), + name => importsToCopy.has(checker.getSymbolAtLocation(name)!), + ), + ); }); } } @@ -308,20 +411,43 @@ function getTargetFileImportsAndAddExportInOldFile( forEachImportInStatement(oldStatement, i => { // Recomputing module specifier const moduleSpecifier = moduleSpecifierFromImport(i); - const resolved = oldFile.resolvedModules?.get(moduleSpecifier.text, getModeForUsageLocation(oldFile, moduleSpecifier)); + const resolved = oldFile.resolvedModules?.get( + moduleSpecifier.text, + getModeForUsageLocation(oldFile, moduleSpecifier), + ); const fileName = resolved?.resolvedModule?.resolvedFileName; if (fileName && targetSourceFile) { - const newModuleSpecifier = getModuleSpecifier(program.getCompilerOptions(), targetSourceFile, targetSourceFile.path, fileName, createModuleSpecifierResolutionHost(program, host)); - append(copiedOldImports, filterImport(i, makeStringLiteral(newModuleSpecifier, quotePreference), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + const newModuleSpecifier = getModuleSpecifier( + program.getCompilerOptions(), + targetSourceFile, + targetSourceFile.path, + fileName, + createModuleSpecifierResolutionHost(program, host), + ); + append( + copiedOldImports, + filterImport( + i, + makeStringLiteral(newModuleSpecifier, quotePreference), + name => importsToCopy.has(checker.getSymbolAtLocation(name)!), + ), + ); } else { - append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + append( + copiedOldImports, + filterImport( + i, + factory.createStringLiteral(moduleSpecifierFromImport(i).text), + name => importsToCopy.has(checker.getSymbolAtLocation(name)!), + ), + ); } }); } } - //Also, import things used from the old file, and insert 'export' modifiers as necessary in the old file. + // Also, import things used from the old file, and insert 'export' modifiers as necessary in the old file. const targetFileSourceFile = program.getSourceFile(targetFile); let oldFileDefault: Identifier | undefined; const oldFileNamedImports: string[] = []; @@ -352,13 +478,43 @@ function getTargetFileImportsAndAddExportInOldFile( } } }); - return (targetFileSourceFile) - ? append(copiedOldImports, makeImportOrRequire(targetFileSourceFile, oldFileDefault, oldFileNamedImports, oldFile.fileName, program, host, useEsModuleSyntax, quotePreference)) - : append(copiedOldImports, makeImportOrRequire(oldFile, oldFileDefault, oldFileNamedImports, oldFile.fileName, program, host, useEsModuleSyntax, quotePreference)); + return targetFileSourceFile + ? append( + copiedOldImports, + makeImportOrRequire( + targetFileSourceFile, + oldFileDefault, + oldFileNamedImports, + oldFile.fileName, + program, + host, + useEsModuleSyntax, + quotePreference, + ), + ) + : append( + copiedOldImports, + makeImportOrRequire( + oldFile, + oldFileDefault, + oldFileNamedImports, + oldFile.fileName, + program, + host, + useEsModuleSyntax, + quotePreference, + ), + ); } /** @internal */ -export function addNewFileToTsconfig(program: Program, changes: textChanges.ChangeTracker, oldFileName: string, newFileNameWithExtension: string, getCanonicalFileName: GetCanonicalFileName): void { +export function addNewFileToTsconfig( + program: Program, + changes: textChanges.ChangeTracker, + oldFileName: string, + newFileNameWithExtension: string, + getCanonicalFileName: GetCanonicalFileName, +): void { const cfg = program.getCompilerOptions().configFile; if (!cfg) return; @@ -366,31 +522,59 @@ export function addNewFileToTsconfig(program: Program, changes: textChanges.Chan const newFilePath = getRelativePathFromFile(cfg.fileName, newFileAbsolutePath, getCanonicalFileName); const cfgObject = cfg.statements[0] && tryCast(cfg.statements[0].expression, isObjectLiteralExpression); - const filesProp = cfgObject && find(cfgObject.properties, (prop): prop is PropertyAssignment => - isPropertyAssignment(prop) && isStringLiteral(prop.name) && prop.name.text === "files"); + const filesProp = cfgObject + && find( + cfgObject.properties, + (prop): prop is PropertyAssignment => + isPropertyAssignment(prop) && isStringLiteral(prop.name) && prop.name.text === "files", + ); if (filesProp && isArrayLiteralExpression(filesProp.initializer)) { - changes.insertNodeInListAfter(cfg, last(filesProp.initializer.elements), factory.createStringLiteral(newFilePath), filesProp.initializer.elements); + changes.insertNodeInListAfter( + cfg, + last(filesProp.initializer.elements), + factory.createStringLiteral(newFilePath), + filesProp.initializer.elements, + ); } } /** @internal */ -export function deleteMovedStatements(sourceFile: SourceFile, moved: readonly StatementRange[], changes: textChanges.ChangeTracker) { +export 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[], changes: textChanges.ChangeTracker, toDelete: Set, checker: TypeChecker) { +export function deleteUnusedOldImports( + oldFile: SourceFile, + toMove: readonly Statement[], + changes: textChanges.ChangeTracker, + toDelete: Set, + checker: TypeChecker, +) { for (const statement of oldFile.statements) { if (contains(toMove, statement)) continue; - forEachImportInStatement(statement, i => deleteUnusedImports(oldFile, i, changes, name => toDelete.has(checker.getSymbolAtLocation(name)!))); + forEachImportInStatement( + statement, + i => deleteUnusedImports(oldFile, i, changes, name => toDelete.has(checker.getSymbolAtLocation(name)!)), + ); } } /** @internal */ export function updateImportsInOtherFiles( - changes: textChanges.ChangeTracker, program: Program, host: LanguageServiceHost, oldFile: SourceFile, movedSymbols: Set, targetFileName: string, quotePreference: QuotePreference + changes: textChanges.ChangeTracker, + program: Program, + host: LanguageServiceHost, + oldFile: SourceFile, + movedSymbols: Set, + targetFileName: string, + quotePreference: QuotePreference, ): void { const checker = program.getTypeChecker(); for (const sourceFile of program.getSourceFiles()) { @@ -401,19 +585,43 @@ export function updateImportsInOtherFiles( const shouldMove = (name: Identifier): boolean => { const symbol = isBindingElement(name.parent) - ? getPropertySymbolFromBindingElement(checker, name.parent as ObjectBindingElementWithoutPropertyName) + ? getPropertySymbolFromBindingElement( + checker, + name.parent as ObjectBindingElementWithoutPropertyName, + ) : skipAlias(checker.getSymbolAtLocation(name)!, checker); return !!symbol && movedSymbols.has(symbol); }; deleteUnusedImports(sourceFile, importNode, changes, shouldMove); // These will be changed to imports from the new file const pathToTargetFileWithExtension = resolvePath(getDirectoryPath(oldFile.path), targetFileName); - const newModuleSpecifier = getModuleSpecifier(program.getCompilerOptions(), sourceFile, sourceFile.path, pathToTargetFileWithExtension, createModuleSpecifierResolutionHost(program, host)); - const newImportDeclaration = filterImport(importNode, makeStringLiteral(newModuleSpecifier, quotePreference), shouldMove); + const newModuleSpecifier = getModuleSpecifier( + program.getCompilerOptions(), + sourceFile, + sourceFile.path, + pathToTargetFileWithExtension, + createModuleSpecifierResolutionHost(program, host), + ); + const newImportDeclaration = filterImport( + importNode, + makeStringLiteral(newModuleSpecifier, quotePreference), + shouldMove, + ); if (newImportDeclaration) changes.insertNodeAfter(sourceFile, statement, newImportDeclaration); const ns = getNamespaceLikeImport(importNode); - if (ns) updateNamespaceLikeImport(changes, sourceFile, checker, movedSymbols, newModuleSpecifier, ns, importNode, quotePreference); + if (ns) { + updateNamespaceLikeImport( + changes, + sourceFile, + checker, + movedSymbols, + newModuleSpecifier, + ns, + importNode, + quotePreference, + ); + } }); } } @@ -422,8 +630,9 @@ export function updateImportsInOtherFiles( function getNamespaceLikeImport(node: SupportedImport): Identifier | undefined { switch (node.kind) { case SyntaxKind.ImportDeclaration: - return node.importClause && node.importClause.namedBindings && node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport ? - node.importClause.namedBindings.name : undefined; + return node.importClause && node.importClause.namedBindings + && node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport + ? node.importClause.namedBindings.name : undefined; case SyntaxKind.ImportEqualsDeclaration: return node.name; case SyntaxKind.VariableDeclaration: @@ -441,49 +650,82 @@ function updateNamespaceLikeImport( newModuleSpecifier: string, oldImportId: Identifier, oldImportNode: SupportedImport, - quotePreference: QuotePreference + quotePreference: QuotePreference, ): void { const preferredNewNamespaceName = codefix.moduleSpecifierToValidIdentifier(newModuleSpecifier, ScriptTarget.ESNext); let needUniqueName = false; const toChange: Identifier[] = []; FindAllReferences.Core.eachSymbolReferenceInFile(oldImportId, checker, sourceFile, ref => { if (!isPropertyAccessExpression(ref.parent)) return; - needUniqueName = needUniqueName || !!checker.resolveName(preferredNewNamespaceName, ref, SymbolFlags.All, /*excludeGlobals*/ true); + needUniqueName = needUniqueName + || !!checker.resolveName(preferredNewNamespaceName, ref, SymbolFlags.All, /*excludeGlobals*/ true); if (movedSymbols.has(checker.getSymbolAtLocation(ref.parent.name)!)) { toChange.push(ref); } }); if (toChange.length) { - const newNamespaceName = needUniqueName ? getUniqueName(preferredNewNamespaceName, sourceFile) : preferredNewNamespaceName; + const newNamespaceName = needUniqueName ? getUniqueName(preferredNewNamespaceName, sourceFile) + : preferredNewNamespaceName; for (const ref of toChange) { changes.replaceNode(sourceFile, ref, factory.createIdentifier(newNamespaceName)); } - changes.insertNodeAfter(sourceFile, oldImportNode, updateNamespaceLikeImportNode(oldImportNode, preferredNewNamespaceName, newModuleSpecifier, quotePreference)); + changes.insertNodeAfter( + sourceFile, + oldImportNode, + updateNamespaceLikeImportNode( + oldImportNode, + preferredNewNamespaceName, + newModuleSpecifier, + quotePreference, + ), + ); } } -function updateNamespaceLikeImportNode(node: SupportedImport, newNamespaceName: string, newModuleSpecifier: string, quotePreference: QuotePreference): Node { +function updateNamespaceLikeImportNode( + node: SupportedImport, + newNamespaceName: string, + newModuleSpecifier: string, + quotePreference: QuotePreference, +): Node { const newNamespaceId = factory.createIdentifier(newNamespaceName); const newModuleString = makeStringLiteral(newModuleSpecifier, quotePreference); switch (node.kind) { case SyntaxKind.ImportDeclaration: return factory.createImportDeclaration( /*modifiers*/ undefined, - factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(newNamespaceId)), + factory.createImportClause( + /*isTypeOnly*/ false, + /*name*/ undefined, + factory.createNamespaceImport(newNamespaceId), + ), newModuleString, - /*assertClause*/ undefined); + /*assertClause*/ undefined, + ); case SyntaxKind.ImportEqualsDeclaration: - return factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, newNamespaceId, factory.createExternalModuleReference(newModuleString)); + return factory.createImportEqualsDeclaration( + /*modifiers*/ undefined, + /*isTypeOnly*/ false, + newNamespaceId, + factory.createExternalModuleReference(newModuleString), + ); case SyntaxKind.VariableDeclaration: - return factory.createVariableDeclaration(newNamespaceId, /*exclamationToken*/ undefined, /*type*/ undefined, createRequireCall(newModuleString)); + return factory.createVariableDeclaration( + newNamespaceId, + /*exclamationToken*/ undefined, + /*type*/ undefined, + createRequireCall(newModuleString), + ); default: return Debug.assertNever(node, `Unexpected node kind ${(node as SupportedImport).kind}`); } } function createRequireCall(moduleSpecifier: StringLiteralLike): CallExpression { - return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [moduleSpecifier]); + return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, [ + moduleSpecifier, + ]); } /** @internal */ @@ -499,7 +741,10 @@ export function forEachImportInStatement(statement: Statement, cb: (importNode: if (isStringLiteral(statement.moduleSpecifier)) cb(statement as SupportedImport); } else if (isImportEqualsDeclaration(statement)) { - if (isExternalModuleReference(statement.moduleReference) && isStringLiteralLike(statement.moduleReference.expression)) { + if ( + isExternalModuleReference(statement.moduleReference) + && isStringLiteralLike(statement.moduleReference.expression) + ) { cb(statement as SupportedImport); } } @@ -514,9 +759,9 @@ export function forEachImportInStatement(statement: Statement, cb: (importNode: /** @internal */ export type SupportedImport = - | ImportDeclaration & { moduleSpecifier: StringLiteralLike } - | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteralLike } } - | VariableDeclaration & { initializer: RequireOrImportCall }; + | ImportDeclaration & { moduleSpecifier: StringLiteralLike; } + | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteralLike; }; } + | VariableDeclaration & { initializer: RequireOrImportCall; }; /** @internal */ export type SupportedImportStatement = @@ -532,7 +777,7 @@ export function createOldFileImportsFromTargetFile( program: Program, host: LanguageServiceHost, useEs6Imports: boolean, - quotePreference: QuotePreference + quotePreference: QuotePreference, ): AnyImportOrRequireStatement | undefined { let defaultImport: Identifier | undefined; const imports: string[] = []; @@ -544,7 +789,16 @@ export function createOldFileImportsFromTargetFile( imports.push(symbol.name); } }); - return makeImportOrRequire(sourceFile, defaultImport, imports, targetFileNameWithExtension, program, host, useEs6Imports, quotePreference); + return makeImportOrRequire( + sourceFile, + defaultImport, + imports, + targetFileNameWithExtension, + program, + host, + useEs6Imports, + quotePreference, + ); } /** @internal */ @@ -556,34 +810,68 @@ export function makeImportOrRequire( program: Program, host: LanguageServiceHost, useEs6Imports: boolean, - quotePreference: QuotePreference + quotePreference: QuotePreference, ): AnyImportOrRequireStatement | undefined { const pathToTargetFile = resolvePath(getDirectoryPath(sourceFile.path), targetFileNameWithExtension); - const pathToTargetFileWithCorrectExtension = getModuleSpecifier(program.getCompilerOptions(), sourceFile, sourceFile.path, pathToTargetFile, createModuleSpecifierResolutionHost(program, host)); + const pathToTargetFileWithCorrectExtension = getModuleSpecifier( + program.getCompilerOptions(), + sourceFile, + sourceFile.path, + pathToTargetFile, + createModuleSpecifierResolutionHost(program, host), + ); if (useEs6Imports) { - const specifiers = imports.map(i => factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, factory.createIdentifier(i))); + const specifiers = imports.map(i => + factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, factory.createIdentifier(i)) + ); return makeImportIfNecessary(defaultImport, specifiers, pathToTargetFileWithCorrectExtension, quotePreference); } else { Debug.assert(!defaultImport, "No default import should exist"); // If there's a default export, it should have been an es6 module. - const bindingElements = imports.map(i => factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, i)); + const bindingElements = imports.map(i => + factory.createBindingElement(/*dotDotDotToken*/ undefined, /*propertyName*/ undefined, i) + ); return bindingElements.length - ? makeVariableStatement(factory.createObjectBindingPattern(bindingElements), /*type*/ undefined, createRequireCall(makeStringLiteral(pathToTargetFileWithCorrectExtension, quotePreference))) as RequireVariableStatement + ? makeVariableStatement( + factory.createObjectBindingPattern(bindingElements), + /*type*/ undefined, + createRequireCall(makeStringLiteral(pathToTargetFileWithCorrectExtension, quotePreference)), + ) as RequireVariableStatement : undefined; } } -function makeVariableStatement(name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined, flags: NodeFlags = NodeFlags.Const) { - return factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, initializer)], flags)); +function makeVariableStatement( + name: BindingName, + type: TypeNode | undefined, + initializer: Expression | undefined, + flags: NodeFlags = NodeFlags.Const, +) { + return factory.createVariableStatement( + /*modifiers*/ undefined, + factory.createVariableDeclarationList([ + factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, initializer), + ], flags), + ); } /** @internal */ -export function addExports(sourceFile: SourceFile, toMove: readonly Statement[], needExport: Set, useEs6Exports: boolean): readonly Statement[] { +export function addExports( + sourceFile: SourceFile, + toMove: readonly Statement[], + needExport: Set, + useEs6Exports: boolean, +): readonly Statement[] { return flatMap(toMove, statement => { - if (isTopLevelDeclarationStatement(statement) && - !isExported(sourceFile, statement, useEs6Exports) && - forEachTopLevelDeclaration(statement, d => needExport.has(Debug.checkDefined(tryCast(d, canHaveSymbol)?.symbol)))) { + if ( + isTopLevelDeclarationStatement(statement) + && !isExported(sourceFile, statement, useEs6Exports) + && forEachTopLevelDeclaration( + statement, + d => needExport.has(Debug.checkDefined(tryCast(d, canHaveSymbol)?.symbol)), + ) + ) { const exports = addExport(getSynthesizedDeepClone(statement), useEs6Exports); if (exports) return exports; } @@ -591,16 +879,29 @@ export function addExports(sourceFile: SourceFile, toMove: readonly Statement[], }); } -function isExported(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, useEs6Exports: boolean, name?: Identifier): boolean { +function isExported( + sourceFile: SourceFile, + decl: TopLevelDeclarationStatement, + useEs6Exports: boolean, + name?: Identifier, +): boolean { if (useEs6Exports) { - return !isExpressionStatement(decl) && hasSyntacticModifier(decl, ModifierFlags.Export) || !!(name && sourceFile.symbol && sourceFile.symbol.exports?.has(name.escapedText)); + return !isExpressionStatement(decl) && hasSyntacticModifier(decl, ModifierFlags.Export) + || !!(name && sourceFile.symbol && sourceFile.symbol.exports?.has(name.escapedText)); } - return !!sourceFile.symbol && !!sourceFile.symbol.exports && - getNamesToExportInCommonJS(decl).some(name => sourceFile.symbol.exports!.has(escapeLeadingUnderscores(name))); + return !!sourceFile.symbol && !!sourceFile.symbol.exports + && 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 { +export function deleteUnusedImports( + sourceFile: SourceFile, + importDecl: SupportedImport, + changes: textChanges.ChangeTracker, + isUnused: (name: Identifier) => boolean, +): void { switch (importDecl.kind) { case SyntaxKind.ImportDeclaration: deleteUnusedImportsInDeclaration(sourceFile, importDecl, changes, isUnused); @@ -618,12 +919,18 @@ export function deleteUnusedImports(sourceFile: SourceFile, importDecl: Supporte } } -function deleteUnusedImportsInDeclaration(sourceFile: SourceFile, importDecl: ImportDeclaration, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean): void { +function deleteUnusedImportsInDeclaration( + sourceFile: SourceFile, + importDecl: ImportDeclaration, + changes: textChanges.ChangeTracker, + isUnused: (name: Identifier) => boolean, +): void { if (!importDecl.importClause) return; const { name, namedBindings } = importDecl.importClause; const defaultUnused = !name || isUnused(name); - const namedBindingsUnused = !namedBindings || - (namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) : namedBindings.elements.length !== 0 && namedBindings.elements.every(e => isUnused(e.name))); + const namedBindingsUnused = !namedBindings + || (namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) + : namedBindings.elements.length !== 0 && namedBindings.elements.every(e => isUnused(e.name))); if (defaultUnused && namedBindingsUnused) { changes.delete(sourceFile, importDecl); } @@ -636,7 +943,12 @@ function deleteUnusedImportsInDeclaration(sourceFile: SourceFile, importDecl: Im changes.replaceNode( sourceFile, importDecl.importClause, - factory.updateImportClause(importDecl.importClause, importDecl.importClause.isTypeOnly, name, /*namedBindings*/ undefined) + factory.updateImportClause( + importDecl.importClause, + importDecl.importClause.isTypeOnly, + name, + /*namedBindings*/ undefined, + ), ); } else if (namedBindings.kind === SyntaxKind.NamedImports) { @@ -648,14 +960,24 @@ function deleteUnusedImportsInDeclaration(sourceFile: SourceFile, importDecl: Im } } -function deleteUnusedImportsInVariableDeclaration(sourceFile: SourceFile, varDecl: VariableDeclaration, changes: textChanges.ChangeTracker, isUnused: (name: Identifier) => boolean) { +function deleteUnusedImportsInVariableDeclaration( + sourceFile: SourceFile, + varDecl: VariableDeclaration, + changes: textChanges.ChangeTracker, + isUnused: (name: Identifier) => boolean, +) { const { name } = varDecl; switch (name.kind) { case SyntaxKind.Identifier: if (isUnused(name)) { - if (varDecl.initializer && isRequireCall(varDecl.initializer, /*requireStringLiteralLikeArgument*/ true)) { - changes.delete(sourceFile, - isVariableDeclarationList(varDecl.parent) && length(varDecl.parent.declarations) === 1 ? varDecl.parent.parent : varDecl); + if ( + varDecl.initializer && isRequireCall(varDecl.initializer, /*requireStringLiteralLikeArgument*/ true) + ) { + changes.delete( + sourceFile, + isVariableDeclarationList(varDecl.parent) && length(varDecl.parent.declarations) === 1 + ? varDecl.parent.parent : varDecl, + ); } else { changes.delete(sourceFile, name); @@ -666,8 +988,11 @@ function deleteUnusedImportsInVariableDeclaration(sourceFile: SourceFile, varDec break; case SyntaxKind.ObjectBindingPattern: if (name.elements.every(e => isIdentifier(e.name) && isUnused(e.name))) { - changes.delete(sourceFile, - isVariableDeclarationList(varDecl.parent) && varDecl.parent.declarations.length === 1 ? varDecl.parent.parent : varDecl); + changes.delete( + sourceFile, + isVariableDeclarationList(varDecl.parent) && varDecl.parent.declarations.length === 1 + ? varDecl.parent.parent : varDecl, + ); } else { for (const element of name.elements) { @@ -693,13 +1018,30 @@ function addExport(decl: TopLevelDeclarationStatement, useEs6Exports: boolean): } function addEs6Export(d: TopLevelDeclarationStatement): TopLevelDeclarationStatement { - const modifiers = canHaveModifiers(d) ? concatenate([factory.createModifier(SyntaxKind.ExportKeyword)], getModifiers(d)) : undefined; + const modifiers = canHaveModifiers(d) + ? concatenate([factory.createModifier(SyntaxKind.ExportKeyword)], getModifiers(d)) : undefined; switch (d.kind) { case SyntaxKind.FunctionDeclaration: - return factory.updateFunctionDeclaration(d, modifiers, d.asteriskToken, d.name, d.typeParameters, d.parameters, d.type, d.body); + return factory.updateFunctionDeclaration( + d, + modifiers, + d.asteriskToken, + d.name, + d.typeParameters, + d.parameters, + d.type, + d.body, + ); case SyntaxKind.ClassDeclaration: const decorators = canHaveDecorators(d) ? getDecorators(d) : undefined; - return factory.updateClassDeclaration(d, concatenate(decorators, modifiers), d.name, d.typeParameters, d.heritageClauses, d.members); + return factory.updateClassDeclaration( + d, + concatenate(decorators, modifiers), + d.name, + d.typeParameters, + d.heritageClauses, + d.members, + ); case SyntaxKind.VariableStatement: return factory.updateVariableStatement(d, modifiers, d.declarationList); case SyntaxKind.ModuleDeclaration: @@ -709,7 +1051,14 @@ function addEs6Export(d: TopLevelDeclarationStatement): TopLevelDeclarationState case SyntaxKind.TypeAliasDeclaration: return factory.updateTypeAliasDeclaration(d, modifiers, d.name, d.typeParameters, d.type); case SyntaxKind.InterfaceDeclaration: - return factory.updateInterfaceDeclaration(d, modifiers, d.name, d.typeParameters, d.heritageClauses, d.members); + return factory.updateInterfaceDeclaration( + d, + modifiers, + d.name, + d.typeParameters, + d.heritageClauses, + d.members, + ); case SyntaxKind.ImportEqualsDeclaration: return factory.updateImportEqualsDeclaration(d, modifiers, d.isTypeOnly, d.name, d.moduleReference); case SyntaxKind.ExpressionStatement: @@ -729,7 +1078,9 @@ function createExportAssignment(name: string): Statement { factory.createBinaryExpression( factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(name)), SyntaxKind.EqualsToken, - factory.createIdentifier(name))); + factory.createIdentifier(name), + ), + ); } function getNamesToExportInCommonJS(decl: TopLevelDeclarationStatement): readonly string[] { @@ -754,7 +1105,11 @@ function getNamesToExportInCommonJS(decl: TopLevelDeclarationStatement): readonl } /** @internal */ -export function filterImport(i: SupportedImport, moduleSpecifier: StringLiteralLike, keep: (name: Identifier) => boolean): SupportedImportStatement | undefined { +export function filterImport( + i: SupportedImport, + moduleSpecifier: StringLiteralLike, + keep: (name: Identifier) => boolean, +): SupportedImportStatement | undefined { switch (i.kind) { case SyntaxKind.ImportDeclaration: { const clause = i.importClause; @@ -762,21 +1117,30 @@ export function filterImport(i: SupportedImport, moduleSpecifier: StringLiteralL const defaultImport = clause.name && keep(clause.name) ? clause.name : undefined; const namedBindings = clause.namedBindings && filterNamedBindings(clause.namedBindings, keep); return defaultImport || namedBindings - ? factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(clause.isTypeOnly, defaultImport, namedBindings), getSynthesizedDeepClone(moduleSpecifier), /*assertClause*/ undefined) + ? factory.createImportDeclaration( + /*modifiers*/ undefined, + factory.createImportClause(clause.isTypeOnly, defaultImport, namedBindings), + getSynthesizedDeepClone(moduleSpecifier), + /*assertClause*/ undefined, + ) : undefined; } case SyntaxKind.ImportEqualsDeclaration: return keep(i.name) ? i : undefined; case SyntaxKind.VariableDeclaration: { const name = filterBindingName(i.name, keep); - return name ? makeVariableStatement(name, i.type, createRequireCall(moduleSpecifier), i.parent.flags) : undefined; + return name ? makeVariableStatement(name, i.type, createRequireCall(moduleSpecifier), i.parent.flags) + : undefined; } default: return Debug.assertNever(i, `Unexpected import kind ${(i as SupportedImport).kind}`); } } -function filterNamedBindings(namedBindings: NamedImportBindings, keep: (name: Identifier) => boolean): NamedImportBindings | undefined { +function filterNamedBindings( + namedBindings: NamedImportBindings, + keep: (name: Identifier) => boolean, +): NamedImportBindings | undefined { if (namedBindings.kind === SyntaxKind.NamespaceImport) { return keep(namedBindings.name) ? namedBindings : undefined; } @@ -794,7 +1158,9 @@ function filterBindingName(name: BindingName, keep: (name: Identifier) => boolea return name; case SyntaxKind.ObjectBindingPattern: { // We can't handle nested destructurings or property names well here, so just copy them all. - const newElements = name.elements.filter(prop => prop.propertyName || !isIdentifier(prop.name) || keep(prop.name)); + const newElements = name.elements.filter(prop => + prop.propertyName || !isIdentifier(prop.name) || keep(prop.name) + ); return newElements.length ? factory.createObjectBindingPattern(newElements) : undefined; } } @@ -812,14 +1178,25 @@ export function getTopLevelDeclarationStatement(d: TopLevelDeclaration): TopLeve return d.parent.parent; case SyntaxKind.BindingElement: return getTopLevelDeclarationStatement( - cast(d.parent.parent, (p): p is TopLevelVariableDeclaration | BindingElement => isVariableDeclaration(p) || isBindingElement(p))); + cast( + d.parent.parent, + (p): p is TopLevelVariableDeclaration | BindingElement => + isVariableDeclaration(p) || isBindingElement(p), + ), + ); default: return d; } } /** @internal */ -export function addExportToChanges(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, name: Identifier, changes: textChanges.ChangeTracker, useEs6Exports: boolean): void { +export 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); @@ -858,7 +1235,9 @@ export interface UsageInfo { } /** @internal */ -export type TopLevelExpressionStatement = ExpressionStatement & { expression: BinaryExpression & { left: PropertyAccessExpression } }; // 'exports.x = ...' +export type TopLevelExpressionStatement = ExpressionStatement & { + expression: BinaryExpression & { left: PropertyAccessExpression; }; +}; // 'exports.x = ...' /** @internal */ export type NonVariableTopLevelDeclaration = @@ -871,14 +1250,21 @@ export type NonVariableTopLevelDeclaration = | TopLevelExpressionStatement | ImportEqualsDeclaration; - /** @internal */ -export interface TopLevelVariableDeclaration extends VariableDeclaration { parent: VariableDeclarationList & { parent: VariableStatement; }; } +/** @internal */ +export interface TopLevelVariableDeclaration extends VariableDeclaration { + parent: VariableDeclarationList & { parent: VariableStatement; }; +} /** @internal */ export type TopLevelDeclaration = NonVariableTopLevelDeclaration | TopLevelVariableDeclaration | BindingElement; /** @internal */ -export function createNewFileName(oldFile: SourceFile, program: Program, context: RefactorContext, host: LanguageServiceHost): string { +export function createNewFileName( + oldFile: SourceFile, + program: Program, + context: RefactorContext, + host: LanguageServiceHost, +): string { const checker = program.getTypeChecker(); const toMove = getStatementsToMove(context); let usage; @@ -887,23 +1273,28 @@ export function createNewFileName(oldFile: SourceFile, program: Program, context const currentDirectory = getDirectoryPath(oldFile.fileName); const extension = extensionFromPath(oldFile.fileName); const newFileName = combinePaths( - // new file is always placed in the same directory as the old file - currentDirectory, - // ensures the filename computed below isn't already taken - makeUniqueFilename( - // infers a name for the new file from the symbols being moved - inferNewFileName(usage.oldFileImportsFromTargetFile, usage.movedSymbols), - extension, + // new file is always placed in the same directory as the old file currentDirectory, - host)) - // new file has same extension as old file - + extension; - return newFileName; + // ensures the filename computed below isn't already taken + makeUniqueFilename( + // infers a name for the new file from the symbols being moved + inferNewFileName(usage.oldFileImportsFromTargetFile, usage.movedSymbols), + extension, + currentDirectory, + host, + ), + ) + // new file has same extension as old file + + extension; + return newFileName; } return ""; } -interface RangeToMove { readonly toMove: readonly Statement[]; readonly afterLast: Statement | undefined; } +interface RangeToMove { + readonly toMove: readonly Statement[]; + readonly afterLast: Statement | undefined; +} function getRangeToMove(context: RefactorContext): RangeToMove | undefined { const { file } = context; @@ -936,7 +1327,7 @@ function getRangeToMove(context: RefactorContext): RangeToMove | undefined { return { toMove: statements.slice(startNodeIndex, endNodeIndex === -1 ? statements.length : endNodeIndex + 1), - afterLast: endNodeIndex === -1 ? undefined : statements[endNodeIndex + 1] + afterLast: endNodeIndex === -1 ? undefined : statements[endNodeIndex + 1], }; } @@ -968,7 +1359,9 @@ function isPureImport(node: Node): boolean { case SyntaxKind.ImportEqualsDeclaration: return !hasSyntacticModifier(node, ModifierFlags.Export); case SyntaxKind.VariableStatement: - return (node as VariableStatement).declarationList.declarations.every(d => !!d.initializer && isRequireCall(d.initializer, /*requireStringLiteralLikeArgument*/ true)); + return (node as VariableStatement).declarationList.declarations.every(d => + !!d.initializer && isRequireCall(d.initializer, /*requireStringLiteralLikeArgument*/ true) + ); default: return false; } @@ -989,7 +1382,12 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], for (const statement of toMove) { forEachTopLevelDeclaration(statement, decl => { - movedSymbols.add(Debug.checkDefined(isExpressionStatement(decl) ? checker.getSymbolAtLocation(decl.expression.left) : decl.symbol, "Need a symbol here")); + movedSymbols.add( + Debug.checkDefined( + isExpressionStatement(decl) ? checker.getSymbolAtLocation(decl.expression.left) : decl.symbol, + "Need a symbol here", + ), + ); }); } for (const statement of toMove) { @@ -998,9 +1396,16 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], for (const decl of symbol.declarations) { if (isInImport(decl)) { const prevIsTypeOnly = oldImportsNeededByTargetFile.get(symbol); - oldImportsNeededByTargetFile.set(symbol, prevIsTypeOnly === undefined ? isValidTypeOnlyUseSite : prevIsTypeOnly && isValidTypeOnlyUseSite); + oldImportsNeededByTargetFile.set( + symbol, + prevIsTypeOnly === undefined ? isValidTypeOnlyUseSite + : prevIsTypeOnly && isValidTypeOnlyUseSite, + ); } - else if (isTopLevelDeclaration(decl) && sourceFileOfTopLevelDeclaration(decl) === oldFile && !movedSymbols.has(symbol)) { + else if ( + isTopLevelDeclaration(decl) && sourceFileOfTopLevelDeclaration(decl) === oldFile + && !movedSymbols.has(symbol) + ) { targetFileImportsFromOldFile.add(symbol); } } @@ -1023,7 +1428,13 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], }); } - return { movedSymbols, targetFileImportsFromOldFile, oldFileImportsFromTargetFile, oldImportsNeededByTargetFile, unusedImportsFromOldFile }; + return { + movedSymbols, + targetFileImportsFromOldFile, + oldFileImportsFromTargetFile, + oldImportsNeededByTargetFile, + unusedImportsFromOldFile, + }; function getJsxNamespaceSymbol(containsJsx: Node | undefined) { if (containsJsx === undefined) { @@ -1035,7 +1446,12 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], // Strictly speaking, this could resolve to a symbol other than the JSX namespace. // This will produce erroneous output (probably, an incorrectly copied import) but // is expected to be very rare and easily reversible. - const jsxNamespaceSymbol = checker.resolveName(jsxNamespace, containsJsx, SymbolFlags.Namespace, /*excludeGlobals*/ true); + const jsxNamespaceSymbol = checker.resolveName( + jsxNamespace, + containsJsx, + SymbolFlags.Namespace, + /*excludeGlobals*/ true, + ); return !!jsxNamespaceSymbol && some(jsxNamespaceSymbol.declarations, isInImport) ? jsxNamespaceSymbol @@ -1043,9 +1459,14 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], } } -function makeUniqueFilename(proposedFilename: string, extension: string, inDirectory: string, host: LanguageServiceHost): string { +function makeUniqueFilename( + proposedFilename: string, + extension: string, + inDirectory: string, + host: LanguageServiceHost, +): string { let newFilename = proposedFilename; - for (let i = 1; ; i++) { + for (let i = 1;; i++) { const name = combinePaths(inDirectory, newFilename + extension); if (!host.fileExists(name)) return newFilename; newFilename = `${proposedFilename}.${i}`; @@ -1053,10 +1474,15 @@ function makeUniqueFilename(proposedFilename: string, extension: string, inDirec } function inferNewFileName(importsFromNewFile: Set, movedSymbols: Set): string { - return forEachKey(importsFromNewFile, symbolNameNoDefault) || forEachKey(movedSymbols, symbolNameNoDefault) || "newFile"; + 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, + onReference: (s: Symbol, isValidTypeOnlyUseSite: boolean) => void, +) { node.forEachChild(function cb(node) { if (isIdentifier(node) && !isDeclarationName(node)) { const sym = checker.getSymbolAtLocation(node); @@ -1077,14 +1503,27 @@ function forEachTopLevelDeclaration(statement: Statement, cb: (node: TopLevel case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.ImportEqualsDeclaration: - return cb(statement as FunctionDeclaration | ClassDeclaration | EnumDeclaration | ModuleDeclaration | TypeAliasDeclaration | InterfaceDeclaration | ImportEqualsDeclaration); + return cb( + statement as + | FunctionDeclaration + | ClassDeclaration + | EnumDeclaration + | ModuleDeclaration + | TypeAliasDeclaration + | InterfaceDeclaration + | ImportEqualsDeclaration, + ); case SyntaxKind.VariableStatement: - return firstDefined((statement as VariableStatement).declarationList.declarations, decl => forEachTopLevelDeclarationInBindingName(decl.name, cb)); + return firstDefined( + (statement as VariableStatement).declarationList.declarations, + decl => forEachTopLevelDeclarationInBindingName(decl.name, cb), + ); case SyntaxKind.ExpressionStatement: { const { expression } = statement as ExpressionStatement; - return isBinaryExpression(expression) && getAssignmentDeclarationKind(expression) === AssignmentDeclarationKind.ExportsProperty + return isBinaryExpression(expression) + && getAssignmentDeclarationKind(expression) === AssignmentDeclarationKind.ExportsProperty ? cb(statement as TopLevelExpressionStatement) : undefined; } @@ -1108,25 +1547,38 @@ function isInImport(decl: Declaration) { } function isVariableDeclarationInImport(decl: VariableDeclaration) { - return isSourceFile(decl.parent.parent.parent) && - !!decl.initializer && isRequireCall(decl.initializer, /*requireStringLiteralLikeArgument*/ true); + return isSourceFile(decl.parent.parent.parent) + && !!decl.initializer && isRequireCall(decl.initializer, /*requireStringLiteralLikeArgument*/ true); } /** @internal */ export function isTopLevelDeclaration(node: Node): node is TopLevelDeclaration { - return isNonVariableTopLevelDeclaration(node) && isSourceFile(node.parent) || isVariableDeclaration(node) && isSourceFile(node.parent.parent.parent); + return isNonVariableTopLevelDeclaration(node) && isSourceFile(node.parent) + || isVariableDeclaration(node) && isSourceFile(node.parent.parent.parent); } function sourceFileOfTopLevelDeclaration(node: TopLevelDeclaration): Node { return isVariableDeclaration(node) ? node.parent.parent.parent : node.parent; } -function forEachTopLevelDeclarationInBindingName(name: BindingName, cb: (node: TopLevelDeclaration) => T): T | undefined { +function forEachTopLevelDeclarationInBindingName( + name: BindingName, + cb: (node: TopLevelDeclaration) => T, +): T | undefined { switch (name.kind) { case SyntaxKind.Identifier: - return cb(cast(name.parent, (x): x is TopLevelVariableDeclaration | BindingElement => isVariableDeclaration(x) || isBindingElement(x))); + return cb( + cast( + name.parent, + (x): x is TopLevelVariableDeclaration | BindingElement => + isVariableDeclaration(x) || isBindingElement(x), + ), + ); case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ObjectBindingPattern: - return firstDefined(name.elements, em => isOmittedExpression(em) ? undefined : forEachTopLevelDeclarationInBindingName(em.name, cb)); + return firstDefined( + name.elements, + em => isOmittedExpression(em) ? undefined : forEachTopLevelDeclarationInBindingName(em.name, cb), + ); default: return Debug.assertNever(name, `Unexpected name kind ${(name as BindingName).kind}`); } @@ -1147,7 +1599,13 @@ function isNonVariableTopLevelDeclaration(node: Node): node is NonVariableTopLev } } -function moveStatementsToTargetFile(changes: textChanges.ChangeTracker, program: Program, statements: readonly Statement[], targetFile: SourceFile, toMove: ToMove) { +function moveStatementsToTargetFile( + changes: textChanges.ChangeTracker, + program: Program, + statements: readonly Statement[], + targetFile: SourceFile, + toMove: ToMove, +) { const removedExports = new Set(); const targetExports = targetFile.symbol?.exports; if (targetExports) { @@ -1157,23 +1615,35 @@ function moveStatementsToTargetFile(changes: textChanges.ChangeTracker, program: for (const node of toMove.all) { if (isTopLevelDeclarationStatement(node) && hasSyntacticModifier(node, ModifierFlags.Export)) { forEachTopLevelDeclaration(node, declaration => { - const targetDeclarations = canHaveSymbol(declaration) ? targetExports.get(declaration.symbol.escapedName)?.declarations : undefined; + const targetDeclarations = canHaveSymbol(declaration) + ? targetExports.get(declaration.symbol.escapedName)?.declarations : undefined; const exportDeclaration = firstDefined(targetDeclarations, d => - isExportDeclaration(d) ? d : - isExportSpecifier(d) ? tryCast(d.parent.parent, isExportDeclaration) : undefined); + isExportDeclaration(d) ? d + : isExportSpecifier(d) ? tryCast(d.parent.parent, isExportDeclaration) : undefined); if (exportDeclaration && exportDeclaration.moduleSpecifier) { - targetToSourceExports.set(exportDeclaration, - (targetToSourceExports.get(exportDeclaration) || new Set()).add(declaration)); + targetToSourceExports.set( + exportDeclaration, + (targetToSourceExports.get(exportDeclaration) || new Set()).add(declaration), + ); } }); } } for (const [exportDeclaration, topLevelDeclarations] of arrayFrom(targetToSourceExports)) { - if (exportDeclaration.exportClause && isNamedExports(exportDeclaration.exportClause) && length(exportDeclaration.exportClause.elements)) { + if ( + exportDeclaration.exportClause && isNamedExports(exportDeclaration.exportClause) + && length(exportDeclaration.exportClause.elements) + ) { const elements = exportDeclaration.exportClause.elements; - const updatedElements = filter(elements, elem => - find(skipAlias(elem.symbol, checker).declarations, d => isTopLevelDeclaration(d) && topLevelDeclarations.has(d)) === undefined); + const updatedElements = filter( + elements, + elem => + find( + skipAlias(elem.symbol, checker).declarations, + d => isTopLevelDeclaration(d) && topLevelDeclarations.has(d), + ) === undefined, + ); if (length(updatedElements) === 0) { changes.deleteNode(targetFile, exportDeclaration); @@ -1182,16 +1652,30 @@ function moveStatementsToTargetFile(changes: textChanges.ChangeTracker, program: } if (length(updatedElements) < length(elements)) { - changes.replaceNode(targetFile, exportDeclaration, - factory.updateExportDeclaration(exportDeclaration, exportDeclaration.modifiers, exportDeclaration.isTypeOnly, - factory.updateNamedExports(exportDeclaration.exportClause , factory.createNodeArray(updatedElements, elements.hasTrailingComma)), exportDeclaration.moduleSpecifier, exportDeclaration.assertClause)); + changes.replaceNode( + targetFile, + exportDeclaration, + factory.updateExportDeclaration( + exportDeclaration, + exportDeclaration.modifiers, + exportDeclaration.isTypeOnly, + factory.updateNamedExports( + exportDeclaration.exportClause, + factory.createNodeArray(updatedElements, elements.hasTrailingComma), + ), + exportDeclaration.moduleSpecifier, + exportDeclaration.assertClause, + ), + ); } } } } - const lastReExport = findLast(targetFile.statements, n => - isExportDeclaration(n) && !!n.moduleSpecifier && !removedExports.has(n)); + const lastReExport = findLast( + targetFile.statements, + n => isExportDeclaration(n) && !!n.moduleSpecifier && !removedExports.has(n), + ); if (lastReExport) { changes.insertNodesBefore(targetFile, lastReExport, statements, /*blankLineBetween*/ true); } @@ -1208,7 +1692,10 @@ function getOverloadRangeToMove(sourceFile: SourceFile, statement: Statement) { } const firstDecl = declarations[0]; const lastDecl = declarations[length(declarations) - 1]; - const statementsToMove = mapDefined(declarations, d => getSourceFileOfNode(d) === sourceFile && isStatement(d) ? d : undefined); + const statementsToMove = mapDefined( + declarations, + d => getSourceFileOfNode(d) === sourceFile && isStatement(d) ? d : undefined, + ); const end = findIndex(sourceFile.statements, s => s.end >= lastDecl.end); const start = findIndex(sourceFile.statements, s => s.end >= firstDecl.end); return { toMove: statementsToMove, start, end }; diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index 10183ad20acc4..2daa0e5ccbc9f 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -49,7 +49,7 @@ import { SupportedImportStatement, ToMove, updateImportsInOtherFiles, - UsageInfo + UsageInfo, } from "../_namespaces/ts.refactor"; const refactorName = "Move to a new file"; @@ -68,8 +68,15 @@ registerRefactor(refactorName, { return [{ name: refactorName, description, actions: [moveToNewFileAction] }]; } if (context.preferences.provideRefactorNotApplicableReason) { - return [{ name: refactorName, description, actions: - [{ ...moveToNewFileAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_statement_or_statements) }] + return [{ + name: refactorName, + description, + actions: [{ + ...moveToNewFileAction, + notApplicableReason: getLocaleSpecificMessage( + Diagnostics.Selection_is_not_a_valid_statement_or_statements, + ), + }], }]; } return emptyArray; @@ -77,36 +84,74 @@ registerRefactor(refactorName, { getEditsForAction: function getRefactorEditsToMoveToNewFile(context, actionName): RefactorEditInfo { Debug.assert(actionName === refactorName, "Wrong refactor invoked"); const statements = Debug.checkDefined(getStatementsToMove(context)); - const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, statements, t, context.host, context.preferences, context)); + const edits = textChanges.ChangeTracker.with( + context, + t => doChange(context.file, context.program, statements, t, context.host, context.preferences, context), + ); return { edits, renameFilename: undefined, renameLocation: undefined }; - } + }, }); -function doChange(oldFile: SourceFile, program: Program, toMove: ToMove, changes: textChanges.ChangeTracker, host: LanguageServiceHost, preferences: UserPreferences, context: RefactorContext): void { +function doChange( + oldFile: SourceFile, + program: Program, + toMove: ToMove, + changes: textChanges.ChangeTracker, + host: LanguageServiceHost, + preferences: UserPreferences, + context: RefactorContext, +): void { const checker = program.getTypeChecker(); const usage = getUsageInfo(oldFile, toMove.all, checker); const newFilename = createNewFileName(oldFile, program, context, host); // If previous file was global, this is easy. - changes.createNewFile(oldFile, newFilename, getNewStatementsAndRemoveFromOldFile(oldFile, usage, changes, toMove, program, host, newFilename, preferences)); + changes.createNewFile( + oldFile, + newFilename, + getNewStatementsAndRemoveFromOldFile(oldFile, usage, changes, toMove, program, host, newFilename, preferences), + ); addNewFileToTsconfig(program, changes, oldFile.fileName, newFilename, hostGetCanonicalFileName(host)); } function getNewStatementsAndRemoveFromOldFile( - oldFile: SourceFile, usage: UsageInfo, changes: textChanges.ChangeTracker, toMove: ToMove, program: Program, host: LanguageServiceHost, newFilename: string, preferences: UserPreferences, + oldFile: SourceFile, + usage: UsageInfo, + changes: textChanges.ChangeTracker, + toMove: ToMove, + program: Program, + host: LanguageServiceHost, + newFilename: string, + preferences: UserPreferences, ) { const checker = program.getTypeChecker(); const prologueDirectives = takeWhile(oldFile.statements, isPrologueDirective); - if (oldFile.externalModuleIndicator === undefined && oldFile.commonJsModuleIndicator === undefined && usage.oldImportsNeededByTargetFile.size === 0) { + if ( + oldFile.externalModuleIndicator === undefined && oldFile.commonJsModuleIndicator === undefined + && usage.oldImportsNeededByTargetFile.size === 0 + ) { deleteMovedStatements(oldFile, toMove.ranges, changes); return [...prologueDirectives, ...toMove.all]; } - const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(newFilename, program, host, !!oldFile.commonJsModuleIndicator); + const useEsModuleSyntax = !fileShouldUseJavaScriptRequire( + newFilename, + program, + host, + !!oldFile.commonJsModuleIndicator, + ); const quotePreference = getQuotePreference(oldFile, preferences); - const importsFromNewFile = createOldFileImportsFromTargetFile(oldFile, usage.oldFileImportsFromTargetFile, newFilename, program, host, useEsModuleSyntax, quotePreference); + const importsFromNewFile = createOldFileImportsFromTargetFile( + oldFile, + usage.oldFileImportsFromTargetFile, + newFilename, + program, + host, + useEsModuleSyntax, + quotePreference, + ); if (importsFromNewFile) { insertImports(changes, oldFile, importsFromNewFile, /*blankLineBetween*/ true, preferences); } @@ -115,14 +160,24 @@ function getNewStatementsAndRemoveFromOldFile( deleteMovedStatements(oldFile, toMove.ranges, changes); updateImportsInOtherFiles(changes, program, host, oldFile, usage.movedSymbols, newFilename, quotePreference); - const imports = getNewFileImportsAndAddExportInOldFile(oldFile, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, checker, program, host, useEsModuleSyntax, quotePreference); + const imports = getNewFileImportsAndAddExportInOldFile( + oldFile, + usage.oldImportsNeededByTargetFile, + usage.targetFileImportsFromOldFile, + changes, + checker, + program, + host, + useEsModuleSyntax, + quotePreference, + ); const body = addExports(oldFile, toMove.all, usage.oldFileImportsFromTargetFile, useEsModuleSyntax); if (imports.length && body.length) { return [ ...prologueDirectives, ...imports, SyntaxKind.NewLineTrivia as const, - ...body + ...body, ]; } @@ -147,7 +202,14 @@ function getNewFileImportsAndAddExportInOldFile( const copiedOldImports: SupportedImportStatement[] = []; for (const oldStatement of oldFile.statements) { forEachImportInStatement(oldStatement, i => { - append(copiedOldImports, filterImport(i, moduleSpecifierFromImport(i), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + append( + copiedOldImports, + filterImport( + i, + moduleSpecifierFromImport(i), + name => importsToCopy.has(checker.getSymbolAtLocation(name)!), + ), + ); }); } @@ -177,6 +239,18 @@ function getNewFileImportsAndAddExportInOldFile( } }); - append(copiedOldImports, makeImportOrRequire(oldFile, oldFileDefault, oldFileNamedImports, getBaseFileName(oldFile.fileName), program, host, useEsModuleSyntax, quotePreference)); + append( + copiedOldImports, + makeImportOrRequire( + oldFile, + oldFileDefault, + oldFileNamedImports, + getBaseFileName(oldFile.fileName), + program, + host, + useEsModuleSyntax, + quotePreference, + ), + ); return copiedOldImports; } diff --git a/src/services/rename.ts b/src/services/rename.ts index 094e22b15a0f9..cfd7ff2dc820a 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -54,7 +54,12 @@ import { } from "./_namespaces/ts"; /** @internal */ -export function getRenameInfo(program: Program, sourceFile: SourceFile, position: number, preferences: UserPreferences): RenameInfo { +export function getRenameInfo( + program: Program, + sourceFile: SourceFile, + position: number, + preferences: UserPreferences, +): RenameInfo { const node = getAdjustedRenameLocation(getTouchingPropertyName(sourceFile, position)); if (nodeIsEligibleForRename(node)) { const renameInfo = getRenameInfoForNode(node, program.getTypeChecker(), sourceFile, program, preferences); @@ -70,20 +75,31 @@ function getRenameInfoForNode( typeChecker: TypeChecker, sourceFile: SourceFile, program: Program, - preferences: UserPreferences): RenameInfo | undefined { + preferences: UserPreferences, +): RenameInfo | undefined { const symbol = typeChecker.getSymbolAtLocation(node); if (!symbol) { if (isStringLiteralLike(node)) { const type = getContextualTypeFromParentOrAncestorTypeNode(node, typeChecker); - if (type && ((type.flags & TypeFlags.StringLiteral) || ( - (type.flags & TypeFlags.Union) && every((type as UnionType).types, type => !!(type.flags & TypeFlags.StringLiteral)) - ))) { + if ( + type && ((type.flags & TypeFlags.StringLiteral) || ( + (type.flags & TypeFlags.Union) + && every((type as UnionType).types, type => !!(type.flags & TypeFlags.StringLiteral)) + )) + ) { return getRenameInfoSuccess(node.text, node.text, ScriptElementKind.string, "", node, sourceFile); } } else if (isLabelName(node)) { const name = getTextOfNode(node); - return getRenameInfoSuccess(name, name, ScriptElementKind.label, ScriptElementKindModifier.none, node, sourceFile); + return getRenameInfoSuccess( + name, + name, + ScriptElementKind.label, + ScriptElementKindModifier.none, + node, + sourceFile, + ); } return undefined; } @@ -93,11 +109,16 @@ function getRenameInfoForNode( // Disallow rename for elements that are defined in the standard TypeScript library. if (declarations.some(declaration => isDefinedInLibraryFile(program, declaration))) { - return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library); + return getRenameInfoError( + Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library, + ); } // Cannot rename `default` as in `import { default as foo } from "./someModule"; - if (isIdentifier(node) && node.escapedText === "default" && symbol.parent && symbol.parent.flags & SymbolFlags.Module) { + if ( + isIdentifier(node) && node.escapedText === "default" && symbol.parent + && symbol.parent.flags & SymbolFlags.Module + ) { return undefined; } @@ -112,12 +133,20 @@ function getRenameInfoForNode( } const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); - const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteralLike(node) && node.parent.kind === SyntaxKind.ComputedPropertyName) + const specifierName = (isImportOrExportSpecifierName(node) + || isStringOrNumericLiteralLike(node) && node.parent.kind === SyntaxKind.ComputedPropertyName) ? stripQuotes(getTextOfIdentifierOrLiteral(node)) : undefined; const displayName = specifierName || typeChecker.symbolToString(symbol); const fullDisplayName = specifierName || typeChecker.getFullyQualifiedName(symbol); - return getRenameInfoSuccess(displayName, fullDisplayName, kind, SymbolDisplay.getSymbolModifiers(typeChecker,symbol), node, sourceFile); + return getRenameInfoSuccess( + displayName, + fullDisplayName, + kind, + SymbolDisplay.getSymbolModifiers(typeChecker, symbol), + node, + sourceFile, + ); } function isDefinedInLibraryFile(program: Program, declaration: Node) { @@ -129,7 +158,7 @@ function wouldRenameInOtherNodeModules( originalFile: SourceFile, symbol: Symbol, checker: TypeChecker, - preferences: UserPreferences + preferences: UserPreferences, ): DiagnosticMessage | undefined { if (!preferences.providePrefixAndSuffixTextForRename && symbol.flags & SymbolFlags.Alias) { const importSpecifier = symbol.declarations && find(symbol.declarations, decl => isImportSpecifier(decl)); @@ -174,19 +203,27 @@ function getPackagePathComponents(filePath: Path): string[] | undefined { return components.slice(0, nodeModulesIdx + 2); } -function getRenameInfoForModule(node: StringLiteralLike, sourceFile: SourceFile, moduleSymbol: Symbol): RenameInfo | undefined { +function getRenameInfoForModule( + node: StringLiteralLike, + sourceFile: SourceFile, + moduleSymbol: Symbol, +): RenameInfo | undefined { if (!isExternalModuleNameRelative(node.text)) { return getRenameInfoError(Diagnostics.You_cannot_rename_a_module_via_a_global_import); } const moduleSourceFile = moduleSymbol.declarations && find(moduleSymbol.declarations, isSourceFile); if (!moduleSourceFile) return undefined; - const withoutIndex = endsWith(node.text, "/index") || endsWith(node.text, "/index.js") ? undefined : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index"); + const withoutIndex = endsWith(node.text, "/index") || endsWith(node.text, "/index.js") ? undefined + : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index"); const name = withoutIndex === undefined ? moduleSourceFile.fileName : withoutIndex; const kind = withoutIndex === undefined ? ScriptElementKind.moduleElement : ScriptElementKind.directory; const indexAfterLastSlash = node.text.lastIndexOf("/") + 1; // Span should only be the last component of the path. + 1 to account for the quote character. - const triggerSpan = createTextSpan(node.getStart(sourceFile) + 1 + indexAfterLastSlash, node.text.length - indexAfterLastSlash); + const triggerSpan = createTextSpan( + node.getStart(sourceFile) + 1 + indexAfterLastSlash, + node.text.length - indexAfterLastSlash, + ); return { canRename: true, fileToRename: name, @@ -198,7 +235,14 @@ function getRenameInfoForModule(node: StringLiteralLike, sourceFile: SourceFile, }; } -function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: ScriptElementKind, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfoSuccess { +function getRenameInfoSuccess( + displayName: string, + fullDisplayName: string, + kind: ScriptElementKind, + kindModifiers: string, + node: Node, + sourceFile: SourceFile, +): RenameInfoSuccess { return { canRename: true, fileToRename: undefined, @@ -206,7 +250,7 @@ function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind displayName, fullDisplayName, kindModifiers, - triggerSpan: createTriggerSpanForNode(node, sourceFile) + triggerSpan: createTriggerSpanForNode(node, sourceFile), }; } diff --git a/src/services/services.ts b/src/services/services.ts index b0e56cc06453f..5bf07874d87b2 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -325,18 +325,25 @@ import { } from "./_namespaces/ts"; import * as NavigateTo from "./_namespaces/ts.NavigateTo"; import * as NavigationBar from "./_namespaces/ts.NavigationBar"; -import { createNewFileName } from "./_namespaces/ts.refactor"; +import { + createNewFileName, +} from "./_namespaces/ts.refactor"; import * as classifier from "./classifier"; import * as classifier2020 from "./classifier2020"; /** The version of the language service API */ export const servicesVersion = "0.8"; -function createNode(kind: TKind, pos: number, end: number, parent: Node): NodeObject | TokenObject | IdentifierObject | PrivateIdentifierObject { - const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) : - kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) : - kind === SyntaxKind.PrivateIdentifier ? new PrivateIdentifierObject(SyntaxKind.PrivateIdentifier, pos, end) : - new TokenObject(kind, pos, end); +function createNode( + kind: TKind, + pos: number, + end: number, + parent: Node, +): NodeObject | TokenObject | IdentifierObject | PrivateIdentifierObject { + const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) + : kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) + : kind === SyntaxKind.PrivateIdentifier ? new PrivateIdentifierObject(SyntaxKind.PrivateIdentifier, pos, end) + : new TokenObject(kind, pos, end); node.parent = parent; node.flags = parent.flags & NodeFlags.ContextFlags; return node; @@ -367,7 +374,10 @@ class NodeObject implements Node { private assertHasRealPosition(message?: string) { // eslint-disable-next-line local/debug-assert - Debug.assert(!positionIsSynthesized(this.pos) && !positionIsSynthesized(this.end), message || "Node must have a real position for this operation"); + Debug.assert( + !positionIsSynthesized(this.pos) && !positionIsSynthesized(this.end), + message || "Node must have a real position for this operation", + ); } public getSourceFile(): SourceFile { @@ -426,7 +436,9 @@ class NodeObject implements Node { } public getChildren(sourceFile?: SourceFileLike): 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"); + 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 this._children || (this._children = createChildren(this, sourceFile)); } @@ -437,10 +449,13 @@ class NodeObject implements Node { return undefined; } - const child = find(children, kid => kid.kind < SyntaxKind.FirstJSDocNode || kid.kind > SyntaxKind.LastJSDocNode)!; - return child.kind < SyntaxKind.FirstNode ? - child : - child.getFirstToken(sourceFile); + const child = find( + children, + kid => kid.kind < SyntaxKind.FirstJSDocNode || kid.kind > SyntaxKind.LastJSDocNode, + )!; + return child.kind < SyntaxKind.FirstNode + ? child + : child.getFirstToken(sourceFile); } public getLastToken(sourceFile?: SourceFileLike): Node | undefined { @@ -602,7 +617,8 @@ class TokenOrIdentifierObject implements Node { } public getChildren(): Node[] { - return this.kind === SyntaxKind.EndOfFileToken ? (this as Node as EndOfFileToken).jsDoc || emptyArray : emptyArray; + return this.kind === SyntaxKind.EndOfFileToken ? (this as Node as EndOfFileToken).jsDoc || emptyArray + : emptyArray; } public getFirstToken(): Node | undefined { @@ -667,7 +683,10 @@ class SymbolObject implements Symbol { if (!this.documentationComment) { this.documentationComment = emptyArray; // Set temporarily to avoid an infinite loop finding inherited docs - if (!this.declarations && isTransientSymbol(this) && this.links.target && isTransientSymbol(this.links.target) && this.links.target.links.tupleLabelDeclaration) { + if ( + !this.declarations && isTransientSymbol(this) && this.links.target + && isTransientSymbol(this.links.target) && this.links.target.links.tupleLabelDeclaration + ) { const labelDecl = this.links.target.links.tupleLabelDeclaration; this.documentationComment = getDocumentationComment([labelDecl], checker); } @@ -678,11 +697,17 @@ class SymbolObject implements Symbol { return this.documentationComment; } - getContextualDocumentationComment(context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] { + getContextualDocumentationComment( + context: Node | undefined, + checker: TypeChecker | undefined, + ): SymbolDisplayPart[] { if (context) { if (isGetAccessor(context)) { if (!this.contextualGetAccessorDocumentationComment) { - this.contextualGetAccessorDocumentationComment = getDocumentationComment(filter(this.declarations, isGetAccessor), checker); + this.contextualGetAccessorDocumentationComment = getDocumentationComment( + filter(this.declarations, isGetAccessor), + checker, + ); } if (length(this.contextualGetAccessorDocumentationComment)) { return this.contextualGetAccessorDocumentationComment; @@ -690,7 +715,10 @@ class SymbolObject implements Symbol { } if (isSetAccessor(context)) { if (!this.contextualSetAccessorDocumentationComment) { - this.contextualSetAccessorDocumentationComment = getDocumentationComment(filter(this.declarations, isSetAccessor), checker); + this.contextualSetAccessorDocumentationComment = getDocumentationComment( + filter(this.declarations, isSetAccessor), + checker, + ); } if (length(this.contextualSetAccessorDocumentationComment)) { return this.contextualSetAccessorDocumentationComment; @@ -712,7 +740,10 @@ class SymbolObject implements Symbol { if (context) { if (isGetAccessor(context)) { if (!this.contextualGetAccessorTags) { - this.contextualGetAccessorTags = getJsDocTagsOfDeclarations(filter(this.declarations, isGetAccessor), checker); + this.contextualGetAccessorTags = getJsDocTagsOfDeclarations( + filter(this.declarations, isGetAccessor), + checker, + ); } if (length(this.contextualGetAccessorTags)) { return this.contextualGetAccessorTags; @@ -720,7 +751,10 @@ class SymbolObject implements Symbol { } if (isSetAccessor(context)) { if (!this.contextualSetAccessorTags) { - this.contextualSetAccessorTags = getJsDocTagsOfDeclarations(filter(this.declarations, isSetAccessor), checker); + this.contextualSetAccessorTags = getJsDocTagsOfDeclarations( + filter(this.declarations, isSetAccessor), + checker, + ); } if (length(this.contextualSetAccessorTags)) { return this.contextualSetAccessorTags; @@ -752,7 +786,7 @@ class IdentifierObject extends TokenOrIdentifierObject implements Identifier { declare _declarationBrand: any; declare _jsdocContainerBrand: any; declare _flowContainerBrand: any; - /** @internal */typeArguments!: NodeArray; + /** @internal */ typeArguments!: NodeArray; constructor(_kind: SyntaxKind.Identifier, pos: number, end: number) { super(pos, end); } @@ -924,11 +958,16 @@ class SignatureObject implements Signature { } getDocumentationComment(): SymbolDisplayPart[] { - return this.documentationComment || (this.documentationComment = getDocumentationComment(singleElementArray(this.declaration), this.checker)); + return this.documentationComment + || (this.documentationComment = getDocumentationComment( + singleElementArray(this.declaration), + this.checker, + )); } getJsDocTags(): JSDocTagInfo[] { - return this.jsDocTags || (this.jsDocTags = getJsDocTagsOfDeclarations(singleElementArray(this.declaration), this.checker)); + return this.jsDocTags + || (this.jsDocTags = getJsDocTagsOfDeclarations(singleElementArray(this.declaration), this.checker)); } } @@ -941,7 +980,10 @@ function hasJSDocInheritDocTag(node: Node) { return getJSDocTags(node).some(tag => tag.tagName.text === "inheritDoc" || tag.tagName.text === "inheritdoc"); } -function getJsDocTagsOfDeclarations(declarations: Declaration[] | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] { +function getJsDocTagsOfDeclarations( + declarations: Declaration[] | undefined, + checker: TypeChecker | undefined, +): JSDocTagInfo[] { if (!declarations) return emptyArray; let tags = JsDoc.getJsDocTagsFromDeclarations(declarations, checker); @@ -965,7 +1007,10 @@ function getJsDocTagsOfDeclarations(declarations: Declaration[] | undefined, che return tags; } -function getDocumentationComment(declarations: readonly Declaration[] | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] { +function getDocumentationComment( + declarations: readonly Declaration[] | undefined, + checker: TypeChecker | undefined, +): SymbolDisplayPart[] { if (!declarations) return emptyArray; let doc = JsDoc.getJsDocCommentsFromDeclarations(declarations, checker); @@ -982,14 +1027,21 @@ function getDocumentationComment(declarations: readonly Declaration[] | undefine } }); // TODO: GH#16312 Return a ReadonlyArray, avoid copying inheritedDocs - if (inheritedDocs) doc = doc.length === 0 ? inheritedDocs.slice() : inheritedDocs.concat(lineBreakPart(), doc); + if (inheritedDocs) { + doc = doc.length === 0 ? inheritedDocs.slice() : inheritedDocs.concat(lineBreakPart(), doc); + } } } return doc; } -function findBaseOfDeclaration(checker: TypeChecker, declaration: Declaration, cb: (symbol: Symbol) => T[] | undefined): T[] | undefined { - const classOrInterfaceDeclaration = declaration.parent?.kind === SyntaxKind.Constructor ? declaration.parent.parent : declaration.parent; +function findBaseOfDeclaration( + checker: TypeChecker, + declaration: Declaration, + cb: (symbol: Symbol) => T[] | undefined, +): T[] | undefined { + const classOrInterfaceDeclaration = declaration.parent?.kind === SyntaxKind.Constructor ? declaration.parent.parent + : declaration.parent; if (!classOrInterfaceDeclaration) return; const isStaticMember = hasStaticModifier(declaration); @@ -1016,7 +1068,7 @@ class SourceFileObject extends NodeObject implements SourceFile { public statements!: NodeArray; public endOfFileToken!: Token; - public amdDependencies!: { name: string; path: string }[]; + public amdDependencies!: { name: string; path: string; }[]; public moduleName!: string; public referencedFiles!: FileReference[]; public typeReferenceDirectives!: FileReference[]; @@ -1042,7 +1094,9 @@ class SourceFileObject extends NodeObject implements SourceFile { public identifiers!: Map; public nameTable: Map<__String, number> | undefined; public resolvedModules: ModeAwareCache | undefined; - public resolvedTypeReferenceDirectiveNames!: ModeAwareCache; + public resolvedTypeReferenceDirectiveNames!: ModeAwareCache< + ResolvedTypeReferenceDirectiveWithFailedLookupLocations + >; public imports!: readonly StringLiteralLike[]; public moduleAugmentations!: StringLiteral[]; private namedDeclarations: Map | undefined; @@ -1123,8 +1177,10 @@ class SourceFileObject extends NodeObject implements SourceFile { function getDeclarationName(declaration: Declaration) { const name = getNonAssignedNameOfDeclaration(declaration); - return name && (isComputedPropertyName(name) && isPropertyAccessExpression(name.expression) ? name.expression.name.text - : isPropertyName(name) ? getNameFromPropertyName(name) : undefined); + return name + && (isComputedPropertyName(name) && isPropertyAccessExpression(name.expression) + ? name.expression.name.text + : isPropertyName(name) ? getNameFromPropertyName(name) : undefined); } function visit(node: Node): void { @@ -1141,7 +1197,10 @@ class SourceFileObject extends NodeObject implements SourceFile { const lastDeclaration = lastOrUndefined(declarations); // Check whether this declaration belongs to an "overload group". - if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) { + if ( + lastDeclaration && functionDeclaration.parent === lastDeclaration.parent + && functionDeclaration.symbol === lastDeclaration.symbol + ) { // Overwrite the last declaration if it was an overload // and this one is an implementation. if (functionDeclaration.body && !(lastDeclaration as FunctionLikeDeclaration).body) { @@ -1250,7 +1309,7 @@ class SourceFileObject extends NodeObject implements SourceFile { class SourceMapSourceObject implements SourceMapSource { lineMap!: number[]; - constructor(public fileName: string, public text: string, public skipTrivia?: (pos: number) => number) { } + constructor(public fileName: string, public text: string, public skipTrivia?: (pos: number) => number) {} public getLineAndCharacterOfPosition(pos: number): LineAndCharacter { return getLineAndCharacterOfPosition(this, pos); @@ -1319,7 +1378,7 @@ export function getDefaultCompilerOptions(): CompilerOptions { // Always default to "ScriptTarget.ES5" for the language service return { target: ScriptTarget.ES5, - jsx: JsxEmit.Preserve + jsx: JsxEmit.Preserve, }; } @@ -1354,14 +1413,25 @@ class SyntaxTreeCache { const options: CreateSourceFileOptions = { languageVersion: ScriptTarget.Latest, impliedNodeFormat: getImpliedNodeFormatForFile( - toPath(fileName, this.host.getCurrentDirectory(), this.host.getCompilerHost?.()?.getCanonicalFileName || hostGetCanonicalFileName(this.host)), + toPath( + fileName, + this.host.getCurrentDirectory(), + this.host.getCompilerHost?.()?.getCanonicalFileName || hostGetCanonicalFileName(this.host), + ), this.host.getCompilerHost?.()?.getModuleResolutionCache?.()?.getPackageJsonInfoCache(), this.host, - this.host.getCompilationSettings() + this.host.getCompilationSettings(), ), - setExternalModuleIndicator: getSetExternalModuleIndicator(this.host.getCompilationSettings()) + setExternalModuleIndicator: getSetExternalModuleIndicator(this.host.getCompilationSettings()), }; - sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, options, version, /*setNodeParents*/ true, scriptKind); + sourceFile = createLanguageServiceSourceFile( + fileName, + scriptSnapshot, + options, + version, + /*setNodeParents*/ true, + scriptKind, + ); } else if (this.currentFileVersion !== version) { // This is the same file, just a newer version. Incrementally parse the file. @@ -1386,13 +1456,32 @@ function setSourceFileFields(sourceFile: SourceFile, scriptSnapshot: IScriptSnap sourceFile.scriptSnapshot = scriptSnapshot; } -export function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTargetOrOptions: ScriptTarget | CreateSourceFileOptions, version: string, setNodeParents: boolean, scriptKind?: ScriptKind): SourceFile { - const sourceFile = createSourceFile(fileName, getSnapshotText(scriptSnapshot), scriptTargetOrOptions, setNodeParents, scriptKind); +export function createLanguageServiceSourceFile( + fileName: string, + scriptSnapshot: IScriptSnapshot, + scriptTargetOrOptions: ScriptTarget | CreateSourceFileOptions, + version: string, + setNodeParents: boolean, + scriptKind?: ScriptKind, +): SourceFile { + const sourceFile = createSourceFile( + fileName, + getSnapshotText(scriptSnapshot), + scriptTargetOrOptions, + setNodeParents, + scriptKind, + ); setSourceFileFields(sourceFile, scriptSnapshot, version); return sourceFile; } -export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange | undefined, aggressiveChecks?: boolean): SourceFile { +export function updateLanguageServiceSourceFile( + sourceFile: SourceFile, + scriptSnapshot: IScriptSnapshot, + version: string, + textChangeRange: TextChangeRange | undefined, + aggressiveChecks?: boolean, +): SourceFile { // If we were given a text change range, and our version or open-ness changed, then // incrementally parse this file. if (textChangeRange) { @@ -1415,13 +1504,16 @@ export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSn } else { // it was actual edit, fetch the fragment of new text that correspond to new span - const changedText = scriptSnapshot.getText(textChangeRange.span.start, textChangeRange.span.start + textChangeRange.newLength); + const changedText = scriptSnapshot.getText( + textChangeRange.span.start, + textChangeRange.span.start + textChangeRange.newLength, + ); // combine prefix, changed text and suffix newText = prefix && suffix ? prefix + changedText + suffix : prefix - ? (prefix + changedText) - : (changedText + suffix); + ? (prefix + changedText) + : (changedText + suffix); } const newSourceFile = updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); @@ -1449,7 +1541,14 @@ export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSn setExternalModuleIndicator: sourceFile.setExternalModuleIndicator, }; // Otherwise, just create a new source file. - return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, options, version, /*setNodeParents*/ true, sourceFile.scriptKind); + return createLanguageServiceSourceFile( + sourceFile.fileName, + scriptSnapshot, + options, + version, + /*setNodeParents*/ true, + sourceFile.scriptKind, + ); } const NoopCancellationToken: CancellationToken = { @@ -1549,7 +1648,10 @@ const invalidOperationsInSyntacticMode: readonly (keyof LanguageService)[] = [ ]; export function createLanguageService( host: LanguageServiceHost, - documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory()), + documentRegistry: DocumentRegistry = createDocumentRegistry( + host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), + host.getCurrentDirectory(), + ), syntaxOnlyOrLanguageServiceMode?: boolean | LanguageServiceMode, ): LanguageService { let languageServiceMode: LanguageServiceMode; @@ -1558,7 +1660,8 @@ export function createLanguageService( } else if (typeof syntaxOnlyOrLanguageServiceMode === "boolean") { // languageServiceMode = SyntaxOnly - languageServiceMode = syntaxOnlyOrLanguageServiceMode ? LanguageServiceMode.Syntactic : LanguageServiceMode.Semantic; + languageServiceMode = syntaxOnlyOrLanguageServiceMode ? LanguageServiceMode.Syntactic + : LanguageServiceMode.Semantic; } else { languageServiceMode = syntaxOnlyOrLanguageServiceMode; @@ -1595,7 +1698,7 @@ export function createLanguageService( readFile: maybeBind(host, host.readFile), getDocumentPositionMapper: maybeBind(host, host.getDocumentPositionMapper), getSourceFileLike: maybeBind(host, host.getSourceFileLike), - log + log, }); function getValidSourceFile(fileName: string): SourceFile { @@ -1667,8 +1770,17 @@ export function createLanguageService( getDirectories: path => { return host.getDirectories ? host.getDirectories(path) : []; }, - readDirectory: (path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number) => { - Debug.checkDefined(host.readDirectory, "'LanguageServiceHost.readDirectory' must be implemented to correctly process 'projectReferences'"); + readDirectory: ( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ) => { + Debug.checkDefined( + host.readDirectory, + "'LanguageServiceHost.readDirectory' must be implemented to correctly process 'projectReferences'", + ); return host.readDirectory!(path, extensions, exclude, include, depth); }, onReleaseOldSourceFile, @@ -1693,7 +1805,7 @@ export function createLanguageService( const { getSourceFileWithCache } = changeCompilerHostLikeToUseCache( compilerHost, fileName => toPath(fileName, currentDirectory, getCanonicalFileName), - (...args) => originalGetSourceFile.call(compilerHost, ...args) + (...args) => originalGetSourceFile.call(compilerHost, ...args), ); compilerHost.getSourceFile = getSourceFileWithCache!; @@ -1719,7 +1831,20 @@ export function createLanguageService( let releasedScriptKinds: Set | undefined = new Set(); // If the program is already up-to-date, we can reuse it - if (isProgramUptoDate(program, rootFileNames, newSettings, (_path, fileName) => host.getScriptVersion(fileName), fileName => compilerHost!.fileExists(fileName), hasInvalidatedResolutions, hasInvalidatedLibResolutions, hasChangedAutomaticTypeDirectiveNames, getParsedCommandLine, projectReferences)) { + if ( + isProgramUptoDate( + program, + rootFileNames, + newSettings, + (_path, fileName) => host.getScriptVersion(fileName), + fileName => compilerHost!.fileExists(fileName), + hasInvalidatedResolutions, + hasInvalidatedLibResolutions, + hasChangedAutomaticTypeDirectiveNames, + getParsedCommandLine, + projectReferences, + ) + ) { compilerHost = undefined; parsedCommandLines = undefined; releasedScriptKinds = undefined; @@ -1737,7 +1862,7 @@ export function createLanguageService( options: newSettings, host: compilerHost, oldProgram: program, - projectReferences + projectReferences, }; program = createProgram(options); @@ -1762,14 +1887,16 @@ export function createLanguageService( const existing = parsedCommandLines?.get(path); if (existing !== undefined) return existing || undefined; - const result = host.getParsedCommandLine ? - host.getParsedCommandLine(fileName) : - getParsedCommandLineOfConfigFileUsingSourceFile(fileName); + const result = host.getParsedCommandLine + ? host.getParsedCommandLine(fileName) + : getParsedCommandLineOfConfigFileUsingSourceFile(fileName); (parsedCommandLines ||= new Map()).set(path, result || false); return result; } - function getParsedCommandLineOfConfigFileUsingSourceFile(configFileName: string): ParsedCommandLine | undefined { + function getParsedCommandLineOfConfigFileUsingSourceFile( + configFileName: string, + ): ParsedCommandLine | undefined { const result = getOrCreateSourceFile(configFileName, ScriptTarget.JSON) as JsonSourceFile | undefined; if (!result) return undefined; result.path = toPath(configFileName, currentDirectory, getCanonicalFileName); @@ -1784,7 +1911,11 @@ export function createLanguageService( ); } - function onReleaseParsedCommandLine(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, oldOptions: CompilerOptions) { + function onReleaseParsedCommandLine( + configFileName: string, + oldResolvedRef: ResolvedProjectReference | undefined, + oldOptions: CompilerOptions, + ) { if (host.getParsedCommandLine) { host.onReleaseParsedCommandLine?.(configFileName, oldResolvedRef, oldOptions); } @@ -1797,15 +1928,40 @@ export function createLanguageService( // not part of the new program. function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) { const oldSettingsKey = documentRegistry.getKeyForCompilationSettings(oldOptions); - documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, oldSettingsKey, oldSourceFile.scriptKind, oldSourceFile.impliedNodeFormat); + documentRegistry.releaseDocumentWithKey( + oldSourceFile.resolvedPath, + oldSettingsKey, + oldSourceFile.scriptKind, + oldSourceFile.impliedNodeFormat, + ); } - 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); + 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, + ); } - function getOrCreateSourceFileByPath(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, _onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined { - Debug.assert(compilerHost, "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host."); + function getOrCreateSourceFileByPath( + fileName: string, + path: Path, + languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, + _onError?: (message: string) => void, + shouldCreateNewSourceFile?: boolean, + ): SourceFile | undefined { + Debug.assert( + compilerHost, + "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host.", + ); // The program is asking for this file, check first if the host can locate it. // If the host can not locate the file, then it does not exist. return undefined // to the program to allow reporting of errors for missing files. @@ -1849,12 +2005,28 @@ export function createLanguageService( // We do not support the scenario where a host can modify a registered // file's script kind, i.e. in one project some file is treated as ".ts" // and in another as ".js" - if (scriptKind === oldSourceFile.scriptKind || releasedScriptKinds!.has(oldSourceFile.resolvedPath)) { - return documentRegistry.updateDocumentWithKey(fileName, path, host, documentRegistryBucketKey, scriptSnapshot, scriptVersion, scriptKind, languageVersionOrOptions); + if ( + scriptKind === oldSourceFile.scriptKind || releasedScriptKinds!.has(oldSourceFile.resolvedPath) + ) { + return documentRegistry.updateDocumentWithKey( + fileName, + path, + host, + documentRegistryBucketKey, + scriptSnapshot, + scriptVersion, + scriptKind, + languageVersionOrOptions, + ); } else { // Release old source file and fall through to aquire new file with new script kind - documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, documentRegistry.getKeyForCompilationSettings(program.getCompilerOptions()), oldSourceFile.scriptKind, oldSourceFile.impliedNodeFormat); + documentRegistry.releaseDocumentWithKey( + oldSourceFile.resolvedPath, + documentRegistry.getKeyForCompilationSettings(program.getCompilerOptions()), + oldSourceFile.scriptKind, + oldSourceFile.impliedNodeFormat, + ); releasedScriptKinds!.add(oldSourceFile.resolvedPath); } } @@ -1863,7 +2035,16 @@ export function createLanguageService( } // Could not find this file in the old program, create a new SourceFile for it. - return documentRegistry.acquireDocumentWithKey(fileName, path, host, documentRegistryBucketKey, scriptSnapshot, scriptVersion, scriptKind, languageVersionOrOptions); + return documentRegistry.acquireDocumentWithKey( + fileName, + path, + host, + documentRegistryBucketKey, + scriptSnapshot, + scriptVersion, + scriptKind, + languageVersionOrOptions, + ); } } @@ -1883,7 +2064,10 @@ export function createLanguageService( return host.getPackageJsonAutoImportProvider?.(); } - function updateIsDefinitionOfReferencedSymbols(referencedSymbols: readonly ReferencedSymbol[], knownSymbolSpans: Set): boolean { + function updateIsDefinitionOfReferencedSymbols( + referencedSymbols: readonly ReferencedSymbol[], + knownSymbolSpans: Set, + ): boolean { const checker = program.getTypeChecker(); const symbol = getSymbolForProgram(); @@ -1934,7 +2118,9 @@ export function createLanguageService( const sourceFile = program.getSourceFile(docSpan.fileName); if (!sourceFile) return undefined; const rawNode = getTouchingPropertyName(sourceFile, docSpan.textSpan.start); - const adjustedNode = FindAllReferences.Core.getAdjustedNode(rawNode, { use: FindAllReferences.FindReferencesUse.References }); + const adjustedNode = FindAllReferences.Core.getAdjustedNode(rawNode, { + use: FindAllReferences.FindReferencesUse.References, + }); return adjustedNode; } } @@ -1943,8 +2129,10 @@ export function createLanguageService( if (program) { // Use paths to ensure we are using correct key and paths as document registry could be created with different current directory than host const key = documentRegistry.getKeyForCompilationSettings(program.getCompilerOptions()); - forEach(program.getSourceFiles(), f => - documentRegistry.releaseDocumentWithKey(f.resolvedPath, key, f.scriptKind, f.impliedNodeFormat)); + forEach( + program.getSourceFiles(), + f => documentRegistry.releaseDocumentWithKey(f.resolvedPath, key, f.scriptKind, f.impliedNodeFormat), + ); program = undefined!; // TODO: GH#18217 } } @@ -1990,15 +2178,25 @@ export function createLanguageService( function getCompilerOptionsDiagnostics() { synchronizeHostData(); - return [...program.getOptionsDiagnostics(cancellationToken), ...program.getGlobalDiagnostics(cancellationToken)]; + return [ + ...program.getOptionsDiagnostics(cancellationToken), + ...program.getGlobalDiagnostics(cancellationToken), + ]; } - function getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions = emptyOptions, formattingSettings?: FormatCodeSettings): CompletionInfo | undefined { + function getCompletionsAtPosition( + fileName: string, + position: number, + options: GetCompletionsAtPositionOptions = emptyOptions, + formattingSettings?: FormatCodeSettings, + ): CompletionInfo | undefined { // Convert from deprecated options names to new names const fullPreferences: UserPreferences = { ...identity(options), // avoid excess property check - includeCompletionsForModuleExports: options.includeCompletionsForModuleExports || options.includeExternalModuleExports, - includeCompletionsWithInsertText: options.includeCompletionsWithInsertText || options.includeInsertTextCompletions, + includeCompletionsForModuleExports: options.includeCompletionsForModuleExports + || options.includeExternalModuleExports, + includeCompletionsWithInsertText: options.includeCompletionsWithInsertText + || options.includeInsertTextCompletions, }; synchronizeHostData(); return Completions.getCompletionsAtPosition( @@ -2012,10 +2210,19 @@ export function createLanguageService( options.triggerKind, cancellationToken, formattingSettings && formatting.getFormatContext(formattingSettings, host), - options.includeSymbol); + options.includeSymbol, + ); } - function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions: FormatCodeSettings | undefined, source: string | undefined, preferences: UserPreferences = emptyOptions, data?: CompletionEntryData): CompletionEntryDetails | undefined { + function getCompletionEntryDetails( + fileName: string, + position: number, + name: string, + formattingOptions: FormatCodeSettings | undefined, + source: string | undefined, + preferences: UserPreferences = emptyOptions, + data?: CompletionEntryData, + ): CompletionEntryDetails | undefined { synchronizeHostData(); return Completions.getCompletionEntryDetails( program, @@ -2030,9 +2237,23 @@ export function createLanguageService( ); } - function getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string, preferences: UserPreferences = emptyOptions): Symbol | undefined { + function getCompletionEntrySymbol( + fileName: string, + position: number, + name: string, + source?: string, + preferences: UserPreferences = emptyOptions, + ): Symbol | undefined { synchronizeHostData(); - return Completions.getCompletionEntrySymbol(program, log, getValidSourceFile(fileName), position, { name, source }, host, preferences); + return Completions.getCompletionEntrySymbol( + program, + log, + getValidSourceFile(fileName), + position, + { name, source }, + host, + preferences, + ); } function getQuickInfoAtPosition(fileName: string, position: number): QuickInfo | undefined { @@ -2050,19 +2271,31 @@ export function createLanguageService( const symbol = getSymbolAtLocationForQuickInfo(nodeForQuickInfo, typeChecker); if (!symbol || typeChecker.isUnknownSymbol(symbol)) { - const type = shouldGetType(sourceFile, nodeForQuickInfo, position) ? typeChecker.getTypeAtLocation(nodeForQuickInfo) : undefined; + const type = shouldGetType(sourceFile, nodeForQuickInfo, position) + ? typeChecker.getTypeAtLocation(nodeForQuickInfo) : undefined; return type && { kind: ScriptElementKind.unknown, kindModifiers: ScriptElementKindModifier.none, textSpan: createTextSpanFromNode(nodeForQuickInfo, sourceFile), - displayParts: typeChecker.runWithCancellationToken(cancellationToken, typeChecker => typeToDisplayParts(typeChecker, type, getContainerNode(nodeForQuickInfo))), + displayParts: typeChecker.runWithCancellationToken( + cancellationToken, + typeChecker => typeToDisplayParts(typeChecker, type, getContainerNode(nodeForQuickInfo)), + ), documentation: type.symbol ? type.symbol.getDocumentationComment(typeChecker) : undefined, - tags: type.symbol ? type.symbol.getJsDocTags(typeChecker) : undefined + tags: type.symbol ? type.symbol.getJsDocTags(typeChecker) : undefined, }; } - const { symbolKind, displayParts, documentation, tags } = typeChecker.runWithCancellationToken(cancellationToken, typeChecker => - SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, getContainerNode(nodeForQuickInfo), nodeForQuickInfo) + const { symbolKind, displayParts, documentation, tags } = typeChecker.runWithCancellationToken( + cancellationToken, + typeChecker => + SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind( + typeChecker, + symbol, + sourceFile, + getContainerNode(nodeForQuickInfo), + nodeForQuickInfo, + ), ); return { kind: symbolKind, @@ -2111,9 +2344,20 @@ export function createLanguageService( } /// Goto definition - function getDefinitionAtPosition(fileName: string, position: number, searchOtherFilesOnly?: boolean, stopAtAlias?: boolean): readonly DefinitionInfo[] | undefined { + function getDefinitionAtPosition( + fileName: string, + position: number, + searchOtherFilesOnly?: boolean, + stopAtAlias?: boolean, + ): readonly DefinitionInfo[] | undefined { synchronizeHostData(); - return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position, searchOtherFilesOnly, stopAtAlias); + return GoToDefinition.getDefinitionAtPosition( + program, + getValidSourceFile(fileName), + position, + searchOtherFilesOnly, + stopAtAlias, + ); } function getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined { @@ -2123,57 +2367,110 @@ export function createLanguageService( function getTypeDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined { synchronizeHostData(); - return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position); + return GoToDefinition.getTypeDefinitionAtPosition( + program.getTypeChecker(), + getValidSourceFile(fileName), + position, + ); } /// Goto implementation function getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[] | undefined { synchronizeHostData(); - return FindAllReferences.getImplementationsAtPosition(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position); + return FindAllReferences.getImplementationsAtPosition( + program, + cancellationToken, + program.getSourceFiles(), + getValidSourceFile(fileName), + position, + ); } /// References and Occurrences - function getDocumentHighlights(fileName: string, position: number, filesToSearch: readonly string[]): DocumentHighlights[] | undefined { + function getDocumentHighlights( + fileName: string, + position: number, + filesToSearch: readonly string[], + ): DocumentHighlights[] | undefined { const normalizedFileName = normalizePath(fileName); Debug.assert(filesToSearch.some(f => normalizePath(f) === normalizedFileName)); synchronizeHostData(); const sourceFilesToSearch = mapDefined(filesToSearch, fileName => program.getSourceFile(fileName)); const sourceFile = getValidSourceFile(fileName); - return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch); + return DocumentHighlights.getDocumentHighlights( + program, + cancellationToken, + sourceFile, + position, + sourceFilesToSearch, + ); } - function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, preferences?: UserPreferences | boolean): RenameLocation[] | undefined { + function findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + preferences?: UserPreferences | boolean, + ): RenameLocation[] | undefined { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); const node = getAdjustedRenameLocation(getTouchingPropertyName(sourceFile, position)); if (!Rename.nodeIsEligibleForRename(node)) return undefined; - if (isIdentifier(node) && (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) && isIntrinsicJsxName(node.escapedText)) { + if ( + isIdentifier(node) && (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) + && isIntrinsicJsxName(node.escapedText) + ) { const { openingElement, closingElement } = node.parent.parent; return [openingElement, closingElement].map((node): RenameLocation => { const textSpan = createTextSpanFromNode(node.tagName, sourceFile); return { fileName: sourceFile.fileName, textSpan, - ...FindAllReferences.toContextSpan(textSpan, sourceFile, node.parent) + ...FindAllReferences.toContextSpan(textSpan, sourceFile, node.parent), }; }); } else { const quotePreference = getQuotePreference(sourceFile, preferences ?? emptyOptions); - const providePrefixAndSuffixTextForRename = typeof preferences === "boolean" ? preferences : preferences?.providePrefixAndSuffixTextForRename; - return getReferencesWorker(node, position, { findInStrings, findInComments, providePrefixAndSuffixTextForRename, use: FindAllReferences.FindReferencesUse.Rename }, - (entry, originalNode, checker) => FindAllReferences.toRenameLocation(entry, originalNode, checker, providePrefixAndSuffixTextForRename || false, quotePreference)); + const providePrefixAndSuffixTextForRename = typeof preferences === "boolean" ? preferences + : preferences?.providePrefixAndSuffixTextForRename; + return getReferencesWorker( + node, + position, + { + findInStrings, + findInComments, + providePrefixAndSuffixTextForRename, + use: FindAllReferences.FindReferencesUse.Rename, + }, + (entry, originalNode, checker) => + FindAllReferences.toRenameLocation( + entry, + originalNode, + checker, + providePrefixAndSuffixTextForRename || false, + quotePreference, + ), + ); } } function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined { synchronizeHostData(); - return getReferencesWorker(getTouchingPropertyName(getValidSourceFile(fileName), position), position, { use: FindAllReferences.FindReferencesUse.References }, FindAllReferences.toReferenceEntry); + return getReferencesWorker(getTouchingPropertyName(getValidSourceFile(fileName), position), position, { + use: FindAllReferences.FindReferencesUse.References, + }, FindAllReferences.toReferenceEntry); } - function getReferencesWorker(node: Node, position: number, options: FindAllReferences.Options, cb: FindAllReferences.ToReferenceOrRenameEntry): T[] | undefined { + function getReferencesWorker( + node: Node, + position: number, + options: FindAllReferences.Options, + cb: FindAllReferences.ToReferenceOrRenameEntry, + ): T[] | undefined { synchronizeHostData(); // Exclude default library when renaming as commonly user don't want to change that file. @@ -2181,23 +2478,51 @@ export function createLanguageService( ? program.getSourceFiles().filter(sourceFile => !program.isSourceFileDefaultLibrary(sourceFile)) : program.getSourceFiles(); - return FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, sourceFiles, node, position, options, cb); + return FindAllReferences.findReferenceOrRenameEntries( + program, + cancellationToken, + sourceFiles, + node, + position, + options, + cb, + ); } function findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined { synchronizeHostData(); - return FindAllReferences.findReferencedSymbols(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position); + return FindAllReferences.findReferencedSymbols( + program, + cancellationToken, + program.getSourceFiles(), + getValidSourceFile(fileName), + position, + ); } function getFileReferences(fileName: string): ReferenceEntry[] { synchronizeHostData(); - return FindAllReferences.Core.getReferencesForFileName(fileName, program, program.getSourceFiles()).map(FindAllReferences.toReferenceEntry); + return FindAllReferences.Core.getReferencesForFileName(fileName, program, program.getSourceFiles()).map( + FindAllReferences.toReferenceEntry, + ); } - function getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles = false): NavigateToItem[] { + function getNavigateToItems( + searchValue: string, + maxResultCount?: number, + fileName?: string, + excludeDtsFiles = false, + ): NavigateToItem[] { synchronizeHostData(); const sourceFiles = fileName ? [getValidSourceFile(fileName)] : program.getSourceFiles(); - return NavigateTo.getNavigateToItems(sourceFiles, program.getTypeChecker(), cancellationToken, searchValue, maxResultCount, excludeDtsFiles); + return NavigateTo.getNavigateToItems( + sourceFiles, + program.getTypeChecker(), + cancellationToken, + searchValue, + maxResultCount, + excludeDtsFiles, + ); } function getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean) { @@ -2205,14 +2530,25 @@ export function createLanguageService( const sourceFile = getValidSourceFile(fileName); const customTransformers = host.getCustomTransformers && host.getCustomTransformers(); - return getFileEmitOutput(program, sourceFile, !!emitOnlyDtsFiles, cancellationToken, customTransformers, forceDtsEmit); + return getFileEmitOutput( + program, + sourceFile, + !!emitOnlyDtsFiles, + cancellationToken, + customTransformers, + forceDtsEmit, + ); } // Signature help /** * This is a semantic operation. */ - function getSignatureHelpItems(fileName: string, position: number, { triggerReason }: SignatureHelpItemsOptions = emptyOptions): SignatureHelpItems | undefined { + function getSignatureHelpItems( + fileName: string, + position: number, + { triggerReason }: SignatureHelpItemsOptions = emptyOptions, + ): SignatureHelpItems | undefined { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); @@ -2263,8 +2599,10 @@ export function createLanguageService( // If this is name of a module declarations, check if this is right side of dotted module name // If parent of the module declaration which is parent of this node is module declaration and its body is the module declaration that this node is name of // Then this name is name from dotted module - if (nodeForStartPos.parent.parent.kind === SyntaxKind.ModuleDeclaration && - (nodeForStartPos.parent.parent as ModuleDeclaration).body === nodeForStartPos.parent) { + if ( + nodeForStartPos.parent.parent.kind === SyntaxKind.ModuleDeclaration + && (nodeForStartPos.parent.parent as ModuleDeclaration).body === nodeForStartPos.parent + ) { // Use parent module declarations name for start pos nodeForStartPos = (nodeForStartPos.parent.parent as ModuleDeclaration).name; } @@ -2298,38 +2636,76 @@ export function createLanguageService( } function getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; - function getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[] { + function getSemanticClassifications( + fileName: string, + span: TextSpan, + format?: SemanticClassificationFormat, + ): ClassifiedSpan[] | ClassifiedSpan2020[] { synchronizeHostData(); const responseFormat = format || SemanticClassificationFormat.Original; if (responseFormat === SemanticClassificationFormat.TwentyTwenty) { - return classifier2020.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return classifier2020.getSemanticClassifications( + program, + cancellationToken, + getValidSourceFile(fileName), + span, + ); } else { - return classifier.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + return classifier.getSemanticClassifications( + program.getTypeChecker(), + cancellationToken, + getValidSourceFile(fileName), + program.getClassifiableNames(), + span, + ); } } - function getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications { + function getEncodedSemanticClassifications( + fileName: string, + span: TextSpan, + format?: SemanticClassificationFormat, + ): Classifications { synchronizeHostData(); const responseFormat = format || SemanticClassificationFormat.Original; if (responseFormat === SemanticClassificationFormat.Original) { - return classifier.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + return classifier.getEncodedSemanticClassifications( + program.getTypeChecker(), + cancellationToken, + getValidSourceFile(fileName), + program.getClassifiableNames(), + span, + ); } else { - return classifier2020.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return classifier2020.getEncodedSemanticClassifications( + program, + cancellationToken, + getValidSourceFile(fileName), + span, + ); } } function getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { // doesn't use compiler - no need to synchronize with host - return classifier.getSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); + return classifier.getSyntacticClassifications( + cancellationToken, + syntaxTreeCache.getCurrentSourceFile(fileName), + span, + ); } function getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications { // doesn't use compiler - no need to synchronize with host - return classifier.getEncodedSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); + return classifier.getEncodedSyntacticClassifications( + cancellationToken, + syntaxTreeCache.getCurrentSourceFile(fileName), + span, + ); } function getOutliningSpans(fileName: string): OutliningSpan[] { @@ -2349,13 +2725,21 @@ export function createLanguageService( function getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const token = getTouchingToken(sourceFile, position); - const matchKind = token.getStart(sourceFile) === position ? braceMatching.get(token.kind.toString()) : undefined; + const matchKind = token.getStart(sourceFile) === position ? braceMatching.get(token.kind.toString()) + : undefined; const match = matchKind && findChildOfKind(token.parent, matchKind, sourceFile); // We want to order the braces when we return the result. - return match ? [createTextSpanFromNode(token, sourceFile), createTextSpanFromNode(match, sourceFile)].sort((a, b) => a.start - b.start) : emptyArray; + return match + ? [createTextSpanFromNode(token, sourceFile), createTextSpanFromNode(match, sourceFile)].sort((a, b) => + a.start - b.start + ) : emptyArray; } - function getIndentationAtPosition(fileName: string, position: number, editorOptions: EditorOptions | EditorSettings) { + function getIndentationAtPosition( + fileName: string, + position: number, + editorOptions: EditorOptions | EditorSettings, + ) { let start = timestamp(); const settings = toEditorSettings(editorOptions); const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); @@ -2369,16 +2753,37 @@ export function createLanguageService( return result; } - function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { + function getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); - return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options), host)); + return formatting.formatSelection( + start, + end, + sourceFile, + formatting.getFormatContext(toEditorSettings(options), host), + ); } - function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { - return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options), host)); + function getFormattingEditsForDocument( + fileName: string, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[] { + return formatting.formatDocument( + syntaxTreeCache.getCurrentSourceFile(fileName), + formatting.getFormatContext(toEditorSettings(options), host), + ); } - function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] { + function getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const formatContext = formatting.getFormatContext(toEditorSettings(options), host); @@ -2398,7 +2803,14 @@ export function createLanguageService( return []; } - function getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): readonly CodeFixAction[] { + function getCodeFixesAtPosition( + fileName: string, + start: number, + end: number, + errorCodes: readonly number[], + formatOptions: FormatCodeSettings, + preferences: UserPreferences = emptyOptions, + ): readonly CodeFixAction[] { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); const span = createTextSpanFromBounds(start, end); @@ -2406,11 +2818,25 @@ export function createLanguageService( return flatMap(deduplicate(errorCodes, equateValues, compareValues), errorCode => { cancellationToken.throwIfCancellationRequested(); - return codefix.getFixes({ errorCode, sourceFile, span, program, host, cancellationToken, formatContext, preferences }); + return codefix.getFixes({ + errorCode, + sourceFile, + span, + program, + host, + cancellationToken, + formatContext, + preferences, + }); }); } - function getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): CombinedCodeActions { + function getCombinedCodeFix( + scope: CombinedCodeFixScope, + fixId: {}, + formatOptions: FormatCodeSettings, + preferences: UserPreferences = emptyOptions, + ): CombinedCodeActions { synchronizeHostData(); Debug.assert(scope.type === "file"); const sourceFile = getValidSourceFile(scope.fileName); @@ -2419,28 +2845,64 @@ export function createLanguageService( return codefix.getAllFixes({ fixId, sourceFile, program, host, cancellationToken, formatContext, preferences }); } - function organizeImports(args: OrganizeImportsArgs, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): readonly FileTextChanges[] { + function organizeImports( + args: OrganizeImportsArgs, + formatOptions: FormatCodeSettings, + preferences: UserPreferences = emptyOptions, + ): readonly FileTextChanges[] { synchronizeHostData(); Debug.assert(args.type === "file"); const sourceFile = getValidSourceFile(args.fileName); const formatContext = formatting.getFormatContext(formatOptions, host); - const mode = args.mode ?? (args.skipDestructiveCodeActions ? OrganizeImportsMode.SortAndCombine : OrganizeImportsMode.All); + const mode = args.mode + ?? (args.skipDestructiveCodeActions ? OrganizeImportsMode.SortAndCombine : OrganizeImportsMode.All); return OrganizeImports.organizeImports(sourceFile, formatContext, host, program, preferences, mode); } - function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): readonly FileTextChanges[] { - return ts_getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions, host), preferences, sourceMapper); + function getEditsForFileRename( + oldFilePath: string, + newFilePath: string, + formatOptions: FormatCodeSettings, + preferences: UserPreferences = emptyOptions, + ): readonly FileTextChanges[] { + return ts_getEditsForFileRename( + getProgram()!, + oldFilePath, + newFilePath, + host, + formatting.getFormatContext(formatOptions, host), + preferences, + sourceMapper, + ); } - function applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise; - function applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise; - function applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise; + function applyCodeActionCommand( + action: CodeActionCommand, + formatSettings?: FormatCodeSettings, + ): Promise; + function applyCodeActionCommand( + action: CodeActionCommand[], + formatSettings?: FormatCodeSettings, + ): Promise; + function applyCodeActionCommand( + action: CodeActionCommand | CodeActionCommand[], + formatSettings?: FormatCodeSettings, + ): Promise; function applyCodeActionCommand(fileName: Path, action: CodeActionCommand): Promise; - function applyCodeActionCommand(fileName: Path, action: CodeActionCommand[]): Promise; - function applyCodeActionCommand(fileName: Path | CodeActionCommand | CodeActionCommand[], actionOrFormatSettingsOrUndefined?: CodeActionCommand | CodeActionCommand[] | FormatCodeSettings): Promise { - const action = typeof fileName === "string" ? actionOrFormatSettingsOrUndefined as CodeActionCommand | CodeActionCommand[] : fileName as CodeActionCommand[]; - return isArray(action) ? Promise.all(action.map(a => applySingleCodeActionCommand(a))) : applySingleCodeActionCommand(action); + function applyCodeActionCommand( + fileName: Path, + action: CodeActionCommand[], + ): Promise; + function applyCodeActionCommand( + fileName: Path | CodeActionCommand | CodeActionCommand[], + actionOrFormatSettingsOrUndefined?: CodeActionCommand | CodeActionCommand[] | FormatCodeSettings, + ): Promise { + const action = typeof fileName === "string" + ? actionOrFormatSettingsOrUndefined as CodeActionCommand | CodeActionCommand[] + : fileName as CodeActionCommand[]; + return isArray(action) ? Promise.all(action.map(a => applySingleCodeActionCommand(a))) + : applySingleCodeActionCommand(action); } function applySingleCodeActionCommand(action: CodeActionCommand): Promise { @@ -2451,9 +2913,19 @@ export function createLanguageService( : Promise.reject("Host does not implement `installPackage`"); } - function getDocCommentTemplateAtPosition(fileName: string, position: number, options?: DocCommentTemplateOptions, formatOptions?: FormatCodeSettings): TextInsertion | undefined { + function getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: DocCommentTemplateOptions, + formatOptions?: FormatCodeSettings, + ): TextInsertion | undefined { const formatSettings = formatOptions ? formatting.getFormatContext(formatOptions, host).options : undefined; - return JsDoc.getDocCommentTemplateAtPosition(getNewLineOrDefaultFromHost(host, formatSettings), syntaxTreeCache.getCurrentSourceFile(fileName), position, options); + return JsDoc.getDocCommentTemplateAtPosition( + getNewLineOrDefaultFromHost(host, formatSettings), + syntaxTreeCache.getCurrentSourceFile(fileName), + position, + options, + ); } function isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean { @@ -2496,12 +2968,14 @@ export function createLanguageService( const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const token = findPrecedingToken(position, sourceFile); if (!token) return undefined; - const element = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent) ? token.parent.parent + const element = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent) + ? token.parent.parent : isJsxText(token) && isJsxElement(token.parent) ? token.parent : undefined; if (element && isUnclosedTag(element)) { return { newText: `` }; } - const fragment = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningFragment(token.parent) ? token.parent.parent + const fragment = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningFragment(token.parent) + ? token.parent.parent : isJsxText(token) && isJsxFragment(token.parent) ? token.parent : undefined; if (fragment && isUnclosedFragment(fragment)) { return { newText: "" }; @@ -2534,15 +3008,17 @@ export function createLanguageService( } else { // determines if the cursor is in an element tag - const tag = findAncestor(token.parent, - n => { - if (isJsxOpeningElement(n) || isJsxClosingElement(n)) { - return true; - } - return false; - }); + const tag = findAncestor(token.parent, n => { + if (isJsxOpeningElement(n) || isJsxClosingElement(n)) { + return true; + } + return false; + }); if (!tag) return undefined; - Debug.assert(isJsxOpeningElement(tag) || isJsxClosingElement(tag), "tag should be opening or closing element"); + Debug.assert( + isJsxOpeningElement(tag) || isJsxClosingElement(tag), + "tag should be opening or closing element", + ); const openTag = tag.parent.openingElement; const closeTag = tag.parent.closingElement; @@ -2553,14 +3029,20 @@ export function createLanguageService( const closeTagEnd = closeTag.tagName.end; // only return linked cursors if the cursor is within a tag name - if (!(openTagStart <= position && position <= openTagEnd || closeTagStart <= position && position <= closeTagEnd)) return undefined; + if ( + !(openTagStart <= position && position <= openTagEnd + || closeTagStart <= position && position <= closeTagEnd) + ) return undefined; // only return linked cursors if text in both tags is identical const openingTagText = openTag.tagName.getText(sourceFile); if (openingTagText !== closeTag.tagName.getText(sourceFile)) return undefined; return { - ranges: [{ start: openTagStart, length: openTagEnd - openTagStart }, { start: closeTagStart, length: closeTagEnd - closeTagStart }], + ranges: [{ start: openTagStart, length: openTagEnd - openTagStart }, { + start: closeTagStart, + length: closeTagEnd - closeTagStart, + }], wordPattern: jsxTagWordPattern, }; } @@ -2570,7 +3052,7 @@ export function createLanguageService( return { lineStarts: sourceFile.getLineStarts(), firstLine: sourceFile.getLineAndCharacterOfPosition(textRange.pos).line, - lastLine: sourceFile.getLineAndCharacterOfPosition(textRange.end).line + lastLine: sourceFile.getLineAndCharacterOfPosition(textRange.end).line, }; } @@ -2614,15 +3096,25 @@ export function createLanguageService( // If the line is not an empty line; otherwise no-op. if (lineTextStart !== undefined) { if (isJsx) { - textChanges.push(...toggleMultilineComment(fileName, { pos: lineStarts[i] + leftMostPosition, end: sourceFile.getLineEndOfPosition(lineStarts[i]) }, isCommenting, isJsx)); + textChanges.push( + ...toggleMultilineComment( + fileName, + { + pos: lineStarts[i] + leftMostPosition, + end: sourceFile.getLineEndOfPosition(lineStarts[i]), + }, + isCommenting, + isJsx, + ), + ); } else if (isCommenting) { textChanges.push({ newText: openComment, span: { length: 0, - start: lineStarts[i] + leftMostPosition - } + start: lineStarts[i] + leftMostPosition, + }, }); } else if (sourceFile.text.substr(lineStarts[i] + lineTextStart, openComment.length) === openComment) { @@ -2630,8 +3122,8 @@ export function createLanguageService( newText: "", span: { length: openComment.length, - start: lineStarts[i] + lineTextStart - } + start: lineStarts[i] + lineTextStart, + }, }); } } @@ -2640,7 +3132,12 @@ export function createLanguageService( return textChanges; } - function toggleMultilineComment(fileName: string, textRange: TextRange, insertComment?: boolean, isInsideJsx?: boolean): TextChange[] { + function toggleMultilineComment( + fileName: string, + textRange: TextRange, + insertComment?: boolean, + isInsideJsx?: boolean, + ): TextChange[] { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const textChanges: TextChange[] = []; const { text } = sourceFile; @@ -2680,7 +3177,9 @@ export function createLanguageService( pos = commentRange.end + 1; } else { // If it's not in a comment range, then we need to comment the uncommented portions. - const newPos = text.substring(pos, textRange.end).search(`(${openMultilineRegex})|(${closeMultilineRegex})`); + const newPos = text.substring(pos, textRange.end).search( + `(${openMultilineRegex})|(${closeMultilineRegex})`, + ); isCommenting = insertComment !== undefined ? insertComment @@ -2704,8 +3203,8 @@ export function createLanguageService( newText: openMultiline, span: { length: 0, - start: firstPos - } + start: firstPos, + }, }); } @@ -2716,8 +3215,8 @@ export function createLanguageService( newText: closeMultiline, span: { length: 0, - start: positions[i] - } + start: positions[i], + }, }); } @@ -2726,8 +3225,8 @@ export function createLanguageService( newText: openMultiline, span: { length: 0, - start: positions[i] - } + start: positions[i], + }, }); } } @@ -2738,8 +3237,8 @@ export function createLanguageService( newText: closeMultiline, span: { length: 0, - start: positions[positions.length - 1] - } + start: positions[positions.length - 1], + }, }); } } @@ -2752,8 +3251,8 @@ export function createLanguageService( newText: "", span: { length: openMultiline.length, - start: pos - offset - } + start: pos - offset, + }, }); } } @@ -2788,10 +3287,22 @@ export function createLanguageService( if (commentRange) { switch (commentRange.kind) { case SyntaxKind.SingleLineCommentTrivia: - textChanges.push(...toggleLineComment(fileName, { end: commentRange.end, pos: commentRange.pos + 1 }, /*insertComment*/ false)); + textChanges.push( + ...toggleLineComment( + fileName, + { end: commentRange.end, pos: commentRange.pos + 1 }, + /*insertComment*/ false, + ), + ); break; case SyntaxKind.MultiLineCommentTrivia: - textChanges.push(...toggleMultilineComment(fileName, { end: commentRange.end, pos: commentRange.pos + 1 }, /*insertComment*/ false)); + textChanges.push( + ...toggleMultilineComment( + fileName, + { end: commentRange.end, pos: commentRange.pos + 1 }, + /*insertComment*/ false, + ), + ); } i = commentRange.end + 1; @@ -2802,18 +3313,25 @@ export function createLanguageService( } function isUnclosedTag({ openingElement, closingElement, parent }: JsxElement): boolean { - return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) || - isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) && isUnclosedTag(parent); + return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) + || isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) + && isUnclosedTag(parent); } function isUnclosedFragment({ closingFragment, parent }: JsxFragment): boolean { - return !!(closingFragment.flags & NodeFlags.ThisNodeHasError) || (isJsxFragment(parent) && isUnclosedFragment(parent)); + return !!(closingFragment.flags & NodeFlags.ThisNodeHasError) + || (isJsxFragment(parent) && isUnclosedFragment(parent)); } - function getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined { + function getSpanOfEnclosingComment( + fileName: string, + position: number, + onlyMultiLine: boolean, + ): TextSpan | undefined { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); const range = formatting.getRangeOfEnclosingComment(sourceFile, position); - return range && (!onlyMultiLine || range.kind === SyntaxKind.MultiLineCommentTrivia) ? createTextSpanFromRange(range) : undefined; + return range && (!onlyMultiLine || range.kind === SyntaxKind.MultiLineCommentTrivia) + ? createTextSpanFromRange(range) : undefined; } function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] { @@ -2917,7 +3435,8 @@ export function createLanguageService( // Match any of the above three TODO comment start regexps. // Note that the outermost group *is* a capture group. We want to capture the preamble // so that we can determine the starting position of the TODO comment match. - const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")"; + const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + + multiLineCommentStart + ")"; // Takes the descriptors and forms a regexp that matches them as if they were literals. // For example, if the descriptors are "TODO(jason)" and "HACK", then this will be: @@ -2953,9 +3472,9 @@ export function createLanguageService( } function isLetterOrDigit(char: number): boolean { - return (char >= CharacterCodes.a && char <= CharacterCodes.z) || - (char >= CharacterCodes.A && char <= CharacterCodes.Z) || - (char >= CharacterCodes._0 && char <= CharacterCodes._9); + return (char >= CharacterCodes.a && char <= CharacterCodes.z) + || (char >= CharacterCodes.A && char <= CharacterCodes.Z) + || (char >= CharacterCodes._0 && char <= CharacterCodes._9); } function isNodeModulesFile(path: string): boolean { @@ -2963,13 +3482,25 @@ export function createLanguageService( } } - function getRenameInfo(fileName: string, position: number, preferences: UserPreferences | RenameInfoOptions | undefined): RenameInfo { + function getRenameInfo( + fileName: string, + position: number, + preferences: UserPreferences | RenameInfoOptions | undefined, + ): RenameInfo { synchronizeHostData(); return Rename.getRenameInfo(program, getValidSourceFile(fileName), position, preferences || {}); } - function getRefactorContext(file: SourceFile, positionOrRange: number | TextRange, preferences: UserPreferences, formatOptions?: FormatCodeSettings, triggerReason?: RefactorTriggerReason, kind?: string): RefactorContext { - const [startPosition, endPosition] = typeof positionOrRange === "number" ? [positionOrRange, undefined] : [positionOrRange.pos, positionOrRange.end]; + function getRefactorContext( + file: SourceFile, + positionOrRange: number | TextRange, + preferences: UserPreferences, + formatOptions?: FormatCodeSettings, + triggerReason?: RefactorTriggerReason, + kind?: string, + ): RefactorContext { + const [startPosition, endPosition] = typeof positionOrRange === "number" ? [positionOrRange, undefined] + : [positionOrRange.pos, positionOrRange.end]; return { file, startPosition, @@ -2980,7 +3511,7 @@ export function createLanguageService( cancellationToken, preferences, triggerReason, - kind + kind, }; } @@ -2999,22 +3530,45 @@ export function createLanguageService( return SmartSelectionRange.getSmartSelectionRange(position, syntaxTreeCache.getCurrentSourceFile(fileName)); } - function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions, triggerReason: RefactorTriggerReason, kind: string, includeInteractiveActions?: boolean): ApplicableRefactorInfo[] { + function getApplicableRefactors( + fileName: string, + positionOrRange: number | TextRange, + preferences: UserPreferences = emptyOptions, + triggerReason: RefactorTriggerReason, + kind: string, + includeInteractiveActions?: boolean, + ): ApplicableRefactorInfo[] { synchronizeHostData(); const file = getValidSourceFile(fileName); - return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange, preferences, emptyOptions, triggerReason, kind), includeInteractiveActions); + return refactor.getApplicableRefactors( + getRefactorContext(file, positionOrRange, preferences, emptyOptions, triggerReason, kind), + includeInteractiveActions, + ); } - function getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions): { newFileName: string, files: string[] } { + function getMoveToRefactoringFileSuggestions( + fileName: string, + positionOrRange: number | TextRange, + preferences: UserPreferences = emptyOptions, + ): { newFileName: string; files: string[]; } { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); const allFiles = Debug.checkDefined(program.getSourceFiles()); const extension = extensionFromPath(fileName); - const files = mapDefined(allFiles, file => !program?.isSourceFileFromExternalLibrary(sourceFile) && - !(sourceFile === getValidSourceFile(file.fileName) || extension === Extension.Ts && extensionFromPath(file.fileName) === Extension.Dts || extension === Extension.Dts && startsWith(getBaseFileName(file.fileName), "lib.") && extensionFromPath(file.fileName) === Extension.Dts) + const files = mapDefined(allFiles, file => + !program?.isSourceFileFromExternalLibrary(sourceFile) + && !(sourceFile === getValidSourceFile(file.fileName) + || extension === Extension.Ts && extensionFromPath(file.fileName) === Extension.Dts + || extension === Extension.Dts && startsWith(getBaseFileName(file.fileName), "lib.") + && extensionFromPath(file.fileName) === Extension.Dts) && extension === extensionFromPath(file.fileName) ? file.fileName : undefined); - const newFileName = createNewFileName(sourceFile, program, getRefactorContext(sourceFile, positionOrRange, preferences, emptyOptions), host); + const newFileName = createNewFileName( + sourceFile, + program, + getRefactorContext(sourceFile, positionOrRange, preferences, emptyOptions), + host, + ); return { newFileName, files }; } @@ -3029,7 +3583,12 @@ export function createLanguageService( ): RefactorEditInfo | undefined { synchronizeHostData(); const file = getValidSourceFile(fileName); - return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, preferences, formatOptions), refactorName, actionName, interactiveRefactorArguments); + return refactor.getEditsForRefactor( + getRefactorContext(file, positionOrRange, preferences, formatOptions), + refactorName, + actionName, + interactiveRefactorArguments, + ); } function toLineColumnOffset(fileName: string, position: number): LineAndCharacter { @@ -3043,27 +3602,48 @@ export function createLanguageService( return sourceMapper.toLineColumnOffset(fileName, position); } - function prepareCallHierarchy(fileName: string, position: number): CallHierarchyItem | CallHierarchyItem[] | undefined { + function prepareCallHierarchy( + fileName: string, + position: number, + ): CallHierarchyItem | CallHierarchyItem[] | undefined { synchronizeHostData(); - const declarations = CallHierarchy.resolveCallHierarchyDeclaration(program, getTouchingPropertyName(getValidSourceFile(fileName), position)); - return declarations && mapOneOrMany(declarations, declaration => CallHierarchy.createCallHierarchyItem(program, declaration)); + const declarations = CallHierarchy.resolveCallHierarchyDeclaration( + program, + getTouchingPropertyName(getValidSourceFile(fileName), position), + ); + return declarations + && mapOneOrMany(declarations, declaration => CallHierarchy.createCallHierarchyItem(program, declaration)); } function provideCallHierarchyIncomingCalls(fileName: string, position: number): CallHierarchyIncomingCall[] { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); - const declaration = firstOrOnly(CallHierarchy.resolveCallHierarchyDeclaration(program, position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position))); + const declaration = firstOrOnly( + CallHierarchy.resolveCallHierarchyDeclaration( + program, + position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position), + ), + ); return declaration ? CallHierarchy.getIncomingCalls(program, declaration, cancellationToken) : []; } function provideCallHierarchyOutgoingCalls(fileName: string, position: number): CallHierarchyOutgoingCall[] { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); - const declaration = firstOrOnly(CallHierarchy.resolveCallHierarchyDeclaration(program, position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position))); + const declaration = firstOrOnly( + CallHierarchy.resolveCallHierarchyDeclaration( + program, + position === 0 ? sourceFile : getTouchingPropertyName(sourceFile, position), + ), + ); return declaration ? CallHierarchy.getOutgoingCalls(program, declaration) : []; } - function provideInlayHints(fileName: string, span: TextSpan, preferences: UserPreferences = emptyOptions): InlayHint[] { + function provideInlayHints( + fileName: string, + span: TextSpan, + preferences: UserPreferences = emptyOptions, + ): InlayHint[] { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); return InlayHints.provideInlayHints(getInlayHintsContext(sourceFile, span, preferences)); @@ -3147,7 +3727,9 @@ export function createLanguageService( case LanguageServiceMode.PartialSemantic: invalidOperationsInPartialSemanticMode.forEach(key => ls[key] = () => { - throw new Error(`LanguageService Operation: ${key} not allowed in LanguageServiceMode.PartialSemantic`); + throw new Error( + `LanguageService Operation: ${key} not allowed in LanguageServiceMode.PartialSemantic`, + ); } ); break; @@ -3180,7 +3762,10 @@ export function getNameTable(sourceFile: SourceFile): Map<__String, number> { function initializeNameTable(sourceFile: SourceFile): void { const nameTable = sourceFile.nameTable = new Map(); sourceFile.forEachChild(function walk(node) { - if (isIdentifier(node) && !isTagName(node) && node.escapedText || isStringOrNumericLiteralLike(node) && literalIsName(node)) { + if ( + isIdentifier(node) && !isTagName(node) && node.escapedText + || isStringOrNumericLiteralLike(node) && literalIsName(node) + ) { const text = getEscapedTextOfIdentifierOrLiteral(node); nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1); } @@ -3205,10 +3790,10 @@ function initializeNameTable(sourceFile: SourceFile): void { * "a['propname']" then we want to store "propname" in the name table. */ function literalIsName(node: StringLiteralLike | NumericLiteral): boolean { - return isDeclarationName(node) || - node.parent.kind === SyntaxKind.ExternalModuleReference || - isArgumentOfElementAccessExpression(node) || - isLiteralComputedPropertyDeclarationName(node); + return isDeclarationName(node) + || node.parent.kind === SyntaxKind.ExternalModuleReference + || isArgumentOfElementAccessExpression(node) + || isLiteralComputedPropertyDeclarationName(node); } /** @@ -3218,7 +3803,8 @@ function literalIsName(node: StringLiteralLike | NumericLiteral): boolean { */ export function getContainingObjectLiteralElement(node: Node): ObjectLiteralElementWithName | undefined { const element = getContainingObjectLiteralElementWorker(node); - return element && (isObjectLiteralExpression(element.parent) || isJsxAttributes(element.parent)) ? element as ObjectLiteralElementWithName : undefined; + return element && (isObjectLiteralExpression(element.parent) || isJsxAttributes(element.parent)) + ? element as ObjectLiteralElementWithName : undefined; } function getContainingObjectLiteralElementWorker(node: Node): ObjectLiteralElement | undefined { switch (node.kind) { @@ -3231,21 +3817,26 @@ function getContainingObjectLiteralElementWorker(node: Node): ObjectLiteralEleme // falls through case SyntaxKind.Identifier: - return isObjectLiteralElement(node.parent) && - (node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression || node.parent.parent.kind === SyntaxKind.JsxAttributes) && - node.parent.name === node ? node.parent : undefined; + return isObjectLiteralElement(node.parent) + && (node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression + || node.parent.parent.kind === SyntaxKind.JsxAttributes) + && node.parent.name === node ? node.parent : undefined; } return undefined; } /** @internal */ -export type ObjectLiteralElementWithName = ObjectLiteralElement & { name: PropertyName; parent: ObjectLiteralExpression | JsxAttributes }; +export type ObjectLiteralElementWithName = ObjectLiteralElement & { + name: PropertyName; + parent: ObjectLiteralExpression | JsxAttributes; +}; function getSymbolAtLocationForQuickInfo(node: Node, checker: TypeChecker): Symbol | undefined { const object = getContainingObjectLiteralElement(node); if (object) { const contextualType = checker.getContextualType(object.parent); - const properties = contextualType && getPropertySymbolsFromContextualType(object, checker, contextualType, /*unionSymbolOk*/ false); + const properties = contextualType + && getPropertySymbolsFromContextualType(object, checker, contextualType, /*unionSymbolOk*/ false); if (properties && properties.length === 1) { return first(properties); } @@ -3258,7 +3849,12 @@ function getSymbolAtLocationForQuickInfo(node: Node, checker: TypeChecker): Symb * * @internal */ -export function getPropertySymbolsFromContextualType(node: ObjectLiteralElementWithName, checker: TypeChecker, contextualType: Type, unionSymbolOk: boolean): readonly Symbol[] { +export function getPropertySymbolsFromContextualType( + node: ObjectLiteralElementWithName, + checker: TypeChecker, + contextualType: Type, + unionSymbolOk: boolean, +): readonly Symbol[] { const name = getNameFromPropertyName(node.name); if (!name) return emptyArray; if (!contextualType.isUnion()) { @@ -3266,8 +3862,16 @@ export function getPropertySymbolsFromContextualType(node: ObjectLiteralElementW return symbol ? [symbol] : emptyArray; } - const discriminatedPropertySymbols = mapDefined(contextualType.types, t => (isObjectLiteralExpression(node.parent)|| isJsxAttributes(node.parent)) && checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent) ? undefined : t.getProperty(name)); - if (unionSymbolOk && (discriminatedPropertySymbols.length === 0 || discriminatedPropertySymbols.length === contextualType.types.length)) { + const discriminatedPropertySymbols = mapDefined( + contextualType.types, + t => (isObjectLiteralExpression(node.parent) || isJsxAttributes(node.parent)) + && checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent) ? undefined : t.getProperty(name), + ); + if ( + unionSymbolOk + && (discriminatedPropertySymbols.length === 0 + || discriminatedPropertySymbols.length === contextualType.types.length) + ) { const symbol = contextualType.getProperty(name); if (symbol) return [symbol]; } @@ -3279,10 +3883,10 @@ export function getPropertySymbolsFromContextualType(node: ObjectLiteralElementW } function isArgumentOfElementAccessExpression(node: Node) { - return node && - node.parent && - node.parent.kind === SyntaxKind.ElementAccessExpression && - (node.parent as ElementAccessExpression).argumentExpression === node; + return node + && node.parent + && node.parent.kind === SyntaxKind.ElementAccessExpression + && (node.parent as ElementAccessExpression).argumentExpression === node; } /** @@ -3292,7 +3896,10 @@ function isArgumentOfElementAccessExpression(node: Node) { */ export function getDefaultLibFilePath(options: CompilerOptions): string { if (sys) { - return combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), getDefaultLibFileName(options)); + return combinePaths( + getDirectoryPath(normalizePath(sys.getExecutingFilePath())), + getDefaultLibFileName(options), + ); } throw new Error("getDefaultLibFilePath is only supported when consumed as a node module. "); diff --git a/src/services/shims.ts b/src/services/shims.ts index 1c3bdae55e9f0..1b792ab4be6fa 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -83,13 +83,14 @@ import { // /** @internal */ -let debugObjectHost: { CollectGarbage(): void } = (function (this: any) { // eslint-disable-line prefer-const +let debugObjectHost: { CollectGarbage(): void; } = (function (this: any) { // eslint-disable-line prefer-const return this; })(); // We need to use 'null' to interface with the managed side. /* eslint-disable local/no-in-operator */ +// dprint-ignore interface DiscoverTypingsInfo { fileNames: string[]; // The file names that belong to the same project. projectRootPath: string; // The path to the project root directory @@ -151,7 +152,15 @@ export interface LanguageServiceShimHost extends Logger { useCaseSensitiveFileNames?(): boolean; getTypeRootsVersion?(): number; - readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string; + readDirectory( + rootDir: string, + extension: string, + basePaths?: string, + excludeEx?: string, + includeFileEx?: string, + includeDirEx?: string, + depth?: number, + ): string; readFile(path: string, encoding?: string): string | undefined; fileExists(path: string): boolean; @@ -177,7 +186,15 @@ export interface CoreServicesShimHost extends Logger { * @param exclude A JSON encoded string[] containing the paths to exclude * when enumerating the directory. */ - readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string; + readDirectory( + rootDir: string, + extension: string, + basePaths?: string, + excludeEx?: string, + includeFileEx?: string, + includeDirEx?: string, + depth?: number, + ): string; /** * Read arbitrary text files on disk, i.e. when resolution procedure needs the content of 'package.json' to determine location of bundled typings for node modules @@ -231,12 +248,35 @@ export interface LanguageServiceShim extends Shim { getCompilerOptionsDiagnostics(): string; getSyntacticClassifications(fileName: string, start: number, length: number): string; - getSemanticClassifications(fileName: string, start: number, length: number, format?: SemanticClassificationFormat): string; + getSemanticClassifications( + fileName: string, + start: number, + length: number, + format?: SemanticClassificationFormat, + ): string; getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string; - getEncodedSemanticClassifications(fileName: string, start: number, length: number, format?: SemanticClassificationFormat): string; - - getCompletionsAtPosition(fileName: string, position: number, preferences: UserPreferences | undefined, formattingSettings: FormatCodeSettings | undefined): string; - getCompletionEntryDetails(fileName: string, position: number, entryName: string, formatOptions: string/*Services.FormatCodeOptions*/ | undefined, source: string | undefined, preferences: UserPreferences | undefined, data: CompletionEntryData | undefined): string; + getEncodedSemanticClassifications( + fileName: string, + start: number, + length: number, + format?: SemanticClassificationFormat, + ): string; + + getCompletionsAtPosition( + fileName: string, + position: number, + preferences: UserPreferences | undefined, + formattingSettings: FormatCodeSettings | undefined, + ): string; + getCompletionEntryDetails( + fileName: string, + position: number, + entryName: string, + formatOptions: string /*Services.FormatCodeOptions*/ | undefined, + source: string | undefined, + preferences: UserPreferences | undefined, + data: CompletionEntryData | undefined, + ): string; getQuickInfoAtPosition(fileName: string, position: number): string; @@ -256,7 +296,13 @@ export interface LanguageServiceShim extends Shim { * Returns a JSON-encoded value of the type: * { fileName: string, textSpan: { start: number, length: number } }[] */ - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, preferences?: UserPreferences | boolean): string; + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + preferences?: UserPreferences | boolean, + ): string; /** * Returns a JSON-encoded value of the type: @@ -333,16 +379,31 @@ export interface LanguageServiceShim extends Shim { getTodoComments(fileName: string, todoCommentDescriptors: string): string; getBraceMatchingAtPosition(fileName: string, position: number): string; - getIndentationAtPosition(fileName: string, position: number, options: string/*Services.EditorOptions*/): string; - - getFormattingEditsForRange(fileName: string, start: number, end: number, options: string/*Services.FormatCodeOptions*/): string; - getFormattingEditsForDocument(fileName: string, options: string/*Services.FormatCodeOptions*/): string; - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string; + getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string; + + getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: string, /*Services.FormatCodeOptions*/ + ): string; + getFormattingEditsForDocument(fileName: string, options: string /*Services.FormatCodeOptions*/): string; + getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: string, /*Services.FormatCodeOptions*/ + ): string; /** * Returns JSON-encoded value of the type TextInsertion. */ - getDocCommentTemplateAtPosition(fileName: string, position: number, options?: DocCommentTemplateOptions, formatOptions?: FormatCodeSettings): string; + getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: DocCommentTemplateOptions, + formatOptions?: FormatCodeSettings, + ): string; /** * Returns JSON-encoded boolean to indicate whether we should support brace location @@ -371,7 +432,11 @@ export interface LanguageServiceShim extends Shim { /** @internal */ export interface ClassifierShim extends Shim { - getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string; + getEncodedLexicalClassifications( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent?: boolean, + ): string; getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string; } @@ -413,7 +478,9 @@ class ScriptSnapshotShimAdapter implements IScriptSnapshot { const decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded!); // TODO: GH#18217 return createTextChangeRange( - createTextSpan(decoded.span.start, decoded.span.length), decoded.newLength); + createTextSpan(decoded.span.start, decoded.span.length), + decoded.newLength, + ); } public dispose(): void { @@ -430,8 +497,15 @@ export class LanguageServiceShimHostAdapter implements LanguageServiceHost { private loggingEnabled = false; private tracingEnabled = false; - public resolveModuleNames: ((moduleName: string[], containingFile: string) => (ResolvedModuleFull | undefined)[]) | undefined; - public resolveTypeReferenceDirectives: ((typeDirectiveNames: string[] | readonly FileReference[], containingFile: string) => (ResolvedTypeReferenceDirective | undefined)[]) | undefined; + public resolveModuleNames: + | ((moduleName: string[], containingFile: string) => (ResolvedModuleFull | undefined)[]) + | undefined; + public resolveTypeReferenceDirectives: + | (( + typeDirectiveNames: string[] | readonly FileReference[], + containingFile: string, + ) => (ResolvedTypeReferenceDirective | undefined)[]) + | undefined; public directoryExists: ((directoryName: string) => boolean) | undefined; constructor(private shimHost: LanguageServiceShimHost) { @@ -439,10 +513,17 @@ export class LanguageServiceShimHostAdapter implements LanguageServiceHost { // 'in' does not have this effect. if ("getModuleResolutionsForFile" in this.shimHost) { this.resolveModuleNames = (moduleNames, containingFile) => { - const resolutionsInFile = JSON.parse(this.shimHost.getModuleResolutionsForFile!(containingFile)) as MapLike; // TODO: GH#18217 + const resolutionsInFile = JSON.parse( + this.shimHost.getModuleResolutionsForFile!(containingFile), + ) as MapLike; // TODO: GH#18217 return map(moduleNames, name => { const result = getProperty(resolutionsInFile, name); - return result ? { resolvedFileName: result, extension: extensionFromPath(result), isExternalLibraryImport: false } : undefined; + return result + ? { + resolvedFileName: result, + extension: extensionFromPath(result), + isExternalLibraryImport: false, + } : undefined; }); }; } @@ -451,8 +532,14 @@ export class LanguageServiceShimHostAdapter implements LanguageServiceHost { } if ("getTypeReferenceDirectiveResolutionsForFile" in this.shimHost) { this.resolveTypeReferenceDirectives = (typeDirectiveNames, containingFile) => { - const typeDirectivesForFile = JSON.parse(this.shimHost.getTypeReferenceDirectiveResolutionsForFile!(containingFile)) as MapLike; // TODO: GH#18217 - return map(typeDirectiveNames as (string | FileReference)[], name => getProperty(typeDirectivesForFile, isString(name) ? name : toFileNameLowerCase(name.fileName))); + const typeDirectivesForFile = JSON.parse( + this.shimHost.getTypeReferenceDirectiveResolutionsForFile!(containingFile), + ) as MapLike; // TODO: GH#18217 + return map( + typeDirectiveNames as (string | FileReference)[], + name => + getProperty(typeDirectivesForFile, isString(name) ? name : toFileNameLowerCase(name.fileName)), + ); }; } } @@ -562,9 +649,20 @@ export class LanguageServiceShimHostAdapter implements LanguageServiceHost { return this.shimHost.getDefaultLibFileName(JSON.stringify(options)); } - public readDirectory(path: string, extensions?: readonly string[], exclude?: string[], include?: string[], depth?: number): string[] { - const pattern = getFileMatcherPatterns(path, exclude, include, - this.shimHost.useCaseSensitiveFileNames!(), this.shimHost.getCurrentDirectory()); // TODO: GH#18217 + public readDirectory( + path: string, + extensions?: readonly string[], + exclude?: string[], + include?: string[], + depth?: number, + ): string[] { + const pattern = getFileMatcherPatterns( + path, + exclude, + include, + this.shimHost.useCaseSensitiveFileNames!(), + this.shimHost.getCurrentDirectory(), + ); // TODO: GH#18217 return JSON.parse(this.shimHost.readDirectory( path, JSON.stringify(extensions), @@ -572,7 +670,7 @@ export class LanguageServiceShimHostAdapter implements LanguageServiceHost { pattern.excludePattern, pattern.includeFilePattern, pattern.includeDirectoryPattern, - depth + depth, )); } @@ -586,14 +684,16 @@ export class LanguageServiceShimHostAdapter implements LanguageServiceHost { } /** @internal */ -export class CoreServicesShimHostAdapter implements ParseConfigHost, ModuleResolutionHost, JsTyping.TypingResolutionHost { - +export class CoreServicesShimHostAdapter + implements ParseConfigHost, ModuleResolutionHost, JsTyping.TypingResolutionHost +{ public directoryExists: (directoryName: string) => boolean; public realpath: (path: string) => string; public useCaseSensitiveFileNames: boolean; constructor(private shimHost: CoreServicesShimHost) { - this.useCaseSensitiveFileNames = this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false; + this.useCaseSensitiveFileNames = this.shimHost.useCaseSensitiveFileNames + ? this.shimHost.useCaseSensitiveFileNames() : false; if ("directoryExists" in this.shimHost) { this.directoryExists = directoryName => this.shimHost.directoryExists(directoryName); } @@ -608,9 +708,20 @@ export class CoreServicesShimHostAdapter implements ParseConfigHost, ModuleResol } } - public readDirectory(rootDir: string, extensions: readonly string[], exclude: readonly string[], include: readonly string[], depth?: number): string[] { - const pattern = getFileMatcherPatterns(rootDir, exclude, include, - this.shimHost.useCaseSensitiveFileNames!(), this.shimHost.getCurrentDirectory()); // TODO: GH#18217 + public readDirectory( + rootDir: string, + extensions: readonly string[], + exclude: readonly string[], + include: readonly string[], + depth?: number, + ): string[] { + const pattern = getFileMatcherPatterns( + rootDir, + exclude, + include, + this.shimHost.useCaseSensitiveFileNames!(), + this.shimHost.getCurrentDirectory(), + ); // TODO: GH#18217 return JSON.parse(this.shimHost.readDirectory( rootDir, JSON.stringify(extensions), @@ -618,7 +729,7 @@ export class CoreServicesShimHostAdapter implements ParseConfigHost, ModuleResol pattern.excludePattern, pattern.includeFilePattern, pattern.includeDirectoryPattern, - depth + depth, )); } @@ -635,7 +746,12 @@ export class CoreServicesShimHostAdapter implements ParseConfigHost, ModuleResol } } -function simpleForwardCall(logger: Logger, actionDescription: string, action: () => unknown, logPerformance: boolean): unknown { +function simpleForwardCall( + logger: Logger, + actionDescription: string, + action: () => unknown, + logPerformance: boolean, +): unknown { let start: number | undefined; if (logPerformance) { logger.log(actionDescription); @@ -659,11 +775,22 @@ function simpleForwardCall(logger: Logger, actionDescription: string, action: () return result; } -function forwardJSONCall(logger: Logger, actionDescription: string, action: () => {} | null | undefined, logPerformance: boolean): string { +function forwardJSONCall( + logger: Logger, + actionDescription: string, + action: () => {} | null | undefined, + logPerformance: boolean, +): string { return forwardCall(logger, actionDescription, /*returnJson*/ true, action, logPerformance) as string; } -function forwardCall(logger: Logger, actionDescription: string, returnJson: boolean, action: () => T, logPerformance: boolean): T | string { +function forwardCall( + logger: Logger, + actionDescription: string, + returnJson: boolean, + action: () => T, + logPerformance: boolean, +): T | string { try { const result = simpleForwardCall(logger, actionDescription, action, logPerformance); return returnJson ? JSON.stringify({ result }) : result as T; @@ -678,7 +805,6 @@ function forwardCall(logger: Logger, actionDescription: string, returnJson: b } } - class ShimBase implements Shim { constructor(private factory: ShimFactory) { factory.registerShim(this); @@ -711,7 +837,7 @@ function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): RealizedDia category: diagnosticCategoryName(diagnostic), code: diagnostic.code, reportsUnnecessary: diagnostic.reportsUnnecessary, - reportsDeprecated: diagnostic.reportsDeprecated + reportsDeprecated: diagnostic.reportsDeprecated, }; } @@ -719,9 +845,7 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim private logger: Logger; private logPerformance = false; - constructor(factory: ShimFactory, - private host: LanguageServiceShimHost, - public languageService: LanguageService) { + constructor(factory: ShimFactory, private host: LanguageServiceShimHost, public languageService: LanguageService) { super(factory); this.logger = this.host; } @@ -760,7 +884,7 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public refresh(throwOnError: boolean): void { this.forwardJSONCall( `refresh(${throwOnError})`, - () => null // eslint-disable-line no-null/no-null + () => null, // eslint-disable-line no-null/no-null ); } @@ -770,10 +894,13 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim () => { this.languageService.cleanupSemanticCache(); return null; // eslint-disable-line no-null/no-null - }); + }, + ); } - private realizeDiagnostics(diagnostics: readonly Diagnostic[]): { message: string; start: number; length: number; category: string; }[] { + private realizeDiagnostics( + diagnostics: readonly Diagnostic[], + ): { message: string; start: number; length: number; category: string; }[] { const newLine = getNewLineOrDefaultFromHost(this.host, /*formatSettings*/ undefined); return realizeDiagnostics(diagnostics, newLine); } @@ -781,14 +908,14 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getSyntacticClassifications(fileName: string, start: number, length: number): string { return this.forwardJSONCall( `getSyntacticClassifications('${fileName}', ${start}, ${length})`, - () => this.languageService.getSyntacticClassifications(fileName, createTextSpan(start, length)) + () => this.languageService.getSyntacticClassifications(fileName, createTextSpan(start, length)), ); } public getSemanticClassifications(fileName: string, start: number, length: number): string { return this.forwardJSONCall( `getSemanticClassifications('${fileName}', ${start}, ${length})`, - () => this.languageService.getSemanticClassifications(fileName, createTextSpan(start, length)) + () => this.languageService.getSemanticClassifications(fileName, createTextSpan(start, length)), ); } @@ -797,7 +924,10 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim `getEncodedSyntacticClassifications('${fileName}', ${start}, ${length})`, // directly serialize the spans out to a string. This is much faster to decode // on the managed side versus a full JSON array. - () => convertClassifications(this.languageService.getEncodedSyntacticClassifications(fileName, createTextSpan(start, length))) + () => + convertClassifications( + this.languageService.getEncodedSyntacticClassifications(fileName, createTextSpan(start, length)), + ), ); } @@ -806,7 +936,10 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim `getEncodedSemanticClassifications('${fileName}', ${start}, ${length})`, // directly serialize the spans out to a string. This is much faster to decode // on the managed side versus a full JSON array. - () => convertClassifications(this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length))) + () => + convertClassifications( + this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length)), + ), ); } @@ -816,7 +949,8 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim () => { const diagnostics = this.languageService.getSyntacticDiagnostics(fileName); return this.realizeDiagnostics(diagnostics); - }); + }, + ); } public getSemanticDiagnostics(fileName: string): string { @@ -825,11 +959,15 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim () => { const diagnostics = this.languageService.getSemanticDiagnostics(fileName); return this.realizeDiagnostics(diagnostics); - }); + }, + ); } public getSuggestionDiagnostics(fileName: string): string { - return this.forwardJSONCall(`getSuggestionDiagnostics('${fileName}')`, () => this.realizeDiagnostics(this.languageService.getSuggestionDiagnostics(fileName))); + return this.forwardJSONCall( + `getSuggestionDiagnostics('${fileName}')`, + () => this.realizeDiagnostics(this.languageService.getSuggestionDiagnostics(fileName)), + ); } public getCompilerOptionsDiagnostics(): string { @@ -838,7 +976,8 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim () => { const diagnostics = this.languageService.getCompilerOptionsDiagnostics(); return this.realizeDiagnostics(diagnostics); - }); + }, + ); } /// QUICKINFO @@ -850,11 +989,10 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getQuickInfoAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( `getQuickInfoAtPosition('${fileName}', ${position})`, - () => this.languageService.getQuickInfoAtPosition(fileName, position) + () => this.languageService.getQuickInfoAtPosition(fileName, position), ); } - /// NAMEORDOTTEDNAMESPAN /** @@ -864,7 +1002,7 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string { return this.forwardJSONCall( `getNameOrDottedNameSpan('${fileName}', ${startPos}, ${endPos})`, - () => this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos) + () => this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos), ); } @@ -875,16 +1013,20 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getBreakpointStatementAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( `getBreakpointStatementAtPosition('${fileName}', ${position})`, - () => this.languageService.getBreakpointStatementAtPosition(fileName, position) + () => this.languageService.getBreakpointStatementAtPosition(fileName, position), ); } /// SIGNATUREHELP - public getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): string { + public getSignatureHelpItems( + fileName: string, + position: number, + options: SignatureHelpItemsOptions | undefined, + ): string { return this.forwardJSONCall( `getSignatureHelpItems('${fileName}', ${position})`, - () => this.languageService.getSignatureHelpItems(fileName, position, options) + () => this.languageService.getSignatureHelpItems(fileName, position, options), ); } @@ -897,7 +1039,7 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getDefinitionAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( `getDefinitionAtPosition('${fileName}', ${position})`, - () => this.languageService.getDefinitionAtPosition(fileName, position) + () => this.languageService.getDefinitionAtPosition(fileName, position), ); } @@ -908,7 +1050,7 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getDefinitionAndBoundSpan(fileName: string, position: number): string { return this.forwardJSONCall( `getDefinitionAndBoundSpan('${fileName}', ${position})`, - () => this.languageService.getDefinitionAndBoundSpan(fileName, position) + () => this.languageService.getDefinitionAndBoundSpan(fileName, position), ); } @@ -921,7 +1063,7 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getTypeDefinitionAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( `getTypeDefinitionAtPosition('${fileName}', ${position})`, - () => this.languageService.getTypeDefinitionAtPosition(fileName, position) + () => this.languageService.getTypeDefinitionAtPosition(fileName, position), ); } @@ -934,28 +1076,41 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getImplementationAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( `getImplementationAtPosition('${fileName}', ${position})`, - () => this.languageService.getImplementationAtPosition(fileName, position) + () => this.languageService.getImplementationAtPosition(fileName, position), ); } public getRenameInfo(fileName: string, position: number, preferences: UserPreferences): string { return this.forwardJSONCall( `getRenameInfo('${fileName}', ${position})`, - () => this.languageService.getRenameInfo(fileName, position, preferences) + () => this.languageService.getRenameInfo(fileName, position, preferences), ); } public getSmartSelectionRange(fileName: string, position: number): string { return this.forwardJSONCall( `getSmartSelectionRange('${fileName}', ${position})`, - () => this.languageService.getSmartSelectionRange(fileName, position) + () => this.languageService.getSmartSelectionRange(fileName, position), ); } - public findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, preferences: UserPreferences): string { + public findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + preferences: UserPreferences, + ): string { return this.forwardJSONCall( `findRenameLocations('${fileName}', ${position}, ${findInStrings}, ${findInComments})`, - () => this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments, preferences) + () => + this.languageService.findRenameLocations( + fileName, + position, + findInStrings, + findInComments, + preferences, + ), ); } @@ -963,32 +1118,37 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getBraceMatchingAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( `getBraceMatchingAtPosition('${fileName}', ${position})`, - () => this.languageService.getBraceMatchingAtPosition(fileName, position) + () => this.languageService.getBraceMatchingAtPosition(fileName, position), ); } public isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): string { return this.forwardJSONCall( `isValidBraceCompletionAtPosition('${fileName}', ${position}, ${openingBrace})`, - () => this.languageService.isValidBraceCompletionAtPosition(fileName, position, openingBrace) + () => this.languageService.isValidBraceCompletionAtPosition(fileName, position, openingBrace), ); } public getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): string { return this.forwardJSONCall( `getSpanOfEnclosingComment('${fileName}', ${position})`, - () => this.languageService.getSpanOfEnclosingComment(fileName, position, onlyMultiLine) + () => this.languageService.getSpanOfEnclosingComment(fileName, position, onlyMultiLine), ); } /// GET SMART INDENT - public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string { + public getIndentationAtPosition( + fileName: string, + position: number, + options: string, /*Services.EditorOptions*/ + ): string { return this.forwardJSONCall( `getIndentationAtPosition('${fileName}', ${position})`, () => { const localOptions: EditorOptions = JSON.parse(options); return this.languageService.getIndentationAtPosition(fileName, position, localOptions); - }); + }, + ); } /// GET REFERENCES @@ -996,21 +1156,21 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getReferencesAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( `getReferencesAtPosition('${fileName}', ${position})`, - () => this.languageService.getReferencesAtPosition(fileName, position) + () => this.languageService.getReferencesAtPosition(fileName, position), ); } public findReferences(fileName: string, position: number): string { return this.forwardJSONCall( `findReferences('${fileName}', ${position})`, - () => this.languageService.findReferences(fileName, position) + () => this.languageService.findReferences(fileName, position), ); } public getFileReferences(fileName: string) { return this.forwardJSONCall( `getFileReferences('${fileName})`, - () => this.languageService.getFileReferences(fileName) + () => this.languageService.getFileReferences(fileName), ); } @@ -1018,11 +1178,16 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim return this.forwardJSONCall( `getDocumentHighlights('${fileName}', ${position})`, () => { - const results = this.languageService.getDocumentHighlights(fileName, position, JSON.parse(filesToSearch)); + const results = this.languageService.getDocumentHighlights( + fileName, + position, + JSON.parse(filesToSearch), + ); // workaround for VS document highlighting issue - keep only items from the initial file const normalizedName = toFileNameLowerCase(normalizeSlashes(fileName)); return filter(results, r => toFileNameLowerCase(normalizeSlashes(r.fileName)) === normalizedName); - }); + }, + ); } /// COMPLETION LISTS @@ -1032,55 +1197,95 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim * to provide at the given source position and providing a member completion * list if requested. */ - public getCompletionsAtPosition(fileName: string, position: number, preferences: GetCompletionsAtPositionOptions | undefined, formattingSettings: FormatCodeSettings | undefined) { + public getCompletionsAtPosition( + fileName: string, + position: number, + preferences: GetCompletionsAtPositionOptions | undefined, + formattingSettings: FormatCodeSettings | undefined, + ) { return this.forwardJSONCall( `getCompletionsAtPosition('${fileName}', ${position}, ${preferences}, ${formattingSettings})`, - () => this.languageService.getCompletionsAtPosition(fileName, position, preferences, formattingSettings) + () => this.languageService.getCompletionsAtPosition(fileName, position, preferences, formattingSettings), ); } /** Get a string based representation of a completion list entry details */ - public getCompletionEntryDetails(fileName: string, position: number, entryName: string, formatOptions: string/*Services.FormatCodeOptions*/ | undefined, source: string | undefined, preferences: UserPreferences | undefined, data: CompletionEntryData | undefined) { + public getCompletionEntryDetails( + fileName: string, + position: number, + entryName: string, + formatOptions: string /*Services.FormatCodeOptions*/ | undefined, + source: string | undefined, + preferences: UserPreferences | undefined, + data: CompletionEntryData | undefined, + ) { return this.forwardJSONCall( `getCompletionEntryDetails('${fileName}', ${position}, '${entryName}')`, () => { - const localOptions: FormatCodeOptions = formatOptions === undefined ? undefined : JSON.parse(formatOptions); - return this.languageService.getCompletionEntryDetails(fileName, position, entryName, localOptions, source, preferences, data); - } + const localOptions: FormatCodeOptions = formatOptions === undefined ? undefined + : JSON.parse(formatOptions); + return this.languageService.getCompletionEntryDetails( + fileName, + position, + entryName, + localOptions, + source, + preferences, + data, + ); + }, ); } - public getFormattingEditsForRange(fileName: string, start: number, end: number, options: string/*Services.FormatCodeOptions*/): string { + public getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: string, /*Services.FormatCodeOptions*/ + ): string { return this.forwardJSONCall( `getFormattingEditsForRange('${fileName}', ${start}, ${end})`, () => { const localOptions: FormatCodeOptions = JSON.parse(options); return this.languageService.getFormattingEditsForRange(fileName, start, end, localOptions); - }); + }, + ); } - public getFormattingEditsForDocument(fileName: string, options: string/*Services.FormatCodeOptions*/): string { + public getFormattingEditsForDocument(fileName: string, options: string /*Services.FormatCodeOptions*/): string { return this.forwardJSONCall( `getFormattingEditsForDocument('${fileName}')`, () => { const localOptions: FormatCodeOptions = JSON.parse(options); return this.languageService.getFormattingEditsForDocument(fileName, localOptions); - }); + }, + ); } - public getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string { + public getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: string, /*Services.FormatCodeOptions*/ + ): string { return this.forwardJSONCall( `getFormattingEditsAfterKeystroke('${fileName}', ${position}, '${key}')`, () => { const localOptions: FormatCodeOptions = JSON.parse(options); return this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions); - }); + }, + ); } - public getDocCommentTemplateAtPosition(fileName: string, position: number, options?: DocCommentTemplateOptions, formatOptions?: FormatCodeSettings): string { + public getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: DocCommentTemplateOptions, + formatOptions?: FormatCodeSettings, + ): string { return this.forwardJSONCall( `getDocCommentTemplateAtPosition('${fileName}', ${position})`, - () => this.languageService.getDocCommentTemplateAtPosition(fileName, position, options, formatOptions) + () => this.languageService.getDocCommentTemplateAtPosition(fileName, position, options, formatOptions), ); } @@ -1090,35 +1295,35 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string): string { return this.forwardJSONCall( `getNavigateToItems('${searchValue}', ${maxResultCount}, ${fileName})`, - () => this.languageService.getNavigateToItems(searchValue, maxResultCount, fileName) + () => this.languageService.getNavigateToItems(searchValue, maxResultCount, fileName), ); } public getNavigationBarItems(fileName: string): string { return this.forwardJSONCall( `getNavigationBarItems('${fileName}')`, - () => this.languageService.getNavigationBarItems(fileName) + () => this.languageService.getNavigationBarItems(fileName), ); } public getNavigationTree(fileName: string): string { return this.forwardJSONCall( `getNavigationTree('${fileName}')`, - () => this.languageService.getNavigationTree(fileName) + () => this.languageService.getNavigationTree(fileName), ); } public getOutliningSpans(fileName: string): string { return this.forwardJSONCall( `getOutliningSpans('${fileName}')`, - () => this.languageService.getOutliningSpans(fileName) + () => this.languageService.getOutliningSpans(fileName), ); } public getTodoComments(fileName: string, descriptors: string): string { return this.forwardJSONCall( `getTodoComments('${fileName}')`, - () => this.languageService.getTodoComments(fileName, JSON.parse(descriptors)) + () => this.languageService.getTodoComments(fileName, JSON.parse(descriptors)), ); } @@ -1127,28 +1332,28 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim public prepareCallHierarchy(fileName: string, position: number): string { return this.forwardJSONCall( `prepareCallHierarchy('${fileName}', ${position})`, - () => this.languageService.prepareCallHierarchy(fileName, position) + () => this.languageService.prepareCallHierarchy(fileName, position), ); } public provideCallHierarchyIncomingCalls(fileName: string, position: number): string { return this.forwardJSONCall( `provideCallHierarchyIncomingCalls('${fileName}', ${position})`, - () => this.languageService.provideCallHierarchyIncomingCalls(fileName, position) + () => this.languageService.provideCallHierarchyIncomingCalls(fileName, position), ); } public provideCallHierarchyOutgoingCalls(fileName: string, position: number): string { return this.forwardJSONCall( `provideCallHierarchyOutgoingCalls('${fileName}', ${position})`, - () => this.languageService.provideCallHierarchyOutgoingCalls(fileName, position) + () => this.languageService.provideCallHierarchyOutgoingCalls(fileName, position), ); } public provideInlayHints(fileName: string, span: TextSpan, preference: UserPreferences | undefined): string { return this.forwardJSONCall( `provideInlayHints('${fileName}', '${JSON.stringify(span)}', ${JSON.stringify(preference)})`, - () => this.languageService.provideInlayHints(fileName, span, preference) + () => this.languageService.provideInlayHints(fileName, span, preference), ); } @@ -1159,7 +1364,7 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim () => { const { diagnostics, ...rest } = this.languageService.getEmitOutput(fileName); return { ...rest, diagnostics: this.realizeDiagnostics(diagnostics) }; - } + }, ); } @@ -1169,39 +1374,40 @@ class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim `getEmitOutput('${fileName}')`, /*returnJson*/ false, () => this.languageService.getEmitOutput(fileName), - this.logPerformance) as EmitOutput; + this.logPerformance, + ) as EmitOutput; } public toggleLineComment(fileName: string, textRange: TextRange): string { return this.forwardJSONCall( `toggleLineComment('${fileName}', '${JSON.stringify(textRange)}')`, - () => this.languageService.toggleLineComment(fileName, textRange) + () => this.languageService.toggleLineComment(fileName, textRange), ); } public toggleMultilineComment(fileName: string, textRange: TextRange): string { return this.forwardJSONCall( `toggleMultilineComment('${fileName}', '${JSON.stringify(textRange)}')`, - () => this.languageService.toggleMultilineComment(fileName, textRange) + () => this.languageService.toggleMultilineComment(fileName, textRange), ); } public commentSelection(fileName: string, textRange: TextRange): string { return this.forwardJSONCall( `commentSelection('${fileName}', '${JSON.stringify(textRange)}')`, - () => this.languageService.commentSelection(fileName, textRange) + () => this.languageService.commentSelection(fileName, textRange), ); } public uncommentSelection(fileName: string, textRange: TextRange): string { return this.forwardJSONCall( `uncommentSelection('${fileName}', '${JSON.stringify(textRange)}')`, - () => this.languageService.uncommentSelection(fileName, textRange) + () => this.languageService.uncommentSelection(fileName, textRange), ); } } -function convertClassifications(classifications: Classifications): { spans: string, endOfLineState: EndOfLineState } { +function convertClassifications(classifications: Classifications): { spans: string; endOfLineState: EndOfLineState; } { return { spans: classifications.spans.join(","), endOfLineState: classifications.endOfLineState }; } @@ -1214,14 +1420,28 @@ class ClassifierShimObject extends ShimBase implements ClassifierShim { this.classifier = createClassifier(); } - public getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent = false): string { - return forwardJSONCall(this.logger, "getEncodedLexicalClassifications", - () => convertClassifications(this.classifier.getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent)), - this.logPerformance); + public getEncodedLexicalClassifications( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent = false, + ): string { + return forwardJSONCall( + this.logger, + "getEncodedLexicalClassifications", + () => + convertClassifications( + this.classifier.getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent), + ), + this.logPerformance, + ); } /// COLORIZATION - public getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics = false): string { + public getClassificationsForLine( + text: string, + lexState: EndOfLineState, + classifyKeywordsInGenerics = false, + ): string { const classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics); let result = ""; for (const item of classification.entries) { @@ -1237,7 +1457,11 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { private logPerformance = false; private safeList: JsTyping.SafeList | undefined; - constructor(factory: ShimFactory, public readonly logger: Logger, private readonly host: CoreServicesShimHostAdapter) { + constructor( + factory: ShimFactory, + public readonly logger: Logger, + private readonly host: CoreServicesShimHostAdapter, + ) { super(factory); } @@ -1250,7 +1474,11 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { const compilerOptions = JSON.parse(compilerOptionsJson) as CompilerOptions; const result = resolveModuleName(moduleName, normalizeSlashes(fileName), compilerOptions, this.host); let resolvedFileName = result.resolvedModule ? result.resolvedModule.resolvedFileName : undefined; - if (result.resolvedModule && result.resolvedModule.extension !== Extension.Ts && result.resolvedModule.extension !== Extension.Tsx && result.resolvedModule.extension !== Extension.Dts) { + if ( + result.resolvedModule && result.resolvedModule.extension !== Extension.Ts + && result.resolvedModule.extension !== Extension.Tsx + && result.resolvedModule.extension !== Extension.Dts + ) { resolvedFileName = undefined; } @@ -1262,14 +1490,24 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { }); } - public resolveTypeReferenceDirective(fileName: string, typeReferenceDirective: string, compilerOptionsJson: string): string { + public resolveTypeReferenceDirective( + fileName: string, + typeReferenceDirective: string, + compilerOptionsJson: string, + ): string { return this.forwardJSONCall(`resolveTypeReferenceDirective(${fileName})`, () => { const compilerOptions = JSON.parse(compilerOptionsJson) as CompilerOptions; - const result = resolveTypeReferenceDirective(typeReferenceDirective, normalizeSlashes(fileName), compilerOptions, this.host); + const result = resolveTypeReferenceDirective( + typeReferenceDirective, + normalizeSlashes(fileName), + compilerOptions, + this.host, + ); return { - resolvedFileName: result.resolvedTypeReferenceDirective ? result.resolvedTypeReferenceDirective.resolvedFileName : undefined, + resolvedFileName: result.resolvedTypeReferenceDirective + ? result.resolvedTypeReferenceDirective.resolvedFileName : undefined, primary: result.resolvedTypeReferenceDirective ? result.resolvedTypeReferenceDirective.primary : true, - failedLookupLocations: result.failedLookupLocations + failedLookupLocations: result.failedLookupLocations, }; }); } @@ -1279,16 +1517,21 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { `getPreProcessedFileInfo('${fileName}')`, () => { // for now treat files as JavaScript - const result = preProcessFile(getSnapshotText(sourceTextSnapshot), /*readImportFiles*/ true, /*detectJavaScriptImports*/ true); + const result = preProcessFile( + getSnapshotText(sourceTextSnapshot), + /*readImportFiles*/ true, + /*detectJavaScriptImports*/ true, + ); return { referencedFiles: this.convertFileReferences(result.referencedFiles), importedFiles: this.convertFileReferences(result.importedFiles), ambientExternalModules: result.ambientExternalModules, isLibFile: result.isLibFile, typeReferenceDirectives: this.convertFileReferences(result.typeReferenceDirectives), - libReferenceDirectives: this.convertFileReferences(result.libReferenceDirectives) + libReferenceDirectives: this.convertFileReferences(result.libReferenceDirectives), }; - }); + }, + ); } public getAutomaticTypeDirectiveNames(compilerOptionsJson: string): string { @@ -1297,7 +1540,7 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { () => { const compilerOptions = JSON.parse(compilerOptionsJson) as CompilerOptions; return getAutomaticTypeDirectiveNames(compilerOptions, this.host); - } + }, ); } @@ -1310,7 +1553,7 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { result.push({ path: normalizeSlashes(ref.fileName), position: ref.pos, - length: ref.end - ref.pos + length: ref.end - ref.pos, }); } return result; @@ -1322,22 +1565,29 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { () => { const result = parseJsonText(fileName, getSnapshotText(sourceTextSnapshot)); const normalizedFileName = normalizeSlashes(fileName); - const configFile = parseJsonSourceFileConfigFileContent(result, this.host, getDirectoryPath(normalizedFileName), /*existingOptions*/ {}, normalizedFileName); + const configFile = parseJsonSourceFileConfigFileContent( + result, + this.host, + getDirectoryPath(normalizedFileName), + /*existingOptions*/ {}, + normalizedFileName, + ); return { options: configFile.options, typeAcquisition: configFile.typeAcquisition, files: configFile.fileNames, raw: configFile.raw, - errors: realizeDiagnostics([...result.parseDiagnostics, ...configFile.errors], "\r\n") + errors: realizeDiagnostics([...result.parseDiagnostics, ...configFile.errors], "\r\n"), }; - }); + }, + ); } public getDefaultCompilationSettings(): string { return this.forwardJSONCall( "getDefaultCompilationSettings()", - () => getDefaultCompilerOptions() + () => getDefaultCompilerOptions(), ); } @@ -1346,7 +1596,10 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { return this.forwardJSONCall("discoverTypings()", () => { const info = JSON.parse(discoverTypingsJson) as DiscoverTypingsInfo; if (this.safeList === undefined) { - this.safeList = JsTyping.loadSafeList(this.host, toPath(info.safeListPath, info.safeListPath, getCanonicalFileName)); + this.safeList = JsTyping.loadSafeList( + this.host, + toPath(info.safeListPath, info.safeListPath, getCanonicalFileName), + ); } return JsTyping.discoverTypings( this.host, @@ -1358,7 +1611,8 @@ class CoreServicesShimObject extends ShimBase implements CoreServicesShim { info.typeAcquisition, info.unresolvedImports, info.typesRegistry, - emptyOptions); + emptyOptions, + ); }); } } @@ -1378,10 +1632,17 @@ export class TypeScriptServicesFactory implements ShimFactory { public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim { try { if (this.documentRegistry === undefined) { - this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory()); + this.documentRegistry = createDocumentRegistry( + host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), + host.getCurrentDirectory(), + ); } const hostAdapter = new LanguageServiceShimHostAdapter(host); - const languageService = createLanguageService(hostAdapter, this.documentRegistry, /*syntaxOnlyOrLanguageServiceMode*/ false); + const languageService = createLanguageService( + hostAdapter, + this.documentRegistry, + /*syntaxOnlyOrLanguageServiceMode*/ false, + ); return new LanguageServiceShimObject(this, host, languageService); } catch (err) { diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 9d3c350943987..7dc065937892c 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -90,9 +90,19 @@ import { TypeParameter, } from "./_namespaces/ts"; -const enum InvocationKind { Call, TypeArgs, Contextual } -interface CallInvocation { readonly kind: InvocationKind.Call; readonly node: CallLikeExpression; } -interface TypeArgsInvocation { readonly kind: InvocationKind.TypeArgs; readonly called: Identifier; } +const enum InvocationKind { + Call, + TypeArgs, + Contextual, +} +interface CallInvocation { + readonly kind: InvocationKind.Call; + readonly node: CallLikeExpression; +} +interface TypeArgsInvocation { + readonly kind: InvocationKind.TypeArgs; + readonly called: Identifier; +} interface ContextualInvocation { readonly kind: InvocationKind.Contextual; readonly signature: Signature; @@ -111,7 +121,13 @@ interface ArgumentListInfo { } /** @internal */ -export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, triggerReason: SignatureHelpTriggerReason | undefined, cancellationToken: CancellationToken): SignatureHelpItems | undefined { +export function getSignatureHelpItems( + program: Program, + sourceFile: SourceFile, + position: number, + triggerReason: SignatureHelpTriggerReason | undefined, + cancellationToken: CancellationToken, +): SignatureHelpItems | undefined { const typeChecker = program.getTypeChecker(); // Decide whether to show signature help @@ -125,7 +141,9 @@ export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, const onlyUseSyntacticOwners = !!triggerReason && triggerReason.kind === "characterTyped"; // Bail out quickly in the middle of a string or comment, don't provide signature help unless the user explicitly requested it. - if (onlyUseSyntacticOwners && (isInString(sourceFile, position, startingToken) || isInComment(sourceFile, position))) { + if ( + onlyUseSyntacticOwners && (isInString(sourceFile, position, startingToken) || isInComment(sourceFile, position)) + ) { return undefined; } @@ -136,22 +154,41 @@ export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, cancellationToken.throwIfCancellationRequested(); // Extra syntactic and semantic filtering of signature help - const candidateInfo = getCandidateOrTypeInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners); + const candidateInfo = getCandidateOrTypeInfo( + argumentInfo, + typeChecker, + sourceFile, + startingToken, + onlyUseSyntacticOwners, + ); cancellationToken.throwIfCancellationRequested(); if (!candidateInfo) { // We didn't have any sig help items produced by the TS compiler. If this is a JS // file, then see if we can figure out anything better. - return isSourceFileJS(sourceFile) ? createJSSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined; + return isSourceFileJS(sourceFile) ? createJSSignatureHelpItems(argumentInfo, program, cancellationToken) + : undefined; } - return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => - candidateInfo.kind === CandidateOrTypeKind.Candidate - ? createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker) - : createTypeHelpItems(candidateInfo.symbol, argumentInfo, sourceFile, typeChecker)); + return typeChecker.runWithCancellationToken( + cancellationToken, + typeChecker => + candidateInfo.kind === CandidateOrTypeKind.Candidate + ? createSignatureHelpItems( + candidateInfo.candidates, + candidateInfo.resolvedSignature, + argumentInfo, + sourceFile, + typeChecker, + ) + : createTypeHelpItems(candidateInfo.symbol, argumentInfo, sourceFile, typeChecker), + ); } -const enum CandidateOrTypeKind { Candidate, Type } +const enum CandidateOrTypeKind { + Candidate, + Type, +} interface CandidateInfo { readonly kind: CandidateOrTypeKind.Candidate; readonly candidates: readonly Signature[]; @@ -162,29 +199,49 @@ interface TypeInfo { readonly symbol: Symbol; } -function getCandidateOrTypeInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | TypeInfo | undefined { +function getCandidateOrTypeInfo( + { invocation, argumentCount }: ArgumentListInfo, + checker: TypeChecker, + sourceFile: SourceFile, + startingToken: Node, + onlyUseSyntacticOwners: boolean, +): CandidateInfo | TypeInfo | undefined { switch (invocation.kind) { case InvocationKind.Call: { if (onlyUseSyntacticOwners && !isSyntacticOwner(startingToken, invocation.node, sourceFile)) { return undefined; } const candidates: Signature[] = []; - const resolvedSignature = checker.getResolvedSignatureForSignatureHelp(invocation.node, candidates, argumentCount)!; // TODO: GH#18217 - return candidates.length === 0 ? undefined : { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature }; + const resolvedSignature = checker.getResolvedSignatureForSignatureHelp( + invocation.node, + candidates, + argumentCount, + )!; // TODO: GH#18217 + return candidates.length === 0 ? undefined + : { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature }; } case InvocationKind.TypeArgs: { const { called } = invocation; - if (onlyUseSyntacticOwners && !containsPrecedingToken(startingToken, sourceFile, isIdentifier(called) ? called.parent : called)) { + if ( + onlyUseSyntacticOwners + && !containsPrecedingToken(startingToken, sourceFile, isIdentifier(called) ? called.parent : called) + ) { return undefined; } const candidates = getPossibleGenericSignatures(called, argumentCount, checker); - if (candidates.length !== 0) return { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature: first(candidates) }; + if (candidates.length !== 0) { + return { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature: first(candidates) }; + } const symbol = checker.getSymbolAtLocation(called); return symbol && { kind: CandidateOrTypeKind.Type, symbol }; } case InvocationKind.Contextual: - return { kind: CandidateOrTypeKind.Candidate, candidates: [invocation.signature], resolvedSignature: invocation.signature }; + return { + kind: CandidateOrTypeKind.Candidate, + candidates: [invocation.signature], + resolvedSignature: invocation.signature, + }; default: return Debug.assertNever(invocation); } @@ -207,28 +264,40 @@ function isSyntacticOwner(startingToken: Node, node: CallLikeExpression, sourceF } } -function createJSSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined { +function createJSSignatureHelpItems( + argumentInfo: ArgumentListInfo, + program: Program, + cancellationToken: CancellationToken, +): SignatureHelpItems | undefined { if (argumentInfo.invocation.kind === InvocationKind.Contextual) return undefined; // See if we can find some symbol with the call expression name that has call signatures. const expression = getExpressionFromInvocation(argumentInfo.invocation); const name = isPropertyAccessExpression(expression) ? expression.name.text : undefined; const typeChecker = program.getTypeChecker(); - return name === undefined ? undefined : firstDefined(program.getSourceFiles(), sourceFile => - firstDefined(sourceFile.getNamedDeclarations().get(name), declaration => { - const type = declaration.symbol && typeChecker.getTypeOfSymbolAtLocation(declaration.symbol, declaration); - const callSignatures = type && type.getCallSignatures(); - if (callSignatures && callSignatures.length) { - return typeChecker.runWithCancellationToken( - cancellationToken, - typeChecker => createSignatureHelpItems( - callSignatures, - callSignatures[0], - argumentInfo, - sourceFile, - typeChecker, - /*useFullPrefix*/ true)); - } - })); + return name === undefined ? undefined + : firstDefined( + program.getSourceFiles(), + sourceFile => + firstDefined(sourceFile.getNamedDeclarations().get(name), declaration => { + const type = declaration.symbol + && typeChecker.getTypeOfSymbolAtLocation(declaration.symbol, declaration); + const callSignatures = type && type.getCallSignatures(); + if (callSignatures && callSignatures.length) { + return typeChecker.runWithCancellationToken( + cancellationToken, + typeChecker => + createSignatureHelpItems( + callSignatures, + callSignatures[0], + argumentInfo, + sourceFile, + typeChecker, + /*useFullPrefix*/ true, + ), + ); + } + }), + ); } function containsPrecedingToken(startingToken: Node, sourceFile: SourceFile, container: Node) { @@ -256,13 +325,26 @@ export interface ArgumentInfoForCompletions { readonly argumentCount: number; } /** @internal */ -export function getArgumentInfoForCompletions(node: Node, position: number, sourceFile: SourceFile): ArgumentInfoForCompletions | undefined { +export function getArgumentInfoForCompletions( + node: Node, + position: number, + sourceFile: SourceFile, +): ArgumentInfoForCompletions | undefined { const info = getImmediatelyContainingArgumentInfo(node, position, sourceFile); return !info || info.isTypeParameterList || info.invocation.kind !== InvocationKind.Call ? undefined : { invocation: info.invocation.node, argumentCount: info.argumentCount, argumentIndex: info.argumentIndex }; } -function getArgumentOrParameterListInfo(node: Node, position: number, sourceFile: SourceFile): { readonly list: Node, readonly argumentIndex: number, readonly argumentCount: number, readonly argumentsSpan: TextSpan } | undefined { +function getArgumentOrParameterListInfo( + node: Node, + position: number, + sourceFile: SourceFile, +): { + readonly list: Node; + readonly argumentIndex: number; + readonly argumentCount: number; + readonly argumentsSpan: TextSpan; +} | undefined { const info = getArgumentOrParameterListAndIndex(node, sourceFile); if (!info) return undefined; const { list, argumentIndex } = info; @@ -274,7 +356,10 @@ function getArgumentOrParameterListInfo(node: Node, position: number, sourceFile const argumentsSpan = getApplicableSpanForArguments(list, sourceFile); return { list, argumentIndex, argumentCount, argumentsSpan }; } -function getArgumentOrParameterListAndIndex(node: Node, sourceFile: SourceFile): { readonly list: Node, readonly argumentIndex: number } | undefined { +function getArgumentOrParameterListAndIndex( + node: Node, + sourceFile: SourceFile, +): { readonly list: Node; readonly argumentIndex: number; } | undefined { if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) { // Find the list that starts right *after* the < or ( token. // If the user has just opened a list, consider this item 0. @@ -296,7 +381,11 @@ function getArgumentOrParameterListAndIndex(node: Node, sourceFile: SourceFile): * Returns relevant information for the argument list and the current argument if we are * in the argument of an invocation; returns undefined otherwise. */ -function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo | undefined { +function getImmediatelyContainingArgumentInfo( + node: Node, + position: number, + sourceFile: SourceFile, +): ArgumentListInfo | undefined { const { parent } = node; if (isCallOrNewExpression(parent)) { const invocation = parent; @@ -319,7 +408,13 @@ function getImmediatelyContainingArgumentInfo(node: Node, position: number, sour if (!info) return undefined; const { list, argumentIndex, argumentCount, argumentsSpan } = info; const isTypeParameterList = !!parent.typeArguments && parent.typeArguments.pos === list.pos; - return { isTypeParameterList, invocation: { kind: InvocationKind.Call, node: invocation }, argumentsSpan, argumentIndex, argumentCount }; + return { + isTypeParameterList, + invocation: { kind: InvocationKind.Call, node: invocation }, + argumentsSpan, + argumentIndex, + argumentCount, + }; } else if (isNoSubstitutionTemplateLiteral(node) && isTaggedTemplateExpression(parent)) { // Check if we're actually inside the template; @@ -365,7 +460,7 @@ function getImmediatelyContainingArgumentInfo(node: Node, position: number, sour invocation: { kind: InvocationKind.Call, node: parent }, argumentsSpan: createTextSpan(attributeSpanStart, attributeSpanEnd - attributeSpanStart), argumentIndex: 0, - argumentCount: 1 + argumentCount: 1, }; } else { @@ -374,14 +469,26 @@ function getImmediatelyContainingArgumentInfo(node: Node, position: number, sour const { called, nTypeArguments } = typeArgInfo; const invocation: Invocation = { kind: InvocationKind.TypeArgs, called }; const argumentsSpan = createTextSpanFromBounds(called.getStart(sourceFile), node.end); - return { isTypeParameterList: true, invocation, argumentsSpan, argumentIndex: nTypeArguments, argumentCount: nTypeArguments + 1 }; + return { + isTypeParameterList: true, + invocation, + argumentsSpan, + argumentIndex: nTypeArguments, + argumentCount: nTypeArguments + 1, + }; } return undefined; } } -function getImmediatelyContainingArgumentOrContextualParameterInfo(node: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined { - return tryGetParameterInfo(node, position, sourceFile, checker) || getImmediatelyContainingArgumentInfo(node, position, sourceFile); +function getImmediatelyContainingArgumentOrContextualParameterInfo( + node: Node, + position: number, + sourceFile: SourceFile, + checker: TypeChecker, +): ArgumentListInfo | undefined { + return tryGetParameterInfo(node, position, sourceFile, checker) + || getImmediatelyContainingArgumentInfo(node, position, sourceFile); } function getHighestBinary(b: BinaryExpression): BinaryExpression { @@ -392,7 +499,12 @@ function countBinaryExpressionParameters(b: BinaryExpression): number { return isBinaryExpression(b.left) ? countBinaryExpressionParameters(b.left) + 1 : 2; } -function tryGetParameterInfo(startingToken: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined { +function tryGetParameterInfo( + startingToken: Node, + position: number, + sourceFile: SourceFile, + checker: TypeChecker, +): ArgumentListInfo | undefined { const node = getAdjustedNode(startingToken); if (node === undefined) return undefined; @@ -409,7 +521,12 @@ function tryGetParameterInfo(startingToken: Node, position: number, sourceFile: const signature = lastOrUndefined(nonNullableContextualType.getCallSignatures()); if (signature === undefined) return undefined; - const invocation: ContextualInvocation = { kind: InvocationKind.Contextual, signature, node: startingToken, symbol: chooseBetterSymbol(symbol) }; + const invocation: ContextualInvocation = { + kind: InvocationKind.Contextual, + signature, + node: startingToken, + symbol: chooseBetterSymbol(symbol), + }; return { isTypeParameterList: false, invocation, argumentsSpan, argumentIndex, argumentCount }; } @@ -419,13 +536,26 @@ function getAdjustedNode(node: Node) { case SyntaxKind.CommaToken: return node; default: - return findAncestor(node.parent, n => - isParameter(n) ? true : isBindingElement(n) || isObjectBindingPattern(n) || isArrayBindingPattern(n) ? false : "quit"); + return findAncestor( + node.parent, + n => isParameter(n) ? true + : isBindingElement(n) || isObjectBindingPattern(n) || isArrayBindingPattern(n) ? false : "quit", + ); } } -interface ContextualSignatureLocationInfo { readonly contextualType: Type; readonly argumentIndex: number; readonly argumentCount: number; readonly argumentsSpan: TextSpan; } -function getContextualSignatureLocationInfo(node: Node, sourceFile: SourceFile, position: number, checker: TypeChecker): ContextualSignatureLocationInfo | undefined { +interface ContextualSignatureLocationInfo { + readonly contextualType: Type; + readonly argumentIndex: number; + readonly argumentCount: number; + readonly argumentsSpan: TextSpan; +} +function getContextualSignatureLocationInfo( + node: Node, + sourceFile: SourceFile, + position: number, + checker: TypeChecker, +): ContextualSignatureLocationInfo | undefined { const { parent } = node; switch (parent.kind) { case SyntaxKind.ParenthesizedExpression: @@ -435,14 +565,18 @@ function getContextualSignatureLocationInfo(node: Node, sourceFile: SourceFile, const info = getArgumentOrParameterListInfo(node, position, sourceFile); if (!info) return undefined; const { argumentIndex, argumentCount, argumentsSpan } = info; - const contextualType = isMethodDeclaration(parent) ? checker.getContextualTypeForObjectLiteralElement(parent) : checker.getContextualType(parent as ParenthesizedExpression | FunctionExpression | ArrowFunction); + const contextualType = isMethodDeclaration(parent) + ? checker.getContextualTypeForObjectLiteralElement(parent) + : checker.getContextualType(parent as ParenthesizedExpression | FunctionExpression | ArrowFunction); return contextualType && { contextualType, argumentIndex, argumentCount, argumentsSpan }; case SyntaxKind.BinaryExpression: { const highestBinary = getHighestBinary(parent as BinaryExpression); const contextualType = checker.getContextualType(highestBinary); - const argumentIndex = node.kind === SyntaxKind.OpenParenToken ? 0 : countBinaryExpressionParameters(parent as BinaryExpression) - 1; + const argumentIndex = node.kind === SyntaxKind.OpenParenToken ? 0 + : countBinaryExpressionParameters(parent as BinaryExpression) - 1; const argumentCount = countBinaryExpressionParameters(highestBinary); - return contextualType && { contextualType, argumentIndex, argumentCount, argumentsSpan: createTextSpanFromNode(parent) }; + return contextualType + && { contextualType, argumentIndex, argumentCount, argumentsSpan: createTextSpanFromNode(parent) }; } default: return undefined; @@ -452,7 +586,10 @@ function getContextualSignatureLocationInfo(node: Node, sourceFile: SourceFile, // The type of a function type node has a symbol at that node, but it's better to use the symbol for a parameter or type alias. function chooseBetterSymbol(s: Symbol): Symbol { return s.name === InternalSymbolName.Type - ? firstDefined(s.declarations, d => isFunctionTypeNode(d) ? tryCast(d.parent, canHaveSymbol)?.symbol : undefined) || s + ? firstDefined( + s.declarations, + d => isFunctionTypeNode(d) ? tryCast(d.parent, canHaveSymbol)?.symbol : undefined, + ) || s : s; } @@ -504,7 +641,12 @@ function getArgumentCount(argumentsList: Node, ignoreTrailingComma: boolean) { // spanIndex is either the index for a given template span. // This does not give appropriate results for a NoSubstitutionTemplateLiteral -function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, position: number, sourceFile: SourceFile): number { +function getArgumentIndexForTemplatePiece( + spanIndex: number, + node: Node, + position: number, + sourceFile: SourceFile, +): number { // Because the TemplateStringsArray is the first argument, we have to offset each substitution expression by 1. // There are three cases we can encounter: // 1. We are precisely in the template literal (argIndex = 0). @@ -513,11 +655,9 @@ function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, positio // not enough to put us in the substitution expression; we should consider ourselves part of // the *next* span's expression by offsetting the index (argIndex = (spanIndex + 1) + 1). // - /* eslint-disable local/no-double-space */ // Example: f `# abcd $#{# 1 + 1# }# efghi ${ #"#hello"# } # ` // ^ ^ ^ ^ ^ ^ ^ ^ ^ // Case: 1 1 3 2 1 3 2 2 1 - /* eslint-enable local/no-double-space */ Debug.assert(position >= node.getStart(), "Assumed 'position' could not occur before node."); if (isTemplateLiteralToken(node)) { if (isInsideTemplateLiteral(node, position, sourceFile)) { @@ -528,9 +668,14 @@ function getArgumentIndexForTemplatePiece(spanIndex: number, node: Node, positio return spanIndex + 1; } -function getArgumentListInfoForTemplate(tagExpression: TaggedTemplateExpression, argumentIndex: number, sourceFile: SourceFile): ArgumentListInfo { +function getArgumentListInfoForTemplate( + tagExpression: TaggedTemplateExpression, + argumentIndex: number, + sourceFile: SourceFile, +): ArgumentListInfo { // argumentCount is either 1 or (numSpans + 1) to account for the template strings array argument. - const argumentCount = isNoSubstitutionTemplateLiteral(tagExpression.template) ? 1 : tagExpression.template.templateSpans.length + 1; + const argumentCount = isNoSubstitutionTemplateLiteral(tagExpression.template) ? 1 + : tagExpression.template.templateSpans.length + 1; if (argumentIndex !== 0) { Debug.assertLessThan(argumentIndex, argumentCount); } @@ -539,7 +684,7 @@ function getArgumentListInfoForTemplate(tagExpression: TaggedTemplateExpression, invocation: { kind: InvocationKind.Call, node: tagExpression }, argumentsSpan: getApplicableSpanForTaggedTemplate(tagExpression, sourceFile), argumentIndex, - argumentCount + argumentCount, }; } @@ -557,7 +702,10 @@ function getApplicableSpanForArguments(argumentsList: Node, sourceFile: SourceFi return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); } -function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpression, sourceFile: SourceFile): TextSpan { +function getApplicableSpanForTaggedTemplate( + taggedTemplate: TaggedTemplateExpression, + sourceFile: SourceFile, +): TextSpan { const template = taggedTemplate.template; const applicableSpanStart = template.getStart(); let applicableSpanEnd = template.getEnd(); @@ -580,12 +728,27 @@ function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpres return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); } -function getContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile, checker: TypeChecker, isManuallyInvoked: boolean): ArgumentListInfo | undefined { +function getContainingArgumentInfo( + node: Node, + position: number, + sourceFile: SourceFile, + checker: TypeChecker, + isManuallyInvoked: boolean, +): ArgumentListInfo | undefined { for (let n = node; !isSourceFile(n) && (isManuallyInvoked || !isBlock(n)); n = n.parent) { // If the node is not a subspan of its parent, this is a big problem. // There have been crashes that might be caused by this violation. - Debug.assert(rangeContainsRange(n.parent, n), "Not a subspan", () => `Child: ${Debug.formatSyntaxKind(n.kind)}, parent: ${Debug.formatSyntaxKind(n.parent.kind)}`); - const argumentInfo = getImmediatelyContainingArgumentOrContextualParameterInfo(n, position, sourceFile, checker); + Debug.assert( + rangeContainsRange(n.parent, n), + "Not a subspan", + () => `Child: ${Debug.formatSyntaxKind(n.kind)}, parent: ${Debug.formatSyntaxKind(n.parent.kind)}`, + ); + const argumentInfo = getImmediatelyContainingArgumentOrContextualParameterInfo( + n, + position, + sourceFile, + checker, + ); if (argumentInfo) { return argumentInfo; } @@ -600,15 +763,19 @@ function getChildListThatStartsWithOpenerToken(parent: Node, openerToken: Node, return children[indexOfOpenerToken + 1]; } -function getExpressionFromInvocation(invocation: CallInvocation | TypeArgsInvocation): Expression | JsxTagNameExpression { +function getExpressionFromInvocation( + invocation: CallInvocation | TypeArgsInvocation, +): Expression | JsxTagNameExpression { return invocation.kind === InvocationKind.Call ? getInvokedExpression(invocation.node) : invocation.called; } function getEnclosingDeclarationFromInvocation(invocation: Invocation): Node { - return invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node; + return invocation.kind === InvocationKind.Call ? invocation.node + : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node; } -const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; +const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors + | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; function createSignatureHelpItems( candidates: readonly Signature[], resolvedSignature: Signature, @@ -618,9 +785,28 @@ function createSignatureHelpItems( useFullPrefix?: boolean, ): SignatureHelpItems { const enclosingDeclaration = getEnclosingDeclarationFromInvocation(invocation); - const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol : (typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation)) || useFullPrefix && resolvedSignature.declaration?.symbol); - const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts(typeChecker, callTargetSymbol, useFullPrefix ? sourceFile : undefined, /*meaning*/ undefined) : emptyArray; - const items = map(candidates, candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile)); + const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol + : (typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation)) + || useFullPrefix && resolvedSignature.declaration?.symbol); + const callTargetDisplayParts = callTargetSymbol + ? symbolToDisplayParts( + typeChecker, + callTargetSymbol, + useFullPrefix ? sourceFile : undefined, + /*meaning*/ undefined, + ) : emptyArray; + const items = map( + candidates, + candidateSignature => + getSignatureHelpItem( + candidateSignature, + callTargetDisplayParts, + isTypeParameterList, + typeChecker, + enclosingDeclaration, + sourceFile, + ), + ); if (argumentIndex !== 0) { Debug.assertLessThan(argumentIndex, argumentCount); @@ -648,7 +834,13 @@ function createSignatureHelpItems( } Debug.assert(selectedItemIndex !== -1); // If candidates is non-empty it should always include bestSignature. We check for an empty candidates before calling this function. - const help = { items: flatMapToMutable(items, identity), applicableSpan, selectedItemIndex, argumentIndex, argumentCount }; + const help = { + items: flatMapToMutable(items, identity), + applicableSpan, + selectedItemIndex, + argumentIndex, + argumentCount, + }; const selected = help.items[selectedItemIndex]; if (selected.isVariadic) { const firstRest = findIndex(selected.parameters, p => !!p.isRest); @@ -667,40 +859,85 @@ function createTypeHelpItems( symbol: Symbol, { argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex }: ArgumentListInfo, sourceFile: SourceFile, - checker: TypeChecker + checker: TypeChecker, ): SignatureHelpItems | undefined { const typeParameters = checker.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); if (!typeParameters) return undefined; - const items = [getTypeHelpItem(symbol, typeParameters, checker, getEnclosingDeclarationFromInvocation(invocation), sourceFile)]; + const items = [ + getTypeHelpItem(symbol, typeParameters, checker, getEnclosingDeclarationFromInvocation(invocation), sourceFile), + ]; return { items, applicableSpan, selectedItemIndex: 0, argumentIndex, argumentCount }; } -function getTypeHelpItem(symbol: Symbol, typeParameters: readonly TypeParameter[], checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem { +function getTypeHelpItem( + symbol: Symbol, + typeParameters: readonly TypeParameter[], + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, +): SignatureHelpItem { const typeSymbolDisplay = symbolToDisplayParts(checker, symbol); const printer = createPrinterWithRemoveComments(); - const parameters = typeParameters.map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer)); + const parameters = typeParameters.map(t => + createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer) + ); const documentation = symbol.getDocumentationComment(checker); const tags = symbol.getJsDocTags(checker); const prefixDisplayParts = [...typeSymbolDisplay, punctuationPart(SyntaxKind.LessThanToken)]; - return { isVariadic: false, prefixDisplayParts, suffixDisplayParts: [punctuationPart(SyntaxKind.GreaterThanToken)], separatorDisplayParts, parameters, documentation, tags }; + return { + isVariadic: false, + prefixDisplayParts, + suffixDisplayParts: [punctuationPart(SyntaxKind.GreaterThanToken)], + separatorDisplayParts, + parameters, + documentation, + tags, + }; } const separatorDisplayParts: SymbolDisplayPart[] = [punctuationPart(SyntaxKind.CommaToken), spacePart()]; -function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: readonly SymbolDisplayPart[], isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem[] { - const infos = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile); +function getSignatureHelpItem( + candidateSignature: Signature, + callTargetDisplayParts: readonly SymbolDisplayPart[], + isTypeParameterList: boolean, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, +): SignatureHelpItem[] { + const infos = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)( + candidateSignature, + checker, + enclosingDeclaration, + sourceFile, + ); return map(infos, ({ isVariadic, parameters, prefix, suffix }) => { const prefixDisplayParts = [...callTargetDisplayParts, ...prefix]; - const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)]; + const suffixDisplayParts = [ + ...suffix, + ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker), + ]; const documentation = candidateSignature.getDocumentationComment(checker); const tags = candidateSignature.getJsDocTags(); - return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags }; + return { + isVariadic, + prefixDisplayParts, + suffixDisplayParts, + separatorDisplayParts, + parameters, + documentation, + tags, + }; }); } -function returnTypeToDisplayParts(candidateSignature: Signature, enclosingDeclaration: Node, checker: TypeChecker): readonly SymbolDisplayPart[] { +function returnTypeToDisplayParts( + candidateSignature: Signature, + enclosingDeclaration: Node, + checker: TypeChecker, +): readonly SymbolDisplayPart[] { return mapToDisplayParts(writer => { writer.writePunctuation(":"); writer.writeSpace(" "); @@ -709,63 +946,145 @@ function returnTypeToDisplayParts(candidateSignature: Signature, enclosingDeclar checker.writeTypePredicate(predicate, enclosingDeclaration, /*flags*/ undefined, writer); } else { - checker.writeType(checker.getReturnTypeOfSignature(candidateSignature), enclosingDeclaration, /*flags*/ undefined, writer); + checker.writeType( + checker.getReturnTypeOfSignature(candidateSignature), + enclosingDeclaration, + /*flags*/ undefined, + writer, + ); } }); } -interface SignatureHelpItemInfo { readonly isVariadic: boolean; readonly parameters: SignatureHelpParameter[]; readonly prefix: readonly SymbolDisplayPart[]; readonly suffix: readonly SymbolDisplayPart[]; } +interface SignatureHelpItemInfo { + readonly isVariadic: boolean; + readonly parameters: SignatureHelpParameter[]; + readonly prefix: readonly SymbolDisplayPart[]; + readonly suffix: readonly SymbolDisplayPart[]; +} -function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] { +function itemInfoForTypeParameters( + candidateSignature: Signature, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, +): SignatureHelpItemInfo[] { const typeParameters = (candidateSignature.target || candidateSignature).typeParameters; const printer = createPrinterWithRemoveComments(); - const parameters = (typeParameters || emptyArray).map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer)); - const thisParameter = candidateSignature.thisParameter ? [checker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : []; + const parameters = (typeParameters || emptyArray).map(t => + createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer) + ); + const thisParameter = candidateSignature.thisParameter + ? [ + checker.symbolToParameterDeclaration( + candidateSignature.thisParameter, + enclosingDeclaration, + signatureHelpNodeBuilderFlags, + )!, + ] : []; return checker.getExpandedParameters(candidateSignature).map(paramList => { - const params = factory.createNodeArray([...thisParameter, ...map(paramList, param => checker.symbolToParameterDeclaration(param, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)]); + const params = factory.createNodeArray([ + ...thisParameter, + ...map( + paramList, + param => + checker.symbolToParameterDeclaration(param, enclosingDeclaration, signatureHelpNodeBuilderFlags)!, + ), + ]); const parameterParts = mapToDisplayParts(writer => { printer.writeList(ListFormat.CallExpressionArguments, params, sourceFile, writer); }); - return { isVariadic: false, parameters, prefix: [punctuationPart(SyntaxKind.LessThanToken)], suffix: [punctuationPart(SyntaxKind.GreaterThanToken), ...parameterParts] }; + return { + isVariadic: false, + parameters, + prefix: [punctuationPart(SyntaxKind.LessThanToken)], + suffix: [punctuationPart(SyntaxKind.GreaterThanToken), ...parameterParts], + }; }); } -function itemInfoForParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] { +function itemInfoForParameters( + candidateSignature: Signature, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, +): SignatureHelpItemInfo[] { const printer = createPrinterWithRemoveComments(); const typeParameterParts = mapToDisplayParts(writer => { if (candidateSignature.typeParameters && candidateSignature.typeParameters.length) { - const args = factory.createNodeArray(candidateSignature.typeParameters.map(p => checker.typeParameterToDeclaration(p, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)); + const args = factory.createNodeArray( + candidateSignature.typeParameters.map(p => + checker.typeParameterToDeclaration(p, enclosingDeclaration, signatureHelpNodeBuilderFlags)! + ), + ); printer.writeList(ListFormat.TypeParameters, args, sourceFile, writer); } }); const lists = checker.getExpandedParameters(candidateSignature); const isVariadic: (parameterList: readonly Symbol[]) => boolean = !checker.hasEffectiveRestParameter(candidateSignature) ? _ => false - : lists.length === 1 ? _ => true - : pList => !!(pList.length && tryCast(pList[pList.length - 1], isTransientSymbol)?.links.checkFlags! & CheckFlags.RestParameter); + : lists.length === 1 ? _ => true + : pList => + !!(pList.length + && tryCast(pList[pList.length - 1], isTransientSymbol)?.links.checkFlags! + & CheckFlags.RestParameter); return lists.map(parameterList => ({ isVariadic: isVariadic(parameterList), - parameters: parameterList.map(p => createSignatureHelpParameterForParameter(p, checker, enclosingDeclaration, sourceFile, printer)), + parameters: parameterList.map(p => + createSignatureHelpParameterForParameter(p, checker, enclosingDeclaration, sourceFile, printer) + ), prefix: [...typeParameterParts, punctuationPart(SyntaxKind.OpenParenToken)], - suffix: [punctuationPart(SyntaxKind.CloseParenToken)] + suffix: [punctuationPart(SyntaxKind.CloseParenToken)], })); } -function createSignatureHelpParameterForParameter(parameter: Symbol, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile, printer: Printer): SignatureHelpParameter { +function createSignatureHelpParameterForParameter( + parameter: Symbol, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, + printer: Printer, +): SignatureHelpParameter { const displayParts = mapToDisplayParts(writer => { - const param = checker.symbolToParameterDeclaration(parameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!; + const param = checker.symbolToParameterDeclaration( + parameter, + enclosingDeclaration, + signatureHelpNodeBuilderFlags, + )!; printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer); }); const isOptional = checker.isOptionalParameter(parameter.valueDeclaration as ParameterDeclaration); const isRest = isTransientSymbol(parameter) && !!(parameter.links.checkFlags & CheckFlags.RestParameter); - return { name: parameter.name, documentation: parameter.getDocumentationComment(checker), displayParts, isOptional, isRest }; + return { + name: parameter.name, + documentation: parameter.getDocumentationComment(checker), + displayParts, + isOptional, + isRest, + }; } -function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile, printer: Printer): SignatureHelpParameter { +function createSignatureHelpParameterForTypeParameter( + typeParameter: TypeParameter, + checker: TypeChecker, + enclosingDeclaration: Node, + sourceFile: SourceFile, + printer: Printer, +): SignatureHelpParameter { const displayParts = mapToDisplayParts(writer => { - const param = checker.typeParameterToDeclaration(typeParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!; + const param = checker.typeParameterToDeclaration( + typeParameter, + enclosingDeclaration, + signatureHelpNodeBuilderFlags, + )!; printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer); }); - return { name: typeParameter.symbol.name, documentation: typeParameter.symbol.getDocumentationComment(checker), displayParts, isOptional: false, isRest: false }; + return { + name: typeParameter.symbol.name, + documentation: typeParameter.symbol.getDocumentationComment(checker), + displayParts, + isOptional: false, + isRest: false, + }; } diff --git a/src/services/smartSelection.ts b/src/services/smartSelection.ts index 887fe86c0cbb2..6df68e7df5dbd 100644 --- a/src/services/smartSelection.ts +++ b/src/services/smartSelection.ts @@ -51,11 +51,12 @@ import { /** @internal */ export function getSmartSelectionRange(pos: number, sourceFile: SourceFile): SelectionRange { let selectionRange: SelectionRange = { - textSpan: createTextSpanFromBounds(sourceFile.getFullStart(), sourceFile.getEnd()) + textSpan: createTextSpanFromBounds(sourceFile.getFullStart(), sourceFile.getEnd()), }; let parentNode: Node = sourceFile; - outer: while (true) { + outer: + while (true) { const children = getSelectionChildren(parentNode); if (!children.length) break; for (let i = 0; i < children.length; i++) { @@ -73,8 +74,11 @@ export function getSmartSelectionRange(pos: number, sourceFile: SourceFile): Sel } if (positionShouldSnapToNode(sourceFile, pos, node)) { - if (isFunctionBody(node) - && isFunctionLikeDeclaration(parentNode) && !positionsAreOnSameLine(node.getStart(sourceFile), node.getEnd(), sourceFile)) { + if ( + isFunctionBody(node) + && isFunctionLikeDeclaration(parentNode) + && !positionsAreOnSameLine(node.getStart(sourceFile), node.getEnd(), sourceFile) + ) { pushSelectionRange(node.getStart(sourceFile), node.getEnd()); } @@ -84,13 +88,15 @@ export function getSmartSelectionRange(pos: number, sourceFile: SourceFile): Sel // 3. A VariableStatement's children are just a VaraiableDeclarationList and a semicolon. // 4. A lone VariableDeclaration in a VaraibleDeclaration feels redundant with the VariableStatement. // Dive in without pushing a selection range. - if (isBlock(node) + if ( + isBlock(node) || isTemplateSpan(node) || isTemplateHead(node) || isTemplateTail(node) || prevNode && isTemplateHead(prevNode) || isVariableDeclarationList(node) && isVariableStatement(parentNode) || isSyntaxList(node) && isVariableDeclarationList(parentNode) || isVariableDeclaration(node) && isSyntaxList(parentNode) && children.length === 1 - || isJSDocTypeExpression(node) || isJSDocSignature(node) || isJSDocTypeLiteral(node)) { + || isJSDocTypeExpression(node) || isJSDocSignature(node) || isJSDocTypeLiteral(node) + ) { parentNode = node; break; } @@ -104,7 +110,8 @@ export function getSmartSelectionRange(pos: number, sourceFile: SourceFile): Sel // Blocks with braces, brackets, parens, or JSX tags on separate lines should be // selected from open to close, including whitespace but not including the braces/etc. themselves. - const isBetweenMultiLineBookends = isSyntaxList(node) && isListOpener(prevNode) && isListCloser(nextNode) + const isBetweenMultiLineBookends = isSyntaxList(node) && isListOpener(prevNode) + && isListCloser(nextNode) && !positionsAreOnSameLine(prevNode.getStart(), nextNode.getStart(), sourceFile); let start = isBetweenMultiLineBookends ? prevNode.getEnd() : node.getStart(); const end = isBetweenMultiLineBookends ? nextNode.getStart() : getEndPos(sourceFile, node); @@ -120,7 +127,10 @@ export function getSmartSelectionRange(pos: number, sourceFile: SourceFile): Sel // covering the JSDoc comment before diving further. if (isSyntaxList(node)) { const firstChild = node.getChildren()[0]; - if (firstChild && hasJSDocNodes(firstChild) && firstChild.jsDoc?.length && firstChild.getStart() !== node.pos) { + if ( + firstChild && hasJSDocNodes(firstChild) && firstChild.jsDoc?.length + && firstChild.getStart() !== node.pos + ) { start = Math.min(start, first(firstChild.jsDoc).getStart()); } } @@ -150,12 +160,14 @@ export function getSmartSelectionRange(pos: number, sourceFile: SourceFile): Sel // Skip empty ranges if (start !== end) { const textSpan = createTextSpanFromBounds(start, end); - if (!selectionRange || ( - // Skip ranges that are identical to the parent - !textSpansEqual(textSpan, selectionRange.textSpan) && - // Skip ranges that don't contain the original position - textSpanIntersectsWithPosition(textSpan, pos) - )) { + if ( + !selectionRange || ( + // Skip ranges that are identical to the parent + !textSpansEqual(textSpan, selectionRange.textSpan) + // Skip ranges that don't contain the original position + && textSpanIntersectsWithPosition(textSpan, pos) + ) + ) { selectionRange = { textSpan, ...selectionRange && { parent: selectionRange } }; } } @@ -228,14 +240,19 @@ function getSelectionChildren(node: Node): readonly Node[] { Debug.assertEqual(openBraceToken.kind, SyntaxKind.OpenBraceToken); Debug.assertEqual(closeBraceToken.kind, SyntaxKind.CloseBraceToken); // Group `-/+readonly` and `-/+?` - const groupedWithPlusMinusTokens = groupChildren(children, child => - child === node.readonlyToken || child.kind === SyntaxKind.ReadonlyKeyword || - child === node.questionToken || child.kind === SyntaxKind.QuestionToken); + const groupedWithPlusMinusTokens = groupChildren( + children, + child => + child === node.readonlyToken || child.kind === SyntaxKind.ReadonlyKeyword + || child === node.questionToken || child.kind === SyntaxKind.QuestionToken, + ); // Group type parameter with surrounding brackets - const groupedWithBrackets = groupChildren(groupedWithPlusMinusTokens, ({ kind }) => - kind === SyntaxKind.OpenBracketToken || - kind === SyntaxKind.TypeParameter || - kind === SyntaxKind.CloseBracketToken + const groupedWithBrackets = groupChildren( + groupedWithPlusMinusTokens, + ({ kind }) => + kind === SyntaxKind.OpenBracketToken + || kind === SyntaxKind.TypeParameter + || kind === SyntaxKind.CloseBracketToken, ); return [ openBraceToken, @@ -247,20 +264,26 @@ function getSelectionChildren(node: Node): readonly Node[] { // Group modifiers and property name, then pivot on `:`. if (isPropertySignature(node)) { - const children = groupChildren(node.getChildren(), child => - child === node.name || contains(node.modifiers, child)); + const children = groupChildren( + node.getChildren(), + child => child === node.name || contains(node.modifiers, child), + ); const firstJSDocChild = children[0]?.kind === SyntaxKind.JSDoc ? children[0] : undefined; - const withJSDocSeparated = firstJSDocChild? children.slice(1) : children; + const withJSDocSeparated = firstJSDocChild ? children.slice(1) : children; const splittedChildren = splitChildren(withJSDocSeparated, ({ kind }) => kind === SyntaxKind.ColonToken); - return firstJSDocChild? [firstJSDocChild, createSyntaxList(splittedChildren)] : splittedChildren; + return firstJSDocChild ? [firstJSDocChild, createSyntaxList(splittedChildren)] : splittedChildren; } // Group the parameter name with its `...`, then that group with its `?`, then pivot on `=`. if (isParameter(node)) { - const groupedDotDotDotAndName = groupChildren(node.getChildren(), child => - child === node.dotDotDotToken || child === node.name); - const groupedWithQuestionToken = groupChildren(groupedDotDotDotAndName, child => - child === groupedDotDotDotAndName[0] || child === node.questionToken); + const groupedDotDotDotAndName = groupChildren( + node.getChildren(), + child => child === node.dotDotDotToken || child === node.name, + ); + const groupedWithQuestionToken = groupChildren( + groupedDotDotDotAndName, + child => child === groupedDotDotDotAndName[0] || child === node.questionToken, + ); return splitChildren(groupedWithQuestionToken, ({ kind }) => kind === SyntaxKind.EqualsToken); } diff --git a/src/services/sourcemaps.ts b/src/services/sourcemaps.ts index 9408098305551..703249e014e43 100644 --- a/src/services/sourcemaps.ts +++ b/src/services/sourcemaps.ts @@ -77,7 +77,7 @@ export function getSourceMapper(host: SourceMapperHost): SourceMapper { { getSourceFileLike, getCanonicalFileName, log: s => host.log(s) }, generatedFileName, getLineInfo(file.text, getLineStarts(file)), - f => !host.fileExists || host.fileExists(f) ? host.readFile!(f) : undefined + f => !host.fileExists || host.fileExists(f) ? host.readFile!(f) : undefined, ); } documentPositionMappers.set(path, mapper || identitySourceMapConsumer); @@ -109,9 +109,15 @@ export function getSourceMapper(host: SourceMapperHost): SourceMapper { const options = program.getCompilerOptions(); const outPath = outFile(options); - const declarationPath = outPath ? - removeFileExtension(outPath) + Extension.Dts : - getDeclarationEmitOutputFilePathWorker(info.fileName, program.getCompilerOptions(), currentDirectory, program.getCommonSourceDirectory(), getCanonicalFileName); + const declarationPath = outPath + ? removeFileExtension(outPath) + Extension.Dts + : getDeclarationEmitOutputFilePathWorker( + info.fileName, + program.getCompilerOptions(), + currentDirectory, + program.getCommonSourceDirectory(), + getCanonicalFileName, + ); if (declarationPath === undefined) return undefined; const newLoc = getDocumentPositionMapper(declarationPath, info.fileName).getGeneratedPosition(info); @@ -147,9 +153,9 @@ export function getSourceMapper(host: SourceMapperHost): SourceMapper { // This can be called from source mapper in either source program or program that includes generated file function getSourceFileLike(fileName: string) { - return !host.getSourceFileLike ? - getSourceFile(fileName) || getOrCreateSourceFileLike(fileName) : - host.getSourceFileLike(fileName); + return !host.getSourceFileLike + ? getSourceFile(fileName) || getOrCreateSourceFileLike(fileName) + : host.getSourceFileLike(fileName); } function toLineColumnOffset(fileName: string, position: number): LineAndCharacter { @@ -169,14 +175,18 @@ export function getSourceMapper(host: SourceMapperHost): SourceMapper { * * @internal */ -export type ReadMapFile = (mapFileName: string, mapFileNameFromDts: string | undefined) => string | undefined | DocumentPositionMapper | false; +export type ReadMapFile = ( + mapFileName: string, + mapFileNameFromDts: string | undefined, +) => string | undefined | DocumentPositionMapper | false; /** @internal */ export function getDocumentPositionMapper( host: DocumentPositionMapperHost, generatedFileName: string, generatedFileLineInfo: LineInfo, - readMapFile: ReadMapFile) { + readMapFile: ReadMapFile, +) { let mapFileName = tryGetSourceMappingURL(generatedFileLineInfo); if (mapFileName) { const match = base64UrlRegExp.exec(mapFileName); @@ -194,7 +204,8 @@ export function getDocumentPositionMapper( possibleMapLocations.push(mapFileName); } possibleMapLocations.push(generatedFileName + ".map"); - const originalMapFileName = mapFileName && getNormalizedAbsolutePath(mapFileName, getDirectoryPath(generatedFileName)); + const originalMapFileName = mapFileName + && getNormalizedAbsolutePath(mapFileName, getDirectoryPath(generatedFileName)); for (const location of possibleMapLocations) { const mapFileName = getNormalizedAbsolutePath(location, getDirectoryPath(generatedFileName)); const mapFileContents = readMapFile(mapFileName, originalMapFileName); @@ -227,6 +238,6 @@ function createSourceFileLike(text: string, lineMap?: SourceFileLike["lineMap"]) lineMap, getLineAndCharacterOfPosition(pos: number) { return computeLineAndCharacterOfPosition(getLineStarts(this), pos); - } + }, }; } diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index bb41bf4d594bc..97b7de9a9412a 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -197,15 +197,35 @@ export function getStringLiteralCompletions( program: Program, log: Log, preferences: UserPreferences, - includeSymbol: boolean): CompletionInfo | undefined { + includeSymbol: boolean, +): CompletionInfo | undefined { if (isInReferenceComment(sourceFile, position)) { const entries = getTripleSlashReferenceCompletion(sourceFile, position, options, host); return entries && convertPathCompletions(entries); } if (isInString(sourceFile, position, contextToken)) { if (!contextToken || !isStringLiteralLike(contextToken)) return undefined; - const entries = getStringLiteralCompletionEntries(sourceFile, contextToken, position, program.getTypeChecker(), options, host, preferences); - return convertStringLiteralCompletions(entries, contextToken, sourceFile, host, program, log, options, preferences, position, includeSymbol); + const entries = getStringLiteralCompletionEntries( + sourceFile, + contextToken, + position, + program.getTypeChecker(), + options, + host, + preferences, + ); + return convertStringLiteralCompletions( + entries, + contextToken, + sourceFile, + host, + program, + log, + options, + preferences, + position, + includeSymbol, + ); } } @@ -257,9 +277,15 @@ function convertStringLiteralCompletions( /*symbolToSortTextMap*/ undefined, /*isJsxIdentifierExpected*/ undefined, /*isRightOfOpenTag*/ undefined, - includeSymbol + includeSymbol, ); // Target will not be used, so arbitrary - return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: completion.hasIndexSignature, optionalReplacementSpan, entries }; + return { + isGlobalCompletion: false, + isMemberCompletion: true, + isNewIdentifierLocation: completion.hasIndexSignature, + optionalReplacementSpan, + entries, + }; } case StringLiteralCompletionKind.Types: { const entries = completion.types.map(type => ({ @@ -267,9 +293,15 @@ function convertStringLiteralCompletions( kindModifiers: ScriptElementKindModifier.none, kind: ScriptElementKind.string, sortText: SortText.LocationPriority, - replacementSpan: getReplacementSpanForContextToken(contextToken) + replacementSpan: getReplacementSpanForContextToken(contextToken), })); - return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: completion.isNewIdentifier, optionalReplacementSpan, entries }; + return { + isGlobalCompletion: false, + isMemberCompletion: false, + isNewIdentifierLocation: completion.isNewIdentifier, + optionalReplacementSpan, + entries, + }; } default: return Debug.assertNever(completion); @@ -277,24 +309,64 @@ function convertStringLiteralCompletions( } /** @internal */ -export function getStringLiteralCompletionDetails(name: string, sourceFile: SourceFile, position: number, contextToken: Node | undefined, checker: TypeChecker, options: CompilerOptions, host: LanguageServiceHost, cancellationToken: CancellationToken, preferences: UserPreferences) { +export function getStringLiteralCompletionDetails( + name: string, + sourceFile: SourceFile, + position: number, + contextToken: Node | undefined, + checker: TypeChecker, + options: CompilerOptions, + host: LanguageServiceHost, + cancellationToken: CancellationToken, + preferences: UserPreferences, +) { if (!contextToken || !isStringLiteralLike(contextToken)) return undefined; - const completions = getStringLiteralCompletionEntries(sourceFile, contextToken, position, checker, options, host, preferences); - return completions && stringLiteralCompletionDetails(name, contextToken, completions, sourceFile, checker, cancellationToken); + const completions = getStringLiteralCompletionEntries( + sourceFile, + contextToken, + position, + checker, + options, + host, + preferences, + ); + return completions + && stringLiteralCompletionDetails(name, contextToken, completions, sourceFile, checker, cancellationToken); } -function stringLiteralCompletionDetails(name: string, location: Node, completion: StringLiteralCompletion, sourceFile: SourceFile, checker: TypeChecker, cancellationToken: CancellationToken): CompletionEntryDetails | undefined { +function stringLiteralCompletionDetails( + name: string, + location: Node, + completion: StringLiteralCompletion, + sourceFile: SourceFile, + checker: TypeChecker, + cancellationToken: CancellationToken, +): CompletionEntryDetails | undefined { switch (completion.kind) { case StringLiteralCompletionKind.Paths: { const match = find(completion.paths, p => p.name === name); - return match && createCompletionDetails(name, kindModifiersFromExtension(match.extension), match.kind, [textPart(name)]); + return match + && createCompletionDetails(name, kindModifiersFromExtension(match.extension), match.kind, [ + textPart(name), + ]); } case StringLiteralCompletionKind.Properties: { const match = find(completion.symbols, s => s.name === name); - return match && createCompletionDetailsForSymbol(match, match.name, checker, sourceFile, location, cancellationToken); + return match + && createCompletionDetailsForSymbol( + match, + match.name, + checker, + sourceFile, + location, + cancellationToken, + ); } case StringLiteralCompletionKind.Types: - return find(completion.types, t => t.value === name) ? createCompletionDetails(name, ScriptElementKindModifier.none, ScriptElementKind.string, [textPart(name)]) : undefined; + return find(completion.types, t => t.value === name) + ? createCompletionDetails(name, ScriptElementKindModifier.none, ScriptElementKind.string, [ + textPart(name), + ]) : undefined; default: return Debug.assertNever(completion); } @@ -303,32 +375,55 @@ function stringLiteralCompletionDetails(name: string, location: Node, completion function convertPathCompletions(pathCompletions: readonly PathCompletion[]): CompletionInfo { const isGlobalCompletion = false; // We don't want the editor to offer any other completions, such as snippets, inside a comment. const isNewIdentifierLocation = true; // The user may type in a path that doesn't yet exist, creating a "new identifier" with respect to the collection of identifiers the server is aware of. - const entries = pathCompletions.map(({ name, kind, span, extension }): CompletionEntry => - ({ name, kind, kindModifiers: kindModifiersFromExtension(extension), sortText: SortText.LocationPriority, replacementSpan: span })); + const entries = pathCompletions.map(({ name, kind, span, extension }): CompletionEntry => ({ + name, + kind, + kindModifiers: kindModifiersFromExtension(extension), + sortText: SortText.LocationPriority, + replacementSpan: span, + })); return { isGlobalCompletion, isMemberCompletion: false, isNewIdentifierLocation, entries }; } function kindModifiersFromExtension(extension: Extension | undefined): ScriptElementKindModifier { switch (extension) { - case Extension.Dts: return ScriptElementKindModifier.dtsModifier; - case Extension.Js: return ScriptElementKindModifier.jsModifier; - case Extension.Json: return ScriptElementKindModifier.jsonModifier; - case Extension.Jsx: return ScriptElementKindModifier.jsxModifier; - case Extension.Ts: return ScriptElementKindModifier.tsModifier; - case Extension.Tsx: return ScriptElementKindModifier.tsxModifier; - case Extension.Dmts: return ScriptElementKindModifier.dmtsModifier; - case Extension.Mjs: return ScriptElementKindModifier.mjsModifier; - case Extension.Mts: return ScriptElementKindModifier.mtsModifier; - case Extension.Dcts: return ScriptElementKindModifier.dctsModifier; - case Extension.Cjs: return ScriptElementKindModifier.cjsModifier; - case Extension.Cts: return ScriptElementKindModifier.ctsModifier; - case Extension.TsBuildInfo: return Debug.fail(`Extension ${Extension.TsBuildInfo} is unsupported.`); - case undefined: return ScriptElementKindModifier.none; + case Extension.Dts: + return ScriptElementKindModifier.dtsModifier; + case Extension.Js: + return ScriptElementKindModifier.jsModifier; + case Extension.Json: + return ScriptElementKindModifier.jsonModifier; + case Extension.Jsx: + return ScriptElementKindModifier.jsxModifier; + case Extension.Ts: + return ScriptElementKindModifier.tsModifier; + case Extension.Tsx: + return ScriptElementKindModifier.tsxModifier; + case Extension.Dmts: + return ScriptElementKindModifier.dmtsModifier; + case Extension.Mjs: + return ScriptElementKindModifier.mjsModifier; + case Extension.Mts: + return ScriptElementKindModifier.mtsModifier; + case Extension.Dcts: + return ScriptElementKindModifier.dctsModifier; + case Extension.Cjs: + return ScriptElementKindModifier.cjsModifier; + case Extension.Cts: + return ScriptElementKindModifier.ctsModifier; + case Extension.TsBuildInfo: + return Debug.fail(`Extension ${Extension.TsBuildInfo} is unsupported.`); + case undefined: + return ScriptElementKindModifier.none; default: return Debug.assertNever(extension); } } -const enum StringLiteralCompletionKind { Paths, Properties, Types } +const enum StringLiteralCompletionKind { + Paths, + Properties, + Types, +} interface StringLiteralCompletionsFromProperties { readonly kind: StringLiteralCompletionKind.Properties; readonly symbols: readonly Symbol[]; @@ -339,14 +434,35 @@ interface StringLiteralCompletionsFromTypes { readonly types: readonly StringLiteralType[]; readonly isNewIdentifier: boolean; } -type StringLiteralCompletion = { readonly kind: StringLiteralCompletionKind.Paths, readonly paths: readonly PathCompletion[] } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes; -function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, preferences: UserPreferences): StringLiteralCompletion | undefined { +type StringLiteralCompletion = + | { readonly kind: StringLiteralCompletionKind.Paths; readonly paths: readonly PathCompletion[]; } + | StringLiteralCompletionsFromProperties + | StringLiteralCompletionsFromTypes; +function getStringLiteralCompletionEntries( + sourceFile: SourceFile, + node: StringLiteralLike, + position: number, + typeChecker: TypeChecker, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + preferences: UserPreferences, +): StringLiteralCompletion | undefined { const parent = walkUpParentheses(node.parent); switch (parent.kind) { case SyntaxKind.LiteralType: { const grandParent = walkUpParentheses(parent.parent); if (grandParent.kind === SyntaxKind.ImportType) { - return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) }; + return { + kind: StringLiteralCompletionKind.Paths, + paths: getStringLiteralCompletionsFromModuleNames( + sourceFile, + node, + compilerOptions, + host, + typeChecker, + preferences, + ), + }; } return fromUnionableLiteralType(grandParent); } @@ -386,11 +502,28 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL case SyntaxKind.NewExpression: case SyntaxKind.JsxAttribute: if (!isRequireCallArgument(node) && !isImportCall(parent)) { - const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(parent.kind === SyntaxKind.JsxAttribute ? parent.parent : node, position, sourceFile); + const argumentInfo = SignatureHelp.getArgumentInfoForCompletions( + parent.kind === SyntaxKind.JsxAttribute ? parent.parent : node, + position, + sourceFile, + ); // Get string literal completions from specialized signatures of the target // i.e. declare function f(a: 'A'); // f("/*completion position*/") - return argumentInfo && (getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker) || getStringLiteralCompletionsFromSignature(argumentInfo.invocation, node, argumentInfo, typeChecker, CheckMode.Normal)) || fromContextualType(ContextFlags.None); + return argumentInfo + && (getStringLiteralCompletionsFromSignature( + argumentInfo.invocation, + node, + argumentInfo, + typeChecker, + ) + || getStringLiteralCompletionsFromSignature( + argumentInfo.invocation, + node, + argumentInfo, + typeChecker, + CheckMode.Normal, + )) || fromContextualType(ContextFlags.None); } // falls through (is `require("")` or `require(""` or `import("")`) @@ -403,7 +536,17 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL // import x = require("/*completion position*/"); // var y = require("/*completion position*/"); // export * from "/*completion position*/"; - return { kind: StringLiteralCompletionKind.Paths, paths: getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker, preferences) }; + return { + kind: StringLiteralCompletionKind.Paths, + paths: getStringLiteralCompletionsFromModuleNames( + sourceFile, + node, + compilerOptions, + host, + typeChecker, + preferences, + ), + }; case SyntaxKind.CaseClause: const tracker = newCaseClauseTracker(typeChecker, (parent as CaseClause).parent.clauses); const contextualTypes = fromContextualType(); @@ -416,13 +559,19 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL return fromContextualType() || fromContextualType(ContextFlags.None); } - function fromUnionableLiteralType(grandParent: Node): StringLiteralCompletionsFromTypes | StringLiteralCompletionsFromProperties | undefined { + function fromUnionableLiteralType( + grandParent: Node, + ): StringLiteralCompletionsFromTypes | StringLiteralCompletionsFromProperties | undefined { switch (grandParent.kind) { case SyntaxKind.ExpressionWithTypeArguments: case SyntaxKind.TypeReference: { const typeArgument = findAncestor(parent, n => n.parent === grandParent) as LiteralTypeNode; if (typeArgument) { - return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(typeArgument)), isNewIdentifier: false }; + return { + kind: StringLiteralCompletionKind.Types, + types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(typeArgument)), + isNewIdentifier: false, + }; } return undefined; } @@ -443,18 +592,31 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL if (!result) { return undefined; } - const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(grandParent as UnionTypeNode, parent as LiteralTypeNode); + const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion( + grandParent as UnionTypeNode, + parent as LiteralTypeNode, + ); if (result.kind === StringLiteralCompletionKind.Properties) { - return { kind: StringLiteralCompletionKind.Properties, symbols: result.symbols.filter(sym => !contains(alreadyUsedTypes, sym.name)), hasIndexSignature: result.hasIndexSignature }; + return { + kind: StringLiteralCompletionKind.Properties, + symbols: result.symbols.filter(sym => !contains(alreadyUsedTypes, sym.name)), + hasIndexSignature: result.hasIndexSignature, + }; } - return { kind: StringLiteralCompletionKind.Types, types: result.types.filter(t => !contains(alreadyUsedTypes, t.value)), isNewIdentifier: false }; + return { + kind: StringLiteralCompletionKind.Types, + types: result.types.filter(t => !contains(alreadyUsedTypes, t.value)), + isNewIdentifier: false, + }; } default: return undefined; } } - function fromContextualType(contextFlags: ContextFlags = ContextFlags.Completions): StringLiteralCompletionsFromTypes | undefined { + function fromContextualType( + contextFlags: ContextFlags = ContextFlags.Completions, + ): StringLiteralCompletionsFromTypes | undefined { // Get completion for string literal from string literal type // i.e. var x: "hi" | "hello" = "/*completion position*/" const types = getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker, contextFlags)); @@ -477,21 +639,35 @@ function walkUpParentheses(node: Node) { } function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current: LiteralTypeNode): readonly string[] { - return mapDefined(union.types, type => - type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined); + return mapDefined( + union.types, + type => + type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text + : undefined, + ); } -function getStringLiteralCompletionsFromSignature(call: CallLikeExpression, arg: StringLiteralLike, argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker, checkMode = CheckMode.IsForStringLiteralArgumentCompletions): StringLiteralCompletionsFromTypes | undefined { +function getStringLiteralCompletionsFromSignature( + call: CallLikeExpression, + arg: StringLiteralLike, + argumentInfo: SignatureHelp.ArgumentInfoForCompletions, + checker: TypeChecker, + checkMode = CheckMode.IsForStringLiteralArgumentCompletions, +): StringLiteralCompletionsFromTypes | undefined { let isNewIdentifier = false; const uniques = new Map(); const candidates: Signature[] = []; - const editingArgument = isJsxOpeningLikeElement(call) ? Debug.checkDefined(findAncestor(arg.parent, isJsxAttribute)) : arg; + const editingArgument = isJsxOpeningLikeElement(call) ? Debug.checkDefined(findAncestor(arg.parent, isJsxAttribute)) + : arg; checker.getResolvedSignatureForStringLiteralCompletions(call, editingArgument, candidates, checkMode); const types = flatMap(candidates, candidate => { if (!signatureHasRestParameter(candidate) && argumentInfo.argumentCount > candidate.parameters.length) return; let type = candidate.getTypeParameterAtPosition(argumentInfo.argumentIndex); if (isJsxOpeningLikeElement(call)) { - const propType = checker.getTypeOfPropertyOfType(type, getTextOfJsxAttributeName((editingArgument as JsxAttribute).name)); + const propType = checker.getTypeOfPropertyOfType( + type, + getTextOfJsxAttributeName((editingArgument as JsxAttribute).name), + ); if (propType) { type = propType; } @@ -502,15 +678,23 @@ function getStringLiteralCompletionsFromSignature(call: CallLikeExpression, arg: return length(types) ? { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier } : undefined; } -function stringLiteralCompletionsFromProperties(type: Type | undefined): StringLiteralCompletionsFromProperties | undefined { +function stringLiteralCompletionsFromProperties( + type: Type | undefined, +): StringLiteralCompletionsFromProperties | undefined { return type && { kind: StringLiteralCompletionKind.Properties, - symbols: filter(type.getApparentProperties(), prop => !(prop.valueDeclaration && isPrivateIdentifierClassElementDeclaration(prop.valueDeclaration))), - hasIndexSignature: hasIndexSignature(type) + symbols: filter( + type.getApparentProperties(), + prop => !(prop.valueDeclaration && isPrivateIdentifierClassElementDeclaration(prop.valueDeclaration)), + ), + hasIndexSignature: hasIndexSignature(type), }; } -function stringLiteralCompletionsForObjectLiteral(checker: TypeChecker, objectLiteralExpression: ObjectLiteralExpression): StringLiteralCompletionsFromProperties | undefined { +function stringLiteralCompletionsForObjectLiteral( + checker: TypeChecker, + objectLiteralExpression: ObjectLiteralExpression, +): StringLiteralCompletionsFromProperties | undefined { const contextualType = checker.getContextualType(objectLiteralExpression); if (!contextualType) return undefined; @@ -519,21 +703,25 @@ function stringLiteralCompletionsForObjectLiteral(checker: TypeChecker, objectLi contextualType, completionsType, objectLiteralExpression, - checker + checker, ); return { kind: StringLiteralCompletionKind.Properties, symbols, - hasIndexSignature: hasIndexSignature(contextualType) + hasIndexSignature: hasIndexSignature(contextualType), }; } -function getStringLiteralTypes(type: Type | undefined, uniques = new Map()): readonly StringLiteralType[] { +function getStringLiteralTypes( + type: Type | undefined, + uniques = new Map(), +): readonly StringLiteralType[] { if (!type) return emptyArray; type = skipConstraint(type); - return type.isUnion() ? flatMap(type.types, t => getStringLiteralTypes(t, uniques)) : - type.isStringLiteral() && !(type.flags & TypeFlags.EnumLiteral) && addToSeen(uniques, type.value) ? [type] : emptyArray; + return type.isUnion() ? flatMap(type.types, t => getStringLiteralTypes(t, uniques)) + : type.isStringLiteral() && !(type.flags & TypeFlags.EnumLiteral) && addToSeen(uniques, type.value) ? [type] + : emptyArray; } interface NameAndKind { @@ -552,28 +740,83 @@ function directoryResult(name: string): NameAndKind { return nameAndKind(name, ScriptElementKind.directory, /*extension*/ undefined); } -function addReplacementSpans(text: string, textStart: number, names: readonly NameAndKind[]): readonly PathCompletion[] { +function addReplacementSpans( + text: string, + textStart: number, + names: readonly NameAndKind[], +): readonly PathCompletion[] { const span = getDirectoryFragmentTextSpan(text, textStart); const wholeSpan = text.length === 0 ? undefined : createTextSpan(textStart, text.length); return names.map(({ name, kind, extension }): PathCompletion => - Math.max(name.indexOf(directorySeparator), name.indexOf(altDirectorySeparator)) !== -1 ? { name, kind, extension, span: wholeSpan } : { name, kind, extension, span }); + Math.max(name.indexOf(directorySeparator), name.indexOf(altDirectorySeparator)) !== -1 + ? { name, kind, extension, span: wholeSpan } : { name, kind, extension, span } + ); } -function getStringLiteralCompletionsFromModuleNames(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker, preferences: UserPreferences): readonly PathCompletion[] { - return addReplacementSpans(node.text, node.getStart(sourceFile) + 1, getStringLiteralCompletionsFromModuleNamesWorker(sourceFile, node, compilerOptions, host, typeChecker, preferences)); +function getStringLiteralCompletionsFromModuleNames( + sourceFile: SourceFile, + node: LiteralExpression, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + typeChecker: TypeChecker, + preferences: UserPreferences, +): readonly PathCompletion[] { + return addReplacementSpans( + node.text, + node.getStart(sourceFile) + 1, + getStringLiteralCompletionsFromModuleNamesWorker( + sourceFile, + node, + compilerOptions, + host, + typeChecker, + preferences, + ), + ); } -function getStringLiteralCompletionsFromModuleNamesWorker(sourceFile: SourceFile, node: LiteralExpression, compilerOptions: CompilerOptions, host: LanguageServiceHost, typeChecker: TypeChecker, preferences: UserPreferences): readonly NameAndKind[] { +function getStringLiteralCompletionsFromModuleNamesWorker( + sourceFile: SourceFile, + node: LiteralExpression, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + typeChecker: TypeChecker, + preferences: UserPreferences, +): readonly NameAndKind[] { const literalValue = normalizeSlashes(node.text); const mode = isStringLiteralLike(node) ? getModeForUsageLocation(sourceFile, node) : undefined; const scriptPath = sourceFile.path; const scriptDirectory = getDirectoryPath(scriptPath); - const extensionOptions = getExtensionOptions(compilerOptions, ReferenceKind.ModuleSpecifier, sourceFile, typeChecker, preferences, mode); + const extensionOptions = getExtensionOptions( + compilerOptions, + ReferenceKind.ModuleSpecifier, + sourceFile, + typeChecker, + preferences, + mode, + ); - return isPathRelativeToScript(literalValue) || !compilerOptions.baseUrl && !compilerOptions.paths && (isRootedDiskPath(literalValue) || isUrl(literalValue)) - ? getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath, extensionOptions) - : getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, mode, compilerOptions, host, extensionOptions, typeChecker); + return isPathRelativeToScript(literalValue) + || !compilerOptions.baseUrl && !compilerOptions.paths + && (isRootedDiskPath(literalValue) || isUrl(literalValue)) + ? getCompletionEntriesForRelativeModules( + literalValue, + scriptDirectory, + compilerOptions, + host, + scriptPath, + extensionOptions, + ) + : getCompletionEntriesForNonRelativeModules( + literalValue, + scriptDirectory, + mode, + compilerOptions, + host, + extensionOptions, + typeChecker, + ); } interface ExtensionOptions { @@ -584,7 +827,14 @@ interface ExtensionOptions { readonly resolutionMode?: ResolutionMode; } -function getExtensionOptions(compilerOptions: CompilerOptions, referenceKind: ReferenceKind, importingSourceFile: SourceFile, typeChecker?: TypeChecker, preferences?: UserPreferences, resolutionMode?: ResolutionMode): ExtensionOptions { +function getExtensionOptions( + compilerOptions: CompilerOptions, + referenceKind: ReferenceKind, + importingSourceFile: SourceFile, + typeChecker?: TypeChecker, + preferences?: UserPreferences, + resolutionMode?: ResolutionMode, +): ExtensionOptions { return { extensionsToSearch: flatten(getSupportedExtensionsForModuleResolution(compilerOptions, typeChecker)), referenceKind, @@ -593,57 +843,114 @@ function getExtensionOptions(compilerOptions: CompilerOptions, referenceKind: Re resolutionMode, }; } -function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path, extensionOptions: ExtensionOptions) { +function getCompletionEntriesForRelativeModules( + literalValue: string, + scriptDirectory: string, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + scriptPath: Path, + extensionOptions: ExtensionOptions, +) { if (compilerOptions.rootDirs) { return getCompletionEntriesForDirectoryFragmentWithRootDirs( - compilerOptions.rootDirs, literalValue, scriptDirectory, extensionOptions, compilerOptions, host, scriptPath); + compilerOptions.rootDirs, + literalValue, + scriptDirectory, + extensionOptions, + compilerOptions, + host, + scriptPath, + ); } else { - return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, scriptPath).values()); + return arrayFrom( + getCompletionEntriesForDirectoryFragment( + literalValue, + scriptDirectory, + extensionOptions, + host, + /*moduleSpecifierIsRelative*/ true, + scriptPath, + ).values(), + ); } } -function getSupportedExtensionsForModuleResolution(compilerOptions: CompilerOptions, typeChecker?: TypeChecker): readonly string[][] { +function getSupportedExtensionsForModuleResolution( + compilerOptions: CompilerOptions, + typeChecker?: TypeChecker, +): readonly string[][] { /** file extensions from ambient modules declarations e.g. *.css */ - const ambientModulesExtensions = !typeChecker ? [] : mapDefined(typeChecker.getAmbientModules(), - module => { - const name = module.name.slice(1, -1); - if (!name.startsWith("*.") || name.includes("/")) return; - return name.slice(1); - } - ); + const ambientModulesExtensions = !typeChecker ? [] : mapDefined(typeChecker.getAmbientModules(), module => { + const name = module.name.slice(1, -1); + if (!name.startsWith("*.") || name.includes("/")) return; + return name.slice(1); + }); const extensions = [...getSupportedExtensions(compilerOptions), ambientModulesExtensions]; const moduleResolution = getEmitModuleResolutionKind(compilerOptions); - return moduleResolutionUsesNodeModules(moduleResolution) ? - getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, extensions) : - extensions; + return moduleResolutionUsesNodeModules(moduleResolution) + ? getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, extensions) + : extensions; } /** * Takes a script path and returns paths for all potential folders that could be merged with its * containing folder via the "rootDirs" compiler option */ -function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, scriptDirectory: string, ignoreCase: boolean): readonly string[] { +function getBaseDirectoriesFromRootDirs( + rootDirs: string[], + basePath: string, + scriptDirectory: string, + ignoreCase: boolean, +): readonly string[] { // Make all paths absolute/normalized if they are not already - rootDirs = rootDirs.map(rootDirectory => normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory))); + rootDirs = rootDirs.map(rootDirectory => + normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory)) + ); // Determine the path to the directory containing the script relative to the root directory it is contained within - const relativeDirectory = firstDefined(rootDirs, rootDirectory => - containsPath(rootDirectory, scriptDirectory, basePath, ignoreCase) ? scriptDirectory.substr(rootDirectory.length) : undefined)!; // TODO: GH#18217 + const relativeDirectory = firstDefined( + rootDirs, + rootDirectory => + containsPath(rootDirectory, scriptDirectory, basePath, ignoreCase) + ? scriptDirectory.substr(rootDirectory.length) : undefined, + )!; // TODO: GH#18217 // Now find a path for each potential directory that is to be merged with the one containing the script return deduplicate( [...rootDirs.map(rootDirectory => combinePaths(rootDirectory, relativeDirectory)), scriptDirectory], equateStringsCaseSensitive, - compareStringsCaseSensitive); + compareStringsCaseSensitive, + ); } -function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptDirectory: string, extensionOptions: ExtensionOptions, compilerOptions: CompilerOptions, host: LanguageServiceHost, exclude: string): readonly NameAndKind[] { +function getCompletionEntriesForDirectoryFragmentWithRootDirs( + rootDirs: string[], + fragment: string, + scriptDirectory: string, + extensionOptions: ExtensionOptions, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, + exclude: string, +): readonly NameAndKind[] { const basePath = compilerOptions.project || host.getCurrentDirectory(); const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames()); const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptDirectory, ignoreCase); - return flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, exclude).values())); + return flatMap( + baseDirectories, + baseDirectory => + arrayFrom( + getCompletionEntriesForDirectoryFragment( + fragment, + baseDirectory, + extensionOptions, + host, + /*moduleSpecifierIsRelative*/ true, + exclude, + ).values(), + ), + ); } const enum ReferenceKind { @@ -660,7 +967,7 @@ function getCompletionEntriesForDirectoryFragment( host: LanguageServiceHost, moduleSpecifierIsRelative: boolean, exclude?: string, - result = createNameAndKindSet() + result = createNameAndKindSet(), ): NameAndKindSet { if (fragment === undefined) { fragment = ""; @@ -689,14 +996,26 @@ function getCompletionEntriesForDirectoryFragment( // check for a version redirect const packageJsonPath = findPackageJson(baseDirectory, host); if (packageJsonPath) { - const packageJson = readJson(packageJsonPath, host as { readFile: (filename: string) => string | undefined }); + const packageJson = readJson( + packageJsonPath, + host as { readFile: (filename: string) => string | undefined; }, + ); const typesVersions = (packageJson as any).typesVersions; if (typeof typesVersions === "object") { const versionPaths = getPackageJsonTypesVersionsPaths(typesVersions)?.paths; if (versionPaths) { const packageDirectory = getDirectoryPath(packageJsonPath); const pathInPackage = absolutePath.slice(ensureTrailingDirectorySeparator(packageDirectory).length); - if (addCompletionEntriesFromPaths(result, pathInPackage, packageDirectory, extensionOptions, host, versionPaths)) { + if ( + addCompletionEntriesFromPaths( + result, + pathInPackage, + packageDirectory, + extensionOptions, + host, + versionPaths, + ) + ) { // A true result means one of the `versionPaths` was matched, which will block relative resolution // to files and folders from here. All reachable paths given the pattern match are already added. return result; @@ -710,7 +1029,13 @@ function getCompletionEntriesForDirectoryFragment( if (!tryDirectoryExists(host, baseDirectory)) return result; // Enumerate the available files if possible - const files = tryReadDirectory(host, baseDirectory, extensionOptions.extensionsToSearch, /*exclude*/ undefined, /*include*/ ["./*"]); + const files = tryReadDirectory( + host, + baseDirectory, + extensionOptions.extensionsToSearch, + /*exclude*/ undefined, + /*include*/ ["./*"], + ); if (files) { for (let filePath of files) { @@ -719,7 +1044,11 @@ function getCompletionEntriesForDirectoryFragment( continue; } - const { name, extension } = getFilenameWithExtensionOption(getBaseFileName(filePath), host.getCompilationSettings(), extensionOptions); + const { name, extension } = getFilenameWithExtensionOption( + getBaseFileName(filePath), + host.getCompilationSettings(), + extensionOptions, + ); result.add(nameAndKind(name, ScriptElementKind.scriptElement, extension)); } } @@ -739,7 +1068,11 @@ function getCompletionEntriesForDirectoryFragment( return result; } -function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerOptions, extensionOptions: ExtensionOptions): { name: string, extension: Extension | undefined } { +function getFilenameWithExtensionOption( + name: string, + compilerOptions: CompilerOptions, + extensionOptions: ExtensionOptions, +): { name: string; extension: Extension | undefined; } { const nonJsResult = moduleSpecifiers.tryGetRealFileNameForNonJsDeclarationFileName(name); if (nonJsResult) { return { name: nonJsResult, extension: tryGetExtensionFromPath(nonJsResult) }; @@ -748,7 +1081,12 @@ function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerO return { name, extension: tryGetExtensionFromPath(name) }; } - const endingPreference = getModuleSpecifierEndingPreference(extensionOptions.endingPreference, extensionOptions.resolutionMode, compilerOptions, extensionOptions.importingSourceFile); + const endingPreference = getModuleSpecifierEndingPreference( + extensionOptions.endingPreference, + extensionOptions.resolutionMode, + compilerOptions, + extensionOptions.importingSourceFile, + ); if (endingPreference === ModuleSpecifierEnding.TsExtension) { if (fileExtensionIsOneOf(name, supportedTSImplementationExtensions)) { return { name, extension: tryGetExtensionFromPath(name) }; @@ -759,8 +1097,9 @@ function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerO : { name, extension: tryGetExtensionFromPath(name) }; } - if ((endingPreference === ModuleSpecifierEnding.Minimal || endingPreference === ModuleSpecifierEnding.Index) && - fileExtensionIsOneOf(name, [Extension.Js, Extension.Jsx, Extension.Ts, Extension.Tsx, Extension.Dts]) + if ( + (endingPreference === ModuleSpecifierEnding.Minimal || endingPreference === ModuleSpecifierEnding.Index) + && fileExtensionIsOneOf(name, [Extension.Js, Extension.Jsx, Extension.Ts, Extension.Tsx, Extension.Dts]) ) { return { name: removeFileExtension(name), extension: tryGetExtensionFromPath(name) }; } @@ -778,7 +1117,7 @@ function addCompletionEntriesFromPaths( baseDirectory: string, extensionOptions: ExtensionOptions, host: LanguageServiceHost, - paths: MapLike + paths: MapLike, ) { const getPatternsForKey = (key: string) => paths[key]; const comparePaths = (a: string, b: string): Comparison => { @@ -788,7 +1127,16 @@ function addCompletionEntriesFromPaths( const lengthB = typeof patternB === "object" ? patternB.prefix.length : b.length; return compareValues(lengthB, lengthA); }; - return addCompletionEntriesFromPathsOrExports(result, fragment, baseDirectory, extensionOptions, host, getOwnKeys(paths), getPatternsForKey, comparePaths); + return addCompletionEntriesFromPathsOrExports( + result, + fragment, + baseDirectory, + extensionOptions, + host, + getOwnKeys(paths), + getPatternsForKey, + comparePaths, + ); } /** @returns whether `fragment` was a match for any `paths` (which should indicate whether any other path completions should be offered) */ @@ -802,7 +1150,7 @@ function addCompletionEntriesFromPathsOrExports( getPatternsForKey: (key: string) => string[] | undefined, comparePaths: (a: string, b: string) => Comparison, ) { - let pathResults: { results: NameAndKind[], matchedPattern: boolean }[] = []; + let pathResults: { results: NameAndKind[]; matchedPattern: boolean; }[] = []; let matchedPath: string | undefined; for (const key of keys) { if (key === ".") continue; @@ -812,7 +1160,8 @@ function addCompletionEntriesFromPathsOrExports( const pathPattern = tryParsePattern(keyWithoutLeadingDotSlash); if (!pathPattern) continue; const isMatch = typeof pathPattern === "object" && isPatternMatch(pathPattern, fragment); - const isLongestMatch = isMatch && (matchedPath === undefined || comparePaths(key, matchedPath) === Comparison.LessThan); + const isLongestMatch = isMatch + && (matchedPath === undefined || comparePaths(key, matchedPath) === Comparison.LessThan); if (isLongestMatch) { // If this is a higher priority match than anything we've seen so far, previous results from matches are invalid, e.g. // for `import {} from "some-package/|"` with a typesVersions: @@ -828,10 +1177,20 @@ function addCompletionEntriesFromPathsOrExports( matchedPath = key; pathResults = pathResults.filter(r => !r.matchedPattern); } - if (typeof pathPattern === "string" || matchedPath === undefined || comparePaths(key, matchedPath) !== Comparison.GreaterThan) { + if ( + typeof pathPattern === "string" || matchedPath === undefined + || comparePaths(key, matchedPath) !== Comparison.GreaterThan + ) { pathResults.push({ matchedPattern: isMatch, - results: getCompletionsForPathMapping(keyWithoutLeadingDotSlash, patterns, fragment, baseDirectory, extensionOptions, host) + results: getCompletionsForPathMapping( + keyWithoutLeadingDotSlash, + patterns, + fragment, + baseDirectory, + extensionOptions, + host, + ) .map(({ name, kind, extension }) => nameAndKind(name, kind, extension)), }); } @@ -865,7 +1224,15 @@ function getCompletionEntriesForNonRelativeModules( if (baseUrl) { const absolute = normalizePath(combinePaths(host.getCurrentDirectory(), baseUrl)); - getCompletionEntriesForDirectoryFragment(fragment, absolute, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment( + fragment, + absolute, + extensionOptions, + host, + /*moduleSpecifierIsRelative*/ false, + /*exclude*/ undefined, + result, + ); } if (paths) { @@ -886,7 +1253,11 @@ function getCompletionEntriesForNonRelativeModules( let foundGlobal = false; if (fragmentDirectory === undefined) { for (const moduleName of enumerateNodeModulesVisibleToScript(host, scriptPath)) { - const moduleResult = nameAndKind(moduleName, ScriptElementKind.externalModuleName, /*extension*/ undefined); + const moduleResult = nameAndKind( + moduleName, + ScriptElementKind.externalModuleName, + /*extension*/ undefined, + ); if (!result.has(moduleResult.name)) { foundGlobal = true; result.add(moduleResult); @@ -897,7 +1268,15 @@ function getCompletionEntriesForNonRelativeModules( let ancestorLookup: (directory: string) => void | undefined = ancestor => { const nodeModules = combinePaths(ancestor, "node_modules"); if (tryDirectoryExists(host, nodeModules)) { - getCompletionEntriesForDirectoryFragment(fragment, nodeModules, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment( + fragment, + nodeModules, + extensionOptions, + host, + /*moduleSpecifierIsRelative*/ false, + /*exclude*/ undefined, + result, + ); } }; if (fragmentDirectory && getResolvePackageJsonExports(compilerOptions)) { @@ -926,7 +1305,8 @@ function getCompletionEntriesForNonRelativeModules( return; // null exports or entrypoint only, no sub-modules available } const keys = getOwnKeys(exports); - const fragmentSubpath = components.join("/") + (components.length && hasTrailingDirectorySeparator(fragment) ? "/" : ""); + const fragmentSubpath = components.join("/") + + (components.length && hasTrailingDirectorySeparator(fragment) ? "/" : ""); const conditions = getConditions(compilerOptions, mode === ModuleKind.ESNext); addCompletionEntriesFromPathsOrExports( result, @@ -935,8 +1315,10 @@ function getCompletionEntriesForNonRelativeModules( extensionOptions, host, keys, - key => singleElementArray(getPatternFromFirstMatchingCondition(exports[key], conditions)), - comparePatternKeys); + key => + singleElementArray(getPatternFromFirstMatchingCondition(exports[key], conditions)), + comparePatternKeys, + ); return; } } @@ -956,7 +1338,10 @@ function getPatternFromFirstMatchingCondition(target: unknown, conditions: reado } if (target && typeof target === "object" && !isArray(target)) { for (const condition in target) { - if (condition === "default" || conditions.indexOf(condition) > -1 || isApplicableVersionedTypesKey(conditions, condition)) { + if ( + condition === "default" || conditions.indexOf(condition) > -1 + || isApplicableVersionedTypesKey(conditions, condition) + ) { const pattern = (target as MapLike)[condition]; return getPatternFromFirstMatchingCondition(pattern, conditions); } @@ -965,7 +1350,8 @@ function getPatternFromFirstMatchingCondition(target: unknown, conditions: reado } function getFragmentDirectory(fragment: string): string | undefined { - return containsSlash(fragment) ? hasTrailingDirectorySeparator(fragment) ? fragment : getDirectoryPath(fragment) : undefined; + return containsSlash(fragment) ? hasTrailingDirectorySeparator(fragment) ? fragment : getDirectoryPath(fragment) + : undefined; } function getCompletionsForPathMapping( @@ -985,13 +1371,26 @@ function getCompletionsForPathMapping( const remainingFragment = tryRemovePrefix(fragment, pathPrefix); if (remainingFragment === undefined) { const starIsFullPathComponent = path[path.length - 2] === "/"; - return starIsFullPathComponent ? justPathMappingName(pathPrefix, ScriptElementKind.directory) : flatMap(patterns, pattern => - getModulesForPathsPattern("", packageDirectory, pattern, extensionOptions, host)?.map(({ name, ...rest }) => ({ name: pathPrefix + name, ...rest }))); + return starIsFullPathComponent ? justPathMappingName(pathPrefix, ScriptElementKind.directory) + : flatMap( + patterns, + pattern => + getModulesForPathsPattern("", packageDirectory, pattern, extensionOptions, host)?.map(( + { name, ...rest }, + ) => ({ name: pathPrefix + name, ...rest })), + ); } - return flatMap(patterns, pattern => getModulesForPathsPattern(remainingFragment, packageDirectory, pattern, extensionOptions, host)); + return flatMap( + patterns, + pattern => getModulesForPathsPattern(remainingFragment, packageDirectory, pattern, extensionOptions, host), + ); - function justPathMappingName(name: string, kind: ScriptElementKind.directory | ScriptElementKind.scriptElement): readonly NameAndKind[] { - return startsWith(name, fragment) ? [{ name: removeTrailingDirectorySeparator(name), kind, extension: undefined }] : emptyArray; + function justPathMappingName( + name: string, + kind: ScriptElementKind.directory | ScriptElementKind.scriptElement, + ): readonly NameAndKind[] { + return startsWith(name, fragment) + ? [{ name: removeTrailingDirectorySeparator(name), kind, extension: undefined }] : emptyArray; } } @@ -1014,21 +1413,26 @@ function getModulesForPathsPattern( // The prefix has two effective parts: the directory path and the base component after the filepath that is not a // full directory component. For example: directory/path/of/prefix/base* const normalizedPrefix = resolvePath(parsed.prefix); - const normalizedPrefixDirectory = hasTrailingDirectorySeparator(parsed.prefix) ? normalizedPrefix : getDirectoryPath(normalizedPrefix); + const normalizedPrefixDirectory = hasTrailingDirectorySeparator(parsed.prefix) ? normalizedPrefix + : getDirectoryPath(normalizedPrefix); const normalizedPrefixBase = hasTrailingDirectorySeparator(parsed.prefix) ? "" : getBaseFileName(normalizedPrefix); const fragmentHasPath = containsSlash(fragment); - const fragmentDirectory = fragmentHasPath ? hasTrailingDirectorySeparator(fragment) ? fragment : getDirectoryPath(fragment) : undefined; + const fragmentDirectory = fragmentHasPath + ? hasTrailingDirectorySeparator(fragment) ? fragment : getDirectoryPath(fragment) : undefined; // Try and expand the prefix to include any path from the fragment so that we can limit the readDirectory call - const expandedPrefixDirectory = fragmentHasPath ? combinePaths(normalizedPrefixDirectory, normalizedPrefixBase + fragmentDirectory) : normalizedPrefixDirectory; + const expandedPrefixDirectory = fragmentHasPath + ? combinePaths(normalizedPrefixDirectory, normalizedPrefixBase + fragmentDirectory) : normalizedPrefixDirectory; const normalizedSuffix = normalizePath(parsed.suffix); const declarationExtension = normalizedSuffix && getDeclarationEmitExtensionForPath("_" + normalizedSuffix); - const matchingSuffixes = declarationExtension ? [changeExtension(normalizedSuffix, declarationExtension), normalizedSuffix] : [normalizedSuffix]; + const matchingSuffixes = declarationExtension + ? [changeExtension(normalizedSuffix, declarationExtension), normalizedSuffix] : [normalizedSuffix]; // Need to normalize after combining: If we combinePaths("a", "../b"), we want "b" and not "a/../b". const baseDirectory = normalizePath(combinePaths(packageDirectory, expandedPrefixDirectory)); - const completePrefix = fragmentHasPath ? baseDirectory : ensureTrailingDirectorySeparator(baseDirectory) + normalizedPrefixBase; + const completePrefix = fragmentHasPath ? baseDirectory + : ensureTrailingDirectorySeparator(baseDirectory) + normalizedPrefixBase; // If we have a suffix, then we read the directory all the way down to avoid returning completions for // directories that don't contain files that would match the suffix. A previous comment here was concerned @@ -1042,23 +1446,33 @@ function getModulesForPathsPattern( ? matchingSuffixes.map(suffix => "**/*" + suffix) : ["./*"]; - const matches = mapDefined(tryReadDirectory(host, baseDirectory, extensionOptions.extensionsToSearch, /*exclude*/ undefined, includeGlobs), match => { - const trimmedWithPattern = trimPrefixAndSuffix(match); - if (trimmedWithPattern) { - if (containsSlash(trimmedWithPattern)) { - return directoryResult(getPathComponents(removeLeadingDirectorySeparator(trimmedWithPattern))[1]); + const matches = mapDefined( + tryReadDirectory(host, baseDirectory, extensionOptions.extensionsToSearch, /*exclude*/ undefined, includeGlobs), + match => { + const trimmedWithPattern = trimPrefixAndSuffix(match); + if (trimmedWithPattern) { + if (containsSlash(trimmedWithPattern)) { + return directoryResult(getPathComponents(removeLeadingDirectorySeparator(trimmedWithPattern))[1]); + } + const { name, extension } = getFilenameWithExtensionOption( + trimmedWithPattern, + host.getCompilationSettings(), + extensionOptions, + ); + return nameAndKind(name, ScriptElementKind.scriptElement, extension); } - const { name, extension } = getFilenameWithExtensionOption(trimmedWithPattern, host.getCompilationSettings(), extensionOptions); - return nameAndKind(name, ScriptElementKind.scriptElement, extension); - } - }); + }, + ); // If we had a suffix, we already recursively searched for all possible files that could match // it and returned the directories leading to those files. Otherwise, assume any directory could // have something valid to import. const directories = normalizedSuffix ? emptyArray - : mapDefined(tryGetDirectories(host, baseDirectory), dir => dir === "node_modules" ? undefined : directoryResult(dir)); + : mapDefined( + tryGetDirectories(host, baseDirectory), + dir => dir === "node_modules" ? undefined : directoryResult(dir), + ); return [...matches, ...directories]; function trimPrefixAndSuffix(path: string): string | undefined { @@ -1077,25 +1491,39 @@ function removeLeadingDirectorySeparator(path: string): string { return path[0] === directorySeparator ? path.slice(1) : path; } -function getAmbientModuleCompletions(fragment: string, fragmentDirectory: string | undefined, checker: TypeChecker): readonly string[] { +function getAmbientModuleCompletions( + fragment: string, + fragmentDirectory: string | undefined, + checker: TypeChecker, +): readonly string[] { // Get modules that the type checker picked up const ambientModules = checker.getAmbientModules().map(sym => stripQuotes(sym.name)); - const nonRelativeModuleNames = ambientModules.filter(moduleName => startsWith(moduleName, fragment) && moduleName.indexOf("*") < 0); + const nonRelativeModuleNames = ambientModules.filter(moduleName => + startsWith(moduleName, fragment) && moduleName.indexOf("*") < 0 + ); // Nested modules of the form "module-name/sub" need to be adjusted to only return the string // after the last '/' that appears in the fragment because that's where the replacement span // starts if (fragmentDirectory !== undefined) { const moduleNameWithSeparator = ensureTrailingDirectorySeparator(fragmentDirectory); - return nonRelativeModuleNames.map(nonRelativeModuleName => removePrefix(nonRelativeModuleName, moduleNameWithSeparator)); + return nonRelativeModuleNames.map(nonRelativeModuleName => + removePrefix(nonRelativeModuleName, moduleNameWithSeparator) + ); } return nonRelativeModuleNames; } -function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): readonly PathCompletion[] | undefined { +function getTripleSlashReferenceCompletion( + sourceFile: SourceFile, + position: number, + compilerOptions: CompilerOptions, + host: LanguageServiceHost, +): readonly PathCompletion[] | undefined { const token = getTokenAtPosition(sourceFile, position); const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); - const range = commentRanges && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end); + const range = commentRanges + && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end); if (!range) { return undefined; } @@ -1107,13 +1535,35 @@ function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: num const [, prefix, kind, toComplete] = match; const scriptPath = getDirectoryPath(sourceFile.path); - const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getExtensionOptions(compilerOptions, ReferenceKind.Filename, sourceFile), host, /*moduleSpecifierIsRelative*/ true, sourceFile.path) - : kind === "types" ? getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, getFragmentDirectory(toComplete), getExtensionOptions(compilerOptions, ReferenceKind.ModuleSpecifier, sourceFile)) + const names = kind === "path" + ? getCompletionEntriesForDirectoryFragment( + toComplete, + scriptPath, + getExtensionOptions(compilerOptions, ReferenceKind.Filename, sourceFile), + host, + /*moduleSpecifierIsRelative*/ true, + sourceFile.path, + ) + : kind === "types" + ? getCompletionEntriesFromTypings( + host, + compilerOptions, + scriptPath, + getFragmentDirectory(toComplete), + getExtensionOptions(compilerOptions, ReferenceKind.ModuleSpecifier, sourceFile), + ) : Debug.fail(); return addReplacementSpans(toComplete, range.pos + prefix.length, arrayFrom(names.values())); } -function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: CompilerOptions, scriptPath: string, fragmentDirectory: string | undefined, extensionOptions: ExtensionOptions, result = createNameAndKindSet()): NameAndKindSet { +function getCompletionEntriesFromTypings( + host: LanguageServiceHost, + options: CompilerOptions, + scriptPath: string, + fragmentDirectory: string | undefined, + extensionOptions: ExtensionOptions, + result = createNameAndKindSet(), +): NameAndKindSet { // Check for typings specified in compiler options const seen = new Map(); @@ -1146,9 +1596,21 @@ function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: Com } else { const baseDirectory = combinePaths(directory, typeDirectoryName); - const remainingFragment = tryRemoveDirectoryPrefix(fragmentDirectory, packageName, hostGetCanonicalFileName(host)); + const remainingFragment = tryRemoveDirectoryPrefix( + fragmentDirectory, + packageName, + hostGetCanonicalFileName(host), + ); if (remainingFragment !== undefined) { - getCompletionEntriesForDirectoryFragment(remainingFragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment( + remainingFragment, + baseDirectory, + extensionOptions, + host, + /*moduleSpecifierIsRelative*/ false, + /*exclude*/ undefined, + result, + ); } } } @@ -1160,7 +1622,7 @@ function enumerateNodeModulesVisibleToScript(host: LanguageServiceHost, scriptPa const result: string[] = []; for (const packageJson of findPackageJsons(scriptPath, host)) { - const contents = readJson(packageJson, host as { readFile: (filename: string) => string | undefined }); // Cast to assert that readFile is defined + const contents = readJson(packageJson, host as { readFile: (filename: string) => string | undefined; }); // Cast to assert that readFile is defined // Provide completions for all non @types dependencies for (const key of nodeModulesDependencyKeys) { const dependencies: object | undefined = (contents as any)[key]; @@ -1181,7 +1643,8 @@ function getDirectoryFragmentTextSpan(text: string, textStart: number): TextSpan const offset = index !== -1 ? index + 1 : 0; // If the range is an identifier, span is unnecessary. const length = text.length - offset; - return length === 0 || isIdentifierText(text.substr(offset, length), ScriptTarget.ESNext) ? undefined : createTextSpan(textStart + offset, length); + return length === 0 || isIdentifierText(text.substr(offset, length), ScriptTarget.ESNext) ? undefined + : createTextSpan(textStart + offset, length); } // Returns true if the path is explicitly relative to the script (i.e. relative to . or ..) @@ -1208,7 +1671,12 @@ function isPathRelativeToScript(path: string) { */ const tripleSlashDirectiveFragmentRegex = /^(\/\/\/\s*(); /** @internal */ -export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] { +export function computeSuggestionDiagnostics( + sourceFile: SourceFile, + program: Program, + cancellationToken: CancellationToken, +): DiagnosticWithLocation[] { program.getSemanticDiagnostics(sourceFile, cancellationToken); const diags: DiagnosticWithLocation[] = []; const checker = program.getTypeChecker(); - const isCommonJSFile = sourceFile.impliedNodeFormat === ModuleKind.CommonJS || fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cts, Extension.Cjs]) ; + const isCommonJSFile = sourceFile.impliedNodeFormat === ModuleKind.CommonJS + || fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cts, Extension.Cjs]); - if (!isCommonJSFile && - sourceFile.commonJsModuleIndicator && - (programContainsEsModules(program) || compilerOptionsIndicateEsModules(program.getCompilerOptions())) && - containsTopLevelCommonjs(sourceFile)) { - diags.push(createDiagnosticForNode(getErrorNodeFromCommonJsIndicator(sourceFile.commonJsModuleIndicator), Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module)); + if ( + !isCommonJSFile + && sourceFile.commonJsModuleIndicator + && (programContainsEsModules(program) || compilerOptionsIndicateEsModules(program.getCompilerOptions())) + && containsTopLevelCommonjs(sourceFile) + ) { + diags.push( + createDiagnosticForNode( + getErrorNodeFromCommonJsIndicator(sourceFile.commonJsModuleIndicator), + Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module, + ), + ); } const isJsFile = isSourceFileJS(sourceFile); @@ -87,9 +99,17 @@ export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Pr const importNode = importFromModuleSpecifier(moduleSpecifier); const name = importNameForConvertToDefaultImport(importNode); if (!name) continue; - const module = getResolvedModule(sourceFile, moduleSpecifier.text, getModeForUsageLocation(sourceFile, moduleSpecifier)); + const module = getResolvedModule( + sourceFile, + moduleSpecifier.text, + getModeForUsageLocation(sourceFile, moduleSpecifier), + ); const resolvedFile = module && program.getSourceFile(module.resolvedFileName); - if (resolvedFile && resolvedFile.externalModuleIndicator && resolvedFile.externalModuleIndicator !== true && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals) { + if ( + resolvedFile && resolvedFile.externalModuleIndicator && resolvedFile.externalModuleIndicator !== true + && isExportAssignment(resolvedFile.externalModuleIndicator) + && resolvedFile.externalModuleIndicator.isExportEquals + ) { diags.push(createDiagnosticForNode(name, Diagnostics.Import_may_be_converted_to_a_default_import)); } } @@ -102,14 +122,21 @@ export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Pr function check(node: Node) { if (isJsFile) { if (canBeConvertedToClass(node, checker)) { - diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_constructor_function_may_be_converted_to_a_class_declaration)); + diags.push( + createDiagnosticForNode( + isVariableDeclaration(node.parent) ? node.parent.name : node, + Diagnostics.This_constructor_function_may_be_converted_to_a_class_declaration, + ), + ); } } else { - if (isVariableStatement(node) && - node.parent === sourceFile && - node.declarationList.flags & NodeFlags.Const && - node.declarationList.declarations.length === 1) { + if ( + isVariableStatement(node) + && node.parent === sourceFile + && node.declarationList.flags & NodeFlags.Const + && node.declarationList.declarations.length === 1 + ) { const init = node.declarationList.declarations[0].initializer; if (init && isRequireCall(init, /*requireStringLiteralLikeArgument*/ true)) { diags.push(createDiagnosticForNode(init, Diagnostics.require_call_may_be_converted_to_an_import)); @@ -118,11 +145,21 @@ export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Pr const jsdocTypedefNodes = codefix.getJSDocTypedefNodes(node); for (const jsdocTypedefNode of jsdocTypedefNodes) { - diags.push(createDiagnosticForNode(jsdocTypedefNode, Diagnostics.JSDoc_typedef_may_be_converted_to_TypeScript_type)); + diags.push( + createDiagnosticForNode( + jsdocTypedefNode, + Diagnostics.JSDoc_typedef_may_be_converted_to_TypeScript_type, + ), + ); } if (codefix.parameterShouldGetTypeFromJSDoc(node)) { - diags.push(createDiagnosticForNode(node.name || node, Diagnostics.JSDoc_types_may_be_moved_to_TypeScript_types)); + diags.push( + createDiagnosticForNode( + node.name || node, + Diagnostics.JSDoc_types_may_be_moved_to_TypeScript_types, + ), + ); } } @@ -139,12 +176,20 @@ function containsTopLevelCommonjs(sourceFile: SourceFile): boolean { switch (statement.kind) { case SyntaxKind.VariableStatement: return (statement as VariableStatement).declarationList.declarations.some(decl => - !!decl.initializer && isRequireCall(propertyAccessLeftHandSide(decl.initializer), /*requireStringLiteralLikeArgument*/ true)); + !!decl.initializer + && isRequireCall( + propertyAccessLeftHandSide(decl.initializer), + /*requireStringLiteralLikeArgument*/ true, + ) + ); case SyntaxKind.ExpressionStatement: { const { expression } = statement as ExpressionStatement; - if (!isBinaryExpression(expression)) return isRequireCall(expression, /*requireStringLiteralLikeArgument*/ true); + if (!isBinaryExpression(expression)) { + return isRequireCall(expression, /*requireStringLiteralLikeArgument*/ true); + } const kind = getAssignmentDeclarationKind(expression); - return kind === AssignmentDeclarationKind.ExportsProperty || kind === AssignmentDeclarationKind.ModuleExports; + return kind === AssignmentDeclarationKind.ExportsProperty + || kind === AssignmentDeclarationKind.ModuleExports; } default: return false; @@ -160,7 +205,9 @@ function importNameForConvertToDefaultImport(node: AnyValidImportOrReExport): Id switch (node.kind) { case SyntaxKind.ImportDeclaration: const { importClause, moduleSpecifier } = node; - return importClause && !importClause.name && importClause.namedBindings && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(moduleSpecifier) + return importClause && !importClause.name && importClause.namedBindings + && importClause.namedBindings.kind === SyntaxKind.NamespaceImport + && isStringLiteral(moduleSpecifier) ? importClause.namedBindings.name : undefined; case SyntaxKind.ImportEqualsDeclaration: @@ -170,21 +217,27 @@ function importNameForConvertToDefaultImport(node: AnyValidImportOrReExport): Id } } -function addConvertToAsyncFunctionDiagnostics(node: FunctionLikeDeclaration, checker: TypeChecker, diags: DiagnosticWithLocation[]): void { +function addConvertToAsyncFunctionDiagnostics( + node: FunctionLikeDeclaration, + checker: TypeChecker, + diags: DiagnosticWithLocation[], +): void { // need to check function before checking map so that deeper levels of nested callbacks are checked if (isConvertibleFunction(node, checker) && !visitedNestedConvertibleFunctions.has(getKeyFromNode(node))) { diags.push(createDiagnosticForNode( - !node.name && isVariableDeclaration(node.parent) && isIdentifier(node.parent.name) ? node.parent.name : node, - Diagnostics.This_may_be_converted_to_an_async_function)); + !node.name && isVariableDeclaration(node.parent) && isIdentifier(node.parent.name) ? node.parent.name + : node, + Diagnostics.This_may_be_converted_to_an_async_function, + )); } } function isConvertibleFunction(node: FunctionLikeDeclaration, checker: TypeChecker) { - return !isAsyncFunction(node) && - node.body && - isBlock(node.body) && - hasReturnStatementWithPromiseHandler(node.body, checker) && - returnsPromise(node, checker); + return !isAsyncFunction(node) + && node.body + && isBlock(node.body) + && hasReturnStatementWithPromiseHandler(node.body, checker) + && returnsPromise(node, checker); } /** @internal */ @@ -203,7 +256,10 @@ function hasReturnStatementWithPromiseHandler(body: Block, checker: TypeChecker) } /** @internal */ -export function isReturnStatementWithFixablePromiseHandler(node: Node, checker: TypeChecker): node is ReturnStatement & { expression: CallExpression } { +export function isReturnStatementWithFixablePromiseHandler( + node: Node, + checker: TypeChecker, +): node is ReturnStatement & { expression: CallExpression; } { return isReturnStatement(node) && !!node.expression && isFixablePromiseHandler(node.expression, checker); } @@ -211,7 +267,10 @@ export function isReturnStatementWithFixablePromiseHandler(node: Node, checker: /** @internal */ export function isFixablePromiseHandler(node: Node, checker: TypeChecker): boolean { // ensure outermost call exists and is a promise handler - if (!isPromiseHandler(node) || !hasSupportedNumberOfArguments(node) || !node.arguments.every(arg => isFixablePromiseArgument(arg, checker))) { + if ( + !isPromiseHandler(node) || !hasSupportedNumberOfArguments(node) + || !node.arguments.every(arg => isFixablePromiseArgument(arg, checker)) + ) { return false; } @@ -219,7 +278,10 @@ export function isFixablePromiseHandler(node: Node, checker: TypeChecker): boole let currentNode = node.expression.expression; while (isPromiseHandler(currentNode) || isPropertyAccessExpression(currentNode)) { if (isCallExpression(currentNode)) { - if (!hasSupportedNumberOfArguments(currentNode) || !currentNode.arguments.every(arg => isFixablePromiseArgument(arg, checker))) { + if ( + !hasSupportedNumberOfArguments(currentNode) + || !currentNode.arguments.every(arg => isFixablePromiseArgument(arg, checker)) + ) { return false; } currentNode = currentNode.expression.expression; @@ -231,14 +293,15 @@ export function isFixablePromiseHandler(node: Node, checker: TypeChecker): boole return true; } -function isPromiseHandler(node: Node): node is CallExpression & { readonly expression: PropertyAccessExpression } { +function isPromiseHandler(node: Node): node is CallExpression & { readonly expression: PropertyAccessExpression; } { return isCallExpression(node) && ( - hasPropertyAccessExpressionWithName(node, "then") || - hasPropertyAccessExpressionWithName(node, "catch") || - hasPropertyAccessExpressionWithName(node, "finally")); + hasPropertyAccessExpressionWithName(node, "then") + || hasPropertyAccessExpressionWithName(node, "catch") + || hasPropertyAccessExpressionWithName(node, "finally") + ); } -function hasSupportedNumberOfArguments(node: CallExpression & { readonly expression: PropertyAccessExpression }) { +function hasSupportedNumberOfArguments(node: CallExpression & { readonly expression: PropertyAccessExpression; }) { const name = node.expression.name.text; const maxArguments = name === "then" ? 2 : name === "catch" ? 1 : name === "finally" ? 1 : 0; if (node.arguments.length > maxArguments) return false; @@ -269,8 +332,11 @@ function isFixablePromiseArgument(arg: Expression, checker: TypeChecker): boolea if (!symbol) { return false; } - return checker.isUndefinedSymbol(symbol) || - some(skipAlias(symbol, checker).declarations, d => isFunctionLike(d) || hasInitializer(d) && !!d.initializer && isFunctionLike(d.initializer)); + return checker.isUndefinedSymbol(symbol) + || some( + skipAlias(symbol, checker).declarations, + d => isFunctionLike(d) || hasInitializer(d) && !!d.initializer && isFunctionLike(d.initializer), + ); } default: return false; @@ -299,7 +365,9 @@ function canBeConvertedToClass(node: Node, checker: TypeChecker): boolean { } /** @internal */ -export function canBeConvertedToAsync(node: Node): node is FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction { +export function canBeConvertedToAsync( + node: Node, +): node is FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction { switch (node.kind) { case SyntaxKind.FunctionDeclaration: case SyntaxKind.MethodDeclaration: diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index e77a2647f4884..3932953d5a503 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -110,7 +110,8 @@ import { VariableDeclaration, } from "./_namespaces/ts"; -const symbolDisplayNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; +const symbolDisplayNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors + | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope; // TODO(drosen): use contextual SemanticMeaning. /** @internal */ @@ -122,8 +123,8 @@ export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location const flags = getCombinedLocalAndExportSymbolFlags(symbol); if (flags & SymbolFlags.Class) { - return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ? - ScriptElementKind.localClassElement : ScriptElementKind.classElement; + return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) + ? ScriptElementKind.localClassElement : ScriptElementKind.classElement; } if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement; if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement; @@ -136,13 +137,19 @@ export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location return result; } -function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind { +function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar( + typeChecker: TypeChecker, + symbol: Symbol, + location: Node, +): ScriptElementKind { const roots = typeChecker.getRootSymbols(symbol); // If this is a method from a mapped type, leave as a method so long as it still has a call signature. - if (roots.length === 1 + if ( + roots.length === 1 && first(roots).flags & SymbolFlags.Method // Ensure the mapped version is still a method, as opposed to `{ [K in keyof I]: number }`. - && typeChecker.getTypeOfSymbolAtLocation(symbol, location).getNonNullableType().getCallSignatures().length !== 0) { + && typeChecker.getTypeOfSymbolAtLocation(symbol, location).getNonNullableType().getCallSignatures().length !== 0 + ) { return ScriptElementKind.memberFunctionElement; } @@ -172,9 +179,13 @@ function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeCheck else if (forEach(symbol.declarations, isLet)) { return ScriptElementKind.letElement; } - return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement; + return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement + : ScriptElementKind.variableElement; + } + if (flags & SymbolFlags.Function) { + return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement + : ScriptElementKind.functionElement; } - if (flags & SymbolFlags.Function) return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localFunctionElement : ScriptElementKind.functionElement; // FIXME: getter and setter use the same symbol. And it is rare to use only setter without getter, so in most cases the symbol always has getter flag. // So, even when the location is just on the declaration of setter, this function returns getter. if (flags & SymbolFlags.GetAccessor) return ScriptElementKind.memberGetAccessorElement; @@ -214,7 +225,8 @@ function getNormalizedSymbolModifiers(symbol: Symbol) { if (symbol.declarations && symbol.declarations.length) { const [declaration, ...declarations] = symbol.declarations; // omit deprecated flag if some declarations are not deprecated - const excludeFlags = length(declarations) && isDeprecatedDeclaration(declaration) && some(declarations, d => !isDeprecatedDeclaration(d)) + const excludeFlags = length(declarations) && isDeprecatedDeclaration(declaration) && some(declarations, d => + !isDeprecatedDeclaration(d)) ? ModifierFlags.Deprecated : ModifierFlags.None; const modifiers = getNodeModifiers(declaration, excludeFlags); @@ -254,30 +266,54 @@ export interface SymbolDisplayPartsDocumentationAndSymbolKind { tags: JSDocTagInfo[] | undefined; } -function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: TypeChecker, symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node | undefined, - location: Node, type: Type | undefined, semanticMeaning: SemanticMeaning, alias?: Symbol): SymbolDisplayPartsDocumentationAndSymbolKind { +function getSymbolDisplayPartsDocumentationAndSymbolKindWorker( + typeChecker: TypeChecker, + symbol: Symbol, + sourceFile: SourceFile, + enclosingDeclaration: Node | undefined, + location: Node, + type: Type | undefined, + semanticMeaning: SemanticMeaning, + alias?: Symbol, +): SymbolDisplayPartsDocumentationAndSymbolKind { const displayParts: SymbolDisplayPart[] = []; let documentation: SymbolDisplayPart[] = []; let tags: JSDocTagInfo[] = []; const symbolFlags = getCombinedLocalAndExportSymbolFlags(symbol); - let symbolKind = semanticMeaning & SemanticMeaning.Value ? getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location) : ScriptElementKind.unknown; + let symbolKind = semanticMeaning & SemanticMeaning.Value + ? getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location) + : ScriptElementKind.unknown; let hasAddedSymbolInfo = false; - const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isInExpressionContext(location) || isThisInTypeQuery(location); + const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isInExpressionContext(location) + || isThisInTypeQuery(location); let documentationFromAlias: SymbolDisplayPart[] | undefined; let tagsFromAlias: JSDocTagInfo[] | undefined; let hasMultipleSignatures = false; if (location.kind === SyntaxKind.ThisKeyword && !isThisExpression) { - return { displayParts: [keywordPart(SyntaxKind.ThisKeyword)], documentation: [], symbolKind: ScriptElementKind.primitiveType, tags: undefined }; + return { + displayParts: [keywordPart(SyntaxKind.ThisKeyword)], + documentation: [], + symbolKind: ScriptElementKind.primitiveType, + tags: undefined, + }; } // Class at constructor site need to be shown as constructor apart from property,method, vars - if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Alias) { + if ( + symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Alias + ) { // If symbol is accessor, they are allowed only if location is at declaration identifier of the accessor - if (symbolKind === ScriptElementKind.memberGetAccessorElement || symbolKind === ScriptElementKind.memberSetAccessorElement) { - const declaration = find(symbol.declarations as ((GetAccessorDeclaration | SetAccessorDeclaration | PropertyDeclaration)[]), declaration => declaration.name === location); + if ( + symbolKind === ScriptElementKind.memberGetAccessorElement + || symbolKind === ScriptElementKind.memberSetAccessorElement + ) { + const declaration = find( + symbol.declarations as ((GetAccessorDeclaration | SetAccessorDeclaration | PropertyDeclaration)[]), + declaration => declaration.name === location, + ); if (declaration) { - switch(declaration.kind){ + switch (declaration.kind) { case SyntaxKind.GetAccessor: symbolKind = ScriptElementKind.memberGetAccessorElement; break; @@ -289,7 +325,7 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type break; default: Debug.assertNever(declaration); - } + } } else { symbolKind = ScriptElementKind.memberVariableElement; @@ -297,7 +333,8 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type } let signature: Signature | undefined; - type ??= isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol, location); + type ??= isThisExpression ? typeChecker.getTypeAtLocation(location) + : typeChecker.getTypeOfSymbolAtLocation(symbol, location); if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) { const right = (location.parent as PropertyAccessExpression).name; @@ -308,21 +345,31 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type } // try get the call/construct signature from the type if it matches - let callExpressionLike: CallExpression | NewExpression | JsxOpeningLikeElement | TaggedTemplateExpression | undefined; + let callExpressionLike: + | CallExpression + | NewExpression + | JsxOpeningLikeElement + | TaggedTemplateExpression + | undefined; if (isCallOrNewExpression(location)) { callExpressionLike = location; } else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) { callExpressionLike = location.parent as CallExpression | NewExpression; } - else if (location.parent && (isJsxOpeningLikeElement(location.parent) || isTaggedTemplateExpression(location.parent)) && isFunctionLike(symbol.valueDeclaration)) { + else if ( + location.parent && (isJsxOpeningLikeElement(location.parent) || isTaggedTemplateExpression(location.parent)) + && isFunctionLike(symbol.valueDeclaration) + ) { callExpressionLike = location.parent; } if (callExpressionLike) { signature = typeChecker.getResolvedSignature(callExpressionLike); // TODO: GH#18217 - const useConstructSignatures = callExpressionLike.kind === SyntaxKind.NewExpression || (isCallExpression(callExpressionLike) && callExpressionLike.expression.kind === SyntaxKind.SuperKeyword); + const useConstructSignatures = callExpressionLike.kind === SyntaxKind.NewExpression + || (isCallExpression(callExpressionLike) + && callExpressionLike.expression.kind === SyntaxKind.SuperKeyword); const allSignatures = useConstructSignatures ? type.getConstructSignatures() : type.getCallSignatures(); @@ -368,7 +415,17 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type displayParts.push(punctuationPart(SyntaxKind.ColonToken)); displayParts.push(spacePart()); if (!(getObjectFlags(type) & ObjectFlags.Anonymous) && type.symbol) { - addRange(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.AllowAnyNodeKind | SymbolFormatFlags.WriteTypeParametersOrArguments)); + addRange( + displayParts, + symbolToDisplayParts( + typeChecker, + type.symbol, + enclosingDeclaration, + /*meaning*/ undefined, + SymbolFormatFlags.AllowAnyNodeKind + | SymbolFormatFlags.WriteTypeParametersOrArguments, + ), + ); displayParts.push(lineBreakPart()); } if (useConstructSignatures) { @@ -390,16 +447,23 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type hasMultipleSignatures = allSignatures.length > 1; } } - else if ((isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) || // name of function declaration - (location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor)) { // At constructor keyword of constructor declaration + else if ( + (isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) // name of function declaration + || (location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor) + ) { // At constructor keyword of constructor declaration // get the signature from the declaration and write it const functionDeclaration = location.parent as SignatureDeclaration; // Use function declaration to write the signatures only if the symbol corresponding to this declaration - const locationIsSymbolDeclaration = symbol.declarations && find(symbol.declarations, declaration => - declaration === (location.kind === SyntaxKind.ConstructorKeyword ? functionDeclaration.parent : functionDeclaration)); + const locationIsSymbolDeclaration = symbol.declarations + && find(symbol.declarations, declaration => + declaration + === (location.kind === SyntaxKind.ConstructorKeyword ? functionDeclaration.parent + : functionDeclaration)); if (locationIsSymbolDeclaration) { - const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getNonNullableType().getConstructSignatures() : type.getNonNullableType().getCallSignatures(); + const allSignatures = functionDeclaration.kind === SyntaxKind.Constructor + ? type.getNonNullableType().getConstructSignatures() + : type.getNonNullableType().getCallSignatures(); if (!typeChecker.isImplementationOfOverload(functionDeclaration)) { signature = typeChecker.getSignatureFromDeclaration(functionDeclaration); // TODO: GH#18217 } @@ -414,8 +478,12 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type } else { // (function/method) symbol(..signature) - addPrefixForAnyFunctionOrVar(functionDeclaration.kind === SyntaxKind.CallSignature && - !(type.symbol.flags & SymbolFlags.TypeLiteral || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, symbolKind); + addPrefixForAnyFunctionOrVar( + functionDeclaration.kind === SyntaxKind.CallSignature + && !(type.symbol.flags & SymbolFlags.TypeLiteral + || type.symbol.flags & SymbolFlags.ObjectLiteral) ? type.symbol : symbol, + symbolKind, + ); } if (signature) { addSignatureDisplayParts(signature, allSignatures); @@ -457,7 +525,16 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - addRange(displayParts, typeToDisplayParts(typeChecker, location.parent && isConstTypeReference(location.parent) ? typeChecker.getTypeAtLocation(location.parent) : typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration, TypeFormatFlags.InTypeAlias)); + addRange( + displayParts, + typeToDisplayParts( + typeChecker, + location.parent && isConstTypeReference(location.parent) + ? typeChecker.getTypeAtLocation(location.parent) : typeChecker.getDeclaredTypeOfSymbol(symbol), + enclosingDeclaration, + TypeFormatFlags.InTypeAlias, + ), + ); } if (symbolFlags & SymbolFlags.Enum) { prefixNextMeaning(); @@ -507,7 +584,15 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type else if (declaration.kind !== SyntaxKind.CallSignature && declaration.name) { addFullSymbolName(declaration.symbol); } - addRange(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); + addRange( + displayParts, + signatureToDisplayParts( + typeChecker, + signature, + sourceFile, + TypeFormatFlags.WriteTypeArgumentsOfSignature, + ), + ); } else if (isTypeAliasDeclaration(declaration)) { // Type alias type parameter @@ -532,8 +617,13 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - displayParts.push(displayPart(getTextOfConstantValue(constantValue), - typeof constantValue === "number" ? SymbolDisplayPartKind.numericLiteral : SymbolDisplayPartKind.stringLiteral)); + displayParts.push( + displayPart( + getTextOfConstantValue(constantValue), + typeof constantValue === "number" ? SymbolDisplayPartKind.numericLiteral + : SymbolDisplayPartKind.stringLiteral, + ), + ); } } } @@ -546,9 +636,8 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type const resolvedNode = resolvedSymbol.declarations[0]; const declarationName = getNameOfDeclaration(resolvedNode); if (declarationName && !hasAddedSymbolInfo) { - const isExternalModuleDeclaration = - isModuleWithStringLiteralName(resolvedNode) && - hasSyntacticModifier(resolvedNode, ModifierFlags.Ambient); + const isExternalModuleDeclaration = isModuleWithStringLiteralName(resolvedNode) + && hasSyntacticModifier(resolvedNode, ModifierFlags.Ambient); const shouldUseAliasName = symbol.name !== "default" && !isExternalModuleDeclaration; const resolvedInfo = getSymbolDisplayPartsDocumentationAndSymbolKindWorker( typeChecker, @@ -558,14 +647,18 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type declarationName, type, semanticMeaning, - shouldUseAliasName ? symbol : resolvedSymbol); + shouldUseAliasName ? symbol : resolvedSymbol, + ); displayParts.push(...resolvedInfo.displayParts); displayParts.push(lineBreakPart()); documentationFromAlias = resolvedInfo.documentation; tagsFromAlias = resolvedInfo.tags; } else { - documentationFromAlias = resolvedSymbol.getContextualDocumentationComment(resolvedNode, typeChecker); + documentationFromAlias = resolvedSymbol.getContextualDocumentationComment( + resolvedNode, + typeChecker, + ); tagsFromAlias = resolvedSymbol.getJsDocTags(typeChecker); } } @@ -581,7 +674,12 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type case SyntaxKind.ExportAssignment: displayParts.push(keywordPart(SyntaxKind.ExportKeyword)); displayParts.push(spacePart()); - displayParts.push(keywordPart((symbol.declarations[0] as ExportAssignment).isExportEquals ? SyntaxKind.EqualsToken : SyntaxKind.DefaultKeyword)); + displayParts.push( + keywordPart( + (symbol.declarations[0] as ExportAssignment).isExportEquals ? SyntaxKind.EqualsToken + : SyntaxKind.DefaultKeyword, + ), + ); break; case SyntaxKind.ExportSpecifier: displayParts.push(keywordPart(SyntaxKind.ExportKeyword)); @@ -601,11 +699,18 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type displayParts.push(spacePart()); displayParts.push(keywordPart(SyntaxKind.RequireKeyword)); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); - displayParts.push(displayPart(getTextOfNode(getExternalModuleImportEqualsDeclarationExpression(importEqualsDeclaration)), SymbolDisplayPartKind.stringLiteral)); + displayParts.push( + displayPart( + getTextOfNode(getExternalModuleImportEqualsDeclarationExpression(importEqualsDeclaration)), + SymbolDisplayPartKind.stringLiteral, + ), + ); displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); } else { - const internalAliasSymbol = typeChecker.getSymbolAtLocation(importEqualsDeclaration.moduleReference); + const internalAliasSymbol = typeChecker.getSymbolAtLocation( + importEqualsDeclaration.moduleReference, + ); if (internalAliasSymbol) { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); @@ -628,31 +733,48 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type addPrefixForAnyFunctionOrVar(symbol, symbolKind); } // For properties, variables and local vars: show the type - if (symbolKind === ScriptElementKind.memberVariableElement || - symbolKind === ScriptElementKind.memberAccessorVariableElement || - symbolKind === ScriptElementKind.memberGetAccessorElement || - symbolKind === ScriptElementKind.memberSetAccessorElement || - symbolKind === ScriptElementKind.jsxAttribute || - symbolFlags & SymbolFlags.Variable || - symbolKind === ScriptElementKind.localVariableElement || - symbolKind === ScriptElementKind.indexSignatureElement || - symbolKind === ScriptElementKind.variableUsingElement || - symbolKind === ScriptElementKind.variableAwaitUsingElement || - isThisExpression) { + if ( + symbolKind === ScriptElementKind.memberVariableElement + || symbolKind === ScriptElementKind.memberAccessorVariableElement + || symbolKind === ScriptElementKind.memberGetAccessorElement + || symbolKind === ScriptElementKind.memberSetAccessorElement + || symbolKind === ScriptElementKind.jsxAttribute + || symbolFlags & SymbolFlags.Variable + || symbolKind === ScriptElementKind.localVariableElement + || symbolKind === ScriptElementKind.indexSignatureElement + || symbolKind === ScriptElementKind.variableUsingElement + || symbolKind === ScriptElementKind.variableAwaitUsingElement + || isThisExpression + ) { displayParts.push(punctuationPart(SyntaxKind.ColonToken)); displayParts.push(spacePart()); // If the type is type parameter, format it specially - if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter && symbolKind !== ScriptElementKind.indexSignatureElement) { + if ( + type.symbol && type.symbol.flags & SymbolFlags.TypeParameter + && symbolKind !== ScriptElementKind.indexSignatureElement + ) { const typeParameterParts = mapToDisplayParts(writer => { - const param = typeChecker.typeParameterToDeclaration(type as TypeParameter, enclosingDeclaration, symbolDisplayNodeBuilderFlags)!; - getPrinter().writeNode(EmitHint.Unspecified, param, getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), writer); + const param = typeChecker.typeParameterToDeclaration( + type as TypeParameter, + enclosingDeclaration, + symbolDisplayNodeBuilderFlags, + )!; + getPrinter().writeNode( + EmitHint.Unspecified, + param, + getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), + writer, + ); }); addRange(displayParts, typeParameterParts); } else { addRange(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration)); } - if (isTransientSymbol(symbol) && symbol.links.target && isTransientSymbol(symbol.links.target) && symbol.links.target.links.tupleLabelDeclaration) { + if ( + isTransientSymbol(symbol) && symbol.links.target && isTransientSymbol(symbol.links.target) + && symbol.links.target.links.tupleLabelDeclaration + ) { const labelDecl = symbol.links.target.links.tupleLabelDeclaration; Debug.assertNode(labelDecl.name, isIdentifier); displayParts.push(spacePart()); @@ -661,12 +783,14 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); } } - else if (symbolFlags & SymbolFlags.Function || - symbolFlags & SymbolFlags.Method || - symbolFlags & SymbolFlags.Constructor || - symbolFlags & SymbolFlags.Signature || - symbolFlags & SymbolFlags.Accessor || - symbolKind === ScriptElementKind.memberFunctionElement) { + else if ( + symbolFlags & SymbolFlags.Function + || symbolFlags & SymbolFlags.Method + || symbolFlags & SymbolFlags.Constructor + || symbolFlags & SymbolFlags.Signature + || symbolFlags & SymbolFlags.Accessor + || symbolKind === ScriptElementKind.memberFunctionElement + ) { const allSignatures = type.getNonNullableType().getCallSignatures(); if (allSignatures.length) { addSignatureDisplayParts(allSignatures[0], allSignatures); @@ -688,7 +812,10 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type // For some special property access expressions like `exports.foo = foo` or `module.exports.foo = foo` // there documentation comments might be attached to the right hand side symbol of their declarations. // The pattern of such special property access is that the parent symbol is the symbol of the file. - if (symbol.parent && symbol.declarations && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile)) { + if ( + symbol.parent && symbol.declarations + && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile) + ) { for (const declaration of symbol.declarations) { if (!declaration.parent || declaration.parent.kind !== SyntaxKind.BinaryExpression) { continue; @@ -708,7 +835,10 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type } } - if (documentation.length === 0 && isIdentifier(location) && symbol.valueDeclaration && isBindingElement(symbol.valueDeclaration)) { + if ( + documentation.length === 0 && isIdentifier(location) && symbol.valueDeclaration + && isBindingElement(symbol.valueDeclaration) + ) { const declaration = symbol.valueDeclaration; const parent = declaration.parent; if (isIdentifier(declaration.name) && isObjectBindingPattern(parent)) { @@ -775,9 +905,9 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay.parent); } fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.OpenBracketToken)); - //Needed to handle more than one type of index + // Needed to handle more than one type of index indexInfos.forEach((info, i) => { - //Needed to handle template literals + // Needed to handle template literals fullSymbolDisplayParts.push(...typeToDisplayParts(typeChecker, info.keyType)); if (i !== indexInfos.length - 1) { fullSymbolDisplayParts.push(spacePart()); @@ -788,8 +918,14 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type fullSymbolDisplayParts.push(punctuationPart(SyntaxKind.CloseBracketToken)); } else { - fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbolToDisplay, enclosingDeclaration || sourceFile, /*meaning*/ undefined, - SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing | SymbolFormatFlags.AllowAnyNodeKind); + fullSymbolDisplayParts = symbolToDisplayParts( + typeChecker, + symbolToDisplay, + enclosingDeclaration || sourceFile, + /*meaning*/ undefined, + SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing + | SymbolFormatFlags.AllowAnyNodeKind, + ); } addRange(displayParts, fullSymbolDisplayParts); if (symbol.flags & SymbolFlags.Optional) { @@ -801,7 +937,13 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type prefixNextMeaning(); if (symbolKind) { pushSymbolKind(symbolKind); - if (symbol && !some(symbol.declarations, d => isArrowFunction(d) || (isFunctionExpression(d) || isClassExpression(d)) && !d.name)) { + if ( + symbol + && !some( + symbol.declarations, + d => isArrowFunction(d) || (isFunctionExpression(d) || isClassExpression(d)) && !d.name, + ) + ) { displayParts.push(spacePart()); addFullSymbolName(symbol); } @@ -827,8 +969,20 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type } } - function addSignatureDisplayParts(signature: Signature, allSignatures: readonly Signature[], flags = TypeFormatFlags.None) { - addRange(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); + function addSignatureDisplayParts( + signature: Signature, + allSignatures: readonly Signature[], + flags = TypeFormatFlags.None, + ) { + addRange( + displayParts, + signatureToDisplayParts( + typeChecker, + signature, + enclosingDeclaration, + flags | TypeFormatFlags.WriteTypeArgumentsOfSignature, + ), + ); if (allSignatures.length > 1) { displayParts.push(spacePart()); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); @@ -849,8 +1003,17 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node | undefined) { const typeParameterParts = mapToDisplayParts(writer => { - const params = typeChecker.symbolToTypeParameterDeclarations(symbol, enclosingDeclaration, symbolDisplayNodeBuilderFlags); - getPrinter().writeList(ListFormat.TypeParameters, params, getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), writer); + const params = typeChecker.symbolToTypeParameterDeclarations( + symbol, + enclosingDeclaration, + symbolDisplayNodeBuilderFlags, + ); + getPrinter().writeList( + ListFormat.TypeParameters, + params, + getSourceFileOfNode(getParseTreeNode(enclosingDeclaration)), + writer, + ); }); addRange(displayParts, typeParameterParts); } @@ -858,9 +1021,25 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location /** @internal */ -export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: TypeChecker, symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node | undefined, - location: Node, semanticMeaning = getMeaningFromLocation(location), alias?: Symbol): SymbolDisplayPartsDocumentationAndSymbolKind { - return getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker, symbol, sourceFile, enclosingDeclaration, location, /*type*/ undefined, semanticMeaning, alias); +export function getSymbolDisplayPartsDocumentationAndSymbolKind( + typeChecker: TypeChecker, + symbol: Symbol, + sourceFile: SourceFile, + enclosingDeclaration: Node | undefined, + location: Node, + semanticMeaning = getMeaningFromLocation(location), + alias?: Symbol, +): SymbolDisplayPartsDocumentationAndSymbolKind { + return getSymbolDisplayPartsDocumentationAndSymbolKindWorker( + typeChecker, + symbol, + sourceFile, + enclosingDeclaration, + location, + /*type*/ undefined, + semanticMeaning, + alias, + ); } function isLocalVariableOrFunction(symbol: Symbol) { @@ -874,7 +1053,9 @@ function isLocalVariableOrFunction(symbol: Symbol) { return true; } - if (declaration.kind !== SyntaxKind.VariableDeclaration && declaration.kind !== SyntaxKind.FunctionDeclaration) { + if ( + declaration.kind !== SyntaxKind.VariableDeclaration && declaration.kind !== SyntaxKind.FunctionDeclaration + ) { return false; } diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index fbfdba0f59bc3..8954ba8bbe821 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -346,11 +346,24 @@ interface NewFileInsertion { readonly statements: readonly (Statement | SyntaxKind.NewLineTrivia)[]; } -function getAdjustedRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd): TextRange { - return { pos: getAdjustedStartPosition(sourceFile, startNode, options), end: getAdjustedEndPosition(sourceFile, endNode, options) }; +function getAdjustedRange( + sourceFile: SourceFile, + startNode: Node, + endNode: Node, + options: ConfigurableStartEnd, +): TextRange { + return { + pos: getAdjustedStartPosition(sourceFile, startNode, options), + end: getAdjustedEndPosition(sourceFile, endNode, options), + }; } -function getAdjustedStartPosition(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd, hasTrailingComment = false) { +function getAdjustedStartPosition( + sourceFile: SourceFile, + node: Node, + options: ConfigurableStartEnd, + hasTrailingComment = false, +) { const { leadingTriviaOption } = options; if (leadingTriviaOption === LeadingTriviaOption.Exclude) { return node.getStart(sourceFile); @@ -388,7 +401,8 @@ function getAdjustedStartPosition(sourceFile: SourceFile, node: Node, options: C if (hasTrailingComment) { // Check first for leading comments as if the node is the first import, we want to exclude the trivia; // otherwise we get the trailing comments. - const comment = getLeadingCommentRanges(sourceFile.text, fullStart)?.[0] || getTrailingCommentRanges(sourceFile.text, fullStart)?.[0]; + const comment = getLeadingCommentRanges(sourceFile.text, fullStart)?.[0] + || getTrailingCommentRanges(sourceFile.text, fullStart)?.[0]; if (comment) { return skipTrivia(sourceFile.text, comment.end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ true); } @@ -397,14 +411,21 @@ function getAdjustedStartPosition(sourceFile: SourceFile, node: Node, options: C // get start position of the line following the line that contains fullstart position // (but only if the fullstart isn't the very beginning of the file) const nextLineStart = fullStart > 0 ? 1 : 0; - let adjustedStartPosition = getStartPositionOfLine(getLineOfLocalPosition(sourceFile, fullStartLine) + nextLineStart, sourceFile); + let adjustedStartPosition = getStartPositionOfLine( + getLineOfLocalPosition(sourceFile, fullStartLine) + nextLineStart, + sourceFile, + ); // skip whitespaces/newlines adjustedStartPosition = skipWhitespacesAndLineBreaks(sourceFile.text, adjustedStartPosition); return getStartPositionOfLine(getLineOfLocalPosition(sourceFile, adjustedStartPosition), sourceFile); } /** Return the end position of a multiline comment of it is on another line; otherwise returns `undefined`; */ -function getEndPositionOfMultilineTrailingComment(sourceFile: SourceFile, node: Node, options: ConfigurableEnd): number | undefined { +function getEndPositionOfMultilineTrailingComment( + sourceFile: SourceFile, + node: Node, + options: ConfigurableEnd, +): number | undefined { const { end } = node; const { trailingTriviaOption } = options; if (trailingTriviaOption === TrailingTriviaOption.Include) { @@ -416,7 +437,10 @@ function getEndPositionOfMultilineTrailingComment(sourceFile: SourceFile, node: for (const comment of comments) { // Single line can break the loop as trivia will only be this line. // Comments on subsequest lines are also ignored. - if (comment.kind === SyntaxKind.SingleLineCommentTrivia || getLineOfLocalPosition(sourceFile, comment.pos) > nodeEndLine) { + if ( + comment.kind === SyntaxKind.SingleLineCommentTrivia + || getLineOfLocalPosition(sourceFile, comment.pos) > nodeEndLine + ) { break; } @@ -425,7 +449,12 @@ function getEndPositionOfMultilineTrailingComment(sourceFile: SourceFile, node: // then is safe to return the end position. const commentEndLine = getLineOfLocalPosition(sourceFile, comment.end); if (commentEndLine > nodeEndLine) { - return skipTrivia(sourceFile.text, comment.end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ true); + return skipTrivia( + sourceFile.text, + comment.end, + /*stopAfterLineBreak*/ true, + /*stopAtComments*/ true, + ); } } } @@ -441,7 +470,10 @@ function getAdjustedEndPosition(sourceFile: SourceFile, node: Node, options: Con return end; } if (trailingTriviaOption === TrailingTriviaOption.ExcludeWhitespace) { - const comments = concatenate(getTrailingCommentRanges(sourceFile.text, end), getLeadingCommentRanges(sourceFile.text, end)); + const comments = concatenate( + getTrailingCommentRanges(sourceFile.text, end), + getLeadingCommentRanges(sourceFile.text, end), + ); const realEnd = comments?.[comments.length - 1]?.end; if (realEnd) { return realEnd; @@ -456,7 +488,9 @@ function getAdjustedEndPosition(sourceFile: SourceFile, node: Node, options: Con const newEnd = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true); - return newEnd !== end && (trailingTriviaOption === TrailingTriviaOption.Include || isLineBreak(sourceFile.text.charCodeAt(newEnd - 1))) + return newEnd !== end + && (trailingTriviaOption === TrailingTriviaOption.Include + || isLineBreak(sourceFile.text.charCodeAt(newEnd - 1))) ? newEnd : end; } @@ -464,8 +498,14 @@ function getAdjustedEndPosition(sourceFile: SourceFile, node: Node, options: Con /** * Checks if 'candidate' argument is a legal separator in the list that contains 'node' as an element */ -function isSeparator(node: Node, candidate: Node | undefined): candidate is Token { - return !!candidate && !!node.parent && (candidate.kind === SyntaxKind.CommaToken || (candidate.kind === SyntaxKind.SemicolonToken && node.parent.kind === SyntaxKind.ObjectLiteralExpression)); +function isSeparator( + node: Node, + candidate: Node | undefined, +): candidate is Token { + return !!candidate && !!node.parent + && (candidate.kind === SyntaxKind.CommaToken + || (candidate.kind === SyntaxKind.SemicolonToken + && node.parent.kind === SyntaxKind.ObjectLiteralExpression)); } /** @internal */ @@ -476,25 +516,44 @@ export interface TextChangesContext { } /** @internal */ -export type TypeAnnotatable = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature; +export type TypeAnnotatable = + | SignatureDeclaration + | VariableDeclaration + | ParameterDeclaration + | PropertyDeclaration + | PropertySignature; /** @internal */ export type ThisTypeAnnotatable = FunctionDeclaration | FunctionExpression; /** @internal */ -export function isThisTypeAnnotatable(containingFunction: SignatureDeclaration): containingFunction is ThisTypeAnnotatable { +export function isThisTypeAnnotatable( + containingFunction: SignatureDeclaration, +): containingFunction is ThisTypeAnnotatable { return isFunctionExpression(containingFunction) || isFunctionDeclaration(containingFunction); } /** @internal */ export class ChangeTracker { private readonly changes: Change[] = []; - private newFileChanges?: MultiMap ; - private readonly classesWithNodesInsertedAtStart = new Map(); // Set implemented as Map - private readonly deletedNodes: { readonly sourceFile: SourceFile, readonly node: Node | NodeArray }[] = []; + private newFileChanges?: MultiMap; + private readonly classesWithNodesInsertedAtStart = new Map< + number, + { + readonly node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression; + readonly sourceFile: SourceFile; + } + >(); // Set implemented as Map + private readonly deletedNodes: { + readonly sourceFile: SourceFile; + readonly node: Node | NodeArray; + }[] = []; public static fromContext(context: TextChangesContext): ChangeTracker { - return new ChangeTracker(getNewLineOrDefaultFromHost(context.host, context.formatContext.options), context.formatContext); + return new ChangeTracker( + getNewLineOrDefaultFromHost(context.host, context.formatContext.options), + context.formatContext, + ); } public static with(context: TextChangesContext, cb: (tracker: ChangeTracker) => void): FileTextChanges[] { @@ -527,11 +586,20 @@ export class ChangeTracker { } /** Stop! Consider using `delete` instead, which has logic for deleting nodes from delimited lists. */ - public deleteNode(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + public deleteNode( + sourceFile: SourceFile, + node: Node, + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + ): void { this.deleteRange(sourceFile, getAdjustedRange(sourceFile, node, node, options)); } - public deleteNodes(sourceFile: SourceFile, nodes: readonly Node[], options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, hasTrailingComment: boolean): void { + public deleteNodes( + sourceFile: SourceFile, + nodes: readonly Node[], + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + hasTrailingComment: boolean, + ): void { // When deleting multiple nodes we need to track if the end position is including multiline trailing comments. for (const node of nodes) { const pos = getAdjustedStartPosition(sourceFile, node, options, hasTrailingComment); @@ -544,50 +612,114 @@ export class ChangeTracker { } public deleteModifier(sourceFile: SourceFile, modifier: Modifier): void { - this.deleteRange(sourceFile, { pos: modifier.getStart(sourceFile), end: skipTrivia(sourceFile.text, modifier.end, /*stopAfterLineBreak*/ true) }); + this.deleteRange(sourceFile, { + pos: modifier.getStart(sourceFile), + end: skipTrivia(sourceFile.text, modifier.end, /*stopAfterLineBreak*/ true), + }); } - public deleteNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + public deleteNodeRange( + sourceFile: SourceFile, + startNode: Node, + endNode: Node, + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + ): void { const startPosition = getAdjustedStartPosition(sourceFile, startNode, options); const endPosition = getAdjustedEndPosition(sourceFile, endNode, options); this.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } - public deleteNodeRangeExcludingEnd(sourceFile: SourceFile, startNode: Node, afterEndNode: Node | undefined, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { + public deleteNodeRangeExcludingEnd( + sourceFile: SourceFile, + startNode: Node, + afterEndNode: Node | undefined, + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, + ): void { const startPosition = getAdjustedStartPosition(sourceFile, startNode, options); - const endPosition = afterEndNode === undefined ? sourceFile.text.length : getAdjustedStartPosition(sourceFile, afterEndNode, options); + const endPosition = afterEndNode === undefined ? sourceFile.text.length + : getAdjustedStartPosition(sourceFile, afterEndNode, options); this.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } - public replaceRange(sourceFile: SourceFile, range: TextRange, newNode: Node, options: InsertNodeOptions = {}): void { + public replaceRange( + sourceFile: SourceFile, + range: TextRange, + newNode: Node, + options: InsertNodeOptions = {}, + ): void { this.changes.push({ kind: ChangeKind.ReplaceWithSingleNode, sourceFile, range, options, node: newNode }); } - public replaceNode(sourceFile: SourceFile, oldNode: Node, newNode: Node, options: ChangeNodeOptions = useNonAdjustedPositions): void { + public replaceNode( + sourceFile: SourceFile, + oldNode: Node, + newNode: Node, + options: ChangeNodeOptions = useNonAdjustedPositions, + ): void { this.replaceRange(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, options), newNode, options); } - public replaceNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, newNode: Node, options: ChangeNodeOptions = useNonAdjustedPositions): void { + public replaceNodeRange( + sourceFile: SourceFile, + startNode: Node, + endNode: Node, + newNode: Node, + options: ChangeNodeOptions = useNonAdjustedPositions, + ): void { this.replaceRange(sourceFile, getAdjustedRange(sourceFile, startNode, endNode, options), newNode, options); } - private replaceRangeWithNodes(sourceFile: SourceFile, range: TextRange, newNodes: readonly Node[], options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = {}): void { + private replaceRangeWithNodes( + sourceFile: SourceFile, + range: TextRange, + newNodes: readonly Node[], + options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = {}, + ): void { this.changes.push({ kind: ChangeKind.ReplaceWithMultipleNodes, sourceFile, range, options, nodes: newNodes }); } - public replaceNodeWithNodes(sourceFile: SourceFile, oldNode: Node, newNodes: readonly Node[], options: ChangeNodeOptions = useNonAdjustedPositions): void { - this.replaceRangeWithNodes(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, options), newNodes, options); + public replaceNodeWithNodes( + sourceFile: SourceFile, + oldNode: Node, + newNodes: readonly Node[], + options: ChangeNodeOptions = useNonAdjustedPositions, + ): void { + this.replaceRangeWithNodes( + sourceFile, + getAdjustedRange(sourceFile, oldNode, oldNode, options), + newNodes, + options, + ); } public replaceNodeWithText(sourceFile: SourceFile, oldNode: Node, text: string): void { - this.replaceRangeWithText(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, useNonAdjustedPositions), text); - } - - public replaceNodeRangeWithNodes(sourceFile: SourceFile, startNode: Node, endNode: Node, newNodes: readonly Node[], options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = useNonAdjustedPositions): void { - this.replaceRangeWithNodes(sourceFile, getAdjustedRange(sourceFile, startNode, endNode, options), newNodes, options); + this.replaceRangeWithText( + sourceFile, + getAdjustedRange(sourceFile, oldNode, oldNode, useNonAdjustedPositions), + text, + ); } - public nodeHasTrailingComment(sourceFile: SourceFile, oldNode: Node, configurableEnd: ConfigurableEnd = useNonAdjustedPositions): boolean { + public replaceNodeRangeWithNodes( + sourceFile: SourceFile, + startNode: Node, + endNode: Node, + newNodes: readonly Node[], + options: ReplaceWithMultipleNodesOptions & ConfigurableStartEnd = useNonAdjustedPositions, + ): void { + this.replaceRangeWithNodes( + sourceFile, + getAdjustedRange(sourceFile, startNode, endNode, options), + newNodes, + options, + ); + } + + public nodeHasTrailingComment( + sourceFile: SourceFile, + oldNode: Node, + configurableEnd: ConfigurableEnd = useNonAdjustedPositions, + ): boolean { return !!getEndPositionOfMultilineTrailingComment(sourceFile, oldNode, configurableEnd); } @@ -596,7 +728,11 @@ export class ChangeTracker { return next && next.kind === SyntaxKind.CommaToken ? next : undefined; } - public replacePropertyAssignment(sourceFile: SourceFile, oldNode: PropertyAssignment, newNode: PropertyAssignment): void { + public replacePropertyAssignment( + sourceFile: SourceFile, + oldNode: PropertyAssignment, + newNode: PropertyAssignment, + ): void { const suffix = this.nextCommaToken(sourceFile, oldNode) ? "" : ("," + this.newLineCharacter); this.replaceNode(sourceFile, oldNode, newNode, { suffix }); } @@ -605,7 +741,12 @@ export class ChangeTracker { this.replaceRange(sourceFile, createRange(pos), newNode, options); } - private insertNodesAt(sourceFile: SourceFile, pos: number, newNodes: readonly Node[], options: ReplaceWithMultipleNodesOptions = {}): void { + private insertNodesAt( + sourceFile: SourceFile, + pos: number, + newNodes: readonly Node[], + options: ReplaceWithMultipleNodesOptions = {}, + ): void { this.replaceRangeWithNodes(sourceFile, createRange(pos), newNodes, options); } @@ -613,15 +754,24 @@ export class ChangeTracker { this.insertAtTopOfFile(sourceFile, newNode, blankLineBetween); } - public insertNodesAtTopOfFile(sourceFile: SourceFile, newNodes: readonly Statement[], blankLineBetween: boolean): void { + public insertNodesAtTopOfFile( + sourceFile: SourceFile, + newNodes: readonly Statement[], + blankLineBetween: boolean, + ): void { this.insertAtTopOfFile(sourceFile, newNodes, blankLineBetween); } - private insertAtTopOfFile(sourceFile: SourceFile, insert: Statement | readonly Statement[], blankLineBetween: boolean): void { + private insertAtTopOfFile( + sourceFile: SourceFile, + insert: Statement | readonly Statement[], + blankLineBetween: boolean, + ): void { const pos = getInsertionPositionAtSourceFileTop(sourceFile); const options = { prefix: pos === 0 ? undefined : this.newLineCharacter, - suffix: (isLineBreak(sourceFile.text.charCodeAt(pos)) ? "" : this.newLineCharacter) + (blankLineBetween ? this.newLineCharacter : ""), + suffix: (isLineBreak(sourceFile.text.charCodeAt(pos)) ? "" : this.newLineCharacter) + + (blankLineBetween ? this.newLineCharacter : ""), }; if (isArray(insert)) { this.insertNodesAt(sourceFile, pos, insert, options); @@ -634,14 +784,16 @@ export class ChangeTracker { public insertNodesAtEndOfFile( sourceFile: SourceFile, newNodes: readonly Statement[], - blankLineBetween: boolean): void { + blankLineBetween: boolean, + ): void { this.insertAtEndOfFile(sourceFile, newNodes, blankLineBetween); } private insertAtEndOfFile( sourceFile: SourceFile, insert: readonly Statement[], - blankLineBetween: boolean): void { + blankLineBetween: boolean, + ): void { const pos = sourceFile.end + 1; const options = { prefix: this.newLineCharacter, @@ -650,14 +802,22 @@ export class ChangeTracker { this.insertNodesAt(sourceFile, pos, insert, options); } - private insertStatementsInNewFile(fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], oldFile?: SourceFile): void { + private insertStatementsInNewFile( + fileName: string, + statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], + oldFile?: SourceFile, + ): void { if (!this.newFileChanges) { this.newFileChanges = createMultiMap(); } this.newFileChanges.add(fileName, { oldFile, statements }); } - public insertFirstParameter(sourceFile: SourceFile, parameters: NodeArray, newParam: ParameterDeclaration): void { + public insertFirstParameter( + sourceFile: SourceFile, + parameters: NodeArray, + newParam: ParameterDeclaration, + ): void { const p0 = firstOrUndefined(parameters); if (p0) { this.insertNodeBefore(sourceFile, p0, newParam); @@ -667,15 +827,42 @@ export class ChangeTracker { } } - public insertNodeBefore(sourceFile: SourceFile, before: Node, newNode: Node, blankLineBetween = false, options: ConfigurableStartEnd = {}): void { - this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, options), newNode, this.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween)); - } - - public insertNodesBefore(sourceFile: SourceFile, before: Node, newNodes: readonly Node[], blankLineBetween = false, options: ConfigurableStartEnd = {}): void { - this.insertNodesAt(sourceFile, getAdjustedStartPosition(sourceFile, before, options), newNodes, this.getOptionsForInsertNodeBefore(before, first(newNodes), blankLineBetween)); - } - - public insertModifierAt(sourceFile: SourceFile, pos: number, modifier: SyntaxKind, options: InsertNodeOptions = {}): void { + public insertNodeBefore( + sourceFile: SourceFile, + before: Node, + newNode: Node, + blankLineBetween = false, + options: ConfigurableStartEnd = {}, + ): void { + this.insertNodeAt( + sourceFile, + getAdjustedStartPosition(sourceFile, before, options), + newNode, + this.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween), + ); + } + + public insertNodesBefore( + sourceFile: SourceFile, + before: Node, + newNodes: readonly Node[], + blankLineBetween = false, + options: ConfigurableStartEnd = {}, + ): void { + this.insertNodesAt( + sourceFile, + getAdjustedStartPosition(sourceFile, before, options), + newNodes, + this.getOptionsForInsertNodeBefore(before, first(newNodes), blankLineBetween), + ); + } + + public insertModifierAt( + sourceFile: SourceFile, + pos: number, + modifier: SyntaxKind, + options: InsertNodeOptions = {}, + ): void { this.insertNodeAt(sourceFile, pos, factory.createToken(modifier), options); } @@ -683,7 +870,12 @@ export class ChangeTracker { return this.insertModifierAt(sourceFile, before.getStart(sourceFile), modifier, { suffix: " " }); } - public insertCommentBeforeLine(sourceFile: SourceFile, lineNumber: number, position: number, commentText: string): void { + public insertCommentBeforeLine( + sourceFile: SourceFile, + lineNumber: number, + position: number, + commentText: string, + ): void { const lineStartPosition = getStartPositionOfLine(lineNumber, sourceFile); const startPosition = getFirstNonSpaceCharacterPosition(sourceFile.text, lineStartPosition); // First try to see if we can put the comment on the previous line. @@ -693,7 +885,9 @@ export class ChangeTracker { const insertAtLineStart = isValidLocationToAddComment(sourceFile, startPosition); const token = getTouchingToken(sourceFile, insertAtLineStart ? startPosition : position); const indent = sourceFile.text.slice(lineStartPosition, startPosition); - const text = `${insertAtLineStart ? "" : this.newLineCharacter}//${commentText}${this.newLineCharacter}${indent}`; + const text = `${ + insertAtLineStart ? "" : this.newLineCharacter + }//${commentText}${this.newLineCharacter}${indent}`; this.insertText(sourceFile, token.getStart(sourceFile), text); } @@ -703,7 +897,7 @@ export class ChangeTracker { for (const jsdoc of node.jsDoc) { this.deleteRange(sourceFile, { pos: getLineStartPositionForPosition(jsdoc.getStart(sourceFile), sourceFile), - end: getAdjustedEndPosition(sourceFile, jsdoc, /*options*/ {}) + end: getAdjustedEndPosition(sourceFile, jsdoc, /*options*/ {}), }); } } @@ -713,24 +907,32 @@ export class ChangeTracker { } private createJSDocText(sourceFile: SourceFile, node: HasJSDoc) { - const comments = flatMap(node.jsDoc, jsDoc => - isString(jsDoc.comment) ? factory.createJSDocText(jsDoc.comment) : jsDoc.comment) as JSDocComment[]; + const comments = flatMap( + node.jsDoc, + jsDoc => isString(jsDoc.comment) ? factory.createJSDocText(jsDoc.comment) : jsDoc.comment, + ) as JSDocComment[]; const jsDoc = singleOrUndefined(node.jsDoc); - return jsDoc && positionsAreOnSameLine(jsDoc.pos, jsDoc.end, sourceFile) && length(comments) === 0 ? undefined : - factory.createNodeArray(intersperse(comments, factory.createJSDocText("\n"))); + return jsDoc && positionsAreOnSameLine(jsDoc.pos, jsDoc.end, sourceFile) && length(comments) === 0 ? undefined + : factory.createNodeArray(intersperse(comments, factory.createJSDocText("\n"))); } public replaceJSDocComment(sourceFile: SourceFile, node: HasJSDoc, tags: readonly JSDocTag[]) { - this.insertJsdocCommentBefore(sourceFile, updateJSDocHost(node), factory.createJSDocComment(this.createJSDocText(sourceFile, node), factory.createNodeArray(tags))); + this.insertJsdocCommentBefore( + sourceFile, + updateJSDocHost(node), + factory.createJSDocComment(this.createJSDocText(sourceFile, node), factory.createNodeArray(tags)), + ); } public addJSDocTags(sourceFile: SourceFile, parent: HasJSDoc, newTags: readonly JSDocTag[]): void { const oldTags = flatMapToMutable(parent.jsDoc, j => j.tags); - const unmergedNewTags = newTags.filter(newTag => !oldTags.some((tag, i) => { - const merged = tryMergeJsdocTags(tag, newTag); - if (merged) oldTags[i] = merged; - return !!merged; - })); + const unmergedNewTags = newTags.filter(newTag => + !oldTags.some((tag, i) => { + const merged = tryMergeJsdocTags(tag, newTag); + if (merged) oldTags[i] = merged; + return !!merged; + }) + ); this.replaceJSDocComment(sourceFile, parent, [...oldTags, ...unmergedNewTags]); } @@ -758,7 +960,8 @@ export class ChangeTracker { } } else { - endNode = (node.kind === SyntaxKind.VariableDeclaration ? node.exclamationToken : node.questionToken) ?? node.name; + endNode = (node.kind === SyntaxKind.VariableDeclaration ? node.exclamationToken : node.questionToken) + ?? node.name; } this.insertNodeAt(sourceFile, endNode.end, type, { prefix: ": " }); @@ -772,9 +975,15 @@ export class ChangeTracker { this.insertNodeAt(sourceFile, start, type, { prefix: "this: ", suffix }); } - public insertTypeParameters(sourceFile: SourceFile, node: SignatureDeclaration, typeParameters: readonly TypeParameterDeclaration[]): void { + public insertTypeParameters( + sourceFile: SourceFile, + node: SignatureDeclaration, + typeParameters: readonly TypeParameterDeclaration[], + ): void { // If no `(`, is an arrow function `x => x`, so use the pos of the first parameter - const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)).getStart(sourceFile); + const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)).getStart( + sourceFile, + ); this.insertNodesAt(sourceFile, start, typeParameters, { prefix: "<", suffix: ">", joiner: ", " }); } @@ -797,7 +1006,11 @@ export class ChangeTracker { return Debug.failBadSyntaxKind(before); // We haven't handled this kind of node yet -- add it } - public insertNodeAtConstructorStart(sourceFile: SourceFile, ctr: ConstructorDeclaration, newStatement: Statement): void { + public insertNodeAtConstructorStart( + sourceFile: SourceFile, + ctr: ConstructorDeclaration, + newStatement: Statement, + ): void { const firstStatement = firstOrUndefined(ctr.body!.statements); if (!firstStatement || !ctr.body!.multiLine) { this.replaceConstructorBody(sourceFile, ctr, [newStatement, ...ctr.body!.statements]); @@ -807,8 +1020,15 @@ export class ChangeTracker { } } - public insertNodeAtConstructorStartAfterSuperCall(sourceFile: SourceFile, ctr: ConstructorDeclaration, newStatement: Statement): void { - const superCallStatement = find(ctr.body!.statements, stmt => isExpressionStatement(stmt) && isSuperCall(stmt.expression)); + public insertNodeAtConstructorStartAfterSuperCall( + sourceFile: SourceFile, + ctr: ConstructorDeclaration, + newStatement: Statement, + ): void { + const superCallStatement = find( + ctr.body!.statements, + stmt => isExpressionStatement(stmt) && isSuperCall(stmt.expression), + ); if (!superCallStatement || !ctr.body!.multiLine) { this.replaceConstructorBody(sourceFile, ctr, [...ctr.body!.statements, newStatement]); } @@ -817,7 +1037,11 @@ export class ChangeTracker { } } - public insertNodeAtConstructorEnd(sourceFile: SourceFile, ctr: ConstructorDeclaration, newStatement: Statement): void { + public insertNodeAtConstructorEnd( + sourceFile: SourceFile, + ctr: ConstructorDeclaration, + newStatement: Statement, + ): void { const lastStatement = lastOrUndefined(ctr.body!.statements); if (!lastStatement || !ctr.body!.multiLine) { this.replaceConstructorBody(sourceFile, ctr, [...ctr.body!.statements, newStatement]); @@ -827,36 +1051,62 @@ export class ChangeTracker { } } - private replaceConstructorBody(sourceFile: SourceFile, ctr: ConstructorDeclaration, statements: readonly Statement[]): void { + private replaceConstructorBody( + sourceFile: SourceFile, + ctr: ConstructorDeclaration, + statements: readonly Statement[], + ): void { this.replaceNode(sourceFile, ctr.body!, factory.createBlock(statements, /*multiLine*/ true)); } public insertNodeAtEndOfScope(sourceFile: SourceFile, scope: Node, newNode: Node): void { const pos = getAdjustedStartPosition(sourceFile, scope.getLastToken()!, {}); this.insertNodeAt(sourceFile, pos, newNode, { - prefix: isLineBreak(sourceFile.text.charCodeAt(scope.getLastToken()!.pos)) ? this.newLineCharacter : this.newLineCharacter + this.newLineCharacter, - suffix: this.newLineCharacter + prefix: isLineBreak(sourceFile.text.charCodeAt(scope.getLastToken()!.pos)) ? this.newLineCharacter + : this.newLineCharacter + this.newLineCharacter, + suffix: this.newLineCharacter, }); } - public insertMemberAtStart(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, newElement: ClassElement | PropertySignature | MethodSignature): void { + public insertMemberAtStart( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, + newElement: ClassElement | PropertySignature | MethodSignature, + ): void { this.insertNodeAtStartWorker(sourceFile, node, newElement); } - public insertNodeAtObjectStart(sourceFile: SourceFile, obj: ObjectLiteralExpression, newElement: ObjectLiteralElementLike): void { + public insertNodeAtObjectStart( + sourceFile: SourceFile, + obj: ObjectLiteralExpression, + newElement: ObjectLiteralElementLike, + ): void { this.insertNodeAtStartWorker(sourceFile, obj, newElement); } - private insertNodeAtStartWorker(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, newElement: ClassElement | ObjectLiteralElementLike | PropertySignature | MethodSignature): void { - const indentation = this.guessIndentationFromExistingMembers(sourceFile, node) ?? this.computeIndentationForNewMember(sourceFile, node); - this.insertNodeAt(sourceFile, getMembersOrProperties(node).pos, newElement, this.getInsertNodeAtStartInsertOptions(sourceFile, node, indentation)); + private insertNodeAtStartWorker( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + newElement: ClassElement | ObjectLiteralElementLike | PropertySignature | MethodSignature, + ): void { + const indentation = this.guessIndentationFromExistingMembers(sourceFile, node) + ?? this.computeIndentationForNewMember(sourceFile, node); + this.insertNodeAt( + sourceFile, + getMembersOrProperties(node).pos, + newElement, + this.getInsertNodeAtStartInsertOptions(sourceFile, node, indentation), + ); } /** * Tries to guess the indentation from the existing members of a class/interface/object. All members must be on * new lines and must share the same indentation. */ - private guessIndentationFromExistingMembers(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode) { + private guessIndentationFromExistingMembers( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + ) { let indentation: number | undefined; let lastRange: TextRange = node; for (const member of getMembersOrProperties(node)) { @@ -865,7 +1115,12 @@ export class ChangeTracker { return undefined; } const memberStart = member.getStart(sourceFile); - const memberIndentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(memberStart, sourceFile), memberStart, sourceFile, this.formatContext.options); + const memberIndentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn( + getLineStartPositionForPosition(memberStart, sourceFile), + memberStart, + sourceFile, + this.formatContext.options, + ); if (indentation === undefined) { indentation = memberIndentation; } @@ -878,13 +1133,25 @@ export class ChangeTracker { return indentation; } - private computeIndentationForNewMember(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode) { + private computeIndentationForNewMember( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + ) { const nodeStart = node.getStart(sourceFile); - return formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(nodeStart, sourceFile), nodeStart, sourceFile, this.formatContext.options) + return formatting.SmartIndenter.findFirstNonWhitespaceColumn( + getLineStartPositionForPosition(nodeStart, sourceFile), + nodeStart, + sourceFile, + this.formatContext.options, + ) + (this.formatContext.options.indentSize ?? 4); } - private getInsertNodeAtStartInsertOptions(sourceFile: SourceFile, node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, indentation: number): InsertNodeOptions { + private getInsertNodeAtStartInsertOptions( + sourceFile: SourceFile, + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, + indentation: number, + ): InsertNodeOptions { // Rules: // - Always insert leading newline. // - For object literals: @@ -899,16 +1166,21 @@ export class ChangeTracker { const isEmpty = members.length === 0; const isFirstInsertion = addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(node), { node, sourceFile }); const insertTrailingComma = isObjectLiteralExpression(node) && (!isJsonSourceFile(sourceFile) || !isEmpty); - const insertLeadingComma = isObjectLiteralExpression(node) && isJsonSourceFile(sourceFile) && isEmpty && !isFirstInsertion; + const insertLeadingComma = isObjectLiteralExpression(node) && isJsonSourceFile(sourceFile) && isEmpty + && !isFirstInsertion; return { indentation, prefix: (insertLeadingComma ? "," : "") + this.newLineCharacter, - suffix: insertTrailingComma ? "," : isInterfaceDeclaration(node) && isEmpty ? ";" : "" + suffix: insertTrailingComma ? "," : isInterfaceDeclaration(node) && isEmpty ? ";" : "", }; } public insertNodeAfterComma(sourceFile: SourceFile, after: Node, newNode: Node): void { - const endPosition = this.insertNodeAfterWorker(sourceFile, this.nextCommaToken(sourceFile, after) || after, newNode); + const endPosition = this.insertNodeAfterWorker( + sourceFile, + this.nextCommaToken(sourceFile, after) || after, + newNode, + ); this.insertNodeAt(sourceFile, endPosition, newNode, this.getInsertNodeAfterOptions(sourceFile, after)); } @@ -942,7 +1214,8 @@ export class ChangeTracker { const options = this.getInsertNodeAfterOptionsWorker(after); return { ...options, - prefix: after.end === sourceFile.end && isStatement(after) ? (options.prefix ? `\n${options.prefix}` : "\n") : options.prefix, + prefix: after.end === sourceFile.end && isStatement(after) ? (options.prefix ? `\n${options.prefix}` : "\n") + : options.prefix, }; } @@ -972,14 +1245,21 @@ export class ChangeTracker { } } - public insertName(sourceFile: SourceFile, node: FunctionExpression | ClassExpression | ArrowFunction, name: string): void { + public insertName( + sourceFile: SourceFile, + node: FunctionExpression | ClassExpression | ArrowFunction, + name: string, + ): void { Debug.assert(!node.name); if (node.kind === SyntaxKind.ArrowFunction) { const arrow = findChildOfKind(node, SyntaxKind.EqualsGreaterThanToken, sourceFile)!; const lparen = findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile); if (lparen) { // `() => {}` --> `function f() {}` - this.insertNodesAt(sourceFile, lparen.getStart(sourceFile), [factory.createToken(SyntaxKind.FunctionKeyword), factory.createIdentifier(name)], { joiner: " " }); + this.insertNodesAt(sourceFile, lparen.getStart(sourceFile), [ + factory.createToken(SyntaxKind.FunctionKeyword), + factory.createIdentifier(name), + ], { joiner: " " }); deleteNode(this, sourceFile, arrow); } else { @@ -991,12 +1271,22 @@ export class ChangeTracker { if (node.body.kind !== SyntaxKind.Block) { // `() => 0` => `function f() { return 0; }` - this.insertNodesAt(sourceFile, node.body.getStart(sourceFile), [factory.createToken(SyntaxKind.OpenBraceToken), factory.createToken(SyntaxKind.ReturnKeyword)], { joiner: " ", suffix: " " }); - this.insertNodesAt(sourceFile, node.body.end, [factory.createToken(SyntaxKind.SemicolonToken), factory.createToken(SyntaxKind.CloseBraceToken)], { joiner: " " }); + this.insertNodesAt(sourceFile, node.body.getStart(sourceFile), [ + factory.createToken(SyntaxKind.OpenBraceToken), + factory.createToken(SyntaxKind.ReturnKeyword), + ], { joiner: " ", suffix: " " }); + this.insertNodesAt(sourceFile, node.body.end, [ + factory.createToken(SyntaxKind.SemicolonToken), + factory.createToken(SyntaxKind.CloseBraceToken), + ], { joiner: " " }); } } else { - const pos = findChildOfKind(node, node.kind === SyntaxKind.FunctionExpression ? SyntaxKind.FunctionKeyword : SyntaxKind.ClassKeyword, sourceFile)!.end; + const pos = findChildOfKind( + node, + node.kind === SyntaxKind.FunctionExpression ? SyntaxKind.FunctionKeyword : SyntaxKind.ClassKeyword, + sourceFile, + )!.end; this.insertNodeAt(sourceFile, pos, factory.createIdentifier(name), { prefix: " " }); } } @@ -1005,7 +1295,12 @@ export class ChangeTracker { this.insertText(sourceFile, node.getStart(sourceFile), "export "); } - public insertImportSpecifierAtIndex(sourceFile: SourceFile, importSpecifier: ImportSpecifier, namedImports: NamedImports, index: number) { + public insertImportSpecifierAtIndex( + sourceFile: SourceFile, + importSpecifier: ImportSpecifier, + namedImports: NamedImports, + index: number, + ) { const prevSpecifier = namedImports.elements[index - 1]; if (prevSpecifier) { this.insertNodeInListAfter(sourceFile, prevSpecifier, importSpecifier); @@ -1015,7 +1310,12 @@ export class ChangeTracker { sourceFile, namedImports.elements[0], importSpecifier, - !positionsAreOnSameLine(namedImports.elements[0].getStart(), namedImports.parent.parent.getStart(), sourceFile)); + !positionsAreOnSameLine( + namedImports.elements[0].getStart(), + namedImports.parent.parent.getStart(), + sourceFile, + ), + ); } } @@ -1024,7 +1324,12 @@ export class ChangeTracker { * i.e. arguments in arguments lists, parameters in parameter lists etc. * Note that separators are part of the node in statements and class elements. */ - public insertNodeInListAfter(sourceFile: SourceFile, after: Node, newNode: Node, containingList = formatting.SmartIndenter.getContainingList(after, sourceFile)): void { + public insertNodeInListAfter( + sourceFile: SourceFile, + after: Node, + newNode: Node, + containingList = formatting.SmartIndenter.getContainingList(after, sourceFile), + ): void { if (!containingList) { Debug.fail("node is not a list element"); return; @@ -1083,9 +1388,13 @@ export class ChangeTracker { else { // element has more than one element, pick separator from the list const tokenBeforeInsertPosition = findPrecedingToken(after.pos, sourceFile); - separator = isSeparator(after, tokenBeforeInsertPosition) ? tokenBeforeInsertPosition.kind : SyntaxKind.CommaToken; + separator = isSeparator(after, tokenBeforeInsertPosition) ? tokenBeforeInsertPosition.kind + : SyntaxKind.CommaToken; // determine if list is multiline by checking lines of after element and element that precedes it. - const afterMinusOneStartLinePosition = getLineStartPositionForPosition(containingList[index - 1].getStart(sourceFile), sourceFile); + const afterMinusOneStartLinePosition = getLineStartPositionForPosition( + containingList[index - 1].getStart(sourceFile), + sourceFile, + ); multilineList = afterMinusOneStartLinePosition !== afterStartLinePosition; } if (hasCommentsBeforeLineBreak(sourceFile.text, after.end)) { @@ -1096,14 +1405,22 @@ export class ChangeTracker { // insert separator immediately following the 'after' node to preserve comments in trailing trivia this.replaceRange(sourceFile, createRange(end), factory.createToken(separator)); // use the same indentation as 'after' item - const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.formatContext.options); + const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn( + afterStartLinePosition, + afterStart, + sourceFile, + this.formatContext.options, + ); // insert element before the line break on the line that contains 'after' element let insertPos = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ false); // find position before "\n" or "\r\n" while (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) { insertPos--; } - this.replaceRange(sourceFile, createRange(insertPos), newNode, { indentation, prefix: this.newLineCharacter }); + this.replaceRange(sourceFile, createRange(insertPos), newNode, { + indentation, + prefix: this.newLineCharacter, + }); } else { this.replaceRange(sourceFile, createRange(end), newNode, { prefix: `${tokenToString(separator)} ` }); @@ -1135,7 +1452,9 @@ export class ChangeTracker { private finishDeleteDeclarations(): void { const deletedNodesInLists = new Set(); // Stores nodes in lists that we already deleted. Used to avoid deleting `, ` twice in `a, b`. for (const { sourceFile, node } of this.deletedNodes) { - if (!this.deletedNodes.some(d => d.sourceFile === sourceFile && rangeContainsRangeExclusive(d.node, node))) { + if ( + !this.deletedNodes.some(d => d.sourceFile === sourceFile && rangeContainsRangeExclusive(d.node, node)) + ) { if (isArray(node)) { this.deleteRange(sourceFile, rangeOfTypeParameters(sourceFile, node)); } @@ -1152,7 +1471,10 @@ export class ChangeTracker { const lastNonDeletedIndex = findLastIndex(list, n => !deletedNodesInLists.has(n), list.length - 2); if (lastNonDeletedIndex !== -1) { - this.deleteRange(sourceFile, { pos: list[lastNonDeletedIndex].end, end: startPositionToDeleteNodeInList(sourceFile, list[lastNonDeletedIndex + 1]) }); + this.deleteRange(sourceFile, { + pos: list[lastNonDeletedIndex].end, + end: startPositionToDeleteNodeInList(sourceFile, list[lastNonDeletedIndex + 1]), + }); } }); } @@ -1166,16 +1488,27 @@ export class ChangeTracker { public getChanges(validate?: ValidateNonFormattedText): FileTextChanges[] { this.finishDeleteDeclarations(); this.finishClassesWithNodesInsertedAtStart(); - const changes = changesToText.getTextChangesFromChanges(this.changes, this.newLineCharacter, this.formatContext, validate); + const changes = changesToText.getTextChangesFromChanges( + this.changes, + this.newLineCharacter, + this.formatContext, + validate, + ); if (this.newFileChanges) { this.newFileChanges.forEach((insertions, fileName) => { - changes.push(changesToText.newFileChanges(fileName, insertions, this.newLineCharacter, this.formatContext)); + changes.push( + changesToText.newFileChanges(fileName, insertions, this.newLineCharacter, this.formatContext), + ); }); } return changes; } - public createNewFile(oldFile: SourceFile | undefined, fileName: string, statements: readonly (Statement | SyntaxKind.NewLineTrivia)[]): void { + public createNewFile( + oldFile: SourceFile | undefined, + fileName: string, + statements: readonly (Statement | SyntaxKind.NewLineTrivia)[], + ): void { this.insertStatementsInNewFile(fileName, statements, oldFile); } } @@ -1184,9 +1517,9 @@ function updateJSDocHost(parent: HasJSDoc): HasJSDoc { if (parent.kind !== SyntaxKind.ArrowFunction) { return parent; } - const jsDocNode = parent.parent.kind === SyntaxKind.PropertyDeclaration ? - parent.parent as HasJSDoc : - parent.parent.parent as HasJSDoc; + const jsDocNode = parent.parent.kind === SyntaxKind.PropertyDeclaration + ? parent.parent as HasJSDoc + : parent.parent.parent as HasJSDoc; jsDocNode.jsDoc = parent.jsDoc; return jsDocNode; } @@ -1199,32 +1532,65 @@ function tryMergeJsdocTags(oldTag: JSDocTag, newTag: JSDocTag): JSDocTag | undef case SyntaxKind.JSDocParameterTag: { const oldParam = oldTag as JSDocParameterTag; const newParam = newTag as JSDocParameterTag; - return isIdentifier(oldParam.name) && isIdentifier(newParam.name) && oldParam.name.escapedText === newParam.name.escapedText - ? factory.createJSDocParameterTag(/*tagName*/ undefined, newParam.name, /*isBracketed*/ false, newParam.typeExpression, newParam.isNameFirst, oldParam.comment) + return isIdentifier(oldParam.name) && isIdentifier(newParam.name) + && oldParam.name.escapedText === newParam.name.escapedText + ? factory.createJSDocParameterTag( + /*tagName*/ undefined, + newParam.name, + /*isBracketed*/ false, + newParam.typeExpression, + newParam.isNameFirst, + oldParam.comment, + ) : undefined; } case SyntaxKind.JSDocReturnTag: - return factory.createJSDocReturnTag(/*tagName*/ undefined, (newTag as JSDocReturnTag).typeExpression, oldTag.comment); + return factory.createJSDocReturnTag( + /*tagName*/ undefined, + (newTag as JSDocReturnTag).typeExpression, + oldTag.comment, + ); case SyntaxKind.JSDocTypeTag: - return factory.createJSDocTypeTag(/*tagName*/ undefined, (newTag as JSDocTypeTag).typeExpression, oldTag.comment); + return factory.createJSDocTypeTag( + /*tagName*/ undefined, + (newTag as JSDocTypeTag).typeExpression, + oldTag.comment, + ); } } // find first non-whitespace position in the leading trivia of the node function startPositionToDeleteNodeInList(sourceFile: SourceFile, node: Node): number { - return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, { leadingTriviaOption: LeadingTriviaOption.IncludeAll }), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); + return skipTrivia( + sourceFile.text, + getAdjustedStartPosition(sourceFile, node, { leadingTriviaOption: LeadingTriviaOption.IncludeAll }), + /*stopAfterLineBreak*/ false, + /*stopAtComments*/ true, + ); } -function endPositionToDeleteNodeInList(sourceFile: SourceFile, node: Node, prevNode: Node | undefined, nextNode: Node): number { +function endPositionToDeleteNodeInList( + sourceFile: SourceFile, + node: Node, + prevNode: Node | undefined, + nextNode: Node, +): number { const end = startPositionToDeleteNodeInList(sourceFile, nextNode); - if (prevNode === undefined || positionsAreOnSameLine(getAdjustedEndPosition(sourceFile, node, {}), end, sourceFile)) { + if ( + prevNode === undefined || positionsAreOnSameLine(getAdjustedEndPosition(sourceFile, node, {}), end, sourceFile) + ) { return end; } const token = findPrecedingToken(nextNode.getStart(sourceFile), sourceFile); if (isSeparator(node, token)) { const prevToken = findPrecedingToken(node.getStart(sourceFile), sourceFile); if (isSeparator(prevNode, prevToken)) { - const pos = skipTrivia(sourceFile.text, token.getEnd(), /*stopAfterLineBreak*/ true, /*stopAtComments*/ true); + const pos = skipTrivia( + sourceFile.text, + token.getEnd(), + /*stopAfterLineBreak*/ true, + /*stopAtComments*/ true, + ); if (positionsAreOnSameLine(prevToken.getStart(sourceFile), token.getStart(sourceFile), sourceFile)) { return isLineBreak(sourceFile.text.charCodeAt(pos - 1)) ? pos - 1 : pos; } @@ -1236,12 +1602,17 @@ function endPositionToDeleteNodeInList(sourceFile: SourceFile, node: Node, prevN return end; } -function getClassOrObjectBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, sourceFile: SourceFile): [number | undefined, number | undefined] { +function getClassOrObjectBraceEnds( + cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, + sourceFile: SourceFile, +): [number | undefined, number | undefined] { const open = findChildOfKind(cls, SyntaxKind.OpenBraceToken, sourceFile); const close = findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile); return [open?.end, close?.end]; } -function getMembersOrProperties(node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode): NodeArray { +function getMembersOrProperties( + node: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression | TypeLiteralNode, +): NodeArray { return isObjectLiteralExpression(node) ? node.properties : node.members; } @@ -1249,24 +1620,44 @@ function getMembersOrProperties(node: ClassLikeDeclaration | InterfaceDeclaratio export type ValidateNonFormattedText = (node: Node, text: string) => void; namespace changesToText { - export function getTextChangesFromChanges(changes: readonly Change[], newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): FileTextChanges[] { + export function getTextChangesFromChanges( + changes: readonly Change[], + newLineCharacter: string, + formatContext: formatting.FormatContext, + validate: ValidateNonFormattedText | undefined, + ): FileTextChanges[] { return mapDefined(group(changes, c => c.sourceFile.path), changesInFile => { const sourceFile = changesInFile[0].sourceFile; // order changes by start position // If the start position is the same, put the shorter range first, since an empty range (x, x) may precede (x, y) but not vice-versa. - const normalized = stableSort(changesInFile, (a, b) => (a.range.pos - b.range.pos) || (a.range.end - b.range.end)); + const normalized = stableSort( + changesInFile, + (a, b) => (a.range.pos - b.range.pos) || (a.range.end - b.range.end), + ); // verify that change intervals do not overlap, except possibly at end points. for (let i = 0; i < normalized.length - 1; i++) { - Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos, "Changes overlap", () => - `${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`); + Debug.assert( + normalized[i].range.end <= normalized[i + 1].range.pos, + "Changes overlap", + () => `${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`, + ); } const textChanges = mapDefined(normalized, c => { const span = createTextSpanFromRange(c.range); - const targetSourceFile = c.kind === ChangeKind.ReplaceWithSingleNode ? getSourceFileOfNode(getOriginalNode(c.node)) ?? c.sourceFile : - c.kind === ChangeKind.ReplaceWithMultipleNodes ? getSourceFileOfNode(getOriginalNode(c.nodes[0])) ?? c.sourceFile : - c.sourceFile; - const newText = computeNewText(c, targetSourceFile, sourceFile, newLineCharacter, formatContext, validate); + const targetSourceFile = c.kind === ChangeKind.ReplaceWithSingleNode + ? getSourceFileOfNode(getOriginalNode(c.node)) ?? c.sourceFile + : c.kind === ChangeKind.ReplaceWithMultipleNodes + ? getSourceFileOfNode(getOriginalNode(c.nodes[0])) ?? c.sourceFile + : c.sourceFile; + const newText = computeNewText( + c, + targetSourceFile, + sourceFile, + newLineCharacter, + formatContext, + validate, + ); // Filter out redundant changes. if (span.length === newText.length && stringContainsAt(targetSourceFile.text, newText, span.start)) { return undefined; @@ -1279,20 +1670,55 @@ namespace changesToText { }); } - export function newFileChanges(fileName: string, insertions: readonly NewFileInsertion[], newLineCharacter: string, formatContext: formatting.FormatContext): FileTextChanges { - const text = newFileChangesWorker(getScriptKindFromFileName(fileName), insertions, newLineCharacter, formatContext); + export function newFileChanges( + fileName: string, + insertions: readonly NewFileInsertion[], + newLineCharacter: string, + formatContext: formatting.FormatContext, + ): FileTextChanges { + const text = newFileChangesWorker( + getScriptKindFromFileName(fileName), + insertions, + newLineCharacter, + formatContext, + ); return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true }; } - export function newFileChangesWorker(scriptKind: ScriptKind, insertions: readonly NewFileInsertion[], newLineCharacter: string, formatContext: formatting.FormatContext): string { + export function newFileChangesWorker( + scriptKind: ScriptKind, + insertions: readonly NewFileInsertion[], + newLineCharacter: string, + formatContext: formatting.FormatContext, + ): string { // TODO: this emits the file, parses it back, then formats it that -- may be a less roundabout way to do this - const nonFormattedText = flatMap(insertions, insertion => insertion.statements.map(s => s === SyntaxKind.NewLineTrivia ? "" : getNonformattedText(s, insertion.oldFile, newLineCharacter).text)).join(newLineCharacter); - const sourceFile = createSourceFile("any file name", nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true, scriptKind); + const nonFormattedText = flatMap( + insertions, + insertion => + insertion.statements.map(s => + s === SyntaxKind.NewLineTrivia ? "" + : getNonformattedText(s, insertion.oldFile, newLineCharacter).text + ), + ).join(newLineCharacter); + const sourceFile = createSourceFile( + "any file name", + nonFormattedText, + ScriptTarget.ESNext, + /*setParentNodes*/ true, + scriptKind, + ); const changes = formatting.formatDocument(sourceFile, formatContext); return applyChanges(nonFormattedText, changes) + newLineCharacter; } - function computeNewText(change: Change, targetSourceFile: SourceFile, sourceFile: SourceFile, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string { + function computeNewText( + change: Change, + targetSourceFile: SourceFile, + sourceFile: SourceFile, + newLineCharacter: string, + formatContext: formatting.FormatContext, + validate: ValidateNonFormattedText | undefined, + ): string { if (change.kind === ChangeKind.Remove) { return ""; } @@ -1301,49 +1727,88 @@ namespace changesToText { } const { options = {}, range: { pos } } = change; - const format = (n: Node) => getFormattedTextOfNode(n, targetSourceFile, sourceFile, pos, options, newLineCharacter, formatContext, validate); + const format = (n: Node) => + getFormattedTextOfNode( + n, + targetSourceFile, + sourceFile, + pos, + options, + newLineCharacter, + formatContext, + validate, + ); const text = change.kind === ChangeKind.ReplaceWithMultipleNodes - ? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join(change.options?.joiner || newLineCharacter) + ? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join( + change.options?.joiner || newLineCharacter, + ) : format(change.node); // strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line - const noIndent = (options.indentation !== undefined || getLineStartPositionForPosition(pos, targetSourceFile) === pos) ? text : text.replace(/^\s+/, ""); + const noIndent = + (options.indentation !== undefined || getLineStartPositionForPosition(pos, targetSourceFile) === pos) ? text + : text.replace(/^\s+/, ""); return (options.prefix || "") + noIndent - + ((!options.suffix || endsWith(noIndent, options.suffix)) + + ((!options.suffix || endsWith(noIndent, options.suffix)) ? "" : options.suffix); } /** Note: this may mutate `nodeIn`. */ - function getFormattedTextOfNode(nodeIn: Node, targetSourceFile: SourceFile, sourceFile: SourceFile, pos: number, { indentation, prefix, delta }: InsertNodeOptions, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string { + function getFormattedTextOfNode( + nodeIn: Node, + targetSourceFile: SourceFile, + sourceFile: SourceFile, + pos: number, + { indentation, prefix, delta }: InsertNodeOptions, + newLineCharacter: string, + formatContext: formatting.FormatContext, + validate: ValidateNonFormattedText | undefined, + ): string { const { node, text } = getNonformattedText(nodeIn, targetSourceFile, newLineCharacter); if (validate) validate(node, text); const formatOptions = getFormatCodeSettingsForWriting(formatContext, targetSourceFile); - const initialIndentation = - indentation !== undefined - ? indentation - : formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, prefix === newLineCharacter || getLineStartPositionForPosition(pos, targetSourceFile) === pos); + const initialIndentation = indentation !== undefined + ? indentation + : formatting.SmartIndenter.getIndentation( + pos, + sourceFile, + formatOptions, + prefix === newLineCharacter || getLineStartPositionForPosition(pos, targetSourceFile) === pos, + ); if (delta === undefined) { - delta = formatting.SmartIndenter.shouldIndentChildNode(formatOptions, nodeIn) ? (formatOptions.indentSize || 0) : 0; + delta = formatting.SmartIndenter.shouldIndentChildNode(formatOptions, nodeIn) + ? (formatOptions.indentSize || 0) : 0; } const file: SourceFileLike = { text, getLineAndCharacterOfPosition(pos) { return getLineAndCharacterOfPosition(this, pos); - } + }, }; - const changes = formatting.formatNodeGivenIndentation(node, file, targetSourceFile.languageVariant, initialIndentation, delta, { ...formatContext, options: formatOptions }); + const changes = formatting.formatNodeGivenIndentation( + node, + file, + targetSourceFile.languageVariant, + initialIndentation, + delta, + { ...formatContext, options: formatOptions }, + ); return applyChanges(text, changes); } /** Note: output node may be mutated input node. */ - export function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string, node: Node } { + export function getNonformattedText( + node: Node, + sourceFile: SourceFile | undefined, + newLineCharacter: string, + ): { text: string; node: Node; } { const writer = createWriter(newLineCharacter); const newLine = getNewLineKind(newLineCharacter); createPrinter({ newLine, neverAsciiEscape: true, preserveSourceNewlines: true, - terminateUnterminatedLiterals: true + terminateUnterminatedLiterals: true, }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer); return { text: writer.getText(), node: assignPositionsToNode(node) }; } @@ -1368,12 +1833,19 @@ const textChangesTransformationContext: TransformationContext = { ...nullTransformationContext, factory: createNodeFactory( nullTransformationContext.factory.flags | NodeFactoryFlags.NoParenthesizerRules, - nullTransformationContext.factory.baseFactory), + nullTransformationContext.factory.baseFactory, + ), }; /** @internal */ export function assignPositionsToNode(node: Node): Node { - const visited = visitEachChild(node, assignPositionsToNode, textChangesTransformationContext, assignPositionsToNodeArray, assignPositionsToNode); + const visited = visitEachChild( + node, + assignPositionsToNode, + textChangesTransformationContext, + assignPositionsToNodeArray, + assignPositionsToNode, + ); // create proxy node for non synthesized nodes const newNode = nodeIsSynthesized(visited) ? visited : Object.create(visited) as Node; setTextRangePosEnd(newNode, getPos(node), getEnd(node)); @@ -1563,7 +2035,7 @@ export function createWriter(newLine: string): TextChangesWriter { isAtStartOfLine, hasTrailingComment: () => writer.hasTrailingComment(), hasTrailingWhitespace: () => writer.hasTrailingWhitespace(), - clear + clear, }; } @@ -1622,7 +2094,9 @@ function getInsertionPositionAtSourceFileTop(sourceFile: SourceFile): number { } if (sourceFile.statements.length) { - if (firstNodeLine === undefined) firstNodeLine = sourceFile.getLineAndCharacterOfPosition(sourceFile.statements[0].getStart()).line; + if (firstNodeLine === undefined) { + firstNodeLine = sourceFile.getLineAndCharacterOfPosition(sourceFile.statements[0].getStart()).line; + } const commentEndLine = sourceFile.getLineAndCharacterOfPosition(range.end).line; if (firstNodeLine < commentEndLine + 2) break; } @@ -1641,7 +2115,10 @@ function getInsertionPositionAtSourceFileTop(sourceFile: SourceFile): number { if (isLineBreak(charCode)) { position++; - if (position < text.length && charCode === CharacterCodes.carriageReturn && text.charCodeAt(position) === CharacterCodes.lineFeed) { + if ( + position < text.length && charCode === CharacterCodes.carriageReturn + && text.charCodeAt(position) === CharacterCodes.lineFeed + ) { position++; } } @@ -1651,22 +2128,31 @@ function getInsertionPositionAtSourceFileTop(sourceFile: SourceFile): number { /** @internal */ export function isValidLocationToAddComment(sourceFile: SourceFile, position: number) { - return !isInComment(sourceFile, position) && !isInString(sourceFile, position) && !isInTemplateString(sourceFile, position) && !isInJSXText(sourceFile, position); + return !isInComment(sourceFile, position) && !isInString(sourceFile, position) + && !isInTemplateString(sourceFile, position) && !isInJSXText(sourceFile, position); } function needSemicolonBetween(a: Node, b: Node): boolean { - return (isPropertySignature(a) || isPropertyDeclaration(a)) && isClassOrTypeElement(b) && b.name!.kind === SyntaxKind.ComputedPropertyName + return (isPropertySignature(a) || isPropertyDeclaration(a)) && isClassOrTypeElement(b) + && b.name!.kind === SyntaxKind.ComputedPropertyName || isStatementButNotDeclaration(a) && isStatementButNotDeclaration(b); // TODO: only if b would start with a `(` or `[` } namespace deleteDeclaration { - export function deleteDeclaration(changes: ChangeTracker, deletedNodesInLists: Set, sourceFile: SourceFile, node: Node): void { + export function deleteDeclaration( + changes: ChangeTracker, + deletedNodesInLists: Set, + sourceFile: SourceFile, + node: Node, + ): void { switch (node.kind) { case SyntaxKind.Parameter: { const oldFunction = node.parent; - if (isArrowFunction(oldFunction) && - oldFunction.parameters.length === 1 && - !findChildOfKind(oldFunction, SyntaxKind.OpenParenToken, sourceFile)) { + if ( + isArrowFunction(oldFunction) + && oldFunction.parameters.length === 1 + && !findChildOfKind(oldFunction, SyntaxKind.OpenParenToken, sourceFile) + ) { // Lambdas with exactly one parameter are special because, after removal, there // must be an empty parameter list (i.e. `()`) and this won't necessarily be the // case if the parameter is simply removed (e.g. in `x => 1`). @@ -1680,16 +2166,19 @@ namespace deleteDeclaration { case SyntaxKind.ImportDeclaration: case SyntaxKind.ImportEqualsDeclaration: - const isFirstImport = sourceFile.imports.length && node === first(sourceFile.imports).parent || node === find(sourceFile.statements, isAnyImportSyntax); + const isFirstImport = sourceFile.imports.length && node === first(sourceFile.imports).parent + || node === find(sourceFile.statements, isAnyImportSyntax); // For first import, leave header comment in place, otherwise only delete JSDoc comments deleteNode(changes, sourceFile, node, { - leadingTriviaOption: isFirstImport ? LeadingTriviaOption.Exclude : hasJSDocNodes(node) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine, + leadingTriviaOption: isFirstImport ? LeadingTriviaOption.Exclude + : hasJSDocNodes(node) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine, }); break; case SyntaxKind.BindingElement: const pattern = (node as BindingElement).parent; - const preserveComma = pattern.kind === SyntaxKind.ArrayBindingPattern && node !== last(pattern.elements); + const preserveComma = pattern.kind === SyntaxKind.ArrayBindingPattern + && node !== last(pattern.elements); if (preserveComma) { deleteNode(changes, sourceFile, node); } @@ -1730,7 +2219,10 @@ namespace deleteDeclaration { case SyntaxKind.ClassDeclaration: case SyntaxKind.FunctionDeclaration: - deleteNode(changes, sourceFile, node, { leadingTriviaOption: hasJSDocNodes(node) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine }); + deleteNode(changes, sourceFile, node, { + leadingTriviaOption: hasJSDocNodes(node) ? LeadingTriviaOption.JSDoc + : LeadingTriviaOption.StartLine, + }); break; default: @@ -1761,7 +2253,12 @@ namespace deleteDeclaration { const nextToken = getTokenAtPosition(sourceFile, importClause.name!.end); if (nextToken && nextToken.kind === SyntaxKind.CommaToken) { // shift first non-whitespace position after comma to the start position of the node - const end = skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); + const end = skipTrivia( + sourceFile.text, + nextToken.end, + /*stopAfterLineBreak*/ false, + /*stopAtComments*/ true, + ); changes.deleteRange(sourceFile, { pos: start, end }); } else { @@ -1787,12 +2284,21 @@ namespace deleteDeclaration { } } - function deleteVariableDeclaration(changes: ChangeTracker, deletedNodesInLists: Set, sourceFile: SourceFile, node: VariableDeclaration): void { + function deleteVariableDeclaration( + changes: ChangeTracker, + deletedNodesInLists: Set, + sourceFile: SourceFile, + node: VariableDeclaration, + ): void { const { parent } = node; if (parent.kind === SyntaxKind.CatchClause) { // TODO: There's currently no unused diagnostic for this, could be a suggestion - changes.deleteNodeRange(sourceFile, findChildOfKind(parent, SyntaxKind.OpenParenToken, sourceFile)!, findChildOfKind(parent, SyntaxKind.CloseParenToken, sourceFile)!); + changes.deleteNodeRange( + sourceFile, + findChildOfKind(parent, SyntaxKind.OpenParenToken, sourceFile)!, + findChildOfKind(parent, SyntaxKind.CloseParenToken, sourceFile)!, + ); return; } @@ -1813,7 +2319,9 @@ namespace deleteDeclaration { break; case SyntaxKind.VariableStatement: - deleteNode(changes, sourceFile, gp, { leadingTriviaOption: hasJSDocNodes(gp) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine }); + deleteNode(changes, sourceFile, gp, { + leadingTriviaOption: hasJSDocNodes(gp) ? LeadingTriviaOption.JSDoc : LeadingTriviaOption.StartLine, + }); break; default: @@ -1828,13 +2336,23 @@ namespace deleteDeclaration { * * @internal */ -export function deleteNode(changes: ChangeTracker, sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void { +export function deleteNode( + changes: ChangeTracker, + sourceFile: SourceFile, + node: Node, + options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }, +): void { const startPosition = getAdjustedStartPosition(sourceFile, node, options); const endPosition = getAdjustedEndPosition(sourceFile, node, options); changes.deleteRange(sourceFile, { pos: startPosition, end: endPosition }); } -function deleteNodeInList(changes: ChangeTracker, deletedNodesInLists: Set, sourceFile: SourceFile, node: Node): void { +function deleteNodeInList( + changes: ChangeTracker, + deletedNodesInLists: Set, + sourceFile: SourceFile, + node: Node, +): void { const containingList = Debug.checkDefined(formatting.SmartIndenter.getContainingList(node, sourceFile)); const index = indexOfNode(containingList, node); Debug.assert(index !== -1); @@ -1850,6 +2368,7 @@ function deleteNodeInList(changes: ChangeTracker, deletedNodesInLists: Set changes.deleteRange(sourceFile, { pos: startPositionToDeleteNodeInList(sourceFile, node), - end: index === containingList.length - 1 ? getAdjustedEndPosition(sourceFile, node, {}) : endPositionToDeleteNodeInList(sourceFile, node, containingList[index - 1], containingList[index + 1]), + end: index === containingList.length - 1 ? getAdjustedEndPosition(sourceFile, node, {}) + : endPositionToDeleteNodeInList(sourceFile, node, containingList[index - 1], containingList[index + 1]), }); } diff --git a/src/services/transform.ts b/src/services/transform.ts index 85fae890c0984..67ee013360de5 100644 --- a/src/services/transform.ts +++ b/src/services/transform.ts @@ -17,11 +17,23 @@ import { * @param transformers An array of `TransformerFactory` callbacks used to process the transformation. * @param compilerOptions Optional compiler options. */ -export function transform(source: T | T[], transformers: TransformerFactory[], compilerOptions?: CompilerOptions): TransformationResult { +export function transform( + source: T | T[], + transformers: TransformerFactory[], + compilerOptions?: CompilerOptions, +): TransformationResult { const diagnostics: DiagnosticWithLocation[] = []; compilerOptions = fixupCompilerOptions(compilerOptions!, diagnostics); // TODO: GH#18217 const nodes = isArray(source) ? source : [source]; - const result = transformNodes(/*resolver*/ undefined, /*host*/ undefined, factory, compilerOptions, nodes, transformers, /*allowDtsFiles*/ true); + const result = transformNodes( + /*resolver*/ undefined, + /*host*/ undefined, + factory, + compilerOptions, + nodes, + transformers, + /*allowDtsFiles*/ true, + ); result.diagnostics = concatenate(result.diagnostics, diagnostics); return result; } diff --git a/src/services/transpile.ts b/src/services/transpile.ts index 0f7e2b238c002..bd97358bc0001 100644 --- a/src/services/transpile.ts +++ b/src/services/transpile.ts @@ -46,7 +46,7 @@ export interface TranspileOutput { const optionsRedundantWithVerbatimModuleSyntax = new Set([ "isolatedModules", "preserveValueImports", - "importsNotUsedAsValues" + "importsNotUsedAsValues", ]); /* @@ -61,7 +61,8 @@ const optionsRedundantWithVerbatimModuleSyntax = new Set([ export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput { const diagnostics: Diagnostic[] = []; - const options: CompilerOptions = transpileOptions.compilerOptions ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : {}; + const options: CompilerOptions = transpileOptions.compilerOptions + ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : {}; // mix in default options const defaultOptions = getDefaultCompilerOptions(); @@ -89,7 +90,7 @@ export function transpileModule(input: string, transpileOptions: TranspileOption const newLine = getNewLineCharacter(options); // Create a compilerHost object to allow the compiler to read and write files const compilerHost: CompilerHost = { - getSourceFile: (fileName) => fileName === normalizePath(inputFileName) ? sourceFile : undefined, + getSourceFile: fileName => fileName === normalizePath(inputFileName) ? sourceFile : undefined, writeFile: (name, text) => { if (fileExtensionIs(name, ".map")) { Debug.assertEqual(sourceMapText, undefined, "Unexpected multiple source map outputs, file:", name); @@ -108,19 +109,25 @@ export function transpileModule(input: string, transpileOptions: TranspileOption fileExists: (fileName): boolean => fileName === inputFileName, readFile: () => "", directoryExists: () => true, - getDirectories: () => [] + getDirectories: () => [], }; // if jsx is specified then treat file as .tsx - const inputFileName = transpileOptions.fileName || (transpileOptions.compilerOptions && transpileOptions.compilerOptions.jsx ? "module.tsx" : "module.ts"); + const inputFileName = transpileOptions.fileName + || (transpileOptions.compilerOptions && transpileOptions.compilerOptions.jsx ? "module.tsx" : "module.ts"); const sourceFile = createSourceFile( inputFileName, input, { languageVersion: getEmitScriptTarget(options), - impliedNodeFormat: getImpliedNodeFormatForFile(toPath(inputFileName, "", compilerHost.getCanonicalFileName), /*packageJsonInfoCache*/ undefined, compilerHost, options), - setExternalModuleIndicator: getSetExternalModuleIndicator(options) - } + impliedNodeFormat: getImpliedNodeFormatForFile( + toPath(inputFileName, "", compilerHost.getCanonicalFileName), + /*packageJsonInfoCache*/ undefined, + compilerHost, + options, + ), + setExternalModuleIndicator: getSetExternalModuleIndicator(options), + }, ); if (transpileOptions.moduleName) { sourceFile.moduleName = transpileOptions.moduleName; @@ -141,7 +148,13 @@ export function transpileModule(input: string, transpileOptions: TranspileOption addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics()); } // Emit - program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ undefined, transpileOptions.transformers); + program.emit( + /*targetSourceFile*/ undefined, + /*writeFile*/ undefined, + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ undefined, + transpileOptions.transformers, + ); if (outputText === undefined) return Debug.fail("Output generation failed"); @@ -151,7 +164,13 @@ export function transpileModule(input: string, transpileOptions: TranspileOption /* * This is a shortcut function for transpileModule - it accepts transpileOptions as parameters and returns only outputText part of the result. */ -export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string { +export function transpile( + input: string, + compilerOptions?: CompilerOptions, + fileName?: string, + diagnostics?: Diagnostic[], + moduleName?: string, +): string { const output = transpileModule(input, { compilerOptions, fileName, reportDiagnostics: !!diagnostics, moduleName }); // addRange correctly handles cases when wither 'from' or 'to' argument is missing addRange(diagnostics, output.diagnostics); @@ -167,8 +186,11 @@ let commandLineOptionsStringToEnum: CommandLineOptionOfCustomType[]; */ export function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions { // Lazily create this value to fix module loading errors. - commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || - filter(optionDeclarations, o => typeof o.type === "object" && !forEachEntry(o.type, v => typeof v !== "number")) as CommandLineOptionOfCustomType[]; + commandLineOptionsStringToEnum = commandLineOptionsStringToEnum + || filter( + optionDeclarations, + o => typeof o.type === "object" && !forEachEntry(o.type, v => typeof v !== "number"), + ) as CommandLineOptionOfCustomType[]; options = cloneCompilerOptions(options); diff --git a/src/services/types.ts b/src/services/types.ts index dc69092d3fe9a..5a1321e01facb 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -67,7 +67,10 @@ declare module "../compiler/types" { /** @internal */ getLastToken(sourceFile?: SourceFileLike): Node | undefined; // eslint-disable-line @typescript-eslint/unified-signatures // See ts.forEachChild for documentation. - forEachChild(cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray) => T | undefined): T | undefined; + forEachChild( + cbNode: (node: Node) => T | undefined, + cbNodeArray?: (nodes: NodeArray) => T | undefined, + ): T | undefined; } } @@ -95,7 +98,10 @@ declare module "../compiler/types" { getDeclarations(): Declaration[] | undefined; getDocumentationComment(typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; /** @internal */ - getContextualDocumentationComment(context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] + getContextualDocumentationComment( + context: Node | undefined, + checker: TypeChecker | undefined, + ): SymbolDisplayPart[]; getJsDocTags(checker?: TypeChecker): JSDocTagInfo[]; /** @internal */ getContextualJsDocTags(context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[]; @@ -215,7 +221,6 @@ export interface IScriptSnapshot { export namespace ScriptSnapshot { class StringScriptSnapshot implements IScriptSnapshot { - constructor(private text: string) { } @@ -334,7 +339,13 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR * LS host can optionally implement these methods to support completions for module specifiers. * Without these methods, only completions for ambient modules will be provided. */ - readDirectory?(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[]; + readDirectory?( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[]; realpath?(path: string): string; /** @internal */ createHash?(data: string): string; @@ -358,10 +369,27 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR * If this is implemented, `getResolvedModuleWithFailedLookupLocationsFromCache` should be too. */ /** @deprecated supply resolveModuleNameLiterals instead for resolution that can handle newer resolution modes like nodenext */ - resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[]; - getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string, resolutionMode?: ResolutionMode): ResolvedModuleWithFailedLookupLocations | undefined; + resolveModuleNames?( + moduleNames: string[], + containingFile: string, + reusedNames: string[] | undefined, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingSourceFile?: SourceFile, + ): (ResolvedModule | undefined)[]; + getResolvedModuleWithFailedLookupLocationsFromCache?( + modulename: string, + containingFile: string, + resolutionMode?: ResolutionMode, + ): ResolvedModuleWithFailedLookupLocations | undefined; /** @deprecated supply resolveTypeReferenceDirectiveReferences instead for resolution that can handle newer resolution modes like nodenext */ - resolveTypeReferenceDirectives?(typeDirectiveNames: string[] | FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: ResolutionMode): (ResolvedTypeReferenceDirective | undefined)[]; + resolveTypeReferenceDirectives?( + typeDirectiveNames: string[] | FileReference[], + containingFile: string, + redirectedReference: ResolvedProjectReference | undefined, + options: CompilerOptions, + containingFileMode?: ResolutionMode, + ): (ResolvedTypeReferenceDirective | undefined)[]; resolveModuleNameLiterals?( moduleLiterals: readonly StringLiteralLike[], containingFile: string, @@ -376,7 +404,7 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile: SourceFile | undefined, - reusedNames: readonly T[] | undefined + reusedNames: readonly T[] | undefined, ): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; /** @internal */ resolveLibrary?( @@ -413,9 +441,15 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR installPackage?(options: InstallPackageOptions): Promise; writeFile?(fileName: string, content: string): void; - /** @internal */ getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined; + /** @internal */ getDocumentPositionMapper?( + generatedFileName: string, + sourceFileName?: string, + ): DocumentPositionMapper | undefined; /** @internal */ getSourceFileLike?(fileName: string): SourceFileLike | undefined; - /** @internal */ getPackageJsonsVisibleToFile?(fileName: string, rootDir?: string): readonly ProjectPackageJsonInfo[]; + /** @internal */ getPackageJsonsVisibleToFile?( + fileName: string, + rootDir?: string, + ): readonly ProjectPackageJsonInfo[]; /** @internal */ getNearestAncestorDirectoryWithPackageJson?(fileName: string): string | undefined; /** @internal */ getPackageJsonsForAutoImport?(rootDir?: string): readonly ProjectPackageJsonInfo[]; /** @internal */ getCachedExportInfoMap?(): ExportInfoMap; @@ -425,7 +459,11 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR /** @internal */ getPackageJsonAutoImportProvider?(): Program | undefined; /** @internal */ sendPerformanceEvent?(kind: PerformanceEvent["kind"], durationMs: number): void; getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; - /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; + /** @internal */ onReleaseParsedCommandLine?( + configFileName: string, + oldResolvedRef: ResolvedProjectReference | undefined, + optionOptions: CompilerOptions, + ): void; /** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; } @@ -436,7 +474,7 @@ export type WithMetadata = T & { metadata?: unknown; }; export const enum SemanticClassificationFormat { Original = "original", - TwentyTwenty = "2020" + TwentyTwenty = "2020", } // @@ -502,11 +540,19 @@ export interface LanguageService { /** @deprecated Use getEncodedSyntacticClassifications instead. */ getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; - getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; + getSyntacticClassifications( + fileName: string, + span: TextSpan, + format: SemanticClassificationFormat, + ): ClassifiedSpan[] | ClassifiedSpan2020[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; - getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; + getSemanticClassifications( + fileName: string, + span: TextSpan, + format: SemanticClassificationFormat, + ): ClassifiedSpan[] | ClassifiedSpan2020[]; /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; @@ -520,7 +566,11 @@ export interface LanguageService { * @param format Which format to use, defaults to "original" * @returns a number array encoded as triples of [start, length, ClassificationType, ...]. */ - getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications; + getEncodedSemanticClassifications( + fileName: string, + span: TextSpan, + format?: SemanticClassificationFormat, + ): Classifications; /** * Gets completion entries at a particular position in a file. @@ -531,7 +581,12 @@ export interface LanguageService { * of code actions can be returned with the completions. * @param formattingSettings settings needed for calling formatting functions. */ - getCompletionsAtPosition(fileName: string, position: number, options: GetCompletionsAtPositionOptions | undefined, formattingSettings?: FormatCodeSettings): WithMetadata | undefined; + getCompletionsAtPosition( + fileName: string, + position: number, + options: GetCompletionsAtPositionOptions | undefined, + formattingSettings?: FormatCodeSettings, + ): WithMetadata | undefined; /** * Gets the extended details for a completion entry retrieved from `getCompletionsAtPosition`. @@ -554,7 +609,12 @@ export interface LanguageService { data: CompletionEntryData | undefined, ): CompletionEntryDetails | undefined; - getCompletionEntrySymbol(fileName: string, position: number, name: string, source: string | undefined): Symbol | undefined; + getCompletionEntrySymbol( + fileName: string, + position: number, + name: string, + source: string | undefined, + ): Symbol | undefined; /** * Gets semantic information about the identifier at a particular position in a @@ -569,22 +629,48 @@ export interface LanguageService { getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined; - getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined; + getSignatureHelpItems( + fileName: string, + position: number, + options: SignatureHelpItemsOptions | undefined, + ): SignatureHelpItems | undefined; getRenameInfo(fileName: string, position: number, preferences: UserPreferences): RenameInfo; /** @deprecated Use the signature with `UserPreferences` instead. */ getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo; - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, preferences: UserPreferences): readonly RenameLocation[] | undefined; + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + preferences: UserPreferences, + ): readonly RenameLocation[] | undefined; /** @deprecated Pass `providePrefixAndSuffixTextForRename` as part of a `UserPreferences` parameter. */ - findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): readonly RenameLocation[] | undefined; + findRenameLocations( + fileName: string, + position: number, + findInStrings: boolean, + findInComments: boolean, + providePrefixAndSuffixTextForRename?: boolean, + ): readonly RenameLocation[] | undefined; getSmartSelectionRange(fileName: string, position: number): SelectionRange; /** @internal */ - getDefinitionAtPosition(fileName: string, position: number, searchOtherFilesOnly: false, stopAtAlias: boolean): readonly DefinitionInfo[] | undefined; + getDefinitionAtPosition( + fileName: string, + position: number, + searchOtherFilesOnly: false, + stopAtAlias: boolean, + ): readonly DefinitionInfo[] | undefined; /** @internal */ - getDefinitionAtPosition(fileName: string, position: number, searchOtherFilesOnly: boolean, stopAtAlias: false): readonly DefinitionInfo[] | undefined; + getDefinitionAtPosition( + fileName: string, + position: number, + searchOtherFilesOnly: boolean, + stopAtAlias: false, + ): readonly DefinitionInfo[] | undefined; getDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined; getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined; getTypeDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined; @@ -592,10 +678,19 @@ export interface LanguageService { getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined; findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined; - getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] | undefined; + getDocumentHighlights( + fileName: string, + position: number, + filesToSearch: string[], + ): DocumentHighlights[] | undefined; getFileReferences(fileName: string): ReferenceEntry[]; - getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[]; + getNavigateToItems( + searchValue: string, + maxResultCount?: number, + fileName?: string, + excludeDtsFiles?: boolean, + ): NavigateToItem[]; getNavigationBarItems(fileName: string): NavigationBarItem[]; getNavigationTree(fileName: string): NavigationTree; @@ -603,18 +698,33 @@ export interface LanguageService { provideCallHierarchyIncomingCalls(fileName: string, position: number): CallHierarchyIncomingCall[]; provideCallHierarchyOutgoingCalls(fileName: string, position: number): CallHierarchyOutgoingCall[]; - provideInlayHints(fileName: string, span: TextSpan, preferences: UserPreferences | undefined): InlayHint[] + provideInlayHints(fileName: string, span: TextSpan, preferences: UserPreferences | undefined): InlayHint[]; getOutliningSpans(fileName: string): OutliningSpan[]; getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[]; getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[]; getIndentationAtPosition(fileName: string, position: number, options: EditorOptions | EditorSettings): number; - getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[]; + getFormattingEditsForRange( + fileName: string, + start: number, + end: number, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[]; getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[]; - getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[]; + getFormattingEditsAfterKeystroke( + fileName: string, + position: number, + key: string, + options: FormatCodeOptions | FormatCodeSettings, + ): TextChange[]; - getDocCommentTemplateAtPosition(fileName: string, position: number, options?: DocCommentTemplateOptions, formatOptions?: FormatCodeSettings): TextInsertion | undefined; + getDocCommentTemplateAtPosition( + fileName: string, + position: number, + options?: DocCommentTemplateOptions, + formatOptions?: FormatCodeSettings, + ): TextInsertion | undefined; isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; /** @@ -632,18 +742,42 @@ export interface LanguageService { /** @internal */ clearSourceMapperCache(): void; - getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: readonly number[], formatOptions: FormatCodeSettings, preferences: UserPreferences): readonly CodeFixAction[]; - getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions; - - applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise; - applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise; - applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise; + getCodeFixesAtPosition( + fileName: string, + start: number, + end: number, + errorCodes: readonly number[], + formatOptions: FormatCodeSettings, + preferences: UserPreferences, + ): readonly CodeFixAction[]; + getCombinedCodeFix( + scope: CombinedCodeFixScope, + fixId: {}, + formatOptions: FormatCodeSettings, + preferences: UserPreferences, + ): CombinedCodeActions; + + applyCodeActionCommand( + action: CodeActionCommand, + formatSettings?: FormatCodeSettings, + ): Promise; + applyCodeActionCommand( + action: CodeActionCommand[], + formatSettings?: FormatCodeSettings, + ): Promise; + applyCodeActionCommand( + action: CodeActionCommand | CodeActionCommand[], + formatSettings?: FormatCodeSettings, + ): Promise; /** @deprecated `fileName` will be ignored */ applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise; /** @deprecated `fileName` will be ignored */ applyCodeActionCommand(fileName: string, action: CodeActionCommand[]): Promise; /** @deprecated `fileName` will be ignored */ - applyCodeActionCommand(fileName: string, action: CodeActionCommand | CodeActionCommand[]): Promise; + applyCodeActionCommand( + fileName: string, + action: CodeActionCommand | CodeActionCommand[], + ): Promise; /** * @param includeInteractiveActions Include refactor actions that require additional arguments to be @@ -651,11 +785,41 @@ export interface LanguageService { * property of each returned `RefactorActionInfo` and ensure they are able to collect the appropriate * arguments for any interactive action before offering it. */ - getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string, includeInteractiveActions?: boolean): ApplicableRefactorInfo[]; - getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined, interactiveRefactorArguments?: InteractiveRefactorArguments): RefactorEditInfo | undefined; - getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string): { newFileName: string, files: string[] }; - organizeImports(args: OrganizeImportsArgs, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[]; - getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[]; + getApplicableRefactors( + fileName: string, + positionOrRange: number | TextRange, + preferences: UserPreferences | undefined, + triggerReason?: RefactorTriggerReason, + kind?: string, + includeInteractiveActions?: boolean, + ): ApplicableRefactorInfo[]; + getEditsForRefactor( + fileName: string, + formatOptions: FormatCodeSettings, + positionOrRange: number | TextRange, + refactorName: string, + actionName: string, + preferences: UserPreferences | undefined, + interactiveRefactorArguments?: InteractiveRefactorArguments, + ): RefactorEditInfo | undefined; + getMoveToRefactoringFileSuggestions( + fileName: string, + positionOrRange: number | TextRange, + preferences: UserPreferences | undefined, + triggerReason?: RefactorTriggerReason, + kind?: string, + ): { newFileName: string; files: string[]; }; + organizeImports( + args: OrganizeImportsArgs, + formatOptions: FormatCodeSettings, + preferences: UserPreferences | undefined, + ): readonly FileTextChanges[]; + getEditsForFileRename( + oldFilePath: string, + newFilePath: string, + formatOptions: FormatCodeSettings, + preferences: UserPreferences | undefined, + ): readonly FileTextChanges[]; getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean, forceDtsEmit?: boolean): EmitOutput; @@ -668,7 +832,10 @@ export interface LanguageService { /// Returns true if a suitable symbol was found in the project. /// May set isDefinition properties in `referencedSymbols` to false. /// May add elements to `knownSymbolSpans`. - /** @internal */ updateIsDefinitionOfReferencedSymbols(referencedSymbols: readonly ReferencedSymbol[], knownSymbolSpans: Set): boolean; + /** @internal */ updateIsDefinitionOfReferencedSymbols( + referencedSymbols: readonly ReferencedSymbol[], + knownSymbolSpans: Set, + ): boolean; toggleLineComment(fileName: string, textRange: TextRange): TextChange[]; toggleMultilineComment(fileName: string, textRange: TextRange): TextChange[]; @@ -689,7 +856,10 @@ export interface LinkedEditingInfo { wordPattern?: string; } -export interface CombinedCodeFixScope { type: "file"; fileName: string; } +export interface CombinedCodeFixScope { + type: "file"; + fileName: string; +} export const enum OrganizeImportsMode { All = "All", @@ -729,7 +899,7 @@ export interface GetCompletionsAtPositionOptions extends UserPreferences { * so use caution when serializing or retaining completion entries retrieved with this option. * @default false */ - includeSymbol?: boolean + includeSymbol?: boolean; /** @deprecated Use includeCompletionsForModuleExports */ includeExternalModuleExports?: boolean; /** @deprecated Use includeCompletionsWithInsertText */ @@ -1181,7 +1351,7 @@ export function getDefaultFormatCodeSettings(newLineCharacter?: string): FormatC placeOpenBraceOnNewLineForControlBlocks: false, semicolons: SemicolonPreference.Ignore, trimTrailingWhitespace: true, - indentSwitchCase: true + indentSwitchCase: true, }; } @@ -1436,7 +1606,7 @@ export interface CompletionEntry { * Included for non-string completions only when `includeSymbol: true` option is passed to `getCompletionsAtPosition`. * @example Get declaration of completion: `symbol.valueDeclaration` */ - symbol?: Symbol + symbol?: Symbol; /** * A property to be sent back to TS Server in the CompletionDetailsRequest, along with `name`, * that allows TS Server to look up the symbol represented by the completion item, disambiguating @@ -1456,7 +1626,7 @@ export interface CompletionEntryLabelDetails { export interface CompletionEntryDetails { name: string; kind: ScriptElementKind; - kindModifiers: string; // see ScriptElementKindModifier, comma separated + kindModifiers: string; // see ScriptElementKindModifier, comma separated displayParts: SymbolDisplayPart[]; documentation?: SymbolDisplayPart[]; tags?: JSDocTagInfo[]; @@ -1499,13 +1669,13 @@ export const enum OutliningSpanKind { Code = "code", /** Contiguous blocks of import declarations */ - Imports = "imports" + Imports = "imports", } export const enum OutputFileType { JavaScript, SourceMap, - Declaration + Declaration, } export const enum EndOfLineState { @@ -1562,8 +1732,16 @@ export interface Classifier { * subsume the classification. * @deprecated Use getLexicalClassifications instead. */ - getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent: boolean): ClassificationResult; - getEncodedLexicalClassifications(text: string, endOfLineState: EndOfLineState, syntacticClassifierAbsent: boolean): Classifications; + getClassificationsForLine( + text: string, + lexState: EndOfLineState, + syntacticClassifierAbsent: boolean, + ): ClassificationResult; + getEncodedLexicalClassifications( + text: string, + endOfLineState: EndOfLineState, + syntacticClassifierAbsent: boolean, + ): Classifications; } export const enum ScriptElementKind { @@ -1806,10 +1984,18 @@ export interface Refactor { kinds?: string[]; /** Compute the associated code actions */ - getEditsForAction(context: RefactorContext, actionName: string, interactiveRefactorArguments?: InteractiveRefactorArguments): RefactorEditInfo | undefined; + getEditsForAction( + context: RefactorContext, + actionName: string, + interactiveRefactorArguments?: InteractiveRefactorArguments, + ): RefactorEditInfo | undefined; /** Compute (quickly) which actions are available here */ - getAvailableActions(context: RefactorContext, includeInteractive?: boolean, interactiveRefactorArguments?: InteractiveRefactorArguments): readonly ApplicableRefactorInfo[]; + getAvailableActions( + context: RefactorContext, + includeInteractive?: boolean, + interactiveRefactorArguments?: InteractiveRefactorArguments, + ): readonly ApplicableRefactorInfo[]; } /** @internal */ diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 4d94041411e8b..c3a6b884f25ee 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -376,7 +376,7 @@ import { } from "./_namespaces/ts"; // These utilities are common to multiple language service features. -//#region +// #region /** @internal */ export const scanner: Scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); @@ -386,7 +386,7 @@ export const enum SemanticMeaning { Value = 0x1, Type = 0x2, Namespace = 0x4, - All = Value | Type | Namespace + All = Value | Type | Namespace, } /** @internal */ @@ -421,7 +421,8 @@ export function getMeaningFromDeclaration(node: Node): SemanticMeaning { case SyntaxKind.JSDocTypedefTag: // If it has no name node, it shares the name with the value declaration below it. - return (node as JSDocTypedefTag).name === undefined ? SemanticMeaning.Value | SemanticMeaning.Type : SemanticMeaning.Type; + return (node as JSDocTypedefTag).name === undefined ? SemanticMeaning.Value | SemanticMeaning.Type + : SemanticMeaning.Type; case SyntaxKind.EnumMember: case SyntaxKind.ClassDeclaration: @@ -462,12 +463,14 @@ export function getMeaningFromLocation(node: Node): SemanticMeaning { if (node.kind === SyntaxKind.SourceFile) { return SemanticMeaning.Value; } - else if (isExportAssignment(parent) + else if ( + isExportAssignment(parent) || isExportSpecifier(parent) || isExternalModuleReference(parent) || isImportSpecifier(parent) || isImportClause(parent) - || isImportEqualsDeclaration(parent) && node === parent.name) { + || isImportEqualsDeclaration(parent) && node === parent.name + ) { return SemanticMeaning.All; } else if (isInRightSideOfInternalImportEqualsDeclaration(node)) { @@ -502,8 +505,10 @@ function getMeaningFromRightHandSideOfImportEquals(node: Node): SemanticMeaning // import a = |b|; // Namespace // import a = |b.c|; // Value, type, namespace // import a = |b.c|.d; // Namespace - const name = node.kind === SyntaxKind.QualifiedName ? node : isQualifiedName(node.parent) && node.parent.right === node ? node.parent : undefined; - return name && name.parent.kind === SyntaxKind.ImportEqualsDeclaration ? SemanticMeaning.All : SemanticMeaning.Namespace; + const name = node.kind === SyntaxKind.QualifiedName ? node + : isQualifiedName(node.parent) && node.parent.right === node ? node.parent : undefined; + return name && name.parent.kind === SyntaxKind.ImportEqualsDeclaration ? SemanticMeaning.All + : SemanticMeaning.Namespace; } /** @internal */ @@ -543,10 +548,15 @@ function isPropertyAccessNamespaceReference(node: Node): boolean { isLastClause = (root as PropertyAccessExpression).name === node; } - if (!isLastClause && root.parent.kind === SyntaxKind.ExpressionWithTypeArguments && root.parent.parent.kind === SyntaxKind.HeritageClause) { + if ( + !isLastClause && root.parent.kind === SyntaxKind.ExpressionWithTypeArguments + && root.parent.parent.kind === SyntaxKind.HeritageClause + ) { const decl = root.parent.parent.parent; - return (decl.kind === SyntaxKind.ClassDeclaration && (root.parent.parent as HeritageClause).token === SyntaxKind.ImplementsKeyword) || - (decl.kind === SyntaxKind.InterfaceDeclaration && (root.parent.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword); + return (decl.kind === SyntaxKind.ClassDeclaration + && (root.parent.parent as HeritageClause).token === SyntaxKind.ImplementsKeyword) + || (decl.kind === SyntaxKind.InterfaceDeclaration + && (root.parent.parent as HeritageClause).token === SyntaxKind.ExtendsKeyword); } return false; @@ -577,33 +587,89 @@ function isTypeReference(node: Node): boolean { } /** @internal */ -export function isCallExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isCallExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions); +export function isCallExpressionTarget( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, +): boolean { + return isCalleeWorker( + node, + isCallExpression, + selectExpressionOfCallOrNewExpressionOrDecorator, + includeElementAccess, + skipPastOuterExpressions, + ); } /** @internal */ -export function isNewExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions); +export function isNewExpressionTarget( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, +): boolean { + return isCalleeWorker( + node, + isNewExpression, + selectExpressionOfCallOrNewExpressionOrDecorator, + includeElementAccess, + skipPastOuterExpressions, + ); } /** @internal */ -export function isCallOrNewExpressionTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isCallOrNewExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions); +export function isCallOrNewExpressionTarget( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, +): boolean { + return isCalleeWorker( + node, + isCallOrNewExpression, + selectExpressionOfCallOrNewExpressionOrDecorator, + includeElementAccess, + skipPastOuterExpressions, + ); } /** @internal */ -export function isTaggedTemplateTag(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isTaggedTemplateExpression, selectTagOfTaggedTemplateExpression, includeElementAccess, skipPastOuterExpressions); +export function isTaggedTemplateTag( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, +): boolean { + return isCalleeWorker( + node, + isTaggedTemplateExpression, + selectTagOfTaggedTemplateExpression, + includeElementAccess, + skipPastOuterExpressions, + ); } /** @internal */ export function isDecoratorTarget(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isDecorator, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions); + return isCalleeWorker( + node, + isDecorator, + selectExpressionOfCallOrNewExpressionOrDecorator, + includeElementAccess, + skipPastOuterExpressions, + ); } /** @internal */ -export function isJsxOpeningLikeElementTagName(node: Node, includeElementAccess = false, skipPastOuterExpressions = false): boolean { - return isCalleeWorker(node, isJsxOpeningLikeElement, selectTagNameOfJsxOpeningLikeElement, includeElementAccess, skipPastOuterExpressions); +export function isJsxOpeningLikeElementTagName( + node: Node, + includeElementAccess = false, + skipPastOuterExpressions = false, +): boolean { + return isCalleeWorker( + node, + isJsxOpeningLikeElement, + selectTagNameOfJsxOpeningLikeElement, + includeElementAccess, + skipPastOuterExpressions, + ); } function selectExpressionOfCallOrNewExpressionOrDecorator(node: CallExpression | NewExpression | Decorator) { @@ -618,7 +684,15 @@ function selectTagNameOfJsxOpeningLikeElement(node: JsxOpeningLikeElement) { return node.tagName; } -function isCalleeWorker(node: Node, pred: (node: Node) => node is T, calleeSelector: (node: T) => Expression | JsxTagNameExpression, includeElementAccess: boolean, skipPastOuterExpressions: boolean) { +function isCalleeWorker< + T extends CallExpression | NewExpression | TaggedTemplateExpression | Decorator | JsxOpeningLikeElement, +>( + node: Node, + pred: (node: Node) => node is T, + calleeSelector: (node: T) => Expression | JsxTagNameExpression, + includeElementAccess: boolean, + skipPastOuterExpressions: boolean, +) { let target = includeElementAccess ? climbPastPropertyOrElementAccess(node) : climbPastPropertyAccess(node); if (skipPastOuterExpressions) { target = skipOuterExpressions(target); @@ -639,7 +713,10 @@ export function climbPastPropertyOrElementAccess(node: Node) { /** @internal */ export function getTargetLabel(referenceNode: Node, labelName: string): Identifier | undefined { while (referenceNode) { - if (referenceNode.kind === SyntaxKind.LabeledStatement && (referenceNode as LabeledStatement).label.escapedText === labelName) { + if ( + referenceNode.kind === SyntaxKind.LabeledStatement + && (referenceNode as LabeledStatement).label.escapedText === labelName + ) { return (referenceNode as LabeledStatement).label; } referenceNode = referenceNode.parent; @@ -657,7 +734,7 @@ export function hasPropertyAccessExpressionWithName(node: CallExpression, funcNa } /** @internal */ -export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement } { +export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement; } { return isIdentifier(node) && tryCast(node.parent, isBreakOrContinueStatement)?.label === node; } @@ -702,7 +779,9 @@ export function isNameOfFunctionDeclaration(node: Node): boolean { } /** @internal */ -export function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: StringLiteral | NumericLiteral | NoSubstitutionTemplateLiteral): boolean { +export function isLiteralNameOfPropertyDeclarationOrIndexAccess( + node: StringLiteral | NumericLiteral | NoSubstitutionTemplateLiteral, +): boolean { switch (node.parent.kind) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: @@ -727,8 +806,8 @@ export function isLiteralNameOfPropertyDeclarationOrIndexAccess(node: StringLite /** @internal */ export function isExpressionOfExternalModuleImportEqualsDeclaration(node: Node) { - return isExternalModuleImportEqualsDeclaration(node.parent.parent) && - getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node; + return isExternalModuleImportEqualsDeclaration(node.parent.parent) + && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node; } /** @internal */ @@ -766,18 +845,21 @@ export function getContainerNode(node: Node): Declaration | undefined { export function getNodeKind(node: Node): ScriptElementKind { switch (node.kind) { case SyntaxKind.SourceFile: - return isExternalModule(node as SourceFile) ? ScriptElementKind.moduleElement : ScriptElementKind.scriptElement; + return isExternalModule(node as SourceFile) ? ScriptElementKind.moduleElement + : ScriptElementKind.scriptElement; case SyntaxKind.ModuleDeclaration: return ScriptElementKind.moduleElement; case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: return ScriptElementKind.classElement; - case SyntaxKind.InterfaceDeclaration: return ScriptElementKind.interfaceElement; + case SyntaxKind.InterfaceDeclaration: + return ScriptElementKind.interfaceElement; case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.JSDocCallbackTag: case SyntaxKind.JSDocTypedefTag: return ScriptElementKind.typeElement; - case SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement; + case SyntaxKind.EnumDeclaration: + return ScriptElementKind.enumElement; case SyntaxKind.VariableDeclaration: return getKindOfVariableDeclaration(node as VariableDeclaration); case SyntaxKind.BindingElement: @@ -786,28 +868,38 @@ export function getNodeKind(node: Node): ScriptElementKind { case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: return ScriptElementKind.functionElement; - case SyntaxKind.GetAccessor: return ScriptElementKind.memberGetAccessorElement; - case SyntaxKind.SetAccessor: return ScriptElementKind.memberSetAccessorElement; + case SyntaxKind.GetAccessor: + return ScriptElementKind.memberGetAccessorElement; + case SyntaxKind.SetAccessor: + return ScriptElementKind.memberSetAccessorElement; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: return ScriptElementKind.memberFunctionElement; case SyntaxKind.PropertyAssignment: const { initializer } = node as PropertyAssignment; - return isFunctionLike(initializer) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement; + return isFunctionLike(initializer) ? ScriptElementKind.memberFunctionElement + : ScriptElementKind.memberVariableElement; case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.SpreadAssignment: return ScriptElementKind.memberVariableElement; - case SyntaxKind.IndexSignature: return ScriptElementKind.indexSignatureElement; - case SyntaxKind.ConstructSignature: return ScriptElementKind.constructSignatureElement; - case SyntaxKind.CallSignature: return ScriptElementKind.callSignatureElement; + case SyntaxKind.IndexSignature: + return ScriptElementKind.indexSignatureElement; + case SyntaxKind.ConstructSignature: + return ScriptElementKind.constructSignatureElement; + case SyntaxKind.CallSignature: + return ScriptElementKind.callSignatureElement; case SyntaxKind.Constructor: case SyntaxKind.ClassStaticBlockDeclaration: return ScriptElementKind.constructorImplementationElement; - case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement; - case SyntaxKind.EnumMember: return ScriptElementKind.enumMemberElement; - case SyntaxKind.Parameter: return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; + case SyntaxKind.TypeParameter: + return ScriptElementKind.typeParameterElement; + case SyntaxKind.EnumMember: + return ScriptElementKind.enumMemberElement; + case SyntaxKind.Parameter: + return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) + ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ImportSpecifier: case SyntaxKind.ExportSpecifier: @@ -828,12 +920,14 @@ export function getNodeKind(node: Node): ScriptElementKind { const rightKind = getNodeKind(right); return rightKind === ScriptElementKind.unknown ? ScriptElementKind.constElement : rightKind; case AssignmentDeclarationKind.PrototypeProperty: - return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement; + return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement + : ScriptElementKind.memberVariableElement; case AssignmentDeclarationKind.ThisProperty: return ScriptElementKind.memberVariableElement; // property case AssignmentDeclarationKind.Property: // static method / property - return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement; + return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement + : ScriptElementKind.memberVariableElement; case AssignmentDeclarationKind.Prototype: return ScriptElementKind.localClassElement; default: { @@ -855,8 +949,8 @@ export function getNodeKind(node: Node): ScriptElementKind { return isVarConst(v) ? ScriptElementKind.constElement : isLet(v) - ? ScriptElementKind.letElement - : ScriptElementKind.variableElement; + ? ScriptElementKind.letElement + : ScriptElementKind.variableElement; } } @@ -1014,8 +1108,8 @@ function isCompletedNode(n: Node | undefined, sourceFile: SourceFile): boolean { return isCompletedNode((n as IfStatement).thenStatement, sourceFile); case SyntaxKind.ExpressionStatement: - return isCompletedNode((n as ExpressionStatement).expression, sourceFile) || - hasChildOfKind(n, SyntaxKind.SemicolonToken, sourceFile); + return isCompletedNode((n as ExpressionStatement).expression, sourceFile) + || hasChildOfKind(n, SyntaxKind.SemicolonToken, sourceFile); case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ArrayBindingPattern: @@ -1055,7 +1149,8 @@ function isCompletedNode(n: Node | undefined, sourceFile: SourceFile): boolean { case SyntaxKind.VoidExpression: case SyntaxKind.YieldExpression: case SyntaxKind.SpreadElement: - const unaryWordExpression = n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElement); + const unaryWordExpression = + n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElement); return isCompletedNode(unaryWordExpression.expression, sourceFile); case SyntaxKind.TaggedTemplateExpression: @@ -1117,7 +1212,7 @@ export function findListItemInfo(node: Node): ListItemInfo | undefined { return { listItemIndex, - list + list, }; } @@ -1137,7 +1232,10 @@ export function findContainingList(node: Node): SyntaxList | undefined { // be parented by the container of the SyntaxList, not the SyntaxList itself. // In order to find the list item index, we first need to locate SyntaxList itself and then search // for the position of the relevant node (or comma). - const syntaxList = find(node.parent.getChildren(), (c): c is SyntaxList => isSyntaxList(c) && rangeContainsRange(c, node)); + const syntaxList = find( + node.parent.getChildren(), + (c): c is SyntaxList => isSyntaxList(c) && rangeContainsRange(c, node), + ); // Either we didn't find an appropriate list, or the list must contain us. Debug.assert(!syntaxList || contains(syntaxList.getChildren(), node)); return syntaxList; @@ -1201,7 +1299,10 @@ function getAncestorTypeNode(node: Node) { } /** @internal */ -export function getContextualTypeFromParentOrAncestorTypeNode(node: Expression, checker: TypeChecker): Type | undefined { +export function getContextualTypeFromParentOrAncestorTypeNode( + node: Expression, + checker: TypeChecker, +): Type | undefined { if (node.flags & (NodeFlags.JSDoc & ~NodeFlags.JavaScriptFile)) return undefined; const contextualType = getContextualTypeFromParent(node, checker); @@ -1317,24 +1418,31 @@ function getAdjustedLocation(node: Node, forRename: boolean): Node { // // NOTE: If the node is a modifier, we don't adjust its location if it is the `default` modifier as that is handled // specially by `getSymbolAtLocation`. - if (isModifier(node) && (forRename || node.kind !== SyntaxKind.DefaultKeyword) ? canHaveModifiers(parent) && contains(parent.modifiers, node) : - node.kind === SyntaxKind.ClassKeyword ? isClassDeclaration(parent) || isClassExpression(node) : - node.kind === SyntaxKind.FunctionKeyword ? isFunctionDeclaration(parent) || isFunctionExpression(node) : - node.kind === SyntaxKind.InterfaceKeyword ? isInterfaceDeclaration(parent) : - node.kind === SyntaxKind.EnumKeyword ? isEnumDeclaration(parent) : - node.kind === SyntaxKind.TypeKeyword ? isTypeAliasDeclaration(parent) : - node.kind === SyntaxKind.NamespaceKeyword || node.kind === SyntaxKind.ModuleKeyword ? isModuleDeclaration(parent) : - node.kind === SyntaxKind.ImportKeyword ? isImportEqualsDeclaration(parent) : - node.kind === SyntaxKind.GetKeyword ? isGetAccessorDeclaration(parent) : - node.kind === SyntaxKind.SetKeyword && isSetAccessorDeclaration(parent)) { + if ( + isModifier(node) && (forRename || node.kind !== SyntaxKind.DefaultKeyword) + ? canHaveModifiers(parent) && contains(parent.modifiers, node) + : node.kind === SyntaxKind.ClassKeyword ? isClassDeclaration(parent) || isClassExpression(node) + : node.kind === SyntaxKind.FunctionKeyword ? isFunctionDeclaration(parent) || isFunctionExpression(node) + : node.kind === SyntaxKind.InterfaceKeyword ? isInterfaceDeclaration(parent) + : node.kind === SyntaxKind.EnumKeyword ? isEnumDeclaration(parent) + : node.kind === SyntaxKind.TypeKeyword ? isTypeAliasDeclaration(parent) + : node.kind === SyntaxKind.NamespaceKeyword || node.kind === SyntaxKind.ModuleKeyword + ? isModuleDeclaration(parent) + : node.kind === SyntaxKind.ImportKeyword ? isImportEqualsDeclaration(parent) + : node.kind === SyntaxKind.GetKeyword ? isGetAccessorDeclaration(parent) + : node.kind === SyntaxKind.SetKeyword && isSetAccessorDeclaration(parent) + ) { const location = getAdjustedLocationForDeclaration(parent, forRename); if (location) { return location; } } // /**/ [|name|] ... - if ((node.kind === SyntaxKind.VarKeyword || node.kind === SyntaxKind.ConstKeyword || node.kind === SyntaxKind.LetKeyword) && - isVariableDeclarationList(parent) && parent.declarations.length === 1) { + if ( + (node.kind === SyntaxKind.VarKeyword || node.kind === SyntaxKind.ConstKeyword + || node.kind === SyntaxKind.LetKeyword) + && isVariableDeclarationList(parent) && parent.declarations.length === 1 + ) { const decl = parent.declarations[0]; if (isIdentifier(decl.name)) { return decl.name; @@ -1367,10 +1475,12 @@ function getAdjustedLocation(node: Node, forRename: boolean): Node { // export { propertyName /**/as [|name|] } ... // export * /**/as [|name|] ... if (node.kind === SyntaxKind.AsKeyword) { - if (isImportSpecifier(parent) && parent.propertyName || - isExportSpecifier(parent) && parent.propertyName || - isNamespaceImport(parent) || - isNamespaceExport(parent)) { + if ( + isImportSpecifier(parent) && parent.propertyName + || isExportSpecifier(parent) && parent.propertyName + || isNamespaceImport(parent) + || isNamespaceExport(parent) + ) { return parent.name; } if (isExportDeclaration(parent) && parent.exportClause && isNamespaceExport(parent.exportClause)) { @@ -1412,7 +1522,10 @@ function getAdjustedLocation(node: Node, forRename: boolean): Node { } // import ... /**/from "[|module|]"; // export ... /**/from "[|module|]"; - if (node.kind === SyntaxKind.FromKeyword && (isImportDeclaration(parent) || isExportDeclaration(parent)) && parent.moduleSpecifier) { + if ( + node.kind === SyntaxKind.FromKeyword && (isImportDeclaration(parent) || isExportDeclaration(parent)) + && parent.moduleSpecifier + ) { return parent.moduleSpecifier; } // class ... /**/extends [|name|] ... @@ -1420,7 +1533,10 @@ function getAdjustedLocation(node: Node, forRename: boolean): Node { // class ... /**/implements name1, name2 ... // interface ... /**/extends [|name|] ... // interface ... /**/extends name1, name2 ... - if ((node.kind === SyntaxKind.ExtendsKeyword || node.kind === SyntaxKind.ImplementsKeyword) && isHeritageClause(parent) && parent.token === node.kind) { + if ( + (node.kind === SyntaxKind.ExtendsKeyword || node.kind === SyntaxKind.ImplementsKeyword) + && isHeritageClause(parent) && parent.token === node.kind + ) { const location = getAdjustedLocationForHeritageClause(parent); if (location) { return location; @@ -1445,13 +1561,19 @@ function getAdjustedLocation(node: Node, forRename: boolean): Node { return parent.name; } // /**/keyof [|T|] - if (node.kind === SyntaxKind.KeyOfKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.KeyOfKeyword && - isTypeReferenceNode(parent.type)) { + if ( + node.kind === SyntaxKind.KeyOfKeyword && isTypeOperatorNode(parent) + && parent.operator === SyntaxKind.KeyOfKeyword + && isTypeReferenceNode(parent.type) + ) { return parent.type.typeName; } // /**/readonly [|name|][] - if (node.kind === SyntaxKind.ReadonlyKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.ReadonlyKeyword && - isArrayTypeNode(parent.type) && isTypeReferenceNode(parent.type.elementType)) { + if ( + node.kind === SyntaxKind.ReadonlyKeyword && isTypeOperatorNode(parent) + && parent.operator === SyntaxKind.ReadonlyKeyword + && isArrayTypeNode(parent.type) && isTypeReferenceNode(parent.type.elementType) + ) { return parent.type.elementType.typeName; } if (!forRename) { @@ -1465,19 +1587,24 @@ function getAdjustedLocation(node: Node, forRename: boolean): Node { // /**/yield [|name|] // /**/yield obj.[|name|] // /**/delete obj.[|name|] - if (node.kind === SyntaxKind.NewKeyword && isNewExpression(parent) || - node.kind === SyntaxKind.VoidKeyword && isVoidExpression(parent) || - node.kind === SyntaxKind.TypeOfKeyword && isTypeOfExpression(parent) || - node.kind === SyntaxKind.AwaitKeyword && isAwaitExpression(parent) || - node.kind === SyntaxKind.YieldKeyword && isYieldExpression(parent) || - node.kind === SyntaxKind.DeleteKeyword && isDeleteExpression(parent)) { + if ( + node.kind === SyntaxKind.NewKeyword && isNewExpression(parent) + || node.kind === SyntaxKind.VoidKeyword && isVoidExpression(parent) + || node.kind === SyntaxKind.TypeOfKeyword && isTypeOfExpression(parent) + || node.kind === SyntaxKind.AwaitKeyword && isAwaitExpression(parent) + || node.kind === SyntaxKind.YieldKeyword && isYieldExpression(parent) + || node.kind === SyntaxKind.DeleteKeyword && isDeleteExpression(parent) + ) { if (parent.expression) { return skipOuterExpressions(parent.expression); } } // left /**/in [|name|] // left /**/instanceof [|name|] - if ((node.kind === SyntaxKind.InKeyword || node.kind === SyntaxKind.InstanceOfKeyword) && isBinaryExpression(parent) && parent.operatorToken === node) { + if ( + (node.kind === SyntaxKind.InKeyword || node.kind === SyntaxKind.InstanceOfKeyword) + && isBinaryExpression(parent) && parent.operatorToken === node + ) { return skipOuterExpressions(parent.right); } // left /**/as [|name|] @@ -1486,8 +1613,10 @@ function getAdjustedLocation(node: Node, forRename: boolean): Node { } // for (... /**/in [|name|]) // for (... /**/of [|name|]) - if (node.kind === SyntaxKind.InKeyword && isForInStatement(parent) || - node.kind === SyntaxKind.OfKeyword && isForOfStatement(parent)) { + if ( + node.kind === SyntaxKind.InKeyword && isForInStatement(parent) + || node.kind === SyntaxKind.OfKeyword && isForOfStatement(parent) + ) { return skipOuterExpressions(parent.expression); } } @@ -1520,7 +1649,11 @@ export function getAdjustedRenameLocation(node: Node): Node { * @internal */ export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node { - return getTouchingToken(sourceFile, position, n => isPropertyNameLiteral(n) || isKeyword(n.kind) || isPrivateIdentifier(n)); + return getTouchingToken( + sourceFile, + position, + n => isPropertyNameLiteral(n) || isKeyword(n.kind) || isPrivateIdentifier(n), + ); } /** @@ -1529,8 +1662,18 @@ export function getTouchingPropertyName(sourceFile: SourceFile, position: number * * @internal */ -export function getTouchingToken(sourceFile: SourceFile, position: number, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includePrecedingTokenAtEndPosition, /*includeEndPosition*/ false); +export function getTouchingToken( + sourceFile: SourceFile, + position: number, + includePrecedingTokenAtEndPosition?: (n: Node) => boolean, +): Node { + return getTokenAtPositionWorker( + sourceFile, + position, + /*allowPositionInLeadingTrivia*/ false, + includePrecedingTokenAtEndPosition, + /*includeEndPosition*/ false, + ); } /** @@ -1539,14 +1682,27 @@ export function getTouchingToken(sourceFile: SourceFile, position: number, inclu * @internal */ export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false); + return getTokenAtPositionWorker( + sourceFile, + position, + /*allowPositionInLeadingTrivia*/ true, + /*includePrecedingTokenAtEndPosition*/ undefined, + /*includeEndPosition*/ false, + ); } /** Get the token whose text contains the position */ -function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includePrecedingTokenAtEndPosition: ((n: Node) => boolean) | undefined, includeEndPosition: boolean): Node { +function getTokenAtPositionWorker( + sourceFile: SourceFile, + position: number, + allowPositionInLeadingTrivia: boolean, + includePrecedingTokenAtEndPosition: ((n: Node) => boolean) | undefined, + includeEndPosition: boolean, +): Node { let current: Node = sourceFile; let foundToken: Node | undefined; - outer: while (true) { + outer: + while (true) { // find the child that contains 'position' const children = current.getChildren(sourceFile); @@ -1572,7 +1728,6 @@ function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allo // kind. Meanwhile, if includePrecedingTokenAtEndPosition is unset, we look for the first node whose start is <= the // position and whose end is greater than the position. - // There are more sophisticated end tests later, but this one is very fast // and allows us to skip a bunch of work const end = children[middle].getEnd(); @@ -1580,7 +1735,8 @@ function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allo return Comparison.LessThan; } - const start = allowPositionInLeadingTrivia ? children[middle].getFullStart() : children[middle].getStart(sourceFile, /*includeJsDocComment*/ true); + const start = allowPositionInLeadingTrivia ? children[middle].getFullStart() + : children[middle].getStart(sourceFile, /*includeJsDocComment*/ true); if (start > position) { return Comparison.GreaterThan; } @@ -1597,7 +1753,10 @@ function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allo } // this complex condition makes us left-recur around a zero-length node when includePrecedingTokenAtEndPosition is set, rather than right-recur on it - if (includePrecedingTokenAtEndPosition && start === position && children[middle - 1] && children[middle - 1].getEnd() === position && nodeContainsPosition(children[middle - 1])) { + if ( + includePrecedingTokenAtEndPosition && start === position && children[middle - 1] + && children[middle - 1].getEnd() === position && nodeContainsPosition(children[middle - 1]) + ) { return Comparison.GreaterThan; } return Comparison.LessThan; @@ -1619,7 +1778,8 @@ function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allo if (end < position) { return false; } - start ??= allowPositionInLeadingTrivia ? node.getFullStart() : node.getStart(sourceFile, /*includeJsDocComment*/ true); + start ??= allowPositionInLeadingTrivia ? node.getFullStart() + : node.getStart(sourceFile, /*includeJsDocComment*/ true); if (start > position) { // If this child begins after position, then all subsequent children will as well. return false; @@ -1661,7 +1821,6 @@ export function findFirstNonJsxWhitespaceToken(sourceFile: SourceFile, position: * fo|o -> will return foo * foo |bar -> will return foo * - * * @internal */ export function findTokenOnLeftOfPosition(file: SourceFile, position: number): Node | undefined { @@ -1687,9 +1846,9 @@ export function findNextToken(previousToken: Node, parent: Node, sourceFile: Sou return firstDefined(n.getChildren(sourceFile), child => { const shouldDiveInChildNode = // previous token is enclosed somewhere in the child - (child.pos <= previousToken.pos && child.end > previousToken.end) || + (child.pos <= previousToken.pos && child.end > previousToken.end) // previous token ends exactly at the beginning of child - (child.pos === previousToken.end); + || (child.pos === previousToken.end); return shouldDiveInChildNode && nodeHasTokens(child, sourceFile) ? find(child) : undefined; }); } @@ -1701,11 +1860,26 @@ export function findNextToken(previousToken: Node, parent: Node, sourceFile: Sou * * @internal */ -export function findPrecedingToken(position: number, sourceFile: SourceFileLike, startNode: Node, excludeJsdoc?: boolean): Node | undefined; -/** @internal */ -export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node, excludeJsdoc?: boolean): Node | undefined; -/** @internal */ -export function findPrecedingToken(position: number, sourceFile: SourceFileLike, startNode?: Node, excludeJsdoc?: boolean): Node | undefined { +export function findPrecedingToken( + position: number, + sourceFile: SourceFileLike, + startNode: Node, + excludeJsdoc?: boolean, +): Node | undefined; +/** @internal */ +export function findPrecedingToken( + position: number, + sourceFile: SourceFile, + startNode?: Node, + excludeJsdoc?: boolean, +): Node | undefined; +/** @internal */ +export function findPrecedingToken( + position: number, + sourceFile: SourceFileLike, + startNode?: Node, + excludeJsdoc?: boolean, +): Node | undefined { const result = find((startNode || sourceFile) as Node); Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result))); return result; @@ -1739,17 +1913,24 @@ export function findPrecedingToken(position: number, sourceFile: SourceFileLike, // 2) `position` is within the same span: we recurse on `child`. if (position < child.end) { const start = child.getStart(sourceFile, /*includeJsDoc*/ !excludeJsdoc); - const lookInPreviousChild = - (start >= position) || // cursor in the leading trivia - !nodeHasTokens(child, sourceFile) || - isWhiteSpaceOnlyJsxText(child); + const lookInPreviousChild = (start >= position) // cursor in the leading trivia + || !nodeHasTokens(child, sourceFile) + || isWhiteSpaceOnlyJsxText(child); if (lookInPreviousChild) { // actual start of the node is past the position - previous token should be at the end of previous child - const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i, sourceFile, n.kind); + const candidate = findRightmostChildNodeWithTokens( + children, + /*exclusiveStartPosition*/ i, + sourceFile, + n.kind, + ); if (candidate) { // Ensure we recurse into JSDoc nodes with children. - if (!excludeJsdoc && isJSDocCommentContainingNode(candidate) && candidate.getChildren(sourceFile).length) { + if ( + !excludeJsdoc && isJSDocCommentContainingNode(candidate) + && candidate.getChildren(sourceFile).length + ) { return find(candidate); } return findRightmostToken(candidate, sourceFile); @@ -1763,13 +1944,21 @@ export function findPrecedingToken(position: number, sourceFile: SourceFileLike, } } - Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || n.kind === SyntaxKind.EndOfFileToken || isJSDocCommentContainingNode(n)); + Debug.assert( + startNode !== undefined || n.kind === SyntaxKind.SourceFile || n.kind === SyntaxKind.EndOfFileToken + || isJSDocCommentContainingNode(n), + ); // Here we know that none of child token nodes embrace the position, // the only known case is when position is at the end of the file. // Try to find the rightmost token in the file without filtering. // Namely we are skipping the check: 'position < node.end' - const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile, n.kind); + const candidate = findRightmostChildNodeWithTokens( + children, + /*exclusiveStartPosition*/ children.length, + sourceFile, + n.kind, + ); return candidate && findRightmostToken(candidate, sourceFile); } } @@ -1788,14 +1977,24 @@ function findRightmostToken(n: Node, sourceFile: SourceFileLike): Node | undefin return n; } - const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile, n.kind); + const candidate = findRightmostChildNodeWithTokens( + children, + /*exclusiveStartPosition*/ children.length, + sourceFile, + n.kind, + ); return candidate && findRightmostToken(candidate, sourceFile); } /** * Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens. */ -function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number, sourceFile: SourceFileLike, parentKind: SyntaxKind): Node | undefined { +function findRightmostChildNodeWithTokens( + children: Node[], + exclusiveStartPosition: number, + sourceFile: SourceFileLike, + parentKind: SyntaxKind, +): Node | undefined { for (let i = exclusiveStartPosition - 1; i >= 0; i--) { const child = children[i]; @@ -1811,7 +2010,11 @@ function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPositi } /** @internal */ -export function isInString(sourceFile: SourceFile, position: number, previousToken = findPrecedingToken(position, sourceFile)): boolean { +export function isInString( + sourceFile: SourceFile, + position: number, + previousToken = findPrecedingToken(position, sourceFile), +): boolean { if (previousToken && isStringTextContainingNode(previousToken)) { const start = previousToken.getStart(sourceFile); const end = previousToken.getEnd(); @@ -1833,7 +2036,6 @@ export function isInString(sourceFile: SourceFile, position: number, previousTok } /** - * * @internal */ export function isInsideJsxElementOrAttribute(sourceFile: SourceFile, position: number) { @@ -1888,10 +2090,15 @@ export function isInJSXText(sourceFile: SourceFile, position: number) { if (isJsxText(token)) { return true; } - if (token.kind === SyntaxKind.OpenBraceToken && isJsxExpression(token.parent) && isJsxElement(token.parent.parent)) { + if ( + token.kind === SyntaxKind.OpenBraceToken && isJsxExpression(token.parent) && isJsxElement(token.parent.parent) + ) { return true; } - if (token.kind === SyntaxKind.LessThanToken && isJsxOpeningLikeElement(token.parent) && isJsxElement(token.parent.parent)) { + if ( + token.kind === SyntaxKind.LessThanToken && isJsxOpeningLikeElement(token.parent) + && isJsxElement(token.parent.parent) + ) { return true; } return false; @@ -1901,14 +2108,16 @@ export function isInJSXText(sourceFile: SourceFile, position: number) { export function isInsideJsxElement(sourceFile: SourceFile, position: number): boolean { function isInsideJsxElementTraversal(node: Node): boolean { while (node) { - if (node.kind >= SyntaxKind.JsxSelfClosingElement && node.kind <= SyntaxKind.JsxExpression + if ( + node.kind >= SyntaxKind.JsxSelfClosingElement && node.kind <= SyntaxKind.JsxExpression || node.kind === SyntaxKind.JsxText || node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.GreaterThanToken || node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.CloseBraceToken || node.kind === SyntaxKind.OpenBraceToken - || node.kind === SyntaxKind.SlashToken) { + || node.kind === SyntaxKind.SlashToken + ) { node = node.parent; } else if (node.kind === SyntaxKind.JsxElement) { @@ -1928,7 +2137,11 @@ export function isInsideJsxElement(sourceFile: SourceFile, position: number): bo } /** @internal */ -export function findPrecedingMatchingToken(token: Node, matchingTokenKind: SyntaxKind.OpenBraceToken | SyntaxKind.OpenParenToken | SyntaxKind.OpenBracketToken, sourceFile: SourceFile) { +export function findPrecedingMatchingToken( + token: Node, + matchingTokenKind: SyntaxKind.OpenBraceToken | SyntaxKind.OpenParenToken | SyntaxKind.OpenBracketToken, + sourceFile: SourceFile, +) { const closeTokenText = tokenToString(token.kind)!; const matchingTokenText = tokenToString(matchingTokenKind)!; const tokenFullStart = token.getFullStart(); @@ -1969,28 +2182,34 @@ export function findPrecedingMatchingToken(token: Node, matchingTokenKind: Synta /** @internal */ export function removeOptionality(type: Type, isOptionalExpression: boolean, isOptionalChain: boolean) { - return isOptionalExpression ? type.getNonNullableType() : - isOptionalChain ? type.getNonOptionalType() : - type; + return isOptionalExpression ? type.getNonNullableType() + : isOptionalChain ? type.getNonOptionalType() + : type; } /** @internal */ export function isPossiblyTypeArgumentPosition(token: Node, sourceFile: SourceFile, checker: TypeChecker): boolean { const info = getPossibleTypeArgumentsInfo(token, sourceFile); - return info !== undefined && (isPartOfTypeNode(info.called) || - getPossibleGenericSignatures(info.called, info.nTypeArguments, checker).length !== 0 || - isPossiblyTypeArgumentPosition(info.called, sourceFile, checker)); + return info !== undefined && (isPartOfTypeNode(info.called) + || getPossibleGenericSignatures(info.called, info.nTypeArguments, checker).length !== 0 + || isPossiblyTypeArgumentPosition(info.called, sourceFile, checker)); } /** @internal */ -export function getPossibleGenericSignatures(called: Expression, typeArgumentCount: number, checker: TypeChecker): readonly Signature[] { +export function getPossibleGenericSignatures( + called: Expression, + typeArgumentCount: number, + checker: TypeChecker, +): readonly Signature[] { let type = checker.getTypeAtLocation(called); if (isOptionalChain(called.parent)) { type = removeOptionality(type, isOptionalChainRoot(called.parent), /*isOptionalChain*/ true); } const signatures = isNewExpression(called.parent) ? type.getConstructSignatures() : type.getCallSignatures(); - return signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= typeArgumentCount); + return signatures.filter(candidate => + !!candidate.typeParameters && candidate.typeParameters.length >= typeArgumentCount + ); } /** @internal */ @@ -2006,7 +2225,10 @@ export interface PossibleProgramFileInfo { // Get info for an expression like `f <` that may be the start of type arguments. /** @internal */ -export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFile: SourceFile): PossibleTypeArgumentInfo | undefined { +export function getPossibleTypeArgumentsInfo( + tokenIn: Node | undefined, + sourceFile: SourceFile, +): PossibleTypeArgumentInfo | undefined { // This is a rare case, but one that saves on a _lot_ of work if true - if the source file has _no_ `<` character, // then there obviously can't be any type arguments - no expensive brace-matching backwards scanning required @@ -2038,11 +2260,11 @@ export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFi break; case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - remainingLessThanTokens = + 3; + remainingLessThanTokens = +3; break; case SyntaxKind.GreaterThanGreaterThanToken: - remainingLessThanTokens = + 2; + remainingLessThanTokens = +2; break; case SyntaxKind.GreaterThanToken: @@ -2077,7 +2299,6 @@ export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFi case SyntaxKind.EqualsGreaterThanToken: // falls through - case SyntaxKind.Identifier: case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: @@ -2085,7 +2306,6 @@ export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFi case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: // falls through - case SyntaxKind.TypeOfKeyword: case SyntaxKind.ExtendsKeyword: case SyntaxKind.KeyOfKeyword: @@ -2118,7 +2338,11 @@ export function getPossibleTypeArgumentsInfo(tokenIn: Node | undefined, sourceFi * * @internal */ -export function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition?: Node): CommentRange | undefined { +export function isInComment( + sourceFile: SourceFile, + position: number, + tokenAtPosition?: Node, +): CommentRange | undefined { return formatting.getRangeOfEnclosingComment(sourceFile, position, /*precedingToken*/ undefined, tokenAtPosition); } @@ -2144,7 +2368,9 @@ export function getNodeModifiers(node: Node, excludeFlags = ModifierFlags.None): if (flags & ModifierFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); if (flags & ModifierFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier); if (flags & ModifierFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); - if (flags & ModifierFlags.Static || isClassStaticBlockDeclaration(node)) result.push(ScriptElementKindModifier.staticModifier); + if (flags & ModifierFlags.Static || isClassStaticBlockDeclaration(node)) { + result.push(ScriptElementKindModifier.staticModifier); + } if (flags & ModifierFlags.Abstract) result.push(ScriptElementKindModifier.abstractModifier); if (flags & ModifierFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); if (flags & ModifierFlags.Deprecated) result.push(ScriptElementKindModifier.deprecatedModifier); @@ -2160,7 +2386,10 @@ export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray return (node as CallExpression).typeArguments; } - if (isFunctionLike(node) || node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.InterfaceDeclaration) { + if ( + isFunctionLike(node) || node.kind === SyntaxKind.ClassDeclaration + || node.kind === SyntaxKind.InterfaceDeclaration + ) { return (node as FunctionLikeDeclaration).typeParameters; } @@ -2174,9 +2403,11 @@ export function isComment(kind: SyntaxKind): boolean { /** @internal */ export function isStringOrRegularExpressionOrTemplateLiteral(kind: SyntaxKind): boolean { - if (kind === SyntaxKind.StringLiteral + if ( + kind === SyntaxKind.StringLiteral || kind === SyntaxKind.RegularExpressionLiteral - || isTemplateLiteralKind(kind)) { + || isTemplateLiteralKind(kind) + ) { return true; } return false; @@ -2193,14 +2424,16 @@ export function isStringAndEmptyAnonymousObjectIntersection(type: Type) { } const { types, checker } = type; - return types.length === 2 && - (areIntersectedTypesAvoidingStringReduction(checker, types[0], types[1]) || areIntersectedTypesAvoidingStringReduction(checker, types[1], types[0])); + return types.length === 2 + && (areIntersectedTypesAvoidingStringReduction(checker, types[0], types[1]) + || areIntersectedTypesAvoidingStringReduction(checker, types[1], types[0])); } /** @internal */ export function isInsideTemplateLiteral(node: TemplateLiteralToken, position: number, sourceFile: SourceFile): boolean { return isTemplateLiteralKind(node.kind) - && (node.getStart(sourceFile) < position && position < node.end) || (!!node.isUnterminated && position === node.end); + && (node.getStart(sourceFile) < position && position < node.end) + || (!!node.isUnterminated && position === node.end); } /** @internal */ @@ -2224,20 +2457,26 @@ export function cloneCompilerOptions(options: CompilerOptions): CompilerOptions /** @internal */ export function isArrayLiteralOrObjectLiteralDestructuringPattern(node: Node) { - if (node.kind === SyntaxKind.ArrayLiteralExpression || - node.kind === SyntaxKind.ObjectLiteralExpression) { + if ( + node.kind === SyntaxKind.ArrayLiteralExpression + || node.kind === SyntaxKind.ObjectLiteralExpression + ) { // [a,b,c] from: // [a, b, c] = someExpression; - if (node.parent.kind === SyntaxKind.BinaryExpression && - (node.parent as BinaryExpression).left === node && - (node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { + if ( + node.parent.kind === SyntaxKind.BinaryExpression + && (node.parent as BinaryExpression).left === node + && (node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken + ) { return true; } // [a, b, c] from: // for([a, b, c] of expression) - if (node.parent.kind === SyntaxKind.ForOfStatement && - (node.parent as ForOfStatement).initializer === node) { + if ( + node.parent.kind === SyntaxKind.ForOfStatement + && (node.parent as ForOfStatement).initializer === node + ) { return true; } @@ -2245,7 +2484,11 @@ export function isArrayLiteralOrObjectLiteralDestructuringPattern(node: Node) { // [x, [a, b, c] ] = someExpression // or // {x, a: {a, b, c} } = someExpression - if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent)) { + if ( + isArrayLiteralOrObjectLiteralDestructuringPattern( + node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent, + ) + ) { return true; } } @@ -2265,7 +2508,8 @@ export function isInNonReferenceComment(sourceFile: SourceFile, position: number function isInReferenceCommentWorker(sourceFile: SourceFile, position: number, shouldBeReference: boolean): boolean { const range = isInComment(sourceFile, position, /*tokenAtPosition*/ undefined); - return !!range && shouldBeReference === tripleSlashDirectivePrefixRegex.test(sourceFile.text.substring(range.pos, range.end)); + return !!range + && shouldBeReference === tripleSlashDirectivePrefixRegex.test(sourceFile.text.substring(range.pos, range.end)); } /** @internal */ @@ -2362,7 +2606,8 @@ export function isTypeKeywordTokenOrIdentifier(node: Node) { * @internal */ export function isExternalModuleSymbol(moduleSymbol: Symbol): boolean { - return !!(moduleSymbol.flags & SymbolFlags.Module) && moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote; + return !!(moduleSymbol.flags & SymbolFlags.Module) + && moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote; } /** @@ -2409,20 +2654,29 @@ export function getNameFromPropertyName(name: PropertyName): string | undefined /** @internal */ export function programContainsModules(program: Program): boolean { - return program.getSourceFiles().some(s => !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!(s.externalModuleIndicator || s.commonJsModuleIndicator)); + return program.getSourceFiles().some(s => + !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) + && !!(s.externalModuleIndicator || s.commonJsModuleIndicator) + ); } /** @internal */ export function programContainsEsModules(program: Program): boolean { - return program.getSourceFiles().some(s => !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!s.externalModuleIndicator); + return program.getSourceFiles().some(s => + !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!s.externalModuleIndicator + ); } // TODO: this function is, at best, poorly named. Use sites are pretty suspicious. /** @internal */ export function compilerOptionsIndicateEsModules(compilerOptions: CompilerOptions): boolean { - return !!compilerOptions.module || getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 || !!compilerOptions.noEmit; + return !!compilerOptions.module || getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 + || !!compilerOptions.noEmit; } /** @internal */ -export function createModuleSpecifierResolutionHost(program: Program, host: LanguageServiceHost): ModuleSpecifierResolutionHost { +export function createModuleSpecifierResolutionHost( + program: Program, + host: LanguageServiceHost, +): ModuleSpecifierResolutionHost { // Mix in `getSymlinkCache` from Program when host doesn't have it // in order for non-Project hosts to have a symlinks cache. return { @@ -2443,7 +2697,10 @@ export function createModuleSpecifierResolutionHost(program: Program, host: Lang } /** @internal */ -export function getModuleSpecifierResolverHost(program: Program, host: LanguageServiceHost): SymbolTracker["moduleResolverHost"] { +export function getModuleSpecifierResolverHost( + program: Program, + host: LanguageServiceHost, +): SymbolTracker["moduleResolverHost"] { return { ...createModuleSpecifierResolutionHost(program, host), getCommonSourceDirectory: () => program.getCommonSourceDirectory(), @@ -2458,19 +2715,36 @@ export function moduleResolutionUsesNodeModules(moduleResolution: ModuleResoluti } /** @internal */ -export function makeImportIfNecessary(defaultImport: Identifier | undefined, namedImports: readonly ImportSpecifier[] | undefined, moduleSpecifier: string, quotePreference: QuotePreference): ImportDeclaration | undefined { - return defaultImport || namedImports && namedImports.length ? makeImport(defaultImport, namedImports, moduleSpecifier, quotePreference) : undefined; +export function makeImportIfNecessary( + defaultImport: Identifier | undefined, + namedImports: readonly ImportSpecifier[] | undefined, + moduleSpecifier: string, + quotePreference: QuotePreference, +): ImportDeclaration | undefined { + return defaultImport || namedImports && namedImports.length + ? makeImport(defaultImport, namedImports, moduleSpecifier, quotePreference) : undefined; } /** @internal */ -export function makeImport(defaultImport: Identifier | undefined, namedImports: readonly ImportSpecifier[] | undefined, moduleSpecifier: string | Expression, quotePreference: QuotePreference, isTypeOnly?: boolean): ImportDeclaration { +export function makeImport( + defaultImport: Identifier | undefined, + namedImports: readonly ImportSpecifier[] | undefined, + moduleSpecifier: string | Expression, + quotePreference: QuotePreference, + isTypeOnly?: boolean, +): ImportDeclaration { return factory.createImportDeclaration( /*modifiers*/ undefined, defaultImport || namedImports - ? factory.createImportClause(!!isTypeOnly, defaultImport, namedImports && namedImports.length ? factory.createNamedImports(namedImports) : undefined) + ? factory.createImportClause( + !!isTypeOnly, + defaultImport, + namedImports && namedImports.length ? factory.createNamedImports(namedImports) : undefined, + ) : undefined, typeof moduleSpecifier === "string" ? makeStringLiteral(moduleSpecifier, quotePreference) : moduleSpecifier, - /*assertClause*/ undefined); + /*assertClause*/ undefined, + ); } /** @internal */ @@ -2479,7 +2753,10 @@ export function makeStringLiteral(text: string, quotePreference: QuotePreference } /** @internal */ -export const enum QuotePreference { Single, Double } +export const enum QuotePreference { + Single, + Double, +} /** @internal */ export function quotePreferenceFromString(str: StringLiteral, sourceFile: SourceFile): QuotePreference { @@ -2493,18 +2770,22 @@ export function getQuotePreference(sourceFile: SourceFile, preferences: UserPref } else { // ignore synthetic import added when importHelpers: true - const firstModuleSpecifier = sourceFile.imports && - find(sourceFile.imports, n => isStringLiteral(n) && !nodeIsSynthesized(n.parent)) as StringLiteral; - return firstModuleSpecifier ? quotePreferenceFromString(firstModuleSpecifier, sourceFile) : QuotePreference.Double; + const firstModuleSpecifier = sourceFile.imports + && find(sourceFile.imports, n => isStringLiteral(n) && !nodeIsSynthesized(n.parent)) as StringLiteral; + return firstModuleSpecifier ? quotePreferenceFromString(firstModuleSpecifier, sourceFile) + : QuotePreference.Double; } } /** @internal */ export function getQuoteFromPreference(qp: QuotePreference): string { switch (qp) { - case QuotePreference.Single: return "'"; - case QuotePreference.Double: return '"'; - default: return Debug.assertNever(qp); + case QuotePreference.Single: + return "'"; + case QuotePreference.Double: + return '"'; + default: + return Debug.assertNever(qp); } } @@ -2529,25 +2810,31 @@ export function symbolEscapedNameNoDefault(symbol: Symbol): __String | undefined /** @internal */ export function isModuleSpecifierLike(node: Node): node is StringLiteralLike { return isStringLiteralLike(node) && ( - isExternalModuleReference(node.parent) || - isImportDeclaration(node.parent) || - isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) && node.parent.arguments[0] === node || - isImportCall(node.parent) && node.parent.arguments[0] === node); + isExternalModuleReference(node.parent) + || isImportDeclaration(node.parent) + || isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) && node.parent.arguments[0] === node + || isImportCall(node.parent) && node.parent.arguments[0] === node + ); } /** @internal */ -export type ObjectBindingElementWithoutPropertyName = BindingElement & { name: Identifier }; +export type ObjectBindingElementWithoutPropertyName = BindingElement & { name: Identifier; }; /** @internal */ -export function isObjectBindingElementWithoutPropertyName(bindingElement: Node): bindingElement is ObjectBindingElementWithoutPropertyName { - return isBindingElement(bindingElement) && - isObjectBindingPattern(bindingElement.parent) && - isIdentifier(bindingElement.name) && - !bindingElement.propertyName; +export function isObjectBindingElementWithoutPropertyName( + bindingElement: Node, +): bindingElement is ObjectBindingElementWithoutPropertyName { + return isBindingElement(bindingElement) + && isObjectBindingPattern(bindingElement.parent) + && isIdentifier(bindingElement.name) + && !bindingElement.propertyName; } /** @internal */ -export function getPropertySymbolFromBindingElement(checker: TypeChecker, bindingElement: ObjectBindingElementWithoutPropertyName): Symbol | undefined { +export function getPropertySymbolFromBindingElement( + checker: TypeChecker, + bindingElement: ObjectBindingElementWithoutPropertyName, +): Symbol | undefined { const typeOfPattern = checker.getTypeAtLocation(bindingElement.parent); return typeOfPattern && checker.getPropertyOfType(typeOfPattern, bindingElement.name.text); } @@ -2566,8 +2853,8 @@ export function getParentNodeInSpan(node: Node | undefined, file: SourceFile, sp } function spanContainsNode(span: TextSpan, node: Node, file: SourceFile): boolean { - return textSpanContainsPosition(span, node.getStart(file)) && - node.getEnd() <= textSpanEnd(span); + return textSpanContainsPosition(span, node.getStart(file)) + && node.getEnd() <= textSpanEnd(span); } /** @internal */ @@ -2576,25 +2863,47 @@ export function findModifier(node: Node, kind: Modifier["kind"]): Modifier | und } /** @internal */ -export function insertImports(changes: textChanges.ChangeTracker, sourceFile: SourceFile, imports: AnyImportOrRequireStatement | readonly AnyImportOrRequireStatement[], blankLineBetween: boolean, preferences: UserPreferences): void { +export function insertImports( + changes: textChanges.ChangeTracker, + sourceFile: SourceFile, + imports: AnyImportOrRequireStatement | readonly AnyImportOrRequireStatement[], + blankLineBetween: boolean, + preferences: UserPreferences, +): void { const decl = isArray(imports) ? imports[0] : imports; - const importKindPredicate: (node: Node) => node is AnyImportOrRequireStatement = decl.kind === SyntaxKind.VariableStatement ? isRequireVariableStatement : isAnyImportSyntax; + const importKindPredicate: (node: Node) => node is AnyImportOrRequireStatement = + decl.kind === SyntaxKind.VariableStatement ? isRequireVariableStatement : isAnyImportSyntax; const existingImportStatements = filter(sourceFile.statements, importKindPredicate); - let sortKind = isArray(imports) ? OrganizeImports.detectImportDeclarationSorting(imports, preferences) : SortKind.Both; + let sortKind = isArray(imports) ? OrganizeImports.detectImportDeclarationSorting(imports, preferences) + : SortKind.Both; const comparer = OrganizeImports.getOrganizeImportsComparer(preferences, sortKind === SortKind.CaseInsensitive); - const sortedNewImports = isArray(imports) ? stableSort(imports, (a, b) => OrganizeImports.compareImportsOrRequireStatements(a, b, comparer)) : [imports]; + const sortedNewImports = isArray(imports) + ? stableSort(imports, (a, b) => OrganizeImports.compareImportsOrRequireStatements(a, b, comparer)) : [imports]; if (!existingImportStatements.length) { changes.insertNodesAtTopOfFile(sourceFile, sortedNewImports, blankLineBetween); } - else if (existingImportStatements && (sortKind = OrganizeImports.detectImportDeclarationSorting(existingImportStatements, preferences))) { + else if ( + existingImportStatements + && (sortKind = OrganizeImports.detectImportDeclarationSorting(existingImportStatements, preferences)) + ) { const comparer = OrganizeImports.getOrganizeImportsComparer(preferences, sortKind === SortKind.CaseInsensitive); for (const newImport of sortedNewImports) { - const insertionIndex = OrganizeImports.getImportDeclarationInsertionIndex(existingImportStatements, newImport, comparer); + const insertionIndex = OrganizeImports.getImportDeclarationInsertionIndex( + existingImportStatements, + newImport, + comparer, + ); if (insertionIndex === 0) { // If the first import is top-of-file, insert after the leading comment which is likely the header. - const options = existingImportStatements[0] === sourceFile.statements[0] ? - { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude } : {}; - changes.insertNodeBefore(sourceFile, existingImportStatements[0], newImport, /*blankLineBetween*/ false, options); + const options = existingImportStatements[0] === sourceFile.statements[0] + ? { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude } : {}; + changes.insertNodeBefore( + sourceFile, + existingImportStatements[0], + newImport, + /*blankLineBetween*/ false, + options, + ); } else { const prevImport = existingImportStatements[insertionIndex - 1]; @@ -2614,7 +2923,10 @@ export function insertImports(changes: textChanges.ChangeTracker, sourceFile: So } /** @internal */ -export function getTypeKeywordOfTypeOnlyImport(importClause: ImportClause, sourceFile: SourceFile): Token { +export function getTypeKeywordOfTypeOnlyImport( + importClause: ImportClause, + sourceFile: SourceFile, +): Token { Debug.assert(importClause.isTypeOnly); return cast(importClause.getChildAt(0, sourceFile), isTypeKeywordToken); } @@ -2635,7 +2947,10 @@ export function documentSpansEqual(a: DocumentSpan, b: DocumentSpan): boolean { * * @internal */ -export function forEachUnique(array: readonly T[] | undefined, callback: (element: T, index: number) => U): U | undefined { +export function forEachUnique( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U, +): U | undefined { if (array) { for (let i = 0; i < array.length; i++) { if (array.indexOf(array[i]) === i) { @@ -2661,17 +2976,29 @@ export function isTextWhiteSpaceLike(text: string, startPos: number, endPos: num } /** @internal */ -export function getMappedLocation(location: DocumentPosition, sourceMapper: SourceMapper, fileExists: ((path: string) => boolean) | undefined): DocumentPosition | undefined { +export function getMappedLocation( + location: DocumentPosition, + sourceMapper: SourceMapper, + fileExists: ((path: string) => boolean) | undefined, +): DocumentPosition | undefined { const mapsTo = sourceMapper.tryGetSourcePosition(location); return mapsTo && (!fileExists || fileExists(normalizePath(mapsTo.fileName)) ? mapsTo : undefined); } /** @internal */ -export function getMappedDocumentSpan(documentSpan: DocumentSpan, sourceMapper: SourceMapper, fileExists?: (path: string) => boolean): DocumentSpan | undefined { +export function getMappedDocumentSpan( + documentSpan: DocumentSpan, + sourceMapper: SourceMapper, + fileExists?: (path: string) => boolean, +): DocumentSpan | undefined { const { fileName, textSpan } = documentSpan; const newPosition = getMappedLocation({ fileName, pos: textSpan.start }, sourceMapper, fileExists); if (!newPosition) return undefined; - const newEndPosition = getMappedLocation({ fileName, pos: textSpan.start + textSpan.length }, sourceMapper, fileExists); + const newEndPosition = getMappedLocation( + { fileName, pos: textSpan.start + textSpan.length }, + sourceMapper, + fileExists, + ); const newLength = newEndPosition ? newEndPosition.pos - newPosition.pos : textSpan.length; // This shouldn't happen @@ -2684,25 +3011,29 @@ export function getMappedDocumentSpan(documentSpan: DocumentSpan, sourceMapper: originalFileName: documentSpan.fileName, originalTextSpan: documentSpan.textSpan, contextSpan: getMappedContextSpan(documentSpan, sourceMapper, fileExists), - originalContextSpan: documentSpan.contextSpan + originalContextSpan: documentSpan.contextSpan, }; } /** @internal */ -export function getMappedContextSpan(documentSpan: DocumentSpan, sourceMapper: SourceMapper, fileExists?: (path: string) => boolean): TextSpan | undefined { +export function getMappedContextSpan( + documentSpan: DocumentSpan, + sourceMapper: SourceMapper, + fileExists?: (path: string) => boolean, +): TextSpan | undefined { const contextSpanStart = documentSpan.contextSpan && getMappedLocation( { fileName: documentSpan.fileName, pos: documentSpan.contextSpan.start }, sourceMapper, - fileExists + fileExists, ); const contextSpanEnd = documentSpan.contextSpan && getMappedLocation( { fileName: documentSpan.fileName, pos: documentSpan.contextSpan.start + documentSpan.contextSpan.length }, sourceMapper, - fileExists + fileExists, ); - return contextSpanStart && contextSpanEnd ? - { start: contextSpanStart.pos, length: contextSpanEnd.pos - contextSpanStart.pos } : - undefined; + return contextSpanStart && contextSpanEnd + ? { start: contextSpanStart.pos, length: contextSpanEnd.pos - contextSpanStart.pos } + : undefined; } // #endregion @@ -2712,8 +3043,11 @@ export function getMappedContextSpan(documentSpan: DocumentSpan, sourceMapper: S /** @internal */ export function isFirstDeclarationOfSymbolParameter(symbol: Symbol) { const declaration = symbol.declarations ? firstOrUndefined(symbol.declarations) : undefined; - return !!findAncestor(declaration, n => - isParameter(n) ? true : isBindingElement(n) || isObjectBindingPattern(n) || isArrayBindingPattern(n) ? false : "quit"); + return !!findAncestor( + declaration, + n => isParameter(n) ? true + : isBindingElement(n) || isObjectBindingPattern(n) || isArrayBindingPattern(n) ? false : "quit", + ); } const displayPartWriter = getDisplayPartWriter(); @@ -2759,8 +3093,12 @@ function getDisplayPartWriter(): DisplayPartsSymbolWriter { hasTrailingComment: () => false, rawWrite: notImplemented, getIndent: () => indent, - increaseIndent: () => { indent++; }, - decreaseIndent: () => { indent--; }, + increaseIndent: () => { + indent++; + }, + decreaseIndent: () => { + indent--; + }, clear: resetWriter, }; @@ -2813,7 +3151,8 @@ export function symbolPart(text: string, symbol: Symbol) { const flags = symbol.flags; if (flags & SymbolFlags.Variable) { - return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName; + return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName + : SymbolDisplayPartKind.localName; } if (flags & SymbolFlags.Property) return SymbolDisplayPartKind.propertyName; if (flags & SymbolFlags.GetAccessor) return SymbolDisplayPartKind.propertyName; @@ -2914,7 +3253,10 @@ export function linkPart(text: string) { } /** @internal */ -export function buildLinkParts(link: JSDocLink | JSDocLinkCode | JSDocLinkPlain, checker?: TypeChecker): SymbolDisplayPart[] { +export function buildLinkParts( + link: JSDocLink | JSDocLinkCode | JSDocLinkPlain, + checker?: TypeChecker, +): SymbolDisplayPart[] { const prefix = isJSDocLink(link) ? "link" : isJSDocLinkCode(link) ? "linkcode" : "linkplain"; @@ -2978,9 +3320,9 @@ const lineFeed = "\n"; * @internal */ export function getNewLineOrDefaultFromHost(host: FormattingHost, formatSettings: FormatCodeSettings | undefined) { - return formatSettings?.newLineCharacter || - host.getNewLine?.() || - lineFeed; + return formatSettings?.newLineCharacter + || host.getNewLine?.() + || lineFeed; } /** @internal */ @@ -3000,22 +3342,50 @@ export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbol } /** @internal */ -export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.None): SymbolDisplayPart[] { +export function typeToDisplayParts( + typechecker: TypeChecker, + type: Type, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.None, +): SymbolDisplayPart[] { return mapToDisplayParts(writer => { - typechecker.writeType(type, enclosingDeclaration, flags | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer); + typechecker.writeType( + type, + enclosingDeclaration, + flags | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer, + ); }); } /** @internal */ -export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags: SymbolFormatFlags = SymbolFormatFlags.None): SymbolDisplayPart[] { +export function symbolToDisplayParts( + typeChecker: TypeChecker, + symbol: Symbol, + enclosingDeclaration?: Node, + meaning?: SymbolFlags, + flags: SymbolFormatFlags = SymbolFormatFlags.None, +): SymbolDisplayPart[] { return mapToDisplayParts(writer => { - typeChecker.writeSymbol(symbol, enclosingDeclaration, meaning, flags | SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope, writer); + typeChecker.writeSymbol( + symbol, + enclosingDeclaration, + meaning, + flags | SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope, + writer, + ); }); } /** @internal */ -export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.None): SymbolDisplayPart[] { - flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers; +export function signatureToDisplayParts( + typechecker: TypeChecker, + signature: Signature, + enclosingDeclaration?: Node, + flags: TypeFormatFlags = TypeFormatFlags.None, +): SymbolDisplayPart[] { + flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.MultilineObjectLiterals + | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers; return mapToDisplayParts(writer => { typechecker.writeSignature(signature, enclosingDeclaration, flags, /*kind*/ undefined, writer); }); @@ -3099,7 +3469,7 @@ export function getSynthesizedDeepClone(node: T, inc export function getSynthesizedDeepCloneWithReplacements( node: T, includeTrivia: boolean, - replaceNode: (node: Node) => Node | undefined + replaceNode: (node: Node) => Node | undefined, ): T { let clone = replaceNode(node); if (clone) { @@ -3120,15 +3490,15 @@ function getSynthesizedDeepCloneWorker(node: T, replaceNode?: (n const nodesClone: (ns: NodeArray | undefined) => NodeArray | undefined = replaceNode ? ns => ns && getSynthesizedDeepClonesWithReplacements(ns, /*includeTrivia*/ true, replaceNode) : ns => ns && getSynthesizedDeepClones(ns); - const visited = - visitEachChild(node, nodeClone, nullTransformationContext, nodesClone, nodeClone); + const visited = visitEachChild(node, nodeClone, nullTransformationContext, nodesClone, nodeClone); if (visited === node) { // This only happens for leaf nodes - internal nodes always see their children change. - const clone = - isStringLiteral(node) ? setOriginalNode(factory.createStringLiteralFromNode(node), node) as Node as T : - isNumericLiteral(node) ? setOriginalNode(factory.createNumericLiteral(node.text, node.numericLiteralFlags), node) as Node as T : - factory.cloneNode(node); + const clone = isStringLiteral(node) + ? setOriginalNode(factory.createStringLiteralFromNode(node), node) as Node as T + : isNumericLiteral(node) + ? setOriginalNode(factory.createNumericLiteral(node.text, node.numericLiteralFlags), node) as Node as T + : factory.cloneNode(node); return setTextRange(clone, node); } @@ -3142,11 +3512,20 @@ function getSynthesizedDeepCloneWorker(node: T, replaceNode?: (n /** @internal */ export function getSynthesizedDeepClones(nodes: NodeArray, includeTrivia?: boolean): NodeArray; /** @internal */ -export function getSynthesizedDeepClones(nodes: NodeArray | undefined, includeTrivia?: boolean): NodeArray | undefined; +export function getSynthesizedDeepClones( + nodes: NodeArray | undefined, + includeTrivia?: boolean, +): NodeArray | undefined; /** @internal */ -export function getSynthesizedDeepClones(nodes: NodeArray | undefined, includeTrivia = true): NodeArray | undefined { +export function getSynthesizedDeepClones( + nodes: NodeArray | undefined, + includeTrivia = true, +): NodeArray | undefined { if (nodes) { - const cloned = factory.createNodeArray(nodes.map(n => getSynthesizedDeepClone(n, includeTrivia)), nodes.hasTrailingComma); + const cloned = factory.createNodeArray( + nodes.map(n => getSynthesizedDeepClone(n, includeTrivia)), + nodes.hasTrailingComma, + ); setTextRange(cloned, nodes); return cloned; } @@ -3157,9 +3536,12 @@ export function getSynthesizedDeepClones(nodes: NodeArray | u export function getSynthesizedDeepClonesWithReplacements( nodes: NodeArray, includeTrivia: boolean, - replaceNode: (node: Node) => Node | undefined + replaceNode: (node: Node) => Node | undefined, ): NodeArray { - return factory.createNodeArray(nodes.map(n => getSynthesizedDeepCloneWithReplacements(n, includeTrivia, replaceNode)), nodes.hasTrailingComma); + return factory.createNodeArray( + nodes.map(n => getSynthesizedDeepCloneWithReplacements(n, includeTrivia, replaceNode)), + nodes.hasTrailingComma, + ); } /** @@ -3238,7 +3620,12 @@ export function getUniqueName(baseName: string, sourceFile: SourceFile): string * * @internal */ -export function getRenameLocation(edits: readonly FileTextChanges[], renameFilename: string, name: string, preferLastLocation: boolean): number { +export function getRenameLocation( + edits: readonly FileTextChanges[], + renameFilename: string, + name: string, + preferLastLocation: boolean, +): number { let delta = 0; let lastPos = -1; for (const { fileName, textChanges } of edits) { @@ -3265,14 +3652,33 @@ export function getRenameLocation(edits: readonly FileTextChanges[], renameFilen } /** @internal */ -export function copyLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { - forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment)); +export function copyLeadingComments( + sourceNode: Node, + targetNode: Node, + sourceFile: SourceFile, + commentKind?: CommentKind, + hasTrailingNewLine?: boolean, +) { + forEachLeadingCommentRange( + sourceFile.text, + sourceNode.pos, + getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment), + ); } - /** @internal */ -export function copyTrailingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { - forEachTrailingCommentRange(sourceFile.text, sourceNode.end, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticTrailingComment)); +export function copyTrailingComments( + sourceNode: Node, + targetNode: Node, + sourceFile: SourceFile, + commentKind?: CommentKind, + hasTrailingNewLine?: boolean, +) { + forEachTrailingCommentRange( + sourceFile.text, + sourceNode.end, + getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticTrailingComment), + ); } /** @@ -3284,11 +3690,27 @@ export function copyTrailingComments(sourceNode: Node, targetNode: Node, sourceF * * @internal */ -export function copyTrailingAsLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { - forEachTrailingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment)); +export function copyTrailingAsLeadingComments( + sourceNode: Node, + targetNode: Node, + sourceFile: SourceFile, + commentKind?: CommentKind, + hasTrailingNewLine?: boolean, +) { + forEachTrailingCommentRange( + sourceFile.text, + sourceNode.pos, + getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment), + ); } -function getAddCommentsFunction(targetNode: Node, sourceFile: SourceFile, commentKind: CommentKind | undefined, hasTrailingNewLine: boolean | undefined, cb: (node: Node, kind: CommentKind, text: string, hasTrailingNewLine?: boolean) => void) { +function getAddCommentsFunction( + targetNode: Node, + sourceFile: SourceFile, + commentKind: CommentKind | undefined, + hasTrailingNewLine: boolean | undefined, + cb: (node: Node, kind: CommentKind, text: string, hasTrailingNewLine?: boolean) => void, +) { return (pos: number, end: number, kind: CommentKind, htnl: boolean) => { if (kind === SyntaxKind.MultiLineCommentTrivia) { // Remove leading /* @@ -3300,7 +3722,12 @@ function getAddCommentsFunction(targetNode: Node, sourceFile: SourceFile, commen // Remove leading // pos += 2; } - cb(targetNode, commentKind || kind, sourceFile.text.slice(pos, end), hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl); + cb( + targetNode, + commentKind || kind, + sourceFile.text.slice(pos, end), + hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl, + ); }; } @@ -3321,7 +3748,11 @@ export function needsParentheses(expression: Expression): boolean { } /** @internal */ -export function getContextualTypeFromParent(node: Expression, checker: TypeChecker, contextFlags?: ContextFlags): Type | undefined { +export function getContextualTypeFromParent( + node: Expression, + checker: TypeChecker, + contextFlags?: ContextFlags, +): Type | undefined { const parent = walkUpParenthesizedExpressions(node.parent); switch (parent.kind) { case SyntaxKind.NewExpression: @@ -3344,7 +3775,8 @@ export function quote(sourceFile: SourceFile, preferences: UserPreferences, text // Editors can pass in undefined or empty string - we want to infer the preference in those cases. const quotePreference = getQuotePreference(sourceFile, preferences); const quoted = JSON.stringify(text); - return quotePreference === QuotePreference.Single ? `'${stripQuotes(quoted).replace(/'/g, "\\'").replace(/\\"/g, '"')}'` : quoted; + return quotePreference === QuotePreference.Single + ? `'${stripQuotes(quoted).replace(/'/g, "\\'").replace(/\\"/g, '"')}'` : quoted; } /** @internal */ @@ -3361,7 +3793,9 @@ export function isEqualityOperatorKind(kind: SyntaxKind): kind is EqualityOperat } /** @internal */ -export function isStringLiteralOrTemplate(node: Node): node is StringLiteralLike | TemplateExpression | TaggedTemplateExpression { +export function isStringLiteralOrTemplate( + node: Node, +): node is StringLiteralLike | TemplateExpression | TaggedTemplateExpression { switch (node.kind) { case SyntaxKind.StringLiteral: case SyntaxKind.NoSubstitutionTemplateLiteral: @@ -3387,19 +3821,26 @@ export function getSwitchedType(caseClause: CaseClause, checker: TypeChecker): T export const ANONYMOUS = "anonymous function"; /** @internal */ -export function getTypeNodeIfAccessible(type: Type, enclosingScope: Node, program: Program, host: LanguageServiceHost): TypeNode | undefined { +export function getTypeNodeIfAccessible( + type: Type, + enclosingScope: Node, + program: Program, + host: LanguageServiceHost, +): TypeNode | undefined { const checker = program.getTypeChecker(); let typeIsAccessible = true; const notAccessible = () => typeIsAccessible = false; const res = checker.typeToTypeNode(type, enclosingScope, NodeBuilderFlags.NoTruncation, { trackSymbol: (symbol, declaration, meaning) => { - typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible; + typeIsAccessible = typeIsAccessible + && checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false) + .accessibility === SymbolAccessibility.Accessible; return !typeIsAccessible; }, reportInaccessibleThisError: notAccessible, reportPrivateInBaseOfClassExpression: notAccessible, reportInaccessibleUniqueSymbolError: notAccessible, - moduleResolverHost: getModuleSpecifierResolverHost(program, host) + moduleResolverHost: getModuleSpecifierResolverHost(program, host), }); return typeIsAccessible ? res : undefined; } @@ -3448,7 +3889,8 @@ export const syntaxMayBeASICandidate = or( syntaxRequiresTrailingCommaOrSemicolonOrASI, syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI, syntaxRequiresTrailingModuleBlockOrSemicolonOrASI, - syntaxRequiresTrailingSemicolonOrASI); + syntaxRequiresTrailingSemicolonOrASI, +); function nodeIsASICandidate(node: Node, sourceFile: SourceFileLike): boolean { const lastToken = node.getLastToken(sourceFile); @@ -3527,7 +3969,9 @@ export function probablyUsesSemicolons(sourceFile: SourceFile): boolean { } else if (lastToken && lastToken.kind !== SyntaxKind.CommaToken) { const lastTokenLine = getLineAndCharacterOfPosition(sourceFile, lastToken.getStart(sourceFile)).line; - const nextTokenLine = getLineAndCharacterOfPosition(sourceFile, getSpanOfTokenAtPosition(sourceFile, lastToken.end).start).line; + const nextTokenLine = + getLineAndCharacterOfPosition(sourceFile, getSpanOfTokenAtPosition(sourceFile, lastToken.end).start) + .line; // Avoid counting missing semicolon in single-line objects: // `function f(p: { x: string /*no semicolon here is insignificant*/ }) {` if (lastTokenLine !== nextTokenLine) { @@ -3559,7 +4003,13 @@ export function tryGetDirectories(host: Pick, path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[]): readonly string[] { +export function tryReadDirectory( + host: Pick, + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], +): readonly string[] { return tryIOAndConsumeErrors(host, host.readDirectory, path, extensions, exclude, include) || emptyArray; } @@ -3589,7 +4039,11 @@ export function tryIOAndConsumeErrors(host: unknown, toApply: ((...a: any[]) } /** @internal */ -export function findPackageJsons(startDirectory: string, host: Pick, stopDirectory?: string): string[] { +export function findPackageJsons( + startDirectory: string, + host: Pick, + stopDirectory?: string, +): string[] { const paths: string[] = []; forEachAncestorDirectory(startDirectory, ancestor => { if (ancestor === stopDirectory) { @@ -3608,7 +4062,7 @@ export function findPackageJson(directory: string, host: LanguageServiceHost): s let packageJson: string | undefined; forEachAncestorDirectory(directory, ancestor => { if (ancestor === "node_modules") return true; - packageJson = findConfigFile(ancestor, (f) => tryFileExists(host, f), "package.json"); + packageJson = findConfigFile(ancestor, f => tryFileExists(host, f), "package.json"); if (packageJson) { return true; // break out } @@ -3617,7 +4071,10 @@ export function findPackageJson(directory: string, host: LanguageServiceHost): s } /** @internal */ -export function getPackageJsonsVisibleToFile(fileName: string, host: LanguageServiceHost): readonly ProjectPackageJsonInfo[] { +export function getPackageJsonsVisibleToFile( + fileName: string, + host: LanguageServiceHost, +): readonly ProjectPackageJsonInfo[] { if (!host.fileExists) { return []; } @@ -3637,7 +4094,10 @@ export function getPackageJsonsVisibleToFile(fileName: string, host: LanguageSer } /** @internal */ -export function createPackageJsonInfo(fileName: string, host: { readFile?(fileName: string): string | undefined }): ProjectPackageJsonInfo | undefined { +export function createPackageJsonInfo( + fileName: string, + host: { readFile?(fileName: string): string | undefined; }, +): ProjectPackageJsonInfo | undefined { if (!host.readFile) { return undefined; } @@ -3692,8 +4152,14 @@ export function createPackageJsonInfo(fileName: string, host: { readFile?(fileNa /** @internal */ export interface PackageJsonImportFilter { - allowsImportingAmbientModule: (moduleSymbol: Symbol, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost) => boolean; - allowsImportingSourceFile: (sourceFile: SourceFile, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost) => boolean; + allowsImportingAmbientModule: ( + moduleSymbol: Symbol, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ) => boolean; + allowsImportingSourceFile: ( + sourceFile: SourceFile, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ) => boolean; /** * Use for a specific module specifier that has already been resolved. * Use `allowsImportingAmbientModule` or `allowsImportingSourceFile` to resolve @@ -3703,10 +4169,15 @@ export interface PackageJsonImportFilter { } /** @internal */ -export function createPackageJsonImportFilter(fromFile: SourceFile, preferences: UserPreferences, host: LanguageServiceHost): PackageJsonImportFilter { +export function createPackageJsonImportFilter( + fromFile: SourceFile, + preferences: UserPreferences, + host: LanguageServiceHost, +): PackageJsonImportFilter { const packageJsons = ( - (host.getPackageJsonsVisibleToFile && host.getPackageJsonsVisibleToFile(fromFile.fileName)) || getPackageJsonsVisibleToFile(fromFile.fileName, host) - ).filter(p => p.parseable); + (host.getPackageJsonsVisibleToFile && host.getPackageJsonsVisibleToFile(fromFile.fileName)) + || getPackageJsonsVisibleToFile(fromFile.fileName, host) + ).filter(p => p.parseable); let usesNodeCoreModules: boolean | undefined; let ambientModuleCache: Map | undefined; @@ -3727,7 +4198,10 @@ export function createPackageJsonImportFilter(fromFile: SourceFile, preferences: return false; } - function allowsImportingAmbientModule(moduleSymbol: Symbol, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost): boolean { + function allowsImportingAmbientModule( + moduleSymbol: Symbol, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ): boolean { if (!packageJsons.length || !moduleSymbol.valueDeclaration) { return true; } @@ -3749,20 +4223,25 @@ export function createPackageJsonImportFilter(fromFile: SourceFile, preferences: } const declaringSourceFile = moduleSymbol.valueDeclaration.getSourceFile(); - const declaringNodeModuleName = getNodeModulesPackageNameFromFileName(declaringSourceFile.fileName, moduleSpecifierResolutionHost); + const declaringNodeModuleName = getNodeModulesPackageNameFromFileName( + declaringSourceFile.fileName, + moduleSpecifierResolutionHost, + ); if (typeof declaringNodeModuleName === "undefined") { ambientModuleCache.set(moduleSymbol, true); return true; } - const result = - moduleSpecifierIsCoveredByPackageJson(declaringNodeModuleName) || - moduleSpecifierIsCoveredByPackageJson(declaredModuleSpecifier); + const result = moduleSpecifierIsCoveredByPackageJson(declaringNodeModuleName) + || moduleSpecifierIsCoveredByPackageJson(declaredModuleSpecifier); ambientModuleCache.set(moduleSymbol, result); return result; } - function allowsImportingSourceFile(sourceFile: SourceFile, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost): boolean { + function allowsImportingSourceFile( + sourceFile: SourceFile, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ): boolean { if (!packageJsons.length) { return true; } @@ -3777,7 +4256,10 @@ export function createPackageJsonImportFilter(fromFile: SourceFile, preferences: } } - const moduleSpecifier = getNodeModulesPackageNameFromFileName(sourceFile.fileName, moduleSpecifierResolutionHost); + const moduleSpecifier = getNodeModulesPackageNameFromFileName( + sourceFile.fileName, + moduleSpecifierResolutionHost, + ); if (!moduleSpecifier) { sourceFileCache.set(sourceFile, true); return true; @@ -3814,7 +4296,10 @@ export function createPackageJsonImportFilter(fromFile: SourceFile, preferences: return false; } - function getNodeModulesPackageNameFromFileName(importedFileName: string, moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost): string | undefined { + function getNodeModulesPackageNameFromFileName( + importedFileName: string, + moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost, + ): string | undefined { if (!stringContains(importedFileName, "node_modules")) { return undefined; } @@ -3871,18 +4356,28 @@ export function isDiagnosticWithLocation(diagnostic: Diagnostic): diagnostic is } /** @internal */ -export function findDiagnosticForNode(node: Node, sortedFileDiagnostics: readonly Diagnostic[]): DiagnosticWithLocation | undefined { +export function findDiagnosticForNode( + node: Node, + sortedFileDiagnostics: readonly Diagnostic[], +): DiagnosticWithLocation | undefined { const span: Partial = createTextSpanFromNode(node); const index = binarySearchKey(sortedFileDiagnostics, span, identity, compareTextSpans); if (index >= 0) { const diagnostic = sortedFileDiagnostics[index]; - Debug.assertEqual(diagnostic.file, node.getSourceFile(), "Diagnostics proided to 'findDiagnosticForNode' must be from a single SourceFile"); + Debug.assertEqual( + diagnostic.file, + node.getSourceFile(), + "Diagnostics proided to 'findDiagnosticForNode' must be from a single SourceFile", + ); return cast(diagnostic, isDiagnosticWithLocation); } } /** @internal */ -export function getDiagnosticsWithinSpan(span: TextSpan, sortedFileDiagnostics: readonly Diagnostic[]): readonly DiagnosticWithLocation[] { +export function getDiagnosticsWithinSpan( + span: TextSpan, + sortedFileDiagnostics: readonly Diagnostic[], +): readonly DiagnosticWithLocation[] { let index = binarySearchKey(sortedFileDiagnostics, span.start, diag => diag.start, compareValues); if (index < 0) { index = ~index; @@ -3936,13 +4431,28 @@ export function getFixableErrorSpanExpression(sourceFile: SourceFile, span: Text */ export function mapOneOrMany(valueOrArray: T | readonly T[], f: (x: T, i: number) => U): U | U[]; /** @internal */ -export function mapOneOrMany(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U): U | U[] | undefined; -/** @internal */ -export function mapOneOrMany(valueOrArray: T | readonly T[], f: (x: T, i: number) => U, resultSelector: (x: U[]) => U): U; -/** @internal */ -export function mapOneOrMany(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U, resultSelector: (x: U[]) => U): U | undefined; -/** @internal */ -export function mapOneOrMany(valueOrArray: T | readonly T[] | undefined, f: (x: T, i: number) => U, resultSelector: (x: U[]) => U | U[] = identity): U | U[] | undefined { +export function mapOneOrMany( + valueOrArray: T | readonly T[] | undefined, + f: (x: T, i: number) => U, +): U | U[] | undefined; +/** @internal */ +export function mapOneOrMany( + valueOrArray: T | readonly T[], + f: (x: T, i: number) => U, + resultSelector: (x: U[]) => U, +): U; +/** @internal */ +export function mapOneOrMany( + valueOrArray: T | readonly T[] | undefined, + f: (x: T, i: number) => U, + resultSelector: (x: U[]) => U, +): U | undefined; +/** @internal */ +export function mapOneOrMany( + valueOrArray: T | readonly T[] | undefined, + f: (x: T, i: number) => U, + resultSelector: (x: U[]) => U | U[] = identity, +): U | U[] | undefined { return valueOrArray ? isArray(valueOrArray) ? resultSelector(map(valueOrArray, f)) : f(valueOrArray, 0) : undefined; } @@ -3956,12 +4466,23 @@ export function firstOrOnly(valueOrArray: T | readonly T[]): T { } /** @internal */ -export function getNamesForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined): string | [lowercase: string, capitalized: string] { +export function getNamesForExportedSymbol( + symbol: Symbol, + scriptTarget: ScriptTarget | undefined, +): string | [lowercase: string, capitalized: string] { if (needsNameFromDeclaration(symbol)) { const fromDeclaration = getDefaultLikeExportNameFromDeclaration(symbol); if (fromDeclaration) return fromDeclaration; - const fileNameCase = codefix.moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget, /*forceCapitalize*/ false); - const capitalized = codefix.moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget, /*forceCapitalize*/ true); + const fileNameCase = codefix.moduleSymbolToValidIdentifier( + getSymbolParentOrFail(symbol), + scriptTarget, + /*forceCapitalize*/ false, + ); + const capitalized = codefix.moduleSymbolToValidIdentifier( + getSymbolParentOrFail(symbol), + scriptTarget, + /*forceCapitalize*/ true, + ); if (fileNameCase === capitalized) return fileNameCase; return [fileNameCase, capitalized]; } @@ -3969,7 +4490,11 @@ export function getNamesForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTa } /** @internal */ -export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined, preferCapitalized?: boolean) { +export function getNameForExportedSymbol( + symbol: Symbol, + scriptTarget: ScriptTarget | undefined, + preferCapitalized?: boolean, +) { if (needsNameFromDeclaration(symbol)) { // Names for default exports: // - export default foo => foo @@ -3982,7 +4507,9 @@ export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTar } function needsNameFromDeclaration(symbol: Symbol) { - return !(symbol.flags & SymbolFlags.Transient) && (symbol.escapedName === InternalSymbolName.ExportEquals || symbol.escapedName === InternalSymbolName.Default); + return !(symbol.flags & SymbolFlags.Transient) + && (symbol.escapedName === InternalSymbolName.ExportEquals + || symbol.escapedName === InternalSymbolName.Default); } function getDefaultLikeExportNameFromDeclaration(symbol: Symbol): string | undefined { @@ -4003,13 +4530,17 @@ function getDefaultLikeExportNameFromDeclaration(symbol: Symbol): string | undef function getSymbolParentOrFail(symbol: Symbol) { return Debug.checkDefined( symbol.parent, - `Symbol parent was undefined. Flags: ${Debug.formatSymbolFlags(symbol.flags)}. ` + - `Declarations: ${symbol.declarations?.map(d => { - const kind = Debug.formatSyntaxKind(d.kind); - const inJS = isInJSFile(d); - const { expression } = d as any; - return (inJS ? "[JS]" : "") + kind + (expression ? ` (expression: ${Debug.formatSyntaxKind(expression.kind)})` : ""); - }).join(", ")}.`); + `Symbol parent was undefined. Flags: ${Debug.formatSymbolFlags(symbol.flags)}. ` + + `Declarations: ${ + symbol.declarations?.map(d => { + const kind = Debug.formatSyntaxKind(d.kind); + const inJS = isInJSFile(d); + const { expression } = d as any; + return (inJS ? "[JS]" : "") + kind + + (expression ? ` (expression: ${Debug.formatSyntaxKind(expression.kind)})` : ""); + }).join(", ") + }.`, + ); } /** @@ -4061,7 +4592,8 @@ export function isNonGlobalDeclaration(declaration: Declaration) { 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)); + return isInJSFile(declaration) + || !findAncestor(declaration, d => isModuleDeclaration(d) && isGlobalScopeAugmentation(d)); } /** @internal */ @@ -4098,9 +4630,14 @@ export function diagnosticToString(diag: DiagnosticOrDiagnosticAndArguments): st * * @internal */ -export function getFormatCodeSettingsForWriting({ options }: formatting.FormatContext, sourceFile: SourceFile): FormatCodeSettings { - const shouldAutoDetectSemicolonPreference = !options.semicolons || options.semicolons === SemicolonPreference.Ignore; - const shouldRemoveSemicolons = options.semicolons === SemicolonPreference.Remove || shouldAutoDetectSemicolonPreference && !probablyUsesSemicolons(sourceFile); +export function getFormatCodeSettingsForWriting( + { options }: formatting.FormatContext, + sourceFile: SourceFile, +): FormatCodeSettings { + const shouldAutoDetectSemicolonPreference = !options.semicolons + || options.semicolons === SemicolonPreference.Ignore; + const shouldRemoveSemicolons = options.semicolons === SemicolonPreference.Remove + || shouldAutoDetectSemicolonPreference && !probablyUsesSemicolons(sourceFile); return { ...options, semicolons: shouldRemoveSemicolons ? SemicolonPreference.Remove : SemicolonPreference.Ignore, @@ -4124,7 +4661,10 @@ export interface CaseClauseTracker { } /** @internal */ -export function newCaseClauseTracker(checker: TypeChecker, clauses: readonly (CaseClause | DefaultClause)[]): CaseClauseTracker { +export function newCaseClauseTracker( + checker: TypeChecker, + clauses: readonly (CaseClause | DefaultClause)[], +): CaseClauseTracker { const existingStrings = new Set(); const existingNumbers = new Set(); const existingBigInts = new Set(); @@ -4142,7 +4682,9 @@ export function newCaseClauseTracker(checker: TypeChecker, clauses: readonly (Ca existingNumbers.add(parseInt(expression.text)); break; case SyntaxKind.BigIntLiteral: - const parsedBigInt = parseBigInt(endsWith(expression.text, "n") ? expression.text.slice(0, -1) : expression.text); + const parsedBigInt = parseBigInt( + endsWith(expression.text, "n") ? expression.text.slice(0, -1) : expression.text, + ); if (parsedBigInt) { existingBigInts.add(pseudoBigIntToString(parsedBigInt)); } @@ -4189,7 +4731,12 @@ export function newCaseClauseTracker(checker: TypeChecker, clauses: readonly (Ca } /** @internal */ -export function fileShouldUseJavaScriptRequire(file: SourceFile | string, program: Program, host: LanguageServiceHost, preferRequire?: boolean) { +export function fileShouldUseJavaScriptRequire( + file: SourceFile | string, + program: Program, + host: LanguageServiceHost, + preferRequire?: boolean, +) { const fileName = typeof file === "string" ? file : file.fileName; if (!hasJSFileExtension(fileName)) { return false; @@ -4197,7 +4744,12 @@ export function fileShouldUseJavaScriptRequire(file: SourceFile | string, progra const compilerOptions = program.getCompilerOptions(); const moduleKind = getEmitModuleKind(compilerOptions); const impliedNodeFormat = typeof file === "string" - ? getImpliedNodeFormatForFile(toPath(file, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), program.getPackageJsonInfoCache?.(), host, compilerOptions) + ? getImpliedNodeFormatForFile( + toPath(file, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), + program.getPackageJsonInfoCache?.(), + host, + compilerOptions, + ) : file.impliedNodeFormat; if (impliedNodeFormat === ModuleKind.ESNext) { diff --git a/src/testRunner/compilerRunner.ts b/src/testRunner/compilerRunner.ts index c11c2645b02b4..3584eabedcccd 100644 --- a/src/testRunner/compilerRunner.ts +++ b/src/testRunner/compilerRunner.ts @@ -66,7 +66,10 @@ export class CompilerBaselineRunner extends RunnerBase { const files = this.tests.length > 0 ? this.tests : IO.enumerateTestFiles(this); files.forEach(test => { const file = typeof test === "string" ? test : test.file; - this.checkTestCodeOutput(vpath.normalizeSeparators(file), typeof test === "string" ? CompilerTest.getConfigurations(test) : test); + this.checkTestCodeOutput( + vpath.normalizeSeparators(file), + typeof test === "string" ? CompilerTest.getConfigurations(test) : test, + ); }); }); } @@ -177,7 +180,11 @@ class CompilerTest { // equivalent to other files on the file system not directly passed to the compiler (ie things that are referenced by other files) private otherFiles: Compiler.TestFile[]; - constructor(fileName: string, testCaseContent?: TestCaseParser.TestCaseContent, configurationOverrides?: TestCaseParser.CompilerSettings) { + constructor( + fileName: string, + testCaseContent?: TestCaseParser.TestCaseContent, + configurationOverrides?: TestCaseParser.CompilerSettings, + ) { const absoluteRootDir = vfs.srcFolder; this.fileName = fileName; this.justName = vpath.basename(fileName); @@ -205,7 +212,10 @@ class CompilerTest { } if (configurationOverrides) { - testCaseContent = { ...testCaseContent, settings: { ...testCaseContent.settings, ...configurationOverrides } }; + testCaseContent = { + ...testCaseContent, + settings: { ...testCaseContent.settings, ...configurationOverrides }, + }; } const units = testCaseContent.testUnitData; @@ -219,7 +229,11 @@ class CompilerTest { tsConfigOptions = ts.cloneCompilerOptions(testCaseContent.tsConfig.options); this.tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData!)); for (const unit of units) { - if (testCaseContent.tsConfig.fileNames.includes(ts.getNormalizedAbsolutePath(unit.name, absoluteRootDir))) { + if ( + testCaseContent.tsConfig.fileNames.includes( + ts.getNormalizedAbsolutePath(unit.name, absoluteRootDir), + ) + ) { this.toBeCompiled.push(this.createHarnessTestFile(unit)); } else { @@ -238,7 +252,10 @@ class CompilerTest { // If the last file in a test uses require or a triple slash reference we'll assume all other files will be brought in via references, // otherwise, assume all files are just meant to be in the same compilation session without explicit references to one another. - if (testCaseContent.settings.noImplicitReferences || /require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) { + if ( + testCaseContent.settings.noImplicitReferences || /require\(/.test(lastUnit.content) + || /reference\spath/.test(lastUnit.content) + ) { this.toBeCompiled.push(this.createHarnessTestFile(lastUnit)); units.forEach(unit => { if (unit.name !== lastUnit.name) { @@ -263,7 +280,7 @@ class CompilerTest { this.harnessSettings, /*options*/ tsConfigOptions, /*currentDirectory*/ this.harnessSettings.currentDirectory, - testCaseContent.symlinks + testCaseContent.symlinks, ); this.options = this.result.options; @@ -283,23 +300,27 @@ class CompilerTest { this.configuredName, this.tsConfigFiles.concat(this.toBeCompiled, this.otherFiles), this.result.diagnostics, - !!this.options.pretty); + !!this.options.pretty, + ); } public verifyModuleResolution() { if (this.options.traceResolution) { - Baseline.runBaseline(this.configuredName.replace(/\.tsx?$/, ".trace.json"), - JSON.stringify(this.result.traces.map(Utils.sanitizeTraceResolutionLogEntry), undefined, 4)); + Baseline.runBaseline( + this.configuredName.replace(/\.tsx?$/, ".trace.json"), + JSON.stringify(this.result.traces.map(Utils.sanitizeTraceResolutionLogEntry), undefined, 4), + ); } } public verifySourceMapRecord() { if (this.options.sourceMap || this.options.inlineSourceMap || this.options.declarationMap) { const record = Utils.removeTestPathPrefixes(this.result.getSourceMapRecord()!); - const baseline = (this.options.noEmitOnError && this.result.diagnostics.length !== 0) || record === undefined - // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. - ? null // eslint-disable-line no-null/no-null - : record; + const baseline = + (this.options.noEmitOnError && this.result.diagnostics.length !== 0) || record === undefined + // Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required. + ? null // eslint-disable-line no-null/no-null + : record; Baseline.runBaseline(this.configuredName.replace(/\.tsx?$/, ".sourcemap.txt"), baseline); } } @@ -314,7 +335,8 @@ class CompilerTest { this.tsConfigFiles, this.toBeCompiled, this.otherFiles, - this.harnessSettings); + this.harnessSettings, + ); } } @@ -323,7 +345,8 @@ class CompilerTest { this.configuredName, this.options, this.result, - this.harnessSettings); + this.harnessSettings, + ); } public verifyTypesAndSymbols() { @@ -331,9 +354,8 @@ class CompilerTest { return; } - const noTypesAndSymbols = - this.harnessSettings.noTypesAndSymbols && - this.harnessSettings.noTypesAndSymbols.toLowerCase() === "true"; + const noTypesAndSymbols = this.harnessSettings.noTypesAndSymbols + && this.harnessSettings.noTypesAndSymbols.toLowerCase() === "true"; if (noTypesAndSymbols) { return; } @@ -342,12 +364,14 @@ class CompilerTest { this.configuredName, this.fileName, this.result.program!, - this.toBeCompiled.concat(this.otherFiles).filter(file => !!this.result.program!.getSourceFile(file.unitName)), + this.toBeCompiled.concat(this.otherFiles).filter(file => + !!this.result.program!.getSourceFile(file.unitName) + ), /*opts*/ undefined, /*multifile*/ undefined, /*skipTypeBaselines*/ undefined, /*skipSymbolBaselines*/ undefined, - !!ts.length(this.result.diagnostics) + !!ts.length(this.result.diagnostics), ); } @@ -355,7 +379,7 @@ class CompilerTest { return { unitName: unit.name, content: unit.content, - fileOptions: unit.fileOptions + fileOptions: unit.fileOptions, }; } } diff --git a/src/testRunner/parallel/host.ts b/src/testRunner/parallel/host.ts index b803324184558..aadc403cfeae9 100644 --- a/src/testRunner/parallel/host.ts +++ b/src/testRunner/parallel/host.ts @@ -40,7 +40,9 @@ export function start() { 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 - const FailedTestReporter = require(Utils.findUpFile("scripts/failed-tests.cjs")) as typeof import("../../../scripts/failed-tests.cjs"); + const FailedTestReporter = require( + Utils.findUpFile("scripts/failed-tests.cjs"), + ) as typeof import("../../../scripts/failed-tests.cjs"); const perfdataFileNameFragment = ".parallelperf"; const perfData = readSavedPerfData(configOption); @@ -79,7 +81,7 @@ export function start() { interface Worker { process: import("child_process").ChildProcess; accumulatedOutput: string; - currentTasks?: { file: string }[]; + currentTasks?: { file: string; }[]; timer?: any; } @@ -118,7 +120,7 @@ export function start() { incomplete, close, width, - noColors: options.noColors || false + noColors: options.noColors || false, }; this._progressBars = []; @@ -200,7 +202,7 @@ export function start() { return `${perfdataFileNameFragment}${target ? `.${target}` : ""}.json`; } - function readSavedPerfData(target?: string): { [testHash: string]: number } | undefined { + function readSavedPerfData(target?: string): { [testHash: string]: number; } | undefined { const perfDataContents = IO.readFile(perfdataFileName(target)); if (perfDataContents) { return JSON.parse(perfDataContents); @@ -212,8 +214,11 @@ export function start() { return `tsrunner-${runner}://${test}`; } - function startDelayed(perfData: { [testHash: string]: number } | undefined, totalCost: number) { - console.log(`Discovered ${tasks.length} unittest suites` + (newTasks.length ? ` and ${newTasks.length} new suites.` : ".")); + function startDelayed(perfData: { [testHash: string]: number; } | undefined, totalCost: number) { + console.log( + `Discovered ${tasks.length} unittest suites` + + (newTasks.length ? ` and ${newTasks.length} new suites.` : "."), + ); console.log("Discovering runner-based tests..."); const discoverStart = +(new Date()); for (const runner of runners) { @@ -227,7 +232,8 @@ export function start() { catch { // May be a directory try { - size = IO.listFiles(path.join(runner.workingDirectory, file), /.*/g, { recursive: true }).reduce((acc, elem) => acc + statSync(elem).size, 0); + size = IO.listFiles(path.join(runner.workingDirectory, file), /.*/g, { recursive: true }) + .reduce((acc, elem) => acc + statSync(elem).size, 0); } catch { // Unknown test kind, just return 0 and let the historical analysis take over after one run @@ -262,7 +268,7 @@ export function start() { let passingFiles = 0; let failingFiles = 0; let errorResults: ErrorInfo[] = []; - let passingResults: { name: string[] }[] = []; + let passingResults: { name: string[]; }[] = []; let totalPassing = 0; const startDate = new Date(); @@ -270,20 +276,28 @@ export function start() { const progressUpdateInterval = 1 / progressBars._options.width; let nextProgress = progressUpdateInterval; - const newPerfData: { [testHash: string]: number } = {}; + const newPerfData: { [testHash: string]: number; } = {}; const workers: Worker[] = []; let closedWorkers = 0; for (let i = 0; i < workerCount; i++) { // TODO: Just send the config over the IPC channel or in the command line arguments - const config: TestConfig = { light: lightMode, listenForWork: true, runUnitTests, stackTraceLimit, timeout: globalTimeout }; + const config: TestConfig = { + light: lightMode, + listenForWork: true, + runUnitTests, + stackTraceLimit, + timeout: globalTimeout, + }; const configPath = ts.combinePaths(taskConfigsFolder, `task-config${i}.json`); IO.writeFile(configPath, JSON.stringify(config)); const worker: Worker = { - process: fork(process.argv[1], [`--config="${configPath}"`], { stdio: ["pipe", "pipe", "pipe", "ipc"] }), + process: fork(process.argv[1], [`--config="${configPath}"`], { + stdio: ["pipe", "pipe", "pipe", "ipc"], + }), accumulatedOutput: "", currentTasks: undefined, - timer: undefined + timer: undefined, }; const appendOutput = (d: Buffer) => { worker.accumulatedOutput += d.toString(); @@ -293,7 +307,12 @@ export function start() { worker.process.stdout!.on("data", appendOutput); const killChild = (timeout: TaskTimeout) => { worker.process.kill(); - console.error(`Worker exceeded ${timeout.duration}ms timeout ${worker.currentTasks && worker.currentTasks.length ? `while running test '${worker.currentTasks[0].file}'.` : `during test setup.`}`); + console.error( + `Worker exceeded ${timeout.duration}ms timeout ${ + worker.currentTasks && worker.currentTasks.length + ? `while running test '${worker.currentTasks[0].file}'.` : `during test setup.` + }`, + ); return process.exit(2); }; worker.process.on("error", err => { @@ -311,9 +330,13 @@ export function start() { worker.process.on("message", (data: ParallelClientMessage) => { switch (data.type) { case "error": { - console.error(`Test worker encountered unexpected error${data.payload.name ? ` during the execution of test ${data.payload.name}` : ""} and was forced to close: + console.error( + `Test worker encountered unexpected error${ + data.payload.name ? ` during the execution of test ${data.payload.name}` : "" + } and was forced to close: Message: ${data.payload.error} - Stack: ${data.payload.stack}`); + Stack: ${data.payload.stack}`, + ); return process.exit(2); } case "timeout": { @@ -350,7 +373,11 @@ export function start() { while (nextProgress < progress) { nextProgress += progressUpdateInterval; } - updateProgress(progress, errorResults.length ? `${errorResults.length} failing` : `${totalPassing} passing`, errorResults.length ? "fail" : undefined); + updateProgress( + progress, + errorResults.length ? `${errorResults.length} failing` : `${totalPassing} passing`, + errorResults.length ? "fail" : undefined, + ); } if (data.type === "result") { @@ -370,7 +397,9 @@ export function start() { } worker.currentTasks = taskList; if (taskList.length === 1) { - worker.process.send({ type: "test", payload: taskList[0] } satisfies ParallelHostMessage); // TODO: GH#18217 + worker.process.send( + { type: "test", payload: taskList[0] } satisfies ParallelHostMessage, + ); // TODO: GH#18217 } else { worker.process.send({ type: "batch", payload: taskList } satisfies ParallelHostMessage); // TODO: GH#18217 @@ -385,13 +414,18 @@ export function start() { // It's only really worth doing an initial batching if there are a ton of files to go through (and they have estimates) if (totalFiles > 1000 && batchSize > 0) { console.log("Batching initial test lists..."); - const batches: { runner: TestRunnerKind | "unittest", file: string, size: number }[][] = new Array(batchCount); + const batches: { runner: TestRunnerKind | "unittest"; file: string; size: number; }[][] = new Array( + batchCount, + ); const doneBatching = new Array(batchCount); let scheduledTotal = 0; - batcher: while (true) { + batcher: + while (true) { for (let i = 0; i < batchCount; i++) { if (tasks.length <= workerCount) { // Keep a small reserve even in the suboptimally packed case - console.log(`Suboptimal packing detected: no tests remain to be stolen. Reduce packing fraction from ${packfraction} to fix.`); + console.log( + `Suboptimal packing detected: no tests remain to be stolen. Reduce packing fraction from ${packfraction} to fix.`, + ); break batcher; } if (doneBatching[i]) { @@ -421,7 +455,11 @@ export function start() { console.log(`${prefix}. Unprofiled tests including ${unknownValue} will be run first.`); } else { - console.log(`${prefix} with approximate total ${perfData ? "time" : "file sizes"} of ${perfData ? ms(batchSize) : `${Math.floor(batchSize)} bytes`} in each group. (${(scheduledTotal / totalCost * 100).toFixed(1)}% of total tests batched)`); + console.log( + `${prefix} with approximate total ${perfData ? "time" : "file sizes"} of ${ + perfData ? ms(batchSize) : `${Math.floor(batchSize)} bytes` + } in each group. (${(scheduledTotal / totalCost * 100).toFixed(1)}% of total tests batched)`, + ); } for (const worker of workers) { const payload = batches.pop(); @@ -455,12 +493,15 @@ export function start() { const summaryColor = isPartitionFail ? "fail" : "green"; const summarySymbol = isPartitionFail ? Base.symbols.err : Base.symbols.ok; - const summaryTests = (isPartitionFail ? totalPassing + "/" + (errorResults.length + totalPassing) : totalPassing) + " passing"; + const summaryTests = + (isPartitionFail ? totalPassing + "/" + (errorResults.length + totalPassing) : totalPassing) + + " passing"; const summaryDuration = "(" + ms(duration) + ")"; const savedUseColors = Base.useColors; Base.useColors = !noColors; - const summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration); + const summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + + color("light", summaryDuration); Base.useColors = savedUseColors; updateProgress(1, summary); @@ -477,7 +518,7 @@ export function start() { percentComplete, progressColor, title, - titleColor + titleColor, ); } @@ -485,20 +526,29 @@ export function start() { function patchStats(stats: Mocha.Stats) { Object.defineProperties(stats, { start: { - configurable: true, enumerable: true, - get() { return startDate; }, - set(_: Date) { /*do nothing*/ } + configurable: true, + enumerable: true, + get() { + return startDate; + }, + set(_: Date) {/*do nothing*/}, }, end: { - configurable: true, enumerable: true, - get() { return endDate; }, - set(_: Date) { /*do nothing*/ } + configurable: true, + enumerable: true, + get() { + return endDate; + }, + set(_: Date) {/*do nothing*/}, }, duration: { - configurable: true, enumerable: true, - get() { return duration; }, - set(_: number) { /*do nothing*/ } - } + configurable: true, + enumerable: true, + get() { + return duration; + }, + set(_: number) {/*do nothing*/}, + }, }); } @@ -536,7 +586,11 @@ export function start() { function replayTest(runner: Mocha.Runner, test: RemoteTest) { runner.emit("test", test); if (test.isFailed()) { - runner.emit("fail", test, "error" in test.info ? rebuildError(test.info) : new Error("Unknown error")); // eslint-disable-line local/no-in-operator + runner.emit( + "fail", + test, + "error" in test.info ? rebuildError(test.info) : new Error("Unknown error"), + ); // eslint-disable-line local/no-in-operator } else { runner.emit("pass", test); @@ -563,8 +617,8 @@ export function start() { xunitReporter = new Mocha.reporters.XUnit(replayRunner, { reporterOptions: { suiteName: "Tests", - output: "./TEST-results.xml" - } + output: "./TEST-results.xml", + }, }); patchStats(xunitReporter.stats); xunitReporter.write(`\n`); @@ -574,7 +628,7 @@ export function start() { reporterOptions: { file: path.resolve(".failed-tests"), keepFailed, - } + }, }); } diff --git a/src/testRunner/parallel/shared.ts b/src/testRunner/parallel/shared.ts index f645d2bc6024a..7d673ca5205d7 100644 --- a/src/testRunner/parallel/shared.ts +++ b/src/testRunner/parallel/shared.ts @@ -1,4 +1,6 @@ -import { TestRunnerKind } from "../_namespaces/Harness"; +import { + TestRunnerKind, +} from "../_namespaces/Harness"; import * as ts from "../_namespaces/ts"; export interface RunnerTask { @@ -55,7 +57,7 @@ export type ParallelHostMessage = ParallelTestMessage | ParallelCloseMessage | P export interface ParallelErrorMessage { type: "error"; - payload: { error: string, stack: string, name?: string[] }; + payload: { error: string; stack: string; name?: string[]; }; } export interface ParallelResultMessage { @@ -73,17 +75,21 @@ export interface ParallelTimeoutChangeMessage { payload: TaskTimeout; } -export type ParallelClientMessage = ParallelErrorMessage | ParallelResultMessage | ParallelBatchProgressMessage | ParallelTimeoutChangeMessage; +export type ParallelClientMessage = + | ParallelErrorMessage + | ParallelResultMessage + | ParallelBatchProgressMessage + | ParallelTimeoutChangeMessage; export function shimNoopTestInterface(global: Mocha.MochaGlobals) { global.before = ts.noop; global.after = ts.noop; global.beforeEach = ts.noop; global.afterEach = ts.noop; - global.describe = global.context = ((_: any, __: any) => { /*empty*/ }) as Mocha.SuiteFunction; + global.describe = global.context = ((_: any, __: any) => {/*empty*/}) as Mocha.SuiteFunction; global.describe.skip = global.xdescribe = global.xcontext = ts.noop as Mocha.PendingSuiteFunction; global.describe.only = ts.noop as Mocha.ExclusiveSuiteFunction; - global.it = global.specify = ((_: any, __: any) => { /*empty*/ }) as Mocha.TestFunction; + global.it = global.specify = ((_: any, __: any) => {/*empty*/}) as Mocha.TestFunction; global.it.skip = global.xit = global.xspecify = ts.noop as Mocha.PendingTestFunction; global.it.only = ts.noop as Mocha.ExclusiveTestFunction; } diff --git a/src/testRunner/parallel/worker.ts b/src/testRunner/parallel/worker.ts index e65020391f158..9916b061f093c 100644 --- a/src/testRunner/parallel/worker.ts +++ b/src/testRunner/parallel/worker.ts @@ -115,16 +115,28 @@ export function start() { */ function shimTestInterface(rootSuite: Mocha.Suite, context: Mocha.MochaGlobals) { const suites = [rootSuite]; - context.before = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => suites[0].beforeAll(title as string, fn); - context.after = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => suites[0].afterAll(title as string, fn); - context.beforeEach = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => suites[0].beforeEach(title as string, fn); - context.afterEach = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => suites[0].afterEach(title as string, fn); - context.describe = context.context = ((title: string, fn: (this: Mocha.Suite) => void) => addSuite(title, fn)) as Mocha.SuiteFunction; - context.describe.skip = context.xdescribe = context.xcontext = (title: string) => addSuite(title, /*fn*/ undefined); + context.before = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + suites[0].beforeAll(title as string, fn); + context.after = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + suites[0].afterAll(title as string, fn); + context.beforeEach = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + suites[0].beforeEach(title as string, fn); + context.afterEach = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + suites[0].afterEach(title as string, fn); + context.describe = + context.context = + ((title: string, fn: (this: Mocha.Suite) => void) => addSuite(title, fn)) as Mocha.SuiteFunction; + context.describe.skip = context.xdescribe = context.xcontext = (title: string) => + addSuite(title, /*fn*/ undefined); context.describe.only = (title: string, fn?: (this: Mocha.Suite) => void) => addSuite(title, fn); - context.it = context.specify = ((title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => addTest(title, fn)) as Mocha.TestFunction; - context.it.skip = context.xit = context.xspecify = (title: string | Mocha.Func | Mocha.AsyncFunc) => addTest(typeof title === "function" ? title.name : title, /*fn*/ undefined); - context.it.only = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => addTest(title, fn); + context.it = + context.specify = + ((title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + addTest(title, fn)) as Mocha.TestFunction; + context.it.skip = context.xit = context.xspecify = (title: string | Mocha.Func | Mocha.AsyncFunc) => + addTest(typeof title === "function" ? title.name : title, /*fn*/ undefined); + context.it.only = (title: string | Mocha.Func | Mocha.AsyncFunc, fn?: Mocha.Func | Mocha.AsyncFunc) => + addTest(title, fn); function addSuite(title: string, fn: ((this: Mocha.Suite) => void) | undefined): Mocha.Suite { const suite = new Suite(title, suites[0].ctx); @@ -138,7 +150,10 @@ export function start() { return suite; } - function addTest(title: string | Mocha.Func | Mocha.AsyncFunc, fn: Mocha.Func | Mocha.AsyncFunc | undefined): Mocha.Test { + function addTest( + title: string | Mocha.Func | Mocha.AsyncFunc, + fn: Mocha.Func | Mocha.AsyncFunc | undefined, + ): Mocha.Test { if (typeof title === "function") { fn = title; title = fn.name; @@ -252,10 +267,14 @@ export function start() { */ function validateHostMessage(message: ParallelHostMessage) { switch (message.type) { - case "test": return validateTest(message.payload); - case "batch": return validateBatch(message.payload); - case "close": return true; - default: return false; + case "test": + return validateTest(message.payload); + case "batch": + return validateBatch(message.payload); + case "close": + return true; + default: + return false; } } @@ -280,9 +299,12 @@ export function start() { } switch (message.type) { - case "test": return processTest(message.payload, /*last*/ true); - case "batch": return processBatch(message.payload); - case "close": return process.exit(0); + case "test": + return processTest(message.payload, /*last*/ true); + case "batch": + return processBatch(message.payload); + case "close": + return process.exit(0); } } diff --git a/src/testRunner/projectsRunner.ts b/src/testRunner/projectsRunner.ts index bae70f81f6590..a84c2501ec940 100644 --- a/src/testRunner/projectsRunner.ts +++ b/src/testRunner/projectsRunner.ts @@ -61,21 +61,29 @@ export class ProjectRunner extends Harness.RunnerBase { private runProjectTestCase(testCaseFileName: string) { for (const { name, payload } of ProjectTestCase.getConfigurations(testCaseFileName)) { - describe("Compiling project for " + payload.testCase.scenario + ": testcase " + testCaseFileName + (name ? ` (${name})` : ``), () => { - let projectTestCase: ProjectTestCase | undefined; - before(() => { - projectTestCase = new ProjectTestCase(testCaseFileName, payload); - }); - it(`Correct module resolution tracing for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifyResolution()); - it(`Correct errors for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifyDiagnostics()); - it(`Correct JS output for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifyJavaScriptOutput()); - // NOTE: This check was commented out in previous code. Leaving this here to eventually be restored if needed. - // it(`Correct sourcemap content for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifySourceMapRecord()); - it(`Correct declarations for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifyDeclarations()); - after(() => { - projectTestCase = undefined; - }); - }); + describe( + "Compiling project for " + payload.testCase.scenario + ": testcase " + testCaseFileName + + (name ? ` (${name})` : ``), + () => { + let projectTestCase: ProjectTestCase | undefined; + before(() => { + projectTestCase = new ProjectTestCase(testCaseFileName, payload); + }); + it(`Correct module resolution tracing for ${testCaseFileName}`, () => + projectTestCase && projectTestCase.verifyResolution()); + it(`Correct errors for ${testCaseFileName}`, () => + projectTestCase && projectTestCase.verifyDiagnostics()); + it(`Correct JS output for ${testCaseFileName}`, () => + projectTestCase && projectTestCase.verifyJavaScriptOutput()); + // NOTE: This check was commented out in previous code. Leaving this here to eventually be restored if needed. + // it(`Correct sourcemap content for ${testCaseFileName}`, () => projectTestCase && projectTestCase.verifySourceMapRecord()); + it(`Correct declarations for ${testCaseFileName}`, () => + projectTestCase && projectTestCase.verifyDeclarations()); + after(() => { + projectTestCase = undefined; + }); + }, + ); } } } @@ -84,13 +92,20 @@ class ProjectCompilerHost extends fakes.CompilerHost { private _testCase: ProjectRunnerTestCase & ts.CompilerOptions; private _projectParseConfigHost: ProjectParseConfigHost | undefined; - constructor(sys: fakes.System | vfs.FileSystem, compilerOptions: ts.CompilerOptions, _testCaseJustName: string, testCase: ProjectRunnerTestCase & ts.CompilerOptions, _moduleKind: ts.ModuleKind) { + constructor( + sys: fakes.System | vfs.FileSystem, + compilerOptions: ts.CompilerOptions, + _testCaseJustName: string, + testCase: ProjectRunnerTestCase & ts.CompilerOptions, + _moduleKind: ts.ModuleKind, + ) { super(sys, compilerOptions); this._testCase = testCase; } public override get parseConfigHost(): fakes.ParseConfigHost { - return this._projectParseConfigHost || (this._projectParseConfigHost = new ProjectParseConfigHost(this.sys, this._testCase)); + return this._projectParseConfigHost + || (this._projectParseConfigHost = new ProjectParseConfigHost(this.sys, this._testCase)); } public override getDefaultLibFileName(_options: ts.CompilerOptions) { @@ -106,14 +121,22 @@ class ProjectParseConfigHost extends fakes.ParseConfigHost { this._testCase = testCase; } - public override readDirectory(path: string, extensions: string[], excludes: string[], includes: string[], depth: number): string[] { + public override readDirectory( + path: string, + extensions: string[], + excludes: string[], + includes: string[], + depth: number, + ): string[] { const result = super.readDirectory(path, extensions, excludes, includes, depth); const projectRoot = vpath.resolve(vfs.srcFolder, this._testCase.projectRoot); - return result.map(item => vpath.relative( - projectRoot, - vpath.resolve(projectRoot, item), - this.vfs.ignoreCase - )); + return result.map(item => + vpath.relative( + projectRoot, + vpath.resolve(projectRoot, item), + this.vfs.ignoreCase, + ) + ); } } @@ -158,14 +181,31 @@ class ProjectTestCase { const result = ts.readJsonConfigFile(configFileName, path => this.sys.readFile(path)); configFileSourceFiles.push(result); const configParseHost = new ProjectParseConfigHost(this.sys, this.testCase); - const configParseResult = ts.parseJsonSourceFileConfigFileContent(result, configParseHost, ts.getDirectoryPath(configFileName), this.compilerOptions); + const configParseResult = ts.parseJsonSourceFileConfigFileContent( + result, + configParseHost, + ts.getDirectoryPath(configFileName), + this.compilerOptions, + ); inputFiles = configParseResult.fileNames; this.compilerOptions = configParseResult.options; errors = [...result.parseDiagnostics, ...configParseResult.errors]; } - const compilerHost = new ProjectCompilerHost(this.sys, this.compilerOptions, this.testCaseJustName, this.testCase, moduleKind); - const projectCompilerResult = this.compileProjectFiles(moduleKind, configFileSourceFiles, () => inputFiles, compilerHost, this.compilerOptions); + const compilerHost = new ProjectCompilerHost( + this.sys, + this.compilerOptions, + this.testCaseJustName, + this.testCase, + moduleKind, + ); + const projectCompilerResult = this.compileProjectFiles( + moduleKind, + configFileSourceFiles, + () => inputFiles, + compilerHost, + this.compilerOptions, + ); this.compilerResult = { configFileSourceFiles, @@ -201,38 +241,57 @@ class ProjectTestCase { } const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false); - fs.mountSync(vpath.resolve(Harness.IO.getWorkspaceRoot(), "tests"), vpath.combine(vfs.srcFolder, "tests"), vfs.createResolver(Harness.IO)); + fs.mountSync( + vpath.resolve(Harness.IO.getWorkspaceRoot(), "tests"), + vpath.combine(vfs.srcFolder, "tests"), + vfs.createResolver(Harness.IO), + ); fs.mkdirpSync(vpath.combine(vfs.srcFolder, testCase.projectRoot)); fs.chdir(vpath.combine(vfs.srcFolder, testCase.projectRoot)); fs.makeReadonly(); return [ { name: `@module: commonjs`, payload: { testCase, moduleKind: ts.ModuleKind.CommonJS, vfs: fs } }, - { name: `@module: amd`, payload: { testCase, moduleKind: ts.ModuleKind.AMD, vfs: fs } } + { name: `@module: amd`, payload: { testCase, moduleKind: ts.ModuleKind.AMD, vfs: fs } }, ]; } public verifyResolution() { const cwd = this.vfs.cwd(); const ignoreCase = this.vfs.ignoreCase; - const resolutionInfo: ProjectRunnerTestCaseResolutionInfo & ts.CompilerOptions = JSON.parse(JSON.stringify(this.testCase)); + const resolutionInfo: ProjectRunnerTestCaseResolutionInfo & ts.CompilerOptions = JSON.parse( + JSON.stringify(this.testCase), + ); resolutionInfo.resolvedInputFiles = this.compilerResult.program!.getSourceFiles() .map(({ fileName: input }) => - vpath.beneath(vfs.builtFolder, input, this.vfs.ignoreCase) || vpath.beneath(vfs.testLibFolder, input, this.vfs.ignoreCase) ? Utils.removeTestPathPrefixes(input) : - vpath.isAbsolute(input) ? vpath.relative(cwd, input, ignoreCase) : - input); + vpath.beneath(vfs.builtFolder, input, this.vfs.ignoreCase) + || vpath.beneath(vfs.testLibFolder, input, this.vfs.ignoreCase) + ? Utils.removeTestPathPrefixes(input) + : vpath.isAbsolute(input) ? vpath.relative(cwd, input, ignoreCase) + : input + ); resolutionInfo.emittedFiles = this.compilerResult.outputFiles! .map(output => output.meta.get("fileName") || output.file) - .map(output => Utils.removeTestPathPrefixes(vpath.isAbsolute(output) ? vpath.relative(cwd, output, ignoreCase) : output)); + .map(output => + Utils.removeTestPathPrefixes( + vpath.isAbsolute(output) ? vpath.relative(cwd, output, ignoreCase) : output, + ) + ); const content = JSON.stringify(resolutionInfo, undefined, " "); - Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".json", content); + Harness.Baseline.runBaseline( + this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".json", + content, + ); } public verifyDiagnostics() { if (this.compilerResult.errors.length) { - Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".errors.txt", getErrorsBaseline(this.compilerResult)); + Harness.Baseline.runBaseline( + this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".errors.txt", + getErrorsBaseline(this.compilerResult), + ); } } @@ -245,7 +304,8 @@ class ProjectTestCase { // convert file name to rooted name // if filename is not rooted - concat it with project root and then expand project root relative to current directory const fileName = output.meta.get("fileName") || output.file; - const diskFileName = vpath.isAbsolute(fileName) ? fileName : vpath.resolve(this.vfs.cwd(), fileName); + const diskFileName = vpath.isAbsolute(fileName) ? fileName + : vpath.resolve(this.vfs.cwd(), fileName); // compute file name relative to current directory (expanded project root) let diskRelativeName = vpath.relative(this.vfs.cwd(), diskFileName, this.vfs.ignoreCase); @@ -253,12 +313,20 @@ class ProjectTestCase { // If the generated output file resides in the parent folder or is rooted path, // we need to instead create files that can live in the project reference folder // but make sure extension of these files matches with the fileName the compiler asked to write - diskRelativeName = `diskFile${nonSubfolderDiskFiles}${vpath.extname(fileName, [".js.map", ".js", ".d.ts"], this.vfs.ignoreCase)}`; + diskRelativeName = `diskFile${nonSubfolderDiskFiles}${ + vpath.extname(fileName, [".js.map", ".js", ".d.ts"], this.vfs.ignoreCase) + }`; nonSubfolderDiskFiles++; } - const content = Utils.removeTestPathPrefixes(output.text, /*retainTrailingDirectorySeparator*/ true); - Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + diskRelativeName, content as string | null); // TODO: GH#18217 + const content = Utils.removeTestPathPrefixes( + output.text, + /*retainTrailingDirectorySeparator*/ true, + ); + Harness.Baseline.runBaseline( + this.getBaselineFolder(this.compilerResult.moduleKind) + diskRelativeName, + content as string | null, + ); // TODO: GH#18217 } catch (e) { errs.push(e); @@ -285,7 +353,10 @@ class ProjectTestCase { if (!this.compilerResult.errors.length && this.testCase.declaration) { const dTsCompileResult = this.compileDeclarations(this.compilerResult); if (dTsCompileResult && dTsCompileResult.errors.length) { - Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".dts.errors.txt", getErrorsBaseline(dTsCompileResult)); + Harness.Baseline.runBaseline( + this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".dts.errors.txt", + getErrorsBaseline(dTsCompileResult), + ); } } } @@ -318,11 +389,13 @@ class ProjectTestCase { return url; } - private compileProjectFiles(moduleKind: ts.ModuleKind, configFileSourceFiles: readonly ts.SourceFile[], + private compileProjectFiles( + moduleKind: ts.ModuleKind, + configFileSourceFiles: readonly ts.SourceFile[], getInputFiles: () => readonly string[], compilerHost: ts.CompilerHost, - compilerOptions: ts.CompilerOptions): CompileProjectFilesResult { - + compilerOptions: ts.CompilerOptions, + ): CompileProjectFilesResult { const program = ts.createProgram(getInputFiles(), compilerOptions, compilerHost); const errors = ts.getPreEmitDiagnostics(program); @@ -334,7 +407,7 @@ class ProjectTestCase { data.sourceMap = { ...data.sourceMap, sources: data.sourceMap.sources.map(source => this.cleanProjectUrl(source)), - sourceRoot: data.sourceMap.sourceRoot && this.cleanProjectUrl(data.sourceMap.sourceRoot) + sourceRoot: data.sourceMap.sourceRoot && this.cleanProjectUrl(data.sourceMap.sourceRoot), }; } } @@ -344,7 +417,7 @@ class ProjectTestCase { moduleKind, program, errors: ts.concatenate(errors, emitDiagnostics), - sourceMapData + sourceMapData, }; } @@ -366,9 +439,14 @@ class ProjectTestCase { else if (!(compilerOptions.outFile || compilerOptions.out)) { let emitOutputFilePathWithoutExtension: string | undefined; if (compilerOptions.outDir) { - let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, compilerResult.program!.getCurrentDirectory()); + let sourceFilePath = ts.getNormalizedAbsolutePath( + sourceFile.fileName, + compilerResult.program!.getCurrentDirectory(), + ); sourceFilePath = sourceFilePath.replace(compilerResult.program!.getCommonSourceDirectory(), ""); - emitOutputFilePathWithoutExtension = ts.removeFileExtension(ts.combinePaths(compilerOptions.outDir, sourceFilePath)); + emitOutputFilePathWithoutExtension = ts.removeFileExtension( + ts.combinePaths(compilerOptions.outDir, sourceFilePath), + ); } else { emitOutputFilePathWithoutExtension = ts.removeFileExtension(sourceFile.fileName); @@ -382,7 +460,8 @@ class ProjectTestCase { } } else { - const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out!) + ts.Extension.Dts; + const outputDtsFileName = ts.removeFileExtension(compilerOptions.outFile || compilerOptions.out!) + + ts.Extension.Dts; const outputDtsFile = findOutputDtsFile(outputDtsFileName)!; if (!ts.contains(allInputFiles, outputDtsFile)) { allInputFiles.unshift(outputDtsFile); @@ -393,22 +472,37 @@ class ProjectTestCase { const _vfs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: allInputFiles, - cwd: vpath.combine(vfs.srcFolder, this.testCase.projectRoot) + cwd: vpath.combine(vfs.srcFolder, this.testCase.projectRoot), }); // Dont allow config files since we are compiling existing source options - const compilerHost = new ProjectCompilerHost(_vfs, compilerResult.compilerOptions!, this.testCaseJustName, this.testCase, compilerResult.moduleKind); - return this.compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, () => rootFiles, compilerHost, compilerResult.compilerOptions!); + const compilerHost = new ProjectCompilerHost( + _vfs, + compilerResult.compilerOptions!, + this.testCaseJustName, + this.testCase, + compilerResult.moduleKind, + ); + return this.compileProjectFiles( + compilerResult.moduleKind, + compilerResult.configFileSourceFiles, + () => rootFiles, + compilerHost, + compilerResult.compilerOptions!, + ); function findOutputDtsFile(fileName: string) { - return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.meta.get("fileName") === fileName ? outputFile : undefined); + return ts.forEach( + compilerResult.outputFiles, + outputFile => outputFile.meta.get("fileName") === fileName ? outputFile : undefined, + ); } } } function moduleNameToString(moduleKind: ts.ModuleKind) { - return moduleKind === ts.ModuleKind.AMD ? "amd" : - moduleKind === ts.ModuleKind.CommonJS ? "node" : "none"; + return moduleKind === ts.ModuleKind.AMD ? "amd" + : moduleKind === ts.ModuleKind.CommonJS ? "node" : "none"; } function getErrorsBaseline(compilerResult: CompileProjectFilesResult) { @@ -422,10 +516,10 @@ function getErrorsBaseline(compilerResult: CompileProjectFilesResult) { } const inputFiles = inputSourceFiles.map(sourceFile => ({ - unitName: ts.isRootedDiskPath(sourceFile.fileName) ? - Harness.RunnerBase.removeFullPaths(sourceFile.fileName) : - sourceFile.fileName, - content: sourceFile.text + unitName: ts.isRootedDiskPath(sourceFile.fileName) + ? Harness.RunnerBase.removeFullPaths(sourceFile.fileName) + : sourceFile.fileName, + content: sourceFile.text, })); return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors); @@ -445,7 +539,7 @@ function createCompilerOptions(testCase: ProjectRunnerTestCase & ts.CompilerOpti sourceRoot: testCase.resolveSourceRoot && testCase.sourceRoot ? vpath.resolve(vfs.srcFolder, testCase.sourceRoot) - : testCase.sourceRoot + : testCase.sourceRoot, }; // Set the values specified using json diff --git a/src/testRunner/runner.ts b/src/testRunner/runner.ts index 3331be003e784..396c9da080b5b 100644 --- a/src/testRunner/runner.ts +++ b/src/testRunner/runner.ts @@ -81,12 +81,11 @@ const mytestconfigFileName = "mytest.config"; const testconfigFileName = "test.config"; const customConfig = tryGetConfig(IO.args()); -const testConfigContent = - customConfig && IO.fileExists(customConfig) - ? IO.readFile(customConfig)! - : IO.fileExists(mytestconfigFileName) - ? IO.readFile(mytestconfigFileName)! - : IO.fileExists(testconfigFileName) ? IO.readFile(testconfigFileName)! : ""; +const testConfigContent = customConfig && IO.fileExists(customConfig) + ? IO.readFile(customConfig)! + : IO.fileExists(mytestconfigFileName) + ? IO.readFile(mytestconfigFileName)! + : IO.fileExists(testconfigFileName) ? IO.readFile(testconfigFileName)! : ""; export let taskConfigsFolder: string; export let workerCount: number; @@ -232,7 +231,7 @@ function beginTests() { ts.Debug.loggingHost = { log(_level, s) { console.log(s || ""); - } + }, }; if (ts.Debug.isDebugging) { diff --git a/src/testRunner/unittests/asserts.ts b/src/testRunner/unittests/asserts.ts index 23d8e20a0df95..9b38fb4302e98 100644 --- a/src/testRunner/unittests/asserts.ts +++ b/src/testRunner/unittests/asserts.ts @@ -2,11 +2,24 @@ import * as ts from "../_namespaces/ts"; describe("unittests:: assert", () => { it("deepEqual", () => { - assert.throws(() => assert.deepEqual(ts.factory.createNodeArray([ts.factory.createIdentifier("A")]), ts.factory.createNodeArray([ts.factory.createIdentifier("B")]))); - assert.throws(() => assert.deepEqual(ts.factory.createNodeArray([], /*hasTrailingComma*/ true), ts.factory.createNodeArray([], /*hasTrailingComma*/ false))); - assert.deepEqual(ts.factory.createNodeArray([ts.factory.createIdentifier("A")], /*hasTrailingComma*/ true), ts.factory.createNodeArray([ts.factory.createIdentifier("A")], /*hasTrailingComma*/ true)); + assert.throws(() => + assert.deepEqual( + ts.factory.createNodeArray([ts.factory.createIdentifier("A")]), + ts.factory.createNodeArray([ts.factory.createIdentifier("B")]), + ) + ); + assert.throws(() => + assert.deepEqual( + ts.factory.createNodeArray([], /*hasTrailingComma*/ true), + ts.factory.createNodeArray([], /*hasTrailingComma*/ false), + ) + ); + assert.deepEqual( + ts.factory.createNodeArray([ts.factory.createIdentifier("A")], /*hasTrailingComma*/ true), + ts.factory.createNodeArray([ts.factory.createIdentifier("A")], /*hasTrailingComma*/ true), + ); }); it("assertNever on string has correct error", () => { - assert.throws(() => ts.Debug.assertNever("hi" as never), "Debug Failure. Illegal value: \"hi\""); + assert.throws(() => ts.Debug.assertNever("hi" as never), 'Debug Failure. Illegal value: "hi"'); }); }); diff --git a/src/testRunner/unittests/builder.ts b/src/testRunner/unittests/builder.ts index 2c965e45323e0..79fee960eb820 100644 --- a/src/testRunner/unittests/builder.ts +++ b/src/testRunner/unittests/builder.ts @@ -81,7 +81,7 @@ describe("unittests:: builder", () => { }); function makeAssertChanges(getProgram: () => ts.Program): (fileNames: readonly string[]) => void { - const host: ts.BuilderProgramHost = { }; + const host: ts.BuilderProgramHost = {}; let builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram | undefined; return fileNames => { const program = getProgram(); @@ -94,8 +94,10 @@ function makeAssertChanges(getProgram: () => ts.Program): (fileNames: readonly s }; } -function makeAssertChangesWithCancellationToken(getProgram: () => ts.Program): (fileNames: readonly string[], cancelAfterEmitLength?: number) => void { - const host: ts.BuilderProgramHost = { }; +function makeAssertChangesWithCancellationToken( + getProgram: () => ts.Program, +): (fileNames: readonly string[], cancelAfterEmitLength?: number) => void { + const host: ts.BuilderProgramHost = {}; let builderProgram: ts.EmitAndSemanticDiagnosticsBuilderProgram | undefined; let cancel = false; const cancellationToken: ts.CancellationToken = { @@ -118,7 +120,8 @@ function makeAssertChangesWithCancellationToken(getProgram: () => ts.Program): ( if (outputFileNames.length === cancelAfterEmitLength) { cancel = true; } - } while (builderProgram.emitNextAffectedFile(fileName => outputFileNames.push(fileName), cancellationToken)); + } + while (builderProgram.emitNextAffectedFile(fileName => outputFileNames.push(fileName), cancellationToken)); } catch (e) { assert.isFalse(operationWasCancelled); @@ -131,7 +134,11 @@ function makeAssertChangesWithCancellationToken(getProgram: () => ts.Program): ( }; } -function updateProgramFile(program: ProgramWithSourceTexts, fileName: string, fileContent: string): ProgramWithSourceTexts { +function updateProgramFile( + program: ProgramWithSourceTexts, + fileName: string, + fileContent: string, +): ProgramWithSourceTexts { return updateProgram(program, program.getRootFileNames(), program.getCompilerOptions(), files => { updateProgramText(files, fileName, fileContent); }); diff --git a/src/testRunner/unittests/canWatch.ts b/src/testRunner/unittests/canWatch.ts index cf6d005e097a4..b4a1706ef8ed6 100644 --- a/src/testRunner/unittests/canWatch.ts +++ b/src/testRunner/unittests/canWatch.ts @@ -1,5 +1,6 @@ - -import { Baseline } from "../_namespaces/Harness"; +import { + Baseline, +} from "../_namespaces/Harness"; import * as ts from "../_namespaces/ts"; describe("unittests:: canWatch::", () => { baselineCanWatch( @@ -21,7 +22,8 @@ describe("unittests:: canWatch::", () => { baselineCanWatch( "canWatchAtTypes", - () => `Determines if given node_modules/@types can be watched.\r\nThese are the typeRoots calculated because user didnt specify typeRoots in compierOptions`, + () => + `Determines if given node_modules/@types can be watched.\r\nThese are the typeRoots calculated because user didnt specify typeRoots in compierOptions`, (paths, longestPathLength, baseline) => { const testType = "canWatchAtTypes"; const maxLengths = [longestPathLength + "/node_modules/@types".length, testType.length] as const; @@ -36,7 +38,8 @@ describe("unittests:: canWatch::", () => { baselineCanWatch( "canWatchAffectingLocation", - () => `Determines if package.json that was found during module resolution and change in it will affect resolution can be watched.`, + () => + `Determines if package.json that was found during module resolution and change in it will affect resolution can be watched.`, (paths, longestPathLength, baseline) => { const testType = "canWatchAffectingLocation"; const maxLengths = [longestPathLength + "/package.json".length, testType.length] as const; @@ -58,20 +61,45 @@ describe("unittests:: canWatch::", () => { ) { baselineCanWatch( scenario, - () => `Determines whether to watch given failed lookup location (file that didnt exist) when resolving module.\r\nIt also determines the directory to watch and whether to watch it recursively or not.`, + () => + `Determines whether to watch given failed lookup location (file that didnt exist) when resolving module.\r\nIt also determines the directory to watch and whether to watch it recursively or not.`, (paths, longestPathLength, baseline) => { const recursive = "Recursive"; const maxLength = longestPathLength + ts.combinePaths(forPath, "dir/subdir/somefile.d.ts").length; const maxLengths = [maxLength, maxLength, recursive.length] as const; baselineCanWatchForRoot(paths, baseline, (rootPathCompoments, root) => { - pushHeader(baseline, ["Location", "getDirectoryToWatchFailedLookupLocation", recursive], maxLengths); + pushHeader( + baseline, + ["Location", "getDirectoryToWatchFailedLookupLocation", recursive], + maxLengths, + ); paths.forEach(path => { - baselineGetDirectoryToWatchFailedLookupLocation(combinePaths(path, forPath, "somefile.d.ts"), root, rootPathCompoments, maxLengths); - baselineGetDirectoryToWatchFailedLookupLocation(combinePaths(path, forPath, "dir/somefile.d.ts"), root, rootPathCompoments, maxLengths); - baselineGetDirectoryToWatchFailedLookupLocation(combinePaths(path, forPath, "dir/subdir/somefile.d.ts"), root, rootPathCompoments, maxLengths); + baselineGetDirectoryToWatchFailedLookupLocation( + combinePaths(path, forPath, "somefile.d.ts"), + root, + rootPathCompoments, + maxLengths, + ); + baselineGetDirectoryToWatchFailedLookupLocation( + combinePaths(path, forPath, "dir/somefile.d.ts"), + root, + rootPathCompoments, + maxLengths, + ); + baselineGetDirectoryToWatchFailedLookupLocation( + combinePaths(path, forPath, "dir/subdir/somefile.d.ts"), + root, + rootPathCompoments, + maxLengths, + ); }); }); - function baselineGetDirectoryToWatchFailedLookupLocation(path: ts.Path, root: ts.Path, rootPathCompoments: Readonly, maxLengths: readonly number[]) { + function baselineGetDirectoryToWatchFailedLookupLocation( + path: ts.Path, + root: ts.Path, + rootPathCompoments: Readonly, + maxLengths: readonly number[], + ) { const result = ts.getDirectoryToWatchFailedLookupLocation( path, path, @@ -80,7 +108,11 @@ describe("unittests:: canWatch::", () => { rootPathCompoments, ts.returnUndefined, ); - pushRow(baseline, [path, result ? result.dir : "", result ? `${!result.nonRecursive}` : ""], maxLengths); + pushRow( + baseline, + [path, result ? result.dir : "", result ? `${!result.nonRecursive}` : ""], + maxLengths, + ); } }, ); @@ -88,7 +120,8 @@ describe("unittests:: canWatch::", () => { baselineCanWatch( "getDirectoryToWatchFailedLookupLocationFromTypeRoot", - () => `When watched typeRoot handler is invoked, this method determines the directory for which the failedLookupLocation would need to be invalidated.\r\nSince this is invoked only when watching default typeRoot and is used to handle flaky directory watchers, this is used as a fail safe where if failed lookup starts with returned directory we will invalidate that resolution.`, + () => + `When watched typeRoot handler is invoked, this method determines the directory for which the failedLookupLocation would need to be invalidated.\r\nSince this is invoked only when watching default typeRoot and is used to handle flaky directory watchers, this is used as a fail safe where if failed lookup starts with returned directory we will invalidate that resolution.`, (paths, longestPathLength, baseline) => { const maxLength = longestPathLength + "/node_modules/@types".length; const maxLengths = [maxLength, maxLength] as const; @@ -112,7 +145,11 @@ describe("unittests:: canWatch::", () => { }, ); - function baselineCanWatchForRoot(paths: readonly ts.Path[], baseline: string[], baselineForRoot: (rootPathCompoments: Readonly, root: ts.Path) => void) { + function baselineCanWatchForRoot( + paths: readonly ts.Path[], + baseline: string[], + baselineForRoot: (rootPathCompoments: Readonly, root: ts.Path) => void, + ) { paths.forEach(rootDirForResolution => { const root = ts.getRootDirectoryOfResolutionCache(rootDirForResolution, ts.returnUndefined) as ts.Path; assert(root === rootDirForResolution); @@ -195,4 +232,4 @@ describe("unittests:: canWatch::", () => { baseline.push(result); if (divider) baseline.push(divider); } -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/config/commandLineParsing.ts b/src/testRunner/unittests/config/commandLineParsing.ts index 33a6ad5c24db9..b6fa0fc6110e6 100644 --- a/src/testRunner/unittests/config/commandLineParsing.ts +++ b/src/testRunner/unittests/config/commandLineParsing.ts @@ -2,11 +2,18 @@ import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => { - function assertParseResult(subScenario: string, commandLine: string[], workerDiagnostic?: () => ts.ParseCommandLineWorkerDiagnostics) { + function assertParseResult( + subScenario: string, + commandLine: string[], + workerDiagnostic?: () => ts.ParseCommandLineWorkerDiagnostics, + ) { it(subScenario, () => { const baseline: string[] = []; baseline.push(commandLine.join(" ")); - const parsed = ts.parseCommandLineWorker(workerDiagnostic?.() || ts.compilerOptionsDidYouMeanDiagnostics, commandLine); + const parsed = ts.parseCommandLineWorker( + workerDiagnostic?.() || ts.compilerOptionsDidYouMeanDiagnostics, + commandLine, + ); baseline.push("CompilerOptions::"); baseline.push(JSON.stringify(parsed.options, /*replacer*/ undefined, " ")); baseline.push("WatchOptions::"); @@ -19,7 +26,10 @@ describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => { getCanonicalFileName: ts.identity, getNewLine: () => "\n", })); - Harness.Baseline.runBaseline(`config/commandLineParsing/parseCommandLine/${subScenario}.js`, baseline.join("\n")); + Harness.Baseline.runBaseline( + `config/commandLineParsing/parseCommandLine/${subScenario}.js`, + baseline.join("\n"), + ); }); } @@ -54,11 +64,35 @@ describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => { // --lib es5, es7 0.ts assertParseResult("Parse --lib option with trailing white-space", ["--lib", "es5, ", "es7", "0.ts"]); // --lib es5,es2015.symbol.wellknown --target es5 0.ts - assertParseResult("Parse multiple compiler flags with input files at the end", ["--lib", "es5,es2015.symbol.wellknown", "--target", "es5", "0.ts"]); + assertParseResult("Parse multiple compiler flags with input files at the end", [ + "--lib", + "es5,es2015.symbol.wellknown", + "--target", + "es5", + "0.ts", + ]); // --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown - assertParseResult("Parse multiple compiler flags with input files in the middle", ["--module", "commonjs", "--target", "es5", "0.ts", "--lib", "es5,es2015.symbol.wellknown"]); + assertParseResult("Parse multiple compiler flags with input files in the middle", [ + "--module", + "commonjs", + "--target", + "es5", + "0.ts", + "--lib", + "es5,es2015.symbol.wellknown", + ]); // --module commonjs --target es5 --lib es5 0.ts --library es2015.array,es2015.symbol.wellknown - assertParseResult("Parse multiple library compiler flags ", ["--module", "commonjs", "--target", "es5", "--lib", "es5", "0.ts", "--lib", "es2015.core, es2015.symbol.wellknown "]); + assertParseResult("Parse multiple library compiler flags ", [ + "--module", + "commonjs", + "--target", + "es5", + "--lib", + "es5", + "0.ts", + "--lib", + "es2015.core, es2015.symbol.wellknown ", + ]); assertParseResult("Parse explicit boolean flag value", ["--strictNullChecks", "false", "0.ts"]); assertParseResult("Parse non boolean argument after boolean flag", ["--noImplicitAny", "t", "0.ts"]); assertParseResult("Parse implicit boolean flag value", ["--strictNullChecks"]); @@ -67,7 +101,7 @@ describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => { describe("parses command line null for tsconfig only option", () => { interface VerifyNull { - subScenario: string, + subScenario: string; optionName: string; nonNullValue?: string; workerDiagnostic?: () => ts.ParseCommandLineWorkerDiagnostics; @@ -77,32 +111,32 @@ describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => { assertParseResult( `${subScenario} allows setting it to null`, [`--${optionName}`, "null", "0.ts"], - workerDiagnostic + workerDiagnostic, ); if (nonNullValue) { assertParseResult( `${subScenario} errors if non null value is passed`, [`--${optionName}`, nonNullValue, "0.ts"], - workerDiagnostic + workerDiagnostic, ); } assertParseResult( `${subScenario} errors if its followed by another option`, ["0.ts", "--strictNullChecks", `--${optionName}`], - workerDiagnostic + workerDiagnostic, ); assertParseResult( `${subScenario} errors if its last option`, ["0.ts", `--${optionName}`], - workerDiagnostic + workerDiagnostic, ); }); } interface VerifyNullNonIncludedOption { - subScenario: string, + subScenario: string; type: () => "string" | "number" | Map; nonNullValue?: string; } @@ -121,14 +155,14 @@ describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => { category: ts.Diagnostics.Backwards_Compatibility, description: ts.Diagnostics.Enable_project_compilation, defaultValueDescription: undefined, - } + }, ]; return { ...ts.compilerOptionsDidYouMeanDiagnostics, optionDeclarations, - getOptionsNameMap: () => ts.createOptionNameMap(optionDeclarations) + getOptionsNameMap: () => ts.createOptionNameMap(optionDeclarations), }; - } + }, }); } @@ -158,26 +192,33 @@ describe("unittests:: config:: commandLineParsing:: parseCommandLine", () => { verifyNullNonIncludedOption({ subScenario: "option of type string", type: () => "string", - nonNullValue: "hello" + nonNullValue: "hello", }); verifyNullNonIncludedOption({ subScenario: "option of type number", type: () => "number", - nonNullValue: "10" + nonNullValue: "10", }); verifyNullNonIncludedOption({ subScenario: "option of type custom map", - type: () => new Map(Object.entries({ - node: ts.ModuleResolutionKind.Node10, - classic: ts.ModuleResolutionKind.Classic, - })), - nonNullValue: "node" + type: () => + new Map(Object.entries({ + node: ts.ModuleResolutionKind.Node10, + classic: ts.ModuleResolutionKind.Classic, + })), + nonNullValue: "node", }); }); - assertParseResult("allows tsconfig only option to be set to null", ["--composite", "null", "-tsBuildInfoFile", "null", "0.ts"]); + assertParseResult("allows tsconfig only option to be set to null", [ + "--composite", + "null", + "-tsBuildInfoFile", + "null", + "0.ts", + ]); describe("Watch options", () => { assertParseResult("parse --watchFile", ["--watchFile", "UseFsEvents", "0.ts"]); @@ -210,15 +251,28 @@ describe("unittests:: config:: commandLineParsing:: parseBuildOptions", () => { getCanonicalFileName: ts.identity, getNewLine: () => "\n", })); - Harness.Baseline.runBaseline(`config/commandLineParsing/parseBuildOptions/${subScenario}.js`, baseline.join("\n")); + Harness.Baseline.runBaseline( + `config/commandLineParsing/parseBuildOptions/${subScenario}.js`, + baseline.join("\n"), + ); }); } assertParseResult("parse build without any options ", []); assertParseResult("Parse multiple options", ["--verbose", "--force", "tests"]); assertParseResult("Parse option with invalid option", ["--verbose", "--invalidOption"]); assertParseResult("Parse multiple flags with input projects at the end", ["--force", "--verbose", "src", "tests"]); - assertParseResult("Parse multiple flags with input projects in the middle", ["--force", "src", "tests", "--verbose"]); - assertParseResult("Parse multiple flags with input projects in the beginning", ["src", "tests", "--force", "--verbose"]); + assertParseResult("Parse multiple flags with input projects in the middle", [ + "--force", + "src", + "tests", + "--verbose", + ]); + assertParseResult("Parse multiple flags with input projects in the beginning", [ + "src", + "tests", + "--force", + "--verbose", + ]); assertParseResult("parse build with --incremental", ["--incremental", "tests"]); assertParseResult("parse build with --locale en-us", ["--locale", "en-us", "src"]); assertParseResult("parse build with --tsBuildInfoFile", ["--tsBuildInfoFile", "build.tsbuildinfo", "tests"]); diff --git a/src/testRunner/unittests/config/configurationExtension.ts b/src/testRunner/unittests/config/configurationExtension.ts index 6fe4159834589..f70e2c9d5e98f 100644 --- a/src/testRunner/unittests/config/configurationExtension.ts +++ b/src/testRunner/unittests/config/configurationExtension.ts @@ -2,7 +2,10 @@ import * as fakes from "../../_namespaces/fakes"; import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; import * as vfs from "../../_namespaces/vfs"; -import { baselineParseConfig, baselineParseConfigHost } from "./helpers"; +import { + baselineParseConfig, + baselineParseConfigHost, +} from "./helpers"; function createFileSystem(ignoreCase: boolean, cwd: string, root: string) { return new vfs.FileSystem(ignoreCase, { @@ -13,58 +16,58 @@ function createFileSystem(ignoreCase: boolean, cwd: string, root: string) { name: "@foo/tsconfig", version: "1.0.0", exports: { - ".": "./src/tsconfig.json" - } + ".": "./src/tsconfig.json", + }, }), "dev/node_modules/@foo/tsconfig/src/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true, - } + }, }), "dev/tsconfig.extendsFoo.json": JSON.stringify({ extends: "@foo/tsconfig", files: [ "main.ts", - ] + ], }), "dev/node_modules/config-box/package.json": JSON.stringify({ name: "config-box", version: "1.0.0", - tsconfig: "./strict.json" + tsconfig: "./strict.json", }), "dev/node_modules/config-box/strict.json": JSON.stringify({ compilerOptions: { strict: true, - } + }, }), "dev/node_modules/config-box/unstrict.json": JSON.stringify({ compilerOptions: { strict: false, - } + }, }), "dev/tsconfig.extendsBox.json": JSON.stringify({ extends: "config-box", files: [ "main.ts", - ] + ], }), "dev/tsconfig.extendsStrict.json": JSON.stringify({ extends: "config-box/strict", files: [ "main.ts", - ] + ], }), "dev/tsconfig.extendsUnStrict.json": JSON.stringify({ extends: "config-box/unstrict", files: [ "main.ts", - ] + ], }), "dev/tsconfig.extendsStrictExtension.json": JSON.stringify({ extends: "config-box/strict.json", files: [ "main.ts", - ] + ], }), "dev/node_modules/config-box-implied/package.json": JSON.stringify({ name: "config-box-implied", @@ -73,131 +76,131 @@ function createFileSystem(ignoreCase: boolean, cwd: string, root: string) { "dev/node_modules/config-box-implied/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true, - } + }, }), "dev/node_modules/config-box-implied/unstrict/tsconfig.json": JSON.stringify({ compilerOptions: { strict: false, - } + }, }), "dev/tsconfig.extendsBoxImplied.json": JSON.stringify({ extends: "config-box-implied", files: [ "main.ts", - ] + ], }), "dev/tsconfig.extendsBoxImpliedUnstrict.json": JSON.stringify({ extends: "config-box-implied/unstrict", files: [ "main.ts", - ] + ], }), "dev/tsconfig.extendsBoxImpliedUnstrictExtension.json": JSON.stringify({ extends: "config-box-implied/unstrict/tsconfig", files: [ "main.ts", - ] + ], }), "dev/tsconfig.extendsBoxImpliedPath.json": JSON.stringify({ extends: "config-box-implied/tsconfig.json", files: [ "main.ts", - ] + ], }), "dev/tsconfig.json": JSON.stringify({ extends: "./configs/base", files: [ "main.ts", - "supplemental.ts" - ] + "supplemental.ts", + ], }), "dev/tsconfig.nostrictnull.json": JSON.stringify({ extends: "./tsconfig", compilerOptions: { - strictNullChecks: false - } + strictNullChecks: false, + }, }), "dev/configs/base.json": JSON.stringify({ compilerOptions: { allowJs: true, noImplicitAny: true, - strictNullChecks: true - } + strictNullChecks: true, + }, }), "dev/configs/tests.json": JSON.stringify({ compilerOptions: { preserveConstEnums: true, removeComments: false, - sourceMap: true + sourceMap: true, }, exclude: [ "../tests/baselines", - "../tests/scenarios" + "../tests/scenarios", ], include: [ - "../tests/**/*.ts" - ] + "../tests/**/*.ts", + ], }), "dev/circular.json": JSON.stringify({ extends: "./circular2", compilerOptions: { - module: "amd" - } + module: "amd", + }, }), "dev/circular2.json": JSON.stringify({ extends: "./circular", compilerOptions: { - module: "commonjs" - } + module: "commonjs", + }, }), "dev/missing.json": JSON.stringify({ extends: "./missing2", compilerOptions: { - types: [] - } + types: [], + }, }), "dev/failure.json": JSON.stringify({ extends: "./failure2.json", compilerOptions: { - typeRoots: [] - } + typeRoots: [], + }, }), "dev/failure2.json": JSON.stringify({ - excludes: ["*.js"] + excludes: ["*.js"], }), "dev/configs/first.json": JSON.stringify({ extends: "./base", compilerOptions: { - module: "commonjs" + module: "commonjs", }, - files: ["../main.ts"] + files: ["../main.ts"], }), "dev/configs/second.json": JSON.stringify({ extends: "./base", compilerOptions: { - module: "amd" + module: "amd", }, - include: ["../supplemental.*"] + include: ["../supplemental.*"], }), "dev/configs/third.json": JSON.stringify({ extends: "./second", compilerOptions: { - module: null // eslint-disable-line no-null/no-null + module: null, // eslint-disable-line no-null/no-null }, - include: ["../supplemental.*"] + include: ["../supplemental.*"], }), "dev/configs/fourth.json": JSON.stringify({ extends: "./third", compilerOptions: { - module: "system" + module: "system", }, include: null, // eslint-disable-line no-null/no-null - files: ["../main.ts"] + files: ["../main.ts"], }), "dev/configs/fifth.json": JSON.stringify({ extends: "./fourth", include: ["../tests/utils.ts"], - files: [] + files: [], }), "dev/extends.json": JSON.stringify({ extends: 42 }), "dev/extends2.json": JSON.stringify({ extends: "configs/base" }), @@ -213,49 +216,56 @@ function createFileSystem(ignoreCase: boolean, cwd: string, root: string) { compilerOptions: { allowJs: true, noImplicitAny: true, - strictNullChecks: true - } + strictNullChecks: true, + }, }), "dev/configs/extendsArraySecond.json": JSON.stringify({ compilerOptions: { - module: "amd" + module: "amd", }, - include: ["../supplemental.*"] + include: ["../supplemental.*"], }), "dev/configs/extendsArrayThird.json": JSON.stringify({ compilerOptions: { module: null, // eslint-disable-line no-null/no-null - noImplicitAny: false + noImplicitAny: false, }, extends: "./extendsArrayFirst", - include: ["../supplemental.*"] + include: ["../supplemental.*"], }), "dev/configs/extendsArrayFourth.json": JSON.stringify({ compilerOptions: { module: "system", - strictNullChecks: false + strictNullChecks: false, }, include: null, // eslint-disable-line no-null/no-null - files: ["../main.ts"] + files: ["../main.ts"], }), "dev/configs/extendsArrayFifth.json": JSON.stringify({ - extends: ["./extendsArrayFirst", "./extendsArraySecond", "./extendsArrayThird", "./extendsArrayFourth"], + extends: [ + "./extendsArrayFirst", + "./extendsArraySecond", + "./extendsArrayThird", + "./extendsArrayFourth", + ], files: [], }), "dev/extendsArrayFails.json": JSON.stringify({ extends: ["./missingFile"], compilerOptions: { - types: [] - } + types: [], + }, }), "dev/extendsArrayFails2.json": JSON.stringify({ extends: [42] }), - } - } + }, + }, }); } const caseInsensitiveBasePath = "c:/dev/"; -const caseInsensitiveHost = new fakes.ParseConfigHost(createFileSystem(/*ignoreCase*/ true, caseInsensitiveBasePath, "c:/")); +const caseInsensitiveHost = new fakes.ParseConfigHost( + createFileSystem(/*ignoreCase*/ true, caseInsensitiveBasePath, "c:/"), +); const caseSensitiveBasePath = "/dev/"; const caseSensitiveHost = new fakes.ParseConfigHost(createFileSystem(/*ignoreCase*/ false, caseSensitiveBasePath, "/")); @@ -263,7 +273,7 @@ const caseSensitiveHost = new fakes.ParseConfigHost(createFileSystem(/*ignoreCas describe("unittests:: config:: configurationExtension", () => { ts.forEach<[string, string, fakes.ParseConfigHost], void>([ ["under a case insensitive host", caseInsensitiveBasePath, caseInsensitiveHost], - ["under a case sensitive host", caseSensitiveBasePath, caseSensitiveHost] + ["under a case sensitive host", caseSensitiveBasePath, caseSensitiveHost], ], ([testName, basePath, host]) => { const nameAndEntry: [name: string, entry: string][] = []; function baselineParsedCommandLine(name: string, entry: string) { @@ -271,7 +281,10 @@ describe("unittests:: config:: configurationExtension", () => { } baselineParsedCommandLine("can resolve an extension with a base extension", "tsconfig.json"); - baselineParsedCommandLine("can resolve an extension with a base extension that overrides options", "tsconfig.nostrictnull.json"); + baselineParsedCommandLine( + "can resolve an extension with a base extension that overrides options", + "tsconfig.nostrictnull.json", + ); baselineParsedCommandLine("can report errors on circular imports", "circular.json"); baselineParsedCommandLine("can report missing configurations", "missing.json"); baselineParsedCommandLine("can report errors in extended configs", "failure.json"); @@ -283,12 +296,27 @@ describe("unittests:: config:: configurationExtension", () => { baselineParsedCommandLine("can overwrite top-level files using extended []", "configs/fifth.json"); baselineParsedCommandLine("can lookup via tsconfig field", "tsconfig.extendsBox.json"); baselineParsedCommandLine("can lookup via package-relative path", "tsconfig.extendsStrict.json"); - baselineParsedCommandLine("can lookup via non-redirected-to package-relative path", "tsconfig.extendsUnStrict.json"); - baselineParsedCommandLine("can lookup via package-relative path with extension", "tsconfig.extendsStrictExtension.json"); + baselineParsedCommandLine( + "can lookup via non-redirected-to package-relative path", + "tsconfig.extendsUnStrict.json", + ); + baselineParsedCommandLine( + "can lookup via package-relative path with extension", + "tsconfig.extendsStrictExtension.json", + ); baselineParsedCommandLine("can lookup via an implicit tsconfig", "tsconfig.extendsBoxImplied.json"); - baselineParsedCommandLine("can lookup via an implicit tsconfig in a package-relative directory", "tsconfig.extendsBoxImpliedUnstrict.json"); - baselineParsedCommandLine("can lookup via an implicit tsconfig in a package-relative directory with name", "tsconfig.extendsBoxImpliedUnstrictExtension.json"); - baselineParsedCommandLine("can lookup via an implicit tsconfig in a package-relative directory with extension", "tsconfig.extendsBoxImpliedPath.json"); + baselineParsedCommandLine( + "can lookup via an implicit tsconfig in a package-relative directory", + "tsconfig.extendsBoxImpliedUnstrict.json", + ); + baselineParsedCommandLine( + "can lookup via an implicit tsconfig in a package-relative directory with name", + "tsconfig.extendsBoxImpliedUnstrictExtension.json", + ); + baselineParsedCommandLine( + "can lookup via an implicit tsconfig in a package-relative directory with extension", + "tsconfig.extendsBoxImpliedPath.json", + ); baselineParsedCommandLine("can lookup via an package.json exports", "tsconfig.extendsFoo.json"); baselineExtendsSourceFile("adds extendedSourceFiles only once", "configs/fourth.json"); @@ -301,20 +329,21 @@ describe("unittests:: config:: configurationExtension", () => { baselineParseConfig({ scenario: "configurationExtension", subScenario: testName, - input: () => nameAndEntry.map(([name, entry]) => ({ - createHost: baseline => { - baseline.push(name); - return host; - }, - jsonText: host.readFile(entry)!, - configFileName: entry, - baselineParsed: (baseline, parsed) => { - baseline.push("CompilerOptions::"); - baseline.push(JSON.stringify(parsed.options, undefined, " ")); - baseline.push("FileNames::"); - baseline.push(parsed.fileNames.join()); - }, - })), + input: () => + nameAndEntry.map(([name, entry]) => ({ + createHost: baseline => { + baseline.push(name); + return host; + }, + jsonText: host.readFile(entry)!, + configFileName: entry, + baselineParsed: (baseline, parsed) => { + baseline.push("CompilerOptions::"); + baseline.push(JSON.stringify(parsed.options, undefined, " ")); + baseline.push("FileNames::"); + baseline.push(parsed.fileNames.join()); + }, + })), skipFs: true, header: baseline => baselineParseConfigHost(baseline, host), }); @@ -324,13 +353,16 @@ describe("unittests:: config:: configurationExtension", () => { const baseline: string[] = []; baselineParseConfigHost(baseline, host); baseline.push(`configFileName:: ${name}`); - const sourceFile = ts.readJsonConfigFile(entry, (path) => host.readFile(path)); + const sourceFile = ts.readJsonConfigFile(entry, path => host.readFile(path)); const dir = ts.combinePaths(basePath, "configs"); ts.parseJsonSourceFileConfigFileContent(sourceFile, host, dir, {}, ts.getBaseFileName(entry)); baseline.push("ExtendedSourceFiles::", ...sourceFile.extendedSourceFiles!); ts.parseJsonSourceFileConfigFileContent(sourceFile, host, dir, {}, ts.getBaseFileName(entry)); baseline.push("After reusing sourceFile ExtendedSourceFiles::", ...sourceFile.extendedSourceFiles!); - Harness.Baseline.runBaseline(`config/configurationExtension/${name} ${testName}.js`, baseline.join("\n")); + Harness.Baseline.runBaseline( + `config/configurationExtension/${name} ${testName}.js`, + baseline.join("\n"), + ); }); } }); diff --git a/src/testRunner/unittests/config/convertCompilerOptionsFromJson.ts b/src/testRunner/unittests/config/convertCompilerOptionsFromJson.ts index d636d07c4e449..e974d8cf0159d 100644 --- a/src/testRunner/unittests/config/convertCompilerOptionsFromJson.ts +++ b/src/testRunner/unittests/config/convertCompilerOptionsFromJson.ts @@ -1,6 +1,8 @@ import * as fakes from "../../_namespaces/fakes"; import * as vfs from "../../_namespaces/vfs"; -import { baselineParseConfig } from "./helpers"; +import { + baselineParseConfig, +} from "./helpers"; describe("unittests:: config:: convertCompilerOptionsFromJson", () => { function baselineCompilerOptions(subScenario: string, json: any, configFileName: string) { @@ -12,26 +14,35 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { ); } - function baselineCompilerOptionsJsonText(subScenario: string, jsonText: string, configFileName: string, skipJson = true) { + function baselineCompilerOptionsJsonText( + subScenario: string, + jsonText: string, + configFileName: string, + skipJson = true, + ) { baselineParseConfig({ scenario: "convertCompilerOptionsFromJson", subScenario, input: () => [{ - createHost: () => new fakes.ParseConfigHost(new vfs.FileSystem( - /*ignoreCase*/ false, - { - cwd: "/apath/", - files: { - [`/apath/${configFileName}`]: jsonText, - "/apath/a.ts": "", - "/apath/b.js": "", - } - }, - )), + createHost: () => + new fakes.ParseConfigHost( + new vfs.FileSystem( + /*ignoreCase*/ false, + { + cwd: "/apath/", + files: { + [`/apath/${configFileName}`]: jsonText, + "/apath/a.ts": "", + "/apath/b.js": "", + }, + }, + ), + ), jsonText, configFileName, basePath: "/apath", - baselineParsed: (baseline, parsed) => baseline.push("CompilerOptions::", JSON.stringify(parsed.options, undefined, " ")), + baselineParsed: (baseline, parsed) => + baseline.push("CompilerOptions::", JSON.stringify(parsed.options, undefined, " ")), }], skipJson, }); @@ -44,8 +55,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - lib: ["es5", "es2015.core", "es2015.symbol"] - } + lib: ["es5", "es2015.core", "es2015.symbol"], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert correctly format tsconfig.json with allowJs is false to compiler-options", { @@ -55,8 +66,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { noImplicitAny: false, sourceMap: false, allowJs: false, - lib: ["es5", "es2015.core", "es2015.symbol"] - } + lib: ["es5", "es2015.core", "es2015.symbol"], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert incorrect option of jsx to compiler-options", { @@ -65,8 +76,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - jsx: "" - } + jsx: "", + }, }, "tsconfig.json"); baselineCompilerOptions("Convert incorrect option of module to compiler-options", { @@ -75,7 +86,7 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - } + }, }, "tsconfig.json"); baselineCompilerOptions("Convert incorrect option of newLine to compiler-options", { @@ -84,7 +95,7 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - } + }, }, "tsconfig.json"); baselineCompilerOptions("Convert incorrect option of target to compiler-options", { @@ -92,7 +103,7 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "", noImplicitAny: false, sourceMap: false, - } + }, }, "tsconfig.json"); baselineCompilerOptions("Convert incorrect option of module-resolution to compiler-options", { @@ -100,7 +111,7 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { moduleResolution: "", noImplicitAny: false, sourceMap: false, - } + }, }, "tsconfig.json"); baselineCompilerOptions("Convert incorrect option of libs to compiler-options", { @@ -109,8 +120,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - lib: ["es5", "es2015.core", "incorrectLib"] - } + lib: ["es5", "es2015.core", "incorrectLib"], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert empty string option of libs to compiler-options", { @@ -119,8 +130,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - lib: ["es5", ""] - } + lib: ["es5", ""], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert empty string option of libs array to compiler-options", { @@ -129,8 +140,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - lib: [""] - } + lib: [""], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert trailing-whitespace string option of libs to compiler-options", { @@ -139,8 +150,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - lib: [" "] - } + lib: [" "], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert empty option of libs to compiler-options", { @@ -149,38 +160,38 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - lib: [] - } + lib: [], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert empty string option of moduleSuffixes to compiler-options", { compilerOptions: { - moduleSuffixes: [".ios", ""] - } + moduleSuffixes: [".ios", ""], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert empty string option of moduleSuffixes single to compiler-options", { compilerOptions: { - moduleSuffixes: [""] - } + moduleSuffixes: [""], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert trailing-whitespace string option of moduleSuffixes to compiler-options", { compilerOptions: { - moduleSuffixes: [" "] - } + moduleSuffixes: [" "], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert empty option of moduleSuffixes to compiler-options", { compilerOptions: { - moduleSuffixes: [] - } + moduleSuffixes: [], + }, }, "tsconfig.json"); baselineCompilerOptions("Convert incorrectly format tsconfig.json to compiler-options", { compilerOptions: { modu: "commonjs", - } + }, }, "tsconfig.json"); baselineCompilerOptions("Convert default tsconfig.json to compiler-options", {}, "tsconfig.json"); @@ -188,8 +199,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { baselineCompilerOptions("Convert negative numbers in tsconfig.json", { compilerOptions: { allowJs: true, - maxNodeModuleJsDepth: -1 - } + maxNodeModuleJsDepth: -1, + }, }, "tsconfig.json"); // jsconfig.json @@ -199,8 +210,8 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { target: "es5", noImplicitAny: false, sourceMap: false, - lib: ["es5", "es2015.core", "es2015.symbol"] - } + lib: ["es5", "es2015.core", "es2015.symbol"], + }, }, "jsconfig.json"); baselineCompilerOptions("Convert correctly format jsconfig.json with allowJs is false to compiler-options", { @@ -210,19 +221,21 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { noImplicitAny: false, sourceMap: false, allowJs: false, - lib: ["es5", "es2015.core", "es2015.symbol"] - } + lib: ["es5", "es2015.core", "es2015.symbol"], + }, }, "jsconfig.json"); baselineCompilerOptions("Convert incorrectly format jsconfig.json to compiler-options", { compilerOptions: { modu: "commonjs", - } + }, }, "jsconfig.json"); baselineCompilerOptions("Convert default jsconfig.json to compiler-options", {}, "jsconfig.json"); - baselineCompilerOptionsJsonText("Convert tsconfig options when there are multiple invalid strings", `{ + baselineCompilerOptionsJsonText( + "Convert tsconfig options when there are multiple invalid strings", + `{ "compilerOptions": { "target": "<%- options.useTsWithBabel ? 'esnext' : 'es5' %>", "module": "esnext", @@ -242,41 +255,57 @@ describe("unittests:: config:: convertCompilerOptionsFromJson", () => { } } `, - "tsconfig.json"); + "tsconfig.json", + ); - baselineCompilerOptionsJsonText("Convert a tsconfig file with stray trailing characters", + baselineCompilerOptionsJsonText( + "Convert a tsconfig file with stray trailing characters", `{ "compilerOptions": { "target": "esnext" } - } blah`, "tsconfig.json"); + } blah`, + "tsconfig.json", + ); - baselineCompilerOptionsJsonText("Convert a tsconfig file with stray leading characters", + baselineCompilerOptionsJsonText( + "Convert a tsconfig file with stray leading characters", `blah { "compilerOptions": { "target": "esnext" } - }`, "tsconfig.json"); + }`, + "tsconfig.json", + ); - baselineCompilerOptionsJsonText("Convert a tsconfig file as an array", + baselineCompilerOptionsJsonText( + "Convert a tsconfig file as an array", `[{ "compilerOptions": { "target": "esnext" } - }]`, "tsconfig.json"); + }]`, + "tsconfig.json", + ); - baselineCompilerOptionsJsonText("raises an error if you've set a compiler flag in the root without including compilerOptions", + baselineCompilerOptionsJsonText( + "raises an error if you've set a compiler flag in the root without including compilerOptions", `{ "module": "esnext", - }`, "tsconfig.json"); + }`, + "tsconfig.json", + ); - baselineCompilerOptionsJsonText("does not raise an error if you've set a compiler flag in the root when you have included 'compilerOptions'", + baselineCompilerOptionsJsonText( + "does not raise an error if you've set a compiler flag in the root when you have included 'compilerOptions'", `{ "target": "esnext", "compilerOptions": { "module": "esnext" } - }`, "tsconfig.json"); + }`, + "tsconfig.json", + ); baselineCompilerOptionsJsonText("Don't crash when root expression is not object at all", `42`, "tsconfig.json"); diff --git a/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts b/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts index f506eab089061..43a1565b7ac83 100644 --- a/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts +++ b/src/testRunner/unittests/config/convertTypeAcquisitionFromJson.ts @@ -1,6 +1,8 @@ import * as fakes from "../../_namespaces/fakes"; import * as vfs from "../../_namespaces/vfs"; -import { baselineParseConfig } from "./helpers"; +import { + baselineParseConfig, +} from "./helpers"; describe("unittests:: config:: convertTypeAcquisitionFromJson", () => { function baselineTypeAcquisition(subScenario: string, json: any, configFileName: string) { @@ -10,87 +12,72 @@ describe("unittests:: config:: convertTypeAcquisitionFromJson", () => { input: () => { const jsonText = JSON.stringify(json, undefined, " "); return [{ - createHost: () => new fakes.ParseConfigHost(new vfs.FileSystem( - /*ignoreCase*/ false, - { - cwd: "/apath/", - files: { - [`/apath/${configFileName}`]: jsonText, - "/apath/a.ts": "", - "/apath/b.js": "", - } - }, - )), + createHost: () => + new fakes.ParseConfigHost( + new vfs.FileSystem( + /*ignoreCase*/ false, + { + cwd: "/apath/", + files: { + [`/apath/${configFileName}`]: jsonText, + "/apath/a.ts": "", + "/apath/b.js": "", + }, + }, + ), + ), jsonText, configFileName, basePath: "/apath", - baselineParsed: (baseline, parsed) => baseline.push("TypeAcquisition::", JSON.stringify(parsed.typeAcquisition, undefined, " ")), + baselineParsed: (baseline, parsed) => + baseline.push("TypeAcquisition::", JSON.stringify(parsed.typeAcquisition, undefined, " ")), }]; }, }); } - baselineTypeAcquisition("Convert correctly format tsconfig.json to typeAcquisition ", - { - typeAcquisition: - { - enable: true, - include: ["0.d.ts", "1.d.ts"], - exclude: ["0.js", "1.js"] - } + baselineTypeAcquisition("Convert correctly format tsconfig.json to typeAcquisition ", { + typeAcquisition: { + enable: true, + include: ["0.d.ts", "1.d.ts"], + exclude: ["0.js", "1.js"], }, - "tsconfig.json" - ); + }, "tsconfig.json"); - baselineTypeAcquisition("Convert incorrect format tsconfig.json to typeAcquisition ", - { - typeAcquisition: - { - enableAutoDiscovy: true, - } - }, "tsconfig.json", - ); + baselineTypeAcquisition("Convert incorrect format tsconfig.json to typeAcquisition ", { + typeAcquisition: { + enableAutoDiscovy: true, + }, + }, "tsconfig.json"); baselineTypeAcquisition("Convert default tsconfig.json to typeAcquisition ", {}, "tsconfig.json"); - baselineTypeAcquisition("Convert tsconfig.json with only enable property to typeAcquisition ", - { - typeAcquisition: - { - enable: true - } - }, "tsconfig.json", - ); + baselineTypeAcquisition("Convert tsconfig.json with only enable property to typeAcquisition ", { + typeAcquisition: { + enable: true, + }, + }, "tsconfig.json"); // jsconfig.json - baselineTypeAcquisition("Convert jsconfig.json to typeAcquisition ", - { - typeAcquisition: - { - enable: false, - include: ["0.d.ts"], - exclude: ["0.js"] - } - }, "jsconfig.json", - ); + baselineTypeAcquisition("Convert jsconfig.json to typeAcquisition ", { + typeAcquisition: { + enable: false, + include: ["0.d.ts"], + exclude: ["0.js"], + }, + }, "jsconfig.json"); baselineTypeAcquisition("Convert default jsconfig.json to typeAcquisition ", {}, "jsconfig.json"); - baselineTypeAcquisition("Convert incorrect format jsconfig.json to typeAcquisition ", - { - typeAcquisition: - { - enableAutoDiscovy: true, - } - }, "jsconfig.json", - ); + baselineTypeAcquisition("Convert incorrect format jsconfig.json to typeAcquisition ", { + typeAcquisition: { + enableAutoDiscovy: true, + }, + }, "jsconfig.json"); - baselineTypeAcquisition("Convert jsconfig.json with only enable property to typeAcquisition ", - { - typeAcquisition: - { - enable: false - } - }, "jsconfig.json", - ); + baselineTypeAcquisition("Convert jsconfig.json with only enable property to typeAcquisition ", { + typeAcquisition: { + enable: false, + }, + }, "jsconfig.json"); }); diff --git a/src/testRunner/unittests/config/helpers.ts b/src/testRunner/unittests/config/helpers.ts index 8c754e92e63a0..f6e08a4be80d1 100644 --- a/src/testRunner/unittests/config/helpers.ts +++ b/src/testRunner/unittests/config/helpers.ts @@ -51,7 +51,7 @@ export interface ParseConfigInput { createHost: (baseline: string[]) => fakes.ParseConfigHost; jsonText: string; configFileName: string; - basePath?: string, + basePath?: string; existingOptions?: ts.CompilerOptions; existingWatchOptions?: ts.WatchOptions; baselineParsed(baseline: string[], parsed: ts.ParsedCommandLine): void; @@ -83,11 +83,28 @@ function baselineParseConfigWith( it(jsonTest, () => { const baseline: string[] = []; header?.(baseline); - for (const { createHost, jsonText, configFileName, existingOptions, basePath, existingWatchOptions, baselineParsed } of input()) { + for ( + const { + createHost, + jsonText, + configFileName, + existingOptions, + basePath, + existingWatchOptions, + baselineParsed, + } of input() + ) { const host = createHost(baseline); if (!skipFs) baselineParseConfigHost(baseline, host); baseline.push(`configFileName:: ${configFileName}`); - const parsed = getParsed(jsonText, configFileName, host, basePath, existingOptions, existingWatchOptions); + const parsed = getParsed( + jsonText, + configFileName, + host, + basePath, + existingOptions, + existingWatchOptions, + ); baselineParsed(baseline, parsed); if (!skipErrors) { baseline.push("Errors::"); @@ -102,4 +119,4 @@ function baselineParseConfigWith( Harness.Baseline.runBaseline(`config/${scenario}/${subScenario} ${jsonTest}.js`, baseline.join("\n")); }); }); -} \ No newline at end of file +} diff --git a/src/testRunner/unittests/config/initializeTSConfig.ts b/src/testRunner/unittests/config/initializeTSConfig.ts index d2965cdca7c17..b13f281a593c4 100644 --- a/src/testRunner/unittests/config/initializeTSConfig.ts +++ b/src/testRunner/unittests/config/initializeTSConfig.ts @@ -20,17 +20,38 @@ describe("unittests:: config:: initTSConfig", () => { initTSConfigCorrectly("Initialized TSConfig with boolean value compiler options", ["--init", "--noUnusedLocals"]); - initTSConfigCorrectly("Initialized TSConfig with enum value compiler options", ["--init", "--target", "es5", "--jsx", "react"]); + initTSConfigCorrectly("Initialized TSConfig with enum value compiler options", [ + "--init", + "--target", + "es5", + "--jsx", + "react", + ]); initTSConfigCorrectly("Initialized TSConfig with list compiler options", ["--init", "--types", "jquery,mocha"]); - initTSConfigCorrectly("Initialized TSConfig with list compiler options with enum value", ["--init", "--lib", "es5,es2015.core"]); + initTSConfigCorrectly("Initialized TSConfig with list compiler options with enum value", [ + "--init", + "--lib", + "es5,es2015.core", + ]); initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option", ["--init", "--someNonExistOption"]); - initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option value", ["--init", "--lib", "nonExistLib,es5,es2015.promise"]); - - initTSConfigCorrectly("Initialized TSConfig with advanced options", ["--init", "--declaration", "--declarationDir", "lib", "--skipLibCheck", "--noErrorTruncation"]); + initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option value", [ + "--init", + "--lib", + "nonExistLib,es5,es2015.promise", + ]); + + initTSConfigCorrectly("Initialized TSConfig with advanced options", [ + "--init", + "--declaration", + "--declarationDir", + "lib", + "--skipLibCheck", + "--noErrorTruncation", + ]); initTSConfigCorrectly("Initialized TSConfig with --help", ["--init", "--help"]); diff --git a/src/testRunner/unittests/config/matchFiles.ts b/src/testRunner/unittests/config/matchFiles.ts index 33c21ff241011..58e198f02e9cf 100644 --- a/src/testRunner/unittests/config/matchFiles.ts +++ b/src/testRunner/unittests/config/matchFiles.ts @@ -1,108 +1,145 @@ import * as fakes from "../../_namespaces/fakes"; import * as ts from "../../_namespaces/ts"; import * as vfs from "../../_namespaces/vfs"; -import { baselineParseConfig } from "./helpers"; +import { + baselineParseConfig, +} from "./helpers"; const caseInsensitiveBasePath = "c:/dev/"; const caseInsensitiveTsconfigPath = "c:/dev/tsconfig.json"; -const caseInsensitiveHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ true, { cwd: caseInsensitiveBasePath, files: { - "c:/dev/a.ts": "", - "c:/dev/a.d.ts": "", - "c:/dev/a.js": "", - "c:/dev/b.ts": "", - "c:/dev/b.js": "", - "c:/dev/c.d.ts": "", - "c:/dev/z/a.ts": "", - "c:/dev/z/abz.ts": "", - "c:/dev/z/aba.ts": "", - "c:/dev/z/b.ts": "", - "c:/dev/z/bbz.ts": "", - "c:/dev/z/bba.ts": "", - "c:/dev/x/a.ts": "", - "c:/dev/x/aa.ts": "", - "c:/dev/x/b.ts": "", - "c:/dev/x/y/a.ts": "", - "c:/dev/x/y/b.ts": "", - "c:/dev/js/a.js": "", - "c:/dev/js/b.js": "", - "c:/dev/js/d.min.js": "", - "c:/dev/js/ab.min.js": "", - "c:/ext/ext.ts": "", - "c:/ext/b/a..b.ts": "", -}})); +const caseInsensitiveHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ true, { + cwd: caseInsensitiveBasePath, + files: { + "c:/dev/a.ts": "", + "c:/dev/a.d.ts": "", + "c:/dev/a.js": "", + "c:/dev/b.ts": "", + "c:/dev/b.js": "", + "c:/dev/c.d.ts": "", + "c:/dev/z/a.ts": "", + "c:/dev/z/abz.ts": "", + "c:/dev/z/aba.ts": "", + "c:/dev/z/b.ts": "", + "c:/dev/z/bbz.ts": "", + "c:/dev/z/bba.ts": "", + "c:/dev/x/a.ts": "", + "c:/dev/x/aa.ts": "", + "c:/dev/x/b.ts": "", + "c:/dev/x/y/a.ts": "", + "c:/dev/x/y/b.ts": "", + "c:/dev/js/a.js": "", + "c:/dev/js/b.js": "", + "c:/dev/js/d.min.js": "", + "c:/dev/js/ab.min.js": "", + "c:/ext/ext.ts": "", + "c:/ext/b/a..b.ts": "", + }, + }), +); const caseSensitiveBasePath = "/dev/"; -const caseSensitiveHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ false, { cwd: caseSensitiveBasePath, files: { - "/dev/a.ts": "", - "/dev/a.d.ts": "", - "/dev/a.js": "", - "/dev/b.ts": "", - "/dev/b.js": "", - "/dev/A.ts": "", - "/dev/B.ts": "", - "/dev/c.d.ts": "", - "/dev/z/a.ts": "", - "/dev/z/abz.ts": "", - "/dev/z/aba.ts": "", - "/dev/z/b.ts": "", - "/dev/z/bbz.ts": "", - "/dev/z/bba.ts": "", - "/dev/x/a.ts": "", - "/dev/x/b.ts": "", - "/dev/x/y/a.ts": "", - "/dev/x/y/b.ts": "", - "/dev/q/a/c/b/d.ts": "", - "/dev/js/a.js": "", - "/dev/js/b.js": "", -}})); +const caseSensitiveHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ false, { + cwd: caseSensitiveBasePath, + files: { + "/dev/a.ts": "", + "/dev/a.d.ts": "", + "/dev/a.js": "", + "/dev/b.ts": "", + "/dev/b.js": "", + "/dev/A.ts": "", + "/dev/B.ts": "", + "/dev/c.d.ts": "", + "/dev/z/a.ts": "", + "/dev/z/abz.ts": "", + "/dev/z/aba.ts": "", + "/dev/z/b.ts": "", + "/dev/z/bbz.ts": "", + "/dev/z/bba.ts": "", + "/dev/x/a.ts": "", + "/dev/x/b.ts": "", + "/dev/x/y/a.ts": "", + "/dev/x/y/b.ts": "", + "/dev/q/a/c/b/d.ts": "", + "/dev/js/a.js": "", + "/dev/js/b.js": "", + }, + }), +); -const caseInsensitiveMixedExtensionHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ true, { cwd: caseInsensitiveBasePath, files: { - "c:/dev/a.ts": "", - "c:/dev/a.d.ts": "", - "c:/dev/a.js": "", - "c:/dev/b.tsx": "", - "c:/dev/b.d.ts": "", - "c:/dev/b.jsx": "", - "c:/dev/c.tsx": "", - "c:/dev/c.js": "", - "c:/dev/d.js": "", - "c:/dev/e.jsx": "", - "c:/dev/f.other": "", -}})); +const caseInsensitiveMixedExtensionHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ true, { + cwd: caseInsensitiveBasePath, + files: { + "c:/dev/a.ts": "", + "c:/dev/a.d.ts": "", + "c:/dev/a.js": "", + "c:/dev/b.tsx": "", + "c:/dev/b.d.ts": "", + "c:/dev/b.jsx": "", + "c:/dev/c.tsx": "", + "c:/dev/c.js": "", + "c:/dev/d.js": "", + "c:/dev/e.jsx": "", + "c:/dev/f.other": "", + }, + }), +); -const caseInsensitiveCommonFoldersHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ true, { cwd: caseInsensitiveBasePath, files: { - "c:/dev/a.ts": "", - "c:/dev/a.d.ts": "", - "c:/dev/a.js": "", - "c:/dev/b.ts": "", - "c:/dev/x/a.ts": "", - "c:/dev/node_modules/a.ts": "", - "c:/dev/bower_components/a.ts": "", - "c:/dev/jspm_packages/a.ts": "", -}})); +const caseInsensitiveCommonFoldersHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ true, { + cwd: caseInsensitiveBasePath, + files: { + "c:/dev/a.ts": "", + "c:/dev/a.d.ts": "", + "c:/dev/a.js": "", + "c:/dev/b.ts": "", + "c:/dev/x/a.ts": "", + "c:/dev/node_modules/a.ts": "", + "c:/dev/bower_components/a.ts": "", + "c:/dev/jspm_packages/a.ts": "", + }, + }), +); -const caseInsensitiveDottedFoldersHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ true, { cwd: caseInsensitiveBasePath, files: { - "c:/dev/x/d.ts": "", - "c:/dev/x/y/d.ts": "", - "c:/dev/x/y/.e.ts": "", - "c:/dev/x/.y/a.ts": "", - "c:/dev/.z/.b.ts": "", - "c:/dev/.z/c.ts": "", - "c:/dev/w/.u/e.ts": "", - "c:/dev/g.min.js/.g/g.ts": "", -}})); +const caseInsensitiveDottedFoldersHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ true, { + cwd: caseInsensitiveBasePath, + files: { + "c:/dev/x/d.ts": "", + "c:/dev/x/y/d.ts": "", + "c:/dev/x/y/.e.ts": "", + "c:/dev/x/.y/a.ts": "", + "c:/dev/.z/.b.ts": "", + "c:/dev/.z/c.ts": "", + "c:/dev/w/.u/e.ts": "", + "c:/dev/g.min.js/.g/g.ts": "", + }, + }), +); -const caseInsensitiveOrderingDiffersWithCaseHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ true, { cwd: caseInsensitiveBasePath, files: { - "c:/dev/xylophone.ts": "", - "c:/dev/Yosemite.ts": "", - "c:/dev/zebra.ts": "", -}})); +const caseInsensitiveOrderingDiffersWithCaseHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ true, { + cwd: caseInsensitiveBasePath, + files: { + "c:/dev/xylophone.ts": "", + "c:/dev/Yosemite.ts": "", + "c:/dev/zebra.ts": "", + }, + }), +); -const caseSensitiveOrderingDiffersWithCaseHost = new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ false, { cwd: caseSensitiveBasePath, files: { - "/dev/xylophone.ts": "", - "/dev/Yosemite.ts": "", - "/dev/zebra.ts": "", -}})); +const caseSensitiveOrderingDiffersWithCaseHost = new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ false, { + cwd: caseSensitiveBasePath, + files: { + "/dev/xylophone.ts": "", + "/dev/Yosemite.ts": "", + "/dev/zebra.ts": "", + }, + }), +); function baselineMatches(subScenario: string, json: any, host: fakes.ParseConfigHost, basePath: string) { const jsonText = JSON.stringify(json, undefined, " "); @@ -116,13 +153,26 @@ function baselineMatches(subScenario: string, json: any, host: fakes.ParseConfig basePath, baselineParsed: (baseline, parsed) => { const wildcardDirectories = parsed.wildcardDirectories ? {} as ts.MapLike : undefined; - if (parsed.wildcardDirectories) ts.getOwnKeys(parsed.wildcardDirectories).forEach(dir => wildcardDirectories![dir] = `WatchDirectoryFlags.${(ts as any).WatchDirectoryFlags[parsed.wildcardDirectories![dir]]}`); - baseline.push("Result", JSON.stringify({ - ...parsed, - errors: undefined, - wildcardDirectories, - }, undefined, " ")); - } + if (parsed.wildcardDirectories) { + ts.getOwnKeys(parsed.wildcardDirectories).forEach(dir => + wildcardDirectories![dir] = `WatchDirectoryFlags.${ + (ts as any).WatchDirectoryFlags[parsed.wildcardDirectories![dir]] + }` + ); + } + baseline.push( + "Result", + JSON.stringify( + { + ...parsed, + errors: undefined, + wildcardDirectories, + }, + undefined, + " ", + ), + ); + }, }], header: baseline => baseline.push("config:", jsonText), }); @@ -131,465 +181,776 @@ function baselineMatches(subScenario: string, json: any, host: fakes.ParseConfig describe("unittests:: config:: matchFiles", () => { baselineMatches("with defaults", {}, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); describe("with literal file list", () => { - baselineMatches("without exclusions with literal file list", { - files: [ - "a.ts", - "b.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("missing files are still present", { - files: [ - "z.ts", - "x.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("are not removed due to excludes", { - files: [ - "a.ts", - "b.ts" - ], - exclude: [ - "b.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); + baselineMatches( + "without exclusions with literal file list", + { + files: [ + "a.ts", + "b.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "missing files are still present", + { + files: [ + "z.ts", + "x.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "are not removed due to excludes", + { + files: [ + "a.ts", + "b.ts", + ], + exclude: [ + "b.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); }); describe("with literal include list", () => { - baselineMatches("without exclusions with literal include list", { - include: [ - "a.ts", - "b.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with non .ts file extensions are excluded", { - include: [ - "a.js", - "b.js" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with missing files are excluded with literal include list", { - include: [ - "z.ts", - "x.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with literal excludes", { - include: [ - "a.ts", - "b.ts" - ], - exclude: [ - "b.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with wildcard excludes", { - include: [ - "a.ts", - "b.ts", - "z/a.ts", - "z/abz.ts", - "z/aba.ts", - "x/b.ts" - ], - exclude: [ - "*.ts", - "z/??z.ts", - "*/b.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with recursive excludes", { - include: [ - "a.ts", - "b.ts", - "x/a.ts", - "x/b.ts", - "x/y/a.ts", - "x/y/b.ts" - ], - exclude: [ - "**/b.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with case sensitive exclude", { - include: [ - "B.ts" - ], - exclude: [ - "**/b.ts" - ] - }, caseSensitiveHost, caseSensitiveBasePath); - baselineMatches("with common package folders and no exclusions", { - include: [ - "a.ts", - "b.ts", - "node_modules/a.ts", - "bower_components/a.ts", - "jspm_packages/a.ts" - ] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - baselineMatches("with common package folders and exclusions", { - include: [ - "a.ts", - "b.ts", - "node_modules/a.ts", - "bower_components/a.ts", - "jspm_packages/a.ts" - ], - exclude: [ - "a.ts", - "b.ts" - ] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - baselineMatches("with common package folders and empty exclude", { - include: [ - "a.ts", - "b.ts", - "node_modules/a.ts", - "bower_components/a.ts", - "jspm_packages/a.ts" - ] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); + baselineMatches( + "without exclusions with literal include list", + { + include: [ + "a.ts", + "b.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with non .ts file extensions are excluded", + { + include: [ + "a.js", + "b.js", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with missing files are excluded with literal include list", + { + include: [ + "z.ts", + "x.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with literal excludes", + { + include: [ + "a.ts", + "b.ts", + ], + exclude: [ + "b.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with wildcard excludes", + { + include: [ + "a.ts", + "b.ts", + "z/a.ts", + "z/abz.ts", + "z/aba.ts", + "x/b.ts", + ], + exclude: [ + "*.ts", + "z/??z.ts", + "*/b.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with recursive excludes", + { + include: [ + "a.ts", + "b.ts", + "x/a.ts", + "x/b.ts", + "x/y/a.ts", + "x/y/b.ts", + ], + exclude: [ + "**/b.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with case sensitive exclude", + { + include: [ + "B.ts", + ], + exclude: [ + "**/b.ts", + ], + }, + caseSensitiveHost, + caseSensitiveBasePath, + ); + baselineMatches( + "with common package folders and no exclusions", + { + include: [ + "a.ts", + "b.ts", + "node_modules/a.ts", + "bower_components/a.ts", + "jspm_packages/a.ts", + ], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with common package folders and exclusions", + { + include: [ + "a.ts", + "b.ts", + "node_modules/a.ts", + "bower_components/a.ts", + "jspm_packages/a.ts", + ], + exclude: [ + "a.ts", + "b.ts", + ], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with common package folders and empty exclude", + { + include: [ + "a.ts", + "b.ts", + "node_modules/a.ts", + "bower_components/a.ts", + "jspm_packages/a.ts", + ], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); }); describe("with wildcard include list", () => { - baselineMatches("is sorted in include order, then in alphabetical order", { - include: [ - "z/*.ts", - "x/*.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("same named declarations are excluded", { - include: [ - "*.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("star matches only ts files", { - include: [ - "*" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("question matches only a single character", { - include: [ - "x/?.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with recursive directory", { - include: [ - "**/a.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with multiple recursive directories", { - include: [ - "x/y/**/a.ts", - "x/**/a.ts", - "z/**/a.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("case sensitive", { - include: [ - "**/A.ts" - ] - }, caseSensitiveHost, caseSensitiveBasePath); - baselineMatches("with missing files are excluded with wildcard include list", { - include: [ - "*/z.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("always include literal files", { - files: [ - "a.ts" - ], - include: [ - "*/z.ts" - ], - exclude: [ - "**/a.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("exclude folders", { - include: [ - "**/*" - ], - exclude: [ - "z", - "x" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - describe("with common package folders", () => { - baselineMatches("and no exclusions", { + baselineMatches( + "is sorted in include order, then in alphabetical order", + { include: [ - "**/a.ts" - ] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - baselineMatches("and exclusions", { + "z/*.ts", + "x/*.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "same named declarations are excluded", + { include: [ - "**/?.ts" + "*.ts", ], - exclude: [ - "a.ts" - ] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - baselineMatches("and empty exclude", { + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "star matches only ts files", + { include: [ - "**/a.ts" + "*", ], - exclude: [] as string[] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - baselineMatches("and explicit recursive include", { + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "question matches only a single character", + { + include: [ + "x/?.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with recursive directory", + { include: [ "**/a.ts", - "**/node_modules/a.ts" - ] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - baselineMatches("and wildcard include", { - include: [ - "*/a.ts" - ] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - baselineMatches("and explicit wildcard include", { - include: [ - "*/a.ts", - "node_modules/a.ts" - ] - }, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - }); - baselineMatches("exclude .js files when allowJs=false", { - compilerOptions: { - allowJs: false - }, - include: [ - "js/*" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("include .js files when allowJs=true", { - compilerOptions: { - allowJs: true - }, - include: [ - "js/*" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("include explicitly listed .min.js files when allowJs=true", { - compilerOptions: { - allowJs: true - }, - include: [ - "js/*.min.js" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("include paths outside of the project", { - include: [ - "*", - "c:/ext/*" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("include paths outside of the project using relative paths", { - include: [ - "*", - "../ext/*" - ], - exclude: [ - "**" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("exclude paths outside of the project using relative paths", { - include: [ - "c:/**/*" - ], - exclude: [ - "../**" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("include files with .. in their name", { - include: [ - "c:/ext/b/a..b.ts" - ], - exclude: [ - "**" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("exclude files with .. in their name", { - include: [ - "c:/ext/**/*" - ], - exclude: [ - "c:/ext/b/a..b.ts" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("with jsx=none, allowJs=false", { - compilerOptions: { - allowJs: false - } - }, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - baselineMatches("with jsx=preserve, allowJs=false", { - compilerOptions: { - jsx: "preserve", - allowJs: false - } - }, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - baselineMatches("with jsx=react-native, allowJs=false", { - compilerOptions: { - jsx: "react-native", - allowJs: false - } - }, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - baselineMatches("with jsx=none, allowJs=true", { - compilerOptions: { - allowJs: true - } - }, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - baselineMatches("with jsx=preserve, allowJs=true", { - compilerOptions: { - jsx: "preserve", - allowJs: true - } - }, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - baselineMatches("with jsx=react-native, allowJs=true", { - compilerOptions: { - jsx: "react-native", - allowJs: true - } - }, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - baselineMatches("exclude .min.js files using wildcards", { - compilerOptions: { - allowJs: true - }, - include: [ - "js/*.min.js" - ], - exclude: [ - "js/a*" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - - describe("with trailing recursive directory", () => { - baselineMatches("in includes with trailing recursive directory", { + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with multiple recursive directories", + { + include: [ + "x/y/**/a.ts", + "x/**/a.ts", + "z/**/a.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "case sensitive", + { include: [ - "**" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - baselineMatches("in excludes with trailing recursive directory", { + "**/A.ts", + ], + }, + caseSensitiveHost, + caseSensitiveBasePath, + ); + baselineMatches( + "with missing files are excluded with wildcard include list", + { include: [ - "**/*" + "*/z.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "always include literal files", + { + files: [ + "a.ts", + ], + include: [ + "*/z.ts", ], exclude: [ - "**" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - }); - describe("with multiple recursive directory patterns", () => { - baselineMatches("in includes with multiple recursive directory patterns", { + "**/a.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "exclude folders", + { include: [ - "**/x/**/*" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); + "**/*", + ], + exclude: [ + "z", + "x", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + describe("with common package folders", () => { + baselineMatches( + "and no exclusions", + { + include: [ + "**/a.ts", + ], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "and exclusions", + { + include: [ + "**/?.ts", + ], + exclude: [ + "a.ts", + ], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "and empty exclude", + { + include: [ + "**/a.ts", + ], + exclude: [] as string[], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "and explicit recursive include", + { + include: [ + "**/a.ts", + "**/node_modules/a.ts", + ], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "and wildcard include", + { + include: [ + "*/a.ts", + ], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "and explicit wildcard include", + { + include: [ + "*/a.ts", + "node_modules/a.ts", + ], + }, + caseInsensitiveCommonFoldersHost, + caseInsensitiveBasePath, + ); }); - baselineMatches("in excludes", { - include: [ - "**/a.ts" - ], - exclude: [ - "**/x/**" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - - describe("with parent directory symbols after a recursive directory pattern", () => { - baselineMatches("in includes immediately after", { + baselineMatches( + "exclude .js files when allowJs=false", + { + compilerOptions: { + allowJs: false, + }, include: [ - "**/../*" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - - baselineMatches("in includes after a subdirectory", { + "js/*", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "include .js files when allowJs=true", + { + compilerOptions: { + allowJs: true, + }, include: [ - "**/y/../*" - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); - - baselineMatches("in excludes immediately after", { + "js/*", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "include explicitly listed .min.js files when allowJs=true", + { + compilerOptions: { + allowJs: true, + }, + include: [ + "js/*.min.js", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "include paths outside of the project", + { + include: [ + "*", + "c:/ext/*", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "include paths outside of the project using relative paths", + { + include: [ + "*", + "../ext/*", + ], + exclude: [ + "**", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "exclude paths outside of the project using relative paths", + { include: [ - "**/a.ts" + "c:/**/*", ], exclude: [ - "**/.." - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); + "../**", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "include files with .. in their name", + { + include: [ + "c:/ext/b/a..b.ts", + ], + exclude: [ + "**", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "exclude files with .. in their name", + { + include: [ + "c:/ext/**/*", + ], + exclude: [ + "c:/ext/b/a..b.ts", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with jsx=none, allowJs=false", + { + compilerOptions: { + allowJs: false, + }, + }, + caseInsensitiveMixedExtensionHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with jsx=preserve, allowJs=false", + { + compilerOptions: { + jsx: "preserve", + allowJs: false, + }, + }, + caseInsensitiveMixedExtensionHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with jsx=react-native, allowJs=false", + { + compilerOptions: { + jsx: "react-native", + allowJs: false, + }, + }, + caseInsensitiveMixedExtensionHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with jsx=none, allowJs=true", + { + compilerOptions: { + allowJs: true, + }, + }, + caseInsensitiveMixedExtensionHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with jsx=preserve, allowJs=true", + { + compilerOptions: { + jsx: "preserve", + allowJs: true, + }, + }, + caseInsensitiveMixedExtensionHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with jsx=react-native, allowJs=true", + { + compilerOptions: { + jsx: "react-native", + allowJs: true, + }, + }, + caseInsensitiveMixedExtensionHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "exclude .min.js files using wildcards", + { + compilerOptions: { + allowJs: true, + }, + include: [ + "js/*.min.js", + ], + exclude: [ + "js/a*", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); - baselineMatches("in excludes after a subdirectory", { + describe("with trailing recursive directory", () => { + baselineMatches( + "in includes with trailing recursive directory", + { + include: [ + "**", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "in excludes with trailing recursive directory", + { + include: [ + "**/*", + ], + exclude: [ + "**", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + }); + describe("with multiple recursive directory patterns", () => { + baselineMatches( + "in includes with multiple recursive directory patterns", + { + include: [ + "**/x/**/*", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + }); + baselineMatches( + "in excludes", + { include: [ - "**/a.ts" + "**/a.ts", ], exclude: [ - "**/y/.." - ] - }, caseInsensitiveHost, caseInsensitiveBasePath); + "**/x/**", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + + describe("with parent directory symbols after a recursive directory pattern", () => { + baselineMatches( + "in includes immediately after", + { + include: [ + "**/../*", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + + baselineMatches( + "in includes after a subdirectory", + { + include: [ + "**/y/../*", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + + baselineMatches( + "in excludes immediately after", + { + include: [ + "**/a.ts", + ], + exclude: [ + "**/..", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); + + baselineMatches( + "in excludes after a subdirectory", + { + include: [ + "**/a.ts", + ], + exclude: [ + "**/y/..", + ], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); }); describe("with implicit globbification", () => { - baselineMatches("Expands z to z/starstart/star", { - include: ["z"] - }, caseInsensitiveHost, caseInsensitiveBasePath); + baselineMatches( + "Expands z to z/starstart/star", + { + include: ["z"], + }, + caseInsensitiveHost, + caseInsensitiveBasePath, + ); }); }); describe("with files or folders that begin with a .", () => { - baselineMatches("that are not explicitly included", { - include: [ - "x/**/*", - "w/*/*" - ] - }, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); - describe("that are explicitly included", () => { - baselineMatches("without wildcards", { + baselineMatches( + "that are not explicitly included", + { include: [ - "x/.y/a.ts", - "c:/dev/.z/.b.ts" - ] - }, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); - baselineMatches("with recursive wildcards that match directories", { - include: [ - "**/.*/*" - ] - }, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); - baselineMatches("with recursive wildcards that match nothing", { - include: [ - "x/**/.y/*", - ".z/**/.*" - ] - }, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); - baselineMatches("with wildcard excludes that implicitly exclude dotted files", { - include: [ - "**/.*/*" + "x/**/*", + "w/*/*", ], - exclude: [ - "**/*" - ] - }, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); + }, + caseInsensitiveDottedFoldersHost, + caseInsensitiveBasePath, + ); + describe("that are explicitly included", () => { + baselineMatches( + "without wildcards", + { + include: [ + "x/.y/a.ts", + "c:/dev/.z/.b.ts", + ], + }, + caseInsensitiveDottedFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with recursive wildcards that match directories", + { + include: [ + "**/.*/*", + ], + }, + caseInsensitiveDottedFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with recursive wildcards that match nothing", + { + include: [ + "x/**/.y/*", + ".z/**/.*", + ], + }, + caseInsensitiveDottedFoldersHost, + caseInsensitiveBasePath, + ); + baselineMatches( + "with wildcard excludes that implicitly exclude dotted files", + { + include: [ + "**/.*/*", + ], + exclude: [ + "**/*", + ], + }, + caseInsensitiveDottedFoldersHost, + caseInsensitiveBasePath, + ); }); }); describe("exclude or include patterns which start with **", () => { - baselineMatches("can exclude dirs whose pattern starts with starstar", { - exclude: [ - "**/x" - ] - }, caseSensitiveHost, caseSensitiveBasePath); - baselineMatches("can include dirs whose pattern starts with starstart", { - include: [ - "**/x", - "**/a/**/b" - ] - }, caseSensitiveHost, caseSensitiveBasePath); + baselineMatches( + "can exclude dirs whose pattern starts with starstar", + { + exclude: [ + "**/x", + ], + }, + caseSensitiveHost, + caseSensitiveBasePath, + ); + baselineMatches( + "can include dirs whose pattern starts with starstart", + { + include: [ + "**/x", + "**/a/**/b", + ], + }, + caseSensitiveHost, + caseSensitiveBasePath, + ); }); - baselineMatches("can include files in the same order on multiple platforms case sensitive", {}, caseSensitiveOrderingDiffersWithCaseHost, caseSensitiveBasePath); - baselineMatches("can include files in the same order on multiple platforms case insensitive", {}, caseInsensitiveOrderingDiffersWithCaseHost, caseInsensitiveBasePath); + baselineMatches( + "can include files in the same order on multiple platforms case sensitive", + {}, + caseSensitiveOrderingDiffersWithCaseHost, + caseSensitiveBasePath, + ); + baselineMatches( + "can include files in the same order on multiple platforms case insensitive", + {}, + caseInsensitiveOrderingDiffersWithCaseHost, + caseInsensitiveBasePath, + ); describe("when recursive symlinked directories are present", () => { const fs = new vfs.FileSystem(/*ignoreCase*/ true, { - cwd: caseInsensitiveBasePath, files: { - "c:/dev/index.ts": "" - } + cwd: caseInsensitiveBasePath, + files: { + "c:/dev/index.ts": "", + }, }); fs.mkdirpSync("c:/dev/a/b/c"); fs.symlinkSync("c:/dev/A", "c:/dev/a/self"); diff --git a/src/testRunner/unittests/config/showConfig.ts b/src/testRunner/unittests/config/showConfig.ts index 5b5a7bc12c4bc..47ba51c794367 100644 --- a/src/testRunner/unittests/config/showConfig.ts +++ b/src/testRunner/unittests/config/showConfig.ts @@ -12,19 +12,29 @@ describe("unittests:: config:: showConfig", () => { const configContents = configJson ? JSON.stringify(configJson) : undefined; const configParseHost: ts.ParseConfigFileHost = { fileExists: path => - ts.comparePaths(ts.getNormalizedAbsolutePath(path, cwd), configPath) === ts.Comparison.EqualTo ? true : false, - getCurrentDirectory() { return cwd; }, + ts.comparePaths(ts.getNormalizedAbsolutePath(path, cwd), configPath) === ts.Comparison.EqualTo + ? true : false, + getCurrentDirectory() { + return cwd; + }, useCaseSensitiveFileNames: true, onUnRecoverableConfigFileDiagnostic: d => { throw new Error(ts.flattenDiagnosticMessageText(d.messageText, "\n")); }, - readDirectory() { return []; }, + readDirectory() { + return []; + }, readFile: path => - ts.comparePaths(ts.getNormalizedAbsolutePath(path, cwd), configPath) === ts.Comparison.EqualTo ? configContents : undefined, + ts.comparePaths(ts.getNormalizedAbsolutePath(path, cwd), configPath) === ts.Comparison.EqualTo + ? configContents : undefined, }; let commandLine = ts.parseCommandLine(commandLinesArgs); if (commandLine.options.project) { - const result = ts.getParsedCommandLineOfConfigFile(commandLine.options.project, commandLine.options, configParseHost); + const result = ts.getParsedCommandLineOfConfigFile( + commandLine.options.project, + commandLine.options, + configParseHost, + ); if (result) { commandLine = result; } @@ -43,17 +53,38 @@ describe("unittests:: config:: showConfig", () => { showTSConfigCorrectly("Show TSConfig with boolean value compiler options", ["--showConfig", "--noUnusedLocals"]); - showTSConfigCorrectly("Show TSConfig with enum value compiler options", ["--showConfig", "--target", "es5", "--jsx", "react"]); + showTSConfigCorrectly("Show TSConfig with enum value compiler options", [ + "--showConfig", + "--target", + "es5", + "--jsx", + "react", + ]); showTSConfigCorrectly("Show TSConfig with list compiler options", ["--showConfig", "--types", "jquery,mocha"]); - showTSConfigCorrectly("Show TSConfig with list compiler options with enum value", ["--showConfig", "--lib", "es5,es2015.core"]); + showTSConfigCorrectly("Show TSConfig with list compiler options with enum value", [ + "--showConfig", + "--lib", + "es5,es2015.core", + ]); showTSConfigCorrectly("Show TSConfig with incorrect compiler option", ["--showConfig", "--someNonExistOption"]); - showTSConfigCorrectly("Show TSConfig with incorrect compiler option value", ["--showConfig", "--lib", "nonExistLib,es5,es2015.promise"]); - - showTSConfigCorrectly("Show TSConfig with advanced options", ["--showConfig", "--declaration", "--declarationDir", "lib", "--skipLibCheck", "--noErrorTruncation"]); + showTSConfigCorrectly("Show TSConfig with incorrect compiler option value", [ + "--showConfig", + "--lib", + "nonExistLib,es5,es2015.promise", + ]); + + showTSConfigCorrectly("Show TSConfig with advanced options", [ + "--showConfig", + "--declaration", + "--declarationDir", + "lib", + "--skipLibCheck", + "--noErrorTruncation", + ]); showTSConfigCorrectly("Show TSConfig with compileOnSave and more", ["-p", "tsconfig.json"], { compilerOptions: { @@ -64,14 +95,14 @@ describe("unittests:: config:: showConfig", () => { }, compileOnSave: true, exclude: [ - "dist" + "dist", ], files: [], include: [ - "src/*" + "src/*", ], references: [ - { path: "./test" } + { path: "./test" }, ], }); @@ -92,25 +123,25 @@ describe("unittests:: config:: showConfig", () => { "@common/*": ["src/common/*"], "*": [ "node_modules/*", - "src/types/*" - ] + "src/types/*", + ], }, experimentalDecorators: true, emitDecoratorMetadata: true, - resolveJsonModule: true + resolveJsonModule: true, }, include: [ - "./src/**/*" - ] + "./src/**/*", + ], }); showTSConfigCorrectly("Show TSConfig with watch options", ["-p", "tsconfig.json"], { watchOptions: { - watchFile: "DynamicPriorityPolling" + watchFile: "DynamicPriorityPolling", }, include: [ - "./src/**/*" - ] + "./src/**/*", + ], }); // Bulk validation of all option declarations @@ -190,8 +221,8 @@ describe("unittests:: config:: showConfig", () => { } } - const configObject = optionValue && - (isCompilerOptions ? { compilerOptions: optionValue } : { watchOptions: optionValue }); + const configObject = optionValue + && (isCompilerOptions ? { compilerOptions: optionValue } : { watchOptions: optionValue }); showTSConfigCorrectly(`Shows tsconfig for single option/${option.name}`, args, configObject); } }); diff --git a/src/testRunner/unittests/config/tsconfigParsing.ts b/src/testRunner/unittests/config/tsconfigParsing.ts index ee32fe5b58d26..c3906365847e8 100644 --- a/src/testRunner/unittests/config/tsconfigParsing.ts +++ b/src/testRunner/unittests/config/tsconfigParsing.ts @@ -2,7 +2,9 @@ import * as fakes from "../../_namespaces/fakes"; import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; import * as vfs from "../../_namespaces/vfs"; -import { baselineParseConfig } from "./helpers"; +import { + baselineParseConfig, +} from "./helpers"; describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () => { function formatErrors(errors: readonly ts.Diagnostic[]) { @@ -38,26 +40,33 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () baselineParseConfig({ scenario: "tsconfigParsing", subScenario, - input: () => scenario().map(({ jsonText, configFileName, basePath, allFileList }) => ({ - createHost: () => { - const files = allFileList.reduce((files, value) => (files[value] = "", files), {} as vfs.FileSet); - files[ts.combinePaths(basePath, configFileName)] = jsonText; - return new fakes.ParseConfigHost(new vfs.FileSystem( - /*ignoreCase*/ false, - { - cwd: basePath, - files: { "/": {}, ...files } - })); - }, - jsonText, - configFileName, - basePath, - baselineParsed: (baseline, parsed) => { - baseline.push("FileNames::"); - baseline.push(parsed.fileNames.join()); - }, - })), - skipJson + input: () => + scenario().map(({ jsonText, configFileName, basePath, allFileList }) => ({ + createHost: () => { + const files = allFileList.reduce( + (files, value) => (files[value] = "", files), + {} as vfs.FileSet, + ); + files[ts.combinePaths(basePath, configFileName)] = jsonText; + return new fakes.ParseConfigHost( + new vfs.FileSystem( + /*ignoreCase*/ false, + { + cwd: basePath, + files: { "/": {}, ...files }, + }, + ), + ); + }, + jsonText, + configFileName, + basePath, + baselineParsed: (baseline, parsed) => { + baseline.push("FileNames::"); + baseline.push(parsed.fileNames.join()); + }, + })), + skipJson, }); } @@ -72,7 +81,7 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () ]); baselineParseResult("returns empty config when config is empty object", () => [ - "{}" + "{}", ]); baselineParseResult("returns config object without comments", () => [ @@ -166,14 +175,12 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () }]); baselinedParsed("exclude outDir unless overridden", () => { - const tsconfigWithoutExclude = - `{ + const tsconfigWithoutExclude = `{ "compilerOptions": { "outDir": "bin" } }`; - const tsconfigWithExclude = - `{ + const tsconfigWithExclude = `{ "compilerOptions": { "outDir": "bin" }, @@ -188,14 +195,12 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () }); baselinedParsed("exclude declarationDir unless overridden", () => { - const tsconfigWithoutExclude = - `{ + const tsconfigWithoutExclude = `{ "compilerOptions": { "declarationDir": "declarations" } }`; - const tsconfigWithExclude = - `{ + const tsconfigWithExclude = `{ "compilerOptions": { "declarationDir": "declarations" }, @@ -232,7 +237,10 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () const configJsonObject = ts.convertToObject(result, result.parseDiagnostics); baseline.push("Result::", JSON.stringify(configJsonObject, undefined, " ")); baseline.push("Errors::", formatErrors(result.parseDiagnostics)); - Harness.Baseline.runBaseline(`config/tsconfigParsing/parse and re-emit tsconfig.json file with diagnostics.js`, baseline.join("\n")); + Harness.Baseline.runBaseline( + `config/tsconfigParsing/parse and re-emit tsconfig.json file with diagnostics.js`, + baseline.join("\n"), + ); }); baselinedParsed("generates errors for empty files list", () => [{ @@ -322,9 +330,9 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () files: [{ compilerOptions: { experimentalDecorators: true, - allowJs: true - } - }] + allowJs: true, + }, + }], }), configFileName: "/apath/tsconfig.json", basePath: "tests/cases/unittests", @@ -334,8 +342,8 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () baselinedParsed("generates errors when include is not string", () => [{ jsonText: JSON.stringify({ include: [ - ["./**/*.ts"] - ] + ["./**/*.ts"], + ], }), configFileName: "/apath/tsconfig.json", basePath: "tests/cases/unittests", @@ -346,32 +354,43 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () jsonText: JSON.stringify({ compilerOptions: { help: true, - } + }, }), configFileName: "/apath/tsconfig.json", basePath: "tests/cases/unittests", allFileList: ["/apath/a.ts"], }]); - function baselineWildcards(subScenario: string, scenario: () => { configFileName: string, jsonText: string, basePath: string }[]) { + function baselineWildcards( + subScenario: string, + scenario: () => { configFileName: string; jsonText: string; basePath: string; }[], + ) { baselineParseConfig({ scenario: "tsconfigParsing", subScenario, - input: () => scenario().map(({ jsonText, configFileName, basePath }) => ({ - createHost: () => new fakes.ParseConfigHost(new vfs.FileSystem(/*ignoreCase*/ false, { - cwd: basePath, - files: { [configFileName]: jsonText } + input: () => + scenario().map(({ jsonText, configFileName, basePath }) => ({ + createHost: () => + new fakes.ParseConfigHost( + new vfs.FileSystem(/*ignoreCase*/ false, { + cwd: basePath, + files: { [configFileName]: jsonText }, + }), + ), + jsonText, + configFileName, + basePath, + baselineParsed: (baseline, parsed) => { + baseline.push("Wildcards::"); + ts.getOwnKeys(parsed.wildcardDirectories!).forEach(dir => + baseline.push( + `${dir}: WatchDirectoryFlags.${ + (ts as any).WatchDirectoryFlags[parsed.wildcardDirectories![dir]] + }`, + ) + ); + }, })), - jsonText, - configFileName, - basePath, - baselineParsed: (baseline, parsed) => { - baseline.push("Wildcards::"); - ts.getOwnKeys(parsed.wildcardDirectories!).forEach(dir => - baseline.push(`${dir}: WatchDirectoryFlags.${(ts as any).WatchDirectoryFlags[parsed.wildcardDirectories![dir]]}`) - ); - }, - })), skipErrors: true, }); } @@ -379,16 +398,19 @@ describe("unittests:: config:: tsconfigParsing:: parseConfigFileTextToJson", () baselineWildcards("parses wildcard directories even when parent directories have dots", () => [{ configFileName: "/foo.bar/tsconfig.json", jsonText: JSON.stringify({ - include: ["src"] + include: ["src"], }), basePath: "/foo.bar", }]); - baselineWildcards("correctly parses wild card directories from implicit glob when two keys differ only in directory seperator", () => [{ - configFileName: "/foo.bar/tsconfig.json", - jsonText: JSON.stringify({ - include: ["./", "./**/*.json"] - }), - basePath: "/foo", - }]); + baselineWildcards( + "correctly parses wild card directories from implicit glob when two keys differ only in directory seperator", + () => [{ + configFileName: "/foo.bar/tsconfig.json", + jsonText: JSON.stringify({ + include: ["./", "./**/*.json"], + }), + basePath: "/foo", + }], + ); }); diff --git a/src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts b/src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts index e87053dd5f546..10a6cf35c379d 100644 --- a/src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts +++ b/src/testRunner/unittests/config/tsconfigParsingWatchOptions.ts @@ -1,7 +1,9 @@ import * as fakes from "../../_namespaces/fakes"; import * as ts from "../../_namespaces/ts"; import * as vfs from "../../_namespaces/vfs"; -import { baselineParseConfig } from "./helpers"; +import { + baselineParseConfig, +} from "./helpers"; describe("unittests:: config:: tsconfigParsingWatchOptions:: parseConfigFileTextToJson", () => { interface VerifyWatchOptions { @@ -14,31 +16,33 @@ describe("unittests:: config:: tsconfigParsingWatchOptions:: parseConfigFileText baselineParseConfig({ scenario: "tsconfigParsingWatchOptions", subScenario, - input: () => scenario().map(({ json, additionalFiles, existingWatchOptions }) => { - const jsonText = JSON.stringify(json, undefined, " "); - return { - createHost: () => new fakes.ParseConfigHost( - new vfs.FileSystem( - /*ignoreCase*/ false, - { - cwd: "/", - files: { - "/a.ts": "", - ...additionalFiles, - "/tsconfig.json": jsonText, - } - } - ) - ), - jsonText, - configFileName: "tsconfig.json", - existingWatchOptions, - baselineParsed: (baseline, parsed) => { - baseline.push(`Result: WatchOptions::`); - baseline.push(JSON.stringify(parsed.watchOptions, undefined, " ")); - }, - }; - }), + input: () => + scenario().map(({ json, additionalFiles, existingWatchOptions }) => { + const jsonText = JSON.stringify(json, undefined, " "); + return { + createHost: () => + new fakes.ParseConfigHost( + new vfs.FileSystem( + /*ignoreCase*/ false, + { + cwd: "/", + files: { + "/a.ts": "", + ...additionalFiles, + "/tsconfig.json": jsonText, + }, + }, + ), + ), + jsonText, + configFileName: "tsconfig.json", + existingWatchOptions, + baselineParsed: (baseline, parsed) => { + baseline.push(`Result: WatchOptions::`); + baseline.push(JSON.stringify(parsed.watchOptions, undefined, " ")); + }, + }; + }), }); } @@ -54,14 +58,14 @@ describe("unittests:: config:: tsconfigParsingWatchOptions:: parseConfigFileText { json: { extends: "./base.json", - watchOptions: { watchFile: "UseFsEvents" } + watchOptions: { watchFile: "UseFsEvents" }, }, - additionalFiles: { "/base.json": "{}" } + additionalFiles: { "/base.json": "{}" }, }, { - json: { extends: "./base.json", }, - additionalFiles: { "/base.json": "{}" } - } + json: { extends: "./base.json" }, + additionalFiles: { "/base.json": "{}" }, + }, ]); verifyWatchOptions("when extending config file with watchOptions", () => [ @@ -70,16 +74,16 @@ describe("unittests:: config:: tsconfigParsingWatchOptions:: parseConfigFileText extends: "./base.json", watchOptions: { watchFile: "UseFsEvents", - } + }, }, additionalFiles: { "/base.json": JSON.stringify({ watchOptions: { watchFile: "UseFsEventsOnParentDirectory", - watchDirectory: "FixedPollingInterval" - } - }) - } + watchDirectory: "FixedPollingInterval", + }, + }), + }, }, { json: { @@ -89,11 +93,11 @@ describe("unittests:: config:: tsconfigParsingWatchOptions:: parseConfigFileText "/base.json": JSON.stringify({ watchOptions: { watchFile: "UseFsEventsOnParentDirectory", - watchDirectory: "FixedPollingInterval" - } - }) - } - } + watchDirectory: "FixedPollingInterval", + }, + }), + }, + }, ]); verifyWatchOptions("different options", () => [ diff --git a/src/testRunner/unittests/convertToBase64.ts b/src/testRunner/unittests/convertToBase64.ts index e801451208ef9..6f6b6366681cf 100644 --- a/src/testRunner/unittests/convertToBase64.ts +++ b/src/testRunner/unittests/convertToBase64.ts @@ -9,7 +9,9 @@ describe("unittests:: convertToBase64", () => { if (Buffer) { it("Converts ASCII charaters correctly", () => { - runTest(" !\"#$ %&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"); + runTest( + " !\"#$ %&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", + ); }); it("Converts escape sequences correctly", () => { diff --git a/src/testRunner/unittests/customTransforms.ts b/src/testRunner/unittests/customTransforms.ts index c6cbf4391ed06..28cd14065ff77 100644 --- a/src/testRunner/unittests/customTransforms.ts +++ b/src/testRunner/unittests/customTransforms.ts @@ -2,26 +2,40 @@ import * as Harness from "../_namespaces/Harness"; import * as ts from "../_namespaces/ts"; describe("unittests:: customTransforms", () => { - function emitsCorrectly(name: string, sources: { file: string, text: string }[], customTransformers: ts.CustomTransformers, options: ts.CompilerOptions = {}) { + function emitsCorrectly( + name: string, + sources: { file: string; text: string; }[], + customTransformers: ts.CustomTransformers, + options: ts.CompilerOptions = {}, + ) { it(name, () => { const roots = sources.map(source => ts.createSourceFile(source.file, source.text, ts.ScriptTarget.ES2015)); const fileMap = ts.arrayToMap(roots, file => file.fileName); const outputs = new Map(); const host: ts.CompilerHost = { - getSourceFile: (fileName) => fileMap.get(fileName), + getSourceFile: fileName => fileMap.get(fileName), getDefaultLibFileName: () => "lib.d.ts", getCurrentDirectory: () => "", getDirectories: () => [], - getCanonicalFileName: (fileName) => fileName, + getCanonicalFileName: fileName => fileName, useCaseSensitiveFileNames: () => true, getNewLine: () => "\n", - fileExists: (fileName) => fileMap.has(fileName), - readFile: (fileName) => fileMap.has(fileName) ? fileMap.get(fileName)!.text : undefined, + fileExists: fileName => fileMap.has(fileName), + readFile: fileName => fileMap.has(fileName) ? fileMap.get(fileName)!.text : undefined, writeFile: (fileName, text) => outputs.set(fileName, text), }; - const program = ts.createProgram(ts.arrayFrom(fileMap.keys()), { newLine: ts.NewLineKind.LineFeed, ...options }, host); - program.emit(/*targetSourceFile*/ undefined, host.writeFile, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ false, customTransformers); + const program = ts.createProgram(ts.arrayFrom(fileMap.keys()), { + newLine: ts.NewLineKind.LineFeed, + ...options, + }, host); + program.emit( + /*targetSourceFile*/ undefined, + host.writeFile, + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ false, + customTransformers, + ); let content = ""; for (const [file, text] of outputs.entries()) { if (content) content += "\n\n"; @@ -40,7 +54,7 @@ describe("unittests:: customTransforms", () => { enum e { } // leading function f2() { } // trailing - ` + `, }]; const before: ts.TransformerFactory = context => { @@ -54,7 +68,12 @@ describe("unittests:: customTransforms", () => { } } function visitFunction(node: ts.FunctionDeclaration) { - ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, "@before", /*hasTrailingNewLine*/ true); + ts.addSyntheticLeadingComment( + node, + ts.SyntaxKind.MultiLineCommentTrivia, + "@before", + /*hasTrailingNewLine*/ true, + ); return node; } }; @@ -86,84 +105,86 @@ describe("unittests:: customTransforms", () => { class B {} @dec export class C { constructor(b: B) { } } 'change' - ` - }], {before: [ - context => node => ts.visitNode(node, function visitor(node: ts.Node): ts.Node { - if (ts.isStringLiteral(node) && node.text === "change") return ts.factory.createStringLiteral("changed"); - return ts.visitEachChild(node, visitor, context); - }, ts.isSourceFile) - ]}, { + `, + }], { + before: [ + context => node => + ts.visitNode(node, function visitor(node: ts.Node): ts.Node { + if (ts.isStringLiteral(node) && node.text === "change") { + return ts.factory.createStringLiteral("changed"); + } + return ts.visitEachChild(node, visitor, context); + }, ts.isSourceFile), + ], + }, { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.ES2015, emitDecoratorMetadata: true, - experimentalDecorators: true + experimentalDecorators: true, }); - emitsCorrectly("sourceMapExternalSourceFiles", - [ - { - file: "source.ts", - // The text of length 'changed' is made to be on two lines so we know the line map change - text: `\`multi - line\` -'change'` - }, - ], + emitsCorrectly("sourceMapExternalSourceFiles", [ { - before: [ - context => node => ts.visitNode(node, function visitor(node: ts.Node): ts.Node { + file: "source.ts", + // The text of length 'changed' is made to be on two lines so we know the line map change + text: `\`multi + line\` +'change'`, + }, + ], { + before: [ + context => node => + ts.visitNode(node, function visitor(node: ts.Node): ts.Node { if (ts.isStringLiteral(node) && node.text === "change") { const text = "'changed'"; const lineMap = ts.computeLineStarts(text); ts.setSourceMapRange(node, { - pos: 0, end: text.length, source: { + pos: 0, + end: text.length, + source: { text, fileName: "another.html", lineMap, - getLineAndCharacterOfPosition: pos => ts.computeLineAndCharacterOfPosition(lineMap, pos) - } + getLineAndCharacterOfPosition: pos => + ts.computeLineAndCharacterOfPosition(lineMap, pos), + }, }); return node; } return ts.visitEachChild(node, visitor, context); - }, ts.isSourceFile) - ] - }, - { sourceMap: true } - ); - - emitsCorrectly("skipTriviaExternalSourceFiles", - [ - { - file: "source.ts", - // The source file contains preceding trivia (e.g. whitespace) to try to confuse the `skipSourceTrivia` function. - text: " original;" - }, + }, ts.isSourceFile), ], + }, { sourceMap: true }); + + emitsCorrectly("skipTriviaExternalSourceFiles", [ { - before: [ - context => { - const transformSourceFile: ts.Transformer = node => ts.visitNode(node, function visitor(node: ts.Node): ts.Node { + file: "source.ts", + // The source file contains preceding trivia (e.g. whitespace) to try to confuse the `skipSourceTrivia` function. + text: " original;", + }, + ], { + before: [ + context => { + const transformSourceFile: ts.Transformer = node => + ts.visitNode(node, function visitor(node: ts.Node): ts.Node { if (ts.isIdentifier(node) && node.text === "original") { const newNode = ts.factory.createIdentifier("changed"); ts.setSourceMapRange(newNode, { pos: 0, end: 7, // Do not provide a custom skipTrivia function for `source`. - source: ts.createSourceMapSource("another.html", "changed;") + source: ts.createSourceMapSource("another.html", "changed;"), }); return newNode; } return ts.visitEachChild(node, visitor, context); }, ts.isSourceFile); - return { - transformSourceFile, - transformBundle: node => ts.factory.createBundle(ts.map(node.sourceFiles, transformSourceFile), node.prepends), - }; - } - ] - }, - { sourceMap: true, outFile: "source.js" } - ); - + return { + transformSourceFile, + transformBundle: node => + ts.factory.createBundle(ts.map(node.sourceFiles, transformSourceFile), node.prepends), + }; + }, + ], + }, { sourceMap: true, outFile: "source.js" }); }); diff --git a/src/testRunner/unittests/debugDeprecation.ts b/src/testRunner/unittests/debugDeprecation.ts index 9dd3b0fee319f..c40943be0d37b 100644 --- a/src/testRunner/unittests/debugDeprecation.ts +++ b/src/testRunner/unittests/debugDeprecation.ts @@ -1,4 +1,6 @@ -import { deprecate } from "../../deprecatedCompat/deprecate"; +import { + deprecate, +} from "../../deprecatedCompat/deprecate"; import * as ts from "../_namespaces/ts"; describe("unittests:: debugDeprecation", () => { @@ -14,13 +16,13 @@ describe("unittests:: debugDeprecation", () => { it("silent deprecation", () => { const deprecation = deprecate(ts.noop, { warnAfter: "3.9", - typeScriptVersion: "3.8" + typeScriptVersion: "3.8", }); let logWritten = false; ts.Debug.loggingHost = { log() { logWritten = true; - } + }, }; deprecation(); assert.isFalse(logWritten); @@ -28,39 +30,39 @@ describe("unittests:: debugDeprecation", () => { it("warning deprecation with warnAfter", () => { const deprecation = deprecate(ts.noop, { warnAfter: "3.9", - typeScriptVersion: "3.9" + typeScriptVersion: "3.9", }); let logWritten = false; ts.Debug.loggingHost = { log() { logWritten = true; - } + }, }; deprecation(); assert.isTrue(logWritten); }); it("warning deprecation without warnAfter", () => { const deprecation = deprecate(ts.noop, { - typeScriptVersion: "3.9" + typeScriptVersion: "3.9", }); let logWritten = false; ts.Debug.loggingHost = { log() { logWritten = true; - } + }, }; deprecation(); assert.isTrue(logWritten); }); it("warning deprecation writes once", () => { const deprecation = deprecate(ts.noop, { - typeScriptVersion: "3.9" + typeScriptVersion: "3.9", }); let logWrites = 0; ts.Debug.loggingHost = { log() { logWrites++; - } + }, }; deprecation(); deprecation(); @@ -70,13 +72,13 @@ describe("unittests:: debugDeprecation", () => { const deprecation = deprecate(ts.noop, { warnAfter: "3.8", errorAfter: "3.9", - typeScriptVersion: "3.9" + typeScriptVersion: "3.9", }); let logWritten = false; ts.Debug.loggingHost = { log() { logWritten = true; - } + }, }; expect(deprecation).throws(); assert.isFalse(logWritten); @@ -89,7 +91,7 @@ describe("unittests:: debugDeprecation", () => { ts.Debug.loggingHost = { log() { logWritten = true; - } + }, }; expect(deprecation).throws(); assert.isFalse(logWritten); diff --git a/src/testRunner/unittests/evaluation/arraySpread.ts b/src/testRunner/unittests/evaluation/arraySpread.ts index e8f37ba755dde..cc871a76a2f46 100644 --- a/src/testRunner/unittests/evaluation/arraySpread.ts +++ b/src/testRunner/unittests/evaluation/arraySpread.ts @@ -35,7 +35,7 @@ describe("unittests:: evaluation:: arraySpread", () => { const o = f(3, ...k, 4); export const output = o; `); - assert.deepEqual(result.output, [3, 1, undefined, 2,4]); + assert.deepEqual(result.output, [3, 1, undefined, 2, 4]); assert.hasAllKeys(result.output, ["0", "1", "2", "3", "4"]); }); }); diff --git a/src/testRunner/unittests/evaluation/asyncGenerator.ts b/src/testRunner/unittests/evaluation/asyncGenerator.ts index d901223c86e46..a912a143ae537 100644 --- a/src/testRunner/unittests/evaluation/asyncGenerator.ts +++ b/src/testRunner/unittests/evaluation/asyncGenerator.ts @@ -13,25 +13,29 @@ describe("unittests:: evaluation:: asyncGeneratorEvaluation", () => { }`); await result.main(); assert.deepEqual(result.output, [ - { value: 0, done: true } + { value: 0, done: true }, ]); }); it("return (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` async function * g() { return Promise.resolve(0); } export const output: any[] = []; export async function main() { output.push(await g().next()); - }`, { target: ts.ScriptTarget.ES2015 }); + }`, + { target: ts.ScriptTarget.ES2015 }, + ); await result.main(); assert.deepEqual(result.output, [ - { value: 0, done: true } + { value: 0, done: true }, ]); }); it("yields in finally block with async delegator (es2017)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` async function* g1() { try { yield 1; @@ -48,12 +52,14 @@ describe("unittests:: evaluation:: asyncGeneratorEvaluation", () => { output.push(await it.next()); output.push(await it.return()); output.push(await it.next()); - }`, { target: ts.ScriptTarget.ES2017 }); + }`, + { target: ts.ScriptTarget.ES2017 }, + ); await result.main(); assert.deepEqual(result.output, [ { done: false, value: 1 }, { done: false, value: 2 }, - { done: true, value: undefined } + { done: true, value: undefined }, ]); }); }); diff --git a/src/testRunner/unittests/evaluation/autoAccessors.ts b/src/testRunner/unittests/evaluation/autoAccessors.ts index 0e73daf54f4b1..6f4d37587a3f7 100644 --- a/src/testRunner/unittests/evaluation/autoAccessors.ts +++ b/src/testRunner/unittests/evaluation/autoAccessors.ts @@ -9,11 +9,14 @@ describe("unittests:: evaluation:: autoAccessors", () => { for (const { name, target } of editions) { describe(name, () => { it("generates accessor pair", async () => { - const { C } = evaluator.evaluateTypeScript(` + const { C } = evaluator.evaluateTypeScript( + ` export class C { accessor x; } - `, { target }); + `, + { target }, + ); const desc = Object.getOwnPropertyDescriptor(C.prototype, "x"); assert.isDefined(desc); @@ -22,11 +25,14 @@ describe("unittests:: evaluation:: autoAccessors", () => { }); it("storage is private", async () => { - const { C } = evaluator.evaluateTypeScript(` + const { C } = evaluator.evaluateTypeScript( + ` export class C { accessor x; } - `, { target }); + `, + { target }, + ); const desc = Object.getOwnPropertyDescriptor(C.prototype, "x"); const obj = Object.create(C.prototype); @@ -34,11 +40,14 @@ describe("unittests:: evaluation:: autoAccessors", () => { }); it("getter and setter wrap same field", async () => { - const { C } = evaluator.evaluateTypeScript(` + const { C } = evaluator.evaluateTypeScript( + ` export class C { accessor x; } - `, { target }); + `, + { target }, + ); const obj = new C(); obj.x = 1; assert.equal(obj.x, 1); @@ -48,17 +57,21 @@ describe("unittests:: evaluation:: autoAccessors", () => { }); it("supports initializer", async () => { - const { C } = evaluator.evaluateTypeScript(` + const { C } = evaluator.evaluateTypeScript( + ` export class C { accessor x = 1; } - `, { target }); + `, + { target }, + ); const obj = new C(); assert.equal(obj.x, 1); }); it("legacy decorator can intercept getter/setter", async () => { - const { actions, C } = evaluator.evaluateTypeScript(` + const { actions, C } = evaluator.evaluateTypeScript( + ` function dec(target, key, descriptor) { const { get, set } = descriptor; actions.push({ kind: "decorate", target, key }); @@ -76,10 +89,12 @@ describe("unittests:: evaluation:: autoAccessors", () => { @dec accessor x; } - `, { target, experimentalDecorators: true }); + `, + { target, experimentalDecorators: true }, + ); assert.deepEqual(actions, [ - { kind: "decorate", target: C.prototype, key: "x" } + { kind: "decorate", target: C.prototype, key: "x" }, ]); const obj = new C(); obj.x = 1; @@ -92,7 +107,8 @@ describe("unittests:: evaluation:: autoAccessors", () => { }); it("legacy decorator cannot intercept initializer", async () => { - const { actions, C } = evaluator.evaluateTypeScript(` + const { actions, C } = evaluator.evaluateTypeScript( + ` function dec(target, key, descriptor) { const { get, set } = descriptor; descriptor.set = function(value) { @@ -105,7 +121,9 @@ describe("unittests:: evaluation:: autoAccessors", () => { @dec accessor x = 1; } - `, { target, experimentalDecorators: true }); + `, + { target, experimentalDecorators: true }, + ); const obj = new C(); assert.equal(obj.x, 1); @@ -113,4 +131,4 @@ describe("unittests:: evaluation:: autoAccessors", () => { }); }); } -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/evaluation/awaitUsingDeclarations.ts b/src/testRunner/unittests/evaluation/awaitUsingDeclarations.ts index c3e5c7e999637..aced8512f138f 100644 --- a/src/testRunner/unittests/evaluation/awaitUsingDeclarations.ts +++ b/src/testRunner/unittests/evaluation/awaitUsingDeclarations.ts @@ -7,7 +7,8 @@ function FakeSuppressedError(error: any, suppressed: any) { describe("unittests:: evaluation:: awaitUsingDeclarations", () => { it("'await using' in Block, normal completion (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -30,7 +31,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -40,12 +43,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "exit block", "disposed", - "after block" + "after block", ]); }); it("'await using' in Block, 'throw' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -72,7 +76,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -82,12 +88,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "disposed", "error", - "after try" + "after try", ]); }); it("'await using' in Block, 'throw' in dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -114,7 +121,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -125,12 +134,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "exit try", "disposed", "error", - "after try" + "after try", ]); }); it("'await using' in Block, 'throw' in body and dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -158,7 +168,10 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); await main(); @@ -169,14 +182,15 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "disposed", { error: "dispose error", - suppressed: "body error" + suppressed: "body error", }, - "after try" + "after try", ]); }); it("'await using' in Block, 'throw' in body and dispose, no global SuppressedError (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -204,7 +218,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -212,18 +228,20 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "before try", "enter try", "body", - "disposed"]); + "disposed", + ]); assert.instanceOf(output[4], Error); assert.strictEqual(output[4].name, "SuppressedError"); assert.strictEqual(output[4].error, "dispose error"); assert.strictEqual(output[4].suppressed, "body error"); assert.deepEqual(output.slice(5), [ - "after try" + "after try", ]); }); it("'await using' in Block, 'return' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -246,7 +264,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -254,12 +274,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "before block", "enter block", "body", - "disposed" + "disposed", ]); }); it("'await using' in Block, 'break' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -282,7 +303,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -291,12 +314,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter block", "body", "disposed", - "after block" + "after block", ]); }); it("'await using' in Block, 'continue' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -319,7 +343,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -331,12 +357,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter block", "body", "disposed", - "after block" + "after block", ]); }); it("'await using' in head of 'for', normal completion (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -359,7 +386,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -372,12 +401,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "exit loop", "disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for', 'throw' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -405,7 +435,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -415,12 +447,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "disposed", "error", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for', 'throw' in dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -448,7 +481,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -462,12 +497,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "exit loop", "disposed", "error", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for', 'throw' in body and dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -496,7 +532,10 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); await main(); @@ -507,14 +546,15 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "disposed", { error: "dispose error", - suppressed: "body error" + suppressed: "body error", }, - "after loop" + "after loop", ]); }); it("'await using' in head of 'for', 'return' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -537,7 +577,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -545,12 +587,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "before loop", "enter loop", "body", - "disposed" + "disposed", ]); }); it("'await using' in head of 'for', 'break' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -573,7 +616,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -582,12 +627,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter loop", "body", "disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for', 'continue' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -610,7 +656,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -621,12 +669,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter loop", "body", "disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for', multiple iterations (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -649,7 +698,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -662,12 +713,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "exit loop", "disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for-of', normal completion (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -696,7 +748,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -710,12 +764,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "exit loop", "b disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for-of', 'throw' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -750,7 +805,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -765,7 +822,8 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { }); it("'await using' in head of 'for-of', 'throw' in dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -800,7 +858,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -816,7 +876,8 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { }); it("'await using' in head of 'for-of', 'throw' in body and dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -852,7 +913,10 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); await main(); @@ -863,14 +927,15 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "a disposed", { error: "dispose error", - suppressed: "body error" + suppressed: "body error", }, "after loop", ]); }); it("'await using' in head of 'for-of', 'return' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -899,7 +964,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -912,7 +979,8 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { }); it("'await using' in head of 'for-of', 'break' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -941,7 +1009,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -950,12 +1020,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter loop", "body", "a disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for-of', 'continue' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -984,7 +1055,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -996,12 +1069,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter loop", "body", "b disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for-await-of', normal completion (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1030,7 +1104,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1044,12 +1120,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "exit loop", "b disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for-await-of', 'throw' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1084,7 +1161,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1099,7 +1178,8 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { }); it("'await using' in head of 'for-await-of', 'throw' in dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1134,7 +1214,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1150,7 +1232,8 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { }); it("'await using' in head of 'for-await-of', 'throw' in body and dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1186,7 +1269,10 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); await main(); @@ -1197,14 +1283,15 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "a disposed", { error: "dispose error", - suppressed: "body error" + suppressed: "body error", }, "after loop", ]); }); it("'await using' in head of 'for-await-of', 'return' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1233,7 +1320,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1246,7 +1335,8 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { }); it("'await using' in head of 'for-await-of', 'break' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1275,7 +1365,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1284,12 +1376,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter loop", "body", "a disposed", - "after loop" + "after loop", ]); }); it("'await using' in head of 'for-await-of', 'continue' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1318,7 +1411,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1330,12 +1425,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter loop", "body", "b disposed", - "after loop" + "after loop", ]); }); it("'await using' at top level of module (System)", async () => { - const { output, x, y } = await evaluator.evaluateTypeScript(` + const { output, x, y } = await evaluator.evaluateTypeScript( + ` export const output: any[] = []; output.push("before export x"); export const x = 1; @@ -1348,7 +1444,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { output.push("after using"); export const y = 2; output.push("after export y"); - `, { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.System }); + `, + { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.System }, + ); assert.strictEqual(x, 1); assert.strictEqual(y, 2); @@ -1357,12 +1455,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "before using", "after using", "after export y", - "disposed" + "disposed", ]); }); it("'await using' for 'null' value", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function body() { @@ -1379,7 +1478,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1388,12 +1489,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter block", "body", "exit block", - "after block" + "after block", ]); }); it("'await using' for 'undefined' value", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function body() { @@ -1410,7 +1512,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1419,12 +1523,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "enter block", "body", "exit block", - "after block" + "after block", ]); }); it("'await using' for sync disposable value", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -1447,7 +1552,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1457,12 +1564,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "exit block", "disposed", - "after block" + "after block", ]); }); it("'await using' for non-disposable value", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function body() { @@ -1479,7 +1587,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); try { await main(); @@ -1496,7 +1606,8 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { }); it("'await using' disposes in reverse order", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable_1 = { @@ -1524,7 +1635,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1535,12 +1648,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "exit block", "disposed_2", "disposed_1", - "after block" + "after block", ]); }); it("'await using' + 'using' disposes in reverse order", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable_1 = { @@ -1570,7 +1684,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1581,12 +1697,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "exit block", "disposed_2", "disposed_1", - "after block" + "after block", ]); }); it("'await using' forces await if null and evaluated", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function body() { @@ -1614,7 +1731,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { await p; } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1624,12 +1743,13 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { "body", "exit block", "interleave", - "after block" + "after block", ]); }); it("'await using' does not force await if null and not evaluated", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function body() { @@ -1658,7 +1778,9 @@ describe("unittests:: evaluation:: awaitUsingDeclarations", () => { await p; } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); diff --git a/src/testRunner/unittests/evaluation/destructuring.ts b/src/testRunner/unittests/evaluation/destructuring.ts index c52c4d4b0a61a..6a36f92fab830 100644 --- a/src/testRunner/unittests/evaluation/destructuring.ts +++ b/src/testRunner/unittests/evaluation/destructuring.ts @@ -5,63 +5,84 @@ describe("unittests:: evaluation:: destructuring", () => { // https://github.com/microsoft/TypeScript/issues/39205 describe("correct order for array destructuring evaluation and initializers", () => { it("when element is undefined", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const order = (n: any): any => output.push(n); let [{ [order(1)]: x } = order(0)] = []; - `, { target: ts.ScriptTarget.ES5 }); + `, + { target: ts.ScriptTarget.ES5 }, + ); assert.deepEqual(result.output, [0, 1]); }); it("when element is defined", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const order = (n: any): any => output.push(n); let [{ [order(1)]: x } = order(0)] = [{}]; - `, { target: ts.ScriptTarget.ES5 }); + `, + { target: ts.ScriptTarget.ES5 }, + ); assert.deepEqual(result.output, [1]); }); }); describe("correct order for array destructuring evaluation and initializers with spread", () => { it("ES5", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const order = (n: any): any => output.push(n); let { [order(0)]: { [order(2)]: z } = order(1), ...w } = {} as any; - `, { target: ts.ScriptTarget.ES5 }); + `, + { target: ts.ScriptTarget.ES5 }, + ); assert.deepEqual(result.output, [0, 1, 2]); }); it("ES2015", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const order = (n: any): any => output.push(n); let { [order(0)]: { [order(2)]: z } = order(1), ...w } = {} as any; - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.deepEqual(result.output, [0, 1, 2]); }); }); describe("correct evaluation for nested rest assignment in destructured object", () => { it("ES5", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let a: any, b: any, c: any = { x: { a: 1, y: 2 } }, d: any; ({ x: { a, ...b } = d } = c); export const output = { a, b }; - `, { target: ts.ScriptTarget.ES5 }); + `, + { target: ts.ScriptTarget.ES5 }, + ); assert.deepEqual(result.output, { a: 1, b: { y: 2 } }); }); it("ES2015", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let a: any, b: any, c: any = { x: { a: 1, y: 2 } }, d: any; ({ x: { a, ...b } = d } = c); export const output = { a, b }; - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.deepEqual(result.output, { a: 1, b: { y: 2 } }); }); it("ES2018", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let a: any, b: any, c: any = { x: { a: 1, y: 2 } }, d: any; ({ x: { a, ...b } = d } = c); export const output = { a, b }; - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); assert.deepEqual(result.output, { a: 1, b: { y: 2 } }); }); }); diff --git a/src/testRunner/unittests/evaluation/esDecorators.ts b/src/testRunner/unittests/evaluation/esDecorators.ts index 35be87f5a5c41..a4c12a2d7dad8 100644 --- a/src/testRunner/unittests/evaluation/esDecorators.ts +++ b/src/testRunner/unittests/evaluation/esDecorators.ts @@ -1,6 +1,8 @@ import * as evaluator from "../../_namespaces/evaluator"; import * as ts from "../../_namespaces/ts"; -import { ScriptTarget } from "../../_namespaces/ts"; +import { + ScriptTarget, +} from "../../_namespaces/ts"; describe("unittests:: evaluation:: esDecorators", () => { const options: ts.CompilerOptions = { target: ts.ScriptTarget.ES2021 }; @@ -739,7 +741,7 @@ describe("unittests:: evaluation:: esDecorators", () => { `; assert.isTrue(context.access.has(C)); assert.isTrue(context.access.has({ method() {} })); - assert.isFalse(context.access.has({ })); + assert.isFalse(context.access.has({})); }); it("test private element presence via .has", () => { const { context, C, D } = exec` @@ -754,7 +756,7 @@ describe("unittests:: evaluation:: esDecorators", () => { `; assert.isTrue(context.access.has(C)); assert.isFalse(context.access.has(D)); - assert.isFalse(context.access.has({ })); + assert.isFalse(context.access.has({})); }); it("read public element of argument", () => { const { context, C } = exec` @@ -809,9 +811,11 @@ describe("unittests:: evaluation:: esDecorators", () => { `; assert.isTrue(context.access.has(C)); assert.isTrue(context.access.has({ - get x() { return 2; } + get x() { + return 2; + }, })); - assert.isFalse(context.access.has({ })); + assert.isFalse(context.access.has({})); }); it("test private element presence via .has", () => { const { context, C, D } = exec` @@ -826,7 +830,7 @@ describe("unittests:: evaluation:: esDecorators", () => { `; assert.isTrue(context.access.has(C)); assert.isFalse(context.access.has(D)); - assert.isFalse(context.access.has({ })); + assert.isFalse(context.access.has({})); }); it("read public element of argument", () => { const { context, C } = exec` @@ -879,7 +883,7 @@ describe("unittests:: evaluation:: esDecorators", () => { `; assert.isTrue(context.access.has(C)); assert.isTrue(context.access.has({ x: 2 })); - assert.isFalse(context.access.has({ })); + assert.isFalse(context.access.has({})); }); it("test private element presence via .has", () => { const { context, C, D } = exec` @@ -953,7 +957,7 @@ describe("unittests:: evaluation:: esDecorators", () => { `; assert.isTrue(context.access.has(C)); assert.isTrue(context.access.has({ x: 2 })); - assert.isFalse(context.access.has({ })); + assert.isFalse(context.access.has({})); }); it("test private element presence via .has", () => { const { context, C, D } = exec` @@ -1036,7 +1040,7 @@ describe("unittests:: evaluation:: esDecorators", () => { `; assert.isTrue(context.access.has(C)); assert.isTrue(context.access.has({ x: 2 })); - assert.isFalse(context.access.has({ })); + assert.isFalse(context.access.has({})); }); it("test private element presence via .has", () => { const { context, C, D } = exec` @@ -1136,7 +1140,7 @@ describe("unittests:: evaluation:: esDecorators", () => { @((t, c) => { context = c; }) class C { } `; - assert.throws(() => context.addInitializer(() => { })); + assert.throws(() => context.addInitializer(() => {})); }); }); describe("for: method", () => { @@ -1186,7 +1190,7 @@ describe("unittests:: evaluation:: esDecorators", () => { static method() {} } `; - assert.throws(() => context.addInitializer(() => { })); + assert.throws(() => context.addInitializer(() => {})); }); describe("when: static", () => { it("extra initializers run once", () => { @@ -1267,7 +1271,7 @@ describe("unittests:: evaluation:: esDecorators", () => { static get x() { return 1; } } `; - assert.throws(() => context.addInitializer(() => { })); + assert.throws(() => context.addInitializer(() => {})); }); describe("when: static", () => { it("extra initializers run once", () => { @@ -1348,7 +1352,7 @@ describe("unittests:: evaluation:: esDecorators", () => { static set x(v: number) {} } `; - assert.throws(() => context.addInitializer(() => { })); + assert.throws(() => context.addInitializer(() => {})); }); describe("when: static", () => { it("extra initializers run once", () => { @@ -1429,7 +1433,7 @@ describe("unittests:: evaluation:: esDecorators", () => { static x: number; } `; - assert.throws(() => context.addInitializer(() => { })); + assert.throws(() => context.addInitializer(() => {})); }); describe("when: static", () => { it("extra initializers run once", () => { @@ -1510,7 +1514,7 @@ describe("unittests:: evaluation:: esDecorators", () => { static accessor x: number; } `; - assert.throws(() => context.addInitializer(() => { })); + assert.throws(() => context.addInitializer(() => {})); }); describe("when: static", () => { it("extra initializers run once", () => { @@ -2249,7 +2253,7 @@ describe("unittests:: evaluation:: esDecorators", () => { "post-super constructor evaluation", // and now evaluation has completed: - "done" + "done", ]); }); diff --git a/src/testRunner/unittests/evaluation/esDecoratorsMetadata.ts b/src/testRunner/unittests/evaluation/esDecoratorsMetadata.ts index 3a5a979d4895d..1c14cdcab233f 100644 --- a/src/testRunner/unittests/evaluation/esDecoratorsMetadata.ts +++ b/src/testRunner/unittests/evaluation/esDecoratorsMetadata.ts @@ -1,6 +1,8 @@ import * as evaluator from "../../_namespaces/evaluator"; import * as ts from "../../_namespaces/ts"; -import { ScriptTarget } from "../../_namespaces/ts"; +import { + ScriptTarget, +} from "../../_namespaces/ts"; describe("unittests:: evaluation:: esDecoratorsMetadata", () => { const nodeVersion = new ts.Version(process.versions.node); diff --git a/src/testRunner/unittests/evaluation/externalModules.ts b/src/testRunner/unittests/evaluation/externalModules.ts index 04a0b55abbf34..f6719764870bb 100644 --- a/src/testRunner/unittests/evaluation/externalModules.ts +++ b/src/testRunner/unittests/evaluation/externalModules.ts @@ -32,10 +32,10 @@ describe("unittests:: evaluation:: externalModules", () => { // 3 other.f(other); - ` + `, }, rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" + main: "/.src/main.ts", }); assert.equal(result.output[0], true); // `f(undefined)` inside module. Existing behavior is correct. assert.equal(result.output[1], true); // `f(undefined)` from import. New behavior to match first case. @@ -73,14 +73,14 @@ describe("unittests:: evaluation:: externalModules", () => { // 3 other.f(other); - ` + `, }, rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" + main: "/.src/main.ts", }); assert.equal(result.output[0], true); // `f(undefined)` inside module. Existing behavior is incorrect. assert.equal(result.output[1], true); // `f(undefined)` from import. New behavior to match first case. assert.equal(result.output[2], true); // `f.call(obj, obj)`. Behavior of `.call` (or `.apply`, etc.) should not be affected. assert.equal(result.output[3], true); // `other.f(other)`. `this` is still namespace because it is left of `.`. }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/evaluation/forAwaitOf.ts b/src/testRunner/unittests/evaluation/forAwaitOf.ts index ad5aba9c295f9..76b1f931c5540 100644 --- a/src/testRunner/unittests/evaluation/forAwaitOf.ts +++ b/src/testRunner/unittests/evaluation/forAwaitOf.ts @@ -3,7 +3,8 @@ import * as ts from "../../_namespaces/ts"; describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { it("sync (es5)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let i = 0; const iterator: IterableIterator = { [Symbol.iterator]() { return this; }, @@ -21,7 +22,9 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { for await (const item of iterator) { output.push(item); } - }`, { downlevelIteration: true }); + }`, + { downlevelIteration: true }, + ); await result.main(); assert.strictEqual(result.output[0], 1); assert.strictEqual(result.output[1], 2); @@ -29,7 +32,8 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { }); it("sync (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let i = 0; const iterator: IterableIterator = { [Symbol.iterator]() { return this; }, @@ -47,7 +51,9 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { for await (const item of iterator) { output.push(item); } - }`, { target: ts.ScriptTarget.ES2015 }); + }`, + { target: ts.ScriptTarget.ES2015 }, + ); await result.main(); assert.strictEqual(result.output[0], 1); assert.strictEqual(result.output[1], 2); @@ -55,7 +61,8 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { }); it("async (es5)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let i = 0; const iterator = { [Symbol.asyncIterator](): AsyncIterableIterator { return this; }, @@ -73,7 +80,9 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { for await (const item of iterator) { output.push(item); } - }`, { downlevelIteration: true }); + }`, + { downlevelIteration: true }, + ); await result.main(); assert.strictEqual(result.output[0], 1); assert.instanceOf(result.output[1], Promise); @@ -81,7 +90,8 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { }); it("async (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let i = 0; const iterator = { [Symbol.asyncIterator](): AsyncIterableIterator { return this; }, @@ -99,7 +109,9 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { for await (const item of iterator) { output.push(item); } - }`, { target: ts.ScriptTarget.ES2015 }); + }`, + { target: ts.ScriptTarget.ES2015 }, + ); await result.main(); assert.strictEqual(result.output[0], 1); assert.instanceOf(result.output[1], Promise); @@ -107,7 +119,8 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { }); it("call return when user code return (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let returnCalled = false; async function f() { const iterator = { @@ -127,12 +140,15 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { try { await f(); } catch { } return returnCalled; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.isTrue(await result.main()); }); it("call return when user code break (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let returnCalled = false; async function f() { const iterator = { @@ -152,12 +168,15 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { try { await f(); } catch { } return returnCalled; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.isTrue(await result.main()); }); it("call return when user code throws (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let returnCalled = false; async function f() { const iterator = { @@ -177,12 +196,15 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { try { await f(); } catch { } return returnCalled; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.isTrue(await result.main()); }); it("don't call return when non-user code throws (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let returnCalled = false; async function f() { let i = 0; @@ -204,12 +226,15 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { try { await f(); } catch { } return returnCalled; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.isFalse(await result.main()); }); it("don't call return when user code continue (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let returnCalled = false; async function f() { let i = 0; @@ -232,12 +257,15 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { try { await f(); } catch { } return returnCalled; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.isFalse(await result.main()); }); it("don't call return when user code continue to local label (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let returnCalled = false; async function f() { let i = 0; @@ -264,12 +292,15 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { try { await f(); } catch { } return returnCalled; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.isFalse(await result.main()); }); it("call return when user code continue to non-local label (es2015)", async () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` let returnCalled = false; async function f() { let i = 0; @@ -296,7 +327,9 @@ describe("unittests:: evaluation:: forAwaitOfEvaluation", () => { try { await f(); } catch { } return returnCalled; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); assert.isTrue(await result.main()); }); }); diff --git a/src/testRunner/unittests/evaluation/forOf.ts b/src/testRunner/unittests/evaluation/forOf.ts index 5afe159495f54..8b2fd226770e8 100644 --- a/src/testRunner/unittests/evaluation/forOf.ts +++ b/src/testRunner/unittests/evaluation/forOf.ts @@ -3,7 +3,8 @@ import * as ts from "../../_namespaces/ts"; describe("unittests:: evaluation:: forOfEvaluation", () => { it("es5 over a array with no Symbol", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` Symbol = undefined; export var output = []; export function main() { @@ -13,18 +14,20 @@ describe("unittests:: evaluation:: forOfEvaluation", () => { output.push(value); } } - `, { downlevelIteration: true, target: ts.ScriptTarget.ES5 }); + `, + { downlevelIteration: true, target: ts.ScriptTarget.ES5 }, + ); result.main(); assert.strictEqual(result.output[0], 1); assert.strictEqual(result.output[1], 2); assert.strictEqual(result.output[2], 3); - }); it("es5 over a string with no Symbol", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` Symbol = undefined; export var output = []; export function main() { @@ -34,7 +37,9 @@ describe("unittests:: evaluation:: forOfEvaluation", () => { output.push(value); } } - `, { downlevelIteration: true, target: ts.ScriptTarget.ES5 }); + `, + { downlevelIteration: true, target: ts.ScriptTarget.ES5 }, + ); result.main(); @@ -46,7 +51,8 @@ describe("unittests:: evaluation:: forOfEvaluation", () => { }); it("es5 over undefined with no Symbol", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` Symbol = undefined; export function main() { let x = undefined; @@ -54,26 +60,32 @@ describe("unittests:: evaluation:: forOfEvaluation", () => { for (let value of x) { } } - `, { downlevelIteration: true, target: ts.ScriptTarget.ES5 }); + `, + { downlevelIteration: true, target: ts.ScriptTarget.ES5 }, + ); assert.throws(() => result.main(), "Symbol.iterator is not defined"); }); it("es5 over undefined with Symbol", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { let x = undefined; for (let value of x) { } } - `, { downlevelIteration: true, target: ts.ScriptTarget.ES5 }); + `, + { downlevelIteration: true, target: ts.ScriptTarget.ES5 }, + ); assert.throws(() => result.main(), /cannot read property.*Symbol\(Symbol\.iterator\).*/i); }); it("es5 over object with no Symbol.iterator with no Symbol", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` Symbol = undefined; export function main() { let x = {} as any; @@ -81,26 +93,32 @@ describe("unittests:: evaluation:: forOfEvaluation", () => { for (let value of x) { } } - `, { downlevelIteration: true, target: ts.ScriptTarget.ES5 }); + `, + { downlevelIteration: true, target: ts.ScriptTarget.ES5 }, + ); assert.throws(() => result.main(), "Symbol.iterator is not defined"); }); it("es5 over object with no Symbol.iterator with Symbol", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { let x = {} as any; for (let value of x) { } } - `, { downlevelIteration: true, target: ts.ScriptTarget.ES5 }); + `, + { downlevelIteration: true, target: ts.ScriptTarget.ES5 }, + ); assert.throws(() => result.main(), "Object is not iterable"); }); it("es5 over object with Symbol.iterator", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export var output = []; export function main() { let thing : any = {}; @@ -114,9 +132,10 @@ describe("unittests:: evaluation:: forOfEvaluation", () => { output.push(value) } - }`, { downlevelIteration: true, target: ts.ScriptTarget.ES5 }); + }`, + { downlevelIteration: true, target: ts.ScriptTarget.ES5 }, + ); result.main(); }); - -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/evaluation/generator.ts b/src/testRunner/unittests/evaluation/generator.ts index 3d04fe189172c..676b9ff699750 100644 --- a/src/testRunner/unittests/evaluation/generator.ts +++ b/src/testRunner/unittests/evaluation/generator.ts @@ -3,14 +3,17 @@ import * as ts from "../../_namespaces/ts"; describe("unittests:: evaluation:: generatorEvaluation", () => { it("throw before start (es5)", () => { - const { gen, output } = evaluator.evaluateTypeScript(` + const { gen, output } = evaluator.evaluateTypeScript( + ` export const output: string[] = []; export function * gen() { output.push("start"); yield 1; output.push("end"); } - `, { target: ts.ScriptTarget.ES5 }); + `, + { target: ts.ScriptTarget.ES5 }, + ); const g = gen(); const e = new Error(); @@ -19,14 +22,17 @@ describe("unittests:: evaluation:: generatorEvaluation", () => { assert.deepEqual(output, []); }); it("return before start (es5)", () => { - const { gen, output } = evaluator.evaluateTypeScript(` + const { gen, output } = evaluator.evaluateTypeScript( + ` export const output: string[] = []; export function * gen() { output.push("start"); yield 1; output.push("end"); } - `, { target: ts.ScriptTarget.ES5 }); + `, + { target: ts.ScriptTarget.ES5 }, + ); const g = gen(); assert.deepEqual(g.return(2), { value: 2, done: true }); diff --git a/src/testRunner/unittests/evaluation/superInStaticInitializer.ts b/src/testRunner/unittests/evaluation/superInStaticInitializer.ts index b6d858c69e72f..c5e2f84b4eb0b 100644 --- a/src/testRunner/unittests/evaluation/superInStaticInitializer.ts +++ b/src/testRunner/unittests/evaluation/superInStaticInitializer.ts @@ -3,7 +3,8 @@ import * as ts from "../../_namespaces/ts"; describe("unittests:: evaluation:: superInStaticInitializer", () => { it("super-property-get in es2015", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { class Base { static x = 1; @@ -16,13 +17,16 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { Derived ]; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); const [Base, Derived] = result.main(); assert.strictEqual(Base.x, 1); assert.strictEqual(Derived.y, 1); }); it("super-property-set in es2015", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { class Base { static x = 1; @@ -35,14 +39,17 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { Derived ]; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); const [Base, Derived] = result.main(); assert.strictEqual(Base.x, 1); assert.strictEqual(Derived.x, 2); assert.strictEqual(Derived.y, 1); }); it("super-accessor-get in es2015", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { let thisInBase; class Base { @@ -61,14 +68,17 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { thisInBase ]; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); const [Base, Derived, thisInBase] = result.main(); assert.strictEqual(Base._x, 1); assert.strictEqual(Derived.y, 1); assert.strictEqual(thisInBase, Derived); }); it("super-accessor-set in es2015", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { let thisInBaseGet; let thisInBaseSet; @@ -93,7 +103,9 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { thisInBaseSet ]; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); const [Base, Derived, thisInBaseGet, thisInBaseSet] = result.main(); assert.strictEqual(Base._x, 1); assert.strictEqual(Derived._x, 2); @@ -102,7 +114,8 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { assert.strictEqual(thisInBaseSet, Derived); }); it("super-call in es2015", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { let thisInBase; class Base { @@ -119,13 +132,16 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { thisInBase, ]; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); const [Derived, thisInBase] = result.main(); assert.strictEqual(Derived.y, 1); assert.strictEqual(thisInBase, Derived); }); it("super-call in es5", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { let thisInBase; class Base { @@ -142,13 +158,16 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { thisInBase, ]; } - `, { target: ts.ScriptTarget.ES5 }); + `, + { target: ts.ScriptTarget.ES5 }, + ); const [Derived, thisInBase] = result.main(); assert.strictEqual(Derived.y, 1); assert.strictEqual(thisInBase, Derived); }); it("super- and this-call in es2015", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { class Base { static x() { @@ -165,12 +184,15 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { Derived, ]; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); const [Derived] = result.main(); assert.strictEqual(Derived.y, 2); }); it("super- and this-call in es5", () => { - const result = evaluator.evaluateTypeScript(` + const result = evaluator.evaluateTypeScript( + ` export function main() { class Base { static x() { @@ -187,8 +209,10 @@ describe("unittests:: evaluation:: superInStaticInitializer", () => { Derived, ]; } - `, { target: ts.ScriptTarget.ES2015 }); + `, + { target: ts.ScriptTarget.ES2015 }, + ); const [Derived] = result.main(); assert.strictEqual(Derived.y, 2); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/evaluation/updateExpressionInModule.ts b/src/testRunner/unittests/evaluation/updateExpressionInModule.ts index 071a975b78856..dc0eaade1c1eb 100644 --- a/src/testRunner/unittests/evaluation/updateExpressionInModule.ts +++ b/src/testRunner/unittests/evaluation/updateExpressionInModule.ts @@ -12,10 +12,10 @@ describe("unittests:: evaluation:: updateExpressionInModule", () => { let a = 1; export { a }; export const b = ++a; - ` + `, }, rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" + main: "/.src/main.ts", }, { module: ts.ModuleKind.CommonJS }); assert.equal(result.a, 2); assert.equal(result.b, 2); @@ -27,41 +27,49 @@ describe("unittests:: evaluation:: updateExpressionInModule", () => { let a = 1; export { a }; export const b = ++a; - ` + `, }, rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" + main: "/.src/main.ts", }, { module: ts.ModuleKind.System }); assert.equal(result.a, 2); assert.equal(result.b, 2); }); itIfBigInt("pre-increment in commonjs using BigInt", () => { - const result = evaluator.evaluateTypeScript({ - files: { - "/.src/main.ts": ` + const result = evaluator.evaluateTypeScript( + { + files: { + "/.src/main.ts": ` let a = BigInt(1); export { a }; export const b = ++a; - ` + `, + }, + rootFiles: ["/.src/main.ts"], + main: "/.src/main.ts", }, - rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" - }, { module: ts.ModuleKind.CommonJS }, { BigInt }); + { module: ts.ModuleKind.CommonJS }, + { BigInt }, + ); assert.equal(result.a, BigInt(2)); assert.equal(result.b, BigInt(2)); }); itIfBigInt("pre-increment in System using BigInt", () => { - const result = evaluator.evaluateTypeScript({ - files: { - "/.src/main.ts": ` + const result = evaluator.evaluateTypeScript( + { + files: { + "/.src/main.ts": ` let a = BigInt(1); export { a }; export const b = ++a; - ` + `, + }, + rootFiles: ["/.src/main.ts"], + main: "/.src/main.ts", }, - rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" - }, { module: ts.ModuleKind.System }, { BigInt }); + { module: ts.ModuleKind.System }, + { BigInt }, + ); assert.equal(result.a, BigInt(2)); assert.equal(result.b, BigInt(2)); }); @@ -72,10 +80,10 @@ describe("unittests:: evaluation:: updateExpressionInModule", () => { let a = 1; export { a }; export const b = a++; - ` + `, }, rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" + main: "/.src/main.ts", }, { module: ts.ModuleKind.CommonJS }); assert.equal(result.a, 2); assert.equal(result.b, 1); @@ -87,42 +95,50 @@ describe("unittests:: evaluation:: updateExpressionInModule", () => { let a = 1; export { a }; export const b = a++; - ` + `, }, rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" + main: "/.src/main.ts", }, { module: ts.ModuleKind.System }); assert.equal(result.a, 2); assert.equal(result.b, 1); }); itIfBigInt("post-increment in commonjs using BigInt", () => { - const result = evaluator.evaluateTypeScript({ - files: { - "/.src/main.ts": ` + const result = evaluator.evaluateTypeScript( + { + files: { + "/.src/main.ts": ` let a = BigInt(1); export { a }; export const b = a++; - ` + `, + }, + rootFiles: ["/.src/main.ts"], + main: "/.src/main.ts", }, - rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" - }, { module: ts.ModuleKind.CommonJS }, { BigInt }); + { module: ts.ModuleKind.CommonJS }, + { BigInt }, + ); assert.equal(result.a, BigInt(2)); assert.equal(result.b, BigInt(1)); }); itIfBigInt("post-increment in System using BigInt", () => { - const result = evaluator.evaluateTypeScript({ - files: { - "/.src/main.ts": ` + const result = evaluator.evaluateTypeScript( + { + files: { + "/.src/main.ts": ` let a = BigInt(1); export { a }; export const b = a++; - ` + `, + }, + rootFiles: ["/.src/main.ts"], + main: "/.src/main.ts", }, - rootFiles: ["/.src/main.ts"], - main: "/.src/main.ts" - }, { module: ts.ModuleKind.System }, { BigInt }); + { module: ts.ModuleKind.System }, + { BigInt }, + ); assert.equal(result.a, BigInt(2)); assert.equal(result.b, BigInt(1)); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/evaluation/usingDeclarations.ts b/src/testRunner/unittests/evaluation/usingDeclarations.ts index 701daf7208f3c..11adef2fb2b31 100644 --- a/src/testRunner/unittests/evaluation/usingDeclarations.ts +++ b/src/testRunner/unittests/evaluation/usingDeclarations.ts @@ -7,7 +7,8 @@ function FakeSuppressedError(error: any, suppressed: any) { describe("unittests:: evaluation:: usingDeclarations", () => { it("'using' in Block, normal completion (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -30,7 +31,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -40,12 +43,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "body", "exit block", "disposed", - "after block" + "after block", ]); }); it("'using' in Block, 'throw' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -72,7 +76,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -82,12 +88,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "body", "disposed", "error", - "after try" + "after try", ]); }); it("'using' in Block, 'throw' in dispose (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -114,7 +121,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -125,12 +134,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "exit try", "disposed", "error", - "after try" + "after try", ]); }); it("'using' in Block, 'throw' in multiple dispose (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable_1 = { @@ -164,7 +174,10 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); main(); @@ -177,14 +190,15 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "disposed 1", { error: "error 1", - suppressed: "error 2" + suppressed: "error 2", }, - "after try" + "after try", ]); }); it("'using' in Block, 'throw' in body and dispose (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -212,7 +226,10 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); main(); @@ -223,14 +240,15 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "disposed", { error: "dispose error", - suppressed: "body error" + suppressed: "body error", }, - "after try" + "after try", ]); }); it("'using' in Block, 'throw' in body and multiple dispose (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable_1 = { @@ -265,7 +283,10 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); main(); @@ -279,15 +300,16 @@ describe("unittests:: evaluation:: usingDeclarations", () => { error: "dispose error 1", suppressed: { error: "dispose error 2", - suppressed: "body error" - } + suppressed: "body error", + }, }, - "after try" + "after try", ]); }); it("'using' in Block, 'throw' in body and dispose, no global SuppressedError (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -315,7 +337,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after try"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -323,18 +347,20 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "before try", "enter try", "body", - "disposed"]); + "disposed", + ]); assert.instanceOf(output[4], Error); assert.strictEqual(output[4].name, "SuppressedError"); assert.strictEqual(output[4].error, "dispose error"); assert.strictEqual(output[4].suppressed, "body error"); assert.deepEqual(output.slice(5), [ - "after try" + "after try", ]); }); it("'using' in Block, 'return' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -357,7 +383,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -365,12 +393,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "before block", "enter block", "body", - "disposed" + "disposed", ]); }); it("'using' in Block, 'break' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -393,7 +422,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -402,12 +433,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter block", "body", "disposed", - "after block" + "after block", ]); }); it("'using' in Block, 'continue' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -430,7 +462,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -442,12 +476,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter block", "body", "disposed", - "after block" + "after block", ]); }); it("'using' in head of 'for', normal completion (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -470,7 +505,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -483,12 +520,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "body", "exit loop", "disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for', 'throw' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -516,7 +554,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -526,12 +566,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "body", "disposed", "error", - "after loop" + "after loop", ]); }); it("'using' in head of 'for', 'throw' in dispose (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -559,7 +600,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -573,12 +616,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "exit loop", "disposed", "error", - "after loop" + "after loop", ]); }); it("'using' in head of 'for', 'throw' in body and dispose (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -607,7 +651,10 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); main(); @@ -618,14 +665,15 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "disposed", { error: "dispose error", - suppressed: "body error" + suppressed: "body error", }, - "after loop" + "after loop", ]); }); it("'using' in head of 'for', 'return' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -648,7 +696,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -656,12 +706,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "before loop", "enter loop", "body", - "disposed" + "disposed", ]); }); it("'using' in head of 'for', 'break' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -684,7 +735,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -693,12 +746,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter loop", "body", "disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for', 'continue' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -721,7 +775,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -732,12 +788,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter loop", "body", "disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for', multiple iterations (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable = { @@ -760,7 +817,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -773,12 +832,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "body", "exit loop", "disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for-of', normal completion (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -807,7 +867,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -821,12 +883,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "body", "exit loop", "b disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for-of', 'throw' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -861,7 +924,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -876,7 +941,8 @@ describe("unittests:: evaluation:: usingDeclarations", () => { }); it("'using' in head of 'for-of', 'throw' in dispose (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -911,7 +977,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -927,7 +995,8 @@ describe("unittests:: evaluation:: usingDeclarations", () => { }); it("'using' in head of 'for-of', 'throw' in body and dispose (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -963,7 +1032,10 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); main(); @@ -974,14 +1046,15 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "a disposed", { error: "dispose error", - suppressed: "body error" + suppressed: "body error", }, "after loop", ]); }); it("'using' in head of 'for-of', 'return' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1010,7 +1083,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -1023,7 +1098,8 @@ describe("unittests:: evaluation:: usingDeclarations", () => { }); it("'using' in head of 'for-of', 'break' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1052,7 +1128,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -1061,12 +1139,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter loop", "body", "a disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for-of', 'continue' in body (es2018)", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1095,7 +1174,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -1107,12 +1188,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter loop", "body", "b disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for-await-of', normal completion (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1141,7 +1223,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1155,12 +1239,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "body", "exit loop", "b disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for-await-of', 'throw' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1195,7 +1280,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1210,7 +1297,8 @@ describe("unittests:: evaluation:: usingDeclarations", () => { }); it("'using' in head of 'for-await-of', 'throw' in dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1245,7 +1333,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1261,7 +1351,8 @@ describe("unittests:: evaluation:: usingDeclarations", () => { }); it("'using' in head of 'for-await-of', 'throw' in body and dispose (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1297,7 +1388,10 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }, { SuppressedError: FakeSuppressedError }); + `, + { target: ts.ScriptTarget.ES2018 }, + { SuppressedError: FakeSuppressedError }, + ); await main(); @@ -1308,14 +1402,15 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "a disposed", { error: "dispose error", - suppressed: "body error" + suppressed: "body error", }, "after loop", ]); }); it("'using' in head of 'for-await-of', 'return' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1344,7 +1439,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1357,7 +1454,8 @@ describe("unittests:: evaluation:: usingDeclarations", () => { }); it("'using' in head of 'for-await-of', 'break' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1386,7 +1484,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1395,12 +1495,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter loop", "body", "a disposed", - "after loop" + "after loop", ]); }); it("'using' in head of 'for-await-of', 'continue' in body (es2018)", async () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function* g() { @@ -1429,7 +1530,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after loop"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); await main(); @@ -1441,12 +1544,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter loop", "body", "b disposed", - "after loop" + "after loop", ]); }); it("'using' at top level of module (CommonJS)", () => { - const { output, x, y } = evaluator.evaluateTypeScript(` + const { output, x, y } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; output.push("before export x"); export const x = 1; @@ -1459,7 +1563,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { output.push("after using"); export const y = 2; output.push("after export y"); - `, { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.CommonJS }); + `, + { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.CommonJS }, + ); assert.strictEqual(x, 1); assert.strictEqual(y, 2); @@ -1468,12 +1574,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "before using", "after using", "after export y", - "disposed" + "disposed", ]); }); it("'using' at top level of module (AMD)", () => { - const { output, x, y } = evaluator.evaluateTypeScript(` + const { output, x, y } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; output.push("before export x"); export const x = 1; @@ -1486,7 +1593,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { output.push("after using"); export const y = 2; output.push("after export y"); - `, { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.AMD }); + `, + { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.AMD }, + ); assert.strictEqual(x, 1); assert.strictEqual(y, 2); @@ -1495,12 +1604,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "before using", "after using", "after export y", - "disposed" + "disposed", ]); }); it("'using' at top level of module (System)", () => { - const { output, x, y } = evaluator.evaluateTypeScript(` + const { output, x, y } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; output.push("before export x"); export const x = 1; @@ -1513,7 +1623,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { output.push("after using"); export const y = 2; output.push("after export y"); - `, { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.System }); + `, + { target: ts.ScriptTarget.ES2018, module: ts.ModuleKind.System }, + ); assert.strictEqual(x, 1); assert.strictEqual(y, 2); @@ -1522,12 +1634,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "before using", "after using", "after export y", - "disposed" + "disposed", ]); }); it("'using' for 'null' value", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function body() { @@ -1544,7 +1657,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -1553,12 +1668,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter block", "body", "exit block", - "after block" + "after block", ]); }); it("'using' for 'undefined' value", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function body() { @@ -1575,7 +1691,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -1584,12 +1702,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "enter block", "body", "exit block", - "after block" + "after block", ]); }); it("'using' for non-disposable value", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function body() { @@ -1606,7 +1725,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); assert.throws(main); assert.deepEqual(output, [ @@ -1616,7 +1737,8 @@ describe("unittests:: evaluation:: usingDeclarations", () => { }); it("'using' disposes in reverse order", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; const disposable_1 = { @@ -1644,7 +1766,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { } output.push("after block"); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); @@ -1655,12 +1779,13 @@ describe("unittests:: evaluation:: usingDeclarations", () => { "exit block", "disposed 2", "disposed 1", - "after block" + "after block", ]); }); it("'using' for 'function' disposable resource ", () => { - const { main, output } = evaluator.evaluateTypeScript(` + const { main, output } = evaluator.evaluateTypeScript( + ` export const output: any[] = []; function disposable() { @@ -1674,7 +1799,9 @@ describe("unittests:: evaluation:: usingDeclarations", () => { run(); } - `, { target: ts.ScriptTarget.ES2018 }); + `, + { target: ts.ScriptTarget.ES2018 }, + ); main(); diff --git a/src/testRunner/unittests/factory.ts b/src/testRunner/unittests/factory.ts index 5740c30c90775..88a45eb611848 100644 --- a/src/testRunner/unittests/factory.ts +++ b/src/testRunner/unittests/factory.ts @@ -2,7 +2,11 @@ import * as ts from "../_namespaces/ts"; describe("unittests:: FactoryAPI", () => { function assertSyntaxKind(node: ts.Node, expected: ts.SyntaxKind) { - assert.strictEqual(node.kind, expected, `Actual: ${ts.Debug.formatSyntaxKind(node.kind)} Expected: ${ts.Debug.formatSyntaxKind(expected)}`); + assert.strictEqual( + node.kind, + expected, + `Actual: ${ts.Debug.formatSyntaxKind(node.kind)} Expected: ${ts.Debug.formatSyntaxKind(expected)}`, + ); } describe("factory.createExportAssignment", () => { it("parenthesizes default export if necessary", () => { @@ -15,19 +19,58 @@ describe("unittests:: FactoryAPI", () => { assertSyntaxKind(node.expression, ts.SyntaxKind.ParenthesizedExpression); } - const clazz = ts.factory.createClassExpression(/*modifiers*/ undefined, "C", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [ - ts.factory.createPropertyDeclaration([ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], "prop", /*questionOrExclamationToken*/ undefined, /*type*/ undefined, ts.factory.createStringLiteral("1")), - ]); + const clazz = ts.factory.createClassExpression( + /*modifiers*/ undefined, + "C", + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [ + ts.factory.createPropertyDeclaration( + [ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], + "prop", + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createStringLiteral("1"), + ), + ], + ); checkExpression(clazz); checkExpression(ts.factory.createPropertyAccessExpression(clazz, "prop")); - const func = ts.factory.createFunctionExpression(/*modifiers*/ undefined, /*asteriskToken*/ undefined, "fn", /*typeParameters*/ undefined, /*parameters*/ undefined, /*type*/ undefined, ts.factory.createBlock([])); + const func = ts.factory.createFunctionExpression( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + "fn", + /*typeParameters*/ undefined, + /*parameters*/ undefined, + /*type*/ undefined, + ts.factory.createBlock([]), + ); checkExpression(func); - checkExpression(ts.factory.createCallExpression(func, /*typeArguments*/ undefined, /*argumentsArray*/ undefined)); - checkExpression(ts.factory.createTaggedTemplateExpression(func, /*typeArguments*/ undefined, ts.factory.createNoSubstitutionTemplateLiteral(""))); + checkExpression( + ts.factory.createCallExpression(func, /*typeArguments*/ undefined, /*argumentsArray*/ undefined), + ); + checkExpression( + ts.factory.createTaggedTemplateExpression( + func, + /*typeArguments*/ undefined, + ts.factory.createNoSubstitutionTemplateLiteral(""), + ), + ); - checkExpression(ts.factory.createBinaryExpression(ts.factory.createStringLiteral("a"), ts.SyntaxKind.CommaToken, ts.factory.createStringLiteral("b"))); - checkExpression(ts.factory.createCommaListExpression([ts.factory.createStringLiteral("a"), ts.factory.createStringLiteral("b")])); + checkExpression( + ts.factory.createBinaryExpression( + ts.factory.createStringLiteral("a"), + ts.SyntaxKind.CommaToken, + ts.factory.createStringLiteral("b"), + ), + ); + checkExpression( + ts.factory.createCommaListExpression([ + ts.factory.createStringLiteral("a"), + ts.factory.createStringLiteral("b"), + ]), + ); }); }); @@ -47,10 +90,30 @@ describe("unittests:: FactoryAPI", () => { checkBody(ts.factory.createObjectLiteralExpression()); checkBody(ts.factory.createPropertyAccessExpression(ts.factory.createObjectLiteralExpression(), "prop")); - checkBody(ts.factory.createAsExpression(ts.factory.createPropertyAccessExpression(ts.factory.createObjectLiteralExpression(), "prop"), ts.factory.createTypeReferenceNode("T", /*typeArguments*/ undefined))); - checkBody(ts.factory.createNonNullExpression(ts.factory.createPropertyAccessExpression(ts.factory.createObjectLiteralExpression(), "prop"))); - checkBody(ts.factory.createCommaListExpression([ts.factory.createStringLiteral("a"), ts.factory.createStringLiteral("b")])); - checkBody(ts.factory.createBinaryExpression(ts.factory.createStringLiteral("a"), ts.SyntaxKind.CommaToken, ts.factory.createStringLiteral("b"))); + checkBody( + ts.factory.createAsExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createObjectLiteralExpression(), "prop"), + ts.factory.createTypeReferenceNode("T", /*typeArguments*/ undefined), + ), + ); + checkBody( + ts.factory.createNonNullExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createObjectLiteralExpression(), "prop"), + ), + ); + checkBody( + ts.factory.createCommaListExpression([ + ts.factory.createStringLiteral("a"), + ts.factory.createStringLiteral("b"), + ]), + ); + checkBody( + ts.factory.createBinaryExpression( + ts.factory.createStringLiteral("a"), + ts.SyntaxKind.CommaToken, + ts.factory.createStringLiteral("b"), + ), + ); }); }); @@ -67,7 +130,10 @@ describe("unittests:: FactoryAPI", () => { ); function checkRhs(operator: ts.BinaryOperator, expectParens: boolean) { const node = ts.factory.createBinaryExpression(lhs, operator, rhs); - assertSyntaxKind(node.right, expectParens ? ts.SyntaxKind.ParenthesizedExpression : ts.SyntaxKind.ArrowFunction); + assertSyntaxKind( + node.right, + expectParens ? ts.SyntaxKind.ParenthesizedExpression : ts.SyntaxKind.ArrowFunction, + ); } checkRhs(ts.SyntaxKind.CommaToken, /*expectParens*/ false); @@ -82,5 +148,4 @@ describe("unittests:: FactoryAPI", () => { checkRhs(ts.SyntaxKind.QuestionQuestionEqualsToken, /*expectParens*/ false); }); }); - }); diff --git a/src/testRunner/unittests/helpers.ts b/src/testRunner/unittests/helpers.ts index 4e5f2046a416a..fa5f015935922 100644 --- a/src/testRunner/unittests/helpers.ts +++ b/src/testRunner/unittests/helpers.ts @@ -4,7 +4,7 @@ const enum ChangedPart { none = 0, references = 1 << 0, importsAndExports = 1 << 1, - program = 1 << 2 + program = 1 << 2, } export const newLine = "\r\n"; @@ -31,11 +31,13 @@ export interface TestCompilerHost extends ts.CompilerHost { export class SourceText implements ts.IScriptSnapshot { private fullText: string | undefined; - constructor(private references: string, + constructor( + private references: string, private importsAndExports: string, private program: string, private changedPart = ChangedPart.none, - private version = 0) { + private version = 0, + ) { } static New(references: string, importsAndExports: string, program: string): SourceText { @@ -51,15 +53,33 @@ export class SourceText implements ts.IScriptSnapshot { public updateReferences(newReferences: string): SourceText { ts.Debug.assert(newReferences !== undefined); - return new SourceText(newReferences + newLine, this.importsAndExports, this.program, this.changedPart | ChangedPart.references, this.version + 1); + return new SourceText( + newReferences + newLine, + this.importsAndExports, + this.program, + this.changedPart | ChangedPart.references, + this.version + 1, + ); } public updateImportsAndExports(newImportsAndExports: string): SourceText { ts.Debug.assert(newImportsAndExports !== undefined); - return new SourceText(this.references, newImportsAndExports + newLine, this.program, this.changedPart | ChangedPart.importsAndExports, this.version + 1); + return new SourceText( + this.references, + newImportsAndExports + newLine, + this.program, + this.changedPart | ChangedPart.importsAndExports, + this.version + 1, + ); } public updateProgram(newProgram: string): SourceText { ts.Debug.assert(newProgram !== undefined); - return new SourceText(this.references, this.importsAndExports, newProgram, this.changedPart | ChangedPart.program, this.version + 1); + return new SourceText( + this.references, + this.importsAndExports, + newProgram, + this.changedPart | ChangedPart.program, + this.version + 1, + ); } public getFullText() { @@ -88,7 +108,10 @@ export class SourceText implements ts.IScriptSnapshot { newLength = this.importsAndExports.length; break; case ChangedPart.program: - oldSpan = ts.createTextSpan(oldText.references.length + oldText.importsAndExports.length, oldText.program.length); + oldSpan = ts.createTextSpan( + oldText.references.length + oldText.importsAndExports.length, + oldText.program.length, + ); newLength = this.program.length; break; default: @@ -106,7 +129,12 @@ function createSourceFileWithText(fileName: string, sourceText: SourceText, targ return file; } -export function createTestCompilerHost(texts: readonly NamedSourceText[], target: ts.ScriptTarget, oldProgram?: ProgramWithSourceTexts, useGetSourceFileByPath?: boolean) { +export function createTestCompilerHost( + texts: readonly NamedSourceText[], + target: ts.ScriptTarget, + oldProgram?: ProgramWithSourceTexts, + useGetSourceFileByPath?: boolean, +) { const files = ts.arrayToMap(texts, t => t.name, t => { if (oldProgram) { let oldFile = oldProgram.getSourceFile(t.name) as SourceFileWithText; @@ -141,13 +169,21 @@ export function createTestCompilerHost(texts: readonly NamedSourceText[], target }, }; if (useGetSourceFileByPath) { - const filesByPath = ts.mapEntries(files, (fileName, file) => [ts.toPath(fileName, "", getCanonicalFileName), file]); + const filesByPath = ts.mapEntries( + files, + (fileName, file) => [ts.toPath(fileName, "", getCanonicalFileName), file], + ); result.getSourceFileByPath = (_fileName, path) => filesByPath.get(path); } return result; } -export function newProgram(texts: NamedSourceText[], rootNames: string[], options: ts.CompilerOptions, useGetSourceFileByPath?: boolean): ProgramWithSourceTexts { +export function newProgram( + texts: NamedSourceText[], + rootNames: string[], + options: ts.CompilerOptions, + useGetSourceFileByPath?: boolean, +): ProgramWithSourceTexts { const host = createTestCompilerHost(texts, options.target!, /*oldProgram*/ undefined, useGetSourceFileByPath); const program = ts.createProgram(rootNames, options, host) as ProgramWithSourceTexts; program.sourceTexts = texts; @@ -155,7 +191,14 @@ export function newProgram(texts: NamedSourceText[], rootNames: string[], option return program; } -export function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: readonly string[], options: ts.CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[], useGetSourceFileByPath?: boolean) { +export function updateProgram( + oldProgram: ProgramWithSourceTexts, + rootNames: readonly string[], + options: ts.CompilerOptions, + updater: (files: NamedSourceText[]) => void, + newTexts?: NamedSourceText[], + useGetSourceFileByPath?: boolean, +) { if (!newTexts) { newTexts = oldProgram.sourceTexts!.slice(0); } diff --git a/src/testRunner/unittests/helpers/baseline.ts b/src/testRunner/unittests/helpers/baseline.ts index e3075686be24d..d5061340314d0 100644 --- a/src/testRunner/unittests/helpers/baseline.ts +++ b/src/testRunner/unittests/helpers/baseline.ts @@ -1,8 +1,12 @@ import * as fakes from "../../_namespaces/fakes"; import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; -import { TscCompileSystem } from "./tsc"; -import { TestServerHost } from "./virtualFileSystemWithWatch"; +import { + TscCompileSystem, +} from "./tsc"; +import { + TestServerHost, +} from "./virtualFileSystemWithWatch"; export type CommandLineProgram = [ts.Program, ts.BuilderProgram?]; export interface CommandLineCallbacks { @@ -10,7 +14,9 @@ export interface CommandLineCallbacks { getPrograms: () => readonly CommandLineProgram[]; } -function isAnyProgram(program: ts.Program | ts.BuilderProgram | ts.ParsedCommandLine): program is ts.Program | ts.BuilderProgram { +function isAnyProgram( + program: ts.Program | ts.BuilderProgram | ts.ParsedCommandLine, +): program is ts.Program | ts.BuilderProgram { return !!(program as ts.Program | ts.BuilderProgram).getCompilerOptions; } export function commandLineCallbacks( @@ -23,9 +29,10 @@ export function commandLineCallbacks( cb: program => { if (isAnyProgram(program)) { baselineBuildInfo(program.getCompilerOptions(), sys, originalReadCall); - (programs || (programs = [])).push(ts.isBuilderProgram(program) ? - [program.getProgram(), program] : - [program] + (programs || (programs = [])).push( + ts.isBuilderProgram(program) + ? [program.getProgram(), program] + : [program], ); } else { @@ -36,11 +43,16 @@ export function commandLineCallbacks( const result = programs || ts.emptyArray; programs = undefined; return result; - } + }, }; } -export function baselinePrograms(baseline: string[], getPrograms: () => readonly CommandLineProgram[], oldPrograms: readonly (CommandLineProgram | undefined)[], baselineDependencies: boolean | undefined) { +export function baselinePrograms( + baseline: string[], + getPrograms: () => readonly CommandLineProgram[], + oldPrograms: readonly (CommandLineProgram | undefined)[], + baselineDependencies: boolean | undefined, +) { const programs = getPrograms(); for (let i = 0; i < programs.length; i++) { baselineProgram(baseline, programs[i], oldPrograms[i], baselineDependencies); @@ -48,7 +60,12 @@ export function baselinePrograms(baseline: string[], getPrograms: () => readonly return programs; } -function baselineProgram(baseline: string[], [program, builderProgram]: CommandLineProgram, oldProgram: CommandLineProgram | undefined, baselineDependencies: boolean | undefined) { +function baselineProgram( + baseline: string[], + [program, builderProgram]: CommandLineProgram, + oldProgram: CommandLineProgram | undefined, + baselineDependencies: boolean | undefined, +) { if (program !== oldProgram?.[0]) { const options = program.getCompilerOptions(); baseline.push(`Program root files: ${JSON.stringify(program.getRootFileNames())}`); @@ -71,7 +88,10 @@ function baselineProgram(baseline: string[], [program, builderProgram]: CommandL if (state.semanticDiagnosticsPerFile?.size) { baseline.push("Semantic diagnostics in builder refreshed for::"); for (const file of program.getSourceFiles()) { - if (!internalState.semanticDiagnosticsFromOldState || !internalState.semanticDiagnosticsFromOldState.has(file.resolvedPath)) { + if ( + !internalState.semanticDiagnosticsFromOldState + || !internalState.semanticDiagnosticsFromOldState.has(file.resolvedPath) + ) { baseline.push(file.fileName); } } @@ -124,7 +144,13 @@ export function generateSourceMapBaselineFiles(sys: ts.System & { writtenFiles: } } -function generateBundleFileSectionInfo(sys: ts.System, originalReadCall: ts.System["readFile"], baselineRecorder: Harness.Compiler.WriterAggregator, bundleFileInfo: ts.BundleFileInfo | undefined, outFile: string | undefined) { +function generateBundleFileSectionInfo( + sys: ts.System, + originalReadCall: ts.System["readFile"], + baselineRecorder: Harness.Compiler.WriterAggregator, + bundleFileInfo: ts.BundleFileInfo | undefined, + outFile: string | undefined, +) { if (!ts.length(bundleFileInfo && bundleFileInfo.sections) && !outFile) return; // Nothing to baseline const content = outFile && sys.fileExists(outFile) ? originalReadCall.call(sys, outFile, "utf8")! : ""; @@ -159,77 +185,109 @@ function generateBundleFileSectionInfo(sys: ts.System, originalReadCall: ts.Syst } function writeSectionHeader(section: ts.BundleFileSection) { - baselineRecorder.WriteLine(`${section.kind}: (${section.pos}-${section.end})${section.data ? ":: " + section.data : ""}${section.kind === ts.BundleFileSectionKind.Prepend ? " texts:: " + section.texts.length : ""}`); + baselineRecorder.WriteLine( + `${section.kind}: (${section.pos}-${section.end})${section.data ? ":: " + section.data : ""}${ + section.kind === ts.BundleFileSectionKind.Prepend ? " texts:: " + section.texts.length : "" + }`, + ); } } export type ReadableProgramBuildInfoDiagnostic = string | [string, readonly ts.ReusableDiagnostic[]]; export type ReadableBuilderFileEmit = string & { __readableBuilderFileEmit: any; }; -export type ReadableProgramBuilderInfoFilePendingEmit = [original: string | [string], emitKind: ReadableBuilderFileEmit]; +export type ReadableProgramBuilderInfoFilePendingEmit = [ + original: string | [string], + emitKind: ReadableBuilderFileEmit, +]; export type ReadableProgramBuildInfoEmitSignature = string | [string, ts.EmitSignature | []]; export type ReadableProgramBuildInfoFileInfo = Omit & { impliedFormat: string | undefined; original: T | undefined; }; export type ReadableProgramBuildInfoRoot = - [original: ts.ProgramBuildInfoFileId, readable: string] | - [orginal: ts.ProgramBuildInfoRootStartEnd, readable: readonly string[]]; -export type ReadableProgramMultiFileEmitBuildInfo = Omit & { - fileNamesList: readonly (readonly string[])[] | undefined; - fileInfos: ts.MapLike>; - root: readonly ReadableProgramBuildInfoRoot[]; - referencedMap: ts.MapLike | undefined; - exportedModulesMap: ts.MapLike | undefined; - semanticDiagnosticsPerFile: readonly ReadableProgramBuildInfoDiagnostic[] | undefined; - affectedFilesPendingEmit: readonly ReadableProgramBuilderInfoFilePendingEmit[] | undefined; - changeFileSet: readonly string[] | undefined; - emitSignatures: readonly ReadableProgramBuildInfoEmitSignature[] | undefined; -}; -export type ReadableProgramBuildInfoBundlePendingEmit = [emitKind: ReadableBuilderFileEmit, original: ts.ProgramBuildInfoBundlePendingEmit]; -export type ReadableProgramBundleEmitBuildInfo = Omit & { - fileInfos: ts.MapLike>; - root: readonly ReadableProgramBuildInfoRoot[]; - pendingEmit: ReadableProgramBuildInfoBundlePendingEmit | undefined; -}; + | [original: ts.ProgramBuildInfoFileId, readable: string] + | [orginal: ts.ProgramBuildInfoRootStartEnd, readable: readonly string[]]; +export type ReadableProgramMultiFileEmitBuildInfo = + & Omit< + ts.ProgramMultiFileEmitBuildInfo, + | "fileIdsList" + | "fileInfos" + | "root" + | "referencedMap" + | "exportedModulesMap" + | "semanticDiagnosticsPerFile" + | "affectedFilesPendingEmit" + | "changeFileSet" + | "emitSignatures" + > + & { + fileNamesList: readonly (readonly string[])[] | undefined; + fileInfos: ts.MapLike>; + root: readonly ReadableProgramBuildInfoRoot[]; + referencedMap: ts.MapLike | undefined; + exportedModulesMap: ts.MapLike | undefined; + semanticDiagnosticsPerFile: readonly ReadableProgramBuildInfoDiagnostic[] | undefined; + affectedFilesPendingEmit: readonly ReadableProgramBuilderInfoFilePendingEmit[] | undefined; + changeFileSet: readonly string[] | undefined; + emitSignatures: readonly ReadableProgramBuildInfoEmitSignature[] | undefined; + }; +export type ReadableProgramBuildInfoBundlePendingEmit = [ + emitKind: ReadableBuilderFileEmit, + original: ts.ProgramBuildInfoBundlePendingEmit, +]; +export type ReadableProgramBundleEmitBuildInfo = + & Omit + & { + fileInfos: ts.MapLike>; + root: readonly ReadableProgramBuildInfoRoot[]; + pendingEmit: ReadableProgramBuildInfoBundlePendingEmit | undefined; + }; export type ReadableProgramBuildInfo = ReadableProgramMultiFileEmitBuildInfo | ReadableProgramBundleEmitBuildInfo; -export function isReadableProgramBundleEmitBuildInfo(info: ReadableProgramBuildInfo | undefined): info is ReadableProgramBundleEmitBuildInfo { +export function isReadableProgramBundleEmitBuildInfo( + info: ReadableProgramBuildInfo | undefined, +): info is ReadableProgramBundleEmitBuildInfo { return !!info && !!ts.outFile(info.options || {}); } -export type ReadableBuildInfo = Omit & { program: ReadableProgramBuildInfo | undefined; size: number; }; +export type ReadableBuildInfo = Omit & { + program: ReadableProgramBuildInfo | undefined; + size: number; +}; function generateBuildInfoProgramBaseline(sys: ts.System, buildInfoPath: string, buildInfo: ts.BuildInfo) { let program: ReadableProgramBuildInfo | undefined; let fileNamesList: string[][] | undefined; if (buildInfo.program && ts.isProgramBundleEmitBuildInfo(buildInfo.program)) { const fileInfos: ReadableProgramBundleEmitBuildInfo["fileInfos"] = {}; buildInfo.program?.fileInfos?.forEach((fileInfo, index) => - fileInfos[toFileName(index + 1 as ts.ProgramBuildInfoFileId)] = ts.isString(fileInfo) ? - fileInfo : - toReadableFileInfo(fileInfo, ts.identity) + fileInfos[toFileName(index + 1 as ts.ProgramBuildInfoFileId)] = ts.isString(fileInfo) + ? fileInfo + : toReadableFileInfo(fileInfo, ts.identity) ); const pendingEmit = buildInfo.program.pendingEmit; program = { ...buildInfo.program, fileInfos, root: buildInfo.program.root.map(toReadableProgramBuildInfoRoot), - pendingEmit: pendingEmit === undefined ? - undefined : - [ + pendingEmit: pendingEmit === undefined + ? undefined + : [ toReadableBuilderFileEmit(ts.toProgramEmitPending(pendingEmit, buildInfo.program.options)), - pendingEmit + pendingEmit, ], }; } else if (buildInfo.program) { const fileInfos: ReadableProgramMultiFileEmitBuildInfo["fileInfos"] = {}; - buildInfo.program?.fileInfos?.forEach((fileInfo, index) => fileInfos[toFileName(index + 1 as ts.ProgramBuildInfoFileId)] = toReadableFileInfo(fileInfo, ts.toBuilderStateFileInfoForMultiEmit)); + buildInfo.program?.fileInfos?.forEach((fileInfo, index) => + fileInfos[toFileName(index + 1 as ts.ProgramBuildInfoFileId)] = toReadableFileInfo( + fileInfo, + ts.toBuilderStateFileInfoForMultiEmit, + ) + ); fileNamesList = buildInfo.program.fileIdsList?.map(fileIdsListId => fileIdsListId.map(toFileName)); - const fullEmitForOptions = buildInfo.program.affectedFilesPendingEmit ? ts.getBuilderFileEmit(buildInfo.program.options || {}) : undefined; + const fullEmitForOptions = buildInfo.program.affectedFilesPendingEmit + ? ts.getBuilderFileEmit(buildInfo.program.options || {}) : undefined; program = buildInfo.program && { fileNames: buildInfo.program.fileNames, fileNamesList, @@ -239,16 +297,18 @@ function generateBuildInfoProgramBaseline(sys: ts.System, buildInfoPath: string, referencedMap: toMapOfReferencedSet(buildInfo.program.referencedMap), exportedModulesMap: toMapOfReferencedSet(buildInfo.program.exportedModulesMap), semanticDiagnosticsPerFile: buildInfo.program.semanticDiagnosticsPerFile?.map(d => - ts.isNumber(d) ? - toFileName(d) : - [toFileName(d[0]), d[1]] + ts.isNumber(d) + ? toFileName(d) + : [toFileName(d[0]), d[1]] + ), + affectedFilesPendingEmit: buildInfo.program.affectedFilesPendingEmit?.map(value => + toReadableProgramBuilderInfoFilePendingEmit(value, fullEmitForOptions!) ), - affectedFilesPendingEmit: buildInfo.program.affectedFilesPendingEmit?.map(value => toReadableProgramBuilderInfoFilePendingEmit(value, fullEmitForOptions!)), changeFileSet: buildInfo.program.changeFileSet?.map(toFileName), emitSignatures: buildInfo.program.emitSignatures?.map(s => - ts.isNumber(s) ? - toFileName(s) : - [toFileName(s[0]), s[1]] + ts.isNumber(s) + ? toFileName(s) + : [toFileName(s[0]), s[1]] ), latestChangedDtsFile: buildInfo.program.latestChangedDtsFile, }; @@ -286,12 +346,16 @@ function generateBuildInfoProgramBaseline(sys: ts.System, buildInfoPath: string, return fileNamesList![fileIdsListId - 1]; } - function toReadableFileInfo(original: T, toFileInfo: (fileInfo: T) => ts.BuilderState.FileInfo): ReadableProgramBuildInfoFileInfo { + function toReadableFileInfo( + original: T, + toFileInfo: (fileInfo: T) => ts.BuilderState.FileInfo, + ): ReadableProgramBuildInfoFileInfo { const info = toFileInfo(original); return { original: ts.isString(original) ? undefined : original, ...info, - impliedFormat: info.impliedFormat && ts.getNameOfCompilerOptionValue(info.impliedFormat, ts.moduleOptionDeclaration.type), + impliedFormat: info.impliedFormat + && ts.getNameOfCompilerOptionValue(info.impliedFormat, ts.moduleOptionDeclaration.type), }; } @@ -302,7 +366,9 @@ function generateBuildInfoProgramBaseline(sys: ts.System, buildInfoPath: string, return [original, readable]; } - function toMapOfReferencedSet(referenceMap: ts.ProgramBuildInfoReferencedMap | undefined): ts.MapLike | undefined { + function toMapOfReferencedSet( + referenceMap: ts.ProgramBuildInfoReferencedMap | undefined, + ): ts.MapLike | undefined { if (!referenceMap) return undefined; const result: ts.MapLike = {}; for (const [fileNamesKey, fileNamesListKey] of referenceMap) { @@ -311,7 +377,10 @@ function generateBuildInfoProgramBaseline(sys: ts.System, buildInfoPath: string, return result; } - function toReadableProgramBuilderInfoFilePendingEmit(value: ts.ProgramBuilderInfoFilePendingEmit, fullEmitForOptions: ts.BuilderFileEmit): ReadableProgramBuilderInfoFilePendingEmit { + function toReadableProgramBuilderInfoFilePendingEmit( + value: ts.ProgramBuilderInfoFilePendingEmit, + fullEmitForOptions: ts.BuilderFileEmit, + ): ReadableProgramBuilderInfoFilePendingEmit { return [ ts.isNumber(value) ? toFileName(value) : [toFileName(value[0])], toReadableBuilderFileEmit(ts.toBuilderFileEmit(value, fullEmitForOptions)), @@ -347,24 +416,43 @@ export function baselineBuildInfo( if (!buildInfoPath || !sys.writtenFiles!.has(toPathWithSystem(sys, buildInfoPath))) return; if (!sys.fileExists(buildInfoPath)) return; - const buildInfo = ts.getBuildInfo(buildInfoPath, (originalReadCall || sys.readFile).call(sys, buildInfoPath, "utf8")!); + const buildInfo = ts.getBuildInfo( + buildInfoPath, + (originalReadCall || sys.readFile).call(sys, buildInfoPath, "utf8")!, + ); if (!buildInfo) return sys.writeFile(`${buildInfoPath}.baseline.txt`, "Error reading valid buildinfo file"); generateBuildInfoProgramBaseline(sys, buildInfoPath, buildInfo); if (!ts.outFile(options)) return; const { jsFilePath, declarationFilePath } = ts.getOutputPathsForBundle(options, /*forceDtsPaths*/ false); const bundle = buildInfo.bundle; - if (!bundle || (!ts.length(bundle.js && bundle.js.sections) && !ts.length(bundle.dts && bundle.dts.sections))) return; + if (!bundle || (!ts.length(bundle.js && bundle.js.sections) && !ts.length(bundle.dts && bundle.dts.sections))) { + return; + } // Write the baselines: const baselineRecorder = new Harness.Compiler.WriterAggregator(); generateBundleFileSectionInfo(sys, originalReadCall || sys.readFile, baselineRecorder, bundle.js, jsFilePath); - generateBundleFileSectionInfo(sys, originalReadCall || sys.readFile, baselineRecorder, bundle.dts, declarationFilePath); + generateBundleFileSectionInfo( + sys, + originalReadCall || sys.readFile, + baselineRecorder, + bundle.dts, + declarationFilePath, + ); baselineRecorder.Close(); const text = baselineRecorder.lines.join("\r\n"); sys.writeFile(`${buildInfoPath}.baseline.txt`, text); } -export function tscBaselineName(scenario: string, subScenario: string, commandLineArgs: readonly string[], isWatch?: boolean, suffix?: string) { - return `${ts.isBuild(commandLineArgs) ? "tsbuild" : "tsc"}${isWatch ? "Watch" : ""}/${scenario}/${subScenario.split(" ").join("-")}${suffix ? suffix : ""}.js`; -} \ No newline at end of file +export function tscBaselineName( + scenario: string, + subScenario: string, + commandLineArgs: readonly string[], + isWatch?: boolean, + suffix?: string, +) { + return `${ts.isBuild(commandLineArgs) ? "tsbuild" : "tsc"}${isWatch ? "Watch" : ""}/${scenario}/${ + subScenario.split(" ").join("-") + }${suffix ? suffix : ""}.js`; +} diff --git a/src/testRunner/unittests/helpers/contents.ts b/src/testRunner/unittests/helpers/contents.ts index 4a0bb4918dec9..d31379328ee31 100644 --- a/src/testRunner/unittests/helpers/contents.ts +++ b/src/testRunner/unittests/helpers/contents.ts @@ -1,5 +1,7 @@ import * as ts from "../../_namespaces/ts"; -import { libFile } from "./virtualFileSystemWithWatch"; +import { + libFile, +} from "./virtualFileSystemWithWatch"; export function compilerOptionsToConfigJson(options: ts.CompilerOptions) { return ts.optionMapToObject(ts.serializeCompilerOptions(options)); @@ -22,4 +24,4 @@ interface Symbol { export interface FsContents { [path: string]: string; -} \ No newline at end of file +} diff --git a/src/testRunner/unittests/helpers/extends.ts b/src/testRunner/unittests/helpers/extends.ts index 397d4821047d5..f4eccbe357312 100644 --- a/src/testRunner/unittests/helpers/extends.ts +++ b/src/testRunner/unittests/helpers/extends.ts @@ -1,4 +1,6 @@ -import { dedent } from "../../_namespaces/Utils"; +import { + dedent, +} from "../../_namespaces/Utils"; import { createServerHost, createWatchedSystem, @@ -12,7 +14,7 @@ export function getSymlinkedExtendsSys(forTsserver?: true): TestServerHost { extends: "@something/tsconfig-base/tsconfig.json", compilerOptions: { removeComments: true, - } + }, }), "/users/user/projects/myconfigs/node_modules/@something/tsconfig-base/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true }, @@ -29,4 +31,4 @@ export function getSymlinkedExtendsSys(forTsserver?: true): TestServerHost { }, [libFile.path]: libFile.content, }, { currentDirectory: "/users/user/projects/myproject" }); -} \ No newline at end of file +} diff --git a/src/testRunner/unittests/helpers/libraryResolution.ts b/src/testRunner/unittests/helpers/libraryResolution.ts index 11bf63292c10a..5cfb7b9279863 100644 --- a/src/testRunner/unittests/helpers/libraryResolution.ts +++ b/src/testRunner/unittests/helpers/libraryResolution.ts @@ -1,7 +1,17 @@ -import { dedent } from "../../_namespaces/Utils"; -import { FsContents, libContent } from "./contents"; -import { loadProjectFromFiles } from "./vfs"; -import { createServerHost, createWatchedSystem } from "./virtualFileSystemWithWatch"; +import { + dedent, +} from "../../_namespaces/Utils"; +import { + FsContents, + libContent, +} from "./contents"; +import { + loadProjectFromFiles, +} from "./vfs"; +import { + createServerHost, + createWatchedSystem, +} from "./virtualFileSystemWithWatch"; function getFsContentsForLibResolution(libRedirection?: boolean): FsContents { return { @@ -15,7 +25,12 @@ function getFsContentsForLibResolution(libRedirection?: boolean): FsContents { /// `, "/home/src/projects/project1/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true, typeRoots: ["./typeroot1"], lib: ["es5", "dom"], traceResolution: true }, + compilerOptions: { + composite: true, + typeRoots: ["./typeroot1"], + lib: ["es5", "dom"], + traceResolution: true, + }, }), "/home/src/projects/project1/typeroot1/sometype/index.d.ts": `export type TheNum = "type1";`, "/home/src/projects/project2/utils.d.ts": `export const y = 10;`, @@ -44,8 +59,9 @@ function getFsContentsForLibResolution(libRedirection?: boolean): FsContents { "/home/src/projects/node_modules/@typescript/lib-esnext/index.d.ts": libContent, "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts": "interface DOMInterface { }", "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts": "interface WebworkerInterface { }", - "/home/src/projects/node_modules/@typescript/lib-scripthost/index.d.ts": "interface ScriptHostInterface { }", - } : undefined + "/home/src/projects/node_modules/@typescript/lib-scripthost/index.d.ts": + "interface ScriptHostInterface { }", + } : undefined, }; } @@ -55,7 +71,7 @@ export function getFsForLibResolution(libRedirection: true | undefined) { { cwd: "/home/src/projects", executingFilePath: "/home/src/lib/tsc.js", - } + }, ); } @@ -65,7 +81,7 @@ export function getSysForLibResolution(libRedirection?: true) { { currentDirectory: "/home/src/projects", executingFilePath: "/home/src/lib/tsc.js", - } + }, ); } @@ -75,12 +91,22 @@ export function getServerHosForLibResolution(libRedirection?: true) { { currentDirectory: "/home/src/projects", executingFilePath: "/home/src/lib/tsc.js", - } + }, ); } export function getCommandLineArgsForLibResolution(withoutConfig: true | undefined) { - return withoutConfig ? - ["project1/core.d.ts", "project1/utils.d.ts", "project1/file.ts", "project1/index.ts", "project1/file2.ts", "--lib", "es5,dom", "--traceResolution", "--explainFiles"] : - ["-p", "project1", "--explainFiles"]; + return withoutConfig + ? [ + "project1/core.d.ts", + "project1/utils.d.ts", + "project1/file.ts", + "project1/index.ts", + "project1/file2.ts", + "--lib", + "es5,dom", + "--traceResolution", + "--explainFiles", + ] + : ["-p", "project1", "--explainFiles"]; } diff --git a/src/testRunner/unittests/helpers/node10Result.ts b/src/testRunner/unittests/helpers/node10Result.ts index 5961d211f3f94..17c8722567743 100644 --- a/src/testRunner/unittests/helpers/node10Result.ts +++ b/src/testRunner/unittests/helpers/node10Result.ts @@ -1,35 +1,53 @@ -import { dedent } from "../../_namespaces/Utils"; -import { FsContents } from "./contents"; -import { libFile } from "./virtualFileSystemWithWatch"; +import { + dedent, +} from "../../_namespaces/Utils"; +import { + FsContents, +} from "./contents"; +import { + libFile, +} from "./virtualFileSystemWithWatch"; export function getFsConentsForNode10ResultAtTypesPackageJson(packageName: string, addTypesCondition: boolean) { - return JSON.stringify({ - name: `@types/${packageName}`, - version: "1.0.0", - types: "index.d.ts", - exports: { - ".": { - ...(addTypesCondition ? { types: "./index.d.ts" } : {}), - require: "./index.d.ts" - } - } - }, undefined, " "); + return JSON.stringify( + { + name: `@types/${packageName}`, + version: "1.0.0", + types: "index.d.ts", + exports: { + ".": { + ...(addTypesCondition ? { types: "./index.d.ts" } : {}), + require: "./index.d.ts", + }, + }, + }, + undefined, + " ", + ); } -export function getFsContentsForNode10ResultPackageJson(packageName: string, addTypes: boolean, addTypesCondition: boolean) { - return JSON.stringify({ - name: packageName, - version: "1.0.0", - main: "index.js", - ...(addTypes ? { types: "index.d.ts" } : {}), - exports: { - ".": { - ...(addTypesCondition ? { types: "./index.d.ts" } : {}), - import: "./index.mjs", - require: "./index.js" - } - } - }, undefined, " "); +export function getFsContentsForNode10ResultPackageJson( + packageName: string, + addTypes: boolean, + addTypesCondition: boolean, +) { + return JSON.stringify( + { + name: packageName, + version: "1.0.0", + main: "index.js", + ...(addTypes ? { types: "index.d.ts" } : {}), + exports: { + ".": { + ...(addTypesCondition ? { types: "./index.d.ts" } : {}), + import: "./index.mjs", + require: "./index.js", + }, + }, + }, + undefined, + " ", + ); } export function getFsContentsForNode10ResultDts(packageName: string) { @@ -46,21 +64,39 @@ function mjs(packageName: string) { export function getFsContentsForNode10Result(): FsContents { return { - "/home/src/projects/project/node_modules/@types/bar/package.json": getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ false), + "/home/src/projects/project/node_modules/@types/bar/package.json": + getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ false), "/home/src/projects/project/node_modules/@types/bar/index.d.ts": getFsContentsForNode10ResultDts("bar"), - "/home/src/projects/project/node_modules/bar/package.json": getFsContentsForNode10ResultPackageJson("bar", /*addTypes*/ false, /*addTypesCondition*/ false), + "/home/src/projects/project/node_modules/bar/package.json": getFsContentsForNode10ResultPackageJson( + "bar", + /*addTypes*/ false, + /*addTypesCondition*/ false, + ), "/home/src/projects/project/node_modules/bar/index.js": js("bar"), "/home/src/projects/project/node_modules/bar/index.mjs": mjs("bar"), - "/home/src/projects/project/node_modules/foo/package.json": getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ false), + "/home/src/projects/project/node_modules/foo/package.json": getFsContentsForNode10ResultPackageJson( + "foo", + /*addTypes*/ true, + /*addTypesCondition*/ false, + ), "/home/src/projects/project/node_modules/foo/index.js": js("foo"), "/home/src/projects/project/node_modules/foo/index.mjs": mjs("foo"), "/home/src/projects/project/node_modules/foo/index.d.ts": getFsContentsForNode10ResultDts("foo"), - "/home/src/projects/project/node_modules/@types/bar2/package.json": getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ true), + "/home/src/projects/project/node_modules/@types/bar2/package.json": + getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ true), "/home/src/projects/project/node_modules/@types/bar2/index.d.ts": getFsContentsForNode10ResultDts("bar2"), - "/home/src/projects/project/node_modules/bar2/package.json": getFsContentsForNode10ResultPackageJson("bar2", /*addTypes*/ false, /*addTypesCondition*/ false), + "/home/src/projects/project/node_modules/bar2/package.json": getFsContentsForNode10ResultPackageJson( + "bar2", + /*addTypes*/ false, + /*addTypesCondition*/ false, + ), "/home/src/projects/project/node_modules/bar2/index.js": js("bar2"), "/home/src/projects/project/node_modules/bar2/index.mjs": mjs("bar2"), - "/home/src/projects/project/node_modules/foo2/package.json": getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ true), + "/home/src/projects/project/node_modules/foo2/package.json": getFsContentsForNode10ResultPackageJson( + "foo2", + /*addTypes*/ true, + /*addTypesCondition*/ true, + ), "/home/src/projects/project/node_modules/foo2/index.js": js("foo2"), "/home/src/projects/project/node_modules/foo2/index.mjs": mjs("foo2"), "/home/src/projects/project/node_modules/foo2/index.d.ts": getFsContentsForNode10ResultDts("foo2"), @@ -78,8 +114,8 @@ export function getFsContentsForNode10Result(): FsContents { strict: true, types: [], }, - files: ["index.mts"] + files: ["index.mts"], }), [libFile.path]: libFile.content, }; -} \ No newline at end of file +} diff --git a/src/testRunner/unittests/helpers/solutionBuilder.ts b/src/testRunner/unittests/helpers/solutionBuilder.ts index 018594d044d6d..06e064694d3bc 100644 --- a/src/testRunner/unittests/helpers/solutionBuilder.ts +++ b/src/testRunner/unittests/helpers/solutionBuilder.ts @@ -1,6 +1,8 @@ import * as fakes from "../../_namespaces/fakes"; import * as ts from "../../_namespaces/ts"; -import { commandLineCallbacks } from "./baseline"; +import { + commandLineCallbacks, +} from "./baseline"; import { makeSystemReadyForBaseline, TscCompileSystem, @@ -17,21 +19,26 @@ import { export function createSolutionBuilderHostForBaseline( sys: TscCompileSystem | TestServerHost, versionToWrite?: string, - originalRead?: (TscCompileSystem | TestServerHost)["readFile"] + originalRead?: (TscCompileSystem | TestServerHost)["readFile"], ) { if (sys instanceof fakes.System) makeSystemReadyForBaseline(sys, versionToWrite); const { cb } = commandLineCallbacks(sys, originalRead); - const host = ts.createSolutionBuilderHost(sys, + const host = ts.createSolutionBuilderHost( + sys, /*createProgram*/ undefined, ts.createDiagnosticReporter(sys, /*pretty*/ true), - ts.createBuilderStatusReporter(sys, /*pretty*/ true) + ts.createBuilderStatusReporter(sys, /*pretty*/ true), ); host.afterProgramEmitAndDiagnostics = cb; host.afterEmitBundle = cb; return host; } -export function createSolutionBuilder(system: TestServerHost, rootNames: readonly string[], originalRead?: TestServerHost["readFile"]) { +export function createSolutionBuilder( + system: TestServerHost, + rootNames: readonly string[], + originalRead?: TestServerHost["readFile"], +) { const host = createSolutionBuilderHostForBaseline(system, /*versionToWrite*/ undefined, originalRead); return ts.createSolutionBuilder(host, rootNames, {}); } @@ -42,14 +49,22 @@ export function ensureErrorFreeBuild(host: TestServerHost, rootNames: readonly s assert.equal(host.getOutput().length, 0, JSON.stringify(host.getOutput(), /*replacer*/ undefined, " ")); } -export function solutionBuildWithBaseline(sys: TestServerHost, solutionRoots: readonly string[], originalRead?: TestServerHost["readFile"]) { +export function solutionBuildWithBaseline( + sys: TestServerHost, + solutionRoots: readonly string[], + originalRead?: TestServerHost["readFile"], +) { const originalReadFile = sys.readFile; const originalWrite = sys.write; const originalWriteFile = sys.writeFile; ts.Debug.assert(sys.writtenFiles === undefined); - const solutionBuilder = createSolutionBuilder(changeToHostTrackingWrittenFiles( - fakes.patchHostForBuildInfoReadWrite(sys) - ), solutionRoots, originalRead); + const solutionBuilder = createSolutionBuilder( + changeToHostTrackingWrittenFiles( + fakes.patchHostForBuildInfoReadWrite(sys), + ), + solutionRoots, + originalRead, + ); solutionBuilder.build(); sys.readFile = originalReadFile; sys.write = originalWrite; @@ -58,6 +73,10 @@ export function solutionBuildWithBaseline(sys: TestServerHost, solutionRoots: re return sys; } -export function createSystemWithSolutionBuild(solutionRoots: readonly string[], files: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], params?: TestServerHostCreationParameters) { +export function createSystemWithSolutionBuild( + solutionRoots: readonly string[], + files: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], + params?: TestServerHostCreationParameters, +) { return solutionBuildWithBaseline(createWatchedSystem(files, params), solutionRoots); -} \ No newline at end of file +} diff --git a/src/testRunner/unittests/helpers/tsc.ts b/src/testRunner/unittests/helpers/tsc.ts index d6681047f9664..f28a91041bcec 100644 --- a/src/testRunner/unittests/helpers/tsc.ts +++ b/src/testRunner/unittests/helpers/tsc.ts @@ -30,7 +30,7 @@ export type TscCompileSystem = fakes.System & { export const noChangeRun: TestTscEdit = { caption: "no-change-run", - edit: ts.noop + edit: ts.noop, }; export const noChangeOnlyRuns = [noChangeRun]; @@ -59,17 +59,24 @@ export function testTscCompileLike(input: TestTscCompileLike) { const initialFs = input.fs(); const inputFs = initialFs.shadow(); const { - scenario, subScenario, diffWithInitial, - commandLineArgs, modifyFs, + scenario, + subScenario, + diffWithInitial, + commandLineArgs, + modifyFs, environmentVariables, - compile: worker, additionalBaseline, + compile: worker, + additionalBaseline, } = input; if (modifyFs) modifyFs(inputFs); inputFs.makeReadonly(); const fs = inputFs.shadow(); // Create system - const sys = new fakes.System(fs, { executingFilePath: `${fs.meta.get("defaultLibLocation")}/tsc`, env: environmentVariables }) as TscCompileSystem; + const sys = new fakes.System(fs, { + executingFilePath: `${fs.meta.get("defaultLibLocation")}/tsc`, + env: environmentVariables, + }) as TscCompileSystem; sys.storeFilesChangingSignatureDuringEmit = true; sys.write(`${sys.getExecutingFilePath()} ${commandLineArgs.join(" ")}\n`); sys.exit = exitCode => sys.exitCode = exitCode; @@ -78,9 +85,9 @@ export function testTscCompileLike(input: TestTscCompileLike) { additionalBaseline?.(sys); fs.makeReadonly(); sys.baseLine = () => { - const baseFsPatch = diffWithInitial ? - inputFs.diff(initialFs, { includeChangedFileWithSameContent: true }) : - inputFs.diff(/*base*/ undefined, { baseIsNotShadowRoot: true }); + const baseFsPatch = diffWithInitial + ? inputFs.diff(initialFs, { includeChangedFileWithSameContent: true }) + : inputFs.diff(/*base*/ undefined, { baseIsNotShadowRoot: true }); const patch = fs.diff(inputFs, { includeChangedFileWithSameContent: true }); return { file: tscBaselineName(scenario, subScenario, commandLineArgs), @@ -90,7 +97,7 @@ ${baseFsPatch ? vfs.formatPatch(baseFsPatch) : ""} Output:: ${sys.output.join("")} -${patch ? vfs.formatPatch(patch) : ""}` +${patch ? vfs.formatPatch(patch) : ""}`, }; }; return sys; @@ -125,7 +132,7 @@ export function testTscCompile(input: TestTscCompile) { return testTscCompileLike({ ...input, compile: commandLineCompile, - additionalBaseline + additionalBaseline, }); function commandLineCompile(sys: TscCompileSystem) { @@ -151,7 +158,12 @@ export function testTscCompile(input: TestTscCompile) { } function additionalBaseline(sys: TscCompileSystem) { - const { baselineSourceMap, baselineReadFileCalls, baselinePrograms: shouldBaselinePrograms, baselineDependencies } = input; + const { + baselineSourceMap, + baselineReadFileCalls, + baselinePrograms: shouldBaselinePrograms, + baselineDependencies, + } = input; if (input.computeDtsSignatures) storeDtsSignatures(sys, getPrograms!()); if (shouldBaselinePrograms) { const baseline: string[] = []; @@ -174,7 +186,10 @@ function storeDtsSignatures(sys: TscCompileSystem, programs: readonly CommandLin if (!buildInfoPath) continue; sys.dtsSignaures ??= new Map(); const dtsSignatureData = new Map(); - sys.dtsSignaures.set(`${toPathWithSystem(sys, buildInfoPath)}.readable.baseline.txt` as ts.Path, dtsSignatureData); + sys.dtsSignaures.set( + `${toPathWithSystem(sys, buildInfoPath)}.readable.baseline.txt` as ts.Path, + dtsSignatureData, + ); const state = builderProgram.getState(); state.hasCalledUpdateShapeSignature?.forEach(resolvedPath => { const file = program.getSourceFileByPath(resolvedPath); @@ -186,8 +201,13 @@ function storeDtsSignatures(sys: TscCompileSystem, programs: readonly CommandLin /*cancellationToken*/ undefined, sys, (signature, sourceFiles) => { - const exportedModules = ts.BuilderState.getExportedModules(state.exportedModulesMap && sourceFiles[0].exportedModulesFromDeclarationEmit); - dtsSignatureData.set(relativeToBuildInfo(resolvedPath), { signature, exportedModules: exportedModules && ts.arrayFrom(exportedModules.keys(), relativeToBuildInfo) }); + const exportedModules = ts.BuilderState.getExportedModules( + state.exportedModulesMap && sourceFiles[0].exportedModulesFromDeclarationEmit, + ); + dtsSignatureData.set(relativeToBuildInfo(resolvedPath), { + signature, + exportedModules: exportedModules && ts.arrayFrom(exportedModules.keys(), relativeToBuildInfo), + }); }, ); }); @@ -195,8 +215,12 @@ function storeDtsSignatures(sys: TscCompileSystem, programs: readonly CommandLin function relativeToBuildInfo(path: string) { const currentDirectory = program.getCurrentDirectory(); const getCanonicalFileName = ts.createGetCanonicalFileName(program.useCaseSensitiveFileNames()); - const buildInfoDirectory = ts.getDirectoryPath(ts.getNormalizedAbsolutePath(buildInfoPath!, currentDirectory)); - return ts.ensurePathIsNonModuleName(ts.getRelativePathFromDirectory(buildInfoDirectory, path, getCanonicalFileName)); + const buildInfoDirectory = ts.getDirectoryPath( + ts.getNormalizedAbsolutePath(buildInfoPath!, currentDirectory), + ); + return ts.ensurePathIsNonModuleName( + ts.getRelativePathFromDirectory(buildInfoDirectory, path, getCanonicalFileName), + ); } } } @@ -217,14 +241,19 @@ export interface VerifyTscCompileLike { /** * Verify by baselining after initializing FS and custom compile */ -export function verifyTscCompileLike(verifier: (input: T) => { baseLine: TscCompileSystem["baseLine"]; }, input: T) { +export function verifyTscCompileLike( + verifier: (input: T) => { baseLine: TscCompileSystem["baseLine"]; }, + input: T, +) { describe(`tsc ${input.commandLineArgs.join(" ")} ${input.scenario}:: ${input.subScenario}`, () => { describe(input.scenario, () => { describe(input.subScenario, () => { - verifyTscBaseline(() => verifier({ - ...input, - fs: () => input.fs().makeReadonly() - })); + verifyTscBaseline(() => + verifier({ + ...input, + fs: () => input.fs().makeReadonly(), + }) + ); }); }); }); @@ -242,9 +271,15 @@ interface VerifyTscEditDiscrepanciesInput { environmentVariables: TestTscCompile["environmentVariables"]; } function verifyTscEditDiscrepancies({ - index, edits, scenario, commandLineArgs, environmentVariables, + index, + edits, + scenario, + commandLineArgs, + environmentVariables, baselines, - modifyFs, baseFs, newSys + modifyFs, + baseFs, + newSys, }: VerifyTscEditDiscrepanciesInput): string[] | undefined { const { caption, discrepancyExplanation } = edits[index]; const sys = testTscCompile({ @@ -267,35 +302,53 @@ function verifyTscEditDiscrepancies({ const incrementalBuildText = newSys.readFile(outputFile); if (ts.isBuildInfoFile(outputFile)) { // Check only presence and absence and not text as we will do that for readable baseline - if (!sys.fileExists(`${outputFile}.readable.baseline.txt`)) addBaseline(`Readable baseline not present in clean build:: File:: ${outputFile}`); - if (!newSys.fileExists(`${outputFile}.readable.baseline.txt`)) addBaseline(`Readable baseline not present in incremental build:: File:: ${outputFile}`); - verifyPresenceAbsence(incrementalBuildText, cleanBuildText, `Incremental and clean tsbuildinfo file presence differs:: File:: ${outputFile}`); + if (!sys.fileExists(`${outputFile}.readable.baseline.txt`)) { + addBaseline(`Readable baseline not present in clean build:: File:: ${outputFile}`); + } + if (!newSys.fileExists(`${outputFile}.readable.baseline.txt`)) { + addBaseline(`Readable baseline not present in incremental build:: File:: ${outputFile}`); + } + verifyPresenceAbsence( + incrementalBuildText, + cleanBuildText, + `Incremental and clean tsbuildinfo file presence differs:: File:: ${outputFile}`, + ); } else if (!ts.fileExtensionIs(outputFile, ".tsbuildinfo.readable.baseline.txt")) { verifyTextEqual(incrementalBuildText, cleanBuildText, `File: ${outputFile}`); } else if (incrementalBuildText !== cleanBuildText) { // Verify build info without affectedFilesPendingEmit - const { buildInfo: incrementalBuildInfo, readableBuildInfo: incrementalReadableBuildInfo } = getBuildInfoForIncrementalCorrectnessCheck(incrementalBuildText); - const { buildInfo: cleanBuildInfo, readableBuildInfo: cleanReadableBuildInfo } = getBuildInfoForIncrementalCorrectnessCheck(cleanBuildText); + const { buildInfo: incrementalBuildInfo, readableBuildInfo: incrementalReadableBuildInfo } = + getBuildInfoForIncrementalCorrectnessCheck(incrementalBuildText); + const { buildInfo: cleanBuildInfo, readableBuildInfo: cleanReadableBuildInfo } = + getBuildInfoForIncrementalCorrectnessCheck(cleanBuildText); const dtsSignaures = sys.dtsSignaures?.get(outputFile); - verifyTextEqual(incrementalBuildInfo, cleanBuildInfo, `TsBuild info text without affectedFilesPendingEmit:: ${outputFile}::`); - // Verify file info sigantures + verifyTextEqual( + incrementalBuildInfo, + cleanBuildInfo, + `TsBuild info text without affectedFilesPendingEmit:: ${outputFile}::`, + ); + // Verify file info sigantures verifyMapLike( incrementalReadableBuildInfo?.program?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"], cleanReadableBuildInfo?.program?.fileInfos as ReadableProgramMultiFileEmitBuildInfo["fileInfos"], (key, incrementalFileInfo, cleanFileInfo) => { const dtsForKey = dtsSignaures?.get(key); - if (!incrementalFileInfo || !cleanFileInfo || incrementalFileInfo.signature !== cleanFileInfo.signature && (!dtsForKey || incrementalFileInfo.signature !== dtsForKey.signature)) { + if ( + !incrementalFileInfo || !cleanFileInfo + || incrementalFileInfo.signature !== cleanFileInfo.signature + && (!dtsForKey || incrementalFileInfo.signature !== dtsForKey.signature) + ) { return [ `Incremental signature is neither dts signature nor file version for File:: ${key}`, `Incremental:: ${JSON.stringify(incrementalFileInfo, /*replacer*/ undefined, 2)}`, `Clean:: ${JSON.stringify(cleanFileInfo, /*replacer*/ undefined, 2)}`, - `Dts Signature:: $${JSON.stringify(dtsForKey?.signature)}` + `Dts Signature:: $${JSON.stringify(dtsForKey?.signature)}`, ]; } }, - `FileInfos:: File:: ${outputFile}` + `FileInfos:: File:: ${outputFile}`, ); if (!isReadableProgramBundleEmitBuildInfo(incrementalReadableBuildInfo?.program)) { ts.Debug.assert(!isReadableProgramBundleEmitBuildInfo(cleanReadableBuildInfo?.program)); @@ -305,17 +358,21 @@ function verifyTscEditDiscrepancies({ cleanReadableBuildInfo?.program?.exportedModulesMap, (key, incrementalReferenceSet, cleanReferenceSet) => { const dtsForKey = dtsSignaures?.get(key); - if (!ts.arrayIsEqualTo(incrementalReferenceSet, cleanReferenceSet) && - (!dtsForKey || !ts.arrayIsEqualTo(incrementalReferenceSet, dtsForKey.exportedModules))) { + if ( + !ts.arrayIsEqualTo(incrementalReferenceSet, cleanReferenceSet) + && (!dtsForKey || !ts.arrayIsEqualTo(incrementalReferenceSet, dtsForKey.exportedModules)) + ) { return [ `Incremental Reference set is neither from dts nor files reference map for File:: ${key}::`, `Incremental:: ${JSON.stringify(incrementalReferenceSet, /*replacer*/ undefined, 2)}`, `Clean:: ${JSON.stringify(cleanReferenceSet, /*replacer*/ undefined, 2)}`, - `DtsExportsMap:: ${JSON.stringify(dtsForKey?.exportedModules, /*replacer*/ undefined, 2)}` + `DtsExportsMap:: ${ + JSON.stringify(dtsForKey?.exportedModules, /*replacer*/ undefined, 2) + }`, ]; } }, - `exportedModulesMap:: File:: ${outputFile}` + `exportedModulesMap:: File:: ${outputFile}`, ); // Verify that incrementally pending affected file emit are in clean build since clean build can contain more files compared to incremental depending of noEmitOnError option if (incrementalReadableBuildInfo?.program?.affectedFilesPendingEmit) { @@ -323,22 +380,26 @@ function verifyTscEditDiscrepancies({ addBaseline( `Incremental build contains affectedFilesPendingEmit, clean build does not have it: ${outputFile}::`, `Incremental buildInfoText:: ${incrementalBuildText}`, - `Clean buildInfoText:: ${cleanBuildText}` + `Clean buildInfoText:: ${cleanBuildText}`, ); } let expectedIndex = 0; incrementalReadableBuildInfo.program.affectedFilesPendingEmit.forEach(([actualFileOrArray]) => { const actualFile = ts.isString(actualFileOrArray) ? actualFileOrArray : actualFileOrArray[0]; expectedIndex = ts.findIndex( - (cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo).affectedFilesPendingEmit, - ([expectedFileOrArray]) => actualFile === (ts.isString(expectedFileOrArray) ? expectedFileOrArray : expectedFileOrArray[0]), - expectedIndex + (cleanReadableBuildInfo!.program! as ReadableProgramMultiFileEmitBuildInfo) + .affectedFilesPendingEmit, + ([expectedFileOrArray]) => + actualFile + === (ts.isString(expectedFileOrArray) ? expectedFileOrArray + : expectedFileOrArray[0]), + expectedIndex, ); if (expectedIndex === -1) { addBaseline( `Incremental build contains ${actualFile} file as pending emit, clean build does not have it: ${outputFile}::`, `Incremental buildInfoText:: ${incrementalBuildText}`, - `Clean buildInfoText:: ${cleanBuildText}` + `Clean buildInfoText:: ${cleanBuildText}`, ); } expectedIndex++; @@ -347,7 +408,9 @@ function verifyTscEditDiscrepancies({ } } } - if (!headerAdded && discrepancyExplanation) addBaseline("*** Supplied discrepancy explanation but didnt file any difference"); + if (!headerAdded && discrepancyExplanation) { + addBaseline("*** Supplied discrepancy explanation but didnt file any difference"); + } return baselines; function verifyTextEqual(incrementalText: string | undefined, cleanText: string | undefined, message: string) { @@ -398,7 +461,10 @@ function verifyTscEditDiscrepancies({ function addBaseline(...text: string[]) { if (!baselines || !headerAdded) { - (baselines ||= []).push(`${index}:: ${caption}`, ...(discrepancyExplanation?.()|| ["*** Needs explanation"])); + (baselines ||= []).push( + `${index}:: ${caption}`, + ...(discrepancyExplanation?.() || ["*** Needs explanation"]), + ); headerAdded = true; } baselines.push(...text); @@ -411,32 +477,47 @@ function getBuildInfoForIncrementalCorrectnessCheck(text: string | undefined): { } { if (!text) return { buildInfo: text }; const readableBuildInfo = JSON.parse(text) as ReadableBuildInfo; - let sanitizedFileInfos: ts.MapLike | ReadableProgramBuildInfoFileInfo, "signature" | "original"> & { signature: undefined; original: undefined; }> | undefined; + let sanitizedFileInfos: + | ts.MapLike< + | string + | Omit< + | ReadableProgramBuildInfoFileInfo + | ReadableProgramBuildInfoFileInfo, + "signature" | "original" + > + & { signature: undefined; original: undefined; } + > + | undefined; if (readableBuildInfo.program?.fileInfos) { sanitizedFileInfos = {}; for (const id in readableBuildInfo.program.fileInfos) { if (ts.hasProperty(readableBuildInfo.program.fileInfos, id)) { const info = readableBuildInfo.program.fileInfos[id]; - sanitizedFileInfos[id] = ts.isString(info) ? info : { ...info, signature: undefined, original: undefined }; + sanitizedFileInfos[id] = ts.isString(info) ? info + : { ...info, signature: undefined, original: undefined }; } } } return { - buildInfo: JSON.stringify({ - ...readableBuildInfo, - program: readableBuildInfo.program && { - ...readableBuildInfo.program, - fileNames: undefined, - fileNamesList: undefined, - fileInfos: sanitizedFileInfos, - // Ignore noEmit since that shouldnt be reason to emit the tsbuild info and presence of it in the buildinfo file does not matter - options: { ...readableBuildInfo.program.options, noEmit: undefined }, - exportedModulesMap: undefined, - affectedFilesPendingEmit: undefined, - latestChangedDtsFile: readableBuildInfo.program.latestChangedDtsFile ? "FakeFileName" : undefined, + buildInfo: JSON.stringify( + { + ...readableBuildInfo, + program: readableBuildInfo.program && { + ...readableBuildInfo.program, + fileNames: undefined, + fileNamesList: undefined, + fileInfos: sanitizedFileInfos, + // Ignore noEmit since that shouldnt be reason to emit the tsbuild info and presence of it in the buildinfo file does not matter + options: { ...readableBuildInfo.program.options, noEmit: undefined }, + exportedModulesMap: undefined, + affectedFilesPendingEmit: undefined, + latestChangedDtsFile: readableBuildInfo.program.latestChangedDtsFile ? "FakeFileName" : undefined, + }, + size: undefined, // Size doesnt need to be equal }, - size: undefined, // Size doesnt need to be equal - }, /*replacer*/ undefined, 2), + /*replacer*/ undefined, + 2, + ), readableBuildInfo, }; } @@ -457,9 +538,16 @@ export interface VerifyTscWithEditsInput extends TestTscCompile { * Verify non watch tsc invokcation after each edit */ export function verifyTsc({ - subScenario, fs, scenario, commandLineArgs, environmentVariables, - baselineSourceMap, modifyFs, baselineReadFileCalls, baselinePrograms, - edits + subScenario, + fs, + scenario, + commandLineArgs, + environmentVariables, + baselineSourceMap, + modifyFs, + baselineReadFileCalls, + baselinePrograms, + edits, }: VerifyTscWithEditsInput) { describe(`tsc ${commandLineArgs.join(" ")} ${scenario}:: ${subScenario}`, () => { let sys: TscCompileSystem; @@ -480,7 +568,7 @@ export function verifyTsc({ }); edits?.forEach(( { edit, caption, commandLineArgs: editCommandLineArgs }, - index + index, ) => { (editsSys || (editsSys = [])).push(testTscCompile({ scenario, @@ -513,10 +601,11 @@ export function verifyTsc({ }); return { file, - text: `currentDirectory:: ${sys.getCurrentDirectory()} useCaseSensitiveFileNames: ${sys.useCaseSensitiveFileNames}\r\n` + - texts.join("\r\n"), + text: + `currentDirectory:: ${sys.getCurrentDirectory()} useCaseSensitiveFileNames: ${sys.useCaseSensitiveFileNames}\r\n` + + texts.join("\r\n"), }; - } + }, })); if (edits?.length) { it("tsc invocation after edit and clean build correctness", () => { @@ -536,10 +625,9 @@ export function verifyTsc({ } Harness.Baseline.runBaseline( tscBaselineName(scenario, subScenario, commandLineArgs, /*isWatch*/ undefined, "-discrepancies"), - baselines ? baselines.join("\r\n") : null // eslint-disable-line no-null/no-null + baselines ? baselines.join("\r\n") : null, // eslint-disable-line no-null/no-null ); }); } }); } - diff --git a/src/testRunner/unittests/helpers/tscWatch.ts b/src/testRunner/unittests/helpers/tscWatch.ts index 4b8a3a6076866..e800f8562a42f 100644 --- a/src/testRunner/unittests/helpers/tscWatch.ts +++ b/src/testRunner/unittests/helpers/tscWatch.ts @@ -1,5 +1,9 @@ -import { patchHostForBuildInfoReadWrite } from "../../_namespaces/fakes"; -import { Baseline } from "../../_namespaces/Harness"; +import { + patchHostForBuildInfoReadWrite, +} from "../../_namespaces/fakes"; +import { + Baseline, +} from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; import { baselinePrograms, @@ -18,28 +22,34 @@ import { export const commonFile1: File = { path: "/a/b/commonFile1.ts", - content: "let x = 1" + content: "let x = 1", }; export const commonFile2: File = { path: "/a/b/commonFile2.ts", - content: "let y = 1" + content: "let y = 1", }; -export type WatchOrSolution = void | ts.SolutionBuilder | ts.WatchOfConfigFile | ts.WatchOfFilesAndCompilerOptions; +export type WatchOrSolution = + | void + | ts.SolutionBuilder + | ts.WatchOfConfigFile + | ts.WatchOfFilesAndCompilerOptions; export interface TscWatchCompileChange { caption: string; edit: (sys: TscWatchSystem) => void; timeouts: ( sys: TscWatchSystem, programs: readonly CommandLineProgram[], - watchOrSolution: WatchOrSolution + watchOrSolution: WatchOrSolution, ) => void; } export interface TscWatchCheckOptions { baselineSourceMap?: boolean; baselineDependencies?: boolean; } -export interface TscWatchCompileBase extends TscWatchCheckOptions { +export interface TscWatchCompileBase + extends TscWatchCheckOptions +{ scenario: string; subScenario: string; commandLineArgs: readonly string[]; @@ -60,9 +70,12 @@ function tscWatchCompile(input: TscWatchCompile) { it("tsc-watch:: Generates files matching the baseline", () => { const { sys, baseline, oldSnap } = createBaseline(input.sys()); const { - scenario, subScenario, - commandLineArgs, edits, - baselineSourceMap, baselineDependencies + scenario, + subScenario, + commandLineArgs, + edits, + baselineSourceMap, + baselineDependencies, } = input; if (!isWatch(commandLineArgs)) sys.exit = exitCode => sys.exitCode = exitCode; @@ -83,7 +96,7 @@ function tscWatchCompile(input: TscWatchCompile) { baselineSourceMap, baselineDependencies, edits, - watchOrSolution + watchOrSolution, }); }); } @@ -94,7 +107,10 @@ export interface TestServerHostWithTimeoutLogging { export type TscWatchSystem = TestServerHostTrackingWrittenFiles & TestServerHostWithTimeoutLogging; -function changeToTestServerHostWithTimeoutLogging(inputHost: TestServerHostTrackingWrittenFiles, baseline: string[]): TscWatchSystem { +function changeToTestServerHostWithTimeoutLogging( + inputHost: TestServerHostTrackingWrittenFiles, + baseline: string[], +): TscWatchSystem { const host = inputHost as TscWatchSystem; const originalRunQueuedTimeoutCallbacks = host.runQueuedTimeoutCallbacks; const originalRunQueuedImmediateCallbacks = host.runQueuedImmediateCallbacks; @@ -110,7 +126,13 @@ function changeToTestServerHostWithTimeoutLogging(inputHost: TestServerHostTrack function runQueuedTimeoutCallbacks(timeoutId?: number) { baseline.push(`Before running ${host.timeoutCallbacks.log()}`); - if (timeoutId !== undefined) baseline.push(`Invoking ${host.timeoutCallbacks.callbackType} callback:: timeoutId:: ${timeoutId}:: ${host.timeoutCallbacks.map[timeoutId].args[0]}`); + if (timeoutId !== undefined) { + baseline.push( + `Invoking ${host.timeoutCallbacks.callbackType} callback:: timeoutId:: ${timeoutId}:: ${ + host.timeoutCallbacks.map[timeoutId].args[0] + }`, + ); + } originalRunQueuedTimeoutCallbacks.call(host, timeoutId); baseline.push(`After running ${host.timeoutCallbacks.log()}`); } @@ -131,13 +153,18 @@ export interface BaselineBase { export interface Baseline extends BaselineBase, CommandLineCallbacks { } -export function createBaseline(system: TestServerHost, modifySystem?: (sys: TestServerHost, originalRead: TestServerHost["readFile"]) => void): Baseline { +export function createBaseline( + system: TestServerHost, + modifySystem?: (sys: TestServerHost, originalRead: TestServerHost["readFile"]) => void, +): Baseline { const originalRead = system.readFile; const initialSys = patchHostForBuildInfoReadWrite(system); modifySystem?.(initialSys, originalRead); const baseline: string[] = []; const sys = changeToTestServerHostWithTimeoutLogging(changeToHostTrackingWrittenFiles(initialSys), baseline); - baseline.push(`currentDirectory:: ${sys.getCurrentDirectory()} useCaseSensitiveFileNames: ${sys.useCaseSensitiveFileNames}`); + baseline.push( + `currentDirectory:: ${sys.getCurrentDirectory()} useCaseSensitiveFileNames: ${sys.useCaseSensitiveFileNames}`, + ); baseline.push("Input::"); sys.diff(baseline); const { cb, getPrograms } = commandLineCallbacks(sys); @@ -145,24 +172,29 @@ export function createBaseline(system: TestServerHost, modifySystem?: (sys: Test } export function createSolutionBuilderWithWatchHostForBaseline(sys: TestServerHost, cb: ts.ExecuteCommandLineCallbacks) { - const host = ts.createSolutionBuilderWithWatchHost(sys, + const host = ts.createSolutionBuilderWithWatchHost( + sys, /*createProgram*/ undefined, ts.createDiagnosticReporter(sys, /*pretty*/ true), ts.createBuilderStatusReporter(sys, /*pretty*/ true), - ts.createWatchStatusReporter(sys, /*pretty*/ true) + ts.createWatchStatusReporter(sys, /*pretty*/ true), ); host.afterProgramEmitAndDiagnostics = cb; host.afterEmitBundle = cb; return host; } -interface CreateWatchCompilerHostOfConfigFileForBaseline extends ts.CreateWatchCompilerHostOfConfigFileInput { - system: TestServerHost, +interface CreateWatchCompilerHostOfConfigFileForBaseline + extends ts.CreateWatchCompilerHostOfConfigFileInput +{ + system: TestServerHost; cb: ts.ExecuteCommandLineCallbacks; } -export function createWatchCompilerHostOfConfigFileForBaseline( - input: CreateWatchCompilerHostOfConfigFileForBaseline +export function createWatchCompilerHostOfConfigFileForBaseline< + T extends ts.BuilderProgram = ts.EmitAndSemanticDiagnosticsBuilderProgram, +>( + input: CreateWatchCompilerHostOfConfigFileForBaseline, ) { const host = ts.createWatchCompilerHostOfConfigFile({ ...input, @@ -173,12 +205,16 @@ export function createWatchCompilerHostOfConfigFileForBaseline extends ts.CreateWatchCompilerHostOfFilesAndCompilerOptionsInput { - system: TestServerHost, +interface CreateWatchCompilerHostOfFilesAndCompilerOptionsForBaseline + extends ts.CreateWatchCompilerHostOfFilesAndCompilerOptionsInput +{ + system: TestServerHost; cb: ts.ExecuteCommandLineCallbacks; } -export function createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline( - input: CreateWatchCompilerHostOfFilesAndCompilerOptionsForBaseline +export function createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline< + T extends ts.BuilderProgram = ts.EmitAndSemanticDiagnosticsBuilderProgram, +>( + input: CreateWatchCompilerHostOfFilesAndCompilerOptionsForBaseline, ) { const host = ts.createWatchCompilerHostOfFilesAndCompilerOptions({ ...input, @@ -189,7 +225,10 @@ export function createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline(host: ts.WatchCompilerHost, cb: ts.ExecuteCommandLineCallbacks) { +function updateWatchHostForBaseline( + host: ts.WatchCompilerHost, + cb: ts.ExecuteCommandLineCallbacks, +) { const emitFilesAndReportErrors = host.afterProgramCreate!; host.afterProgramCreate = builderProgram => { emitFilesAndReportErrors.call(host, builderProgram); @@ -198,7 +237,12 @@ function updateWatchHostForBaseline(host: ts.WatchC return host; } -export function applyEdit(sys: BaselineBase["sys"], baseline: BaselineBase["baseline"], edit: TscWatchCompileChange["edit"], caption?: TscWatchCompileChange["caption"]) { +export function applyEdit( + sys: BaselineBase["sys"], + baseline: BaselineBase["baseline"], + edit: TscWatchCompileChange["edit"], + caption?: TscWatchCompileChange["caption"], +) { const oldSnap = sys.snap(); baseline.push(`Change::${caption ? " " + caption : ""}`, ""); edit(sys); @@ -214,10 +258,17 @@ export interface RunWatchBaseline extends BaselineB watchOrSolution: WatchOrSolution; } export function runWatchBaseline({ - scenario, subScenario, commandLineArgs, - getPrograms, sys, baseline, oldSnap, - baselineSourceMap, baselineDependencies, - edits, watchOrSolution + scenario, + subScenario, + commandLineArgs, + getPrograms, + sys, + baseline, + oldSnap, + baselineSourceMap, + baselineDependencies, + edits, + watchOrSolution, }: RunWatchBaseline) { baseline.push(`${sys.getExecutingFilePath()} ${commandLineArgs.join(" ")}`); let programs = watchBaseline({ @@ -245,7 +296,10 @@ export function runWatchBaseline readonly CommandLineProgram[]; } -export function watchBaseline({ baseline, getPrograms, oldPrograms, sys, oldSnap, baselineSourceMap, baselineDependencies }: WatchBaseline) { +export function watchBaseline( + { baseline, getPrograms, oldPrograms, sys, oldSnap, baselineSourceMap, baselineDependencies }: WatchBaseline, +) { if (baselineSourceMap) generateSourceMapBaselineFiles(sys); sys.serializeOutput(baseline); const programs = baselinePrograms(baseline, getPrograms, oldPrograms, baselineDependencies); diff --git a/src/testRunner/unittests/helpers/tsserver.ts b/src/testRunner/unittests/helpers/tsserver.ts index 3a9b6c1e33505..e2188f417ce18 100644 --- a/src/testRunner/unittests/helpers/tsserver.ts +++ b/src/testRunner/unittests/helpers/tsserver.ts @@ -1,8 +1,14 @@ -import { incrementalVerifier } from "../../../harness/incrementalUtils"; +import { + incrementalVerifier, +} from "../../../harness/incrementalUtils"; import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; -import { ActionWatchTypingLocations } from "../../_namespaces/ts.server"; -import { ensureErrorFreeBuild } from "./solutionBuilder"; +import { + ActionWatchTypingLocations, +} from "../../_namespaces/ts.server"; +import { + ensureErrorFreeBuild, +} from "./solutionBuilder"; import { changeToHostTrackingWrittenFiles, createServerHost, @@ -34,15 +40,17 @@ export const customTypesMap = { "react": "react", "lodash": "lodash" } - }` + }`, }; function replaceAll(source: string, searchValue: string, replaceValue: string): string { - let result: string | undefined = - (source as string & { replaceAll: typeof source.replace }).replaceAll?.(searchValue, replaceValue); + let result: string | undefined = (source as string & { replaceAll: typeof source.replace; }).replaceAll?.( + searchValue, + replaceValue, + ); if (result !== undefined) { - return result; + return result; } result = ""; @@ -142,15 +150,27 @@ export function createLoggerWritingToConsole(host: TestServerHost): Logger { function sanitizeLog(s: string): string { s = s.replace(/Elapsed::?\s*\d+(?:\.\d+)?ms/g, "Elapsed:: *ms"); s = s.replace(/"updateGraphDurationMs":\s*\d+(?:\.\d+)?/g, `"updateGraphDurationMs": *`); - s = s.replace(/"createAutoImportProviderProgramDurationMs":\s*\d+(?:\.\d+)?/g, `"createAutoImportProviderProgramDurationMs": *`); + s = s.replace( + /"createAutoImportProviderProgramDurationMs":\s*\d+(?:\.\d+)?/g, + `"createAutoImportProviderProgramDurationMs": *`, + ); s = replaceAll(s, ts.version, "FakeVersion"); s = s.replace(/getCompletionData: Get current token: \d+(?:\.\d+)?/g, `getCompletionData: Get current token: *`); s = s.replace(/getCompletionData: Is inside comment: \d+(?:\.\d+)?/g, `getCompletionData: Is inside comment: *`); s = s.replace(/getCompletionData: Get previous token: \d+(?:\.\d+)?/g, `getCompletionData: Get previous token: *`); - s = s.replace(/getCompletionsAtPosition: isCompletionListBlocker: \d+(?:\.\d+)?/g, `getCompletionsAtPosition: isCompletionListBlocker: *`); + s = s.replace( + /getCompletionsAtPosition: isCompletionListBlocker: \d+(?:\.\d+)?/g, + `getCompletionsAtPosition: isCompletionListBlocker: *`, + ); s = s.replace(/getCompletionData: Semantic work: \d+(?:\.\d+)?/g, `getCompletionData: Semantic work: *`); - s = s.replace(/getCompletionsAtPosition: getCompletionEntriesFromSymbols: \d+(?:\.\d+)?/g, `getCompletionsAtPosition: getCompletionEntriesFromSymbols: *`); - s = s.replace(/forEachExternalModuleToImportFrom autoImportProvider: \d+(?:\.\d+)?/g, `forEachExternalModuleToImportFrom autoImportProvider: *`); + s = s.replace( + /getCompletionsAtPosition: getCompletionEntriesFromSymbols: \d+(?:\.\d+)?/g, + `getCompletionsAtPosition: getCompletionEntriesFromSymbols: *`, + ); + s = s.replace( + /forEachExternalModuleToImportFrom autoImportProvider: \d+(?:\.\d+)?/g, + `forEachExternalModuleToImportFrom autoImportProvider: *`, + ); s = s.replace(/getExportInfoMap: done in \d+(?:\.\d+)?/g, `getExportInfoMap: done in *`); s = s.replace(/collectAutoImports: \d+(?:\.\d+)?/g, `collectAutoImports: *`); s = s.replace(/continuePreviousIncompleteResponse: \d+(?:\.\d+)?/g, `continuePreviousIncompleteResponse: *`); @@ -162,7 +182,11 @@ function sanitizeLog(s: string): string { export function createLoggerWithInMemoryLogs(host: TestServerHost): Logger { const logger = createHasErrorMessageLogger(); const logs: string[] = []; - if (host) logs.push(`currentDirectory:: ${host.getCurrentDirectory()} useCaseSensitiveFileNames: ${host.useCaseSensitiveFileNames}`); + if (host) { + logs.push( + `currentDirectory:: ${host.getCurrentDirectory()} useCaseSensitiveFileNames: ${host.useCaseSensitiveFileNames}`, + ); + } return handleLoggerGroup({ ...logger, logs, @@ -174,13 +198,18 @@ export function createLoggerWithInMemoryLogs(host: TestServerHost): Logger { export function baselineTsserverLogs(scenario: string, subScenario: string, sessionOrService: { logger: Logger; }) { ts.Debug.assert(sessionOrService.logger.logs?.length); // Ensure caller used in memory logger - Harness.Baseline.runBaseline(`tsserver/${scenario}/${subScenario.split(" ").join("-")}.js`, sessionOrService.logger.logs.join("\r\n")); + Harness.Baseline.runBaseline( + `tsserver/${scenario}/${subScenario.split(" ").join("-")}.js`, + sessionOrService.logger.logs.join("\r\n"), + ); } export function appendAllScriptInfos(session: TestSession) { session.logger.log(""); session.logger.log(`ScriptInfos:`); - session.getProjectService().filenameToScriptInfo.forEach(info => session.logger.log(`path: ${info.path} fileName: ${info.fileName}`)); + session.getProjectService().filenameToScriptInfo.forEach(info => + session.logger.log(`path: ${info.path} fileName: ${info.fileName}`) + ); session.logger.log(""); } @@ -207,7 +236,11 @@ interface TypesRegistryFile { entries: ts.MapLike>; } -function loadTypesRegistryFile(typesRegistryFilePath: string, host: TestServerHost, log: ts.server.typingsInstaller.Log): Map> { +function loadTypesRegistryFile( + typesRegistryFilePath: string, + host: TestServerHost, + log: ts.server.typingsInstaller.Log, +): Map> { if (!host.fileExists(typesRegistryFilePath)) { if (log.isEnabled()) { log.writeLine(`Types registry file '${typesRegistryFilePath}' does not exist`); @@ -220,7 +253,11 @@ function loadTypesRegistryFile(typesRegistryFilePath: string, host: TestServerHo } catch (e) { if (log.isEnabled()) { - log.writeLine(`Error when loading types registry file '${typesRegistryFilePath}': ${(e as Error).message}, ${(e as Error).stack}`); + log.writeLine( + `Error when loading types registry file '${typesRegistryFilePath}': ${(e as Error).message}, ${ + (e as Error).stack + }`, + ); } return new Map>(); } @@ -228,7 +265,10 @@ function loadTypesRegistryFile(typesRegistryFilePath: string, host: TestServerHo const typesRegistryPackageName = "types-registry"; function getTypesRegistryFileLocation(globalTypingsCacheLocation: string): string { - return ts.combinePaths(ts.normalizeSlashes(globalTypingsCacheLocation), `node_modules/${typesRegistryPackageName}/index.json`); + return ts.combinePaths( + ts.normalizeSlashes(globalTypingsCacheLocation), + `node_modules/${typesRegistryPackageName}/index.json`, + ); } export class TestTypingsInstallerWorker extends ts.server.typingsInstaller.TypingsInstaller { @@ -245,7 +285,7 @@ export class TestTypingsInstallerWorker extends ts.server.typingsInstaller.Typin if (log?.isEnabled()) { patchHostTimeouts( changeToHostTrackingWrittenFiles(installTypingHost), - logger + logger, ); (installTypingHost as TestSessionAndServiceHost).baselineHost("TI:: Creating typing installer"); } @@ -267,20 +307,25 @@ export class TestTypingsInstallerWorker extends ts.server.typingsInstaller.Typin installTypingHost.ensureFileOrFolder({ path: getTypesRegistryFileLocation(globalTypingsCacheLocation), content: JSON.stringify( - createTypesRegistryFileContent(typesRegistry ? - ts.isString(typesRegistry) ? - [typesRegistry] : - typesRegistry : - ts.emptyArray + createTypesRegistryFileContent( + typesRegistry + ? ts.isString(typesRegistry) + ? [typesRegistry] + : typesRegistry + : ts.emptyArray, ), undefined, " ", - ) + ), }); if (this.log.isEnabled()) { this.log.writeLine(`TI:: Updated ${typesRegistryPackageName} npm package`); } - this.typesRegistry = loadTypesRegistryFile(getTypesRegistryFileLocation(globalTypingsCacheLocation), installTypingHost, this.log); + this.typesRegistry = loadTypesRegistryFile( + getTypesRegistryFileLocation(globalTypingsCacheLocation), + installTypingHost, + this.log, + ); if (this.log.isEnabled()) { (installTypingHost as TestSessionAndServiceHost).baselineHost("TI:: typing installer creation complete"); } @@ -293,7 +338,9 @@ export class TestTypingsInstallerWorker extends ts.server.typingsInstaller.Typin this.postExecActions = []; for (const action of actionsToRun) { if (this.log.isEnabled()) { - this.log.writeLine(`#${action.requestId} with arguments'${JSON.stringify(action.packageNames)}':: ${action.success}`); + this.log.writeLine( + `#${action.requestId} with arguments'${JSON.stringify(action.packageNames)}':: ${action.success}`, + ); } action.callback(action.success); } @@ -307,7 +354,12 @@ export class TestTypingsInstallerWorker extends ts.server.typingsInstaller.Typin return this.installTypingHost; } - installWorker(requestId: number, packageNames: string[], _cwd: string, cb: ts.server.typingsInstaller.RequestCompletedAction): void { + installWorker( + requestId: number, + packageNames: string[], + _cwd: string, + cb: ts.server.typingsInstaller.RequestCompletedAction, + ): void { if (this.log.isEnabled()) { this.log.writeLine(`#${requestId} with arguments'${JSON.stringify(packageNames)}'.`); } @@ -322,24 +374,40 @@ export class TestTypingsInstallerWorker extends ts.server.typingsInstaller.Typin else this.projectService.watchTypingLocations(response); } - enqueueInstallTypingsRequest(project: ts.server.Project, typeAcquisition: ts.TypeAcquisition, unresolvedImports: ts.SortedReadonlyArray) { - const request = ts.server.createInstallTypingsRequest(project, typeAcquisition, unresolvedImports, this.globalTypingsCacheLocation); + enqueueInstallTypingsRequest( + project: ts.server.Project, + typeAcquisition: ts.TypeAcquisition, + unresolvedImports: ts.SortedReadonlyArray, + ) { + const request = ts.server.createInstallTypingsRequest( + project, + typeAcquisition, + unresolvedImports, + this.globalTypingsCacheLocation, + ); this.install(request); } - addPostExecAction(stdout: string | string[], requestId: number, packageNames: string[], cb: ts.server.typingsInstaller.RequestCompletedAction) { + addPostExecAction( + stdout: string | string[], + requestId: number, + packageNames: string[], + cb: ts.server.typingsInstaller.RequestCompletedAction, + ) { const out = ts.isString(stdout) ? stdout : createNpmPackageJsonString(stdout); const action: PostExecAction = { success: !!out, requestId, packageNames, - callback: cb + callback: cb, }; this.postExecActions.push(action); } } -export class TestTypingsInstaller implements ts.server.ITypingsInstaller { +export class TestTypingsInstaller + implements ts.server.ITypingsInstaller +{ protected projectService!: ts.server.ProjectService; public installer!: T; constructor( @@ -363,13 +431,29 @@ export class TestTypingsInstaller) { + enqueueInstallTypingsRequest( + project: ts.server.Project, + typeAcquisition: ts.TypeAcquisition, + unresolvedImports: ts.SortedReadonlyArray, + ) { if (!this.installer) { if (this.workerConstructor) { - this.installer ??= new this.workerConstructor(this.globalTypingsCacheLocation, this.throttleLimit, this.installTypingHost, this.logger, this.typesRegistry); + this.installer ??= new this.workerConstructor( + this.globalTypingsCacheLocation, + this.throttleLimit, + this.installTypingHost, + this.logger, + this.typesRegistry, + ); } else { - this.installer = new TestTypingsInstallerWorker(this.globalTypingsCacheLocation, this.throttleLimit, this.installTypingHost, this.logger, this.typesRegistry) as T; + this.installer = new TestTypingsInstallerWorker( + this.globalTypingsCacheLocation, + this.throttleLimit, + this.installTypingHost, + this.logger, + this.typesRegistry, + ) as T; } this.installer.attach(this.projectService); } @@ -395,7 +479,7 @@ function createTypesRegistryFileContent(list: readonly string[]): TypesRegistryF "ts2.4": "1.3.0", "ts2.5": "1.3.0", "ts2.6": "1.3.0", - "ts2.7": "1.3.0" + "ts2.7": "1.3.0", }; const entries: ts.MapLike> = {}; for (const l of list) { @@ -459,7 +543,13 @@ function patchHostTimeouts( function runQueuedTimeoutCallbacks(timeoutId?: number) { host.baselineHost(`Before running ${host.timeoutCallbacks.log()}`); - if (timeoutId !== undefined) logger.log(`Invoking ${host.timeoutCallbacks.callbackType} callback:: timeoutId:: ${timeoutId}:: ${host.timeoutCallbacks.map[timeoutId].args[0]}`); + if (timeoutId !== undefined) { + logger.log( + `Invoking ${host.timeoutCallbacks.callbackType} callback:: timeoutId:: ${timeoutId}:: ${ + host.timeoutCallbacks.map[timeoutId].args[0] + }`, + ); + } originalRunQueuedTimeoutCallbacks.call(host, timeoutId); host.baselineHost(`After running ${host.timeoutCallbacks.log()}`); } @@ -494,10 +584,13 @@ export class TestSession extends ts.server.Session { constructor(opts: TestSessionOptions) { super(opts); this.logger = opts.logger; - ts.Debug.assert(opts.allowNonBaseliningLogger || this.logger.hasLevel(ts.server.LogLevel.verbose), "Use Baselining logger and baseline tsserver log or create using allowNonBaseliningLogger"); + ts.Debug.assert( + opts.allowNonBaseliningLogger || this.logger.hasLevel(ts.server.LogLevel.verbose), + "Use Baselining logger and baseline tsserver log or create using allowNonBaseliningLogger", + ); this.testhost = patchHostTimeouts( changeToHostTrackingWrittenFiles(this.host as TestServerHost), - this.logger + this.logger, ); } @@ -520,7 +613,18 @@ export class TestSession extends ts.server.Session { } const response = super.executeCommand(request); if (this.logger.hasLevel(ts.server.LogLevel.verbose)) { - this.logger.info(`response:${ts.server.indent(JSON.stringify(response.response === ts.getSupportedCodeFixes() ? { ...response, response: "ts.getSupportedCodeFixes()" } : response, undefined, 2))}`); + this.logger.info( + `response:${ + ts.server.indent( + JSON.stringify( + response.response === ts.getSupportedCodeFixes() + ? { ...response, response: "ts.getSupportedCodeFixes()" } : response, + undefined, + 2, + ), + ) + }`, + ); this.testhost.baselineHost("After request"); } return response; @@ -538,7 +642,12 @@ export class TestSession extends ts.server.Session { export function createSession(host: TestServerHost, opts: Partial = {}) { const logger = opts.logger || createHasErrorMessageLogger(); if (opts.typingsInstaller === undefined) { - opts.typingsInstaller = new TestTypingsInstaller(host.getHostSpecificPath("/a/data/"), /*throttleLimit*/ 5, host, logger); + opts.typingsInstaller = new TestTypingsInstaller( + host.getHostSpecificPath("/a/data/"), + /*throttleLimit*/ 5, + host, + logger, + ); } if (opts.eventHandler !== undefined) { @@ -581,7 +690,13 @@ export function createSessionWithCustomEventHandler(host: TestServerHost, opts?: break; // Map diagnostics case ts.server.ConfigFileDiagEvent: - data = { ...data, diagnostics: ts.map(event.data.diagnostics, diagnostic => ts.server.formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ true)) }; + data = { + ...data, + diagnostics: ts.map( + event.data.diagnostics, + diagnostic => ts.server.formatDiagnosticToProtocol(diagnostic, /*includeFileName*/ true), + ), + }; break; default: ts.Debug.assertNever(event); @@ -597,8 +712,14 @@ export interface TestProjectServiceOptions extends ts.server.ProjectServiceOptio export class TestProjectService extends ts.server.ProjectService { public testhost: TestSessionAndServiceHost; - constructor(host: TestServerHost, public override logger: Logger, cancellationToken: ts.HostCancellationToken, useSingleInferredProject: boolean, - typingsInstaller: ts.server.ITypingsInstaller, opts: Partial = {}) { + constructor( + host: TestServerHost, + public override logger: Logger, + cancellationToken: ts.HostCancellationToken, + useSingleInferredProject: boolean, + typingsInstaller: ts.server.ITypingsInstaller, + opts: Partial = {}, + ) { super({ host, logger, @@ -609,12 +730,15 @@ export class TestProjectService extends ts.server.ProjectService { typingsInstaller, typesMapLocation: customTypesMap.path, incrementalVerifier, - ...opts + ...opts, }); - ts.Debug.assert(opts.allowNonBaseliningLogger || this.logger.hasLevel(ts.server.LogLevel.verbose), "Use Baselining logger and baseline tsserver log or create using allowNonBaseliningLogger"); + ts.Debug.assert( + opts.allowNonBaseliningLogger || this.logger.hasLevel(ts.server.LogLevel.verbose), + "Use Baselining logger and baseline tsserver log or create using allowNonBaseliningLogger", + ); this.testhost = patchHostTimeouts( changeToHostTrackingWrittenFiles(this.host as TestServerHost), - this.logger + this.logger, ); if (logger.hasLevel(ts.server.LogLevel.verbose)) this.testhost.baselineHost("Creating project service"); } @@ -623,11 +747,23 @@ export class TestProjectService extends ts.server.ProjectService { export function createProjectService(host: TestServerHost, options?: Partial) { const cancellationToken = options?.cancellationToken || ts.server.nullCancellationToken; const logger = options?.logger || createHasErrorMessageLogger(); - const useSingleInferredProject = options?.useSingleInferredProject !== undefined ? options.useSingleInferredProject : false; - return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, options?.typingsInstaller || ts.server.nullTypingsInstaller, options); + const useSingleInferredProject = options?.useSingleInferredProject !== undefined ? options.useSingleInferredProject + : false; + return new TestProjectService( + host, + logger, + cancellationToken, + useSingleInferredProject, + options?.typingsInstaller || ts.server.nullTypingsInstaller, + options, + ); } -export function protocolLocationFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): ts.server.protocol.Location { +export function protocolLocationFromSubstring( + str: string, + substring: string, + options?: SpanFromSubstringOptions, +): ts.server.protocol.Location { const start = nthIndexOf(str, substring, options ? options.index : 0); ts.Debug.assert(start !== -1); return protocolToLocation(str)(start); @@ -641,7 +777,11 @@ export function protocolToLocation(text: string): (pos: number) => ts.server.pro }; } -export function protocolTextSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): ts.server.protocol.TextSpan { +export function protocolTextSpanFromSubstring( + str: string, + substring: string, + options?: SpanFromSubstringOptions, +): ts.server.protocol.TextSpan { const span = textSpanFromSubstring(str, substring, options); const toLocation = protocolToLocation(str); return { start: toLocation(span.start), end: toLocation(ts.textSpanEnd(span)) }; @@ -653,7 +793,11 @@ export function textSpanFromSubstring(str: string, substring: string, options?: return ts.createTextSpan(start, substring.length); } -export function protocolFileLocationFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): ts.server.protocol.FileLocationRequestArgs { +export function protocolFileLocationFromSubstring( + file: File, + substring: string, + options?: SpanFromSubstringOptions, +): ts.server.protocol.FileLocationRequestArgs { return { file: file.path, ...protocolLocationFromSubstring(file.content, substring, options) }; } @@ -695,7 +839,11 @@ export class TestServerCancellationToken implements ts.server.ServerCancellation } resetRequest(requestId: number) { - this.logger.log(`TestServerCancellationToken:: resetRequest:: ${requestId} is ${requestId === this.currentId ? "as expected" : `expected to be ${this.currentId}`}`); + this.logger.log( + `TestServerCancellationToken:: resetRequest:: ${requestId} is ${ + requestId === this.currentId ? "as expected" : `expected to be ${this.currentId}` + }`, + ); assert.equal(requestId, this.currentId, "unexpected request id in cancellation"); this.currentId = undefined; } @@ -705,7 +853,8 @@ export class TestServerCancellationToken implements ts.server.ServerCancellation // If the request id is the request to cancel and isCancellationRequestedCount // has been met then cancel the request. Ex: cancel the request if it is a // nav bar request & isCancellationRequested() has already been called three times. - const result = this.requestToCancel === this.currentId && this.isCancellationRequestedCount >= this.cancelAfterRequest; + const result = this.requestToCancel === this.currentId + && this.isCancellationRequestedCount >= this.cancelAfterRequest; if (result) this.logger.log(`TestServerCancellationToken:: Cancellation is requested`); return result; } @@ -717,25 +866,28 @@ export class TestServerCancellationToken implements ts.server.ServerCancellation } } -export function openFilesForSession(files: readonly (string | File | { - readonly file: File | string, - readonly projectRootPath?: string, - content?: string, - scriptKindName?: ts.server.protocol.ScriptKindName, -})[], session: TestSession): void { +export function openFilesForSession( + files: readonly (string | File | { + readonly file: File | string; + readonly projectRootPath?: string; + content?: string; + scriptKindName?: ts.server.protocol.ScriptKindName; + })[], + session: TestSession, +): void { for (const file of files) { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Open, - arguments: ts.isString(file) ? - { file } : - "file" in file ? // eslint-disable-line local/no-in-operator - { - file: typeof file.file === "string" ? file.file : file.file.path, - projectRootPath: file.projectRootPath, - fileContent: file.content, - scriptKindName: file.scriptKindName, - } : - { file: file.path } + arguments: ts.isString(file) + ? { file } + : "file" in file // eslint-disable-line local/no-in-operator + ? { + file: typeof file.file === "string" ? file.file : file.file.path, + projectRootPath: file.projectRootPath, + fileContent: file.content, + scriptKindName: file.scriptKindName, + } + : { file: file.path }, }); } } @@ -744,7 +896,7 @@ export function closeFilesForSession(files: readonly (File | string)[], session: for (const file of files) { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Close, - arguments: { file: ts.isString(file) ? file : file.path } + arguments: { file: ts.isString(file) ? file : file.path }, }); } } @@ -752,30 +904,37 @@ export function closeFilesForSession(files: readonly (File | string)[], session: export function openExternalProjectForSession(project: ts.server.protocol.ExternalProject, session: TestSession) { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.OpenExternalProject, - arguments: project + arguments: project, }); } export function openExternalProjectsForSession(projects: ts.server.protocol.ExternalProject[], session: TestSession) { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.OpenExternalProjects, - arguments: { projects } + arguments: { projects }, }); } export function setCompilerOptionsForInferredProjectsRequestForSession( - options: ts.server.protocol.InferredProjectCompilerOptions | ts.server.protocol.SetCompilerOptionsForInferredProjectsArgs, - session: TestSession + options: + | ts.server.protocol.InferredProjectCompilerOptions + | ts.server.protocol.SetCompilerOptionsForInferredProjectsArgs, + session: TestSession, ) { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompilerOptionsForInferredProjects, - arguments: "options" in options ? // eslint-disable-line local/no-in-operator - options as ts.server.protocol.SetCompilerOptionsForInferredProjectsArgs : - { options } + arguments: "options" in options // eslint-disable-line local/no-in-operator + ? options as ts.server.protocol.SetCompilerOptionsForInferredProjectsArgs + : { options }, }); } -export function logDiagnostics(sessionOrService: TestSession | TestProjectService, diagnosticsType: string, project: ts.server.Project, diagnostics: readonly ts.Diagnostic[]) { +export function logDiagnostics( + sessionOrService: TestSession | TestProjectService, + diagnosticsType: string, + project: ts.server.Project, + diagnostics: readonly ts.Diagnostic[], +) { sessionOrService.logger.info(`${diagnosticsType}:: ${diagnostics.length}`); diagnostics.forEach(d => sessionOrService.logger.info(ts.formatDiagnostic(d, project))); } @@ -791,12 +950,15 @@ export function verifyGetErrRequest(request: VerifyGetErrRequest) { const { session, files } = request; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Geterr, - arguments: { delay: 0, files: files.map(filePath) } + arguments: { delay: 0, files: files.map(filePath) }, }); checkAllErrors(request); } -interface SkipErrors { semantic?: true; suggestion?: true } +interface SkipErrors { + semantic?: true; + suggestion?: true; +} export interface CheckAllErrors extends VerifyGetErrRequestBase { files: readonly any[]; skip?: readonly (SkipErrors | undefined)[]; @@ -804,7 +966,9 @@ export interface CheckAllErrors extends VerifyGetErrRequestBase { function checkAllErrors({ session, existingTimeouts, files, skip }: CheckAllErrors) { ts.Debug.assert(session.logger.logs?.length); for (let i = 0; i < files.length; i++) { - session.testhost.runQueuedTimeoutCallbacks(existingTimeouts ? session.testhost.getNextTimeoutId() - 1 : undefined); + session.testhost.runQueuedTimeoutCallbacks( + existingTimeouts ? session.testhost.getNextTimeoutId() - 1 : undefined, + ); if (!skip?.[i]?.semantic) session.testhost.runQueuedImmediateCallbacks(); if (!skip?.[i]?.suggestion) session.testhost.runQueuedImmediateCallbacks(); } @@ -814,7 +978,7 @@ function filePath(file: string | File) { return ts.isString(file) ? file : file.path; } -function verifyErrorsUsingGeterr({scenario, subScenario, allFiles, openFiles, getErrRequest }: VerifyGetErrScenario) { +function verifyErrorsUsingGeterr({ scenario, subScenario, allFiles, openFiles, getErrRequest }: VerifyGetErrScenario) { it("verifies the errors in open file", () => { const host = createServerHost([...allFiles(), libFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -825,7 +989,9 @@ function verifyErrorsUsingGeterr({scenario, subScenario, allFiles, openFiles, ge }); } -function verifyErrorsUsingGeterrForProject({ scenario, subScenario, allFiles, openFiles, getErrForProjectRequest }: VerifyGetErrScenario) { +function verifyErrorsUsingGeterrForProject( + { scenario, subScenario, allFiles, openFiles, getErrForProjectRequest }: VerifyGetErrScenario, +) { it("verifies the errors in projects", () => { const host = createServerHost([...allFiles(), libFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -834,7 +1000,7 @@ function verifyErrorsUsingGeterrForProject({ scenario, subScenario, allFiles, op for (const expected of getErrForProjectRequest()) { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GeterrForProject, - arguments: { delay: 0, file: filePath(expected.project) } + arguments: { delay: 0, file: filePath(expected.project) }, }); checkAllErrors({ session, files: expected.files }); } @@ -842,7 +1008,9 @@ function verifyErrorsUsingGeterrForProject({ scenario, subScenario, allFiles, op }); } -function verifyErrorsUsingSyncMethods({ scenario, subScenario, allFiles, openFiles, syncDiagnostics }: VerifyGetErrScenario) { +function verifyErrorsUsingSyncMethods( + { scenario, subScenario, allFiles, openFiles, syncDiagnostics }: VerifyGetErrScenario, +) { it("verifies the errors using sync commands", () => { const host = createServerHost([...allFiles(), libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -851,15 +1019,15 @@ function verifyErrorsUsingSyncMethods({ scenario, subScenario, allFiles, openFil const reqArgs = { file: filePath(file), projectFileName: project && filePath(project) }; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SyntacticDiagnosticsSync, - arguments: reqArgs + arguments: reqArgs, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, - arguments: reqArgs + arguments: reqArgs, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SuggestionDiagnosticsSync, - arguments: reqArgs + arguments: reqArgs, }); } baselineTsserverLogs(scenario, `${subScenario} gerErr with sync commands`, session); @@ -902,9 +1070,17 @@ export function createHostWithSolutionBuild(files: readonly FileOrFolderOrSymLin } export function logInferredProjectsOrphanStatus(projectService: ts.server.ProjectService) { - projectService.inferredProjects.forEach(inferredProject => (projectService.logger as Logger).log(`Inferred project: ${inferredProject.projectName} isOrphan:: ${inferredProject.isOrphan()} isClosed: ${inferredProject.isClosed()}`)); + projectService.inferredProjects.forEach(inferredProject => + (projectService.logger as Logger).log( + `Inferred project: ${inferredProject.projectName} isOrphan:: ${inferredProject.isOrphan()} isClosed: ${inferredProject.isClosed()}`, + ) + ); } export function logConfiguredProjectsHasOpenRefStatus(projectService: ts.server.ProjectService) { - projectService.configuredProjects.forEach(configuredProject => (projectService.logger as Logger).log(`Configured project: ${configuredProject.projectName} hasOpenRef:: ${configuredProject.hasOpenRef()} isClosed: ${configuredProject.isClosed()}`)); + projectService.configuredProjects.forEach(configuredProject => + (projectService.logger as Logger).log( + `Configured project: ${configuredProject.projectName} hasOpenRef:: ${configuredProject.hasOpenRef()} isClosed: ${configuredProject.isClosed()}`, + ) + ); } diff --git a/src/testRunner/unittests/helpers/vfs.ts b/src/testRunner/unittests/helpers/vfs.ts index df8fc06f3c1f3..f6303e5ff4402 100644 --- a/src/testRunner/unittests/helpers/vfs.ts +++ b/src/testRunner/unittests/helpers/vfs.ts @@ -1,8 +1,12 @@ import * as Harness from "../../_namespaces/Harness"; -import { getDirectoryPath } from "../../_namespaces/ts"; +import { + getDirectoryPath, +} from "../../_namespaces/ts"; import * as vfs from "../../_namespaces/vfs"; import * as vpath from "../../_namespaces/vpath"; -import { libContent } from "./contents"; +import { + libContent, +} from "./contents"; export interface FsOptions { libContentToAppend?: string; @@ -12,9 +16,9 @@ export interface FsOptions { export type FsOptionsOrLibContentsToAppend = FsOptions | string; function valueOfFsOptions(options: FsOptionsOrLibContentsToAppend | undefined, key: keyof FsOptions) { - return typeof options === "string" ? - key === "libContentToAppend" ? options : undefined : - options?.[key]; + return typeof options === "string" + ? key === "libContentToAppend" ? options : undefined + : options?.[key]; } /** @@ -22,11 +26,11 @@ function valueOfFsOptions(options: FsOptionsOrLibContentsToAppend | undefined, k */ export function loadProjectFromDisk( root: string, - options?: FsOptionsOrLibContentsToAppend + options?: FsOptionsOrLibContentsToAppend, ): vfs.FileSystem { const resolver = vfs.createResolver(Harness.IO); return loadProjectFromFiles({ - ["/src"]: new vfs.Mount(vpath.resolve(Harness.IO.getWorkspaceRoot(), root), resolver) + ["/src"]: new vfs.Mount(vpath.resolve(Harness.IO.getWorkspaceRoot(), root), resolver), }, options); } @@ -46,7 +50,10 @@ export function loadProjectFromFiles( }); const libContentToAppend = valueOfFsOptions(options, "libContentToAppend"); fs.mkdirpSync(defaultLibLocation); - fs.writeFileSync(`${defaultLibLocation}/lib.d.ts`, libContentToAppend ? `${libContent}${libContentToAppend}` : libContent); + fs.writeFileSync( + `${defaultLibLocation}/lib.d.ts`, + libContentToAppend ? `${libContent}${libContentToAppend}` : libContent, + ); fs.makeReadonly(); return fs; } @@ -84,13 +91,21 @@ export function enableStrict(fs: vfs.FileSystem, path: string) { } export function addTestPrologue(fs: vfs.FileSystem, path: string, prologue: string) { - prependText(fs, path, `${prologue} -`); + prependText( + fs, + path, + `${prologue} +`, + ); } export function addShebang(fs: vfs.FileSystem, project: string, file: string) { - prependText(fs, `src/${project}/${file}.ts`, `#!someshebang ${project} ${file} -`); + prependText( + fs, + `src/${project}/${file}.ts`, + `#!someshebang ${project} ${file} +`, + ); } export function restContent(project: string, file: string) { @@ -121,13 +136,21 @@ export function changeStubToRest(fs: vfs.FileSystem, project: string, file: stri export function addSpread(fs: vfs.FileSystem, project: string, file: string) { const path = `src/${project}/${file}.ts`; const content = fs.readFileSync(path, "utf8"); - fs.writeFileSync(path, `${content} + fs.writeFileSync( + path, + `${content} function ${project}${file}Spread(...b: number[]) { } const ${project}${file}_ar = [20, 30]; -${project}${file}Spread(10, ...${project}${file}_ar);`); +${project}${file}Spread(10, ...${project}${file}_ar);`, + ); - replaceText(fs, `src/${project}/tsconfig.json`, `"strict": false,`, `"strict": false, - "downlevelIteration": true,`); + replaceText( + fs, + `src/${project}/tsconfig.json`, + `"strict": false,`, + `"strict": false, + "downlevelIteration": true,`, + ); } export function getTripleSlashRef(project: string) { @@ -136,7 +159,11 @@ export function getTripleSlashRef(project: string) { export function addTripleSlashRef(fs: vfs.FileSystem, project: string, file: string) { fs.writeFileSync(getTripleSlashRef(project), `declare class ${project}${file} { }`); - prependText(fs, `src/${project}/${file}.ts`, `/// + prependText( + fs, + `src/${project}/${file}.ts`, + `/// const ${file}Const = new ${project}${file}(); -`); +`, + ); } diff --git a/src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts b/src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts index 5702e3bca76ee..504a8c6fd0b55 100644 --- a/src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts +++ b/src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts @@ -44,7 +44,9 @@ import { sys, toPath, } from "../../_namespaces/ts"; -import { timeIncrements } from "../../_namespaces/vfs"; +import { + timeIncrements, +} from "../../_namespaces/vfs"; export const libFile: File = { path: "/a/lib/lib.d.ts", @@ -58,7 +60,7 @@ interface Number { toExponential: any; } interface Object {} interface RegExp {} interface String { charAt: any; } -interface Array { length: number; [n: number]: T; }` +interface Array { length: number; [n: number]: T; }`, }; function getExecutingFilePathFromLibFile(): string { @@ -77,11 +79,17 @@ export interface TestServerHostCreationParameters { inodeWatching?: boolean; } -export function createWatchedSystem(fileOrFolderList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], params?: TestServerHostCreationParameters): TestServerHost { +export function createWatchedSystem( + fileOrFolderList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], + params?: TestServerHostCreationParameters, +): TestServerHost { return new TestServerHost(fileOrFolderList, params); } -export function createServerHost(fileOrFolderList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], params?: TestServerHostCreationParameters): TestServerHost { +export function createServerHost( + fileOrFolderList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], + params?: TestServerHostCreationParameters, +): TestServerHost { const host = new TestServerHost(fileOrFolderList, params); // Just like sys, patch the host to use writeFile patchWriteFileEnsuringDirectory(host); @@ -197,7 +205,8 @@ class Callbacks { const { args } = this.map[Number(timeoutId)]; details.push(`${timeoutId}: ${args[0]}`); } - return `${this.callbackType} callback:: count: ${details.length}` + (details.length ? "\r\n" + details.join("\r\n") : ""); + return `${this.callbackType} callback:: count: ${details.length}` + + (details.length ? "\r\n" + details.join("\r\n") : ""); } private invokeCallback(timeoutId: number) { @@ -258,7 +267,7 @@ export enum Tsc_WatchFile { export enum Tsc_WatchDirectory { WatchFile = "RecursiveDirectoryUsingFsWatchFile", NonRecursiveWatchDirectory = "RecursiveDirectoryUsingNonRecursiveWatchDirectory", - DynamicPolling = "RecursiveDirectoryUsingDynamicPriorityPolling" + DynamicPolling = "RecursiveDirectoryUsingDynamicPriorityPolling", } export interface TestServerHostOptions { @@ -303,11 +312,17 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, constructor( fileOrFolderorSymLinkList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[], { - useCaseSensitiveFileNames, executingFilePath, currentDirectory, - newLine, windowsStyleRoot, environmentVariables, - runWithoutRecursiveWatches, runWithFallbackPolling, + useCaseSensitiveFileNames, + executingFilePath, + currentDirectory, + newLine, + windowsStyleRoot, + environmentVariables, + runWithoutRecursiveWatches, + runWithFallbackPolling, inodeWatching, - }: TestServerHostCreationParameters = {}) { + }: TestServerHostCreationParameters = {}, + ) { this.useCaseSensitiveFileNames = !!useCaseSensitiveFileNames; this.newLine = newLine || "\n"; this.windowsStyleRoot = windowsStyleRoot; @@ -395,10 +410,13 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, private reloadFS(fileOrFolderOrSymLinkList: FileOrFolderOrSymLinkMap | readonly FileOrFolderOrSymLink[]) { Debug.assert(this.fs.size === 0); if (isArray(fileOrFolderOrSymLinkList)) { - fileOrFolderOrSymLinkList.forEach(f => this.ensureFileOrFolder(!this.windowsStyleRoot ? - f : - { ...f, path: this.getHostSpecificPath(f.path) } - )); + fileOrFolderOrSymLinkList.forEach(f => + this.ensureFileOrFolder( + !this.windowsStyleRoot + ? f + : { ...f, path: this.getHostSpecificPath(f.path) }, + ) + ); } else { for (const key in fileOrFolderOrSymLinkList) { @@ -427,7 +445,12 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, if (options && options.invokeFileDeleteCreateAsPartInsteadOfChange) { this.removeFileOrFolder(currentEntry, /*isRenaming*/ false, options); - this.ensureFileOrFolder({ path: filePath, content }, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ undefined, /*ignoreParentWatch*/ undefined, options); + this.ensureFileOrFolder( + { path: filePath, content }, + /*ignoreWatchInvokedWithTriggerAsFileCreate*/ undefined, + /*ignoreParentWatch*/ undefined, + options, + ); } else { currentEntry.content = content; @@ -436,11 +459,28 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) { const directoryFullPath = getDirectoryPath(currentEntry.fullPath); this.invokeFileWatcher(directoryFullPath, FileWatcherEventKind.Changed, currentEntry.modifiedTime); - this.invokeFsWatchesCallbacks(directoryFullPath, "rename", currentEntry.modifiedTime, currentEntry.fullPath, options.useTildeAsSuffixInRenameEventFileName); - this.invokeRecursiveFsWatches(directoryFullPath, "rename", currentEntry.modifiedTime, currentEntry.fullPath, options.useTildeAsSuffixInRenameEventFileName); + this.invokeFsWatchesCallbacks( + directoryFullPath, + "rename", + currentEntry.modifiedTime, + currentEntry.fullPath, + options.useTildeAsSuffixInRenameEventFileName, + ); + this.invokeRecursiveFsWatches( + directoryFullPath, + "rename", + currentEntry.modifiedTime, + currentEntry.fullPath, + options.useTildeAsSuffixInRenameEventFileName, + ); } else { - this.invokeFileAndFsWatches(currentEntry.fullPath, FileWatcherEventKind.Changed, currentEntry.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName); + this.invokeFileAndFsWatches( + currentEntry.fullPath, + FileWatcherEventKind.Changed, + currentEntry.modifiedTime, + options?.useTildeAsSuffixInRenameEventFileName, + ); } } } @@ -507,7 +547,12 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, } } - ensureFileOrFolder(fileOrDirectoryOrSymLink: FileOrFolderOrSymLink, ignoreWatchInvokedWithTriggerAsFileCreate?: boolean, ignoreParentWatch?: boolean, options?: Partial) { + ensureFileOrFolder( + fileOrDirectoryOrSymLink: FileOrFolderOrSymLink, + ignoreWatchInvokedWithTriggerAsFileCreate?: boolean, + ignoreParentWatch?: boolean, + options?: Partial, + ) { if (isFile(fileOrDirectoryOrSymLink)) { const file = this.toFsFile(fileOrDirectoryOrSymLink); // file may already exist when updating existing type declaration file @@ -529,7 +574,11 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, } } - private ensureFolder(fullPath: string, ignoreWatch: boolean | undefined, options: Partial | undefined): FsFolder { + private ensureFolder( + fullPath: string, + ignoreWatch: boolean | undefined, + options: Partial | undefined, + ): FsFolder { const path = this.toPath(fullPath); let folder = this.fs.get(path) as FsFolder; if (!folder) { @@ -551,9 +600,18 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, return folder; } - private addFileOrFolderInFolder(folder: FsFolder, fileOrDirectory: FsFile | FsFolder | FsSymLink, ignoreWatch?: boolean, options?: Partial) { + private addFileOrFolderInFolder( + folder: FsFolder, + fileOrDirectory: FsFile | FsFolder | FsSymLink, + ignoreWatch?: boolean, + options?: Partial, + ) { if (!this.fs.has(fileOrDirectory.path)) { - insertSorted(folder.entries, fileOrDirectory, (a, b) => compareStringsCaseSensitive(getBaseFileName(a.path), getBaseFileName(b.path))); + insertSorted( + folder.entries, + fileOrDirectory, + (a, b) => compareStringsCaseSensitive(getBaseFileName(a.path), getBaseFileName(b.path)), + ); } folder.modifiedTime = this.now(); this.fs.set(fileOrDirectory.path, fileOrDirectory); @@ -564,12 +622,26 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, } const inodeWatching = this.inodeWatching; if (options?.skipInodeCheckOnCreate) this.inodeWatching = false; - this.invokeFileAndFsWatches(fileOrDirectory.fullPath, FileWatcherEventKind.Created, fileOrDirectory.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName); - this.invokeFileAndFsWatches(folder.fullPath, FileWatcherEventKind.Changed, fileOrDirectory.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName); + this.invokeFileAndFsWatches( + fileOrDirectory.fullPath, + FileWatcherEventKind.Created, + fileOrDirectory.modifiedTime, + options?.useTildeAsSuffixInRenameEventFileName, + ); + this.invokeFileAndFsWatches( + folder.fullPath, + FileWatcherEventKind.Changed, + fileOrDirectory.modifiedTime, + options?.useTildeAsSuffixInRenameEventFileName, + ); this.inodeWatching = inodeWatching; } - private removeFileOrFolder(fileOrDirectory: FsFile | FsFolder | FsSymLink, isRenaming?: boolean, options?: Partial) { + private removeFileOrFolder( + fileOrDirectory: FsFile | FsFolder | FsSymLink, + isRenaming?: boolean, + options?: Partial, + ) { const basePath = getDirectoryPath(fileOrDirectory.path); const baseFolder = this.fs.get(basePath) as FsFolder; if (basePath !== fileOrDirectory.path) { @@ -582,9 +654,23 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, if (isFsFolder(fileOrDirectory)) { Debug.assert(fileOrDirectory.entries.length === 0 || isRenaming); } - if (!options?.ignoreDelete) this.invokeFileAndFsWatches(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted, /*modifiedTime*/ undefined, options?.useTildeAsSuffixInRenameEventFileName); + if (!options?.ignoreDelete) { + this.invokeFileAndFsWatches( + fileOrDirectory.fullPath, + FileWatcherEventKind.Deleted, + /*modifiedTime*/ undefined, + options?.useTildeAsSuffixInRenameEventFileName, + ); + } this.inodes?.delete(fileOrDirectory.path); - if (!options?.ignoreDelete) this.invokeFileAndFsWatches(baseFolder.fullPath, FileWatcherEventKind.Changed, baseFolder.modifiedTime, options?.useTildeAsSuffixInRenameEventFileName); + if (!options?.ignoreDelete) { + this.invokeFileAndFsWatches( + baseFolder.fullPath, + FileWatcherEventKind.Changed, + baseFolder.modifiedTime, + options?.useTildeAsSuffixInRenameEventFileName, + ); + } } deleteFile(filePath: string) { @@ -623,7 +709,7 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, map.remove(path, callback); this.hasWatchChanges = true; closed = true; - } + }, }; } @@ -631,7 +717,7 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, return this.createWatcher( this.watchedFiles, this.toFullPath(fileName), - { cb, pollingInterval } + { cb, pollingInterval }, ); } @@ -640,7 +726,9 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, recursive: boolean, cb: FsWatchCallback, ) { - if (this.runWithFallbackPolling) throw new Error("Need to use fallback polling instead of file system native watching"); + if (this.runWithFallbackPolling) { + throw new Error("Need to use fallback polling instead of file system native watching"); + } const path = this.toFullPath(fileOrDirectory); // Error if the path does not exist if (this.inodeWatching && !this.inodes?.has(path)) throw new Error(); @@ -649,42 +737,78 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, path, { cb, - inode: this.inodes?.get(path) - } + inode: this.inodes?.get(path), + }, ) as FsWatchWorkerWatcher; result.on = noop; return result; } invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, modifiedTime: Date | undefined) { - invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath)), ({ cb }) => cb(fileFullPath, eventKind, modifiedTime)); + invokeWatcherCallbacks( + this.watchedFiles.get(this.toPath(fileFullPath)), + ({ cb }) => cb(fileFullPath, eventKind, modifiedTime), + ); } - private fsWatchCallback(map: MultiMap, fullPath: string, eventName: "rename" | "change", modifiedTime: Date | undefined, entryFullPath: string | undefined, useTildeSuffix: boolean | undefined) { + private fsWatchCallback( + map: MultiMap, + fullPath: string, + eventName: "rename" | "change", + modifiedTime: Date | undefined, + entryFullPath: string | undefined, + useTildeSuffix: boolean | undefined, + ) { const path = this.toPath(fullPath); const currentInode = this.inodes?.get(path); invokeWatcherCallbacks(map.get(path), ({ cb, inode }) => { // TODO:: if (this.inodeWatching && inode !== undefined && inode !== currentInode) return; - let relativeFileName = (entryFullPath ? this.getRelativePathToDirectory(fullPath, entryFullPath) : ""); - if (useTildeSuffix) relativeFileName = (relativeFileName ? relativeFileName : getBaseFileName(fullPath)) + "~"; + let relativeFileName = entryFullPath ? this.getRelativePathToDirectory(fullPath, entryFullPath) : ""; + if (useTildeSuffix) { + relativeFileName = (relativeFileName ? relativeFileName : getBaseFileName(fullPath)) + "~"; + } cb(eventName, relativeFileName, modifiedTime); }); } - invokeFsWatchesCallbacks(fullPath: string, eventName: "rename" | "change", modifiedTime?: Date, entryFullPath?: string, useTildeSuffix?: boolean) { + invokeFsWatchesCallbacks( + fullPath: string, + eventName: "rename" | "change", + modifiedTime?: Date, + entryFullPath?: string, + useTildeSuffix?: boolean, + ) { this.fsWatchCallback(this.fsWatches, fullPath, eventName, modifiedTime, entryFullPath, useTildeSuffix); } - invokeFsWatchesRecursiveCallbacks(fullPath: string, eventName: "rename" | "change", modifiedTime?: Date, entryFullPath?: string, useTildeSuffix?: boolean) { + invokeFsWatchesRecursiveCallbacks( + fullPath: string, + eventName: "rename" | "change", + modifiedTime?: Date, + entryFullPath?: string, + useTildeSuffix?: boolean, + ) { this.fsWatchCallback(this.fsWatchesRecursive, fullPath, eventName, modifiedTime, entryFullPath, useTildeSuffix); } private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) { - return getRelativePathToDirectoryOrUrl(directoryFullPath, fileFullPath, this.currentDirectory, this.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); + return getRelativePathToDirectoryOrUrl( + directoryFullPath, + fileFullPath, + this.currentDirectory, + this.getCanonicalFileName, + /*isAbsolutePathAnUrl*/ false, + ); } - private invokeRecursiveFsWatches(fullPath: string, eventName: "rename" | "change", modifiedTime?: Date, entryFullPath?: string, useTildeSuffix?: boolean) { + private invokeRecursiveFsWatches( + fullPath: string, + eventName: "rename" | "change", + modifiedTime?: Date, + entryFullPath?: string, + useTildeSuffix?: boolean, + ) { this.invokeFsWatchesRecursiveCallbacks(fullPath, eventName, modifiedTime, entryFullPath, useTildeSuffix); const basePath = getDirectoryPath(fullPath); if (this.getCanonicalFileName(fullPath) !== this.getCanonicalFileName(basePath)) { @@ -692,15 +816,30 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, } } - invokeFsWatches(fullPath: string, eventName: "rename" | "change", modifiedTime: Date | undefined, useTildeSuffix: boolean | undefined) { + invokeFsWatches( + fullPath: string, + eventName: "rename" | "change", + modifiedTime: Date | undefined, + useTildeSuffix: boolean | undefined, + ) { this.invokeFsWatchesCallbacks(fullPath, eventName, modifiedTime, fullPath, useTildeSuffix); this.invokeFsWatchesCallbacks(getDirectoryPath(fullPath), eventName, modifiedTime, fullPath, useTildeSuffix); this.invokeRecursiveFsWatches(fullPath, eventName, modifiedTime, /*entryFullPath*/ undefined, useTildeSuffix); } - private invokeFileAndFsWatches(fileOrFolderFullPath: string, eventKind: FileWatcherEventKind, modifiedTime?: Date, useTildeSuffix?: boolean) { + private invokeFileAndFsWatches( + fileOrFolderFullPath: string, + eventKind: FileWatcherEventKind, + modifiedTime?: Date, + useTildeSuffix?: boolean, + ) { this.invokeFileWatcher(fileOrFolderFullPath, eventKind, modifiedTime); - this.invokeFsWatches(fileOrFolderFullPath, eventKind === FileWatcherEventKind.Changed ? "change" : "rename", modifiedTime, useTildeSuffix); + this.invokeFsWatches( + fileOrFolderFullPath, + eventKind === FileWatcherEventKind.Changed ? "change" : "rename", + modifiedTime, + useTildeSuffix, + ); } private toFsEntry(path: string): FSEntryBase { @@ -708,7 +847,7 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, return { path: this.toPath(fullPath), fullPath, - modifiedTime: this.now() + modifiedTime: this.now(), }; } @@ -731,7 +870,11 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, return fsFolder; } - private getRealFsEntry(isFsEntry: (fsEntry: FSEntry) => fsEntry is T, path: Path, fsEntry = this.fs.get(path)!): T | undefined { + private getRealFsEntry( + isFsEntry: (fsEntry: FSEntry) => fsEntry is T, + path: Path, + fsEntry = this.fs.get(path)!, + ): T | undefined { if (isFsEntry(fsEntry)) { return fsEntry; } @@ -816,32 +959,51 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, const path = this.toFullPath(s); const folder = this.getRealFolder(path); if (folder) { - return mapDefined(folder.entries, entry => this.isFsFolder(entry) ? getBaseFileName(entry.fullPath) : undefined); + return mapDefined( + folder.entries, + entry => this.isFsFolder(entry) ? getBaseFileName(entry.fullPath) : undefined, + ); } Debug.fail(folder ? "getDirectories called on file" : "getDirectories called on missing folder"); return []; } - readDirectory(path: string, extensions?: readonly string[], exclude?: readonly string[], include?: readonly string[], depth?: number): string[] { - return matchFiles(path, extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), depth, (dir) => { - const directories: string[] = []; - const files: string[] = []; - const folder = this.getRealFolder(this.toPath(dir)); - if (folder) { - folder.entries.forEach((entry) => { - if (this.isFsFolder(entry)) { - directories.push(getBaseFileName(entry.fullPath)); - } - else if (this.isFsFile(entry)) { - files.push(getBaseFileName(entry.fullPath)); - } - else { - Debug.fail("Unknown entry"); - } - }); - } - return { directories, files }; - }, path => this.realpath(path)); + readDirectory( + path: string, + extensions?: readonly string[], + exclude?: readonly string[], + include?: readonly string[], + depth?: number, + ): string[] { + return matchFiles( + path, + extensions, + exclude, + include, + this.useCaseSensitiveFileNames, + this.getCurrentDirectory(), + depth, + dir => { + const directories: string[] = []; + const files: string[] = []; + const folder = this.getRealFolder(this.toPath(dir)); + if (folder) { + folder.entries.forEach(entry => { + if (this.isFsFolder(entry)) { + directories.push(getBaseFileName(entry.fullPath)); + } + else if (this.isFsFile(entry)) { + files.push(getBaseFileName(entry.fullPath)); + } + else { + Debug.fail("Unknown entry"); + } + }); + } + return { directories, files }; + }, + path => this.realpath(path), + ); } createHash(s: string): string { @@ -998,9 +1160,19 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, private serializedFsWatchesRecursive: Map | undefined; serializeWatches(baseline: string[] = []) { if (!this.hasWatchChanges) return baseline; - this.serializedWatchedFiles = serializeMultiMap(baseline, "PolledWatches", this.watchedFiles, this.serializedWatchedFiles); + this.serializedWatchedFiles = serializeMultiMap( + baseline, + "PolledWatches", + this.watchedFiles, + this.serializedWatchedFiles, + ); this.serializedFsWatches = serializeMultiMap(baseline, "FsWatches", this.fsWatches, this.serializedFsWatches); - this.serializedFsWatchesRecursive = serializeMultiMap(baseline, "FsWatchesRecursive", this.fsWatchesRecursive, this.serializedFsWatchesRecursive); + this.serializedFsWatchesRecursive = serializeMultiMap( + baseline, + "FsWatchesRecursive", + this.fsWatchesRecursive, + this.serializedFsWatchesRecursive, + ); this.hasWatchChanges = false; return baseline; } @@ -1046,7 +1218,13 @@ function diffFsSymLink(baseline: string[], fsEntry: FsSymLink, newInode: number function inodeString(inode: number | undefined) { return inode !== undefined ? ` Inode:: ${inode}` : ""; } -function diffFsEntry(baseline: string[], oldFsEntry: FSEntry | undefined, newFsEntry: FSEntry | undefined, newInode: number | undefined, writtenFiles: Map | undefined): void { +function diffFsEntry( + baseline: string[], + oldFsEntry: FSEntry | undefined, + newFsEntry: FSEntry | undefined, + newInode: number | undefined, + writtenFiles: Map | undefined, +): void { const file = newFsEntry && newFsEntry.fullPath; if (isFsFile(oldFsEntry)) { if (isFsFile(newFsEntry)) { @@ -1055,7 +1233,9 @@ function diffFsEntry(baseline: string[], oldFsEntry: FSEntry | undefined, newFsE } else if (oldFsEntry.modifiedTime !== newFsEntry.modifiedTime) { if (oldFsEntry.fullPath !== newFsEntry.fullPath) { - baseline.push(`//// [${file}] file was renamed from file ${oldFsEntry.fullPath}${inodeString(newInode)}`); + baseline.push( + `//// [${file}] file was renamed from file ${oldFsEntry.fullPath}${inodeString(newInode)}`, + ); } else if (writtenFiles && !writtenFiles.has(newFsEntry.path)) { baseline.push(`//// [${file}] file changed its modified time${inodeString(newInode)}`); @@ -1079,7 +1259,11 @@ function diffFsEntry(baseline: string[], oldFsEntry: FSEntry | undefined, newFsE } else if (oldFsEntry.modifiedTime !== newFsEntry.modifiedTime) { if (oldFsEntry.fullPath !== newFsEntry.fullPath) { - baseline.push(`//// [${file}] symlink was renamed from symlink ${oldFsEntry.fullPath}${inodeString(newInode)}`); + baseline.push( + `//// [${file}] symlink was renamed from symlink ${oldFsEntry.fullPath}${ + inodeString(newInode) + }`, + ); } else if (writtenFiles && !writtenFiles.has(newFsEntry.path)) { baseline.push(`//// [${file}] symlink changed its modified time${inodeString(newInode)}`); @@ -1104,7 +1288,12 @@ function diffFsEntry(baseline: string[], oldFsEntry: FSEntry | undefined, newFsE } } -function serializeMultiMap(baseline: string[], caption: string, multiMap: MultiMap, serialized: Map | undefined) { +function serializeMultiMap( + baseline: string[], + caption: string, + multiMap: MultiMap, + serialized: Map | undefined, +) { let hasChange = diffMap(baseline, caption, multiMap, serialized, /*deleted*/ false); hasChange = diffMap(baseline, caption, serialized, multiMap, /*deleted*/ true) || hasChange; if (hasChange) { @@ -1119,7 +1308,7 @@ function diffMap( caption: string, map: Map | undefined, old: Map | undefined, - deleted: boolean + deleted: boolean, ) { let captionAdded = false; let baselineChanged = false; @@ -1184,6 +1373,6 @@ export function getTsBuildProjectFilePath(project: string, file: string) { export function getTsBuildProjectFile(project: string, file: string): File { return { path: getTsBuildProjectFilePath(project, file), - content: Harness.IO.readFile(`${Harness.IO.getWorkspaceRoot()}/tests/projects/${project}/${file}`)! + content: Harness.IO.readFile(`${Harness.IO.getWorkspaceRoot()}/tests/projects/${project}/${file}`)!, }; } diff --git a/src/testRunner/unittests/incrementalParser.ts b/src/testRunner/unittests/incrementalParser.ts index 37feb3778854c..caaea4e8019d3 100644 --- a/src/testRunner/unittests/incrementalParser.ts +++ b/src/testRunner/unittests/incrementalParser.ts @@ -1,23 +1,45 @@ import * as ts from "../_namespaces/ts"; import * as Utils from "../_namespaces/Utils"; -function withChange(text: ts.IScriptSnapshot, start: number, length: number, newText: string): { text: ts.IScriptSnapshot; textChangeRange: ts.TextChangeRange; } { +function withChange( + text: ts.IScriptSnapshot, + start: number, + length: number, + newText: string, +): { text: ts.IScriptSnapshot; textChangeRange: ts.TextChangeRange; } { const contents = ts.getSnapshotText(text); const newContents = contents.substr(0, start) + newText + contents.substring(start + length); - return { text: ts.ScriptSnapshot.fromString(newContents), textChangeRange: ts.createTextChangeRange(ts.createTextSpan(start, length), newText.length) }; + return { + text: ts.ScriptSnapshot.fromString(newContents), + textChangeRange: ts.createTextChangeRange(ts.createTextSpan(start, length), newText.length), + }; } -function withInsert(text: ts.IScriptSnapshot, start: number, newText: string): { text: ts.IScriptSnapshot; textChangeRange: ts.TextChangeRange; } { +function withInsert( + text: ts.IScriptSnapshot, + start: number, + newText: string, +): { text: ts.IScriptSnapshot; textChangeRange: ts.TextChangeRange; } { return withChange(text, start, 0, newText); } -function withDelete(text: ts.IScriptSnapshot, start: number, length: number): { text: ts.IScriptSnapshot; textChangeRange: ts.TextChangeRange; } { +function withDelete( + text: ts.IScriptSnapshot, + start: number, + length: number, +): { text: ts.IScriptSnapshot; textChangeRange: ts.TextChangeRange; } { return withChange(text, start, length, ""); } function createTree(text: ts.IScriptSnapshot, version: string) { - return ts.createLanguageServiceSourceFile(/*fileName:*/ "", text, ts.ScriptTarget.Latest, version, /*setNodeParents*/ true); + return ts.createLanguageServiceSourceFile( + /*fileName:*/ "", + text, + ts.ScriptTarget.Latest, + version, + /*setNodeParents*/ true, + ); } function assertSameDiagnostics(file1: ts.SourceFile, file2: ts.SourceFile) { @@ -44,7 +66,13 @@ function assertSameDiagnostics(file1: ts.SourceFile, file2: ts.SourceFile) { // be a good thing. If it decreases, that's not great (less reusability), but that may be // unavoidable. If it does decrease an investigation should be done to make sure that things // are still ok and we're still appropriately reusing most of the tree. -function compareTrees(oldText: ts.IScriptSnapshot, newText: ts.IScriptSnapshot, textChangeRange: ts.TextChangeRange, expectedReusedElements: number, oldTree?: ts.SourceFile) { +function compareTrees( + oldText: ts.IScriptSnapshot, + newText: ts.IScriptSnapshot, + textChangeRange: ts.TextChangeRange, + expectedReusedElements: number, + oldTree?: ts.SourceFile, +) { oldTree = oldTree || createTree(oldText, /*version:*/ "."); Utils.assertInvariants(oldTree, /*parent:*/ undefined); @@ -53,7 +81,12 @@ function compareTrees(oldText: ts.IScriptSnapshot, newText: ts.IScriptSnapshot, Utils.assertInvariants(newTree, /*parent:*/ undefined); // Create a tree for the new text, in an incremental fashion. - const incrementalNewTree = ts.updateLanguageServiceSourceFile(oldTree, newText, oldTree.version + ".", textChangeRange); + const incrementalNewTree = ts.updateLanguageServiceSourceFile( + oldTree, + newText, + oldTree.version + ".", + textChangeRange, + ); Utils.assertInvariants(incrementalNewTree, /*parent:*/ undefined); // We should get the same tree when doign a full or incremental parse. @@ -100,7 +133,8 @@ function deleteCode(source: string, index: number, toDelete: string) { for (let i = 0; i < repeat; i++) { const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withDelete(oldText, index, 1); - const newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree).incrementalNewTree; + const newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree) + .incrementalNewTree; source = ts.getSnapshotText(newTextAndChange.text); oldTree = newTree; @@ -113,7 +147,8 @@ function insertCode(source: string, index: number, toInsert: string) { for (let i = 0; i < repeat; i++) { const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withInsert(oldText, index + i, toInsert.charAt(i)); - const newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree).incrementalNewTree; + const newTree = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1, oldTree) + .incrementalNewTree; source = ts.getSnapshotText(newTextAndChange.text); oldTree = newTree; @@ -122,13 +157,13 @@ function insertCode(source: string, index: number, toInsert: string) { describe("unittests:: Incremental Parser", () => { it("Inserting into method", () => { - const source = "class C {\r\n" + - " public foo1() { }\r\n" + - " public foo2() {\r\n" + - " return 1;\r\n" + - " }\r\n" + - " public foo3() { }\r\n" + - "}"; + const source = "class C {\r\n" + + " public foo1() { }\r\n" + + " public foo2() {\r\n" + + " return 1;\r\n" + + " }\r\n" + + " public foo3() { }\r\n" + + "}"; const oldText = ts.ScriptSnapshot.fromString(source); const semicolonIndex = source.indexOf(";"); @@ -138,13 +173,13 @@ describe("unittests:: Incremental Parser", () => { }); it("Deleting from method", () => { - const source = "class C {\r\n" + - " public foo1() { }\r\n" + - " public foo2() {\r\n" + - " return 1 + 1;\r\n" + - " }\r\n" + - " public foo3() { }\r\n" + - "}"; + const source = "class C {\r\n" + + " public foo1() { }\r\n" + + " public foo2() {\r\n" + + " return 1 + 1;\r\n" + + " }\r\n" + + " public foo3() { }\r\n" + + "}"; const index = source.indexOf("+ 1"); const oldText = ts.ScriptSnapshot.fromString(source); @@ -213,11 +248,11 @@ describe("unittests:: Incremental Parser", () => { it("Parameter 1", () => { // Should be able to reuse all the parameters. - const source = "class C {\r\n" + - " public foo2(a, b, c, d) {\r\n" + - " return 1;\r\n" + - " }\r\n" + - "}"; + const source = "class C {\r\n" + + " public foo2(a, b, c, d) {\r\n" + + " return 1;\r\n" + + " }\r\n" + + "}"; const semicolonIndex = source.indexOf(";"); const oldText = ts.ScriptSnapshot.fromString(source); @@ -287,7 +322,8 @@ describe("unittests:: Incremental Parser", () => { }); it("Strict mode 5", () => { - const source = "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + const source = + "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; const index = source.indexOf("b"); const oldText = ts.ScriptSnapshot.fromString(source); @@ -297,7 +333,8 @@ describe("unittests:: Incremental Parser", () => { }); it("Strict mode 6", () => { - const source = "'use strict';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + const source = + "'use strict';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; const index = source.indexOf("s"); const oldText = ts.ScriptSnapshot.fromString(source); @@ -307,7 +344,8 @@ describe("unittests:: Incremental Parser", () => { }); it("Strict mode 7", () => { - const source = "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; + const source = + "'use blahhh';\r\nfoo1();\r\nfoo2();\r\nfoo3();\r\nfoo4();\r\nfoo4();\r\nfoo6();\r\nfoo7();\r\nfoo8();\r\nfoo9();\r\n"; const index = source.indexOf("f"); const oldText = ts.ScriptSnapshot.fromString(source); @@ -519,7 +557,8 @@ describe("unittests:: Incremental Parser", () => { }); it("Delete semicolon", () => { - const source = "export class Foo {\r\n}\r\n\r\nexport var foo = new Foo();\r\n\r\n export function test(foo: Foo) {\r\n return true;\r\n }\r\n"; + const source = + "export class Foo {\r\n}\r\n\r\nexport var foo = new Foo();\r\n\r\n export function test(foo: Foo) {\r\n return true;\r\n }\r\n"; const oldText = ts.ScriptSnapshot.fromString(source); const index = source.lastIndexOf(";"); @@ -549,8 +588,7 @@ describe("unittests:: Incremental Parser", () => { }); it("Modifier added to accessor", () => { - const source = - "class C {\ + const source = "class C {\ set Bar(bar:string) {}\ }\ var o2 = { set Foo(val:number) { } };"; @@ -563,8 +601,7 @@ var o2 = { set Foo(val:number) { } };"; }); it("Insert parameter ahead of parameter", () => { - const source = - "alert(100);\ + const source = "alert(100);\ \ class OverloadedMonster {\ constructor();\ @@ -579,8 +616,7 @@ constructor(name) { }\ }); it("Insert declare modifier before module", () => { - const source = - "module mAmbient {\ + const source = "module mAmbient {\ module m3 { }\ }"; @@ -592,8 +628,7 @@ module m3 { }\ }); it("Insert function above arrow function with comment", () => { - const source = - "\ + const source = "\ () =>\ // do something\ 0;"; @@ -702,7 +737,7 @@ module m3 { }\ }); it("Moving methods from object literal to class in strict mode", () => { - const source = "\"use strict\"; var v = { public A() { } public B() { } public C() { } }"; + const source = '"use strict"; var v = { public A() { } public B() { } public C() { } }'; const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 14, "var v =".length, "class C"); @@ -719,7 +754,7 @@ module m3 { }\ compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); - it("Do not move methods called \"constructor\" from object literal to class", () => { + it('Do not move methods called "constructor" from object literal to class', () => { const source = "var v = { public constructor() { } public constructor() { } public constructor() { } }"; const oldText = ts.ScriptSnapshot.fromString(source); @@ -738,7 +773,8 @@ module m3 { }\ }); it("Moving index signatures from class to interface in strict mode", () => { - const source = "\"use strict\"; class C { public [a: number]: string; public [a: number]: string; public [a: number]: string }"; + const source = + '"use strict"; class C { public [a: number]: string; public [a: number]: string; public [a: number]: string }'; const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 14, "class".length, "interface"); @@ -747,7 +783,8 @@ module m3 { }\ }); it("Moving index signatures from interface to class", () => { - const source = "interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }"; + const source = + "interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }"; const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 0, "interface".length, "class"); @@ -755,9 +792,9 @@ module m3 { }\ compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 18); }); - it("Moving index signatures from interface to class in strict mode", () => { - const source = "\"use strict\"; interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }"; + const source = + '"use strict"; interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }'; const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 14, "interface".length, "class"); @@ -783,9 +820,8 @@ module m3 { }\ compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); }); - it("Moving accessors from object literal to class in strict mode", () => { - const source = "\"use strict\"; var v = { public get A() { } public get B() { } public get C() { } }"; + const source = '"use strict"; var v = { public get A() { } public get B() { } public get C() { } }'; const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 14, "var v =".length, "class C"); @@ -797,7 +833,12 @@ module m3 { }\ const source = `class Greeter { constructor(element: HTMLElement) { } }`; const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, 15, 0, "\n"); - const { oldTree, incrementalNewTree } = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + const { oldTree, incrementalNewTree } = compareTrees( + oldText, + newTextAndChange.text, + newTextAndChange.textChangeRange, + -1, + ); ts.bindSourceFile(oldTree, {}); ts.bindSourceFile(incrementalNewTree, {}); assert.equal(oldTree.transformFlags, incrementalNewTree.transformFlags); @@ -813,32 +854,34 @@ module m3 { }\ }); it("Type after incomplete enum 1", () => { - const source = "function foo() {\r\n" + - " function getOccurrencesAtPosition() {\r\n" + - " switch (node) {\r\n" + - " enum \r\n" + - " }\r\n" + - " \r\n" + - " return undefined;\r\n" + - " \r\n" + - " function keywordToReferenceEntry() {\r\n" + - " }\r\n" + - " }\r\n" + - " \r\n" + - " return {\r\n" + - " getEmitOutput: (fileName): Bar => null,\r\n" + - " };\r\n" + - " }"; + const source = "function foo() {\r\n" + + " function getOccurrencesAtPosition() {\r\n" + + " switch (node) {\r\n" + + " enum \r\n" + + " }\r\n" + + " \r\n" + + " return undefined;\r\n" + + " \r\n" + + " function keywordToReferenceEntry() {\r\n" + + " }\r\n" + + " }\r\n" + + " \r\n" + + " return {\r\n" + + " getEmitOutput: (fileName): Bar => null,\r\n" + + " };\r\n" + + " }"; const index = source.indexOf("enum ") + "enum ".length; insertCode(source, index, "Fo"); }); - for (const tsIgnoreComment of [ - "// @ts-ignore", - "/* @ts-ignore */", - "/*\n @ts-ignore */" - ]) { + for ( + const tsIgnoreComment of [ + "// @ts-ignore", + "/* @ts-ignore */", + "/*\n @ts-ignore */", + ] + ) { describe(`${tsIgnoreComment} comment directives`, () => { const textWithIgnoreComment = `const x = 10; function foo() { @@ -867,8 +910,16 @@ module m3 { }\ verifyScenario("when changing text that adds another comment", verifyChangeDirectiveType); verifyScenario("when changing text that keeps the comment but adds more nodes", verifyReuseChange); - function verifyCommentDirectives(oldText: ts.IScriptSnapshot, newTextAndChange: { text: ts.IScriptSnapshot; textChangeRange: ts.TextChangeRange; }) { - const { incrementalNewTree, newTree } = compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, -1); + function verifyCommentDirectives( + oldText: ts.IScriptSnapshot, + newTextAndChange: { text: ts.IScriptSnapshot; textChangeRange: ts.TextChangeRange; }, + ) { + const { incrementalNewTree, newTree } = compareTrees( + oldText, + newTextAndChange.text, + newTextAndChange.textChangeRange, + -1, + ); assert.deepEqual(incrementalNewTree.commentDirectives, newTree.commentDirectives); } @@ -910,14 +961,19 @@ module m3 { }\ function verifyDelete(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex); - const oldText = ts.ScriptSnapshot.fromString(textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore)); + const oldText = ts.ScriptSnapshot.fromString( + textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore), + ); const newTextAndChange = withDelete(oldText, index, tsIgnoreComment.length); verifyCommentDirectives(oldText, newTextAndChange); } function verifyInsert(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex); - const source = textWithIgnoreCommentFrom(textWithIgnoreComment.slice(0, index) + textWithIgnoreComment.slice(index + tsIgnoreComment.length), singleIgnore); + const source = textWithIgnoreCommentFrom( + textWithIgnoreComment.slice(0, index) + textWithIgnoreComment.slice(index + tsIgnoreComment.length), + singleIgnore, + ); const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withInsert(oldText, index, tsIgnoreComment); verifyCommentDirectives(oldText, newTextAndChange); @@ -925,14 +981,19 @@ module m3 { }\ function verifyChangeToBlah(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex) + tsIgnoreComment.indexOf("@"); - const oldText = ts.ScriptSnapshot.fromString(textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore)); + const oldText = ts.ScriptSnapshot.fromString( + textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore), + ); const newTextAndChange = withChange(oldText, index, 1, "blah "); verifyCommentDirectives(oldText, newTextAndChange); } function verifyChangeBackToDirective(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex) + tsIgnoreComment.indexOf("@"); - const source = textWithIgnoreCommentFrom(textWithIgnoreComment.slice(0, index) + "blah " + textWithIgnoreComment.slice(index + 1), singleIgnore); + const source = textWithIgnoreCommentFrom( + textWithIgnoreComment.slice(0, index) + "blah " + textWithIgnoreComment.slice(index + 1), + singleIgnore, + ); const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withChange(oldText, index, "blah ".length, "@"); verifyCommentDirectives(oldText, newTextAndChange); @@ -941,7 +1002,10 @@ module m3 { }\ function verifyDeletingBlah(atIndex: number, singleIgnore?: true) { const tsIgnoreIndex = getIndexOfTsIgnoreComment(atIndex); const index = tsIgnoreIndex + tsIgnoreComment.indexOf("@"); - const source = textWithIgnoreCommentFrom(textWithIgnoreComment.slice(0, index) + "blah " + textWithIgnoreComment.slice(index + 1), singleIgnore); + const source = textWithIgnoreCommentFrom( + textWithIgnoreComment.slice(0, index) + "blah " + textWithIgnoreComment.slice(index + 1), + singleIgnore, + ); const oldText = ts.ScriptSnapshot.fromString(source); const newTextAndChange = withDelete(oldText, tsIgnoreIndex, tsIgnoreComment.length + "blah".length); verifyCommentDirectives(oldText, newTextAndChange); @@ -949,7 +1013,9 @@ module m3 { }\ function verifyChangeDirectiveType(atIndex: number, singleIgnore?: true) { const index = getIndexOfTsIgnoreComment(atIndex) + tsIgnoreComment.indexOf("ignore"); - const oldText = ts.ScriptSnapshot.fromString(textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore)); + const oldText = ts.ScriptSnapshot.fromString( + textWithIgnoreCommentFrom(textWithIgnoreComment, singleIgnore), + ); const newTextAndChange = withChange(oldText, index, "ignore".length, "expect-error"); verifyCommentDirectives(oldText, newTextAndChange); } diff --git a/src/testRunner/unittests/jsDocParsing.ts b/src/testRunner/unittests/jsDocParsing.ts index 7fab2e719987b..914865ea46a1a 100644 --- a/src/testRunner/unittests/jsDocParsing.ts +++ b/src/testRunner/unittests/jsDocParsing.ts @@ -9,8 +9,10 @@ describe("unittests:: JSDocParsing", () => { const typeAndDiagnostics = ts.parseJSDocTypeExpressionForTests(content); assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0, "no errors issued"); - Harness.Baseline.runBaseline("JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json", - Utils.sourceFileToJSON(typeAndDiagnostics!.jsDocTypeExpression.type)); + Harness.Baseline.runBaseline( + "JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json", + Utils.sourceFileToJSON(typeAndDiagnostics!.jsDocTypeExpression.type), + ); }); } @@ -99,9 +101,14 @@ describe("unittests:: JSDocParsing", () => { ts.Debug.fail("Comment has at least one diagnostic: " + comment.diagnostics[0].messageText); } - Harness.Baseline.runBaseline("JSDocParsing/DocComments.parsesCorrectly." + name + ".json", - JSON.stringify(comment.jsDoc, - (_, v) => v && v.pos !== undefined ? JSON.parse(Utils.sourceFileToJSON(v)) : v, 4)); + Harness.Baseline.runBaseline( + "JSDocParsing/DocComments.parsesCorrectly." + name + ".json", + JSON.stringify( + comment.jsDoc, + (_, v) => v && v.pos !== undefined ? JSON.parse(Utils.sourceFileToJSON(v)) : v, + 4, + ), + ); }); } @@ -113,240 +120,307 @@ describe("unittests:: JSDocParsing", () => { } describe("parsesIncorrectly", () => { - parsesIncorrectly("multipleTypes", + parsesIncorrectly( + "multipleTypes", `/** * @type {number} * @type {string} - */`); - parsesIncorrectly("multipleReturnTypes", + */`, + ); + parsesIncorrectly( + "multipleReturnTypes", `/** * @return {number} * @return {string} - */`); - parsesIncorrectly("noTypeParameters", + */`, + ); + parsesIncorrectly( + "noTypeParameters", `/** * @template - */`); - parsesIncorrectly("trailingTypeParameterComma", + */`, + ); + parsesIncorrectly( + "trailingTypeParameterComma", `/** * @template T, - */`); - parsesIncorrectly("paramWithoutName", + */`, + ); + parsesIncorrectly( + "paramWithoutName", `/** * @param {number} - */`); - parsesIncorrectly("paramWithoutTypeOrName", + */`, + ); + parsesIncorrectly( + "paramWithoutTypeOrName", `/** * @param - */`); + */`, + ); - parsesIncorrectly("noType", + parsesIncorrectly( + "noType", `/** * @type -*/`); +*/`, + ); - parsesIncorrectly("@augments with no type", + parsesIncorrectly( + "@augments with no type", `/** * @augments - */`); + */`, + ); }); describe("parsesCorrectly", () => { parsesCorrectly("threeAsterisks", "/*** */"); parsesCorrectly("emptyComment", "/***/"); - parsesCorrectly("noLeadingAsterisk", + parsesCorrectly( + "noLeadingAsterisk", `/** @type {number} - */`); + */`, + ); - - parsesCorrectly("noReturnType", + parsesCorrectly( + "noReturnType", `/** * @return - */`); + */`, + ); - parsesCorrectly("leadingAsterisk", + parsesCorrectly( + "leadingAsterisk", `/** * @type {number} - */`); + */`, + ); parsesCorrectly("asteriskAfterPreamble", "/** * @type {number} */"); - parsesCorrectly("typeTag", + parsesCorrectly( + "typeTag", `/** * @type {number} - */`); + */`, + ); - parsesCorrectly("satisfiesTag", + parsesCorrectly( + "satisfiesTag", `/** * @satisfies {number} - */`); + */`, + ); - parsesCorrectly("returnTag1", + parsesCorrectly( + "returnTag1", `/** * @return {number} - */`); - + */`, + ); - parsesCorrectly("returnTag2", + parsesCorrectly( + "returnTag2", `/** * @return {number} Description text follows - */`); - + */`, + ); - parsesCorrectly("returnsTag1", + parsesCorrectly( + "returnsTag1", `/** * @returns {number} - */`); + */`, + ); - - parsesCorrectly("oneParamTag", + parsesCorrectly( + "oneParamTag", `/** * @param {number} name1 - */`); - + */`, + ); - parsesCorrectly("twoParamTag2", + parsesCorrectly( + "twoParamTag2", `/** * @param {number} name1 * @param {number} name2 - */`); + */`, + ); - - parsesCorrectly("paramTag1", + parsesCorrectly( + "paramTag1", `/** * @param {number} name1 Description text follows - */`); - + */`, + ); - parsesCorrectly("paramTagBracketedName1", + parsesCorrectly( + "paramTagBracketedName1", `/** * @param {number} [name1] Description text follows - */`); + */`, + ); - - parsesCorrectly("paramTagBracketedName2", + parsesCorrectly( + "paramTagBracketedName2", `/** * @param {number} [ name1 = 1] Description text follows - */`); - + */`, + ); - parsesCorrectly("twoParamTagOnSameLine", + parsesCorrectly( + "twoParamTagOnSameLine", `/** * @param {number} name1 @param {number} name2 - */`); + */`, + ); - - parsesCorrectly("paramTagNameThenType1", + parsesCorrectly( + "paramTagNameThenType1", `/** * @param name1 {number} - */`); - + */`, + ); - parsesCorrectly("paramTagNameThenType2", + parsesCorrectly( + "paramTagNameThenType2", `/** * @param name1 {number} Description - */`); - + */`, + ); - parsesCorrectly("argSynonymForParamTag", + parsesCorrectly( + "argSynonymForParamTag", `/** * @arg {number} name1 Description - */`); + */`, + ); - - parsesCorrectly("argumentSynonymForParamTag", + parsesCorrectly( + "argumentSynonymForParamTag", `/** * @argument {number} name1 Description - */`); - + */`, + ); - parsesCorrectly("templateTag", + parsesCorrectly( + "templateTag", `/** * @template T - */`); + */`, + ); - - parsesCorrectly("templateTag2", + parsesCorrectly( + "templateTag2", `/** * @template K,V - */`); - + */`, + ); - parsesCorrectly("templateTag3", + parsesCorrectly( + "templateTag3", `/** * @template K ,V - */`); + */`, + ); - - parsesCorrectly("templateTag4", + parsesCorrectly( + "templateTag4", `/** * @template K, V - */`); - + */`, + ); - parsesCorrectly("templateTag5", + parsesCorrectly( + "templateTag5", `/** * @template K , V - */`); + */`, + ); - parsesCorrectly("templateTag6", + parsesCorrectly( + "templateTag6", `/** * @template K , V Description of type parameters. - */`); + */`, + ); - parsesCorrectly("paramWithoutType", + parsesCorrectly( + "paramWithoutType", `/** * @param foo - */`); - parsesCorrectly("throwsTag1", + */`, + ); + parsesCorrectly( + "throwsTag1", `/** * @throws {Error} - */`); + */`, + ); - parsesCorrectly("throwsTag2", + parsesCorrectly( + "throwsTag2", `/** * @throws free-form description - */`); + */`, + ); - parsesCorrectly("throwsTag3", + parsesCorrectly( + "throwsTag3", `/** * @throws {Error} description - */`); + */`, + ); - parsesCorrectly("exceptionTag1", + parsesCorrectly( + "exceptionTag1", `/** * @exception {Error} - */`); + */`, + ); - parsesCorrectly("exceptionTag2", + parsesCorrectly( + "exceptionTag2", `/** * @exception free-form description - */`); + */`, + ); - parsesCorrectly("exceptionTag3", + parsesCorrectly( + "exceptionTag3", `/** * @exception {Error} description - */`); - parsesCorrectly("typedefTagWithChildrenTags", + */`, + ); + parsesCorrectly( + "typedefTagWithChildrenTags", `/** * @typedef People * @type {Object} * @property {number} age * @property {string} name - */`); - parsesCorrectly("less-than and greater-than characters", + */`, + ); + parsesCorrectly( + "less-than and greater-than characters", `/** * @param x hi < > still part of the previous comment - */`); + */`, + ); - parsesCorrectly("Nested @param tags", + parsesCorrectly( + "Nested @param tags", `/** * @param {object} o Doc doc * @param {string} o.f Doc for f -*/`); - parsesCorrectly("@link tags", +*/`, + ); + parsesCorrectly( + "@link tags", `/** * {@link first } * Inside {@link link text} thing @@ -365,8 +439,10 @@ oh.no * nope * }, because of the intermediate asterisks. * @author Alfa Romero See my home page: {@link https://example.com} - */`); - parsesCorrectly("authorTag", + */`, + ); + parsesCorrectly( + "authorTag", `/** * @author John Doe * @author John Doe unexpected comment @@ -385,35 +461,47 @@ oh.no * must be on the same line to parse * @author Long Comment I * want to keep commenting down here, I dunno. - */`); + */`, + ); - parsesCorrectly("consecutive newline tokens", + parsesCorrectly( + "consecutive newline tokens", `/** * @example * Some\n\n * text\r\n * with newlines. - */`); + */`, + ); parsesCorrectly("Chained tags, no leading whitespace", `/**@a @b @c@d*/`); parsesCorrectly("Single trailing whitespace", `/** trailing whitespace */`); parsesCorrectly("Initial star is not a tag", `/***@a*/`); parsesCorrectly("Initial star space is not a tag", `/*** @a*/`); parsesCorrectly("Initial email address is not a tag", `/**bill@example.com*/`); - parsesCorrectly("no space before @ is not a new tag", + parsesCorrectly( + "no space before @ is not a new tag", `/** * @param this (@is@) * @param fine its@fine @zerowidth *@singlestar **@doublestar - */`); - parsesCorrectly("@@ does not start a new tag", + */`, + ); + parsesCorrectly( + "@@ does not start a new tag", `/** * @param this is (@@fine@@and) is one comment - */`); + */`, + ); }); }); describe("getFirstToken", () => { it("gets jsdoc", () => { - const root = ts.createSourceFile("foo.ts", "/** comment */var a = true;", ts.ScriptTarget.ES5, /*setParentNodes*/ true); + const root = ts.createSourceFile( + "foo.ts", + "/** comment */var a = true;", + ts.ScriptTarget.ES5, + /*setParentNodes*/ true, + ); assert.isDefined(root); assert.equal(root.kind, ts.SyntaxKind.SourceFile); const first = root.getFirstToken(); @@ -423,7 +511,12 @@ oh.no }); describe("getLastToken", () => { it("gets jsdoc", () => { - const root = ts.createSourceFile("foo.ts", "var a = true;/** comment */", ts.ScriptTarget.ES5, /*setParentNodes*/ true); + const root = ts.createSourceFile( + "foo.ts", + "var a = true;/** comment */", + ts.ScriptTarget.ES5, + /*setParentNodes*/ true, + ); assert.isDefined(root); const last = root.getLastToken(); assert.isDefined(last); @@ -432,7 +525,12 @@ oh.no }); describe("getStart", () => { it("runs when node with JSDoc but no parent pointers", () => { - const root = ts.createSourceFile("foo.ts", "/** */var a = true;", ts.ScriptTarget.ES5, /*setParentNodes*/ false); + const root = ts.createSourceFile( + "foo.ts", + "/** */var a = true;", + ts.ScriptTarget.ES5, + /*setParentNodes*/ false, + ); root.statements[0].getStart(root, /*includeJsDocComment*/ true); }); }); diff --git a/src/testRunner/unittests/jsonParserRecovery.ts b/src/testRunner/unittests/jsonParserRecovery.ts index 41f4c98559542..c68253ab03609 100644 --- a/src/testRunner/unittests/jsonParserRecovery.ts +++ b/src/testRunner/unittests/jsonParserRecovery.ts @@ -10,8 +10,9 @@ describe("unittests:: jsonParserRecovery", () => { `jsonParserRecovery/${name.replace(/[^a-z0-9_-]/ig, "_")}.errors.txt`, Harness.Compiler.getErrorBaseline([{ content: text, - unitName: name - }], file.parseDiagnostics)); + unitName: name, + }], file.parseDiagnostics), + ); // Will throw if parse tree does not cover full input text file.getChildren(); @@ -22,7 +23,9 @@ describe("unittests:: jsonParserRecovery", () => { parsesToValidSourceFileWithErrors("TypeScript code", "interface Foo {} blah"); parsesToValidSourceFileWithErrors("Two comma-separated objects", "{}, {}"); parsesToValidSourceFileWithErrors("Two objects", "{} {}"); - parsesToValidSourceFileWithErrors("JSX", ` + parsesToValidSourceFileWithErrors( + "JSX", + ` interface Test {} const Header = () => ( @@ -36,5 +39,6 @@ describe("unittests:: jsonParserRecovery", () => { \`}
- )`); + )`, + ); }); diff --git a/src/testRunner/unittests/moduleResolution.ts b/src/testRunner/unittests/moduleResolution.ts index 560d68b7e954f..58c606219eb3a 100644 --- a/src/testRunner/unittests/moduleResolution.ts +++ b/src/testRunner/unittests/moduleResolution.ts @@ -7,7 +7,11 @@ interface File { symlinks?: string[]; } -function createModuleResolutionHost(baselines: string[], hasDirectoryExists: boolean, ...files: File[]): ts.ModuleResolutionHost { +function createModuleResolutionHost( + baselines: string[], + hasDirectoryExists: boolean, + ...files: File[] +): ts.ModuleResolutionHost { const map = new Map(); for (const file of files) { map.set(file.name, file); @@ -38,10 +42,13 @@ function createModuleResolutionHost(baselines: string[], hasDirectoryExists: boo realpath, directoryExists: path => directories.has(path), fileExists: path => { - assert.isTrue(directories.has(ts.getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`); + assert.isTrue( + directories.has(ts.getDirectoryPath(path)), + `'fileExists' '${path}' request in non-existing directory`, + ); return map.has(path); }, - useCaseSensitiveFileNames: true + useCaseSensitiveFileNames: true, }; } else { @@ -62,17 +69,34 @@ function runBaseline(scenario: string, baselines: readonly string[]) { describe("unittests:: moduleResolution:: Node module resolution - relative paths", () => { // node module resolution does _not_ implicitly append these extensions to an extensionless path (though will still attempt to load them if explicitly) - const nonImplicitExtensions = [ts.Extension.Mts, ts.Extension.Dmts, ts.Extension.Mjs, ts.Extension.Cts, ts.Extension.Dcts, ts.Extension.Cjs]; + const nonImplicitExtensions = [ + ts.Extension.Mts, + ts.Extension.Dmts, + ts.Extension.Mjs, + ts.Extension.Cts, + ts.Extension.Dcts, + ts.Extension.Cjs, + ]; const autoExtensions = ts.filter(ts.supportedTSExtensionsFlat, e => nonImplicitExtensions.indexOf(e) === -1); it("load as file", () => { const baselines: string[] = []; - testLoadAsFile("load as file with relative name in current directory", "/foo/bar/baz.ts", "/foo/bar/foo", "./foo"); + testLoadAsFile( + "load as file with relative name in current directory", + "/foo/bar/baz.ts", + "/foo/bar/foo", + "./foo", + ); testLoadAsFile("load as file with relative name in parent directory", "/foo/bar/baz.ts", "/foo/foo", "../foo"); testLoadAsFile("load as file with name starting with directory seperator", "/foo/bar/baz.ts", "/foo", "/foo"); testLoadAsFile("load as file with name starting with window root", "c:/foo/bar/baz.ts", "c:/foo", "c:/foo"); runBaseline("relative module name as file", baselines); - function testLoadAsFile(scenario: string, containingFileName: string, moduleFileNameNoExt: string, moduleName: string): void { + function testLoadAsFile( + scenario: string, + containingFileName: string, + moduleFileNameNoExt: string, + moduleName: string, + ): void { baselines.push(scenario); for (const ext of autoExtensions) { test(ext, /*hasDirectoryExists*/ true); @@ -82,8 +106,17 @@ describe("unittests:: moduleResolution:: Node module resolution - relative paths function test(ext: string, hasDirectoryExists: boolean) { const containingFile = { name: containingFileName }; const moduleFile = { name: moduleFileNameNoExt + ext }; - baselines.push(`Resolving "${moduleName}" from ${containingFile.name} when module has extension: ${ext}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); - const resolution = ts.nodeModuleNameResolver(moduleName, containingFile.name, {}, createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, moduleFile)); + baselines.push( + `Resolving "${moduleName}" from ${containingFile.name} when module has extension: ${ext}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); + const resolution = ts.nodeModuleNameResolver( + moduleName, + containingFile.name, + {}, + createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, moduleFile), + ); baselines.push(`Resolution:: ${JSON.stringify(resolution, /*replacer*/ undefined, 2)}`); baselines.push(""); } @@ -92,13 +125,25 @@ describe("unittests:: moduleResolution:: Node module resolution - relative paths it("module name as directory - load from 'typings'", () => { const baselines: string[] = []; - testLoadingFromPackageJson("/a/b/c/d.ts", "/a/b/c/bar/package.json", "c/d/e.d.ts", "/a/b/c/bar/c/d/e.d.ts", "./bar"); + testLoadingFromPackageJson( + "/a/b/c/d.ts", + "/a/b/c/bar/package.json", + "c/d/e.d.ts", + "/a/b/c/bar/c/d/e.d.ts", + "./bar", + ); testLoadingFromPackageJson("/a/b/c/d.ts", "/a/bar/package.json", "e.d.ts", "/a/bar/e.d.ts", "../../bar"); testLoadingFromPackageJson("/a/b/c/d.ts", "/bar/package.json", "e.d.ts", "/bar/e.d.ts", "/bar"); testLoadingFromPackageJson("c:/a/b/c/d.ts", "c:/bar/package.json", "e.d.ts", "c:/bar/e.d.ts", "c:/bar"); runBaseline("relative module name as directory", baselines); - function testLoadingFromPackageJson(containingFileName: string, packageJsonFileName: string, fieldRef: string, moduleFileName: string, moduleName: string): void { + function testLoadingFromPackageJson( + containingFileName: string, + packageJsonFileName: string, + fieldRef: string, + moduleFileName: string, + moduleName: string, + ): void { test(/*hasDirectoryExists*/ true); test(/*hasDirectoryExists*/ false); @@ -106,8 +151,17 @@ describe("unittests:: moduleResolution:: Node module resolution - relative paths const containingFile = { name: containingFileName }; const packageJson = { name: packageJsonFileName, content: JSON.stringify({ typings: fieldRef }) }; const moduleFile = { name: moduleFileName }; - baselines.push(`Resolving "${moduleName}" from ${containingFile.name} with typings: ${fieldRef}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); - const resolution = ts.nodeModuleNameResolver(moduleName, containingFile.name, {}, createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, packageJson, moduleFile)); + baselines.push( + `Resolving "${moduleName}" from ${containingFile.name} with typings: ${fieldRef}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); + const resolution = ts.nodeModuleNameResolver( + moduleName, + containingFile.name, + {}, + createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, packageJson, moduleFile), + ); baselines.push(`Resolution:: ${JSON.stringify(resolution, /*replacer*/ undefined, 2)}`); baselines.push(""); } @@ -134,8 +188,24 @@ describe("unittests:: moduleResolution:: Node module resolution - relative paths const indexPath = "/node_modules/b/index.d.ts"; const indexFile = { name: indexPath }; - baselines.push(`Resolving "b" from ${containingFile.name} with typings: ${JSON.stringify(typings)}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); - const resolution = ts.nodeModuleNameResolver("b", containingFile.name, {}, createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, packageJson, moduleFile, indexFile)); + baselines.push( + `Resolving "b" from ${containingFile.name} with typings: ${JSON.stringify(typings)}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); + const resolution = ts.nodeModuleNameResolver( + "b", + containingFile.name, + {}, + createModuleResolutionHost( + baselines, + hasDirectoryExists, + containingFile, + packageJson, + moduleFile, + indexFile, + ), + ); baselines.push(`Resolution:: ${JSON.stringify(resolution, /*replacer*/ undefined, 2)}`); baselines.push(""); } @@ -151,8 +221,17 @@ describe("unittests:: moduleResolution:: Node module resolution - relative paths const containingFile = { name: "/a/b/c.ts" }; const packageJson = { name: "/a/b/foo/package.json", content: JSON.stringify({ main: "/c/d" }) }; const indexFile = { name: "/a/b/foo/index.d.ts" }; - baselines.push(`Resolving "./foo" from ${containingFile.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); - const resolution = ts.nodeModuleNameResolver("./foo", containingFile.name, {}, createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, packageJson, indexFile)); + baselines.push( + `Resolving "./foo" from ${containingFile.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); + const resolution = ts.nodeModuleNameResolver( + "./foo", + containingFile.name, + {}, + createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, packageJson, indexFile), + ); baselines.push(`Resolution:: ${JSON.stringify(resolution, /*replacer*/ undefined, 2)}`); baselines.push(""); } @@ -161,7 +240,7 @@ describe("unittests:: moduleResolution:: Node module resolution - relative paths describe("unittests:: moduleResolution:: Node module resolution - non-relative paths", () => { it("computes correct commonPrefix for moduleName cache", () => { - const resolutionCache = ts.createModuleResolutionCache("/", (f) => f); + const resolutionCache = ts.createModuleResolutionCache("/", f => f); let cache = resolutionCache.getOrCreateCacheForNonRelativeName("a", /*mode*/ undefined); cache.set("/sub", { resolvedModule: { @@ -263,8 +342,17 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p function test(hasDirectoryExists: boolean) { const containingFile = { name: "/a/b/c/d/e.ts" }; const moduleFile = { name: "/a/b/node_modules/foo.ts" }; - baselines.push(`Resolving "foo" from ${containingFile.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); - const resolution = ts.nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, moduleFile)); + baselines.push( + `Resolving "foo" from ${containingFile.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); + const resolution = ts.nodeModuleNameResolver( + "foo", + containingFile.name, + {}, + createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, moduleFile), + ); baselines.push(`Resolution:: ${JSON.stringify(resolution, /*replacer*/ undefined, 2)}`); baselines.push(""); } @@ -279,8 +367,17 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p function test(hasDirectoryExists: boolean) { const containingFile = { name: "/a/b/c/d/e.ts" }; const moduleFile = { name: "/a/b/node_modules/foo.d.ts" }; - baselines.push(`Resolving "foo" from ${containingFile.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); - const resolution = ts.nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, moduleFile)); + baselines.push( + `Resolving "foo" from ${containingFile.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); + const resolution = ts.nodeModuleNameResolver( + "foo", + containingFile.name, + {}, + createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, moduleFile), + ); baselines.push(`Resolution:: ${JSON.stringify(resolution, /*replacer*/ undefined, 2)}`); baselines.push(""); } @@ -295,8 +392,17 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p function test(hasDirectoryExists: boolean) { const containingFile: File = { name: "/a/node_modules/b/c/node_modules/d/e.ts" }; const moduleFile: File = { name: "/a/node_modules/foo/index.d.ts" }; - baselines.push(`Resolving "foo" from ${containingFile.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); - const resolution = ts.nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, moduleFile)); + baselines.push( + `Resolving "foo" from ${containingFile.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); + const resolution = ts.nodeModuleNameResolver( + "foo", + containingFile.name, + {}, + createModuleResolutionHost(baselines, hasDirectoryExists, containingFile, moduleFile), + ); baselines.push(`Resolution:: ${JSON.stringify(resolution, /*replacer*/ undefined, 2)}`); baselines.push(""); } @@ -334,11 +440,11 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p }, { name: "/sub/node_modules/a/package.json", - content: '{"version": "0.0.0", "main": "./index"}' - } + content: '{"version": "0.0.0", "main": "./index"}', + }, ); const compilerOptions: ts.CompilerOptions = { moduleResolution: ts.ModuleResolutionKind.Node10 }; - const cache = ts.createModuleResolutionCache("/", (f) => f); + const cache = ts.createModuleResolutionCache("/", f => f); baselines.push(`Resolving "a" from /sub/dir/foo.ts`); let resolution = ts.resolveModuleName("a", "/sub/dir/foo.ts", compilerOptions, host, cache); baselines.push(`Resolution:: ${JSON.stringify(resolution, /*replacer*/ undefined, 2)}`); @@ -364,7 +470,7 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p { name: "/linked/index.d.ts", symlinks: ["/app/node_modules/linked/index.d.ts"] }, { name: "/app/node_modules/linked/package.json", content: '{"version": "0.0.0", "main": "./index"}' }, ); - const cache = ts.createModuleResolutionCache("/", (f) => f); + const cache = ts.createModuleResolutionCache("/", f => f); const compilerOptions: ts.CompilerOptions = { moduleResolution: ts.ModuleResolutionKind.Node10 }; baselineResolution("/app/src/app.ts"); baselineResolution("/app/lib/main.ts"); @@ -380,7 +486,13 @@ describe("unittests:: moduleResolution:: Node module resolution - non-relative p }); describe("unittests:: moduleResolution:: Relative imports", () => { - function test(scenario: string, filesMapLike: ts.MapLike, currentDirectory: string, rootFiles: string[], relativeNamesToCheck: string[]) { + function test( + scenario: string, + filesMapLike: ts.MapLike, + currentDirectory: string, + rootFiles: string[], + relativeNamesToCheck: string[], + ) { it(scenario, () => { const files = new Map(Object.entries(filesMapLike)); const baselines: string[] = []; @@ -418,38 +530,58 @@ describe("unittests:: moduleResolution:: Relative imports", () => { // try to get file using a relative name for (const relativeFileName of relativeNamesToCheck) { - baselines.push(`getSourceFile by ${relativeFileName}: ${program.getSourceFile(relativeFileName)?.fileName}`); + baselines.push( + `getSourceFile by ${relativeFileName}: ${program.getSourceFile(relativeFileName)?.fileName}`, + ); } runBaseline(scenario, baselines); }); } - test("should file all modules", { - "/a/b/c/first/shared.ts": ` + test( + "should file all modules", + { + "/a/b/c/first/shared.ts": ` class A {} export = A`, - "/a/b/c/first/second/class_a.ts": ` + "/a/b/c/first/second/class_a.ts": ` import Shared = require('../shared'); import C = require('../../third/class_c'); class B {} export = B;`, - "/a/b/c/third/class_c.ts": ` + "/a/b/c/third/class_c.ts": ` import Shared = require('../first/shared'); class C {} export = C; - ` - }, "/a/b/c/first/second", ["class_a.ts"], ["../../../c/third/class_c.ts"]); - - test("should find modules in node_modules", { - "/parent/node_modules/mod/index.d.ts": "export var x", - "/parent/app/myapp.ts": `import {x} from "mod"` - }, "/parent/app", ["myapp.ts"], []); - - test("should find file referenced via absolute and relative names", { - "/a/b/c.ts": `/// `, - "/a/b/b.ts": "var x" - }, "/a/b", ["c.ts", "/a/b/b.ts"], []); + `, + }, + "/a/b/c/first/second", + ["class_a.ts"], + ["../../../c/third/class_c.ts"], + ); + + test( + "should find modules in node_modules", + { + "/parent/node_modules/mod/index.d.ts": "export var x", + "/parent/app/myapp.ts": `import {x} from "mod"`, + }, + "/parent/app", + ["myapp.ts"], + [], + ); + + test( + "should find file referenced via absolute and relative names", + { + "/a/b/c.ts": `/// `, + "/a/b/b.ts": "var x", + }, + "/a/b", + ["c.ts", "/a/b/b.ts"], + [], + ); }); describe("unittests:: moduleResolution:: Files with different casing with forceConsistentCasingInFileNames", () => { @@ -501,7 +633,10 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC readFile: ts.notImplemented, }; const program = ts.createProgram(rootFiles, options, host); - const diagnostics = ts.sortAndDeduplicateDiagnostics([...program.getSemanticDiagnostics(), ...program.getOptionsDiagnostics()]); + const diagnostics = ts.sortAndDeduplicateDiagnostics([ + ...program.getSemanticDiagnostics(), + ...program.getOptionsDiagnostics(), + ]); baselines.push("Diagnostics::"); baselines.push(ts.formatDiagnostics(diagnostics, host), ""); runBaseline(scenario, baselines); @@ -512,7 +647,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC "same file is referenced using absolute and relative names", { "/a/b/c.ts": `/// `, - "/a/b/d.ts": "var x" + "/a/b/d.ts": "var x", }, { module: ts.ModuleKind.AMD }, "/a/b", @@ -523,7 +658,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC "two files used in program differ only in casing (tripleslash references)", { "/a/b/c.ts": `/// `, - "/a/b/d.ts": "var x" + "/a/b/d.ts": "var x", }, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", @@ -534,7 +669,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC "two files used in program differ only in casing (imports)", { "/a/b/c.ts": `import {x} from "D"`, - "/a/b/d.ts": "export var x" + "/a/b/d.ts": "export var x", }, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", @@ -545,7 +680,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC "two files used in program differ only in casing (imports, relative module names)", { "moduleA.ts": `import {x} from "./ModuleB"`, - "moduleB.ts": "export var x" + "moduleB.ts": "export var x", }, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", @@ -557,7 +692,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC { "/a/b/c.ts": `import {x} from "D"`, "/a/b/D.ts": "export var x", - "/a/b/d.ts": "export var y" + "/a/b/d.ts": "export var y", }, { module: ts.ModuleKind.AMD }, "/a/b", @@ -569,7 +704,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC { "moduleA.ts": `import a = require("./ModuleC")`, "moduleB.ts": `import a = require("./moduleC")`, - "moduleC.ts": "export var x" + "moduleC.ts": "export var x", }, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", @@ -585,7 +720,7 @@ describe("unittests:: moduleResolution:: Files with different casing with forceC "/a/B/c/moduleD.ts": ` import a = require("./moduleA"); import b = require("./moduleB"); - ` + `, }, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", @@ -601,7 +736,7 @@ import b = require("./moduleB"); "/a/B/c/moduleD.ts": ` import a = require("./moduleA"); import b = require("./moduleB"); - ` + `, }, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", @@ -623,7 +758,6 @@ import b = require("./moduleB"); }); describe("unittests:: moduleResolution:: baseUrl augmented module resolution", () => { - it("module resolution without path mappings/rootDirs", () => { const baselines: string[] = []; test(/*hasDirectoryExists*/ true); @@ -638,19 +772,31 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( for (const moduleResolution of [ts.ModuleResolutionKind.Node10, ts.ModuleResolutionKind.Classic]) { const options: ts.CompilerOptions = { moduleResolution, baseUrl: "/root" }; { - baselines.push(`Resolving "folder2/file2" from ${file1.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "folder2/file2" from ${file1.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName("folder2/file2", file1.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); } { - baselines.push(`Resolving "./file3" from ${file2.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "./file3" from ${file2.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName("./file3", file2.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); } { - baselines.push(`Resolving "/root/folder1/file1" from ${file2.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "/root/folder1/file1" from ${file2.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName("/root/folder1/file1", file2.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); @@ -670,7 +816,10 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( const main: File = { name: "/root/a/b/main.ts" }; const m1: File = { name: "/root/m1.ts" }; // load file as module const m2: File = { name: "/root/m2/index.d.ts" }; // load folder as module - const m3: File = { name: "/root/m3/package.json", content: JSON.stringify({ typings: "dist/typings.d.ts" }) }; + const m3: File = { + name: "/root/m3/package.json", + content: JSON.stringify({ typings: "dist/typings.d.ts" }), + }; const m3Typings: File = { name: "/root/m3/dist/typings.d.ts" }; const m4: File = { name: "/root/node_modules/m4.ts" }; // fallback to node @@ -683,7 +832,11 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( check("m4", main); function check(name: string, caller: File) { - baselines.push(`Resolving "${name}" from ${caller.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "${name}" from ${caller.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName(name, caller.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); @@ -702,14 +855,22 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( const m1: File = { name: "/root/x/m1.ts" }; // load from base url const m2: File = { name: "/m2.ts" }; // fallback to classic - const options: ts.CompilerOptions = { moduleResolution: ts.ModuleResolutionKind.Classic, baseUrl: "/root/x", jsx: ts.JsxEmit.React }; + const options: ts.CompilerOptions = { + moduleResolution: ts.ModuleResolutionKind.Classic, + baseUrl: "/root/x", + jsx: ts.JsxEmit.React, + }; const host = createModuleResolutionHost(baselines, hasDirectoryExists, main, m1, m2); check("m1", main); check("m2", main); function check(name: string, caller: File) { - baselines.push(`Resolving "${name}" from ${caller.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "${name}" from ${caller.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName(name, caller.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); @@ -729,11 +890,24 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( const file1: File = { name: "/root/folder1/file1.ts" }; const file2: File = { name: "/root/generated/folder1/file2.ts" }; // load remapped file as module const file3: File = { name: "/root/generated/folder2/file3/index.d.ts" }; // load folder a module - const file4Typings: File = { name: "/root/generated/folder2/file4/package.json", content: JSON.stringify({ typings: "dist/types.d.ts" }) }; + const file4Typings: File = { + name: "/root/generated/folder2/file4/package.json", + content: JSON.stringify({ typings: "dist/types.d.ts" }), + }; const file4: File = { name: "/root/generated/folder2/file4/dist/types.d.ts" }; // load file pointed by typings const file5: File = { name: "/root/someanotherfolder/file5/index.d.ts" }; // load remapped module from folder const file6: File = { name: "/root/node_modules/file6.ts" }; // fallback to node - const host = createModuleResolutionHost(baselines, hasDirectoryExists, file1, file2, file3, file4, file4Typings, file5, file6); + const host = createModuleResolutionHost( + baselines, + hasDirectoryExists, + file1, + file2, + file3, + file4, + file4Typings, + file5, + file6, + ); const options: ts.CompilerOptions = { moduleResolution: ts.ModuleResolutionKind.Node10, @@ -742,15 +916,15 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( paths: { "*": [ "*", - "generated/*" + "generated/*", ], "somefolder/*": [ - "someanotherfolder/*" + "someanotherfolder/*", ], "/rooted/*": [ - "generated/*" - ] - } + "generated/*", + ], + }, }; check("folder1/file1"); check("folder1/file2"); @@ -761,7 +935,11 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( check("file6"); function check(name: string) { - baselines.push(`Resolving "${name}" from ${main.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "${name}" from ${main.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName(name, main.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); @@ -769,7 +947,7 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( } }); - it ("classic + baseUrl + path mappings", () => { + it("classic + baseUrl + path mappings", () => { const baselines: string[] = []; // classic mode does not use directoryExists test(/*hasDirectoryExists*/ false); @@ -790,15 +968,15 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( paths: { "*": [ "*", - "generated/*" + "generated/*", ], "somefolder/*": [ - "someanotherfolder/*" + "someanotherfolder/*", ], "/rooted/*": [ - "generated/*" - ] - } + "generated/*", + ], + }, }; check("folder1/file1"); check("folder1/file2"); @@ -806,7 +984,11 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( check("folder1/file3"); function check(name: string) { - baselines.push(`Resolving "${name}" from ${main.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "${name}" from ${main.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName(name, main.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); @@ -814,7 +996,7 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( } }); - it ("node + rootDirs", () => { + it("node + rootDirs", () => { const baselines: string[] = []; test(/*hasDirectoryExists*/ true); test(/*hasDirectoryExists*/ false); @@ -830,15 +1012,19 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( moduleResolution: ts.ModuleResolutionKind.Node10, rootDirs: [ "/root", - "/root/generated/" - ] + "/root/generated/", + ], }; check("./file2", file1); check("../folder1/file1", file3); check("../folder1/file1_1", file3); function check(name: string, container: File) { - baselines.push(`Resolving "${name}" from ${container.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "${name}" from ${container.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName(name, container.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); @@ -846,7 +1032,7 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( } }); - it ("classic + rootDirs", () => { + it("classic + rootDirs", () => { const baselines: string[] = []; test(/*hasDirectoryExists*/ false); runBaseline("classic rootDirs", baselines); @@ -862,15 +1048,19 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( jsx: ts.JsxEmit.React, rootDirs: [ "/root", - "/root/generated/" - ] + "/root/generated/", + ], }; check("./file2", file1); check("../folder1/file1", file3); check("folder1/file1_1", file3); function check(name: string, container: File) { - baselines.push(`Resolving "${name}" from ${container.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "${name}" from ${container.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName(name, container.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); @@ -878,7 +1068,7 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( } }); - it ("nested node module", () => { + it("nested node module", () => { const baselines: string[] = []; test(/*hasDirectoryExists*/ true); test(/*hasDirectoryExists*/ false); @@ -886,17 +1076,24 @@ describe("unittests:: moduleResolution:: baseUrl augmented module resolution", ( function test(hasDirectoryExists: boolean) { const app: File = { name: "/root/src/app.ts" }; - const libsPackage: File = { name: "/root/src/libs/guid/package.json", content: JSON.stringify({ typings: "dist/guid.d.ts" }) }; + const libsPackage: File = { + name: "/root/src/libs/guid/package.json", + content: JSON.stringify({ typings: "dist/guid.d.ts" }), + }; const libsTypings: File = { name: "/root/src/libs/guid/dist/guid.d.ts" }; const host = createModuleResolutionHost(baselines, hasDirectoryExists, app, libsPackage, libsTypings); const options: ts.CompilerOptions = { moduleResolution: ts.ModuleResolutionKind.Node10, baseUrl: "/root", paths: { - "libs/guid": [ "src/libs/guid" ] - } + "libs/guid": ["src/libs/guid"], + }, }; - baselines.push(`Resolving "libs/guid" from ${app.name}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); + baselines.push( + `Resolving "libs/guid" from ${app.name}${ + hasDirectoryExists ? "" : " with host that doesnt have directoryExists" + }`, + ); const result = ts.resolveModuleName("libs/guid", app.name, options, host); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); @@ -909,25 +1106,63 @@ describe("unittests:: moduleResolution:: ModuleResolutionHost.directoryExists", const host: ts.ModuleResolutionHost = { readFile: ts.notImplemented, fileExists: ts.notImplemented, - directoryExists: _ => false + directoryExists: _ => false, }; - const result = ts.resolveModuleName("someName", "/a/b/c/d", { moduleResolution: ts.ModuleResolutionKind.Node10 }, host); + const result = ts.resolveModuleName("someName", "/a/b/c/d", { + moduleResolution: ts.ModuleResolutionKind.Node10, + }, host); assert(!result.resolvedModule); }); }); describe("unittests:: moduleResolution:: Type reference directive resolution: ", () => { - function testWorker(baselines: string[], hasDirectoryExists: boolean, typesRoot: string | undefined, typeDirective: string, initialFile: File, targetFile: File, ...otherFiles: File[]) { - const host = createModuleResolutionHost(baselines, hasDirectoryExists, ...[initialFile, targetFile].concat(...otherFiles)); - baselines.push(`Resolving "${typeDirective}" from ${initialFile.name} typesRoots: ${typesRoot ? `[${typesRoot}]` : undefined}${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`); - const result = ts.resolveTypeReferenceDirective(typeDirective, initialFile.name, typesRoot ? { typeRoots: [typesRoot] } : {}, host); + function testWorker( + baselines: string[], + hasDirectoryExists: boolean, + typesRoot: string | undefined, + typeDirective: string, + initialFile: File, + targetFile: File, + ...otherFiles: File[] + ) { + const host = createModuleResolutionHost( + baselines, + hasDirectoryExists, + ...[initialFile, targetFile].concat(...otherFiles), + ); + baselines.push( + `Resolving "${typeDirective}" from ${initialFile.name} typesRoots: ${ + typesRoot ? `[${typesRoot}]` : undefined + }${hasDirectoryExists ? "" : " with host that doesnt have directoryExists"}`, + ); + const result = ts.resolveTypeReferenceDirective( + typeDirective, + initialFile.name, + typesRoot ? { typeRoots: [typesRoot] } : {}, + host, + ); baselines.push(`Resolution:: ${JSON.stringify(result, /*replacer*/ undefined, 2)}`); baselines.push(""); } - function test(baselines: string[], typesRoot: string, typeDirective: string, initialFile: File, targetFile: File, ...otherFiles: File[]) { - testWorker(baselines, /*hasDirectoryExists*/ false, typesRoot, typeDirective, initialFile, targetFile, ...otherFiles); + function test( + baselines: string[], + typesRoot: string, + typeDirective: string, + initialFile: File, + targetFile: File, + ...otherFiles: File[] + ) { + testWorker( + baselines, + /*hasDirectoryExists*/ false, + typesRoot, + typeDirective, + initialFile, + targetFile, + ...otherFiles, + ); } it("Can be resolved from primary location", () => { @@ -935,35 +1170,44 @@ describe("unittests:: moduleResolution:: Type reference directive resolution: ", { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/types/lib/index.d.ts" }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2); + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/types/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/src/types/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2, packageFile); + const packageFile = { + name: "/root/src/types/lib/package.json", + content: JSON.stringify({ types: "typings/lib.d.ts" }), + }; + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2, packageFile); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/node_modules/lib/index.d.ts" }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2); + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/node_modules/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/src/node_modules/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2, packageFile); + const packageFile = { + name: "/root/src/node_modules/lib/package.json", + content: JSON.stringify({ types: "typings/lib.d.ts" }), + }; + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2, packageFile); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/node_modules/@types/lib/index.d.ts" }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2); + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/src/node_modules/@types/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/src/node_modules/@types/lib/package.json", content: JSON.stringify({ types: "typings/lib.d.ts" }) }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2, packageFile); + const packageFile = { + name: "/root/src/node_modules/@types/lib/package.json", + content: JSON.stringify({ types: "typings/lib.d.ts" }), + }; + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2, packageFile); } runBaseline("type reference from primary location", baselines); }); @@ -972,29 +1216,35 @@ describe("unittests:: moduleResolution:: Type reference directive resolution: ", { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/node_modules/lib.d.ts" }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2); + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/node_modules/lib/index.d.ts" }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2); + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/node_modules/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/node_modules/lib/package.json", content: JSON.stringify({ typings: "typings/lib.d.ts" }) }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2, packageFile); + const packageFile = { + name: "/root/node_modules/lib/package.json", + content: JSON.stringify({ typings: "typings/lib.d.ts" }), + }; + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2, packageFile); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/node_modules/@types/lib/index.d.ts" }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2); + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2); } { const f1 = { name: "/root/src/app.ts" }; const f2 = { name: "/root/node_modules/@types/lib/typings/lib.d.ts" }; - const packageFile = { name: "/root/node_modules/@types/lib/package.json", content: JSON.stringify({ typings: "typings/lib.d.ts" }) }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2, packageFile); + const packageFile = { + name: "/root/node_modules/@types/lib/package.json", + content: JSON.stringify({ typings: "typings/lib.d.ts" }), + }; + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2, packageFile); } runBaseline("type reference from secondary location", baselines); }); @@ -1003,7 +1253,7 @@ describe("unittests:: moduleResolution:: Type reference directive resolution: ", const f1 = { name: "/root/src/a/b/c/app.ts" }; const f2 = { name: "/root/src/types/lib/index.d.ts" }; const f3 = { name: "/root/src/a/b/node_modules/lib.d.ts" }; - test(baselines, /*typesRoot*/"/root/src/types", /* typeDirective */"lib", f1, f2, f3); + test(baselines, /*typesRoot*/ "/root/src/types", /* typeDirective */ "lib", f1, f2, f3); runBaseline("type reference overrides secondary location", baselines); }); it("Reused program keeps errors", () => { @@ -1016,7 +1266,10 @@ describe("unittests:: moduleResolution:: Type reference directive resolution: ", files.forEach(file => baselines.push(`//// [${file.name}]\n${file.content || ""}`, "")); const names = ts.map(files, f => f.name); - const sourceFiles = ts.arrayToMap(ts.map(files, f => ts.createSourceFile(f.name, f.content, ts.ScriptTarget.ES2015)), f => f.fileName); + const sourceFiles = ts.arrayToMap( + ts.map(files, f => ts.createSourceFile(f.name, f.content, ts.ScriptTarget.ES2015)), + f => f.fileName, + ); const compilerHost: ts.CompilerHost = { fileExists: fileName => sourceFiles.has(fileName), getSourceFile: fileName => sourceFiles.get(fileName), @@ -1053,7 +1306,7 @@ describe("unittests:: moduleResolution:: Type reference directive resolution: ", declare module "fs-client" { import { Stat } from "fs"; export function foo(): Stat; - }` + }`, }; const file = ts.createSourceFile(f.name, f.content, ts.ScriptTarget.ES2015); const compilerHost: ts.CompilerHost = { @@ -1082,7 +1335,7 @@ describe("unittests:: moduleResolution:: Type reference directive resolution: ", declare module "fs-client" { import { Stat } from "fs"; export function foo(): Stat; - }` + }`, }; const file = ts.createSourceFile(f.name, f.content, ts.ScriptTarget.ES2015); const compilerHost: ts.CompilerHost = { @@ -1099,7 +1352,7 @@ describe("unittests:: moduleResolution:: Type reference directive resolution: ", resolveModuleNames(moduleNames: string[], _containingFile: string) { assert.deepEqual(moduleNames, ["fs"]); return [undefined!]; // TODO: GH#18217 - } + }, }; ts.createProgram([f.name], {}, compilerHost); }); @@ -1107,8 +1360,22 @@ describe("unittests:: moduleResolution:: Type reference directive resolution: ", const baselines: string[] = []; const initialFile = { name: "/root/src/background/app.ts" }; const targetFile = { name: "/root/src/typedefs/filesystem.d.ts" }; - testWorker(baselines, /*hasDirectoryExists*/ true, /*typesRoot*/ undefined, /*typeDirective*/ "../typedefs/filesystem", initialFile, targetFile); - testWorker(baselines, /*hasDirectoryExists*/ false, /*typesRoot*/ undefined, /*typeDirective*/ "../typedefs/filesystem", initialFile, targetFile); + testWorker( + baselines, + /*hasDirectoryExists*/ true, + /*typesRoot*/ undefined, + /*typeDirective*/ "../typedefs/filesystem", + initialFile, + targetFile, + ); + testWorker( + baselines, + /*hasDirectoryExists*/ false, + /*typesRoot*/ undefined, + /*typeDirective*/ "../typedefs/filesystem", + initialFile, + targetFile, + ); runBaseline("typeReferenceDirective is relative and in a sibling folder", baselines); }); }); diff --git a/src/testRunner/unittests/parsePseudoBigInt.ts b/src/testRunner/unittests/parsePseudoBigInt.ts index 10f5e098362f9..52e3f835ca2f8 100644 --- a/src/testRunner/unittests/parsePseudoBigInt.ts +++ b/src/testRunner/unittests/parsePseudoBigInt.ts @@ -12,7 +12,7 @@ describe("unittests:: BigInt literal base conversions", () => { for (let leadingZeros = 0; leadingZeros < 10; leadingZeros++) { assert.equal( ts.parsePseudoBigInt("0".repeat(leadingZeros) + testNumber + "n"), - String(testNumber) + String(testNumber), ); } } @@ -52,19 +52,21 @@ describe("unittests:: BigInt literal base conversions", () => { it("can parse large literals", () => { assert.equal( ts.parsePseudoBigInt("123456789012345678901234567890n"), - "123456789012345678901234567890" + "123456789012345678901234567890", ); assert.equal( - ts.parsePseudoBigInt("0b1100011101110100100001111111101101100001101110011111000001110111001001110001111110000101011010010n"), - "123456789012345678901234567890" + ts.parsePseudoBigInt( + "0b1100011101110100100001111111101101100001101110011111000001110111001001110001111110000101011010010n", + ), + "123456789012345678901234567890", ); assert.equal( ts.parsePseudoBigInt("0o143564417755415637016711617605322n"), - "123456789012345678901234567890" + "123456789012345678901234567890", ); assert.equal( ts.parsePseudoBigInt("0x18ee90ff6c373e0ee4e3f0ad2n"), - "123456789012345678901234567890" + "123456789012345678901234567890", ); }); }); diff --git a/src/testRunner/unittests/paths.ts b/src/testRunner/unittests/paths.ts index fcd8de8ebee75..8bc2567eb24d7 100644 --- a/src/testRunner/unittests/paths.ts +++ b/src/testRunner/unittests/paths.ts @@ -285,28 +285,40 @@ describe("unittests:: core paths", () => { assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/", "file:///a", /*ignoreCase*/ false), ""); assert.strictEqual(ts.getRelativePathFromDirectory("file:///a", "file:///", /*ignoreCase*/ false), ".."); assert.strictEqual(ts.getRelativePathFromDirectory("file:///a", "file:///b", /*ignoreCase*/ false), "../b"); - assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/b", "file:///b", /*ignoreCase*/ false), "../../b"); - assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/b/c", "file:///b", /*ignoreCase*/ false), "../../../b"); - assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/b/c", "file:///b/c", /*ignoreCase*/ false), "../../../b/c"); + assert.strictEqual( + ts.getRelativePathFromDirectory("file:///a/b", "file:///b", /*ignoreCase*/ false), + "../../b", + ); + assert.strictEqual( + ts.getRelativePathFromDirectory("file:///a/b/c", "file:///b", /*ignoreCase*/ false), + "../../../b", + ); + assert.strictEqual( + ts.getRelativePathFromDirectory("file:///a/b/c", "file:///b/c", /*ignoreCase*/ false), + "../../../b/c", + ); assert.strictEqual(ts.getRelativePathFromDirectory("file:///a/b/c", "file:///a/b", /*ignoreCase*/ false), ".."); - assert.strictEqual(ts.getRelativePathFromDirectory("file:///c:", "file:///d:", /*ignoreCase*/ false), "file:///d:/"); + assert.strictEqual( + ts.getRelativePathFromDirectory("file:///c:", "file:///d:", /*ignoreCase*/ false), + "file:///d:/", + ); }); it("toFileNameLowerCase", () => { assert.strictEqual( ts.toFileNameLowerCase("/user/UserName/projects/Project/file.ts"), - "/user/username/projects/project/file.ts" + "/user/username/projects/project/file.ts", ); assert.strictEqual( ts.toFileNameLowerCase("/user/UserName/projects/projectß/file.ts"), - "/user/username/projects/projectß/file.ts" + "/user/username/projects/projectß/file.ts", ); assert.strictEqual( ts.toFileNameLowerCase("/user/UserName/projects/İproject/file.ts"), - "/user/username/projects/İproject/file.ts" + "/user/username/projects/İproject/file.ts", ); assert.strictEqual( ts.toFileNameLowerCase("/user/UserName/projects/ı/file.ts"), - "/user/username/projects/ı/file.ts" + "/user/username/projects/ı/file.ts", ); }); }); diff --git a/src/testRunner/unittests/printer.ts b/src/testRunner/unittests/printer.ts index 1ac368226f435..22843fe13d1dc 100644 --- a/src/testRunner/unittests/printer.ts +++ b/src/testRunner/unittests/printer.ts @@ -5,10 +5,16 @@ import * as vfs from "../_namespaces/vfs"; describe("unittests:: PrinterAPI", () => { function makePrintsCorrectly(prefix: string) { - return function printsCorrectly(name: string, options: ts.PrinterOptions, printCallback: (printer: ts.Printer) => string) { + return function printsCorrectly( + name: string, + options: ts.PrinterOptions, + printCallback: (printer: ts.Printer) => string, + ) { it(name, () => { - Harness.Baseline.runBaseline(`printerApi/${prefix}.${name}.js`, - printCallback(ts.createPrinter({ newLine: ts.NewLineKind.CarriageReturnLineFeed, ...options }))); + Harness.Baseline.runBaseline( + `printerApi/${prefix}.${name}.js`, + printCallback(ts.createPrinter({ newLine: ts.NewLineKind.CarriageReturnLineFeed, ...options })), + ); }); }; } @@ -19,7 +25,9 @@ describe("unittests:: PrinterAPI", () => { // Avoid eagerly creating the sourceFile so that `createSourceFile` doesn't run unless one of these tests is run. let sourceFile: ts.SourceFile; before(() => { - sourceFile = ts.createSourceFile("source.ts", ` + sourceFile = ts.createSourceFile( + "source.ts", + ` interface A { // comment1 readonly prop?: T; @@ -53,7 +61,9 @@ describe("unittests:: PrinterAPI", () => { // comment10 function functionWithDefaultArgValue(argument: string = "defaultValue"): void { } - `, ts.ScriptTarget.ES2015); + `, + ts.ScriptTarget.ES2015, + ); }); printsCorrectly("default", {}, printer => printer.printFile(sourceFile)); printsCorrectly("removeComments", { removeComments: true }, printer => printer.printFile(sourceFile)); @@ -61,29 +71,52 @@ describe("unittests:: PrinterAPI", () => { // https://github.com/microsoft/TypeScript/issues/14948 // eslint-disable-next-line no-template-curly-in-string - printsCorrectly("templateLiteral", {}, printer => printer.printFile(ts.createSourceFile("source.ts", "let greeting = `Hi ${name}, how are you?`;", ts.ScriptTarget.ES2017))); + printsCorrectly( + "templateLiteral", + {}, + printer => + printer.printFile( + ts.createSourceFile( + "source.ts", + "let greeting = `Hi ${name}, how are you?`;", + ts.ScriptTarget.ES2017, + ), + ), + ); // https://github.com/microsoft/TypeScript/issues/18071 - printsCorrectly("regularExpressionLiteral", {}, printer => printer.printFile(ts.createSourceFile("source.ts", "let regex = /abc/;", ts.ScriptTarget.ES2017))); + printsCorrectly( + "regularExpressionLiteral", + {}, + printer => + printer.printFile(ts.createSourceFile("source.ts", "let regex = /abc/;", ts.ScriptTarget.ES2017)), + ); // https://github.com/microsoft/TypeScript/issues/22239 - printsCorrectly("importStatementRemoveComments", { removeComments: true }, printer => printer.printFile(ts.createSourceFile("source.ts", "import {foo} from 'foo';", ts.ScriptTarget.ESNext))); - printsCorrectly("classHeritageClauses", {}, printer => printer.printFile(ts.createSourceFile( - "source.ts", - `class A extends B implements C implements D {}`, - ts.ScriptTarget.ES2017 - ))); + printsCorrectly( + "importStatementRemoveComments", + { removeComments: true }, + printer => + printer.printFile(ts.createSourceFile("source.ts", "import {foo} from 'foo';", ts.ScriptTarget.ESNext)), + ); + printsCorrectly("classHeritageClauses", {}, printer => + printer.printFile(ts.createSourceFile( + "source.ts", + `class A extends B implements C implements D {}`, + ts.ScriptTarget.ES2017, + ))); // https://github.com/microsoft/TypeScript/issues/35093 - printsCorrectly("definiteAssignmentAssertions", {}, printer => printer.printFile(ts.createSourceFile( - "source.ts", - `class A { + printsCorrectly("definiteAssignmentAssertions", {}, printer => + printer.printFile(ts.createSourceFile( + "source.ts", + `class A { prop!: string; } let x!: string;`, - ts.ScriptTarget.ES2017 - ))); + ts.ScriptTarget.ES2017, + ))); // https://github.com/microsoft/TypeScript/issues/35054 printsCorrectly("jsx attribute escaping", {}, printer => { @@ -92,31 +125,36 @@ describe("unittests:: PrinterAPI", () => { String.raw`
`, ts.ScriptTarget.ESNext, /*setParentNodes*/ undefined, - ts.ScriptKind.TSX + ts.ScriptKind.TSX, )); }); }); describe("No duplicate ref directives when emiting .d.ts->.d.ts", () => { it("without statements", () => { - const host = new fakes.CompilerHost(new vfs.FileSystem(/*ignoreCase*/ true, { - files: { - "/test.d.ts": `/// \n/// \n/// { - const host = new fakes.CompilerHost(new vfs.FileSystem(/*ignoreCase*/ true, { - files: { - "/test.d.ts": `/// \n/// \n/// { let bundle: ts.Bundle; before(() => { bundle = ts.factory.createBundle([ - ts.createSourceFile("a.ts", ` + ts.createSourceFile( + "a.ts", + ` /*! [a.ts] */ // comment0 const a = 1; - `, ts.ScriptTarget.ES2015), - ts.createSourceFile("b.ts", ` + `, + ts.ScriptTarget.ES2015, + ), + ts.createSourceFile( + "b.ts", + ` /*! [b.ts] */ // comment1 const b = 2; - `, ts.ScriptTarget.ES2015) + `, + ts.ScriptTarget.ES2015, + ), ]); }); printsCorrectly("default", {}, printer => printer.printBundle(bundle)); @@ -149,169 +195,190 @@ describe("unittests:: PrinterAPI", () => { describe("printNode", () => { const printsCorrectly = makePrintsCorrectly("printsNodeCorrectly"); - printsCorrectly("class", {}, printer => printer.printNode( - ts.EmitHint.Unspecified, - ts.factory.createClassDeclaration( - /*modifiers*/ undefined, - /*name*/ ts.factory.createIdentifier("C"), - /*typeParameters*/ undefined, - /*heritageClauses*/ undefined, - [ts.factory.createPropertyDeclaration( - ts.factory.createNodeArray([ts.factory.createToken(ts.SyntaxKind.PublicKeyword)]), - ts.factory.createIdentifier("prop"), - /*questionOrExclamationToken*/ undefined, - /*type*/ undefined, - /*initializer*/ undefined - )] - ), - ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015) - )); - - printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode( - ts.EmitHint.Unspecified, - ts.factory.createNamespaceExportDeclaration("B"), - ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015) - )); - - printsCorrectly("newExpressionWithPropertyAccessOnCallExpression", {}, printer => printer.printNode( - ts.EmitHint.Unspecified, - ts.factory.createNewExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createCallExpression(ts.factory.createIdentifier("f"), /*typeArguments*/ undefined, /*argumentsArray*/ undefined), - "x"), - /*typeArguments*/ undefined, - /*argumentsArray*/ undefined - ), - ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext)) - ); - - printsCorrectly("newExpressionOnConditionalExpression", {}, printer => printer.printNode( - ts.EmitHint.Unspecified, - ts.factory.createNewExpression( - ts.factory.createConditionalExpression( - ts.factory.createIdentifier("x"), ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createIdentifier("y"), ts.factory.createToken(ts.SyntaxKind.ColonToken), - ts.factory.createIdentifier("z")), - /*typeArguments*/ undefined, - /*argumentsArray*/ undefined - ), - ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext)) - ); - - printsCorrectly("emptyGlobalAugmentation", {}, printer => printer.printNode( - ts.EmitHint.Unspecified, - ts.factory.createModuleDeclaration( - /*modifiers*/ [ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)], - ts.factory.createIdentifier("global"), - ts.factory.createModuleBlock(ts.emptyArray), - ts.NodeFlags.GlobalAugmentation), - ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015) - )); + printsCorrectly("class", {}, printer => + printer.printNode( + ts.EmitHint.Unspecified, + ts.factory.createClassDeclaration( + /*modifiers*/ undefined, + /*name*/ ts.factory.createIdentifier("C"), + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [ts.factory.createPropertyDeclaration( + ts.factory.createNodeArray([ts.factory.createToken(ts.SyntaxKind.PublicKeyword)]), + ts.factory.createIdentifier("prop"), + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined, + )], + ), + ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015), + )); - printsCorrectly("emptyGlobalAugmentationWithNoDeclareKeyword", {}, printer => printer.printNode( - ts.EmitHint.Unspecified, - ts.factory.createModuleDeclaration( - /*modifiers*/ undefined, - ts.factory.createIdentifier("global"), - ts.factory.createModuleBlock(ts.emptyArray), - ts.NodeFlags.GlobalAugmentation), - ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015) - )); + printsCorrectly("namespaceExportDeclaration", {}, printer => + printer.printNode( + ts.EmitHint.Unspecified, + ts.factory.createNamespaceExportDeclaration("B"), + ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015), + )); - // https://github.com/Microsoft/TypeScript/issues/15971 - printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode( - ts.EmitHint.Unspecified, - ts.factory.createClassDeclaration( - /*modifiers*/ [ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)], - /*name*/ ts.factory.createIdentifier("X"), - /*typeParameters*/ undefined, - /*heritageClauses*/ undefined, - [ - ts.factory.createMethodDeclaration( - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - /*name*/ ts.factory.createIdentifier("method"), - /*questionToken*/ ts.factory.createToken(ts.SyntaxKind.QuestionToken), - /*typeParameters*/ undefined, - [], - /*type*/ ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - /*body*/ undefined - ), - ts.factory.createPropertyDeclaration( - /*modifiers*/ undefined, - /*name*/ ts.factory.createIdentifier("property"), - /*questionToken*/ ts.factory.createToken(ts.SyntaxKind.QuestionToken), - /*type*/ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), - /*initializer*/ undefined + printsCorrectly("newExpressionWithPropertyAccessOnCallExpression", {}, printer => + printer.printNode( + ts.EmitHint.Unspecified, + ts.factory.createNewExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createCallExpression( + ts.factory.createIdentifier("f"), + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, + ), + "x", ), - ] - ), - ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015) - )); - - // https://github.com/Microsoft/TypeScript/issues/15651 - printsCorrectly("functionTypes", {}, printer => printer.printNode( - ts.EmitHint.Unspecified, - ts.setEmitFlags(ts.factory.createTupleTypeNode([ - ts.factory.createFunctionTypeNode( - /*typeParameters*/ undefined, - [ts.factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - ts.factory.createIdentifier("args") - )], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, ), - ts.factory.createFunctionTypeNode( - [ts.factory.createTypeParameterDeclaration(/*modifiers*/ undefined, "T")], - [ts.factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - ts.factory.createIdentifier("args") - )], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext), + )); + + printsCorrectly("newExpressionOnConditionalExpression", {}, printer => + printer.printNode( + ts.EmitHint.Unspecified, + ts.factory.createNewExpression( + ts.factory.createConditionalExpression( + ts.factory.createIdentifier("x"), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + ts.factory.createIdentifier("y"), + ts.factory.createToken(ts.SyntaxKind.ColonToken), + ts.factory.createIdentifier("z"), + ), + /*typeArguments*/ undefined, + /*argumentsArray*/ undefined, ), - ts.factory.createFunctionTypeNode( - /*typeParameters*/ undefined, - [ts.factory.createParameterDeclaration( - /*modifiers*/ undefined, - ts.factory.createToken(ts.SyntaxKind.DotDotDotToken), - ts.factory.createIdentifier("args") - )], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ts.createSourceFile("source.ts", "", ts.ScriptTarget.ESNext), + )); + + printsCorrectly("emptyGlobalAugmentation", {}, printer => + printer.printNode( + ts.EmitHint.Unspecified, + ts.factory.createModuleDeclaration( + /*modifiers*/ [ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)], + ts.factory.createIdentifier("global"), + ts.factory.createModuleBlock(ts.emptyArray), + ts.NodeFlags.GlobalAugmentation, ), - ts.factory.createFunctionTypeNode( - /*typeParameters*/ undefined, - [ts.factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - ts.factory.createIdentifier("args"), - ts.factory.createToken(ts.SyntaxKind.QuestionToken) - )], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015), + )); + + printsCorrectly("emptyGlobalAugmentationWithNoDeclareKeyword", {}, printer => + printer.printNode( + ts.EmitHint.Unspecified, + ts.factory.createModuleDeclaration( + /*modifiers*/ undefined, + ts.factory.createIdentifier("global"), + ts.factory.createModuleBlock(ts.emptyArray), + ts.NodeFlags.GlobalAugmentation, ), - ts.factory.createFunctionTypeNode( + ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015), + )); + + // https://github.com/Microsoft/TypeScript/issues/15971 + printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => + printer.printNode( + ts.EmitHint.Unspecified, + ts.factory.createClassDeclaration( + /*modifiers*/ [ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)], + /*name*/ ts.factory.createIdentifier("X"), /*typeParameters*/ undefined, - [ts.factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - ts.factory.createIdentifier("args"), - /*questionToken*/ undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - )], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + /*heritageClauses*/ undefined, + [ + ts.factory.createMethodDeclaration( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + /*name*/ ts.factory.createIdentifier("method"), + /*questionToken*/ ts.factory.createToken(ts.SyntaxKind.QuestionToken), + /*typeParameters*/ undefined, + [], + /*type*/ ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), + /*body*/ undefined, + ), + ts.factory.createPropertyDeclaration( + /*modifiers*/ undefined, + /*name*/ ts.factory.createIdentifier("property"), + /*questionToken*/ ts.factory.createToken(ts.SyntaxKind.QuestionToken), + /*type*/ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + /*initializer*/ undefined, + ), + ], ), - ts.factory.createFunctionTypeNode( - /*typeParameters*/ undefined, - [ts.factory.createParameterDeclaration( - /*modifiers*/ undefined, - /*dotDotDotToken*/ undefined, - ts.factory.createObjectBindingPattern([]) - )], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015), + )); + + // https://github.com/Microsoft/TypeScript/issues/15651 + printsCorrectly("functionTypes", {}, printer => + printer.printNode( + ts.EmitHint.Unspecified, + ts.setEmitFlags( + ts.factory.createTupleTypeNode([ + ts.factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + [ts.factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + ts.factory.createIdentifier("args"), + )], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + ), + ts.factory.createFunctionTypeNode( + [ts.factory.createTypeParameterDeclaration(/*modifiers*/ undefined, "T")], + [ts.factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + ts.factory.createIdentifier("args"), + )], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + ), + ts.factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + [ts.factory.createParameterDeclaration( + /*modifiers*/ undefined, + ts.factory.createToken(ts.SyntaxKind.DotDotDotToken), + ts.factory.createIdentifier("args"), + )], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + ), + ts.factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + [ts.factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + ts.factory.createIdentifier("args"), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + )], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + ), + ts.factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + [ts.factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + ts.factory.createIdentifier("args"), + /*questionToken*/ undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + )], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + ), + ts.factory.createFunctionTypeNode( + /*typeParameters*/ undefined, + [ts.factory.createParameterDeclaration( + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + ts.factory.createObjectBindingPattern([]), + )], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + ), + ]), + ts.EmitFlags.SingleLine, ), - ]), ts.EmitFlags.SingleLine), - ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015) - )); + ts.createSourceFile("source.ts", "", ts.ScriptTarget.ES2015), + )); }); }); diff --git a/src/testRunner/unittests/programApi.ts b/src/testRunner/unittests/programApi.ts index 29ee633f7d05e..f21aba788c7f9 100644 --- a/src/testRunner/unittests/programApi.ts +++ b/src/testRunner/unittests/programApi.ts @@ -9,7 +9,12 @@ function verifyMissingFilePaths(missingPaths: readonly ts.Path[], expected: read const map = new Set(expected); for (const missing of missingPaths) { const value = map.has(missing); - assert.isTrue(value, `${missing} to be ${value === undefined ? "not present" : "present only once"}, in actual: ${missingPaths} expected: ${expected}`); + assert.isTrue( + value, + `${missing} to be ${ + value === undefined ? "not present" : "present only once" + }, in actual: ${missingPaths} expected: ${expected}`, + ); map.delete(missing); } const notFound = ts.arrayFrom(ts.mapDefinedIterator(map.keys(), k => map.has(k) ? k : undefined)); @@ -17,7 +22,6 @@ function verifyMissingFilePaths(missingPaths: readonly ts.Path[], expected: read } describe("unittests:: programApi:: Program.getMissingFilePaths", () => { - const options: ts.CompilerOptions = { noLib: true, }; @@ -30,19 +34,22 @@ describe("unittests:: programApi:: Program.getMissingFilePaths", () => { const referenceFileName = "reference.ts"; const referenceFileRelativePath = "./" + referenceFileName; - const referenceFile = new documents.TextDocument(referenceFileName, - "/// \n" + // Absolute - "/// \n" + // Relative - "/// \n" + // Unqualified - "/// \n" // No extension + const referenceFile = new documents.TextDocument( + referenceFileName, + '/// \n' // Absolute + + '/// \n' // Relative + + '/// \n' // Unqualified + + '/// \n', // No extension ); const testCompilerHost = new fakes.CompilerHost( vfs.createFromFileSystem( Harness.IO, /*ignoreCase*/ true, - { documents: [emptyFile, referenceFile], cwd: "d:\\pretend\\" }), - { newLine: ts.NewLineKind.LineFeed }); + { documents: [emptyFile, referenceFile], cwd: "d:\\pretend\\" }, + ), + { newLine: ts.NewLineKind.LineFeed }, + ); it("handles no missing root files", () => { const program = ts.createProgram([emptyFileRelativePath], options, testCompilerHost); @@ -63,7 +70,11 @@ describe("unittests:: programApi:: Program.getMissingFilePaths", () => { }); it("handles a mix of present and missing root files", () => { - const program = ts.createProgram(["./nonexistent0.ts", emptyFileRelativePath, "./nonexistent1.ts"], options, testCompilerHost); + const program = ts.createProgram( + ["./nonexistent0.ts", emptyFileRelativePath, "./nonexistent1.ts"], + options, + testCompilerHost, + ); const missing = program.getMissingFilePaths(); verifyMissingFilePaths(missing, ["d:/pretend/nonexistent0.ts", "d:/pretend/nonexistent1.ts"]); }); @@ -99,7 +110,7 @@ describe("unittests:: programApi:: Program.getMissingFilePaths", () => { // From no-extension reference "d:/pretend/nonexistent4.d.ts", "d:/pretend/nonexistent4.ts", - "d:/pretend/nonexistent4.tsx" + "d:/pretend/nonexistent4.tsx", ]); }); @@ -110,25 +121,38 @@ describe("unittests:: programApi:: Program.getMissingFilePaths", () => { }`; const host: ts.CompilerHost = { - getSourceFile: (fileName: string, languageVersion: ts.ScriptTarget, _onError?: (message: string) => void) => { + getSourceFile: ( + fileName: string, + languageVersion: ts.ScriptTarget, + _onError?: (message: string) => void, + ) => { return fileName === "test.ts" ? ts.createSourceFile(fileName, testSource, languageVersion) : undefined; }, getDefaultLibFileName: () => "", - writeFile: (_fileName, _content) => { throw new Error("unsupported"); }, + writeFile: (_fileName, _content) => { + throw new Error("unsupported"); + }, getCurrentDirectory: () => ts.sys.getCurrentDirectory(), getCanonicalFileName: fileName => ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(), getNewLine: () => ts.sys.newLine, useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames, fileExists: fileName => fileName === "test.ts", readFile: fileName => fileName === "test.ts" ? testSource : undefined, - resolveModuleNames: (_moduleNames: string[], _containingFile: string) => { throw new Error("unsupported"); }, - getDirectories: _path => { throw new Error("unsupported"); }, + resolveModuleNames: (_moduleNames: string[], _containingFile: string) => { + throw new Error("unsupported"); + }, + getDirectories: _path => { + throw new Error("unsupported"); + }, }; const program = ts.createProgram(["test.ts"], { module: ts.ModuleKind.ES2015 }, host); assert(program.getSourceFiles().length === 1, "expected 'getSourceFiles' length to be 1"); assert(program.getMissingFilePaths().length === 0, "expected 'getMissingFilePaths' length to be 0"); - assert((program.getFileProcessingDiagnostics()?.length || 0) === 0, "expected 'getFileProcessingDiagnostics' length to be 0"); + assert( + (program.getFileProcessingDiagnostics()?.length || 0) === 0, + "expected 'getFileProcessingDiagnostics' length to be 0", + ); }); }); @@ -139,13 +163,23 @@ describe("unittests:: Program.isSourceFileFromExternalLibrary", () => { const bar = new documents.TextDocument("/node_modules/bar/index.d.ts", 'import * as foo from "foo";'); const fooPackageJsonText = '{ "name": "foo", "version": "1.2.3" }'; const fooIndexText = "export const x: number;"; - const barFooPackage = new documents.TextDocument("/node_modules/bar/node_modules/foo/package.json", fooPackageJsonText); + const barFooPackage = new documents.TextDocument( + "/node_modules/bar/node_modules/foo/package.json", + fooPackageJsonText, + ); const barFooIndex = new documents.TextDocument("/node_modules/bar/node_modules/foo/index.d.ts", fooIndexText); const fooPackage = new documents.TextDocument("/node_modules/foo/package.json", fooPackageJsonText); const fooIndex = new documents.TextDocument("/node_modules/foo/index.d.ts", fooIndexText); - const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [a, bar, barFooPackage, barFooIndex, fooPackage, fooIndex], cwd: "/" }); - const program = ts.createProgram(["/a.ts"], ts.emptyOptions, new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed })); + const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { + documents: [a, bar, barFooPackage, barFooIndex, fooPackage, fooIndex], + cwd: "/", + }); + const program = ts.createProgram( + ["/a.ts"], + ts.emptyOptions, + new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed }), + ); assertIsExternal(program, [a, bar, barFooIndex, fooIndex], f => f !== a); }); @@ -153,15 +187,27 @@ describe("unittests:: Program.isSourceFileFromExternalLibrary", () => { const a = new documents.TextDocument("/a.ts", '/// '); const fooIndex = new documents.TextDocument("/node_modules/foo/index.d.ts", "declare const foo: number;"); const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [a, fooIndex], cwd: "/" }); - const program = ts.createProgram(["/a.ts"], ts.emptyOptions, new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed })); + const program = ts.createProgram( + ["/a.ts"], + ts.emptyOptions, + new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed }), + ); assertIsExternal(program, [a, fooIndex], f => f !== a); }); - function assertIsExternal(program: ts.Program, files: readonly documents.TextDocument[], isExternalExpected: (file: documents.TextDocument) => boolean): void { + function assertIsExternal( + program: ts.Program, + files: readonly documents.TextDocument[], + isExternalExpected: (file: documents.TextDocument) => boolean, + ): void { for (const file of files) { const actual = program.isSourceFileFromExternalLibrary(program.getSourceFile(file.file)!); const expected = isExternalExpected(file); - assert.equal(actual, expected, `Expected ${file.file} isSourceFileFromExternalLibrary to be ${expected}, got ${actual}`); + assert.equal( + actual, + expected, + `Expected ${file.file} isSourceFileFromExternalLibrary to be ${expected}, got ${actual}`, + ); } } }); @@ -172,7 +218,11 @@ describe("unittests:: Program.getNodeCount / Program.getIdentifierCount", () => const pkg = new documents.TextDocument("/package.json", '{"version": "1.0.0"}'); const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [main, pkg], cwd: "/" }); - const program = ts.createProgram(["/main.ts"], { resolveJsonModule: true }, new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed })); + const program = ts.createProgram( + ["/main.ts"], + { resolveJsonModule: true }, + new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed }), + ); const json = program.getSourceFile("/package.json")!; assert.equal(json.scriptKind, ts.ScriptKind.JSON); @@ -189,19 +239,29 @@ describe("unittests:: programApi:: Program.getTypeChecker / Program.getSemanticD const main = new documents.TextDocument("/main.ts", "0 as const"); const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [main], cwd: "/" }); - const program = ts.createProgram(["/main.ts"], {}, new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed })); + const program = ts.createProgram( + ["/main.ts"], + {}, + new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed }), + ); const typeChecker = program.getTypeChecker(); const sourceFile = program.getSourceFile("main.ts")!; - typeChecker.getTypeAtLocation(((sourceFile.statements[0] as ts.ExpressionStatement).expression as ts.AsExpression).type); + typeChecker.getTypeAtLocation( + ((sourceFile.statements[0] as ts.ExpressionStatement).expression as ts.AsExpression).type, + ); const diag = program.getSemanticDiagnostics(); assert.isEmpty(diag); }); it("getSymbolAtLocation does not cause additional error to be added on module resolution failure", () => { - const main = new documents.TextDocument("/main.ts", "import \"./module\";"); + const main = new documents.TextDocument("/main.ts", 'import "./module";'); const mod = new documents.TextDocument("/module.d.ts", "declare const foo: any;"); const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [main, mod], cwd: "/" }); - const program = ts.createProgram(["/main.ts"], {}, new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed })); + const program = ts.createProgram( + ["/main.ts"], + {}, + new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed }), + ); const sourceFile = program.getSourceFile("main.ts")!; const typeChecker = program.getTypeChecker(); @@ -212,12 +272,12 @@ describe("unittests:: programApi:: Program.getTypeChecker / Program.getSemanticD describe("unittests:: programApi:: CompilerOptions relative paths", () => { it("resolves relative paths by getCurrentDirectory", () => { - const main = new documents.TextDocument("/main.ts", "import \"module\";"); + const main = new documents.TextDocument("/main.ts", 'import "module";'); const mod = new documents.TextDocument("/lib/module.ts", "declare const foo: any;"); const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false, { documents: [main, mod], cwd: "/" }); const program = ts.createProgram(["./main.ts"], { - paths: { "*": ["./lib/*"] } + paths: { "*": ["./lib/*"] }, }, new fakes.CompilerHost(fs, { newLine: ts.NewLineKind.LineFeed })); assert.isEmpty(program.getConfigFileParsingDiagnostics()); diff --git a/src/testRunner/unittests/publicApi.ts b/src/testRunner/unittests/publicApi.ts index e0facd0594d82..035a17b6a2a17 100644 --- a/src/testRunner/unittests/publicApi.ts +++ b/src/testRunner/unittests/publicApi.ts @@ -46,7 +46,10 @@ describe("unittests:: Public APIs:: token to string", () => { describe("unittests:: Public APIs:: createPrivateIdentifier", () => { it("throws when name doesn't start with #", () => { - assert.throw(() => ts.factory.createPrivateIdentifier("not"), "Debug Failure. First character of private identifier must be #: not"); + assert.throw( + () => ts.factory.createPrivateIdentifier("not"), + "Debug Failure. First character of private identifier must be #: not", + ); }); }); @@ -60,7 +63,12 @@ describe("unittests:: Public APIs:: JSDoc newlines", () => { */ function test() {}`; - const testSourceFile = ts.createSourceFile(testFilePath, testFileText, ts.ScriptTarget.Latest, /*setParentNodes*/ true); + const testSourceFile = ts.createSourceFile( + testFilePath, + testFileText, + ts.ScriptTarget.Latest, + /*setParentNodes*/ true, + ); const funcDec = testSourceFile.statements.find(ts.isFunctionDeclaration)!; const tags = ts.getJSDocTags(funcDec); assert.isDefined(tags[0].comment); @@ -87,12 +95,13 @@ describe("unittests:: Public APIs:: getTypeAtLocation", () => { const host = new fakes.CompilerHost(vfs.createFromFileSystem( Harness.IO, /*ignoreCase*/ true, - { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" })); + { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" }, + )); const program = ts.createProgram({ host, rootNames: ["/file.ts"], - options: { noLib: true } + options: { noLib: true }, }); const checker = program.getTypeChecker(); @@ -109,12 +118,13 @@ describe("unittests:: Public APIs:: getTypeAtLocation", () => { const host = new fakes.CompilerHost(vfs.createFromFileSystem( Harness.IO, /*ignoreCase*/ true, - { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" })); + { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" }, + )); const program = ts.createProgram({ host, rootNames: ["/file.ts"], - options: { noLib: true } + options: { noLib: true }, }); const checker = program.getTypeChecker(); @@ -133,17 +143,19 @@ describe("unittests:: Public APIs:: getTypeAtLocation", () => { const host = new fakes.CompilerHost(vfs.createFromFileSystem( Harness.IO, /*ignoreCase*/ true, - { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" })); + { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" }, + )); const program = ts.createProgram({ host, rootNames: ["/file.ts"], - options: { noLib: true } + options: { noLib: true }, }); const checker = program.getTypeChecker(); const file = program.getSourceFile("/file.ts")!; - const [declaration] = (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations; + const [declaration] = + (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations; assert.equal(checker.getTypeAtLocation(declaration.initializer!).flags, ts.TypeFlags.Object); }); @@ -153,17 +165,19 @@ describe("unittests:: Public APIs:: getTypeAtLocation", () => { const host = new fakes.CompilerHost(vfs.createFromFileSystem( Harness.IO, /*ignoreCase*/ true, - { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" })); + { documents: [new documents.TextDocument("/file.ts", content)], cwd: "/" }, + )); const program = ts.createProgram({ host, rootNames: ["/file.ts"], - options: { noLib: true } + options: { noLib: true }, }); const checker = program.getTypeChecker(); const file = program.getSourceFile("/file.ts")!; - const [declaration] = (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations; + const [declaration] = + (ts.findLast(file.statements, ts.isVariableStatement) as ts.VariableStatement).declarationList.declarations; assert.equal(checker.getTypeAtLocation(declaration).flags, ts.TypeFlags.Any); }); }); @@ -180,14 +194,22 @@ describe("unittests:: Public APIs:: validateLocaleAndSetLanguage", () => { getExecutingFilePath: () => "/tsc.js", resolvePath: ts.identity, fileExists: fileName => { - assert.isTrue(expectedToReadFile, `Locale : ${locale} ${expectedToReadFile ? "should" : "should not"} check if ${fileName} exists.`); + assert.isTrue( + expectedToReadFile, + `Locale : ${locale} ${ + expectedToReadFile ? "should" : "should not" + } check if ${fileName} exists.`, + ); return expectedToReadFile; }, readFile: fileName => { - assert.isTrue(expectedToReadFile, `Locale : ${locale} ${expectedToReadFile ? "should" : "should not"} read ${fileName}.`); + assert.isTrue( + expectedToReadFile, + `Locale : ${locale} ${expectedToReadFile ? "should" : "should not"} read ${fileName}.`, + ); // Throw error here so that actual change to localized diagnostics messages doesnt take place throw new Error("cannot read file"); - } + }, }, errors); }); } diff --git a/src/testRunner/unittests/reuseProgramStructure.ts b/src/testRunner/unittests/reuseProgramStructure.ts index f5df90959ec39..dbf94350e5d44 100644 --- a/src/testRunner/unittests/reuseProgramStructure.ts +++ b/src/testRunner/unittests/reuseProgramStructure.ts @@ -21,7 +21,13 @@ import { describe("unittests:: Reuse program structure:: General", () => { function baselineCache(baselines: string[], cacheType: string, cache: ts.ModeAwareCache | undefined) { baselines.push(`${cacheType}: ${!cache ? cache : ""}`); - cache?.forEach((resolved, key, mode) => baselines.push(`${key}: ${mode ? ts.getNameOfCompilerOptionValue(mode, ts.moduleOptionDeclaration.type) + ": " : ""}${JSON.stringify(resolved, /*replacer*/ undefined, 2)}`)); + cache?.forEach((resolved, key, mode) => + baselines.push( + `${key}: ${mode ? ts.getNameOfCompilerOptionValue(mode, ts.moduleOptionDeclaration.type) + ": " : ""}${ + JSON.stringify(resolved, /*replacer*/ undefined, 2) + }`, + ) + ); } function baselineProgram(baselines: string[], program: ts.Program, host?: TestCompilerHost) { baselines.push(`Program Reused:: ${(ts as any).StructureIsReused[program.structureIsReused]}`); @@ -40,7 +46,7 @@ describe("unittests:: Reuse program structure:: General", () => { baselines.push(ts.formatDiagnostics(program.getSemanticDiagnostics(), { getCurrentDirectory: () => program.getCurrentDirectory(), getNewLine: () => "\n", - getCanonicalFileName: ts.createGetCanonicalFileName(program.useCaseSensitiveFileNames()) + getCanonicalFileName: ts.createGetCanonicalFileName(program.useCaseSensitiveFileNames()), })); baselines.push("", ""); } @@ -53,11 +59,16 @@ describe("unittests:: Reuse program structure:: General", () => { function getFiles(): NamedSourceText[] { return [ { - name: "a.ts", text: SourceText.New(` + name: "a.ts", + text: SourceText.New( + ` /// /// /// -`, "", `var x = 1`) +`, + "", + `var x = 1`, + ), }, { name: "b.ts", text: SourceText.New(`/// `, "", `var y = 2`) }, { name: "c.ts", text: SourceText.New("", "", `var z = 1;`) }, @@ -81,7 +92,10 @@ describe("unittests:: Reuse program structure:: General", () => { { name: "/a.ts", text: SourceText.New("", "import {b} from 'b'", "var a = b;") }, { name: "/node_modules/b/index.d.ts", text: SourceText.New("", "export * from './internal';", "") }, { name: "/node_modules/b/internal.d.ts", text: SourceText.New("", "", "export const b = 1;") }, - { name: "/node_modules/b/package.json", text: SourceText.New("", "", JSON.stringify({ name: "b", version: "1.2.3" })) }, + { + name: "/node_modules/b/package.json", + text: SourceText.New("", "", JSON.stringify({ name: "b", version: "1.2.3" })), + }, ]; const options: ts.CompilerOptions = { target, moduleResolution: ts.ModuleResolutionKind.Node10 }; @@ -166,16 +180,29 @@ describe("unittests:: Reuse program structure:: General", () => { const program1 = newProgram(getFiles(), ["a.ts"], { target, module: ts.ModuleKind.CommonJS, rootDir: "/a/b" }); const baselines: string[] = []; baselineProgram(baselines, program1); - const program2 = updateProgram(program1, ["a.ts"], { target, module: ts.ModuleKind.CommonJS, rootDir: "/a/c" }, ts.noop); + const program2 = updateProgram( + program1, + ["a.ts"], + { target, module: ts.ModuleKind.CommonJS, rootDir: "/a/c" }, + ts.noop, + ); baselineProgram(baselines, program2); runBaseline("rootdir changes", baselines); }); it("fails if config path changes", () => { - const program1 = newProgram(getFiles(), ["a.ts"], { target, module: ts.ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" }); + const program1 = newProgram(getFiles(), ["a.ts"], { + target, + module: ts.ModuleKind.CommonJS, + configFilePath: "/a/b/tsconfig.json", + }); const baselines: string[] = []; baselineProgram(baselines, program1); - const program2 = updateProgram(program1, ["a.ts"], { target, module: ts.ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, ts.noop); + const program2 = updateProgram(program1, ["a.ts"], { + target, + module: ts.ModuleKind.CommonJS, + configFilePath: "/a/c/tsconfig.json", + }, ts.noop); baselineProgram(baselines, program2); runBaseline("config path changes", baselines); }); @@ -196,7 +223,10 @@ describe("unittests:: Reuse program structure:: General", () => { const program1 = newProgram(files, ["a.ts"], options); const baselines: string[] = []; baselineProgram(baselines, program1); - const newTexts: NamedSourceText[] = files.concat([{ name: "non-existing-file.ts", text: SourceText.New("", "", `var x = 1`) }]); + const newTexts: NamedSourceText[] = files.concat([{ + name: "non-existing-file.ts", + text: SourceText.New("", "", `var x = 1`), + }]); const program2 = updateProgram(program1, ["a.ts"], options, ts.noop, newTexts); baselineProgram(baselines, program2); runBaseline("missing file is created", baselines); @@ -262,13 +292,16 @@ describe("unittests:: Reuse program structure:: General", () => { let sourceFile = program1.getSourceFile("/a.ts")!; const baselines: string[] = []; baselineProgram(baselines, program1, host); - sourceFile = ts.updateSourceFile(sourceFile, "'use strict';" + sourceFile.text, { newLength: "'use strict';".length, span: { start: 0, length: 0 } }); + sourceFile = ts.updateSourceFile(sourceFile, "'use strict';" + sourceFile.text, { + newLength: "'use strict';".length, + span: { start: 0, length: 0 }, + }); baselines.push(`parent pointers are updated: ${sourceFile.statements[2].getSourceFile() === sourceFile}`); const updateHost: TestCompilerHost = { ...host, getSourceFile(fileName) { return fileName === sourceFile.fileName ? sourceFile : program1.getSourceFile(fileName); - } + }, }; const program2 = ts.createProgram(["/a.ts"], options, updateHost, program1); baselineProgram(baselines, program2, updateHost); @@ -310,10 +343,20 @@ describe("unittests:: Reuse program structure:: General", () => { }); it("fetches imports after npm install", () => { - const file1Ts = { name: "file1.ts", text: SourceText.New("", `import * as a from "a";`, "const myX: number = a.x;") }; + const file1Ts = { + name: "file1.ts", + text: SourceText.New("", `import * as a from "a";`, "const myX: number = a.x;"), + }; const file2Ts = { name: "file2.ts", text: SourceText.New("", "", "") }; - const indexDTS = { name: "node_modules/a/index.d.ts", text: SourceText.New("", "export declare let x: number;", "") }; - const options: ts.CompilerOptions = { target: ts.ScriptTarget.ES2015, traceResolution: true, moduleResolution: ts.ModuleResolutionKind.Node10 }; + const indexDTS = { + name: "node_modules/a/index.d.ts", + text: SourceText.New("", "export declare let x: number;", ""), + }; + const options: ts.CompilerOptions = { + target: ts.ScriptTarget.ES2015, + traceResolution: true, + moduleResolution: ts.ModuleResolutionKind.Node10, + }; const rootFiles = [file1Ts, file2Ts]; const filesAfterNpmInstall = [file1Ts, file2Ts, indexDTS]; const initialProgram = newProgram(rootFiles, rootFiles.map(f => f.name), options); @@ -331,7 +374,7 @@ describe("unittests:: Reuse program structure:: General", () => { it("can reuse ambient module declarations from non-modified files", () => { const files = [ { name: "/a/b/app.ts", text: SourceText.New("", "import * as fs from 'fs'", "") }, - { name: "/a/b/node.d.ts", text: SourceText.New("", "", "declare module 'fs' {}") } + { name: "/a/b/node.d.ts", text: SourceText.New("", "", "declare module 'fs' {}") }, ]; const options = { target: ts.ScriptTarget.ES2015, traceResolution: true }; const program = newProgram(files, files.map(f => f.name), options); @@ -357,32 +400,45 @@ describe("unittests:: Reuse program structure:: General", () => { { name: "a2.ts", text: SourceText.New("", "", "let x = 1;") }, { name: "b1.ts", text: SourceText.New("", "export class B { x: number; }", "") }, { name: "b2.ts", text: SourceText.New("", "export class B { x: number; }", "") }, - { name: "node_modules/@types/typerefs1/index.d.ts", text: SourceText.New("", "", "declare let z: string;") }, - { name: "node_modules/@types/typerefs2/index.d.ts", text: SourceText.New("", "", "declare let z: string;") }, + { + name: "node_modules/@types/typerefs1/index.d.ts", + text: SourceText.New("", "", "declare let z: string;"), + }, + { + name: "node_modules/@types/typerefs2/index.d.ts", + text: SourceText.New("", "", "declare let z: string;"), + }, { name: "f1.ts", - text: - SourceText.New( - `/// ${newLine}/// ${newLine}/// `, - `import { B } from './b1';${newLine}export let BB = B;`, - "declare module './b1' { interface B { y: string; } }") + text: SourceText.New( + `/// ${newLine}/// ${newLine}/// `, + `import { B } from './b1';${newLine}export let BB = B;`, + "declare module './b1' { interface B { y: string; } }", + ), }, { name: "f2.ts", text: SourceText.New( `/// ${newLine}/// `, `import { B } from './b2';${newLine}import { BB } from './f1';`, - "(new BB).x; (new BB).y;") + "(new BB).x; (new BB).y;", + ), }, ]; - const options: ts.CompilerOptions = { target: ts.ScriptTarget.ES2015, traceResolution: true, moduleResolution: ts.ModuleResolutionKind.Classic }; + const options: ts.CompilerOptions = { + target: ts.ScriptTarget.ES2015, + traceResolution: true, + moduleResolution: ts.ModuleResolutionKind.Classic, + }; const program1 = newProgram(files, files.map(f => f.name), options); const baselines: string[] = []; baselineProgram(baselines, program1); const indexOfF1 = 6; const program2 = updateProgram(program1, program1.getRootFileNames(), options, f => { - const newSourceText = f[indexOfF1].text.updateReferences(`/// ${newLine}/// `); + const newSourceText = f[indexOfF1].text.updateReferences( + `/// ${newLine}/// `, + ); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); baselineProgram(baselines, program2); @@ -427,7 +483,10 @@ describe("unittests:: Reuse program structure:: General", () => { const root = "/a.ts"; const compilerOptions = { target, moduleResolution: ts.ModuleResolutionKind.Node10 }; - function createRedirectProgram(useGetSourceFileByPath: boolean, options?: { bText: string, bVersion: string }): ProgramWithSourceTexts { + function createRedirectProgram( + useGetSourceFileByPath: boolean, + options?: { bText: string; bVersion: string; }, + ): ProgramWithSourceTexts { const files: NamedSourceText[] = [ { name: "/node_modules/a/index.d.ts", @@ -447,11 +506,19 @@ describe("unittests:: Reuse program structure:: General", () => { }, { name: bxIndex, - text: SourceText.New("", "", options ? options.bText : "export default class X { private x: number; }"), + text: SourceText.New( + "", + "", + options ? options.bText : "export default class X { private x: number; }", + ), }, { name: bxPackage, - text: SourceText.New("", "", JSON.stringify({ name: "x", version: options ? options.bVersion : "1.2.3" })), + text: SourceText.New( + "", + "", + JSON.stringify({ name: "x", version: options ? options.bVersion : "1.2.3" }), + ), }, { name: root, @@ -462,12 +529,26 @@ describe("unittests:: Reuse program structure:: General", () => { return newProgram(files, [root], compilerOptions, useGetSourceFileByPath); } - function updateRedirectProgram(program: ProgramWithSourceTexts, updater: (files: NamedSourceText[]) => void, useGetSourceFileByPath: boolean): ProgramWithSourceTexts { - return updateProgram(program, [root], compilerOptions, updater, /*newTexts*/ undefined, useGetSourceFileByPath); + function updateRedirectProgram( + program: ProgramWithSourceTexts, + updater: (files: NamedSourceText[]) => void, + useGetSourceFileByPath: boolean, + ): ProgramWithSourceTexts { + return updateProgram( + program, + [root], + compilerOptions, + updater, + /*newTexts*/ undefined, + useGetSourceFileByPath, + ); } function runRedirectsBaseline(scenario: string, useGetSourceFileByPath: boolean, baselines: readonly string[]) { - return runBaseline(`redirect${useGetSourceFileByPath ? " with getSourceFileByPath" : ""} ${scenario}`, baselines); + return runBaseline( + `redirect${useGetSourceFileByPath ? " with getSourceFileByPath" : ""} ${scenario}`, + baselines, + ); } function verifyRedirects(useGetSourceFileByPath: boolean) { @@ -489,7 +570,11 @@ describe("unittests:: Reuse program structure:: General", () => { baselineProgram(baselines, program1); const program2 = updateRedirectProgram(program1, files => { - updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }"); + updateProgramText( + files, + axIndex, + "export default class X { private x: number; private y: number; }", + ); updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }')); }, useGetSourceFileByPath); baselineProgram(baselines, program2); @@ -502,7 +587,11 @@ describe("unittests:: Reuse program structure:: General", () => { baselineProgram(baselines, program1); const program2 = updateRedirectProgram(program1, files => { - updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }"); + updateProgramText( + files, + bxIndex, + "export default class X { private x: number; private y: number; }", + ); updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" })); }, useGetSourceFileByPath); baselineProgram(baselines, program2); @@ -510,7 +599,10 @@ describe("unittests:: Reuse program structure:: General", () => { }); it("Previously duplicate packages -> program structure not reused", () => { - const program1 = createRedirectProgram(useGetSourceFileByPath, { bVersion: "1.2.4", bText: "export = class X { private x: number; }" }); + const program1 = createRedirectProgram(useGetSourceFileByPath, { + bVersion: "1.2.4", + bText: "export = class X { private x: number; }", + }); const baselines: string[] = []; baselineProgram(baselines, program1); @@ -538,21 +630,23 @@ describe("unittests:: Reuse program structure:: host is optional", () => { }); }); - describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { function getWhetherProgramIsUptoDate( program: ts.Program, newRootFileNames: string[], - newOptions: ts.CompilerOptions + newOptions: ts.CompilerOptions, ) { return ts.isProgramUptoDate( - program, newRootFileNames, newOptions, - path => program.getSourceFileByPath(path)!.version, /*fileExists*/ ts.returnFalse, + program, + newRootFileNames, + newOptions, + path => program.getSourceFileByPath(path)!.version, + /*fileExists*/ ts.returnFalse, /*hasInvalidatedResolutions*/ ts.returnFalse, /*hasInvalidatedLibResolutions*/ ts.returnFalse, /*hasChangedAutomaticTypeDirectiveNames*/ undefined, /*getParsedCommandLine*/ ts.returnUndefined, - /*projectReferences*/ undefined + /*projectReferences*/ undefined, ); } @@ -566,7 +660,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { function verifyProgramIsUptoDate( program: ts.Program, newRootFileNames: string[], - newOptions: ts.CompilerOptions + newOptions: ts.CompilerOptions, ) { const actual = getWhetherProgramIsUptoDate(program, newRootFileNames, newOptions); assert.isTrue(actual); @@ -577,7 +671,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { rootFiles, options, watchOptions: undefined, - system + system, })).getCurrentProgram().getProgram(); verifyProgramIsUptoDate(program, duplicate(rootFiles), duplicate(options)); } @@ -585,9 +679,16 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { function verifyProgramWithConfigFile(system: ts.System, configFileName: string) { const program = ts.createWatchProgram(ts.createWatchCompilerHostOfConfigFile({ configFileName, - system + system, })).getCurrentProgram().getProgram(); - const { fileNames, options } = ts.parseConfigFileWithSystem(configFileName, {}, /*extendedConfigCache*/ undefined, /*watchOptionsToExtend*/ undefined, system, ts.notImplemented)!; // TODO: GH#18217 + const { fileNames, options } = ts.parseConfigFileWithSystem( + configFileName, + {}, + /*extendedConfigCache*/ undefined, + /*watchOptionsToExtend*/ undefined, + system, + ts.notImplemented, + )!; // TODO: GH#18217 verifyProgramIsUptoDate(program, fileNames, options); } @@ -600,15 +701,15 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { it("has empty options", () => { const file1: File = { path: "/a/b/file1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2: File = { path: "/a/b/file2.ts", - content: "let y = 1" + content: "let y = 1", }; const configFile: File = { path: "/a/b/tsconfig.json", - content: "{}" + content: "{}", }; verifyProgram([file1, file2, libFile, configFile], [file1.path, file2.path], {}, configFile.path); }); @@ -617,19 +718,19 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { const compilerOptions: ts.CompilerOptions = { lib: ["es5", "es2015.promise"] }; const app: File = { path: "/src/app.ts", - content: "var x: Promise;" + content: "var x: Promise;", }; const configFile: File = { path: "/src/tsconfig.json", - content: JSON.stringify({ compilerOptions }) + content: JSON.stringify({ compilerOptions }), }; const es5Lib: File = { path: "/compiler/lib.es5.d.ts", - content: "declare const eval: any" + content: "declare const eval: any", }; const es2015Promise: File = { path: "/compiler/lib.es2015.promise.d.ts", - content: "declare class Promise {}" + content: "declare class Promise {}", }; verifyProgram([app, configFile, es5Lib, es2015Promise], [app.path], compilerOptions, configFile.path); @@ -642,16 +743,16 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { "*": [ "packages/mail/data/*", "packages/styles/*", - "*" - ] - } + "*", + ], + }, }; const app: File = { path: "/src/packages/framework/app.ts", content: 'import classc from "module1/lib/file1";\ import classD from "module3/file3";\ let x = new classc();\ - let y = new classD();' + let y = new classD();', }; const module1: File = { path: "/src/packages/mail/data/module1/lib/file1.ts", @@ -663,14 +764,19 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { }; const module3: File = { path: "/src/packages/styles/module3/file3.ts", - content: "class classD { method() { return 10; } }\nexport default classD;" + content: "class classD { method() { return 10; } }\nexport default classD;", }; const configFile: File = { path: "/src/tsconfig.json", - content: JSON.stringify({ compilerOptions }) + content: JSON.stringify({ compilerOptions }), }; - verifyProgram([app, module1, module2, module3, libFile, configFile], [app.path], compilerOptions, configFile.path); + verifyProgram( + [app, module1, module2, module3, libFile, configFile], + [app.path], + compilerOptions, + configFile.path, + ); }); it("has include paths specified in tsconfig file", () => { @@ -680,16 +786,16 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { "*": [ "packages/mail/data/*", "packages/styles/*", - "*" - ] - } + "*", + ], + }, }; const app: File = { path: "/src/packages/framework/app.ts", content: 'import classc from "module1/lib/file1";\ import classD from "module3/file3";\ let x = new classc();\ - let y = new classD();' + let y = new classD();', }; const module1: File = { path: "/src/packages/mail/data/module1/lib/file1.ts", @@ -701,13 +807,16 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { }; const module3: File = { path: "/src/packages/styles/module3/file3.ts", - content: "class classD { method() { return 10; } }\nexport default classD;" + content: "class classD { method() { return 10; } }\nexport default classD;", }; const configFile: File = { path: "/src/tsconfig.json", - content: JSON.stringify({ compilerOptions, include: ["packages/**/*.ts"] }) + content: JSON.stringify({ compilerOptions, include: ["packages/**/*.ts"] }), }; - verifyProgramWithConfigFile(createWatchedSystem([app, module1, module2, module3, libFile, configFile]), configFile.path); + verifyProgramWithConfigFile( + createWatchedSystem([app, module1, module2, module3, libFile, configFile]), + configFile.path, + ); }); it("has the same root file names", () => { const module1: File = { @@ -720,7 +829,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { }; const module3: File = { path: "/src/packages/styles/module3/file3.ts", - content: "class classD { method() { return 10; } }\nexport default classD;" + content: "class classD { method() { return 10; } }\nexport default classD;", }; const rootFiles = [module1.path, module2.path, module3.path]; const system = createWatchedSystem([module1, module2, module3]); @@ -729,17 +838,16 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { rootFiles, options, watchOptions: undefined, - system + system, })).getCurrentProgram().getProgram(); verifyProgramIsUptoDate(program, duplicate(rootFiles), duplicate(options)); }); - }); describe("should return false when there is no change in compiler options but", () => { function verifyProgramIsNotUptoDate( program: ts.Program, newRootFileNames: string[], - newOptions: ts.CompilerOptions + newOptions: ts.CompilerOptions, ) { const actual = getWhetherProgramIsUptoDate(program, newRootFileNames, newOptions); assert.isFalse(actual); @@ -755,7 +863,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { }; const module3: File = { path: "/src/packages/styles/module3/file3.ts", - content: "class classD { method() { return 10; } }\nexport default classD;" + content: "class classD { method() { return 10; } }\nexport default classD;", }; const rootFiles = [module1.path, module2.path]; const newRootFiles = [module1.path, module2.path, module3.path]; @@ -765,7 +873,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { rootFiles, options, watchOptions: undefined, - system + system, })).getCurrentProgram().getProgram(); verifyProgramIsNotUptoDate(program, duplicate(newRootFiles), duplicate(options)); }); @@ -780,7 +888,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { }; const module3: File = { path: "/src/packages/styles/module3/file3.ts", - content: "class classD { method() { return 10; } }\nexport default classD;" + content: "class classD { method() { return 10; } }\nexport default classD;", }; const rootFiles = [module1.path, module2.path]; const newRootFiles = [module2.path, module3.path]; @@ -790,7 +898,7 @@ describe("unittests:: Reuse program structure:: isProgramUptoDate", () => { rootFiles, options, watchOptions: undefined, - system + system, })).getCurrentProgram().getProgram(); verifyProgramIsNotUptoDate(program, duplicate(newRootFiles), duplicate(options)); }); diff --git a/src/testRunner/unittests/semver.ts b/src/testRunner/unittests/semver.ts index 241a2f7209e0b..a61173669797b 100644 --- a/src/testRunner/unittests/semver.ts +++ b/src/testRunner/unittests/semver.ts @@ -4,7 +4,10 @@ import * as Utils from "../_namespaces/Utils"; import theory = Utils.theory; describe("unittests:: semver", () => { describe("Version", () => { - function assertVersion(version: ts.Version, [major, minor, patch, prerelease, build]: [number, number, number, string[]?, string[]?]) { + function assertVersion( + version: ts.Version, + [major, minor, patch, prerelease, build]: [number, number, number, string[]?, string[]?], + ) { assert.strictEqual(version.major, major); assert.strictEqual(version.minor, minor); assert.strictEqual(version.patch, patch); @@ -17,7 +20,10 @@ describe("unittests:: semver", () => { }); it("parts", () => { assertVersion(new ts.Version(1, 2, 3, "pre.4", "build.5"), [1, 2, 3, ["pre", "4"], ["build", "5"]]); - assertVersion(new ts.Version(1, 2, 3, ["pre", "4"], ["build", "5"]), [1, 2, 3, ["pre", "4"], ["build", "5"]]); + assertVersion(new ts.Version(1, 2, 3, ["pre", "4"], ["build", "5"]), [1, 2, 3, ["pre", "4"], [ + "build", + "5", + ]]); assertVersion(new ts.Version(1, 2, 3), [1, 2, 3]); assertVersion(new ts.Version(1, 2), [1, 2, 0]); assertVersion(new ts.Version(1), [1, 0, 0]); @@ -26,7 +32,10 @@ describe("unittests:: semver", () => { it("toString", () => { assert.strictEqual(new ts.Version(1, 2, 3, "pre.4", "build.5").toString(), "1.2.3-pre.4+build.5"); assert.strictEqual(new ts.Version(1, 2, 3, "pre.4").toString(), "1.2.3-pre.4"); - assert.strictEqual(new ts.Version(1, 2, 3, /*prerelease*/ undefined, "build.5").toString(), "1.2.3+build.5"); + assert.strictEqual( + new ts.Version(1, 2, 3, /*prerelease*/ undefined, "build.5").toString(), + "1.2.3+build.5", + ); assert.strictEqual(new ts.Version(1, 2, 3).toString(), "1.2.3"); assert.strictEqual(new ts.Version(1, 2).toString(), "1.2.0"); assert.strictEqual(new ts.Version(1).toString(), "1.0.0"); @@ -47,47 +56,92 @@ describe("unittests:: semver", () => { // https://semver.org/#spec-item-11 // > When major, minor, and patch are equal, a pre-release version has lower // > precedence than a normal version. - assert.strictEqual(new ts.Version("1.0.0").compareTo(new ts.Version("1.0.0-pre")), ts.Comparison.GreaterThan); - assert.strictEqual(new ts.Version("1.0.1-pre").compareTo(new ts.Version("1.0.0")), ts.Comparison.GreaterThan); + assert.strictEqual( + new ts.Version("1.0.0").compareTo(new ts.Version("1.0.0-pre")), + ts.Comparison.GreaterThan, + ); + assert.strictEqual( + new ts.Version("1.0.1-pre").compareTo(new ts.Version("1.0.0")), + ts.Comparison.GreaterThan, + ); assert.strictEqual(new ts.Version("1.0.0-pre").compareTo(new ts.Version("1.0.0")), ts.Comparison.LessThan); // https://semver.org/#spec-item-11 // > identifiers consisting of only digits are compared numerically assert.strictEqual(new ts.Version("1.0.0-0").compareTo(new ts.Version("1.0.0-1")), ts.Comparison.LessThan); - assert.strictEqual(new ts.Version("1.0.0-1").compareTo(new ts.Version("1.0.0-0")), ts.Comparison.GreaterThan); + assert.strictEqual( + new ts.Version("1.0.0-1").compareTo(new ts.Version("1.0.0-0")), + ts.Comparison.GreaterThan, + ); assert.strictEqual(new ts.Version("1.0.0-2").compareTo(new ts.Version("1.0.0-10")), ts.Comparison.LessThan); - assert.strictEqual(new ts.Version("1.0.0-10").compareTo(new ts.Version("1.0.0-2")), ts.Comparison.GreaterThan); + assert.strictEqual( + new ts.Version("1.0.0-10").compareTo(new ts.Version("1.0.0-2")), + ts.Comparison.GreaterThan, + ); assert.strictEqual(new ts.Version("1.0.0-0").compareTo(new ts.Version("1.0.0-0")), ts.Comparison.EqualTo); // https://semver.org/#spec-item-11 // > identifiers with letters or hyphens are compared lexically in ASCII sort order. assert.strictEqual(new ts.Version("1.0.0-a").compareTo(new ts.Version("1.0.0-b")), ts.Comparison.LessThan); - assert.strictEqual(new ts.Version("1.0.0-a-2").compareTo(new ts.Version("1.0.0-a-10")), ts.Comparison.GreaterThan); - assert.strictEqual(new ts.Version("1.0.0-b").compareTo(new ts.Version("1.0.0-a")), ts.Comparison.GreaterThan); + assert.strictEqual( + new ts.Version("1.0.0-a-2").compareTo(new ts.Version("1.0.0-a-10")), + ts.Comparison.GreaterThan, + ); + assert.strictEqual( + new ts.Version("1.0.0-b").compareTo(new ts.Version("1.0.0-a")), + ts.Comparison.GreaterThan, + ); assert.strictEqual(new ts.Version("1.0.0-a").compareTo(new ts.Version("1.0.0-a")), ts.Comparison.EqualTo); assert.strictEqual(new ts.Version("1.0.0-A").compareTo(new ts.Version("1.0.0-a")), ts.Comparison.LessThan); // https://semver.org/#spec-item-11 // > Numeric identifiers always have lower precedence than non-numeric identifiers. - assert.strictEqual(new ts.Version("1.0.0-0").compareTo(new ts.Version("1.0.0-alpha")), ts.Comparison.LessThan); - assert.strictEqual(new ts.Version("1.0.0-alpha").compareTo(new ts.Version("1.0.0-0")), ts.Comparison.GreaterThan); + assert.strictEqual( + new ts.Version("1.0.0-0").compareTo(new ts.Version("1.0.0-alpha")), + ts.Comparison.LessThan, + ); + assert.strictEqual( + new ts.Version("1.0.0-alpha").compareTo(new ts.Version("1.0.0-0")), + ts.Comparison.GreaterThan, + ); assert.strictEqual(new ts.Version("1.0.0-0").compareTo(new ts.Version("1.0.0-0")), ts.Comparison.EqualTo); - assert.strictEqual(new ts.Version("1.0.0-alpha").compareTo(new ts.Version("1.0.0-alpha")), ts.Comparison.EqualTo); + assert.strictEqual( + new ts.Version("1.0.0-alpha").compareTo(new ts.Version("1.0.0-alpha")), + ts.Comparison.EqualTo, + ); // https://semver.org/#spec-item-11 // > A larger set of pre-release fields has a higher precedence than a smaller set, if all // > of the preceding identifiers are equal. - assert.strictEqual(new ts.Version("1.0.0-alpha").compareTo(new ts.Version("1.0.0-alpha.0")), ts.Comparison.LessThan); - assert.strictEqual(new ts.Version("1.0.0-alpha.0").compareTo(new ts.Version("1.0.0-alpha")), ts.Comparison.GreaterThan); + assert.strictEqual( + new ts.Version("1.0.0-alpha").compareTo(new ts.Version("1.0.0-alpha.0")), + ts.Comparison.LessThan, + ); + assert.strictEqual( + new ts.Version("1.0.0-alpha.0").compareTo(new ts.Version("1.0.0-alpha")), + ts.Comparison.GreaterThan, + ); // https://semver.org/#spec-item-11 // > Precedence for two pre-release versions with the same major, minor, and patch version // > MUST be determined by comparing each dot separated identifier from left to right until // > a difference is found [...] - assert.strictEqual(new ts.Version("1.0.0-a.0.b.1").compareTo(new ts.Version("1.0.0-a.0.b.2")), ts.Comparison.LessThan); - assert.strictEqual(new ts.Version("1.0.0-a.0.b.1").compareTo(new ts.Version("1.0.0-b.0.a.1")), ts.Comparison.LessThan); - assert.strictEqual(new ts.Version("1.0.0-a.0.b.2").compareTo(new ts.Version("1.0.0-a.0.b.1")), ts.Comparison.GreaterThan); - assert.strictEqual(new ts.Version("1.0.0-b.0.a.1").compareTo(new ts.Version("1.0.0-a.0.b.1")), ts.Comparison.GreaterThan); + assert.strictEqual( + new ts.Version("1.0.0-a.0.b.1").compareTo(new ts.Version("1.0.0-a.0.b.2")), + ts.Comparison.LessThan, + ); + assert.strictEqual( + new ts.Version("1.0.0-a.0.b.1").compareTo(new ts.Version("1.0.0-b.0.a.1")), + ts.Comparison.LessThan, + ); + assert.strictEqual( + new ts.Version("1.0.0-a.0.b.2").compareTo(new ts.Version("1.0.0-a.0.b.1")), + ts.Comparison.GreaterThan, + ); + assert.strictEqual( + new ts.Version("1.0.0-b.0.a.1").compareTo(new ts.Version("1.0.0-a.0.b.1")), + ts.Comparison.GreaterThan, + ); // https://semver.org/#spec-item-11 // > Build metadata does not figure into precedence @@ -181,7 +235,11 @@ describe("unittests:: semver", () => { function assertRange(rangeText: string, versionText: string, inRange: boolean) { const range = new ts.VersionRange(rangeText); const version = new ts.Version(versionText); - assert.strictEqual(range.test(version), inRange, `Expected version '${version}' ${inRange ? `to be` : `to not be`} in range '${rangeText}' (${range})`); + assert.strictEqual( + range.test(version), + inRange, + `Expected version '${version}' ${inRange ? `to be` : `to not be`} in range '${rangeText}' (${range})`, + ); } theory("comparators", assertRange, [ diff --git a/src/testRunner/unittests/services/cancellableLanguageServiceOperations.ts b/src/testRunner/unittests/services/cancellableLanguageServiceOperations.ts index 7cc688965ad9c..0de18f24a70d3 100644 --- a/src/testRunner/unittests/services/cancellableLanguageServiceOperations.ts +++ b/src/testRunner/unittests/services/cancellableLanguageServiceOperations.ts @@ -9,21 +9,26 @@ describe("unittests:: services:: cancellableLanguageServiceOperations", () => { foo(f); `; it("can cancel signature help mid-request", () => { - verifyOperationCancelledAfter(file, 4, service => // Two calls are top-level in services, one is the root type, and the second should be for the parameter type - service.getSignatureHelpItems("file.ts", file.lastIndexOf("f"), ts.emptyOptions)!, r => assert.exists(r.items[0]) + verifyOperationCancelledAfter( + file, + 4, + service => + // Two calls are top-level in services, one is the root type, and the second should be for the parameter type + service.getSignatureHelpItems("file.ts", file.lastIndexOf("f"), ts.emptyOptions)!, + r => assert.exists(r.items[0]), ); }); it("can cancel find all references mid-request", () => { - verifyOperationCancelledAfter(file, 3, service => // Two calls are top-level in services, one is the root type - service.findReferences("file.ts", file.lastIndexOf("o"))!, r => assert.exists(r[0].definition) - ); + verifyOperationCancelledAfter(file, 3, service => + // Two calls are top-level in services, one is the root type + service.findReferences("file.ts", file.lastIndexOf("o"))!, r => assert.exists(r[0].definition)); }); it("can cancel quick info mid-request", () => { - verifyOperationCancelledAfter(file, 1, service => // The LS doesn't do any top-level checks on the token for quickinfo, so the first check is within the checker - service.getQuickInfoAtPosition("file.ts", file.lastIndexOf("o"))!, r => assert.exists(r.displayParts) - ); + verifyOperationCancelledAfter(file, 1, service => + // The LS doesn't do any top-level checks on the token for quickinfo, so the first check is within the checker + service.getQuickInfoAtPosition("file.ts", file.lastIndexOf("o"))!, r => assert.exists(r.displayParts)); }); it("can cancel completion entry details mid-request", () => { @@ -48,19 +53,43 @@ describe("unittests:: services:: cancellableLanguageServiceOperations", () => { placeOpenBraceOnNewLineForFunctions: false, placeOpenBraceOnNewLineForControlBlocks: false, }; - verifyOperationCancelledAfter(file, 1, service => // The LS doesn't do any top-level checks on the token for completion entry details, so the first check is within the checker - service.getCompletionEntryDetails("file.ts", file.lastIndexOf("f"), "foo", options, /*source*/ undefined, {}, /*data*/ undefined)!, r => assert.exists(r.displayParts) - ); + verifyOperationCancelledAfter(file, 1, service => + // The LS doesn't do any top-level checks on the token for completion entry details, so the first check is within the checker + service.getCompletionEntryDetails( + "file.ts", + file.lastIndexOf("f"), + "foo", + options, + /*source*/ undefined, + {}, + /*data*/ undefined, + )!, r => assert.exists(r.displayParts)); }); it("can cancel suggestion diagnostics mid-request", () => { - verifyOperationCancelledAfter(file, 1, service => // The LS doesn't do any top-level checks on the token for suggestion diagnostics, so the first check is within the checker - service.getSuggestionDiagnostics("file.js"), r => assert.notEqual(r.length, 0), "file.js", "function foo() { let a = 10; }", { allowJs: true } + verifyOperationCancelledAfter( + file, + 1, + service => + // The LS doesn't do any top-level checks on the token for suggestion diagnostics, so the first check is within the checker + service.getSuggestionDiagnostics("file.js"), + r => assert.notEqual(r.length, 0), + "file.js", + "function foo() { let a = 10; }", + { allowJs: true }, ); }); }); -function verifyOperationCancelledAfter(content: string, cancelAfter: number, operation: (service: ts.LanguageService) => T, validator: (arg: T) => void, fileName?: string, fileContent?: string, options?: ts.CompilerOptions) { +function verifyOperationCancelledAfter( + content: string, + cancelAfter: number, + operation: (service: ts.LanguageService) => T, + validator: (arg: T) => void, + fileName?: string, + fileContent?: string, + options?: ts.CompilerOptions, +) { let checks = 0; const token: ts.HostCancellationToken = { isCancellationRequested() { @@ -70,7 +99,7 @@ function verifyOperationCancelledAfter(content: string, cancelAfter: number, checks = -Infinity; // Cancel just once, then disable cancellation, effectively } return result; - } + }, }; const adapter = new Harness.LanguageService.NativeLanguageServiceAdapter(token, options); const host = adapter.getHost(); diff --git a/src/testRunner/unittests/services/colorization.ts b/src/testRunner/unittests/services/colorization.ts index b3747eeadaba7..f1aea82db5ef1 100644 --- a/src/testRunner/unittests/services/colorization.ts +++ b/src/testRunner/unittests/services/colorization.ts @@ -12,7 +12,9 @@ interface ClassificationEntry { describe("unittests:: services:: Colorization", () => { // Use the shim adapter to ensure test coverage of the shim layer for the classifier - const languageServiceAdapter = new Harness.LanguageService.ShimLanguageServiceAdapter(/*preprocessToResolve*/ false); + const languageServiceAdapter = new Harness.LanguageService.ShimLanguageServiceAdapter( + /*preprocessToResolve*/ false, + ); const classifier = languageServiceAdapter.getClassifier(); function getEntryAtPosition(result: ts.ClassificationResult, position: number) { @@ -54,33 +56,69 @@ describe("unittests:: services:: Colorization", () => { // TODO: GH#18217 return { value, classification: undefined!, position: 0 }; } - function createClassification(value: string, classification: ts.TokenClass, position?: number): ClassificationEntry { + function createClassification( + value: string, + classification: ts.TokenClass, + position?: number, + ): ClassificationEntry { return { value, classification, position }; } - function testLexicalClassification(text: string, initialEndOfLineState: ts.EndOfLineState, ...expectedEntries: ClassificationEntry[]): void { - const result = classifier.getClassificationsForLine(text, initialEndOfLineState, /*syntacticClassifierAbsent*/ false); + function testLexicalClassification( + text: string, + initialEndOfLineState: ts.EndOfLineState, + ...expectedEntries: ClassificationEntry[] + ): void { + const result = classifier.getClassificationsForLine( + text, + initialEndOfLineState, + /*syntacticClassifierAbsent*/ false, + ); for (const expectedEntry of expectedEntries) { if (expectedEntry.classification === undefined) { - assert.equal(result.finalLexState, expectedEntry.value, "final endOfLineState does not match expected."); + assert.equal( + result.finalLexState, + expectedEntry.value, + "final endOfLineState does not match expected.", + ); } else { - const actualEntryPosition = expectedEntry.position !== undefined ? expectedEntry.position : text.indexOf(expectedEntry.value); - assert(actualEntryPosition >= 0, "token: '" + expectedEntry.value + "' does not exit in text: '" + text + "'."); + const actualEntryPosition = expectedEntry.position !== undefined ? expectedEntry.position + : text.indexOf(expectedEntry.value); + assert( + actualEntryPosition >= 0, + "token: '" + expectedEntry.value + "' does not exit in text: '" + text + "'.", + ); const actualEntry = getEntryAtPosition(result, actualEntryPosition)!; - assert(actualEntry, "Could not find classification entry for '" + expectedEntry.value + "' at position: " + actualEntryPosition); - assert.equal(actualEntry.classification, expectedEntry.classification, "Classification class does not match expected. Expected: " + ts.TokenClass[expectedEntry.classification] + ", Actual: " + ts.TokenClass[actualEntry.classification]); - assert.equal(actualEntry.length, expectedEntry.value.length, "Classification length does not match expected. Expected: " + ts.TokenClass[expectedEntry.value.length] + ", Actual: " + ts.TokenClass[actualEntry.length]); + assert( + actualEntry, + "Could not find classification entry for '" + expectedEntry.value + "' at position: " + + actualEntryPosition, + ); + assert.equal( + actualEntry.classification, + expectedEntry.classification, + "Classification class does not match expected. Expected: " + + ts.TokenClass[expectedEntry.classification] + ", Actual: " + + ts.TokenClass[actualEntry.classification], + ); + assert.equal( + actualEntry.length, + expectedEntry.value.length, + "Classification length does not match expected. Expected: " + + ts.TokenClass[expectedEntry.value.length] + ", Actual: " + ts.TokenClass[actualEntry.length], + ); } } } describe("test getClassifications", () => { it("returns correct token classes", () => { - testLexicalClassification("var x: string = \"foo\" ?? \"bar\"; //Hello", + testLexicalClassification( + 'var x: string = "foo" ?? "bar"; //Hello', ts.EndOfLineState.None, keyword("var"), whitespace(" "), @@ -88,26 +126,30 @@ describe("unittests:: services:: Colorization", () => { punctuation(":"), keyword("string"), operator("="), - stringLiteral("\"foo\""), + stringLiteral('"foo"'), whitespace(" "), operator("??"), - stringLiteral("\"foo\""), + stringLiteral('"foo"'), comment("//Hello"), - punctuation(";")); + punctuation(";"), + ); }); it("correctly classifies a comment after a divide operator", () => { - testLexicalClassification("1 / 2 // comment", + testLexicalClassification( + "1 / 2 // comment", ts.EndOfLineState.None, numberLiteral("1"), whitespace(" "), operator("/"), numberLiteral("2"), - comment("// comment")); + comment("// comment"), + ); }); it("correctly classifies a literal after a divide operator", () => { - testLexicalClassification("1 / 2, 3 / 4", + testLexicalClassification( + "1 / 2, 3 / 4", ts.EndOfLineState.None, numberLiteral("1"), whitespace(" "), @@ -115,178 +157,215 @@ describe("unittests:: services:: Colorization", () => { numberLiteral("2"), numberLiteral("3"), numberLiteral("4"), - operator(",")); + operator(","), + ); }); it("correctly classifies a multiline string with one backslash", () => { - testLexicalClassification("'line1\\", + testLexicalClassification( + "'line1\\", ts.EndOfLineState.None, stringLiteral("'line1\\"), - finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral)); + finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral), + ); }); it("correctly classifies a multiline string with three backslashes", () => { - testLexicalClassification("'line1\\\\\\", + testLexicalClassification( + "'line1\\\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\\\"), - finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral)); + finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral), + ); }); it("correctly classifies an unterminated single-line string with no backslashes", () => { - testLexicalClassification("'line1", + testLexicalClassification( + "'line1", ts.EndOfLineState.None, stringLiteral("'line1"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies an unterminated single-line string with two backslashes", () => { - testLexicalClassification("'line1\\\\", + testLexicalClassification( + "'line1\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies an unterminated single-line string with four backslashes", () => { - testLexicalClassification("'line1\\\\\\\\", + testLexicalClassification( + "'line1\\\\\\\\", ts.EndOfLineState.None, stringLiteral("'line1\\\\\\\\"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the continuing line of a multiline string ending in one backslash", () => { - testLexicalClassification("\\", + testLexicalClassification( + "\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\"), - finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral)); + finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral), + ); }); it("correctly classifies the continuing line of a multiline string ending in three backslashes", () => { - testLexicalClassification("\\", + testLexicalClassification( + "\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\"), - finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral)); + finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral), + ); }); it("correctly classifies the last line of an unterminated multiline string ending in no backslashes", () => { - testLexicalClassification(" ", + testLexicalClassification( + " ", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral(" "), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the last line of an unterminated multiline string ending in two backslashes", () => { - testLexicalClassification("\\\\", + testLexicalClassification( + "\\\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\\\"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the last line of an unterminated multiline string ending in four backslashes", () => { - testLexicalClassification("\\\\\\\\", + testLexicalClassification( + "\\\\\\\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\\\\\\\"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the last line of a multiline string", () => { - testLexicalClassification("'", + testLexicalClassification( + "'", ts.EndOfLineState.InSingleQuoteStringLiteral, stringLiteral("'"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies an unterminated multiline comment", () => { - testLexicalClassification("/*", + testLexicalClassification( + "/*", ts.EndOfLineState.None, comment("/*"), - finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia), + ); }); it("correctly classifies the termination of a multiline comment", () => { - testLexicalClassification(" */ ", + testLexicalClassification( + " */ ", ts.EndOfLineState.InMultiLineCommentTrivia, comment(" */"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("correctly classifies the continuation of a multiline comment", () => { - testLexicalClassification("LOREM IPSUM DOLOR ", + testLexicalClassification( + "LOREM IPSUM DOLOR ", ts.EndOfLineState.InMultiLineCommentTrivia, comment("LOREM IPSUM DOLOR "), - finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia), + ); }); it("correctly classifies an unterminated multiline comment on a line ending in '/*/'", () => { - testLexicalClassification(" /*/", + testLexicalClassification( + " /*/", ts.EndOfLineState.None, comment("/*/"), - finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia), + ); }); it("correctly classifies an unterminated multiline comment with trailing space", () => { - testLexicalClassification("/* ", + testLexicalClassification( + "/* ", ts.EndOfLineState.None, comment("/* "), - finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia), + ); }); it("correctly classifies a keyword after a dot", () => { - testLexicalClassification("a.var", - ts.EndOfLineState.None, - identifier("var")); + testLexicalClassification("a.var", ts.EndOfLineState.None, identifier("var")); }); it("correctly classifies a string literal after a dot", () => { - testLexicalClassification("a.\"var\"", - ts.EndOfLineState.None, - stringLiteral("\"var\"")); + testLexicalClassification('a."var"', ts.EndOfLineState.None, stringLiteral('"var"')); }); it("correctly classifies a keyword after a dot separated by comment trivia", () => { - testLexicalClassification("a./*hello world*/ var", + testLexicalClassification( + "a./*hello world*/ var", ts.EndOfLineState.None, identifier("a"), punctuation("."), comment("/*hello world*/"), - identifier("var")); + identifier("var"), + ); }); it("classifies a property access with whitespace around the dot", () => { - testLexicalClassification(" x .\tfoo ()", - ts.EndOfLineState.None, - identifier("x"), - identifier("foo")); + testLexicalClassification(" x .\tfoo ()", ts.EndOfLineState.None, identifier("x"), identifier("foo")); }); it("classifies a keyword after a dot on previous line", () => { - testLexicalClassification("var", + testLexicalClassification( + "var", ts.EndOfLineState.None, keyword("var"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies multiple keywords properly", () => { - testLexicalClassification("public static", + testLexicalClassification( + "public static", ts.EndOfLineState.None, keyword("public"), keyword("static"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); - testLexicalClassification("public var", + testLexicalClassification( + "public var", ts.EndOfLineState.None, keyword("public"), identifier("var"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies a single line no substitution template string correctly", () => { - testLexicalClassification("`number number public string`", + testLexicalClassification( + "`number number public string`", ts.EndOfLineState.None, stringLiteral("`number number public string`"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies substitution parts of a template string correctly", () => { - testLexicalClassification("`number '${ 1 + 1 }' string '${ 'hello' }'`", + testLexicalClassification( + "`number '${ 1 + 1 }' string '${ 'hello' }'`", ts.EndOfLineState.None, stringLiteral("`number '${"), numberLiteral("1"), @@ -295,63 +374,79 @@ describe("unittests:: services:: Colorization", () => { stringLiteral("}' string '${"), stringLiteral("'hello'"), stringLiteral("}'`"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies an unterminated no substitution template string correctly", () => { - testLexicalClassification("`hello world", + testLexicalClassification( + "`hello world", ts.EndOfLineState.None, stringLiteral("`hello world"), - finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate)); + finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate), + ); }); it("classifies the entire line of an unterminated multiline no-substitution/head template", () => { - testLexicalClassification("...", + testLexicalClassification( + "...", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("..."), - finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate)); + finalEndOfLineState(ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate), + ); }); it("classifies the entire line of an unterminated multiline template middle/end", () => { - testLexicalClassification("...", + testLexicalClassification( + "...", ts.EndOfLineState.InTemplateMiddleOrTail, stringLiteral("..."), - finalEndOfLineState(ts.EndOfLineState.InTemplateMiddleOrTail)); + finalEndOfLineState(ts.EndOfLineState.InTemplateMiddleOrTail), + ); }); it("classifies a termination of a multiline template head", () => { - testLexicalClassification("...${", + testLexicalClassification( + "...${", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("...${"), - finalEndOfLineState(ts.EndOfLineState.InTemplateSubstitutionPosition)); + finalEndOfLineState(ts.EndOfLineState.InTemplateSubstitutionPosition), + ); }); it("classifies the termination of a multiline no substitution template", () => { - testLexicalClassification("...`", + testLexicalClassification( + "...`", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("...`"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies the substitution parts and middle/tail of a multiline template string", () => { - testLexicalClassification("${ 1 + 1 }...`", + testLexicalClassification( + "${ 1 + 1 }...`", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("${"), numberLiteral("1"), operator("+"), numberLiteral("1"), stringLiteral("}...`"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies a template middle and propagates the end of line state", () => { - testLexicalClassification("${ 1 + 1 }...`", + testLexicalClassification( + "${ 1 + 1 }...`", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral("${"), numberLiteral("1"), operator("+"), numberLiteral("1"), stringLiteral("}...`"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("classifies substitution expressions with curly braces appropriately", () => { let pos = 0; let lastLength = 0; - testLexicalClassification("...${ () => { } } ${ { x: `1` } }...`", + testLexicalClassification( + "...${ () => { } } ${ { x: `1` } }...`", ts.EndOfLineState.InTemplateHeadOrNoSubstitutionTemplate, stringLiteral(track("...${"), pos), punctuation(track(" ", "("), pos), @@ -366,7 +461,8 @@ describe("unittests:: services:: Colorization", () => { stringLiteral(track(" ", "`1`"), pos), punctuation(track(" ", "}"), pos), stringLiteral(track(" ", "}...`"), pos), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); // Adjusts 'pos' by accounting for the length of each portion of the string, // but only return the last given string @@ -380,22 +476,27 @@ describe("unittests:: services:: Colorization", () => { }); it("classifies partially written generics correctly.", () => { - testLexicalClassification("Foo { identifier("Foo"), operator("<"), identifier("number"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("LexicallyClassifiesConflictTokens", () => { // Test conflict markers. testLexicalClassification( - "class C {\r\n\ +"class C {\r\n\ <<<<<<< HEAD\r\n\ v = 1;\r\n\ =======\r\n\ @@ -429,10 +531,11 @@ describe("unittests:: services:: Colorization", () => { comment("=======\r\n v = 2;\r\n"), comment(">>>>>>> Branch - a"), punctuation("}"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); testLexicalClassification( - "<<<<<<< HEAD\r\n\ +"<<<<<<< HEAD\r\n\ class C { }\r\n\ =======\r\n\ class D { }\r\n\ @@ -445,10 +548,11 @@ class D { }\r\n\ punctuation("}"), comment("=======\r\nclass D { }\r\n"), comment(">>>>>>> Branch - a"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); testLexicalClassification( - "class C {\r\n\ +"class C {\r\n\ <<<<<<< HEAD\r\n\ v = 1;\r\n\ ||||||| merged common ancestors\r\n\ @@ -470,10 +574,11 @@ class D { }\r\n\ comment("=======\r\n v = 2;\r\n"), comment(">>>>>>> Branch - a"), punctuation("}"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); testLexicalClassification( - "<<<<<<< HEAD\r\n\ +"<<<<<<< HEAD\r\n\ class C { }\r\n\ ||||||| merged common ancestors\r\n\ class E { }\r\n\ @@ -489,11 +594,13 @@ class D { }\r\n\ comment("||||||| merged common ancestors\r\nclass E { }\r\n"), comment("=======\r\nclass D { }\r\n"), comment(">>>>>>> Branch - a"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); it("'of' keyword", () => { - testLexicalClassification("for (var of of of) { }", + testLexicalClassification( + "for (var of of of) { }", ts.EndOfLineState.None, keyword("for"), punctuation("("), @@ -504,7 +611,8 @@ class D { }\r\n\ punctuation(")"), punctuation("{"), punctuation("}"), - finalEndOfLineState(ts.EndOfLineState.None)); + finalEndOfLineState(ts.EndOfLineState.None), + ); }); }); }); diff --git a/src/testRunner/unittests/services/convertToAsyncFunction.ts b/src/testRunner/unittests/services/convertToAsyncFunction.ts index 00b46896aaaa2..d024df40daaa9 100644 --- a/src/testRunner/unittests/services/convertToAsyncFunction.ts +++ b/src/testRunner/unittests/services/convertToAsyncFunction.ts @@ -1,6 +1,8 @@ import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; -import { createProjectService } from "../helpers/tsserver"; +import { + createProjectService, +} from "../helpers/tsserver"; import { createServerHost, File, @@ -271,15 +273,14 @@ interface PromiseConstructor { declare var Promise: PromiseConstructor; interface RegExp {} interface String { charAt: any; } -interface Array {}` +interface Array {}`, }; const moduleFile: File = { path: "/module.ts", - content: -`export function fn(res: any): any { + content: `export function fn(res: any): any { return res; -}` +}`, }; type WithSkipAndOnly = ((...args: T) => void) & { @@ -287,7 +288,9 @@ type WithSkipAndOnly = ((...args: T) => void) & { only: (...args: T) => void; }; -function createTestWrapper(fn: (it: Mocha.PendingTestFunction, ...args: T) => void): WithSkipAndOnly { +function createTestWrapper( + fn: (it: Mocha.PendingTestFunction, ...args: T) => void, +): WithSkipAndOnly { wrapped.skip = (...args: T) => fn(it.skip, ...args); wrapped.only = (...args: T) => fn(it.only, ...args); return wrapped; @@ -309,7 +312,13 @@ const enum ConvertToAsyncTestFlags { ExpectFailed = ExpectNoSuggestionDiagnostic | ExpectNoAction, } -function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: string, text: string, baselineFolder: string, flags: ConvertToAsyncTestFlags) { +function testConvertToAsyncFunction( + it: Mocha.PendingTestFunction, + caption: string, + text: string, + baselineFolder: string, + flags: ConvertToAsyncTestFlags, +) { const includeLib = !!(flags & ConvertToAsyncTestFlags.IncludeLib); const includeModule = !!(flags & ConvertToAsyncTestFlags.IncludeModule); const expectSuggestionDiagnostic = !!(flags & ConvertToAsyncTestFlags.ExpectSuggestionDiagnostic); @@ -317,7 +326,10 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri const expectAction = !!(flags & ConvertToAsyncTestFlags.ExpectAction); const expectNoAction = !!(flags & ConvertToAsyncTestFlags.ExpectNoAction); const expectFailure = expectNoSuggestionDiagnostic || expectNoAction; - ts.Debug.assert(!(expectSuggestionDiagnostic && expectNoSuggestionDiagnostic), "Cannot combine both 'ExpectSuggestionDiagnostic' and 'ExpectNoSuggestionDiagnostic'"); + ts.Debug.assert( + !(expectSuggestionDiagnostic && expectNoSuggestionDiagnostic), + "Cannot combine both 'ExpectSuggestionDiagnostic' and 'ExpectNoSuggestionDiagnostic'", + ); ts.Debug.assert(!(expectAction && expectNoAction), "Cannot combine both 'ExpectAction' and 'ExpectNoAction'"); const t = extractTest(text); @@ -328,8 +340,7 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri const extensions = expectFailure ? [ts.Extension.Ts] : [ts.Extension.Ts, ts.Extension.Js]; - extensions.forEach(extension => - it(`${caption} [${extension}]`, () => runBaseline(extension))); + extensions.forEach(extension => it(`${caption} [${extension}]`, () => runBaseline(extension))); function runBaseline(extension: ts.Extension) { const path = "/a" + extension; @@ -344,7 +355,7 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri const f = { path, - content: t.source + content: t.source, }; const sourceFile = program.getSourceFile(path)!; @@ -356,14 +367,21 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri cancellationToken: { throwIfCancellationRequested: ts.noop, isCancellationRequested: ts.returnFalse }, preferences: ts.emptyOptions, host: notImplementedHost, - formatContext: ts.formatting.getFormatContext(ts.testFormatSettings, notImplementedHost) + formatContext: ts.formatting.getFormatContext(ts.testFormatSettings, notImplementedHost), }; const diagnostics = languageService.getSuggestionDiagnostics(f.path); - const diagnostic = ts.find(diagnostics, diagnostic => diagnostic.messageText === ts.Diagnostics.This_may_be_converted_to_an_async_function.message && - diagnostic.start === context.span.start && diagnostic.length === context.span.length); + const diagnostic = ts.find( + diagnostics, + diagnostic => + diagnostic.messageText === ts.Diagnostics.This_may_be_converted_to_an_async_function.message + && diagnostic.start === context.span.start && diagnostic.length === context.span.length, + ); const actions = ts.codefix.getFixes(context); - const action = ts.find(actions, action => action.description === ts.Diagnostics.Convert_to_async_function.message); + const action = ts.find( + actions, + action => action.description === ts.Diagnostics.Convert_to_async_function.message, + ); let outputText: string | null; if (action?.changes.length) { @@ -377,7 +395,8 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri const newText = ts.textChanges.applyChanges(sourceFile.text, changes[0].textChanges); data.push(newText); - const diagProgram = makeLanguageService({ path, content: newText }, includeLib, includeModule).getProgram()!; + const diagProgram = makeLanguageService({ path, content: newText }, includeLib, includeModule) + .getProgram()!; assert.isFalse(hasSyntacticDiagnostics(diagProgram)); outputText = data.join(newLineCharacter); } @@ -426,78 +445,146 @@ function testConvertToAsyncFunction(it: Mocha.PendingTestFunction, caption: stri } const _testConvertToAsyncFunction = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuccess); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuccess, + ); }); const _testConvertToAsyncFunctionFailed = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectFailed); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectFailed, + ); }); const _testConvertToAsyncFunctionFailedSuggestion = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectNoSuggestionDiagnostic | ConvertToAsyncTestFlags.ExpectAction); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectNoSuggestionDiagnostic + | ConvertToAsyncTestFlags.ExpectAction, + ); }); const _testConvertToAsyncFunctionFailedAction = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuggestionDiagnostic | ConvertToAsyncTestFlags.ExpectNoAction); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.ExpectSuggestionDiagnostic + | ConvertToAsyncTestFlags.ExpectNoAction, + ); }); const _testConvertToAsyncFunctionWithModule = createTestWrapper((it, caption: string, text: string) => { - testConvertToAsyncFunction(it, caption, text, "convertToAsyncFunction", ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.IncludeModule | ConvertToAsyncTestFlags.ExpectSuccess); + testConvertToAsyncFunction( + it, + caption, + text, + "convertToAsyncFunction", + ConvertToAsyncTestFlags.IncludeLib | ConvertToAsyncTestFlags.IncludeModule + | ConvertToAsyncTestFlags.ExpectSuccess, + ); }); describe("unittests:: services:: convertToAsyncFunction", () => { - _testConvertToAsyncFunction("convertToAsyncFunction_basic", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_basic", + ` function [#|f|](): Promise{ return fetch('https://typescriptlang.org').then(result => { console.log(result) }); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_arrayBindingPattern", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_arrayBindingPattern", + ` function [#|f|](): Promise{ return fetch('https://typescriptlang.org').then(([result]) => { console.log(result) }); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_objectBindingPattern", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_objectBindingPattern", + ` function [#|f|](): Promise{ return fetch('https://typescriptlang.org').then(({ result }) => { console.log(result) }); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_arrayBindingPatternRename", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_arrayBindingPatternRename", + ` function [#|f|](): Promise{ const result = getResult(); return fetch('https://typescriptlang.org').then(([result]) => { console.log(result) }); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_objectBindingPatternRename", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_objectBindingPatternRename", + ` function [#|f|](): Promise{ const result = getResult(); return fetch('https://typescriptlang.org').then(({ result }) => { console.log(result) }); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_basicNoReturnTypeAnnotation", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_basicNoReturnTypeAnnotation", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(result => { console.log(result) }); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_basicWithComments", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_basicWithComments", + ` function [#|f|](): Promise{ /* Note - some of these comments are removed during the refactor. This is not ideal. */ // a /*b*/ return /*c*/ fetch( /*d*/ 'https://typescriptlang.org' /*e*/).then( /*f*/ result /*g*/ => { /*h*/ console.log(/*i*/ result /*j*/) /*k*/}/*l*/); // m -}`); +}`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_ArrowFunction", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_ArrowFunction", + ` [#|():Promise => {|] return fetch('https://typescriptlang.org').then(result => console.log(result)); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_ArrowFunctionNoAnnotation", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_ArrowFunctionNoAnnotation", + ` [#|() => {|] return fetch('https://typescriptlang.org').then(result => console.log(result)); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_Catch", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_Catch", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(result => { console.log(result); }).catch(err => { console.log(err); }); -}`); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_CatchAndRej", ` +}`, + ); + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_CatchAndRej", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); }).catch(err => { console.log(err) }); -}`); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_CatchAndRejRef", ` +}`, + ); + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_CatchAndRejRef", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(res, rej).catch(catch_err) } @@ -509,8 +596,11 @@ function rej(rejection){ } function catch_err(err){ console.log(err); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchRef", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchRef", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(res).catch(catch_err) } @@ -520,49 +610,66 @@ function res(result){ function catch_err(err){ console.log(err); } -`); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchNoBrackets", ` +`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchNoBrackets", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(result => console.log(result)).catch(err => console.log(err)); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_IgnoreArgs1", + ` function [#|f|](): Promise { return fetch('https://typescriptlang.org').then( _ => { console.log("done"); }); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_IgnoreArgs2", + ` function [#|f|](): Promise { return fetch('https://typescriptlang.org').then( () => console.log("done") ); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs3", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_IgnoreArgs3", + ` function [#|f|](): Promise { return fetch('https://typescriptlang.org').then( () => console.log("almost done") ).then( () => console.log("done") ); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs4", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_IgnoreArgs4", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(res); } function res(){ console.log("done"); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Method", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Method", + ` class Parser { [#|f|]():Promise { return fetch('https://typescriptlang.org').then(result => console.log(result)); } -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_MultipleCatches", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_MultipleCatches", + ` function [#|f|](): Promise { return fetch('https://typescriptlang.org').then(res => console.log(res)).catch(err => console.log("err", err)).catch(err2 => console.log("err2", err2)); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_MultipleThens", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_MultipleThens", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(res).then(res2); } @@ -571,9 +678,11 @@ function res(result){ } function res2(result2){ console.log(result2); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_MultipleThensSameVarName", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_MultipleThensSameVarName", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(res).then(res2); } @@ -583,65 +692,85 @@ function res(result){ function res2(result){ return result.bodyUsed; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_NoRes", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_NoRes", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(null, rejection => console.log("rejected:", rejection)); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_NoRes2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_NoRes2", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(undefined).catch(rej => console.log(rej)); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_NoRes3", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_NoRes3", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').catch(rej => console.log(rej)); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_NoRes4", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_NoRes4", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(undefined, rejection => console.log("rejected:", rejection)); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_NoCatchHandler", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_NoCatchHandler", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(x => x.statusText).catch(undefined); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestion", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_NoSuggestion", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org'); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_PromiseDotAll", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_PromiseDotAll", + ` function [#|f|]():Promise{ return Promise.all([fetch('https://typescriptlang.org'), fetch('https://microsoft.com'), fetch('https://youtube.com')]).then(function(vals){ vals.forEach(console.log); }); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionNoPromise", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_NoSuggestionNoPromise", + ` function [#|f|]():void{ } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Rej", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_Rej", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); }); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_RejRef", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_RejRef", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(res, rej); } @@ -651,26 +780,32 @@ function res(result){ function rej(err){ console.log(err); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_RejNoBrackets", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_RejNoBrackets", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(result => console.log(result), rejection => console.log("rejected:", rejection)); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_ResRef", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_ResRef", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(res); } function res(result){ return result.ok; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_ResRef1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_ResRef1", + ` class Foo { public [#|method|](): Promise { return fetch('a').then(this.foo); @@ -680,9 +815,12 @@ class Foo { return res.ok; } } - `); + `, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_ResRef2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_ResRef2", + ` class Foo { public [#|method|](): Promise { return fetch('a').then(this.foo); @@ -690,65 +828,80 @@ class Foo { private foo = res => res; } - `); + `, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_ResRef3", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_ResRef3", + ` const res = (result) => { return result.ok; } function [#|f|](): Promise { return fetch('https://typescriptlang.org').then(res); } - ` + `, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionResRef1", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_NoSuggestionResRef1", + ` const res = 1; function [#|f|]() { return fetch('https://typescriptlang.org').then(res); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionResRef2", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_NoSuggestionResRef2", + ` class Foo { private foo = 1; public [#|method|](): Promise { return fetch('a').then(this.foo); } } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionResRef3", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_NoSuggestionResRef3", + ` const res = undefined; function [#|f|]() { return fetch('https://typescriptlang.org').then(res); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionResRef4", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_NoSuggestionResRef4", + ` class Foo { private foo = undefined; public [#|method|](): Promise { return fetch('a').then(this.foo); } } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_ResRefNoReturnVal", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_ResRefNoReturnVal", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(res); } function res(result){ console.log(result); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_ResRefNoReturnVal1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_ResRefNoReturnVal1", + ` class Foo { public [#|method|](): Promise { return fetch('a').then(this.foo); @@ -758,35 +911,46 @@ class Foo { console.log(res); } } - `); + `, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_NoBrackets", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_NoBrackets", + ` function [#|f|]():Promise { return fetch('https://typescriptlang.org').then(result => console.log(result)); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally1", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_Finally1", + ` function [#|finallyTest|](): Promise { return fetch("https://typescriptlang.org").then(res => console.log(res)).catch(rej => console.log("error", rej)).finally(console.log("finally!")); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally2", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_Finally2", + ` function [#|finallyTest|](): Promise { return fetch("https://typescriptlang.org").then(res => console.log(res)).finally(console.log("finally!")); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally3", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_Finally3", + ` function [#|finallyTest|](): Promise { return fetch("https://typescriptlang.org").finally(console.log("finally!")); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromise", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_InnerPromise", + ` function [#|innerPromise|](): Promise { return fetch("https://typescriptlang.org").then(resp => { var blob2 = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); @@ -795,9 +959,11 @@ function [#|innerPromise|](): Promise { return blob.toString(); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRet", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_InnerPromiseRet", + ` function [#|innerPromise|](): Promise { return fetch("https://typescriptlang.org").then(resp => { return resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); @@ -805,10 +971,12 @@ function [#|innerPromise|](): Promise { return blob.toString(); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRetBinding1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_InnerPromiseRetBinding1", + ` function [#|innerPromise|](): Promise { return fetch("https://typescriptlang.org").then(resp => { return resp.blob().then(({ blob }) => blob.byteOffset).catch(({ message }) => 'Error ' + message); @@ -816,10 +984,12 @@ function [#|innerPromise|](): Promise { return blob.toString(); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRetBinding2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_InnerPromiseRetBinding2", + ` function [#|innerPromise|](): Promise { return fetch("https://typescriptlang.org").then(resp => { return resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); @@ -827,10 +997,12 @@ function [#|innerPromise|](): Promise { return x.toString(); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRetBinding3", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_InnerPromiseRetBinding3", + ` function [#|innerPromise|](): Promise { return fetch("https://typescriptlang.org").then(resp => { return resp.blob().then(({ blob }) => blob.byteOffset).catch(({ message }) => 'Error ' + message); @@ -838,10 +1010,12 @@ function [#|innerPromise|](): Promise { return (x || y).toString(); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRetBinding4", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_InnerPromiseRetBinding4", + ` function [#|innerPromise|](): Promise { return fetch("https://typescriptlang.org").then(resp => { return resp.blob().then(({ blob }: { blob: { byteOffset: number } }) => [0, blob.byteOffset]).catch(({ message }: Error) => ['Error ', message]); @@ -849,25 +1023,31 @@ function [#|innerPromise|](): Promise { return (x || y).toString(); }); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn01", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn01", + ` function [#|f|]() { let blob = fetch("https://typescriptlang.org").then(resp => console.log(resp)); return blob; } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn02", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn02", + ` function [#|f|]() { let blob = fetch("https://typescriptlang.org"); blob.then(resp => console.log(resp)); return blob; } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn03", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn03", + ` function [#|f|]() { let blob = fetch("https://typescriptlang.org") let blob2 = blob.then(resp => console.log(resp)); @@ -878,9 +1058,11 @@ function [#|f|]() { function err (rej) { console.log(rej) } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn04", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn04", + ` function [#|f|]() { var blob = fetch("https://typescriptlang.org").then(res => console.log(res)), blob2 = fetch("https://microsoft.com").then(res => res.ok).catch(err); return blob; @@ -888,27 +1070,33 @@ function [#|f|]() { function err (rej) { console.log(rej) } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn05", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn05", + ` function [#|f|]() { var blob = fetch("https://typescriptlang.org").then(res => console.log(res)); blob.then(x => x); return blob; } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn06", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn06", + ` function [#|f|]() { var blob = fetch("https://typescriptlang.org"); return blob; } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn07", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn07", + ` function [#|f|]() { let blob = fetch("https://typescriptlang.org"); let blob2 = fetch("https://microsoft.com"); @@ -916,10 +1104,12 @@ function [#|f|]() { blob.then(resp => console.log(resp)); return blob; } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn08", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn08", + ` function [#|f|]() { let blob = fetch("https://typescriptlang.org"); if (!blob.ok){ @@ -928,10 +1118,12 @@ function [#|f|]() { blob.then(resp => console.log(resp)); return blob; } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn09", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn09", + ` function [#|f|]() { let blob3; let blob = fetch("https://typescriptlang.org"); @@ -941,11 +1133,12 @@ function [#|f|]() { blob3 = blob2.catch(rej => rej.ok); return blob; } -` +`, ); - - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn10", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn10", + ` function [#|f|]() { let blob3; let blob = fetch("https://typescriptlang.org"); @@ -956,20 +1149,22 @@ function [#|f|]() { blob3 = blob2; return blob; } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn11", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_VarReturn11", + ` function [#|f|]() { let blob; return blob; } -` +`, ); - - - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Param1", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_Param1", + ` function [#|f|]() { return my_print(fetch("https://typescriptlang.org").then(res => console.log(res))); } @@ -980,10 +1175,12 @@ function my_print (resp) { return resp; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Param2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Param2", + ` function [#|f|]() { return my_print(fetch("https://typescriptlang.org").then(res => console.log(res))).catch(err => console.log("Error!", err)); } @@ -995,10 +1192,12 @@ function my_print (resp): Promise { } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_MultipleReturns1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_MultipleReturns1", + ` function [#|f|](): Promise { let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); if (x.ok) { @@ -1008,10 +1207,12 @@ function [#|f|](): Promise { var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_MultipleReturns2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_MultipleReturns2", + ` function [#|f|](): Promise { let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); if (x.ok) { @@ -1022,11 +1223,12 @@ function [#|f|](): Promise { return fetch("https://microsoft.com").then(res => console.log("Another one!")); }); } -` +`, ); - - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_SeperateLines", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_SeperateLines", + ` function [#|f|](): Promise { var blob = fetch("https://typescriptlang.org") blob.then(resp => { @@ -1038,11 +1240,12 @@ function [#|f|](): Promise { return blob; } -` +`, ); - - _testConvertToAsyncFunction("convertToAsyncFunction_InnerVarNameConflict", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_InnerVarNameConflict", + ` function [#|f|](): Promise { return fetch("https://typescriptlang.org").then(resp => { var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); @@ -1050,9 +1253,11 @@ function [#|f|](): Promise { return blob.toString(); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseSimple", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_InnerPromiseSimple", + ` function [#|f|](): Promise { return fetch("https://typescriptlang.org").then(resp => { return resp.blob().then(blob => blob.byteOffset); @@ -1060,9 +1265,11 @@ function [#|f|](): Promise { return blob.toString(); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_PromiseAllAndThen1", + ` function [#|f|]() { return Promise.resolve().then(function () { return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { @@ -1070,10 +1277,12 @@ function [#|f|]() { }).then(res => res.toString())]); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_PromiseAllAndThen2", + ` function [#|f|]() { return Promise.resolve().then(function () { return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { @@ -1081,29 +1290,35 @@ function [#|f|]() { })]).then(res => res.toString()); }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen3", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_PromiseAllAndThen3", + ` function [#|f|]() { return Promise.resolve().then(() => Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { return fetch("https://github.com"); }).then(res => res.toString())])); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen4", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_PromiseAllAndThen4", + ` function [#|f|]() { return Promise.resolve().then(() => Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { return fetch("https://github.com"); })]).then(res => res.toString())); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Scope1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Scope1", + ` function [#|f|]() { var var1: Response, var2; return fetch('https://typescriptlang.org').then( _ => @@ -1118,9 +1333,12 @@ function [#|f|]() { function res(response){ console.log(response); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_Conditionals", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Conditionals", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res => { if (res.ok) { @@ -1136,10 +1354,12 @@ function [#|f|](){ } }); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThen", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThen", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); } @@ -1151,10 +1371,12 @@ function res(result){ function rej(reject){ return reject; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes01", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMatchingTypes01", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); } @@ -1166,10 +1388,12 @@ function res(result): number { function rej(reject): number { return 3; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); } @@ -1181,11 +1405,12 @@ function res(result){ function rej(reject){ return 3; } -` +`, ); - - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes02", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMatchingTypes02", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res); } @@ -1193,10 +1418,12 @@ function [#|f|](){ function res(result): number { return 5; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res); } @@ -1204,10 +1431,12 @@ function [#|f|](){ function res(result){ return 5; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes01", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMismatchTypes01", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); } @@ -1219,10 +1448,12 @@ function res(result){ function rej(reject){ return "Error"; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes02", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMismatchTypes02", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); } @@ -1234,10 +1465,12 @@ function res(result){ function rej(reject): Response{ return reject; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); } @@ -1249,11 +1482,12 @@ function res(result){ function rej(reject){ return reject; } -` +`, ); - - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes03", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMismatchTypes03", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); } @@ -1265,10 +1499,12 @@ function res(result){ function rej(reject){ return Promise.resolve(1); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes04", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_CatchFollowedByThenMismatchTypes04", + ` interface a { name: string; age: number; @@ -1290,10 +1526,12 @@ function res(result): b{ function rej(reject): a{ return {name: "myName", age: 27}; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_ParameterNameCollision", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_ParameterNameCollision", + ` async function foo(x: T): Promise { return x; } @@ -1301,45 +1539,59 @@ async function foo(x: T): Promise { function [#|bar|](x: T): Promise { return foo(x).then(foo) } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Return1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Return1", + ` function [#|f|](p: Promise) { return p.catch((error: Error) => { return Promise.reject(error); }); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Return2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Return2", + ` function [#|f|](p: Promise) { return p.catch((error: Error) => Promise.reject(error)); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Return3", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Return3", + ` function [#|f|](p: Promise) { return p.catch(function (error: Error) { return Promise.reject(error); }); -}` +}`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_LocalReturn", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_LocalReturn", + ` function [#|f|]() { let x = fetch("https://typescriptlang.org").then(res => console.log(res)); return x.catch(err => console.log("Error!", err)); } -`); - _testConvertToAsyncFunction("convertToAsyncFunction_PromiseCallInner", ` +`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_PromiseCallInner", + ` function [#|f|]() { return fetch(Promise.resolve(1).then(res => "https://typescriptlang.org")).catch(err => console.log(err)); } -`); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_CatchFollowedByCall", ` +`, + ); + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_CatchFollowedByCall", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res).catch(rej).toString(); } @@ -1351,27 +1603,33 @@ function res(result){ function rej(reject){ return reject; } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Scope2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Scope2", + ` function [#|f|](){ var i:number; return fetch("https://typescriptlang.org").then(i => i.ok).then(res => i+1).catch(err => i-1) } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Loop", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Loop", + ` function [#|f|](){ return fetch("https://typescriptlang.org").then(res => { for(let i=0; i<10; i++){ console.log(res); }}) } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Conditional2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Conditional2", + ` function [#|f|](){ var res = 100; if (res > 50) { @@ -1385,10 +1643,12 @@ function [#|f|](){ function res_func(result){ console.log(result); } -` +`, ); - _testConvertToAsyncFunction("convertToAsyncFunction_Scope3", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_Scope3", + ` function [#|f|]() { var obj; return fetch("https://typescriptlang.org").then(function (res) { @@ -1399,10 +1659,12 @@ function [#|f|]() { }; }); } -` +`, ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NestedFunctionWrongLocation", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_NestedFunctionWrongLocation", + ` function [#|f|]() { function fn2(){ function fn3(){ @@ -1412,9 +1674,12 @@ function [#|f|]() { } return fn2(); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_NestedFunctionRightLocation", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_NestedFunctionRightLocation", + ` function f() { function fn2(){ function [#|fn3|](){ @@ -1424,67 +1689,97 @@ function f() { } return fn2(); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_UntypedFunction", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_UntypedFunction", + ` function [#|f|]() { return Promise.resolve().then(res => console.log(res)); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_TernaryConditional", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_TernaryConditional", + ` function [#|f|]() { let i; return Promise.resolve().then(res => res ? i = res : i = 100); } -`); +`, + ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_ResRejNoArgsArrow", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_ResRejNoArgsArrow", + ` function [#|f|]() { return Promise.resolve().then(() => 1, () => "a"); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpression", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_simpleFunctionExpression", + ` const [#|foo|] = function () { return fetch('https://typescriptlang.org').then(result => { console.log(result) }); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionWithName", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_simpleFunctionExpressionWithName", + ` const foo = function [#|f|]() { return fetch('https://typescriptlang.org').then(result => { console.log(result) }); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionAssignedToBindingPattern", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_simpleFunctionExpressionAssignedToBindingPattern", + ` const { length } = [#|function|] () { return fetch('https://typescriptlang.org').then(result => { console.log(result) }); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_catchBlockUniqueParams", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_catchBlockUniqueParams", + ` function [#|f|]() { return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_catchBlockUniqueParamsBindingPattern", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_catchBlockUniqueParamsBindingPattern", + ` function [#|f|]() { return Promise.resolve().then(() => ({ x: 3 })).catch(() => ({ x: "a" })).then(({ x }) => !!x); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_bindingPattern", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_bindingPattern", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(res); } function res({ status, trailer }){ console.log(status); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_bindingPatternNameCollision", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_bindingPatternNameCollision", + ` function [#|f|]() { const result = 'https://typescriptlang.org'; return fetch(result).then(res); @@ -1492,68 +1787,98 @@ function [#|f|]() { function res({ status, trailer }){ console.log(status); } -`); +`, + ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunction", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_thenArgumentNotFunction", + ` function [#|f|]() { return Promise.resolve().then(f ? (x => x) : (y => y)); } -`); +`, + ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunctionNotLastInChain", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_thenArgumentNotFunctionNotLastInChain", + ` function [#|f|]() { return Promise.resolve().then(f ? (x => x) : (y => y)).then(q => q); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_runEffectfulContinuation", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_runEffectfulContinuation", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(res).then(_ => console.log("done")); } function res(result) { return Promise.resolve().then(x => console.log(result)); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromise", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_callbackReturnsPromise", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)).then(x => console.log(x + 5)); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromiseInBlock", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_callbackReturnsPromiseInBlock", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(s => { return Promise.resolve(s.statusText.length) }).then(x => x + 5); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsFixablePromise", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_callbackReturnsFixablePromise", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText).then(st => st.length)).then(x => console.log(x + 5)); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromiseLastInChain", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_callbackReturnsPromiseLastInChain", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsRejectedPromiseInTryBlock", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_callbackReturnsRejectedPromiseInTryBlock", + ` function [#|f|]() { return Promise.resolve(1) .then(x => Promise.reject(x)) .catch(err => console.log(err)); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_nestedPromises", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_nestedPromises", + ` function [#|f|]() { return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y))); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_noArgs1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_noArgs1", + ` function delay(millis: number): Promise { throw "no" } @@ -1565,9 +1890,12 @@ function [#|main2|]() { .then(() => { console.log("."); return delay(500); }) .then(() => { console.log("."); return delay(500); }) } - `); + `, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_noArgs2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_noArgs2", + ` function delay(millis: number): Promise { throw "no" } @@ -1579,22 +1907,31 @@ function [#|main2|]() { .then(() => delay(500)) .then(() => delay(500)) } - `); + `, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_exportModifier", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_exportModifier", + ` export function [#|foo|]() { return fetch('https://typescriptlang.org').then(s => console.log(s)); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_OutermostOnlySuccess", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_OutermostOnlySuccess", + ` function [#|foo|]() { return fetch('a').then(() => { return fetch('b').then(() => 'c'); }) } -`); - _testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethod", ` +`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_decoratedMethod", + ` function decorator() { return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor; } @@ -1604,9 +1941,12 @@ class Foo { return fetch('a').then(x => x); } } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithSingleLineComment", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_decoratedMethodWithSingleLineComment", + ` function decorator() { return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor; } @@ -1617,9 +1957,12 @@ class Foo { return fetch('a').then(x => x); } } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithMultipleLineComment", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_decoratedMethodWithMultipleLineComment", + ` function decorator() { return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor; } @@ -1632,9 +1975,12 @@ class Foo { return fetch('a').then(x => x); } } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_decoratedMethodWithModifier", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_decoratedMethodWithModifier", + ` function decorator() { return (target: any, key: any, descriptor: PropertyDescriptor) => descriptor; } @@ -1644,17 +1990,23 @@ class Foo { return fetch('a').then(x => x); } } -`); +`, + ); - _testConvertToAsyncFunctionFailedSuggestion("convertToAsyncFunction_OutermostOnlyFailure", ` + _testConvertToAsyncFunctionFailedSuggestion( + "convertToAsyncFunction_OutermostOnlyFailure", + ` function foo() { return fetch('a').then([#|() => {|] return fetch('b').then(() => 'c'); }) } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_thenTypeArgument1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_thenTypeArgument1", + ` type APIResponse = { success: true, data: T } | { success: false }; function wrapResponse(response: T): APIResponse { @@ -1664,9 +2016,12 @@ function wrapResponse(response: T): APIResponse { function [#|get|]() { return Promise.resolve(undefined!).then>(wrapResponse); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_thenTypeArgument2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_thenTypeArgument2", + ` type APIResponse = { success: true, data: T } | { success: false }; function wrapResponse(response: T): APIResponse { @@ -1676,9 +2031,12 @@ function wrapResponse(response: T): APIResponse { function [#|get|]() { return Promise.resolve(undefined!).then>(d => wrapResponse(d)); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_thenTypeArgument3", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_thenTypeArgument3", + ` type APIResponse = { success: true, data: T } | { success: false }; function wrapResponse(response: T): APIResponse { @@ -1691,9 +2049,12 @@ function [#|get|]() { return wrapResponse(d); }); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_catchTypeArgument1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_catchTypeArgument1", + ` type APIResponse = { success: true, data: T } | { success: false }; function [#|get|]() { @@ -1701,14 +2062,20 @@ function [#|get|]() { .resolve>({ success: true, data: { email: "" } }) .catch>(() => ({ success: false })); } -`); +`, + ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction_threeArguments", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction_threeArguments", + ` function [#|f|]() { return Promise.resolve().then(undefined, undefined, () => 1); -}`); +}`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_callbackArgument", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_callbackArgument", + ` function foo(props: any): void { return props; } @@ -1719,54 +2086,75 @@ const fn = (): Promise<(message: string) => void> => function [#|f|]() { return fn().then(res => res("test")); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_emptyCatch1", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_emptyCatch1", + ` function [#|f|]() { return Promise.resolve().catch(); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_emptyCatch2", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_emptyCatch2", + ` function [#|f|]() { return Promise.resolve(0).then(x => x).catch(); } -`); +`, + ); - _testConvertToAsyncFunctionWithModule("convertToAsyncFunction_importedFunction", ` + _testConvertToAsyncFunctionWithModule( + "convertToAsyncFunction_importedFunction", + ` import { fn } from "./module"; function [#|f|]() { return Promise.resolve(0).then(fn); } -`); +`, + ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction__NoSuggestionInFunctionsWithNonFixableReturnStatements1", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction__NoSuggestionInFunctionsWithNonFixableReturnStatements1", + ` function f(x: number): Promise; function f(): void; function [#|f|](x?: number): Promise | void { if (!x) return; return fetch('').then(() => {}); } -`); +`, + ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction__NoSuggestionInFunctionsWithNonFixableReturnStatements2", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction__NoSuggestionInFunctionsWithNonFixableReturnStatements2", + ` function f(x: number): Promise; function f(): number; function [#|f|](x?: number): Promise | number { if (x) return x; return fetch('').then(() => {}); } -`); +`, + ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction__NoSuggestionInGetters", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction__NoSuggestionInGetters", + ` class Foo { get [#|m|](): Promise { return Promise.resolve(1).then(n => n); } } -`); +`, + ); - _testConvertToAsyncFunctionFailed("convertToAsyncFunction__NoSuggestionForGeneratorCallbacks", ` + _testConvertToAsyncFunctionFailed( + "convertToAsyncFunction__NoSuggestionForGeneratorCallbacks", + ` function [#|foo|](p: Promise) { return p.then(function* (strings) { for (const s of strings) { @@ -1774,54 +2162,84 @@ function [#|foo|](p: Promise) { } }); } -`); +`, + ); - _testConvertToAsyncFunction("convertToAsyncFunction_thenNoArguments", ` + _testConvertToAsyncFunction( + "convertToAsyncFunction_thenNoArguments", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().then(); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_catchNoArguments", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_catchNoArguments", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().catch(); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_chainedThenCatchThen", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_chainedThenCatchThen", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().then(x => Promise.resolve(x + 1)).catch(() => 1).then(y => y + 2); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_finally", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_finally", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().finally(() => console.log("done")); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_finallyNoArguments", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_finallyNoArguments", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().finally(); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_finallyNull", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_finallyNull", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().finally(null); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_finallyUndefined", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_finallyUndefined", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().finally(undefined); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_thenFinally", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_thenFinally", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().then(x => x + 1).finally(() => console.log("done")); -}`); - _testConvertToAsyncFunction("convertToAsyncFunction_thenFinallyThen", ` +}`, + ); + _testConvertToAsyncFunction( + "convertToAsyncFunction_thenFinallyThen", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().then(x => Promise.resolve(x + 1)).finally(() => console.log("done")).then(y => y + 2); -}`); - _testConvertToAsyncFunctionFailedAction("convertToAsyncFunction_returnInBranch", ` +}`, + ); + _testConvertToAsyncFunctionFailedAction( + "convertToAsyncFunction_returnInBranch", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().then(() => { @@ -1833,8 +2251,11 @@ function [#|f|](): Promise { return a + 1; }); } -`); - _testConvertToAsyncFunctionFailedAction("convertToAsyncFunction_partialReturnInBranch", ` +`, + ); + _testConvertToAsyncFunctionFailedAction( + "convertToAsyncFunction_partialReturnInBranch", + ` declare function foo(): Promise; function [#|f|](): Promise { return foo().then(() => { @@ -1846,5 +2267,6 @@ function [#|f|](): Promise { return a + 1; }); } -`); +`, + ); }); diff --git a/src/testRunner/unittests/services/documentRegistry.ts b/src/testRunner/unittests/services/documentRegistry.ts index 6281f73125276..87078f86e5f93 100644 --- a/src/testRunner/unittests/services/documentRegistry.ts +++ b/src/testRunner/unittests/services/documentRegistry.ts @@ -5,8 +5,18 @@ describe("unittests:: services:: DocumentRegistry", () => { const documentRegistry = ts.createDocumentRegistry(); const defaultCompilerOptions = ts.getDefaultCompilerOptions(); - const f1 = documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); - const f2 = documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f1 = documentRegistry.acquireDocument( + "file1.ts", + defaultCompilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); + const f2 = documentRegistry.acquireDocument( + "file1.ts", + defaultCompilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f1 === f2, "DocumentRegistry should return the same document for the same name"); }); @@ -17,26 +27,50 @@ describe("unittests:: services:: DocumentRegistry", () => { // change compilation setting that doesn't affect parsing - should have the same document compilerOptions.declaration = true; - const f1 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f1 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); compilerOptions.declaration = false; - const f2 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f2 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f1 === f2, "Expected to have the same document instance"); - // change value of compilation setting that is used during production of AST - new document is required compilerOptions.target = ts.ScriptTarget.ES3; - const f3 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f3 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f1 !== f3, "Changed target: Expected to have different instances of document"); compilerOptions.preserveConstEnums = true; - const f4 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f4 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f3 === f4, "Changed preserveConstEnums: Expected to have the same instance of the document"); compilerOptions.module = ts.ModuleKind.System; - const f5 = documentRegistry.acquireDocument("file1.ts", compilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + const f5 = documentRegistry.acquireDocument( + "file1.ts", + compilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); assert(f4 !== f5, "Changed module: Expected to have different instances of the document"); }); @@ -46,10 +80,20 @@ describe("unittests:: services:: DocumentRegistry", () => { const defaultCompilerOptions = ts.getDefaultCompilerOptions(); // Simulate one LS getting the document. - documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "1"); + documentRegistry.acquireDocument( + "file1.ts", + defaultCompilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "1", + ); // Simulate another LS getting the document at another version. - const f2 = documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, ts.ScriptSnapshot.fromString("var x = 1;"), /* version */ "2"); + const f2 = documentRegistry.acquireDocument( + "file1.ts", + defaultCompilerOptions, + ts.ScriptSnapshot.fromString("var x = 1;"), + /* version */ "2", + ); assert(f2.version === "2"); }); @@ -62,7 +106,8 @@ describe("unittests:: services:: DocumentRegistry", () => { const snapshot = ts.ScriptSnapshot.fromString(contents); // Always treat any change as a full change. - snapshot.getChangeRange = () => ts.createTextChangeRange(ts.createTextSpan(0, contents.length), contents.length); + snapshot.getChangeRange = () => + ts.createTextChangeRange(ts.createTextSpan(0, contents.length), contents.length); // Simulate one LS getting the document. documentRegistry.acquireDocument("file1.ts", defaultCompilerOptions, snapshot, /* version */ "1"); diff --git a/src/testRunner/unittests/services/extract/constants.ts b/src/testRunner/unittests/services/extract/constants.ts index 24b44e689deb0..a479a311b1aea 100644 --- a/src/testRunner/unittests/services/extract/constants.ts +++ b/src/testRunner/unittests/services/extract/constants.ts @@ -5,59 +5,73 @@ import { } from "./helpers"; describe("unittests:: services:: extract:: extractConstants", () => { - testExtractConstant("extractConstant_TopLevel", - `let x = [#|1|];`); + testExtractConstant("extractConstant_TopLevel", `let x = [#|1|];`); - testExtractConstant("extractConstant_Namespace", + testExtractConstant( + "extractConstant_Namespace", `namespace N { let x = [#|1|]; -}`); +}`, + ); - testExtractConstant("extractConstant_Class", + testExtractConstant( + "extractConstant_Class", `class C { x = [#|1|]; -}`); +}`, + ); - testExtractConstant("extractConstant_Method", + testExtractConstant( + "extractConstant_Method", `class C { M() { let x = [#|1|]; } -}`); +}`, + ); - testExtractConstant("extractConstant_Function", + testExtractConstant( + "extractConstant_Function", `function F() { let x = [#|1|]; -}`); +}`, + ); - testExtractConstant("extractConstant_ExpressionStatement", - `[#|"hello";|]`); + testExtractConstant("extractConstant_ExpressionStatement", `[#|"hello";|]`); - testExtractConstant("extractConstant_ExpressionStatementExpression", - `[#|"hello"|];`); + testExtractConstant("extractConstant_ExpressionStatementExpression", `[#|"hello"|];`); - testExtractConstant("extractConstant_ExpressionStatementInNestedScope", ` + testExtractConstant( + "extractConstant_ExpressionStatementInNestedScope", + ` let i = 0; function F() { [#|i++|]; } - `); + `, + ); - testExtractConstant("extractConstant_ExpressionStatementConsumesLocal", ` + testExtractConstant( + "extractConstant_ExpressionStatementConsumesLocal", + ` function F() { let i = 0; [#|i++|]; } - `); + `, + ); - testExtractConstant("extractConstant_BlockScopes_NoDependencies", + testExtractConstant( + "extractConstant_BlockScopes_NoDependencies", `for (let i = 0; i < 10; i++) { for (let j = 0; j < 10; j++) { let x = [#|1|]; } -}`); +}`, + ); - testExtractConstant("extractConstant_ClassInsertionPosition1", + testExtractConstant( + "extractConstant_ClassInsertionPosition1", `class C { a = 1; b = 2; @@ -66,9 +80,11 @@ function F() { M3() { let x = [#|1|]; } -}`); +}`, + ); - testExtractConstant("extractConstant_ClassInsertionPosition2", + testExtractConstant( + "extractConstant_ClassInsertionPosition2", `class C { a = 1; M1() { } @@ -77,9 +93,11 @@ function F() { M3() { let x = [#|1|]; } -}`); +}`, + ); - testExtractConstant("extractConstant_ClassInsertionPosition3", + testExtractConstant( + "extractConstant_ClassInsertionPosition3", `class C { M1() { } a = 1; @@ -88,91 +106,121 @@ function F() { M3() { let x = [#|1|]; } -}`); +}`, + ); - testExtractConstant("extractConstant_Parameters", + testExtractConstant( + "extractConstant_Parameters", `function F() { let w = 1; let x = [#|w + 1|]; -}`); +}`, + ); - testExtractConstant("extractConstant_TypeParameters", + testExtractConstant( + "extractConstant_TypeParameters", `function F(t: T) { let x = [#|t + 1|]; -}`); +}`, + ); - testExtractConstant("extractConstant_RepeatedSubstitution", + testExtractConstant( + "extractConstant_RepeatedSubstitution", `namespace X { export const j = 10; export const y = [#|j * j|]; -}`); +}`, + ); - testExtractConstant("extractConstant_VariableList_const", - `const a = 1, b = [#|a + 1|];`); + testExtractConstant("extractConstant_VariableList_const", `const a = 1, b = [#|a + 1|];`); // NOTE: this test isn't normative - it just documents our sub-optimal behavior. - testExtractConstant("extractConstant_VariableList_let", - `let a = 1, b = [#|a + 1|];`); + testExtractConstant("extractConstant_VariableList_let", `let a = 1, b = [#|a + 1|];`); // NOTE: this test isn't normative - it just documents our sub-optimal behavior. - testExtractConstant("extractConstant_VariableList_MultipleLines", + testExtractConstant( + "extractConstant_VariableList_MultipleLines", `const /*About A*/a = 1, - /*About B*/b = [#|a + 1|];`); + /*About B*/b = [#|a + 1|];`, + ); - testExtractConstant("extractConstant_BlockScopeMismatch", ` + testExtractConstant( + "extractConstant_BlockScopeMismatch", + ` for (let i = 0; i < 10; i++) { for (let j = 0; j < 10; j++) { const x = [#|i + 1|]; } } - `); + `, + ); - testExtractConstant("extractConstant_StatementInsertionPosition1", ` + testExtractConstant( + "extractConstant_StatementInsertionPosition1", + ` const i = 0; for (let j = 0; j < 10; j++) { const x = [#|i + 1|]; } - `); + `, + ); - testExtractConstant("extractConstant_StatementInsertionPosition2", ` + testExtractConstant( + "extractConstant_StatementInsertionPosition2", + ` const i = 0; function F() { for (let j = 0; j < 10; j++) { const x = [#|i + 1|]; } } - `); + `, + ); - testExtractConstant("extractConstant_StatementInsertionPosition3", ` + testExtractConstant( + "extractConstant_StatementInsertionPosition3", + ` for (let j = 0; j < 10; j++) { const x = [#|2 + 1|]; } - `); + `, + ); - testExtractConstant("extractConstant_StatementInsertionPosition4", ` + testExtractConstant( + "extractConstant_StatementInsertionPosition4", + ` function F() { for (let j = 0; j < 10; j++) { const x = [#|2 + 1|]; } } - `); + `, + ); - testExtractConstant("extractConstant_StatementInsertionPosition5", ` + testExtractConstant( + "extractConstant_StatementInsertionPosition5", + ` function F0() { function F1() { function F2(x = [#|2 + 1|]) { } } } - `); + `, + ); - testExtractConstant("extractConstant_StatementInsertionPosition6", ` + testExtractConstant( + "extractConstant_StatementInsertionPosition6", + ` class C { x = [#|2 + 1|]; } - `); + `, + ); - testExtractConstant("extractConstant_StatementInsertionPosition7", ` + testExtractConstant( + "extractConstant_StatementInsertionPosition7", + ` const i = 0; class C { M() { @@ -181,27 +229,39 @@ class C { } } } - `); + `, + ); - testExtractConstant("extractConstant_TripleSlash", ` + testExtractConstant( + "extractConstant_TripleSlash", + ` /// const x = [#|2 + 1|]; - `); + `, + ); - testExtractConstant("extractConstant_PinnedComment", ` + testExtractConstant( + "extractConstant_PinnedComment", + ` /*! Copyright */ const x = [#|2 + 1|]; - `); + `, + ); - testExtractConstant("extractConstant_Directive", ` + testExtractConstant( + "extractConstant_Directive", + ` "strict"; const x = [#|2 + 1|]; - `); + `, + ); - testExtractConstant("extractConstant_MultipleHeaders", ` + testExtractConstant( + "extractConstant_MultipleHeaders", + ` /*! Copyright */ /// @@ -209,94 +269,126 @@ const x = [#|2 + 1|]; "strict"; const x = [#|2 + 1|]; - `); + `, + ); - testExtractConstant("extractConstant_PinnedCommentAndDocComment", ` + testExtractConstant( + "extractConstant_PinnedCommentAndDocComment", + ` /*! Copyright */ /* About x */ const x = [#|2 + 1|]; - `); + `, + ); - testExtractConstant("extractConstant_ArrowFunction_Block", ` + testExtractConstant( + "extractConstant_ArrowFunction_Block", + ` const f = () => { return [#|2 + 1|]; -};`); +};`, + ); - testExtractConstant("extractConstant_ArrowFunction_Expression", - `const f = () => [#|2 + 1|];`); + testExtractConstant("extractConstant_ArrowFunction_Expression", `const f = () => [#|2 + 1|];`); - testExtractConstant("extractConstant_PreserveTrivia", ` + testExtractConstant( + "extractConstant_PreserveTrivia", + ` // a var q = /*b*/ //c /*d*/ [#|1 /*e*/ //f /*g*/ + /*h*/ //i /*j*/ 2|] /*k*/ //l - /*m*/; /*n*/ //o`); + /*m*/; /*n*/ //o`, + ); - testExtractConstantFailed("extractConstant_Void", ` + testExtractConstantFailed( + "extractConstant_Void", + ` function f(): void { } -[#|f();|]`); +[#|f();|]`, + ); - testExtractConstantFailed("extractConstant_Never", ` + testExtractConstantFailed( + "extractConstant_Never", + ` function f(): never { } -[#|f();|]`); +[#|f();|]`, + ); - testExtractConstant("extractConstant_This_Constructor", ` + testExtractConstant( + "extractConstant_This_Constructor", + ` class C { constructor() { [#|this.m2()|]; } m2() { return 1; } -}`); +}`, + ); - testExtractConstant("extractConstant_This_Method", ` + testExtractConstant( + "extractConstant_This_Method", + ` class C { m1() { [#|this.m2()|]; } m2() { return 1; } -}`); +}`, + ); - testExtractConstant("extractConstant_This_Property", ` + testExtractConstant( + "extractConstant_This_Property", + ` namespace N { // Force this test to be TS-only class C { x = 1; y = [#|this.x|]; } -}`); +}`, + ); // TODO (https://github.com/Microsoft/TypeScript/issues/20727): the extracted constant should have a type annotation. - testExtractConstant("extractConstant_ContextualType", ` + testExtractConstant( + "extractConstant_ContextualType", + ` interface I { a: 1 | 2 | 3 } let i: I = [#|{ a: 1 }|]; -`); +`, + ); - testExtractConstant("extractConstant_ContextualType_Lambda", ` + testExtractConstant( + "extractConstant_ContextualType_Lambda", + ` const myObj: { member(x: number, y: string): void } = { member: [#|(x, y) => x + y|], } -`); +`, + ); - testExtractConstant("extractConstant_CaseClauseExpression", ` + testExtractConstant( + "extractConstant_CaseClauseExpression", + ` switch (1) { case [#|1|]: break; } -`); +`, + ); - testExtractConstant("extractConstant_PropertyName", - `[#|x.y|].z();`); + testExtractConstant("extractConstant_PropertyName", `[#|x.y|].z();`); - testExtractConstant("extractConstant_PropertyName_ExistingName", + testExtractConstant( + "extractConstant_PropertyName_ExistingName", `let y; -[#|x.y|].z();`); +[#|x.y|].z();`, + ); - testExtractConstant("extractConstant_PropertyName_Keyword", - `[#|x.if|].z();`); + testExtractConstant("extractConstant_PropertyName_Keyword", `[#|x.if|].z();`); - testExtractConstant("extractConstant_PropertyName_PrivateIdentifierKeyword", - `[#|this.#if|].z();`); + testExtractConstant("extractConstant_PropertyName_PrivateIdentifierKeyword", `[#|this.#if|].z();`); }); function testExtractConstant(caption: string, text: string) { diff --git a/src/testRunner/unittests/services/extract/functions.ts b/src/testRunner/unittests/services/extract/functions.ts index 0405a55c1f320..359b2d98241d8 100644 --- a/src/testRunner/unittests/services/extract/functions.ts +++ b/src/testRunner/unittests/services/extract/functions.ts @@ -1,8 +1,11 @@ import * as ts from "../../../_namespaces/ts"; -import { testExtractSymbol } from "./helpers"; +import { + testExtractSymbol, +} from "./helpers"; describe("unittests:: services:: extract:: extractFunctions", () => { - testExtractFunction("extractFunction1", + testExtractFunction( + "extractFunction1", `namespace A { let x = 1; function foo() { @@ -17,8 +20,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { foo();|] } } -}`); - testExtractFunction("extractFunction2", +}`, + ); + testExtractFunction( + "extractFunction2", `namespace A { let x = 1; function foo() { @@ -31,8 +36,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return foo();|] } } -}`); - testExtractFunction("extractFunction3", +}`, + ); + testExtractFunction( + "extractFunction3", `namespace A { function foo() { } @@ -44,8 +51,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return foo();|] } } -}`); - testExtractFunction("extractFunction4", +}`, + ); + testExtractFunction( + "extractFunction4", `namespace A { function foo() { } @@ -59,8 +68,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return foo();|] } } -}`); - testExtractFunction("extractFunction5", +}`, + ); + testExtractFunction( + "extractFunction5", `namespace A { let x = 1; export function foo() { @@ -75,8 +86,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { foo();|] } } -}`); - testExtractFunction("extractFunction6", +}`, + ); + testExtractFunction( + "extractFunction6", `namespace A { let x = 1; export function foo() { @@ -91,8 +104,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return foo();|] } } -}`); - testExtractFunction("extractFunction7", +}`, + ); + testExtractFunction( + "extractFunction7", `namespace A { let x = 1; export namespace C { @@ -109,8 +124,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return C.foo();|] } } -}`); - testExtractFunction("extractFunction9", +}`, + ); + testExtractFunction( + "extractFunction9", `namespace A { export interface I { x: number }; namespace B { @@ -119,8 +136,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return a1.x + 10;|] } } -}`); - testExtractFunction("extractFunction10", +}`, + ); + testExtractFunction( + "extractFunction10", `namespace A { export interface I { x: number }; class C { @@ -130,8 +149,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return a1.x + 10;|] } } -}`); - testExtractFunction("extractFunction11", +}`, + ); + testExtractFunction( + "extractFunction11", `namespace A { let y = 1; class C { @@ -143,8 +164,10 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return a1.x + 10;|] } } -}`); - testExtractFunction("extractFunction12", +}`, + ); + testExtractFunction( + "extractFunction12", `namespace A { let y = 1; class C { @@ -158,13 +181,15 @@ describe("unittests:: services:: extract:: extractFunctions", () => { return a1.x + 10;|] } } -}`); +}`, + ); // The "b" type parameters aren't used and shouldn't be passed to the extracted function. // Type parameters should be in syntactic order (i.e. in order or character offset from BOF). // In all cases, we could use type inference, rather than passing explicit type arguments. // Note the inclusion of arrow functions to ensure that some type parameters are not from // targetable scopes. - testExtractFunction("extractFunction13", + testExtractFunction( + "extractFunction13", `(u1a: U1a, u1b: U1b) => { function F1(t1a: T1a, t1b: T1b) { (u2a: U2a, u2b: U2b) => { @@ -179,107 +204,138 @@ describe("unittests:: services:: extract:: extractFunctions", () => { } } } -}`); +}`, + ); // This test is descriptive, rather than normative. The current implementation // doesn't handle type parameter shadowing. - testExtractFunction("extractFunction14", + testExtractFunction( + "extractFunction14", `function F(t1: T) { function G(t2: T) { [#|t1.toString(); t2.toString();|] } -}`); +}`, + ); // Confirm that the constraint is preserved. - testExtractFunction("extractFunction15", + testExtractFunction( + "extractFunction15", `function F(t1: T) { function G(t2: U) { [#|t2.toString();|] } -}`, /*includeLib*/ true); +}`, + /*includeLib*/ true, + ); // Confirm that the contextual type of an extracted expression counts as a use. - testExtractFunction("extractFunction16", + testExtractFunction( + "extractFunction16", `function F() { const array: T[] = [#|[]|]; -}`, /*includeLib*/ true); +}`, + /*includeLib*/ true, + ); // Class type parameter - testExtractFunction("extractFunction17", + testExtractFunction( + "extractFunction17", `class C { M(t1: T1, t2: T2) { [#|t1.toString()|]; } -}`); +}`, + ); // Function type parameter - testExtractFunction("extractFunction18", + testExtractFunction( + "extractFunction18", `class C { M(t1: T1, t2: T2) { [#|t1.toString()|]; } -}`); +}`, + ); // Coupled constraints - testExtractFunction("extractFunction19", + testExtractFunction( + "extractFunction19", `function F(v: V) { [#|v.toString()|]; -}`, /*includeLib*/ true); +}`, + /*includeLib*/ true, + ); - testExtractFunction("extractFunction20", + testExtractFunction( + "extractFunction20", `const _ = class { a() { [#|let a1 = { x: 1 }; return a1.x + 10;|] } -}`); +}`, + ); // Write + void return - testExtractFunction("extractFunction21", + testExtractFunction( + "extractFunction21", `function foo() { let x = 10; [#|x++; return;|] -}`); +}`, + ); // Return in finally block - testExtractFunction("extractFunction22", + testExtractFunction( + "extractFunction22", `function test() { try { } finally { [#|return 1;|] } -}`); +}`, + ); // Extraction position - namespace - testExtractFunction("extractFunction23", + testExtractFunction( + "extractFunction23", `namespace NS { function M1() { } function M2() { [#|return 1;|] } function M3() { } -}`); +}`, + ); // Extraction position - function - testExtractFunction("extractFunction24", + testExtractFunction( + "extractFunction24", `function Outer() { function M1() { } function M2() { [#|return 1;|] } function M3() { } -}`); +}`, + ); // Extraction position - file - testExtractFunction("extractFunction25", + testExtractFunction( + "extractFunction25", `function M1() { } function M2() { [#|return 1;|] } -function M3() { }`); +function M3() { }`, + ); // Extraction position - class without ctor - testExtractFunction("extractFunction26", + testExtractFunction( + "extractFunction26", `class C { M1() { } M2() { [#|return 1;|] } M3() { } -}`); +}`, + ); // Extraction position - class with ctor in middle - testExtractFunction("extractFunction27", + testExtractFunction( + "extractFunction27", `class C { M1() { } M2() { @@ -287,9 +343,11 @@ function M3() { }`); } constructor() { } M3() { } -}`); +}`, + ); // Extraction position - class with ctor at end - testExtractFunction("extractFunction28", + testExtractFunction( + "extractFunction28", `class C { M1() { } M2() { @@ -297,9 +355,11 @@ function M3() { }`); } M3() { } constructor() { } -}`); +}`, + ); // Shorthand property names - testExtractFunction("extractFunction29", + testExtractFunction( + "extractFunction29", `interface UnaryExpression { kind: "Unary"; operator: string; @@ -316,14 +376,18 @@ function parseUnaryExpression(operator: string): UnaryExpression { function parsePrimaryExpression(): any { throw "Not implemented"; -}`); +}`, + ); // Type parameter as declared type - testExtractFunction("extractFunction30", + testExtractFunction( + "extractFunction30", `function F() { [#|let t: T;|] -}`); +}`, + ); // Return in nested function - testExtractFunction("extractFunction31", + testExtractFunction( + "extractFunction31", `namespace N { export const value = 1; @@ -334,9 +398,11 @@ function parsePrimaryExpression(): any { return value; }|] } -}`); +}`, + ); // Return in nested class - testExtractFunction("extractFunction32", + testExtractFunction( + "extractFunction32", `namespace N { export const value = 1; @@ -348,187 +414,262 @@ function parsePrimaryExpression(): any { } }|] } -}`); +}`, + ); // Selection excludes leading trivia of declaration - testExtractFunction("extractFunction33", + testExtractFunction( + "extractFunction33", `function F() { [#|function G() { }|] -}`); +}`, + ); // Arrow function - testExtractFunction("extractFunction34", + testExtractFunction( + "extractFunction34", `const F = () => { [#|function G() { }|] -};`); +};`, + ); - testExtractFunction("extractFunction_RepeatedSubstitution", + testExtractFunction( + "extractFunction_RepeatedSubstitution", `namespace X { export const j = 10; export const y = [#|j * j|]; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Var", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Var", + ` [#|var x = 1; "hello"|] x; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Let_Type", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Let_Type", + ` [#|let x: number = 1; "hello";|] x; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Let_NoType", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Let_NoType", + ` [#|let x = 1; "hello";|] x; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Const_Type", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Const_Type", + ` [#|const x: number = 1; "hello";|] x; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Const_NoType", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Const_NoType", + ` [#|const x = 1; "hello";|] x; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Multiple1", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Multiple1", + ` [#|const x = 1, y: string = "a";|] x; y; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Multiple2", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Multiple2", + ` [#|const x = 1, y = "a"; const z = 3;|] x; y; z; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Multiple3", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Multiple3", + ` [#|const x = 1, y: string = "a"; let z = 3;|] x; y; z; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_ConsumedTwice", ` + testExtractFunction( + "extractFunction_VariableDeclaration_ConsumedTwice", + ` [#|const x: number = 1; "hello";|] x; x; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_DeclaredTwice", ` + testExtractFunction( + "extractFunction_VariableDeclaration_DeclaredTwice", + ` [#|var x = 1; var x = 2;|] x; -`); +`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Var", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Var", + ` function f() { let a = 1; [#|var x = 1; a++;|] a; x; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Let_NoType", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Let_NoType", + ` function f() { let a = 1; [#|let x = 1; a++;|] a; x; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Let_Type", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Let_Type", + ` function f() { let a = 1; [#|let x: number = 1; a++;|] a; x; -}`); +}`, + ); // We propagate numericLiteralFlags, but it's not consumed by the emitter, // so everything comes out decimal. It would be nice to improve this. - testExtractFunction("extractFunction_VariableDeclaration_Writes_Let_LiteralType1", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Let_LiteralType1", + ` function f() { let a = 1; [#|let x: 0o10 | 10 | 0b10 = 10; a++;|] a; x; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Let_LiteralType2", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Let_LiteralType2", + ` function f() { let a = 1; [#|let x: "a" | 'b' = 'a'; a++;|] a; x; -}`); +}`, + ); // We propagate numericLiteralFlags, but it's not consumed by the emitter, // so everything comes out decimal. It would be nice to improve this. - testExtractFunction("extractFunction_VariableDeclaration_Writes_Let_LiteralType1", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Let_LiteralType1", + ` function f() { let a = 1; [#|let x: 0o10 | 10 | 0b10 = 10; a++;|] a; x; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Let_TypeWithComments", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Let_TypeWithComments", + ` function f() { let a = 1; [#|let x: /*A*/ "a" /*B*/ | /*C*/ 'b' /*D*/ = 'a'; a++;|] a; x; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Const_NoType", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Const_NoType", + ` function f() { let a = 1; [#|const x = 1; a++;|] a; x; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Const_Type", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Const_Type", + ` function f() { let a = 1; [#|const x: number = 1; a++;|] a; x; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Mixed1", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Mixed1", + ` function f() { let a = 1; [#|const x = 1; let y = 2; a++;|] a; x; y; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Mixed2", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Mixed2", + ` function f() { let a = 1; [#|var x = 1; let y = 2; a++;|] a; x; y; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_Mixed3", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_Mixed3", + ` function f() { let a = 1; [#|let x: number = 1; let y = 2; a++;|] a; x; y; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_Writes_UnionUndefined", ` + testExtractFunction( + "extractFunction_VariableDeclaration_Writes_UnionUndefined", + ` function f() { let a = 1; [#|let x: number | undefined = 1; @@ -536,33 +677,46 @@ function f() { let z: (undefined | number) = 3; a++;|] a; x; y; z; -}`); +}`, + ); - testExtractFunction("extractFunction_VariableDeclaration_ShorthandProperty", ` + testExtractFunction( + "extractFunction_VariableDeclaration_ShorthandProperty", + ` function f() { [#|let x;|] return { x }; -}`); +}`, + ); - testExtractFunction("extractFunction_PreserveTrivia", ` + testExtractFunction( + "extractFunction_PreserveTrivia", + ` // a var q = /*b*/ //c /*d*/ [#|1 /*e*/ //f /*g*/ + /*h*/ //i /*j*/ 2|] /*k*/ //l - /*m*/; /*n*/ //o`); + /*m*/; /*n*/ //o`, + ); - testExtractFunction("extractFunction_NamelessClass", ` + testExtractFunction( + "extractFunction_NamelessClass", + ` export default class { M() { [#|1 + 1|]; } -}`); +}`, + ); - testExtractFunction("extractFunction_NoDeclarations", ` + testExtractFunction( + "extractFunction_NoDeclarations", + ` function F() { [#|arguments.length|]; // arguments has no declaration -}`); +}`, + ); }); function testExtractFunction(caption: string, text: string, includeLib?: boolean) { diff --git a/src/testRunner/unittests/services/extract/helpers.ts b/src/testRunner/unittests/services/extract/helpers.ts index cc139c3f42a2c..111b45e4c1808 100644 --- a/src/testRunner/unittests/services/extract/helpers.ts +++ b/src/testRunner/unittests/services/extract/helpers.ts @@ -1,6 +1,8 @@ import * as Harness from "../../../_namespaces/Harness"; import * as ts from "../../../_namespaces/ts"; -import { createProjectService } from "../../helpers/tsserver"; +import { + createProjectService, +} from "../../helpers/tsserver"; import { createServerHost, libFile, @@ -25,8 +27,11 @@ export function extractTest(source: string): Test { const ranges = new Map(); while (pos < source.length) { - if (source.charCodeAt(pos) === ts.CharacterCodes.openBracket && - (source.charCodeAt(pos + 1) === ts.CharacterCodes.hash || source.charCodeAt(pos + 1) === ts.CharacterCodes.$)) { + if ( + source.charCodeAt(pos) === ts.CharacterCodes.openBracket + && (source.charCodeAt(pos + 1) === ts.CharacterCodes.hash + || source.charCodeAt(pos + 1) === ts.CharacterCodes.$) + ) { const saved = pos; pos += 2; const s = pos; @@ -46,7 +51,10 @@ export function extractTest(source: string): Test { pos = saved; } } - else if (source.charCodeAt(pos) === ts.CharacterCodes.bar && source.charCodeAt(pos + 1) === ts.CharacterCodes.closeBracket) { + else if ( + source.charCodeAt(pos) === ts.CharacterCodes.bar + && source.charCodeAt(pos + 1) === ts.CharacterCodes.closeBracket + ) { text += source.substring(lastPos, pos); activeRanges[activeRanges.length - 1].end = text.length; const range = activeRanges.pop()!; @@ -80,10 +88,16 @@ export const notImplementedHost: ts.LanguageServiceHost = { getDefaultLibFileName: ts.notImplemented, getCurrentDirectory: ts.notImplemented, readFile: ts.notImplemented, - fileExists: ts.notImplemented + fileExists: ts.notImplemented, }; -export function testExtractSymbol(caption: string, text: string, baselineFolder: string, description: ts.DiagnosticMessage, includeLib?: boolean) { +export function testExtractSymbol( + caption: string, + text: string, + baselineFolder: string, + description: ts.DiagnosticMessage, + includeLib?: boolean, +) { const t = extractTest(text); const selectionRange = t.ranges.get("selection")!; if (!selectionRange) { @@ -91,7 +105,8 @@ export function testExtractSymbol(caption: string, text: string, baselineFolder: } [ts.Extension.Ts, ts.Extension.Js].forEach(extension => - it(`${caption} [${extension}]`, () => runBaseline(extension))); + it(`${caption} [${extension}]`, () => runBaseline(extension)) + ); function runBaseline(extension: ts.Extension) { const path = "/a" + extension; @@ -114,8 +129,15 @@ export function testExtractSymbol(caption: string, text: string, baselineFolder: formatContext: ts.formatting.getFormatContext(ts.testFormatSettings, notImplementedHost), preferences: ts.emptyOptions, }; - const rangeToExtract = ts.refactor.extractSymbol.getRangeToExtract(sourceFile, ts.createTextSpanFromRange(selectionRange)); - assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText); + const rangeToExtract = ts.refactor.extractSymbol.getRangeToExtract( + sourceFile, + ts.createTextSpanFromRange(selectionRange), + ); + assert.equal( + rangeToExtract.errors, + undefined, + rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText, + ); const infos = ts.refactor.extractSymbol.getRefactorActionsToExtractSymbol(context); const actions = ts.find(infos, info => info.description === description.message)!.actions; @@ -123,7 +145,10 @@ export function testExtractSymbol(caption: string, text: string, baselineFolder: data.push(`// ==ORIGINAL==`); data.push(text.replace("[#|", "/*[#|*/").replace("|]", "/*|]*/")); for (const action of actions) { - const { renameLocation, edits } = ts.refactor.extractSymbol.getRefactorEditsToExtractSymbol(context, action.name)!; + const { renameLocation, edits } = ts.refactor.extractSymbol.getRefactorEditsToExtractSymbol( + context, + action.name, + )!; assert.lengthOf(edits, 1); data.push(`// ==SCOPE::${action.description}==`); const newText = ts.textChanges.applyChanges(sourceFile.text, edits[0].textChanges); @@ -136,7 +161,7 @@ export function testExtractSymbol(caption: string, text: string, baselineFolder: Harness.Baseline.runBaseline(`${baselineFolder}/${caption}${extension}`, data.join(newLineCharacter)); } - function makeProgram(f: {path: string, content: string }, includeLib?: boolean) { + function makeProgram(f: { path: string; content: string; }, includeLib?: boolean) { const host = createServerHost(includeLib ? [f, libFile] : [f]); // libFile is expensive to parse repeatedly - only test when required const projectService = createProjectService(host, { allowNonBaseliningLogger: true }); projectService.openClientFile(f.path); @@ -160,7 +185,7 @@ export function testExtractSymbolFailed(caption: string, text: string, descripti } const f = { path: "/a.ts", - content: t.source + content: t.source, }; const host = createServerHost([f, libFile]); const projectService = createProjectService(host, { allowNonBaseliningLogger: true }); @@ -177,8 +202,14 @@ export function testExtractSymbolFailed(caption: string, text: string, descripti formatContext: ts.formatting.getFormatContext(ts.testFormatSettings, notImplementedHost), preferences: ts.emptyOptions, }; - const rangeToExtract = ts.refactor.extractSymbol.getRangeToExtract(sourceFile, ts.createTextSpanFromRange(selectionRange)); - assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText); + const rangeToExtract = ts.refactor.extractSymbol.getRangeToExtract( + sourceFile, + ts.createTextSpanFromRange(selectionRange), + ); + assert.isUndefined( + rangeToExtract.errors, + rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText, + ); const infos = ts.refactor.extractSymbol.getRefactorActionsToExtractSymbol(context); assert.isUndefined(ts.find(infos, info => info.description === description.message)); }); diff --git a/src/testRunner/unittests/services/extract/ranges.ts b/src/testRunner/unittests/services/extract/ranges.ts index 60d4cce5b8694..79251e275f624 100644 --- a/src/testRunner/unittests/services/extract/ranges.ts +++ b/src/testRunner/unittests/services/extract/ranges.ts @@ -1,5 +1,7 @@ import * as ts from "../../../_namespaces/ts"; -import { extractTest } from "./helpers"; +import { + extractTest, +} from "./helpers"; function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) { return it(caption, () => { @@ -9,7 +11,11 @@ function testExtractRangeFailed(caption: string, s: string, expectedErrors: stri if (!selectionRange) { throw new Error(`Test ${s} does not specify selection range`); } - const result = ts.refactor.extractSymbol.getRangeToExtract(file, ts.createTextSpanFromRange(selectionRange), /*invoked*/ false); + const result = ts.refactor.extractSymbol.getRangeToExtract( + file, + ts.createTextSpanFromRange(selectionRange), + /*invoked*/ false, + ); assert(result.targetRange === undefined, "failure expected"); const sortedErrors = result.errors.map(e => e.messageText as string).sort(); assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors"); @@ -48,68 +54,109 @@ function testExtractRange(caption: string, s: string) { describe("unittests:: services:: extract:: extractRanges", () => { describe("get extract range from selection", () => { - testExtractRange("extractRange1", ` + testExtractRange( + "extractRange1", + ` [#| [$|var x = 1; var y = 2;|]|] - `); - testExtractRange("extractRange2", ` + `, + ); + testExtractRange( + "extractRange2", + ` [$|[#|var x = 1; var y = 2|];|] - `); - testExtractRange("extractRange3", ` + `, + ); + testExtractRange( + "extractRange3", + ` [#|var x = [$|1|]|]; var y = 2; - `); - testExtractRange("extractRange4", ` + `, + ); + testExtractRange( + "extractRange4", + ` var x = [$|10[#|00|]|]; - `); - testExtractRange("extractRange5", ` + `, + ); + testExtractRange( + "extractRange5", + ` [$|va[#|r foo = 1; var y = 200|]0;|] - `); - testExtractRange("extractRange6", ` + `, + ); + testExtractRange( + "extractRange6", + ` var x = [$|fo[#|o.bar.baz()|]|]; - `); - testExtractRange("extractRange7", ` + `, + ); + testExtractRange( + "extractRange7", + ` if ([#|[#extracted|a && b && c && d|]|]) { } - `); - testExtractRange("extractRange8", ` + `, + ); + testExtractRange( + "extractRange8", + ` if [#|(a && b && c && d|]) { } - `); - testExtractRange("extractRange9", ` + `, + ); + testExtractRange( + "extractRange9", + ` if ([$|a[#|a && b && c && d|]d|]) { } - `); - testExtractRange("extractRange10", ` + `, + ); + testExtractRange( + "extractRange10", + ` if (a && b && c && d) { [#| [$|var x = 1; console.log(x);|] |] } - `); - testExtractRange("extractRange11", ` + `, + ); + testExtractRange( + "extractRange11", + ` [#| if (a) { return 100; } |] - `); - testExtractRange("extractRange12", ` + `, + ); + testExtractRange( + "extractRange12", + ` function foo() { [#| [$|if (a) { } return 100|] |] } - `); - testExtractRange("extractRange13", ` + `, + ); + testExtractRange( + "extractRange13", + ` [#| [$|l1: if (x) { break l1; }|]|] - `); - testExtractRange("extractRange14", ` + `, + ); + testExtractRange( + "extractRange14", + ` [#| [$|l2: { @@ -117,22 +164,31 @@ describe("unittests:: services:: extract:: extractRanges", () => { } break l2; }|]|] - `); - testExtractRange("extractRange15", ` + `, + ); + testExtractRange( + "extractRange15", + ` while (true) { [#| if(x) { } break; |] } - `); - testExtractRange("extractRange16", ` + `, + ); + testExtractRange( + "extractRange16", + ` while (true) { [#| if(x) { } continue; |] } - `); - testExtractRange("extractRange17", ` + `, + ); + testExtractRange( + "extractRange17", + ` l3: { [#| @@ -140,8 +196,11 @@ describe("unittests:: services:: extract:: extractRanges", () => { } break l3; |] } - `); - testExtractRange("extractRange18", ` + `, + ); + testExtractRange( + "extractRange18", + ` function f() { while (true) { [#| @@ -150,8 +209,11 @@ describe("unittests:: services:: extract:: extractRanges", () => { } |] } } - `); - testExtractRange("extractRange19", ` + `, + ); + testExtractRange( + "extractRange19", + ` function f() { while (true) { [#| @@ -161,14 +223,20 @@ describe("unittests:: services:: extract:: extractRanges", () => { |] } } - `); - testExtractRange("extractRange20", ` + `, + ); + testExtractRange( + "extractRange20", + ` function f() { return [#| [$|1 + 2|] |]+ 3; } } - `); - testExtractRange("extractRange21", ` + `, + ); + testExtractRange( + "extractRange21", + ` function f(x: number) { [#|[$|try { x++; @@ -177,7 +245,8 @@ describe("unittests:: services:: extract:: extractRanges", () => { return 1; }|]|] } - `); + `, + ); // Variable statements testExtractRange("extractRange22", `[#|let x = [$|1|];|]`); @@ -197,7 +266,8 @@ describe("unittests:: services:: extract:: extractRanges", () => { testExtractRange("extractRange30", `for (var i = [#|[$|1|]|]; i < 2; i++) {}`); }); - testExtractRangeFailed("extractRangeFailed1", + testExtractRangeFailed( + "extractRangeFailed1", ` namespace A { function f() { @@ -210,9 +280,11 @@ function f() { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message], + ); - testExtractRangeFailed("extractRangeFailed2", + testExtractRangeFailed( + "extractRangeFailed2", ` namespace A { function f() { @@ -227,9 +299,11 @@ function f() { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message], + ); - testExtractRangeFailed("extractRangeFailed3", + testExtractRangeFailed( + "extractRangeFailed3", ` namespace A { function f() { @@ -244,9 +318,11 @@ function f() { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message], + ); - testExtractRangeFailed("extractRangeFailed4", + testExtractRangeFailed( + "extractRangeFailed4", ` namespace A { function f() { @@ -261,9 +337,14 @@ function f() { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message]); + [ + ts.refactor.extractSymbol.Messages + .cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message, + ], + ); - testExtractRangeFailed("extractRangeFailed5", + testExtractRangeFailed( + "extractRangeFailed5", ` namespace A { function f() { @@ -280,9 +361,11 @@ function f2() { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message], + ); - testExtractRangeFailed("extractRangeFailed6", + testExtractRangeFailed( + "extractRangeFailed6", ` namespace A { function f() { @@ -299,9 +382,11 @@ function f2() { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message], + ); - testExtractRangeFailed("extractRangeFailed7", + testExtractRangeFailed( + "extractRangeFailed7", ` function test(x: number) { while (x) { @@ -310,9 +395,11 @@ while (x) { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message], + ); - testExtractRangeFailed("extractRangeFailed8", + testExtractRangeFailed( + "extractRangeFailed8", ` function test(x: number) { switch (x) { @@ -321,22 +408,26 @@ switch (x) { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message], + ); - testExtractRangeFailed("extractRangeFailed9", - `var x = ([#||]1 + 2);`, - [ts.refactor.extractSymbol.Messages.cannotExtractEmpty.message]); + testExtractRangeFailed("extractRangeFailed9", `var x = ([#||]1 + 2);`, [ + ts.refactor.extractSymbol.Messages.cannotExtractEmpty.message, + ]); - testExtractRangeFailed("extractRangeFailed10", + testExtractRangeFailed( + "extractRangeFailed10", ` function f() { return 1 + [#|2 + 3|]; } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRange.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRange.message], + ); - testExtractRangeFailed("extractRangeFailed11", + testExtractRangeFailed( + "extractRangeFailed11", ` function f(x: number) { while (true) { @@ -349,61 +440,72 @@ switch (x) { } } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message], + ); - testExtractRangeFailed("extractRangeFailed12", - `let [#|x|];`, - [ts.refactor.extractSymbol.Messages.statementOrExpressionExpected.message]); + testExtractRangeFailed("extractRangeFailed12", `let [#|x|];`, [ + ts.refactor.extractSymbol.Messages.statementOrExpressionExpected.message, + ]); - testExtractRangeFailed("extractRangeFailed13", - `[#|return;|]`, - [ts.refactor.extractSymbol.Messages.cannotExtractRange.message]); + testExtractRangeFailed("extractRangeFailed13", `[#|return;|]`, [ + ts.refactor.extractSymbol.Messages.cannotExtractRange.message, + ]); - testExtractRangeFailed("extractRangeFailed14", + testExtractRangeFailed( + "extractRangeFailed14", ` switch(1) { case [#|1: break;|] } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRange.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRange.message], + ); - testExtractRangeFailed("extractRangeFailed15", + testExtractRangeFailed( + "extractRangeFailed15", ` switch(1) { case [#|1: break|]; } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRange.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRange.message], + ); // Documentation only - it would be nice if the result were [$|1|] - testExtractRangeFailed("extractRangeFailed16", + testExtractRangeFailed( + "extractRangeFailed16", ` switch(1) { [#|case 1|]: break; } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRange.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRange.message], + ); // Documentation only - it would be nice if the result were [$|1|] - testExtractRangeFailed("extractRangeFailed17", + testExtractRangeFailed( + "extractRangeFailed17", ` switch(1) { [#|case 1:|] break; } `, - [ts.refactor.extractSymbol.Messages.cannotExtractRange.message]); + [ts.refactor.extractSymbol.Messages.cannotExtractRange.message], + ); - testExtractRangeFailed("extractRangeFailed18", - `[#|{ 1;|] }`, - [ts.refactor.extractSymbol.Messages.cannotExtractRange.message]); + testExtractRangeFailed("extractRangeFailed18", `[#|{ 1;|] }`, [ + ts.refactor.extractSymbol.Messages.cannotExtractRange.message, + ]); - testExtractRangeFailed("extractRangeFailed19", - `[#|/** @type {number} */|] const foo = 1;`, - [ts.refactor.extractSymbol.Messages.cannotExtractJSDoc.message]); + testExtractRangeFailed("extractRangeFailed19", `[#|/** @type {number} */|] const foo = 1;`, [ + ts.refactor.extractSymbol.Messages.cannotExtractJSDoc.message, + ]); - testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [ts.refactor.extractSymbol.Messages.cannotExtractIdentifier.message]); + testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [ + ts.refactor.extractSymbol.Messages.cannotExtractIdentifier.message, + ]); }); diff --git a/src/testRunner/unittests/services/extract/symbolWalker.ts b/src/testRunner/unittests/services/extract/symbolWalker.ts index 0c2285ceda6bc..a5bf6380b7c84 100644 --- a/src/testRunner/unittests/services/extract/symbolWalker.ts +++ b/src/testRunner/unittests/services/extract/symbolWalker.ts @@ -2,45 +2,59 @@ import * as Harness from "../../../_namespaces/Harness"; import * as ts from "../../../_namespaces/ts"; describe("unittests:: services:: extract:: Symbol Walker", () => { - function test(description: string, source: string, verifier: (file: ts.SourceFile, checker: ts.TypeChecker) => void) { + function test( + description: string, + source: string, + verifier: (file: ts.SourceFile, checker: ts.TypeChecker) => void, + ) { it(description, () => { - const result = Harness.Compiler.compileFiles([{ - unitName: "main.ts", - content: source - }], [], {}, {}, "/"); + const result = Harness.Compiler.compileFiles( + [{ + unitName: "main.ts", + content: source, + }], + [], + {}, + {}, + "/", + ); const file = result.program!.getSourceFile("main.ts")!; const checker = result.program!.getTypeChecker(); verifier(file, checker); }); } - test("can be created", ` + test( + "can be created", + ` interface Bar { x: number; y: number; history: Bar[]; } -export default function foo(a: number, b: Bar): void {}`, (file, checker) => { - let foundCount = 0; - let stdLibRefSymbols = 0; - const expectedSymbols = ["default", "a", "b", "Bar", "x", "y", "history"]; - const walker = checker.getSymbolWalker(symbol => { - const isStdLibSymbol = ts.forEach(symbol.declarations, d => { - return ts.getSourceFileOfNode(d).hasNoDefaultLib; +export default function foo(a: number, b: Bar): void {}`, + (file, checker) => { + let foundCount = 0; + let stdLibRefSymbols = 0; + const expectedSymbols = ["default", "a", "b", "Bar", "x", "y", "history"]; + const walker = checker.getSymbolWalker(symbol => { + const isStdLibSymbol = ts.forEach(symbol.declarations, d => { + return ts.getSourceFileOfNode(d).hasNoDefaultLib; + }); + if (isStdLibSymbol) { + stdLibRefSymbols++; + return false; // Don't traverse into the stdlib. That's unnecessary for this test. + } + assert.equal(symbol.name, expectedSymbols[foundCount]); + foundCount++; + return true; }); - if (isStdLibSymbol) { - stdLibRefSymbols++; - return false; // Don't traverse into the stdlib. That's unnecessary for this test. + const symbols = checker.getExportsOfModule(file.symbol); + for (const symbol of symbols) { + walker.walkSymbol(symbol); } - assert.equal(symbol.name, expectedSymbols[foundCount]); - foundCount++; - return true; - }); - const symbols = checker.getExportsOfModule(file.symbol); - for (const symbol of symbols) { - walker.walkSymbol(symbol); - } - assert.equal(foundCount, expectedSymbols.length); - assert.equal(stdLibRefSymbols, 1); // Expect 1 stdlib entry symbol - the implicit Array referenced by Bar.history - }); + assert.equal(foundCount, expectedSymbols.length); + assert.equal(stdLibRefSymbols, 1); // Expect 1 stdlib entry symbol - the implicit Array referenced by Bar.history + }, + ); }); diff --git a/src/testRunner/unittests/services/hostNewLineSupport.ts b/src/testRunner/unittests/services/hostNewLineSupport.ts index d5028708f6dfa..6a289d7c5f03e 100644 --- a/src/testRunner/unittests/services/hostNewLineSupport.ts +++ b/src/testRunner/unittests/services/hostNewLineSupport.ts @@ -31,14 +31,27 @@ describe("unittests:: services:: hostNewLineSupport", () => { const ls = testLSWithFiles(options, [{ content, fileOptions: {}, - unitName: "input.ts" + unitName: "input.ts", }]); const result = ls.getEmitOutput("input.ts"); assert(!result.emitSkipped, "emit was skipped"); assert(result.outputFiles.length === 1, "a number of files other than 1 was output"); - assert(result.outputFiles[0].name === "input.js", `Expected output file name input.js, but got ${result.outputFiles[0].name}`); - assert(result.outputFiles[0].text.match(options.newLine === ts.NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), "expected to find appropriate newlines"); - assert(!result.outputFiles[0].text.match(options.newLine === ts.NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/), "expected not to find inappropriate newlines"); + assert( + result.outputFiles[0].name === "input.js", + `Expected output file name input.js, but got ${result.outputFiles[0].name}`, + ); + assert( + result.outputFiles[0].text.match( + options.newLine === ts.NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/, + ), + "expected to find appropriate newlines", + ); + assert( + !result.outputFiles[0].text.match( + options.newLine === ts.NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/, + ), + "expected not to find inappropriate newlines", + ); } function verifyBothNewLines(content: string) { @@ -50,12 +63,20 @@ describe("unittests:: services:: hostNewLineSupport", () => { const ls = testLSWithFiles(options, [{ content, fileOptions: {}, - unitName: "input.ts" + unitName: "input.ts", }]); const span = ls.getOutliningSpans("input.ts")[0]; const textAfterSpanCollapse = content.substring(span.textSpan.start + span.textSpan.length); - assert(textAfterSpanCollapse.match(options.newLine === ts.NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), "expected to find appropriate newlines"); - assert(!textAfterSpanCollapse.match(options.newLine === ts.NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/), "expected not to find inappropriate newlines"); + assert( + textAfterSpanCollapse.match(options.newLine === ts.NewLineKind.CarriageReturnLineFeed ? /\r\n/ : /[^\r]\n/), + "expected to find appropriate newlines", + ); + assert( + !textAfterSpanCollapse.match( + options.newLine === ts.NewLineKind.CarriageReturnLineFeed ? /[^\r]\n/ : /\r\n/, + ), + "expected not to find inappropriate newlines", + ); } it("should exist and respect provided compiler options", () => { @@ -67,12 +88,16 @@ describe("unittests:: services:: hostNewLineSupport", () => { }); it("should respect CRLF line endings around outlining spans", () => { - verifyOutliningSpanNewLines("// comment not included\r\n// #region name\r\nlet x: string = \"x\";\r\n// #endregion name\r\n", - { newLine: ts.NewLineKind.CarriageReturnLineFeed }); + verifyOutliningSpanNewLines( + '// comment not included\r\n// #region name\r\nlet x: string = "x";\r\n// #endregion name\r\n', + { newLine: ts.NewLineKind.CarriageReturnLineFeed }, + ); }); it("should respect LF line endings around outlining spans", () => { - verifyOutliningSpanNewLines("// comment not included\n// #region name\nlet x: string = \"x\";\n// #endregion name\n\n", - { newLine: ts.NewLineKind.LineFeed }); + verifyOutliningSpanNewLines( + '// comment not included\n// #region name\nlet x: string = "x";\n// #endregion name\n\n', + { newLine: ts.NewLineKind.LineFeed }, + ); }); }); diff --git a/src/testRunner/unittests/services/languageService.ts b/src/testRunner/unittests/services/languageService.ts index f34256c4fccbe..a8dac2a1531d7 100644 --- a/src/testRunner/unittests/services/languageService.ts +++ b/src/testRunner/unittests/services/languageService.ts @@ -1,4 +1,6 @@ -import { expect } from "chai"; +import { + expect, +} from "chai"; import * as ts from "../../_namespaces/ts"; import { @@ -8,7 +10,7 @@ import { } from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: services:: languageService", () => { - const files: {[index: string]: string} = { + const files: { [index: string]: string; } = { "foo.ts": `import Vue from "./vue"; import Component from "./vue-class-component"; import { vueTemplateHtml } from "./variables"; @@ -21,7 +23,7 @@ class Carousel extends Vue { "variables.ts": `export const vueTemplateHtml = \`
\`;`, "vue.d.ts": `export namespace Vue { export type Config = { template: string }; }`, "vue-class-component.d.ts": `import Vue from "./vue"; -export function Component(x: Config): any;` +export function Component(x: Config): any;`, }; function createLanguageService() { @@ -46,7 +48,7 @@ export function Component(x: Config): any;` return ts.getDefaultLibFilePath(options); }, fileExists: name => !!files[name], - readFile: name => files[name] + readFile: name => files[name], }); } // Regression test for GH #18245 - bug in single line comment writer caused a debug assertion when attempting @@ -62,20 +64,20 @@ export function Component(x: Config): any;` assert.deepEqual( languageService.getEmitOutput( "foo.ts", - /*emitOnlyDtsFiles*/ true + /*emitOnlyDtsFiles*/ true, ), { emitSkipped: true, diagnostics: ts.emptyArray, outputFiles: ts.emptyArray, - } + }, ); assert.deepEqual( languageService.getEmitOutput( "foo.ts", /*emitOnlyDtsFiles*/ true, - /*forceDtsEmit*/ true + /*forceDtsEmit*/ true, ), { emitSkipped: false, @@ -83,16 +85,16 @@ export function Component(x: Config): any;` outputFiles: [{ name: "foo.d.ts", text: "export {};\n", - writeByteOrderMark: false + writeByteOrderMark: false, }], - } + }, ); }); describe("detects program upto date correctly", () => { function verifyProgramUptoDate(useProjectVersion: boolean) { let projectVersion = "1"; - const files = new Map(); + const files = new Map(); files.set("/project/root.ts", { version: "1", text: `import { foo } from "./other"` }); files.set("/project/other.ts", { version: "1", text: `export function foo() { }` }); files.set("/lib/lib.d.ts", { version: "1", text: libFile.content }); @@ -109,7 +111,7 @@ export function Component(x: Config): any;` return text ? ts.ScriptSnapshot.fromString(text) : undefined; }, getCurrentDirectory: () => "/project", - getDefaultLibFileName: () => "/lib/lib.d.ts" + getDefaultLibFileName: () => "/lib/lib.d.ts", }; const ls = ts.createLanguageService(host); const program1 = ls.getProgram()!; @@ -119,7 +121,10 @@ export function Component(x: Config): any;` // Change other projectVersion = "2"; - files.set("/project/other.ts", { version: "2", text: `export function foo() { } export function bar() { }` }); + files.set("/project/other.ts", { + version: "2", + text: `export function foo() { } export function bar() { }`, + }); const program3 = ls.getProgram()!; assert.notStrictEqual(program2, program3); verifyProgramFiles(program3); @@ -134,7 +139,7 @@ export function Component(x: Config): any;` function verifyProgramFiles(program: ts.Program) { assert.deepEqual( program.getSourceFiles().map(f => f.fileName), - ["/lib/lib.d.ts", "/project/other.ts", "/project/root.ts"] + ["/lib/lib.d.ts", "/project/other.ts", "/project/root.ts"], ); } } @@ -153,44 +158,49 @@ export function Component(x: Config): any;` content: JSON.stringify({ compilerOptions: { module: "none", - composite: true + composite: true, }, - exclude: ["temp"] - }) + exclude: ["temp"], + }), }; const class1: File = { path: `/user/username/projects/myproject/projects/project1/class1.ts`, - content: `class class1 {}` + content: `class class1 {}`, }; const class1Dts: File = { path: `/user/username/projects/myproject/projects/project1/class1.d.ts`, - content: `declare class class1 {}` + content: `declare class class1 {}`, }; const config2: File = { path: `/user/username/projects/myproject/projects/project2/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "none", - composite: true + composite: true, }, references: [ - { path: "../project1" } - ] - }) + { path: "../project1" }, + ], + }), }; const class2: File = { path: `/user/username/projects/myproject/projects/project2/class2.ts`, - content: `class class2 {}` + content: `class class2 {}`, }; const system = createServerHost([config1, class1, class1Dts, config2, class2, libFile]); - const result = ts.getParsedCommandLineOfConfigFile(`/user/username/projects/myproject/projects/project2/tsconfig.json`, /*optionsToExtend*/ undefined, { - useCaseSensitiveFileNames: true, - fileExists: path => system.fileExists(path), - readFile: path => system.readFile(path), - getCurrentDirectory: () => system.getCurrentDirectory(), - readDirectory: (path, extensions, excludes, includes, depth) => system.readDirectory(path, extensions, excludes, includes, depth), - onUnRecoverableConfigFileDiagnostic: ts.noop, - })!; + const result = ts.getParsedCommandLineOfConfigFile( + `/user/username/projects/myproject/projects/project2/tsconfig.json`, + /*optionsToExtend*/ undefined, + { + useCaseSensitiveFileNames: true, + fileExists: path => system.fileExists(path), + readFile: path => system.readFile(path), + getCurrentDirectory: () => system.getCurrentDirectory(), + readDirectory: (path, extensions, excludes, includes, depth) => + system.readDirectory(path, extensions, excludes, includes, depth), + onUnRecoverableConfigFileDiagnostic: ts.noop, + }, + )!; const host: ts.LanguageServiceHost = { useCaseSensitiveFileNames: ts.returnTrue, useSourceOfProjectReferenceRedirect, @@ -206,7 +216,8 @@ export function Component(x: Config): any;` const text = system.readFile(path); return text ? ts.ScriptSnapshot.fromString(text) : undefined; }, - readDirectory: (path, extensions, excludes, includes, depth) => system.readDirectory(path, extensions, excludes, includes, depth), + readDirectory: (path, extensions, excludes, includes, depth) => + system.readDirectory(path, extensions, excludes, includes, depth), getCurrentDirectory: () => system.getCurrentDirectory(), getDefaultLibFileName: () => libFile.path, getProjectReferences: () => result.projectReferences, @@ -218,7 +229,7 @@ export function Component(x: Config): any;` const { ls, system, class1, class2 } = setup(ts.returnTrue); assert.deepEqual( ls.getProgram()!.getSourceFiles().map(f => f.fileName), - [libFile.path, class1.path, class2.path] + [libFile.path, class1.path, class2.path], ); // Add new file to referenced project const class3 = `/user/username/projects/myproject/projects/project1/class3.ts`; @@ -226,13 +237,19 @@ export function Component(x: Config): any;` const program = ls.getProgram()!; assert.deepEqual( program.getSourceFiles().map(f => f.fileName), - [libFile.path, class1.path, class3, class2.path] + [libFile.path, class1.path, class3, class2.path], ); // Add excluded file to referenced project - system.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + system.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); assert.strictEqual(ls.getProgram(), program); // Add output from new class to referenced project - system.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`); + system.writeFile( + `/user/username/projects/myproject/projects/project1/class3.d.ts`, + `declare class class3 {}`, + ); assert.strictEqual(ls.getProgram(), program); }); @@ -241,7 +258,7 @@ export function Component(x: Config): any;` const program1 = ls.getProgram()!; assert.deepEqual( program1.getSourceFiles().map(f => f.fileName), - [libFile.path, class1Dts.path, class2.path] + [libFile.path, class1Dts.path, class2.path], ); // Add new file to referenced project const class3 = `/user/username/projects/myproject/projects/project1/class3.ts`; @@ -249,7 +266,7 @@ export function Component(x: Config): any;` assert.notStrictEqual(ls.getProgram(), program1); assert.deepEqual( ls.getProgram()!.getSourceFiles().map(f => f.fileName), - [libFile.path, class1Dts.path, class2.path] + [libFile.path, class1Dts.path, class2.path], ); // Add class3 output const class3Dts = `/user/username/projects/myproject/projects/project1/class3.d.ts`; @@ -257,22 +274,25 @@ export function Component(x: Config): any;` const program2 = ls.getProgram()!; assert.deepEqual( program2.getSourceFiles().map(f => f.fileName), - [libFile.path, class1Dts.path, class3Dts, class2.path] + [libFile.path, class1Dts.path, class3Dts, class2.path], ); // Add excluded file to referenced project - system.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + system.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); assert.strictEqual(ls.getProgram(), program2); // Delete output from new class to referenced project system.deleteFile(class3Dts); assert.deepEqual( ls.getProgram()!.getSourceFiles().map(f => f.fileName), - [libFile.path, class1Dts.path, class2.path] + [libFile.path, class1Dts.path, class2.path], ); // Write output again system.writeFile(class3Dts, `declare class class3 {}`); assert.deepEqual( ls.getProgram()!.getSourceFiles().map(f => f.fileName), - [libFile.path, class1Dts.path, class3Dts, class2.path] + [libFile.path, class1Dts.path, class3Dts, class2.path], ); }); }); diff --git a/src/testRunner/unittests/services/organizeImports.ts b/src/testRunner/unittests/services/organizeImports.ts index 9794bd1d68746..eeac990fbe8a3 100644 --- a/src/testRunner/unittests/services/organizeImports.ts +++ b/src/testRunner/unittests/services/organizeImports.ts @@ -1,45 +1,63 @@ import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; -import { createProjectService } from "../helpers/tsserver"; +import { + createProjectService, +} from "../helpers/tsserver"; import { createServerHost, File, } from "../helpers/virtualFileSystemWithWatch"; -import { newLineCharacter } from "./extract/helpers"; +import { + newLineCharacter, +} from "./extract/helpers"; describe("unittests:: services:: organizeImports", () => { describe("Sort imports", () => { it("Sort - non-relative vs non-relative", () => { assertSortsBefore( `import y from "lib1";`, - `import x from "lib2";`); + `import x from "lib2";`, + ); }); it("Sort - relative vs relative", () => { assertSortsBefore( `import y from "./lib1";`, - `import x from "./lib2";`); + `import x from "./lib2";`, + ); }); it("Sort - relative vs non-relative", () => { assertSortsBefore( `import y from "lib";`, - `import x from "./lib";`); + `import x from "./lib";`, + ); }); it("Sort - case-insensitive", () => { assertSortsBefore( `import y from "a";`, - `import x from "Z";`); + `import x from "Z";`, + ); assertSortsBefore( `import y from "A";`, - `import x from "z";`); + `import x from "z";`, + ); }); function assertSortsBefore(importString1: string, importString2: string) { - const [{moduleSpecifier: moduleSpecifier1}, {moduleSpecifier: moduleSpecifier2}] = parseImports(importString1, importString2); - assert.equal(ts.OrganizeImports.compareModuleSpecifiers(moduleSpecifier1, moduleSpecifier2, /*ignoreCase*/ true), ts.Comparison.LessThan); - assert.equal(ts.OrganizeImports.compareModuleSpecifiers(moduleSpecifier2, moduleSpecifier1, /*ignoreCase*/ true), ts.Comparison.GreaterThan); + const [{ moduleSpecifier: moduleSpecifier1 }, { moduleSpecifier: moduleSpecifier2 }] = parseImports( + importString1, + importString2, + ); + assert.equal( + ts.OrganizeImports.compareModuleSpecifiers(moduleSpecifier1, moduleSpecifier2, /*ignoreCase*/ true), + ts.Comparison.LessThan, + ); + assert.equal( + ts.OrganizeImports.compareModuleSpecifiers(moduleSpecifier2, moduleSpecifier1, /*ignoreCase*/ true), + ts.Comparison.GreaterThan, + ); } }); @@ -58,7 +76,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine side-effect-only imports", () => { const sortedImports = parseImports( `import "lib";`, - `import "lib";`); + `import "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = parseImports(`import "lib";`); assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -67,7 +86,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine namespace imports", () => { const sortedImports = parseImports( `import * as x from "lib";`, - `import * as y from "lib";`); + `import * as y from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = sortedImports; assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -76,7 +96,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine default imports", () => { const sortedImports = parseImports( `import x from "lib";`, - `import y from "lib";`); + `import y from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = parseImports(`import { default as x, default as y } from "lib";`); assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -85,7 +106,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine property imports", () => { const sortedImports = parseImports( `import { x } from "lib";`, - `import { y as z } from "lib";`); + `import { y as z } from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = parseImports(`import { x, y as z } from "lib";`); assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -94,7 +116,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine side-effect-only import with namespace import", () => { const sortedImports = parseImports( `import "lib";`, - `import * as x from "lib";`); + `import * as x from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = sortedImports; assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -103,7 +126,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine side-effect-only import with default import", () => { const sortedImports = parseImports( `import "lib";`, - `import x from "lib";`); + `import x from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = sortedImports; assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -112,7 +136,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine side-effect-only import with property import", () => { const sortedImports = parseImports( `import "lib";`, - `import { x } from "lib";`); + `import { x } from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = sortedImports; assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -121,17 +146,20 @@ describe("unittests:: services:: organizeImports", () => { it("Combine namespace import with default import", () => { const sortedImports = parseImports( `import * as x from "lib";`, - `import y from "lib";`); + `import y from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = parseImports( - `import y, * as x from "lib";`); + `import y, * as x from "lib";`, + ); assertListEqual(actualCoalescedImports, expectedCoalescedImports); }); it("Combine namespace import with property import", () => { const sortedImports = parseImports( `import * as x from "lib";`, - `import { y } from "lib";`); + `import { y } from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = sortedImports; assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -140,10 +168,12 @@ describe("unittests:: services:: organizeImports", () => { it("Combine default import with property import", () => { const sortedImports = parseImports( `import x from "lib";`, - `import { y } from "lib";`); + `import { y } from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = parseImports( - `import x, { y } from "lib";`); + `import x, { y } from "lib";`, + ); assertListEqual(actualCoalescedImports, expectedCoalescedImports); }); @@ -156,13 +186,15 @@ describe("unittests:: services:: organizeImports", () => { `import "lib";`, `import * as x from "lib";`, `import z from "lib";`, - `import { a } from "lib";`); + `import { a } from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = parseImports( `import "lib";`, `import * as x from "lib";`, `import * as y from "lib";`, - `import { a, b, default as w, default as z } from "lib";`); + `import { a, b, default as w, default as z } from "lib";`, + ); assertListEqual(actualCoalescedImports, expectedCoalescedImports); }); @@ -171,7 +203,8 @@ describe("unittests:: services:: organizeImports", () => { const sortedImports = parseImports( `import * as x from "lib";`, `import * as y from "lib";`, - `import z from "lib";`); + `import z from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = sortedImports; assertListEqual(actualCoalescedImports, expectedCoalescedImports); @@ -181,11 +214,13 @@ describe("unittests:: services:: organizeImports", () => { const sortedImports = parseImports( `import type { x } from "lib";`, `import type { y } from "lib";`, - `import { z } from "lib";`); + `import { z } from "lib";`, + ); const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); const expectedCoalescedImports = parseImports( `import { z } from "lib";`, - `import type { x, y } from "lib";`); + `import type { x, y } from "lib";`, + ); assertListEqual(actualCoalescedImports, expectedCoalescedImports); }); @@ -193,7 +228,8 @@ describe("unittests:: services:: organizeImports", () => { const sortedImports = parseImports( `import type { x } from "lib";`, `import type * as y from "lib";`, - `import type z from "lib";`); + `import type z from "lib";`, + ); // Default import could be rewritten as a named import to combine with `x`, // but seems of debatable merit. const actualCoalescedImports = ts.OrganizeImports.coalesceImports(sortedImports, /*ignoreCase*/ true); @@ -224,7 +260,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine namespace re-exports", () => { const sortedExports = parseExports( `export * from "lib";`, - `export * from "lib";`); + `export * from "lib";`, + ); const actualCoalescedExports = ts.OrganizeImports.coalesceExports(sortedExports, /*ignoreCase*/ true); const expectedCoalescedExports = parseExports(`export * from "lib";`); assertListEqual(actualCoalescedExports, expectedCoalescedExports); @@ -233,7 +270,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine property exports", () => { const sortedExports = parseExports( `export { x };`, - `export { y as z };`); + `export { y as z };`, + ); const actualCoalescedExports = ts.OrganizeImports.coalesceExports(sortedExports, /*ignoreCase*/ true); const expectedCoalescedExports = parseExports(`export { x, y as z };`); assertListEqual(actualCoalescedExports, expectedCoalescedExports); @@ -242,7 +280,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine property re-exports", () => { const sortedExports = parseExports( `export { x } from "lib";`, - `export { y as z } from "lib";`); + `export { y as z } from "lib";`, + ); const actualCoalescedExports = ts.OrganizeImports.coalesceExports(sortedExports, /*ignoreCase*/ true); const expectedCoalescedExports = parseExports(`export { x, y as z } from "lib";`); assertListEqual(actualCoalescedExports, expectedCoalescedExports); @@ -251,7 +290,8 @@ describe("unittests:: services:: organizeImports", () => { it("Combine namespace re-export with property re-export", () => { const sortedExports = parseExports( `export * from "lib";`, - `export { y } from "lib";`); + `export { y } from "lib";`, + ); const actualCoalescedExports = ts.OrganizeImports.coalesceExports(sortedExports, /*ignoreCase*/ true); const expectedCoalescedExports = sortedExports; assertListEqual(actualCoalescedExports, expectedCoalescedExports); @@ -261,10 +301,12 @@ describe("unittests:: services:: organizeImports", () => { const sortedExports = parseExports( `export { x };`, `export { y as w, z as default };`, - `export { w as q };`); + `export { w as q };`, + ); const actualCoalescedExports = ts.OrganizeImports.coalesceExports(sortedExports, /*ignoreCase*/ true); const expectedCoalescedExports = parseExports( - `export { z as default, w as q, y as w, x };`); + `export { z as default, w as q, y as w, x };`, + ); assertListEqual(actualCoalescedExports, expectedCoalescedExports); }); @@ -272,18 +314,21 @@ describe("unittests:: services:: organizeImports", () => { const sortedExports = parseExports( `export { x as a, y } from "lib";`, `export * from "lib";`, - `export { z as b } from "lib";`); + `export { z as b } from "lib";`, + ); const actualCoalescedExports = ts.OrganizeImports.coalesceExports(sortedExports, /*ignoreCase*/ true); const expectedCoalescedExports = parseExports( `export * from "lib";`, - `export { x as a, z as b, y } from "lib";`); + `export { x as a, z as b, y } from "lib";`, + ); assertListEqual(actualCoalescedExports, expectedCoalescedExports); }); it("Keep type-only exports separate", () => { const sortedExports = parseExports( `export { x };`, - `export type { y };`); + `export type { y };`, + ); const actualCoalescedExports = ts.OrganizeImports.coalesceExports(sortedExports, /*ignoreCase*/ true); const expectedCoalescedExports = sortedExports; assertListEqual(actualCoalescedExports, expectedCoalescedExports); @@ -292,17 +337,17 @@ describe("unittests:: services:: organizeImports", () => { it("Combine type-only exports", () => { const sortedExports = parseExports( `export type { x };`, - `export type { y };`); + `export type { y };`, + ); const actualCoalescedExports = ts.OrganizeImports.coalesceExports(sortedExports, /*ignoreCase*/ true); const expectedCoalescedExports = parseExports( - `export type { x, y };`); + `export type { x, y };`, + ); assertListEqual(actualCoalescedExports, expectedCoalescedExports); }); }); - describe("Baselines", () => { - const libFile = { path: "/lib.ts", content: ` @@ -329,7 +374,11 @@ export const Other = 1; content: "function F() { }", }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, ts.testFormatSettings, ts.emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + ts.testFormatSettings, + ts.emptyOptions, + ); assert.isEmpty(changes); }); @@ -339,36 +388,39 @@ export const Other = 1; content: "declare module '*';", }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, ts.testFormatSettings, ts.emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + ts.testFormatSettings, + ts.emptyOptions, + ); assert.isEmpty(changes); }); it("doesn't return any changes when the text would be identical", () => { const testFile = { path: "/a.ts", - content: `import { f } from 'foo';\nf();` + content: `import { f } from 'foo';\nf();`, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, ts.testFormatSettings, ts.emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + ts.testFormatSettings, + ts.emptyOptions, + ); assert.isEmpty(changes); }); - testOrganizeImports("Renamed_used", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("Renamed_used", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { F1 as EffOne, F2 as EffTwo } from "lib"; EffOne(); `, - }, - libFile); + }, libFile); - testOrganizeImports("Simple", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("Simple", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; import * as NS from "lib"; import D from "lib"; @@ -378,29 +430,23 @@ D(); F1(); F2(); `, - }, - libFile); + }, libFile); - testOrganizeImports("Unused_Some", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("Unused_Some", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; import * as NS from "lib"; import D from "lib"; D(); `, - }, - libFile); - - describe("skipDestructiveCodeActions=true", () => { - testOrganizeImports("Syntax_Error_Body_skipDestructiveCodeActions", - /*skipDestructiveCodeActions*/ true, - { - path: "/test.ts", - content: ` + }, libFile); + + describe("skipDestructiveCodeActions=true", () => { + testOrganizeImports("Syntax_Error_Body_skipDestructiveCodeActions", /*skipDestructiveCodeActions*/ true, { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; import * as NS from "lib"; import D from "lib"; @@ -408,15 +454,12 @@ import D from "lib"; class class class; D; `, - }, - libFile); - }); - - testOrganizeImports("Syntax_Error_Imports_skipDestructiveCodeActions", - /*skipDestructiveCodeActions*/ true, - { - path: "/test.ts", - content: ` + }, libFile); + }); + + testOrganizeImports("Syntax_Error_Imports_skipDestructiveCodeActions", /*skipDestructiveCodeActions*/ true, { + path: "/test.ts", + content: ` import { F1, F2 class class class; } from "lib"; import * as NS from "lib"; class class class; @@ -424,15 +467,12 @@ import D from "lib"; D; `, - }, - libFile); - - describe("skipDestructiveCodeActions=false", () => { - testOrganizeImports("Syntax_Error_Body", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + }, libFile); + + describe("skipDestructiveCodeActions=false", () => { + testOrganizeImports("Syntax_Error_Body", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; import * as NS from "lib"; import D from "lib"; @@ -440,14 +480,11 @@ import D from "lib"; class class class; D; `, - }, - libFile); - - testOrganizeImports("Syntax_Error_Imports", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + }, libFile); + + testOrganizeImports("Syntax_Error_Imports", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { F1, F2 class class class; } from "lib"; import * as NS from "lib"; class class class; @@ -455,31 +492,31 @@ import D from "lib"; D; `, - }, - libFile); - }); - - it("doesn't return any changes when the text would be identical", () => { - const testFile = { - path: "/a.ts", - content: `import { f } from 'foo';\nf();` - }; - const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, ts.testFormatSettings, ts.emptyOptions); - assert.isEmpty(changes); - }); + }, libFile); + }); - testOrganizeImports("Unused_All", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + it("doesn't return any changes when the text would be identical", () => { + const testFile = { + path: "/a.ts", + content: `import { f } from 'foo';\nf();`, + }; + const languageService = makeLanguageService(testFile); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + ts.testFormatSettings, + ts.emptyOptions, + ); + assert.isEmpty(changes); + }); + + testOrganizeImports("Unused_All", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; import * as NS from "lib"; import D from "lib"; `, - }, - libFile); + }, libFile); it("Unused_Empty", () => { const testFile = { @@ -489,15 +526,17 @@ import { } from "lib"; `, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, ts.testFormatSettings, ts.emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + ts.testFormatSettings, + ts.emptyOptions, + ); assert.isEmpty(changes); }); - testOrganizeImports("Unused_false_positive_module_augmentation", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.d.ts", - content: ` + testOrganizeImports("Unused_false_positive_module_augmentation", /*skipDestructiveCodeActions*/ false, { + path: "/test.d.ts", + content: ` import foo from 'foo'; import { Caseless } from 'caseless'; @@ -506,10 +545,11 @@ declare module 'caseless' { interface Caseless { test(name: KeyType): boolean; } -}` - }); +}`, + }); - testOrganizeImports("Unused_preserve_imports_for_module_augmentation_in_non_declaration_file", + testOrganizeImports( + "Unused_preserve_imports_for_module_augmentation_in_non_declaration_file", /*skipDestructiveCodeActions*/ false, { path: "/test.ts", @@ -522,8 +562,9 @@ declare module 'caseless' { interface Caseless { test(name: KeyType): boolean; } -}` - }); +}`, + }, + ); it("Unused_false_positive_shorthand_assignment", () => { const testFile = { @@ -531,10 +572,14 @@ declare module 'caseless' { content: ` import { x } from "a"; const o = { x }; -` +`, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, ts.testFormatSettings, ts.emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + ts.testFormatSettings, + ts.emptyOptions, + ); assert.isEmpty(changes); }); @@ -544,18 +589,20 @@ const o = { x }; content: ` import { x } from "a"; export { x }; -` +`, }; const languageService = makeLanguageService(testFile); - const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, ts.testFormatSettings, ts.emptyOptions); + const changes = languageService.organizeImports( + { type: "file", fileName: testFile.path }, + ts.testFormatSettings, + ts.emptyOptions, + ); assert.isEmpty(changes); }); - testOrganizeImports("MoveToTop", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("MoveToTop", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; F1(); F2(); @@ -564,15 +611,12 @@ NS.F1(); import D from "lib"; D(); `, - }, - libFile); + }, libFile); /* eslint-disable no-template-curly-in-string */ - testOrganizeImports("MoveToTop_Invalid", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("MoveToTop_Invalid", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; F1(); F2(); @@ -583,24 +627,22 @@ import a from ${"`${'lib'}`"}; import D from "lib"; D(); `, - }, - libFile); + }, libFile); /* eslint-enable no-template-curly-in-string */ - testOrganizeImports("TypeOnly", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("TypeOnly", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { X } from "lib"; import type Y from "lib"; import { Z } from "lib"; import type { A, B } from "lib"; -export { A, B, X, Y, Z };` - }); +export { A, B, X, Y, Z };`, + }); - testOrganizeImports("CoalesceMultipleModules", + testOrganizeImports( + "CoalesceMultipleModules", /*skipDestructiveCodeActions*/ false, { path: "/test.ts", @@ -613,23 +655,22 @@ a + b + c + d; `, }, { path: "/lib1.ts", content: "export const b = 1, d = 2;" }, - { path: "/lib2.ts", content: "export const a = 3, c = 4;" }); + { path: "/lib2.ts", content: "export const a = 3, c = 4;" }, + ); - testOrganizeImports("CoalesceTrivia", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("CoalesceTrivia", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` /*A*/import /*B*/ { /*C*/ F2 /*D*/ } /*E*/ from /*F*/ "lib" /*G*/;/*H*/ //I /*J*/import /*K*/ { /*L*/ F1 /*M*/ } /*N*/ from /*O*/ "lib" /*P*/;/*Q*/ //R F1(); F2(); `, - }, - libFile); + }, libFile); - testOrganizeImports("SortTrivia", + testOrganizeImports( + "SortTrivia", /*skipDestructiveCodeActions*/ false, { path: "/test.ts", @@ -639,42 +680,35 @@ F2(); `, }, { path: "/lib1.ts", content: "" }, - { path: "/lib2.ts", content: "" }); + { path: "/lib2.ts", content: "" }, + ); - testOrganizeImports("UnusedTrivia1", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("UnusedTrivia1", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` /*A*/import /*B*/ { /*C*/ F1 /*D*/ } /*E*/ from /*F*/ "lib" /*G*/;/*H*/ //I `, - }, - libFile); + }, libFile); - testOrganizeImports("UnusedTrivia2", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("UnusedTrivia2", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` /*A*/import /*B*/ { /*C*/ F1 /*D*/, /*E*/ F2 /*F*/ } /*G*/ from /*H*/ "lib" /*I*/;/*J*/ //K F1(); `, - }, - libFile); + }, libFile); - testOrganizeImports("UnusedHeaderComment", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("UnusedHeaderComment", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` // Header import { F1 } from "lib"; `, - }, - libFile); + }, libFile); - testOrganizeImports("SortHeaderComment", + testOrganizeImports( + "SortHeaderComment", /*skipDestructiveCodeActions*/ false, { path: "/test.ts", @@ -685,13 +719,12 @@ import "lib1"; `, }, { path: "/lib1.ts", content: "" }, - { path: "/lib2.ts", content: "" }); + { path: "/lib2.ts", content: "" }, + ); - testOrganizeImports("AmbientModule", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("AmbientModule", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` declare module "mod" { import { F1 } from "lib"; import * as NS from "lib"; @@ -700,14 +733,11 @@ declare module "mod" { function F(f1: {} = F1, f2: {} = F2) {} } `, - }, - libFile); + }, libFile); - testOrganizeImports("TopLevelAndAmbientModule", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("TopLevelAndAmbientModule", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import D from "lib"; declare module "mod" { @@ -723,168 +753,130 @@ import "lib"; D(); `, - }, - libFile); + }, libFile); - testOrganizeImports("JsxFactoryUsedJsx", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.jsx", - content: ` + testOrganizeImports("JsxFactoryUsedJsx", /*skipDestructiveCodeActions*/ false, { + path: "/test.jsx", + content: ` import { React, Other } from "react";
; `, - }, - reactLibFile); + }, reactLibFile); - testOrganizeImports("JsxFactoryUsedJs", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.js", - content: ` + testOrganizeImports("JsxFactoryUsedJs", /*skipDestructiveCodeActions*/ false, { + path: "/test.js", + content: ` import { React, Other } from "react";
; `, - }, - reactLibFile); + }, reactLibFile); - testOrganizeImports("JsxFactoryUsedTsx", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.tsx", - content: ` + testOrganizeImports("JsxFactoryUsedTsx", /*skipDestructiveCodeActions*/ false, { + path: "/test.tsx", + content: ` import { React, Other } from "react";
; `, - }, - reactLibFile); + }, reactLibFile); // TS files are not JSX contexts, so the parser does not treat // `
` as a JSX element. - testOrganizeImports("JsxFactoryUsedTs", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("JsxFactoryUsedTs", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { React, Other } from "react";
; `, - }, - reactLibFile); + }, reactLibFile); - testOrganizeImports("JsxFactoryUnusedJsx", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.jsx", - content: ` + testOrganizeImports("JsxFactoryUnusedJsx", /*skipDestructiveCodeActions*/ false, { + path: "/test.jsx", + content: ` import { React, Other } from "react"; `, - }, - reactLibFile); + }, reactLibFile); // Note: Since the file extension does not end with "x", the jsx compiler option // will not be enabled. The import should be retained regardless. - testOrganizeImports("JsxFactoryUnusedJs", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.js", - content: ` + testOrganizeImports("JsxFactoryUnusedJs", /*skipDestructiveCodeActions*/ false, { + path: "/test.js", + content: ` import { React, Other } from "react"; `, - }, - reactLibFile); + }, reactLibFile); - testOrganizeImports("JsxFactoryUnusedTsx", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.tsx", - content: ` + testOrganizeImports("JsxFactoryUnusedTsx", /*skipDestructiveCodeActions*/ false, { + path: "/test.tsx", + content: ` import { React, Other } from "react"; `, - }, - reactLibFile); + }, reactLibFile); - testOrganizeImports("JsxFactoryUnusedTs", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.ts", - content: ` + testOrganizeImports("JsxFactoryUnusedTs", /*skipDestructiveCodeActions*/ false, { + path: "/test.ts", + content: ` import { React, Other } from "react"; `, - }, - reactLibFile); + }, reactLibFile); - testOrganizeImports("JsxPragmaTsx", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.tsx", - content: `/** @jsx jsx */ + testOrganizeImports("JsxPragmaTsx", /*skipDestructiveCodeActions*/ false, { + path: "/test.tsx", + content: `/** @jsx jsx */ import { Global, jsx } from '@emotion/core'; import * as React from 'react'; export const App: React.FunctionComponent = _ =>

Hello!

`, - }, - { - path: "/@emotion/core/index.d.ts", - content: `import { createElement } from 'react' + }, { + path: "/@emotion/core/index.d.ts", + content: `import { createElement } from 'react' export const jsx: typeof createElement; -export function Global(props: any): ReactElement;` - }, - { - path: reactLibFile.path, - content: `${reactLibFile.content} +export function Global(props: any): ReactElement;`, + }, { + path: reactLibFile.path, + content: `${reactLibFile.content} export namespace React { interface FunctionComponent { } } -` - } - ); +`, + }); - testOrganizeImports("JsxFragmentPragmaTsx", - /*skipDestructiveCodeActions*/ false, - { - path: "/test.tsx", - content: `/** @jsx h */ + testOrganizeImports("JsxFragmentPragmaTsx", /*skipDestructiveCodeActions*/ false, { + path: "/test.tsx", + content: `/** @jsx h */ /** @jsxFrag frag */ import { h, frag } from "@foo/core"; const elem = <>
Foo
; `, - }, - { - path: "/@foo/core/index.d.ts", - content: `export function h(): void; + }, { + path: "/@foo/core/index.d.ts", + content: `export function h(): void; export function frag(): void; -` - } - ); +`, + }); describe("Exports", () => { - - testOrganizeExports("MoveToTop", - { - path: "/test.ts", - content: ` + testOrganizeExports("MoveToTop", { + path: "/test.ts", + content: ` export { F1, F2 } from "lib"; 1; export * from "lib"; 2; `, - }, - libFile); + }, libFile); /* eslint-disable no-template-curly-in-string */ - testOrganizeExports("MoveToTop_Invalid", - { - path: "/test.ts", - content: ` + testOrganizeExports("MoveToTop_Invalid", { + path: "/test.ts", + content: ` export { F1, F2 } from "lib"; 1; export * from "lib"; @@ -894,14 +886,12 @@ export { a } from ${"`${'lib'}`"}; export { D } from "lib"; 3; `, - }, - libFile); + }, libFile); /* eslint-enable no-template-curly-in-string */ - testOrganizeExports("MoveToTop_WithImportsFirst", - { - path: "/test.ts", - content: ` + testOrganizeExports("MoveToTop_WithImportsFirst", { + path: "/test.ts", + content: ` import { F1, F2 } from "lib"; 1; export { F1, F2 } from "lib"; @@ -912,13 +902,11 @@ export * from "lib"; 4; F1(); F2(); NS.F1(); `, - }, - libFile); + }, libFile); - testOrganizeExports("MoveToTop_WithExportsFirst", - { - path: "/test.ts", - content: ` + testOrganizeExports("MoveToTop_WithExportsFirst", { + path: "/test.ts", + content: ` export { F1, F2 } from "lib"; 1; import { F1, F2 } from "lib"; @@ -929,10 +917,10 @@ import * as NS from "lib"; 4; F1(); F2(); NS.F1(); `, - }, - libFile); + }, libFile); - testOrganizeExports("CoalesceMultipleModules", + testOrganizeExports( + "CoalesceMultipleModules", { path: "/test.ts", content: ` @@ -943,19 +931,19 @@ export { a } from "lib2"; `, }, { path: "/lib1.ts", content: "export const b = 1, d = 2;" }, - { path: "/lib2.ts", content: "export const a = 3, c = 4;" }); + { path: "/lib2.ts", content: "export const a = 3, c = 4;" }, + ); - testOrganizeExports("CoalesceTrivia", - { - path: "/test.ts", - content: ` + testOrganizeExports("CoalesceTrivia", { + path: "/test.ts", + content: ` /*A*/export /*B*/ { /*C*/ F2 /*D*/ } /*E*/ from /*F*/ "lib" /*G*/;/*H*/ //I /*J*/export /*K*/ { /*L*/ F1 /*M*/ } /*N*/ from /*O*/ "lib" /*P*/;/*Q*/ //R `, - }, - libFile); + }, libFile); - testOrganizeExports("SortTrivia", + testOrganizeExports( + "SortTrivia", { path: "/test.ts", content: ` @@ -964,9 +952,11 @@ export { a } from "lib2"; `, }, { path: "/lib1.ts", content: "" }, - { path: "/lib2.ts", content: "" }); + { path: "/lib2.ts", content: "" }, + ); - testOrganizeExports("SortHeaderComment", + testOrganizeExports( + "SortHeaderComment", { path: "/test.ts", content: ` @@ -976,25 +966,23 @@ export * from "lib1"; `, }, { path: "/lib1.ts", content: "" }, - { path: "/lib2.ts", content: "" }); + { path: "/lib2.ts", content: "" }, + ); - testOrganizeExports("AmbientModule", - { - path: "/test.ts", - content: ` + testOrganizeExports("AmbientModule", { + path: "/test.ts", + content: ` declare module "mod" { export { F1 } from "lib"; export * from "lib"; export { F2 } from "lib"; } `, - }, - libFile); + }, libFile); - testOrganizeExports("TopLevelAndAmbientModule", - { - path: "/test.ts", - content: ` + testOrganizeExports("TopLevelAndAmbientModule", { + path: "/test.ts", + content: ` export { D } from "lib"; declare module "mod" { @@ -1006,52 +994,89 @@ declare module "mod" { export { E } from "lib"; export * from "lib"; `, - }, - libFile); + }, libFile); }); function testOrganizeExports(testName: string, testFile: File, ...otherFiles: File[]) { testOrganizeImports(`${testName}.exports`, /*skipDestructiveCodeActions*/ true, testFile, ...otherFiles); } - function testOrganizeImports(testName: string, skipDestructiveCodeActions: boolean, testFile: File, ...otherFiles: File[]) { - it(testName, () => runBaseline(`organizeImports/${testName}.ts`, skipDestructiveCodeActions, testFile, ...otherFiles)); + function testOrganizeImports( + testName: string, + skipDestructiveCodeActions: boolean, + testFile: File, + ...otherFiles: File[] + ) { + it( + testName, + () => + runBaseline(`organizeImports/${testName}.ts`, skipDestructiveCodeActions, testFile, ...otherFiles), + ); } - function runBaseline(baselinePath: string, skipDestructiveCodeActions: boolean, testFile: File, ...otherFiles: File[]) { + function runBaseline( + baselinePath: string, + skipDestructiveCodeActions: boolean, + testFile: File, + ...otherFiles: File[] + ) { const { path: testPath, content: testContent } = testFile; const languageService = makeLanguageService(testFile, ...otherFiles); - const changes = languageService.organizeImports({ skipDestructiveCodeActions, type: "file", fileName: testPath }, ts.testFormatSettings, ts.emptyOptions); + const changes = languageService.organizeImports( + { skipDestructiveCodeActions, type: "file", fileName: testPath }, + ts.testFormatSettings, + ts.emptyOptions, + ); assert.equal(changes.length, 1); assert.equal(changes[0].fileName, testPath); const newText = ts.textChanges.applyChanges(testContent, changes[0].textChanges); - Harness.Baseline.runBaseline(baselinePath, [ - "// ==ORIGINAL==", - testContent, - "// ==ORGANIZED==", - newText, - ].join(newLineCharacter)); + Harness.Baseline.runBaseline( + baselinePath, + [ + "// ==ORIGINAL==", + testContent, + "// ==ORGANIZED==", + newText, + ].join(newLineCharacter), + ); } function makeLanguageService(...files: File[]) { const host = createServerHost(files); - const projectService = createProjectService(host, { useSingleInferredProject: true, allowNonBaseliningLogger: true }); - projectService.setCompilerOptionsForInferredProjects({ jsx: files.some(f => f.path.endsWith("x")) ? ts.JsxEmit.React : ts.JsxEmit.None }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + allowNonBaseliningLogger: true, + }); + projectService.setCompilerOptionsForInferredProjects({ + jsx: files.some(f => f.path.endsWith("x")) ? ts.JsxEmit.React : ts.JsxEmit.None, + }); files.forEach(f => projectService.openClientFile(f.path)); return projectService.inferredProjects[0].getLanguageService(); } }); function parseImports(...importStrings: string[]): readonly ts.ImportDeclaration[] { - const sourceFile = ts.createSourceFile("a.ts", importStrings.join("\n"), ts.ScriptTarget.ES2015, /*setParentNodes*/ true, ts.ScriptKind.TS); + const sourceFile = ts.createSourceFile( + "a.ts", + importStrings.join("\n"), + ts.ScriptTarget.ES2015, + /*setParentNodes*/ true, + ts.ScriptKind.TS, + ); const imports = ts.filter(sourceFile.statements, ts.isImportDeclaration); assert.equal(imports.length, importStrings.length); return imports; } function parseExports(...exportStrings: string[]): readonly ts.ExportDeclaration[] { - const sourceFile = ts.createSourceFile("a.ts", exportStrings.join("\n"), ts.ScriptTarget.ES2015, /*setParentNodes*/ true, ts.ScriptKind.TS); + const sourceFile = ts.createSourceFile( + "a.ts", + exportStrings.join("\n"), + ts.ScriptTarget.ES2015, + /*setParentNodes*/ true, + ts.ScriptKind.TS, + ); const exports = ts.filter(sourceFile.statements, ts.isExportDeclaration); assert.equal(exports.length, exportStrings.length); return exports; diff --git a/src/testRunner/unittests/services/patternMatcher.ts b/src/testRunner/unittests/services/patternMatcher.ts index d48dd97220b59..1307479226c60 100644 --- a/src/testRunner/unittests/services/patternMatcher.ts +++ b/src/testRunner/unittests/services/patternMatcher.ts @@ -135,7 +135,10 @@ describe("unittests:: services:: PatternMatcher", () => { }); it("TwoUppercaseCharacters", () => { - assertSegmentMatch("SimpleUIElement", "SiUI", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); + assertSegmentMatch("SimpleUIElement", "SiUI", { + kind: ts.PatternMatchKind.camelCase, + isCaseSensitive: true, + }); }); it("PreferCaseSensitiveLowercasePattern", () => { @@ -179,7 +182,10 @@ describe("unittests:: services:: PatternMatcher", () => { }); it("AllLowerPattern1", () => { - assertSegmentMatch("FogBarChangedEventArgs", "changedeventargs", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); + assertSegmentMatch("FogBarChangedEventArgs", "changedeventargs", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: false, + }); }); it("AllLowerPattern2", () => { @@ -197,55 +203,94 @@ describe("unittests:: services:: PatternMatcher", () => { describe("MultiWordPattern", () => { it("ExactWithLowercase", () => { - assertSegmentMatch("AddMetadataReference", "addmetadatareference", { kind: ts.PatternMatchKind.exact, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "addmetadatareference", { + kind: ts.PatternMatchKind.exact, + isCaseSensitive: false, + }); }); it("SingleLowercasedSearchWord1", () => { - assertSegmentMatch("AddMetadataReference", "add", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "add", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: false, + }); }); it("SingleLowercasedSearchWord2", () => { - assertSegmentMatch("AddMetadataReference", "metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "metadata", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: false, + }); }); it("SingleUppercaseSearchWord1", () => { - assertSegmentMatch("AddMetadataReference", "Add", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "Add", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("SingleUppercaseSearchWord2", () => { - assertSegmentMatch("AddMetadataReference", "Metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "Metadata", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: true, + }); }); it("SingleUppercaseSearchLetter1", () => { - assertSegmentMatch("AddMetadataReference", "A", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "A", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("SingleUppercaseSearchLetter2", () => { - assertSegmentMatch("AddMetadataReference", "M", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "M", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: true, + }); }); it("TwoLowercaseWords0", () => { - assertSegmentMatch("AddMetadataReference", "add metadata", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "add metadata", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: false, + }); }); it("TwoLowercaseWords1", () => { - assertSegmentMatch("AddMetadataReference", "A M", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "A M", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("TwoLowercaseWords2", () => { - assertSegmentMatch("AddMetadataReference", "AM", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "AM", { + kind: ts.PatternMatchKind.camelCase, + isCaseSensitive: true, + }); }); it("TwoLowercaseWords3", () => { - assertSegmentMatch("AddMetadataReference", "ref Metadata", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "ref Metadata", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: true, + }); }); it("TwoLowercaseWords4", () => { - assertSegmentMatch("AddMetadataReference", "ref M", { kind: ts.PatternMatchKind.substring, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "ref M", { + kind: ts.PatternMatchKind.substring, + isCaseSensitive: true, + }); }); it("MixedCamelCase", () => { - assertSegmentMatch("AddMetadataReference", "AMRe", { kind: ts.PatternMatchKind.camelCase, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "AMRe", { + kind: ts.PatternMatchKind.camelCase, + isCaseSensitive: true, + }); }); it("BlankPattern", () => { @@ -257,15 +302,24 @@ describe("unittests:: services:: PatternMatcher", () => { }); it("EachWordSeparately1", () => { - assertSegmentMatch("AddMetadataReference", "add Meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: false }); + assertSegmentMatch("AddMetadataReference", "add Meta", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: false, + }); }); it("EachWordSeparately2", () => { - assertSegmentMatch("AddMetadataReference", "Add meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "Add meta", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("EachWordSeparately3", () => { - assertSegmentMatch("AddMetadataReference", "Add Meta", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertSegmentMatch("AddMetadataReference", "Add Meta", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("MixedCasing", () => { @@ -299,15 +353,24 @@ describe("unittests:: services:: PatternMatcher", () => { }); it("DottedPattern3", () => { - assertFullMatch("Foo.Bar.Baz", "Quux", "B.B.Q", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertFullMatch("Foo.Bar.Baz", "Quux", "B.B.Q", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("DottedPattern4", () => { - assertFullMatch("Foo.Bar.Baz", "Quux", "Baz.Quux", { kind: ts.PatternMatchKind.exact, isCaseSensitive: true }); + assertFullMatch("Foo.Bar.Baz", "Quux", "Baz.Quux", { + kind: ts.PatternMatchKind.exact, + isCaseSensitive: true, + }); }); it("DottedPattern5", () => { - assertFullMatch("Foo.Bar.Baz", "Quux", "F.B.B.Quux", { kind: ts.PatternMatchKind.prefix, isCaseSensitive: true }); + assertFullMatch("Foo.Bar.Baz", "Quux", "F.B.B.Quux", { + kind: ts.PatternMatchKind.prefix, + isCaseSensitive: true, + }); }); it("DottedPattern6", () => { @@ -328,8 +391,16 @@ describe("unittests:: services:: PatternMatcher", () => { assert.equal(ts.createPatternMatcher(pattern), undefined); } - function assertFullMatch(dottedContainer: string, candidate: string, pattern: string, expected: ts.PatternMatch | undefined): void { - assert.deepEqual(ts.createPatternMatcher(pattern)!.getFullMatch(dottedContainer.split("."), candidate), expected); + function assertFullMatch( + dottedContainer: string, + candidate: string, + pattern: string, + expected: ts.PatternMatch | undefined, + ): void { + assert.deepEqual( + ts.createPatternMatcher(pattern)!.getFullMatch(dottedContainer.split("."), candidate), + expected, + ); } function spanListToSubstrings(identifier: string, spans: ts.TextSpan[]) { diff --git a/src/testRunner/unittests/services/preProcessFile.ts b/src/testRunner/unittests/services/preProcessFile.ts index 53332cebc5220..e6d2e60f7ca75 100644 --- a/src/testRunner/unittests/services/preProcessFile.ts +++ b/src/testRunner/unittests/services/preProcessFile.ts @@ -1,15 +1,37 @@ import * as ts from "../../_namespaces/ts"; describe("unittests:: services:: PreProcessFile:", () => { - function test(sourceText: string, readImportFile: boolean, detectJavaScriptImports: boolean, expectedPreProcess: ts.PreProcessedFileInfo): void { + function test( + sourceText: string, + readImportFile: boolean, + detectJavaScriptImports: boolean, + expectedPreProcess: ts.PreProcessedFileInfo, + ): void { const resultPreProcess = ts.preProcessFile(sourceText, readImportFile, detectJavaScriptImports); - assert.equal(resultPreProcess.isLibFile, expectedPreProcess.isLibFile, "Pre-processed file has different value for isLibFile. Expected: " + expectedPreProcess.isLibFile + ". Actual: " + resultPreProcess.isLibFile); + assert.equal( + resultPreProcess.isLibFile, + expectedPreProcess.isLibFile, + "Pre-processed file has different value for isLibFile. Expected: " + expectedPreProcess.isLibFile + + ". Actual: " + resultPreProcess.isLibFile, + ); checkFileReferenceList("Imported files", expectedPreProcess.importedFiles, resultPreProcess.importedFiles); - checkFileReferenceList("Referenced files", expectedPreProcess.referencedFiles, resultPreProcess.referencedFiles); - checkFileReferenceList("Type reference directives", expectedPreProcess.typeReferenceDirectives, resultPreProcess.typeReferenceDirectives); - checkFileReferenceList("Lib reference directives", expectedPreProcess.libReferenceDirectives, resultPreProcess.libReferenceDirectives); + checkFileReferenceList( + "Referenced files", + expectedPreProcess.referencedFiles, + resultPreProcess.referencedFiles, + ); + checkFileReferenceList( + "Type reference directives", + expectedPreProcess.typeReferenceDirectives, + resultPreProcess.typeReferenceDirectives, + ); + checkFileReferenceList( + "Lib reference directives", + expectedPreProcess.libReferenceDirectives, + resultPreProcess.libReferenceDirectives, + ); assert.deepEqual(resultPreProcess.ambientExternalModules, expectedPreProcess.ambientExternalModules); } @@ -18,27 +40,40 @@ describe("unittests:: services:: PreProcessFile:", () => { if (expected === actual) { return; } - assert.deepEqual(actual, expected, `Expected [${kind}] ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); + assert.deepEqual( + actual, + expected, + `Expected [${kind}] ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`, + ); } describe("Test preProcessFiles,", () => { it("Correctly return referenced files from triple slash", () => { - test("///" + "\n" + "///" + "\n" + "///" + "\n" + "///", + test( + '///' + "\n" + '///' + "\n" + + '///' + "\n" + '///', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { - referencedFiles: [{ fileName: "refFile1.ts", pos: 22, end: 33 }, { fileName: "refFile2.ts", pos: 59, end: 70 }, - { fileName: "refFile3.ts", pos: 94, end: 105 }, { fileName: "..\\refFile4d.ts", pos: 131, end: 146 }], + referencedFiles: [ + { fileName: "refFile1.ts", pos: 22, end: 33 }, + { fileName: "refFile2.ts", pos: 59, end: 70 }, + { fileName: "refFile3.ts", pos: 94, end: 105 }, + { fileName: "..\\refFile4d.ts", pos: 131, end: 146 }, + ], importedFiles: [] as ts.FileReference[], typeReferenceDirectives: [], libReferenceDirectives: [], ambientExternalModules: undefined, - isLibFile: false - }); + isLibFile: false, + }, + ); }); it("Do not return reference path because of invalid triple-slash syntax", () => { - test("///" + "\n" + "///" + "\n" + "///" + "\n" + "///", + test( + '///' + "\n" + '///' + "\n" + + '///' + "\n" + '///', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -47,55 +82,58 @@ describe("unittests:: services:: PreProcessFile:", () => { typeReferenceDirectives: [], libReferenceDirectives: [], ambientExternalModules: undefined, - isLibFile: false - }); + isLibFile: false, + }, + ); }); it("Do not return reference path of non-imports", () => { - test("Quill.import('delta');", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [] as ts.FileReference[], - importedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - ambientExternalModules: undefined, - isLibFile: false - }); + test("Quill.import('delta');", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { + referencedFiles: [] as ts.FileReference[], + importedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + ambientExternalModules: undefined, + isLibFile: false, + }); }); it("Do not return reference path of nested non-imports", () => { - test("a.b.import('c');", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [] as ts.FileReference[], - importedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - ambientExternalModules: undefined, - isLibFile: false - }); + test("a.b.import('c');", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { + referencedFiles: [] as ts.FileReference[], + importedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + ambientExternalModules: undefined, + isLibFile: false, + }); }); it("Correctly return imported files", () => { - test("import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\"); import i3= require(\"r3.ts\"); import i4=require(\"r4.ts\"); import i5 = require (\"r5.ts\");", + test( + 'import i1 = require("r1.ts"); import i2 =require("r2.ts"); import i3= require("r3.ts"); import i4=require("r4.ts"); import i5 = require ("r5.ts");', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { referencedFiles: [] as ts.FileReference[], typeReferenceDirectives: [], libReferenceDirectives: [], - importedFiles: [{ fileName: "r1.ts", pos: 20, end: 25 }, { fileName: "r2.ts", pos: 49, end: 54 }, { fileName: "r3.ts", pos: 78, end: 83 }, - { fileName: "r4.ts", pos: 106, end: 111 }, { fileName: "r5.ts", pos: 138, end: 143 }], + importedFiles: [ + { fileName: "r1.ts", pos: 20, end: 25 }, + { fileName: "r2.ts", pos: 49, end: 54 }, + { fileName: "r3.ts", pos: 78, end: 83 }, + { fileName: "r4.ts", pos: 106, end: 111 }, + { fileName: "r5.ts", pos: 138, end: 143 }, + ], ambientExternalModules: undefined, - isLibFile: false - }); + isLibFile: false, + }, + ); }); it("Do not return imported files if readImportFiles argument is false", () => { - test("import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\"); import i3= require(\"r3.ts\"); import i4=require(\"r4.ts\"); import i5 = require (\"r5.ts\");", + test( + 'import i1 = require("r1.ts"); import i2 =require("r2.ts"); import i3= require("r3.ts"); import i4=require("r4.ts"); import i5 = require ("r5.ts");', /*readImportFile*/ false, /*detectJavaScriptImports*/ false, { @@ -104,12 +142,14 @@ describe("unittests:: services:: PreProcessFile:", () => { libReferenceDirectives: [], importedFiles: [] as ts.FileReference[], ambientExternalModules: undefined, - isLibFile: false - }); + isLibFile: false, + }, + ); }); it("Do not return import path because of invalid import syntax", () => { - test("import i1 require(\"r1.ts\"); import = require(\"r2.ts\") import i3= require(\"r3.ts\"); import i5", + test( + 'import i1 require("r1.ts"); import = require("r2.ts") import i3= require("r3.ts"); import i5', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -118,26 +158,36 @@ describe("unittests:: services:: PreProcessFile:", () => { libReferenceDirectives: [], importedFiles: [{ fileName: "r3.ts", pos: 73, end: 78 }], ambientExternalModules: undefined, - isLibFile: false - }); + isLibFile: false, + }, + ); }); it("Correctly return referenced files and import files", () => { - test("///" + "\n" + "///" + "\n" + "import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\");", + test( + '///' + "\n" + '///' + "\n" + + 'import i1 = require("r1.ts"); import i2 =require("r2.ts");', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { - referencedFiles: [{ fileName: "refFile1.ts", pos: 20, end: 31 }, { fileName: "refFile2.ts", pos: 57, end: 68 }], + referencedFiles: [{ fileName: "refFile1.ts", pos: 20, end: 31 }, { + fileName: "refFile2.ts", + pos: 57, + end: 68, + }], typeReferenceDirectives: [], libReferenceDirectives: [], importedFiles: [{ fileName: "r1.ts", pos: 92, end: 97 }, { fileName: "r2.ts", pos: 121, end: 126 }], ambientExternalModules: undefined, - isLibFile: false - }); + isLibFile: false, + }, + ); }); it("Correctly return referenced files and import files even with some invalid syntax", () => { - test("///" + "\n" + "///" + "\n" + "import i1 = require(\"r1.ts\"); import = require(\"r2.ts\"); import i2 = require(\"r3.ts\");", + test( + '///' + "\n" + '///' + "\n" + + 'import i1 = require("r1.ts"); import = require("r2.ts"); import i2 = require("r3.ts");', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { @@ -146,551 +196,588 @@ describe("unittests:: services:: PreProcessFile:", () => { libReferenceDirectives: [], importedFiles: [{ fileName: "r1.ts", pos: 91, end: 96 }, { fileName: "r3.ts", pos: 148, end: 153 }], ambientExternalModules: undefined, - isLibFile: false - }); + isLibFile: false, + }, + ); }); it("Correctly return ES6 imports", () => { - test("import * as ns from \"m1\";" + "\n" + - "import def, * as ns from \"m2\";" + "\n" + - "import def from \"m3\";" + "\n" + - "import {a} from \"m4\";" + "\n" + - "import {a as A} from \"m5\";" + "\n" + - "import {a as A, b, c as C} from \"m6\";" + "\n" + - "import def , {a, b, c as C} from \"m7\";" + "\n", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m1", pos: 20, end: 22 }, - { fileName: "m2", pos: 51, end: 53 }, - { fileName: "m3", pos: 73, end: 75 }, - { fileName: "m4", pos: 95, end: 97 }, - { fileName: "m5", pos: 122, end: 124 }, - { fileName: "m6", pos: 160, end: 162 }, - { fileName: "m7", pos: 199, end: 201 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'import * as ns from "m1";' + "\n" + + 'import def, * as ns from "m2";' + "\n" + + 'import def from "m3";' + "\n" + + 'import {a} from "m4";' + "\n" + + 'import {a as A} from "m5";' + "\n" + + 'import {a as A, b, c as C} from "m6";' + "\n" + + 'import def , {a, b, c as C} from "m7";' + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m1", pos: 20, end: 22 }, + { fileName: "m2", pos: 51, end: 53 }, + { fileName: "m3", pos: 73, end: 75 }, + { fileName: "m4", pos: 95, end: 97 }, + { fileName: "m5", pos: 122, end: 124 }, + { fileName: "m6", pos: 160, end: 162 }, + { fileName: "m7", pos: 199, end: 201 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly ignore commented imports following template expression", () => { /* eslint-disable no-template-curly-in-string */ - test("/**" + "\n" + - " * Before" + "\n" + - " * ```" + "\n" + - " * import * as a from \"a\";" + "\n" + - " * ```" + "\n" + - " */" + "\n" + - "type Foo = `${string}`;" + "\n" + - "/**" + "\n" + - " * After" + "\n" + - " * ```" + "\n" + - " * import { B } from \"b\";" + "\n" + - " * import * as c from \"c\";" + "\n" + - " * ```" + "\n" + - " */", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + "/**" + "\n" + + " * Before" + "\n" + + " * ```" + "\n" + + ' * import * as a from "a";' + "\n" + + " * ```" + "\n" + + " */" + "\n" + + "type Foo = `${string}`;" + "\n" + + "/**" + "\n" + + " * After" + "\n" + + " * ```" + "\n" + + ' * import { B } from "b";' + "\n" + + ' * import * as c from "c";' + "\n" + + " * ```" + "\n" + + " */", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Ignores imports in template strings", () => { /* eslint-disable no-template-curly-in-string */ - test("a ? `&${a}` : `#${b}`;\n\n `import(\"${moduleSpecifier}\").${id}`;", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'a ? `&${a}` : `#${b}`;\n\n `import("${moduleSpecifier}").${id}`;', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns imports after a template expression", () => { /* eslint-disable no-template-curly-in-string */ - test("`${foo}`; import \"./foo\";", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { + test('`${foo}`; import "./foo";', /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { referencedFiles: [], typeReferenceDirectives: [], libReferenceDirectives: [], importedFiles: [ - { fileName: "./foo", pos: 17, end: 22 } + { fileName: "./foo", pos: 17, end: 22 }, ], ambientExternalModules: undefined, - isLibFile: false + isLibFile: false, }); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns dynamic imports from template expression", () => { /* eslint-disable no-template-curly-in-string */ - test("`${(
Text `` ${} text {} " + "\n" + - "${import(\"a\")} {import(\"b\")} " + "\n" + - "${/* A comment */} ${/* import(\"ignored\") */}
)}`", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "a", pos: 39, end: 40 }, - { fileName: "b", pos: 53, end: 54 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + "`${(
Text `` ${} text {} " + "\n" + + '${import("a")} {import("b")} ' + "\n" + + '${/* A comment */} ${/* import("ignored") */}
)}`', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 39, end: 40 }, + { fileName: "b", pos: 53, end: 54 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns dynamic imports from nested template expression", () => { /* eslint-disable no-template-curly-in-string */ - test("`${foo(`${bar(`${import(\"a\")} ${import(\"b\")}`, `${baz(`${import(\"c\") ${import(\"d\")}`)}`)}`)}`", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "a", pos: 24, end: 25 }, - { fileName: "b", pos: 39, end: 40 }, - { fileName: "c", pos: 64, end: 65 }, - { fileName: "d", pos: 78, end: 79 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + '`${foo(`${bar(`${import("a")} ${import("b")}`, `${baz(`${import("c") ${import("d")}`)}`)}`)}`', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 24, end: 25 }, + { fileName: "b", pos: 39, end: 40 }, + { fileName: "c", pos: 64, end: 65 }, + { fileName: "d", pos: 78, end: 79 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns dynamic imports from tagged template expression", () => { /* eslint-disable no-template-curly-in-string */ - test("foo`${ fn({ a: 100 }, import(\"a\"), `${import(\"b\")}`, import(\"c\"), `${import(\"d\")} foo`, import(\"e\")) }`", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "a", pos: 29, end: 30 }, - { fileName: "b", pos: 45, end: 46 }, - { fileName: "c", pos: 60, end: 61 }, - { fileName: "d", pos: 76, end: 77 }, - { fileName: "e", pos: 95, end: 96 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'foo`${ fn({ a: 100 }, import("a"), `${import("b")}`, import("c"), `${import("d")} foo`, import("e")) }`', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 29, end: 30 }, + { fileName: "b", pos: 45, end: 46 }, + { fileName: "c", pos: 60, end: 61 }, + { fileName: "d", pos: 76, end: 77 }, + { fileName: "e", pos: 95, end: 96 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns dynamic imports from template expression and imports following it", () => { /* eslint-disable no-template-curly-in-string */ - test("const x = `hello ${await import(\"a\").default}`;" + "\n\n" + - "import { y } from \"b\";", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "a", pos: 32, end: 33 }, - { fileName: "b", pos: 67, end: 68 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'const x = `hello ${await import("a").default}`;' + "\n\n" + + 'import { y } from "b";', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 32, end: 33 }, + { fileName: "b", pos: 67, end: 68 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns dynamic imports from template expressions and other imports", () => { /* eslint-disable no-template-curly-in-string */ - test("const x = `x ${await import(\"a\").default}`;" + "\n\n" + - "import { y } from \"b\";" + "\n" + - "const y = `y ${import(\"c\")}`;" + "\n\n" + - "import { d } from \"d\";", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "a", pos: 28, end: 29 }, - { fileName: "b", pos: 63, end: 64 }, - { fileName: "c", pos: 90, end: 91 }, - { fileName: "d", pos: 117, end: 118 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'const x = `x ${await import("a").default}`;' + "\n\n" + + 'import { y } from "b";' + "\n" + + 'const y = `y ${import("c")}`;' + "\n\n" + + 'import { d } from "d";', + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "a", pos: 28, end: 29 }, + { fileName: "b", pos: 63, end: 64 }, + { fileName: "c", pos: 90, end: 91 }, + { fileName: "d", pos: 117, end: 118 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); /* eslint-enable no-template-curly-in-string */ }); it("Correctly returns empty importedFiles with incorrect template expression", () => { - test("const foo = `${", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { + test("const foo = `${", /*readImportFile*/ true, /*detectJavaScriptImports*/ true, { referencedFiles: [], typeReferenceDirectives: [], libReferenceDirectives: [], importedFiles: [], ambientExternalModules: undefined, - isLibFile: false + isLibFile: false, }); }); it("Correctly return ES6 exports", () => { - test("export * from \"m1\";" + "\n" + - "export {a} from \"m2\";" + "\n" + - "export {a as A} from \"m3\";" + "\n" + - "export {a as A, b, c as C} from \"m4\";" + "\n", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m1", pos: 14, end: 16 }, - { fileName: "m2", pos: 36, end: 38 }, - { fileName: "m3", pos: 63, end: 65 }, - { fileName: "m4", pos: 101, end: 103 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'export * from "m1";' + "\n" + + 'export {a} from "m2";' + "\n" + + 'export {a as A} from "m3";' + "\n" + + 'export {a as A, b, c as C} from "m4";' + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m1", pos: 14, end: 16 }, + { fileName: "m2", pos: 36, end: 38 }, + { fileName: "m3", pos: 63, end: 65 }, + { fileName: "m4", pos: 101, end: 103 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly handles import types", () => { - test("import type * as ns from \"m1\";" + "\n" + - "import type def, * as ns from \"m2\";" + "\n" + - "import type def from \"m3\";" + "\n" + - "import type {a} from \"m4\";" + "\n" + - "import type {a as A} from \"m5\";" + "\n" + - "import type {a as A, b, c as C} from \"m6\";" + "\n" + - "import type def , {a, b, c as C} from \"m7\";" + "\n" + - "import type from \"m8\";" + "\n" + - "import type T = require(\"m9\");" + "\n" + - "import type = require(\"m10\");" + "\n" + - "export import type T = require(\"m11\");" + "\n" + - "export import type = require(\"m12\");" + "\n", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m1", pos: 25, end: 27 }, - { fileName: "m2", pos: 61, end: 63 }, - { fileName: "m3", pos: 88, end: 90 }, - { fileName: "m4", pos: 115, end: 117 }, - { fileName: "m5", pos: 147, end: 149 }, - { fileName: "m6", pos: 190, end: 192 }, - { fileName: "m7", pos: 234, end: 236 }, - { fileName: "m8", pos: 257, end: 259 }, - { fileName: "m9", pos: 287, end: 289 }, - { fileName: "m10", pos: 316, end: 319 }, - { fileName: "m11", pos: 355, end: 358 }, - { fileName: "m12", pos: 392, end: 395 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'import type * as ns from "m1";' + "\n" + + 'import type def, * as ns from "m2";' + "\n" + + 'import type def from "m3";' + "\n" + + 'import type {a} from "m4";' + "\n" + + 'import type {a as A} from "m5";' + "\n" + + 'import type {a as A, b, c as C} from "m6";' + "\n" + + 'import type def , {a, b, c as C} from "m7";' + "\n" + + 'import type from "m8";' + "\n" + + 'import type T = require("m9");' + "\n" + + 'import type = require("m10");' + "\n" + + 'export import type T = require("m11");' + "\n" + + 'export import type = require("m12");' + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m1", pos: 25, end: 27 }, + { fileName: "m2", pos: 61, end: 63 }, + { fileName: "m3", pos: 88, end: 90 }, + { fileName: "m4", pos: 115, end: 117 }, + { fileName: "m5", pos: 147, end: 149 }, + { fileName: "m6", pos: 190, end: 192 }, + { fileName: "m7", pos: 234, end: 236 }, + { fileName: "m8", pos: 257, end: 259 }, + { fileName: "m9", pos: 287, end: 289 }, + { fileName: "m10", pos: 316, end: 319 }, + { fileName: "m11", pos: 355, end: 358 }, + { fileName: "m12", pos: 392, end: 395 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly handles export types", () => { - test("export type * from \"m1\";" + "\n" + - "export type {a} from \"m2\";" + "\n" + - "export type {a as A} from \"m3\";" + "\n" + - "export type {a as A, b, c as C} from \"m4\";" + "\n", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [] as ts.FileReference[], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m1", pos: 19, end: 21 }, - { fileName: "m2", pos: 46, end: 48 }, - { fileName: "m3", pos: 78, end: 80 }, - { fileName: "m4", pos: 121, end: 123 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'export type * from "m1";' + "\n" + + 'export type {a} from "m2";' + "\n" + + 'export type {a as A} from "m3";' + "\n" + + 'export type {a as A, b, c as C} from "m4";' + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [] as ts.FileReference[], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m1", pos: 19, end: 21 }, + { fileName: "m2", pos: 46, end: 48 }, + { fileName: "m3", pos: 78, end: 80 }, + { fileName: "m4", pos: 121, end: 123 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly handles import type node", () => { - test("const x: import(\"m1\") = { x: 0, y: 0 };" + "\n" + - "let y: import(\"m2\").Bar.I = { a: \"\", b: 0 };" + "\n" + - "let shim: typeof import(\"m3\") = { Bar: Bar2 };" + "\n", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m1", pos: 16, end: 18 }, - { fileName: "m2", pos: 54, end: 56 }, - { fileName: "m3", pos: 109, end: 111 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + 'const x: import("m1") = { x: 0, y: 0 };' + "\n" + + 'let y: import("m2").Bar.I = { a: "", b: 0 };' + "\n" + + 'let shim: typeof import("m3") = { Bar: Bar2 };' + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m1", pos: 16, end: 18 }, + { fileName: "m2", pos: 54, end: 56 }, + { fileName: "m3", pos: 109, end: 111 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly return ambient external modules", () => { - test(` + test( + ` declare module A {} declare module "B" {} function foo() { } `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [], - ambientExternalModules: ["B"], - isLibFile: false - }); - }); - - it("Correctly handles export import declarations", () => { - test("export import a = require(\"m1\");", /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { referencedFiles: [], typeReferenceDirectives: [], libReferenceDirectives: [], - importedFiles: [ - { fileName: "m1", pos: 26, end: 28 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + importedFiles: [], + ambientExternalModules: ["B"], + isLibFile: false, + }, + ); }); - it("Correctly handles export require calls in JavaScript files", () => { - test(` - export import a = require("m1"); - var x = require('m2'); - foo(require('m3')); - var z = { f: require('m4') } - `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { + + it("Correctly handles export import declarations", () => { + test('export import a = require("m1");', /*readImportFile*/ true, /*detectJavaScriptImports*/ false, { referencedFiles: [], typeReferenceDirectives: [], libReferenceDirectives: [], importedFiles: [ - { fileName: "m1", pos: 39, end: 41 }, - { fileName: "m2", pos: 74, end: 76 }, - { fileName: "m3", pos: 105, end: 107 }, - { fileName: "m4", pos: 146, end: 148 }, + { fileName: "m1", pos: 26, end: 28 }, ], ambientExternalModules: undefined, - isLibFile: false + isLibFile: false, }); }); + it("Correctly handles export require calls in JavaScript files", () => { + test( + ` + export import a = require("m1"); + var x = require('m2'); + foo(require('m3')); + var z = { f: require('m4') } + `, + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m1", pos: 39, end: 41 }, + { fileName: "m2", pos: 74, end: 76 }, + { fileName: "m3", pos: 105, end: 107 }, + { fileName: "m4", pos: 146, end: 148 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); + }); it("Correctly handles dependency lists in define([deplist]) calls in JavaScript files", () => { - test(` + test( + ` define(["mod1", "mod2"], (m1, m2) => { }); `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "mod1", pos: 21, end: 25 }, - { fileName: "mod2", pos: 29, end: 33 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 21, end: 25 }, + { fileName: "mod2", pos: 29, end: 33 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly handles dependency lists in define(modName, [deplist]) calls in JavaScript files", () => { - test(` + test( + ` define("mod", ["mod1", "mod2"], (m1, m2) => { }); `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "mod1", pos: 28, end: 32 }, - { fileName: "mod2", pos: 36, end: 40 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 28, end: 32 }, + { fileName: "mod2", pos: 36, end: 40 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("correctly handles augmentations in external modules - 1", () => { - test(` + test( + ` declare module "../Observable" { interface I {} } export {} `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "../Observable", pos: 28, end: 41 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "../Observable", pos: 28, end: 41 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("correctly handles augmentations in external modules - 2", () => { - test(` + test( + ` declare module "../Observable" { interface I {} } import * as x from "m"; `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m", pos: 123, end: 124 }, - { fileName: "../Observable", pos: 28, end: 41 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m", pos: 123, end: 124 }, + { fileName: "../Observable", pos: 28, end: 41 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("correctly handles augmentations in external modules - 3", () => { - test(` + test( + ` declare module "../Observable" { interface I {} } import m = require("m"); `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m", pos: 123, end: 124 }, - { fileName: "../Observable", pos: 28, end: 41 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m", pos: 123, end: 124 }, + { fileName: "../Observable", pos: 28, end: 41 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("correctly handles augmentations in external modules - 4", () => { - test(` + test( + ` declare module "../Observable" { interface I {} } namespace N {} export = N; `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "../Observable", pos: 28, end: 41 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "../Observable", pos: 28, end: 41 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("correctly handles augmentations in external modules - 5", () => { - test(` + test( + ` declare module "../Observable" { interface I {} } namespace N {} export import IN = N; `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "../Observable", pos: 28, end: 41 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "../Observable", pos: 28, end: 41 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("correctly handles augmentations in external modules - 6", () => { - test(` + test( + ` declare module "../Observable" { interface I {} } export let x = 1; `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "../Observable", pos: 28, end: 41 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "../Observable", pos: 28, end: 41 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); - it ("correctly handles augmentations in ambient external modules - 1", () => { - test(` + it("correctly handles augmentations in ambient external modules - 1", () => { + test( + ` declare module "m1" { export * from "m2"; declare module "augmentation" { @@ -698,22 +785,24 @@ describe("unittests:: services:: PreProcessFile:", () => { } } `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m2", pos: 65, end: 67 }, - { fileName: "augmentation", pos: 102, end: 114 } - ], - ambientExternalModules: ["m1"], - isLibFile: false - }); - }); - it ("correctly handles augmentations in ambient external modules - 2", () => { - test(` + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m2", pos: 65, end: 67 }, + { fileName: "augmentation", pos: 102, end: 114 }, + ], + ambientExternalModules: ["m1"], + isLibFile: false, + }, + ); + }); + it("correctly handles augmentations in ambient external modules - 2", () => { + test( + ` namespace M { var x; } import IM = M; declare module "m1" { @@ -723,128 +812,138 @@ describe("unittests:: services:: PreProcessFile:", () => { } } `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "m2", pos: 127, end: 129 }, - { fileName: "augmentation", pos: 164, end: 176 } - ], - ambientExternalModules: ["m1"], - isLibFile: false - }); - }); - it ("correctly recognizes type reference directives", () => { - test(` + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "m2", pos: 127, end: 129 }, + { fileName: "augmentation", pos: 164, end: 176 }, + ], + ambientExternalModules: ["m1"], + isLibFile: false, + }, + ); + }); + it("correctly recognizes type reference directives", () => { + test( + ` /// /// /// /// `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [ - { pos: 34, end: 35, fileName: "a" }, - { pos: 112, end: 114, fileName: "a2" } - ], - typeReferenceDirectives: [ - { pos: 73, end: 75, fileName: "a1" }, - { pos: 152, end: 154, fileName: "a3" } - ], - libReferenceDirectives: [], - importedFiles: [], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [ + { pos: 34, end: 35, fileName: "a" }, + { pos: 112, end: 114, fileName: "a2" }, + ], + typeReferenceDirectives: [ + { pos: 73, end: 75, fileName: "a1" }, + { pos: 152, end: 154, fileName: "a3" }, + ], + libReferenceDirectives: [], + importedFiles: [], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); - it ("correctly recognizes lib reference directives", () => { - test(` + it("correctly recognizes lib reference directives", () => { + test( + ` /// /// /// /// `, - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [ - { pos: 34, end: 35, fileName: "a" }, - { pos: 110, end: 112, fileName: "a2" } - ], - typeReferenceDirectives: [ - ], - libReferenceDirectives: [ - { pos: 71, end: 73, fileName: "a1" }, - { pos: 148, end: 150, fileName: "a3" } - ], - importedFiles: [], - ambientExternalModules: undefined, - isLibFile: false - }); + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [ + { pos: 34, end: 35, fileName: "a" }, + { pos: 110, end: 112, fileName: "a2" }, + ], + typeReferenceDirectives: [], + libReferenceDirectives: [ + { pos: 71, end: 73, fileName: "a1" }, + { pos: 148, end: 150, fileName: "a3" }, + ], + importedFiles: [], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly handles dynamic imports with template literals", () => { - test("const m1 = import('mod1');" + "\n" + - "const m2 = import(`mod2`);" + "\n" + - "Promise.all([import('mod3'), import(`mod4`)]);" + "\n" + - "import(/* webpackChunkName: 'module5' */ `mod5`);" + "\n", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ false, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "mod1", pos: 18, end: 22 }, - { fileName: "mod2", pos: 45, end: 49 }, - { fileName: "mod3", pos: 74, end: 78 }, - { fileName: "mod4", pos: 90, end: 94 }, - { fileName: "mod5", pos: 142, end: 146 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + "const m1 = import('mod1');" + "\n" + + "const m2 = import(`mod2`);" + "\n" + + "Promise.all([import('mod3'), import(`mod4`)]);" + "\n" + + "import(/* webpackChunkName: 'module5' */ `mod5`);" + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ false, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 18, end: 22 }, + { fileName: "mod2", pos: 45, end: 49 }, + { fileName: "mod3", pos: 74, end: 78 }, + { fileName: "mod4", pos: 90, end: 94 }, + { fileName: "mod5", pos: 142, end: 146 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly handles require calls with template literals in JS files", () => { - test("const m1 = require(`mod1`);" + "\n" + - "f(require(`mod2`));" + "\n" + - "const a = { x: require(`mod3`) };" + "\n", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "mod1", pos: 19, end: 23 }, - { fileName: "mod2", pos: 38, end: 42 }, - { fileName: "mod3", pos: 71, end: 75 } - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + "const m1 = require(`mod1`);" + "\n" + + "f(require(`mod2`));" + "\n" + + "const a = { x: require(`mod3`) };" + "\n", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 19, end: 23 }, + { fileName: "mod2", pos: 38, end: 42 }, + { fileName: "mod3", pos: 71, end: 75 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); it("Correctly handles dependency lists in define(modName, [deplist]) calls with template literals in JS files", () => { - test("define(`mod`, [`mod1`, `mod2`], (m1, m2) => {});", - /*readImportFile*/ true, - /*detectJavaScriptImports*/ true, - { - referencedFiles: [], - typeReferenceDirectives: [], - libReferenceDirectives: [], - importedFiles: [ - { fileName: "mod1", pos: 15, end: 19 }, - { fileName: "mod2", pos: 23, end: 27 }, - ], - ambientExternalModules: undefined, - isLibFile: false - }); + test( + "define(`mod`, [`mod1`, `mod2`], (m1, m2) => {});", + /*readImportFile*/ true, + /*detectJavaScriptImports*/ true, + { + referencedFiles: [], + typeReferenceDirectives: [], + libReferenceDirectives: [], + importedFiles: [ + { fileName: "mod1", pos: 15, end: 19 }, + { fileName: "mod2", pos: 23, end: 27 }, + ], + ambientExternalModules: undefined, + isLibFile: false, + }, + ); }); }); }); diff --git a/src/testRunner/unittests/services/textChanges.ts b/src/testRunner/unittests/services/textChanges.ts index 0b45e947a2e55..00b430ce2b176 100644 --- a/src/testRunner/unittests/services/textChanges.ts +++ b/src/testRunner/unittests/services/textChanges.ts @@ -1,6 +1,8 @@ import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; -import { notImplementedHost } from "./extract/helpers"; +import { + notImplementedHost, +} from "./extract/helpers"; // Some tests have trailing whitespace @@ -22,7 +24,11 @@ describe("unittests:: services:: textChanges", () => { const newLineCharacter = ts.getNewLineCharacter(printerOptions); function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): ts.formatting.FormatContext { - return ts.formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...ts.testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : ts.testFormatSettings, notImplementedHost); + return ts.formatting.getFormatContext( + placeOpenBraceOnNewLineForFunctions + ? { ...ts.testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : ts.testFormatSettings, + notImplementedHost, + ); } // validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed. @@ -47,7 +53,13 @@ describe("unittests:: services:: textChanges", () => { } } - function runSingleFileTest(caption: string, placeOpenBraceOnNewLineForFunctions: boolean, text: string, validateNodes: boolean, testBlock: (sourceFile: ts.SourceFile, changeTracker: ts.textChanges.ChangeTracker) => void) { + function runSingleFileTest( + caption: string, + placeOpenBraceOnNewLineForFunctions: boolean, + text: string, + validateNodes: boolean, + testBlock: (sourceFile: ts.SourceFile, changeTracker: ts.textChanges.ChangeTracker) => void, + ) { it(caption, () => { const sourceFile = ts.createSourceFile("source.ts", text, ts.ScriptTarget.ES2015, /*setParentNodes*/ true); const rulesProvider = getRuleProvider(placeOpenBraceOnNewLineForFunctions); @@ -57,7 +69,10 @@ describe("unittests:: services:: textChanges", () => { assert.equal(changes.length, 1); assert.equal(changes[0].fileName, sourceFile.fileName); const modified = ts.textChanges.applyChanges(sourceFile.text, changes[0].textChanges); - Harness.Baseline.runBaseline(`textChanges/${caption}.js`, `===ORIGINAL===${newLineCharacter}${text}${newLineCharacter}===MODIFIED===${newLineCharacter}${modified}`); + Harness.Baseline.runBaseline( + `textChanges/${caption}.js`, + `===ORIGINAL===${newLineCharacter}${text}${newLineCharacter}===MODIFIED===${newLineCharacter}${modified}`, + ); }); } @@ -83,29 +98,38 @@ namespace M } } }`; - runSingleFileTest("extractMethodLike", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - const statements = (findChild("foo", sourceFile) as ts.FunctionDeclaration).body!.statements.slice(1); - const newFunction = ts.factory.createFunctionDeclaration( - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - /*name*/ "bar", - /*typeParameters*/ undefined, - /*parameters*/ ts.emptyArray, - /*type*/ ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - /*body */ ts.factory.createBlock(statements) - ); + runSingleFileTest( + "extractMethodLike", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + const statements = (findChild("foo", sourceFile) as ts.FunctionDeclaration).body!.statements.slice(1); + const newFunction = ts.factory.createFunctionDeclaration( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + /*name*/ "bar", + /*typeParameters*/ undefined, + /*parameters*/ ts.emptyArray, + /*type*/ ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + /*body */ ts.factory.createBlock(statements), + ); - changeTracker.insertNodeBefore(sourceFile, /*before*/findChild("M2", sourceFile), newFunction); + changeTracker.insertNodeBefore(sourceFile, /*before*/ findChild("M2", sourceFile), newFunction); - // replace statements with return statement - const newStatement = ts.factory.createReturnStatement( - ts.factory.createCallExpression( - /*expression*/ newFunction.name!, - /*typeArguments*/ undefined, - /*argumentsArray*/ ts.emptyArray - )); - changeTracker.replaceNodeRange(sourceFile, statements[0], ts.last(statements), newStatement, { suffix: newLineCharacter }); - }); + // replace statements with return statement + const newStatement = ts.factory.createReturnStatement( + ts.factory.createCallExpression( + /*expression*/ newFunction.name!, + /*typeArguments*/ undefined, + /*argumentsArray*/ ts.emptyArray, + ), + ); + changeTracker.replaceNodeRange(sourceFile, statements[0], ts.last(statements), newStatement, { + suffix: newLineCharacter, + }); + }, + ); } { const text = ` @@ -117,9 +141,18 @@ function bar() { return 2; } `; - runSingleFileTest("deleteRange1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteRange(sourceFile, { pos: text.indexOf("function foo"), end: text.indexOf("function bar") }); - }); + runSingleFileTest( + "deleteRange1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteRange(sourceFile, { + pos: text.indexOf("function foo"), + end: text.indexOf("function bar"), + }); + }, + ); } function findVariableStatementContaining(name: string, sourceFile: ts.SourceFile): ts.VariableStatement { return ts.cast(findVariableDeclarationContaining(name, sourceFile).parent.parent, ts.isVariableStatement); @@ -137,21 +170,58 @@ var x = 1; // some comment - 1 var y = 2; // comment 3 var z = 3; // comment 4 `; - runSingleFileTest("deleteNode1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile)); - }); - runSingleFileTest("deleteNode2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNode3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNode4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNode5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findVariableStatementContaining("x", sourceFile)); - }); + runSingleFileTest( + "deleteNode1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNode2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { + leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, + }); + }, + ); + runSingleFileTest( + "deleteNode3", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { + trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, + }); + }, + ); + runSingleFileTest( + "deleteNode4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { + leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, + }); + }, + ); + runSingleFileTest( + "deleteNode5", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findVariableStatementContaining("x", sourceFile)); + }, + ); } { const text = ` @@ -163,29 +233,79 @@ var z = 3; // comment 5 // comment 6 var a = 4; // comment 7 `; - runSingleFileTest("deleteNodeRange1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile)); - }); - runSingleFileTest("deleteNodeRange2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), - { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNodeRange3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), - { trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude }); - }); - runSingleFileTest("deleteNodeRange4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), - { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude }); - }); + runSingleFileTest( + "deleteNodeRange1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + ); + }, + ); + runSingleFileTest( + "deleteNodeRange2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude }, + ); + }, + ); + runSingleFileTest( + "deleteNodeRange3", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + { trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude }, + ); + }, + ); + runSingleFileTest( + "deleteNodeRange4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.deleteNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + { + leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, + }, + ); + }, + ); } function createTestVariableDeclaration(name: string) { - return ts.factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createObjectLiteralExpression([ts.factory.createPropertyAssignment("p1", ts.factory.createNumericLiteral(1))], /*multiLine*/ true)); + return ts.factory.createVariableDeclaration( + name, + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createObjectLiteralExpression([ + ts.factory.createPropertyAssignment("p1", ts.factory.createNumericLiteral(1)), + ], /*multiLine*/ true), + ); } function createTestClass() { return ts.factory.createClassDeclaration( [ - ts.factory.createToken(ts.SyntaxKind.PublicKeyword) + ts.factory.createToken(ts.SyntaxKind.PublicKeyword), ], "class1", /*typeParameters*/ undefined, @@ -193,9 +313,12 @@ var a = 4; // comment 7 ts.factory.createHeritageClause( ts.SyntaxKind.ImplementsKeyword, [ - ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier("interface1"), /*typeArguments*/ undefined) - ] - ) + ts.factory.createExpressionWithTypeArguments( + ts.factory.createIdentifier("interface1"), + /*typeArguments*/ undefined, + ), + ], + ), ], [ ts.factory.createPropertyDeclaration( @@ -203,9 +326,9 @@ var a = 4; // comment 7 "property1", /*questionOrExclamationToken*/ undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), - /*initializer*/ undefined - ) - ] + /*initializer*/ undefined, + ), + ], ); } { @@ -217,17 +340,48 @@ var y = 2; // comment 4 var z = 3; // comment 5 // comment 6 var a = 4; // comment 7`; - runSingleFileTest("replaceRange", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceRange(sourceFile, { pos: text.indexOf("var y"), end: text.indexOf("var a") }, createTestClass(), { suffix: newLineCharacter }); - }); - runSingleFileTest("replaceRangeWithForcedIndentation", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceRange(sourceFile, { pos: text.indexOf("var y"), end: text.indexOf("var a") }, createTestClass(), { suffix: newLineCharacter, indentation: 8, delta: 0 }); - }); + runSingleFileTest( + "replaceRange", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceRange( + sourceFile, + { pos: text.indexOf("var y"), end: text.indexOf("var a") }, + createTestClass(), + { suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceRangeWithForcedIndentation", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceRange( + sourceFile, + { pos: text.indexOf("var y"), end: text.indexOf("var a") }, + createTestClass(), + { suffix: newLineCharacter, indentation: 8, delta: 0 }, + ); + }, + ); - runSingleFileTest("replaceRangeNoLineBreakBefore", /*placeOpenBraceOnNewLineForFunctions*/ true, `const x = 1, y = "2";`, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = createTestVariableDeclaration("z1"); - changeTracker.replaceRange(sourceFile, { pos: sourceFile.text.indexOf("y"), end: sourceFile.text.indexOf(";") }, newNode); - }); + runSingleFileTest( + "replaceRangeNoLineBreakBefore", + /*placeOpenBraceOnNewLineForFunctions*/ true, + `const x = 1, y = "2";`, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = createTestVariableDeclaration("z1"); + changeTracker.replaceRange(sourceFile, { + pos: sourceFile.text.indexOf("y"), + end: sourceFile.text.indexOf(";"), + }, newNode); + }, + ); } { const text = ` @@ -235,10 +389,16 @@ namespace A { const x = 1, y = "2"; } `; - runSingleFileTest("replaceNode1NoLineBreakBefore", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = createTestVariableDeclaration("z1"); - changeTracker.replaceNode(sourceFile, findChild("y", sourceFile), newNode); - }); + runSingleFileTest( + "replaceNode1NoLineBreakBefore", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = createTestVariableDeclaration("z1"); + changeTracker.replaceNode(sourceFile, findChild("y", sourceFile), newNode); + }, + ); } { const text = ` @@ -249,21 +409,86 @@ var y = 2; // comment 4 var z = 3; // comment 5 // comment 6 var a = 4; // comment 7`; - runSingleFileTest("replaceNode1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { suffix: newLineCharacter }); - }); - runSingleFileTest("replaceNode2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, suffix: newLineCharacter, prefix: newLineCharacter }); - }); - runSingleFileTest("replaceNode3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }); - }); - runSingleFileTest("replaceNode4", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude }); - }); - runSingleFileTest("replaceNode5", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNode(sourceFile, findVariableStatementContaining("x", sourceFile), createTestClass(), { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude }); - }); + runSingleFileTest( + "replaceNode1", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + { suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceNode2", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + { + leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, + suffix: newLineCharacter, + prefix: newLineCharacter, + }, + ); + }, + ); + runSingleFileTest( + "replaceNode3", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + { trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceNode4", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + { + leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, + }, + ); + }, + ); + runSingleFileTest( + "replaceNode5", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNode( + sourceFile, + findVariableStatementContaining("x", sourceFile), + createTestClass(), + { + leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, + }, + ); + }, + ); } { const text = ` @@ -274,18 +499,73 @@ var y = 2; // comment 4 var z = 3; // comment 5 // comment 6 var a = 4; // comment 7`; - runSingleFileTest("replaceNodeRange1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { suffix: newLineCharacter }); - }); - runSingleFileTest("replaceNodeRange2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, suffix: newLineCharacter, prefix: newLineCharacter }); - }); - runSingleFileTest("replaceNodeRange3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }); - }); - runSingleFileTest("replaceNodeRange4", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude }); - }); + runSingleFileTest( + "replaceNodeRange1", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + createTestClass(), + { suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceNodeRange2", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + createTestClass(), + { + leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, + suffix: newLineCharacter, + prefix: newLineCharacter, + }, + ); + }, + ); + runSingleFileTest( + "replaceNodeRange3", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + createTestClass(), + { trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter }, + ); + }, + ); + runSingleFileTest( + "replaceNodeRange4", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.replaceNodeRange( + sourceFile, + findVariableStatementContaining("y", sourceFile), + findVariableStatementContaining("z", sourceFile), + createTestClass(), + { + leadingTriviaOption: ts.textChanges.LeadingTriviaOption.Exclude, + trailingTriviaOption: ts.textChanges.TrailingTriviaOption.Exclude, + }, + ); + }, + ); } { const text = ` @@ -296,12 +576,32 @@ var y; // comment 4 var z = 3; // comment 5 // comment 6 var a = 4; // comment 7`; - runSingleFileTest("insertNodeBefore3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeBefore(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass()); - }); - runSingleFileTest("insertNodeAfterVariableDeclaration", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findVariableDeclarationContaining("y", sourceFile), createTestVariableDeclaration("z1")); - }); + runSingleFileTest( + "insertNodeBefore3", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeBefore( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + ); + }, + ); + runSingleFileTest( + "insertNodeAfterVariableDeclaration", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter( + sourceFile, + findVariableDeclarationContaining("y", sourceFile), + createTestVariableDeclaration("z1"), + ); + }, + ); } { const text = ` @@ -314,29 +614,64 @@ namespace M { // comment 6 var a = 4; // comment 7 }`; - runSingleFileTest("insertNodeBefore1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeBefore(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass()); - }); - runSingleFileTest("insertNodeBefore2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeBefore(sourceFile, findChild("M", sourceFile), createTestClass()); - }); - runSingleFileTest("insertNodeAfter1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass()); - }); - runSingleFileTest("insertNodeAfter2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findChild("M", sourceFile), createTestClass()); - }); + runSingleFileTest( + "insertNodeBefore1", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeBefore( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + ); + }, + ); + runSingleFileTest( + "insertNodeBefore2", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeBefore(sourceFile, findChild("M", sourceFile), createTestClass()); + }, + ); + runSingleFileTest( + "insertNodeAfter1", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter( + sourceFile, + findVariableStatementContaining("y", sourceFile), + createTestClass(), + ); + }, + ); + runSingleFileTest( + "insertNodeAfter2", + /*placeOpenBraceOnNewLineForFunctions*/ true, + text, + /*validateNodes*/ true, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter(sourceFile, findChild("M", sourceFile), createTestClass()); + }, + ); } function findConstructor(sourceFile: ts.SourceFile): ts.ConstructorDeclaration { const classDecl = sourceFile.statements[0] as ts.ClassDeclaration; - return ts.find(classDecl.members, (m): m is ts.ConstructorDeclaration => ts.isConstructorDeclaration(m) && !!m.body)!; + return ts.find( + classDecl.members, + (m): m is ts.ConstructorDeclaration => ts.isConstructorDeclaration(m) && !!m.body, + )!; } function createTestSuperCall() { const superCall = ts.factory.createCallExpression( ts.factory.createSuper(), /*typeArguments*/ undefined, - /*argumentsArray*/ ts.emptyArray + /*argumentsArray*/ ts.emptyArray, ); return ts.factory.createExpressionStatement(superCall); } @@ -348,9 +683,19 @@ class A { } } `; - runSingleFileTest("insertNodeAtConstructorStart", /*placeOpenBraceOnNewLineForFunctions*/ false, text1, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAtConstructorStart(sourceFile, findConstructor(sourceFile), createTestSuperCall()); - }); + runSingleFileTest( + "insertNodeAtConstructorStart", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text1, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAtConstructorStart( + sourceFile, + findConstructor(sourceFile), + createTestSuperCall(), + ); + }, + ); const text2 = ` class A { constructor() { @@ -358,9 +703,19 @@ class A { } } `; - runSingleFileTest("insertNodeAfter4", /*placeOpenBraceOnNewLineForFunctions*/ false, text2, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), createTestSuperCall()); - }); + runSingleFileTest( + "insertNodeAfter4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text2, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter( + sourceFile, + findVariableStatementContaining("x", sourceFile), + createTestSuperCall(), + ); + }, + ); const text3 = ` class A { constructor() { @@ -368,33 +723,79 @@ class A { } } `; - runSingleFileTest("insertNodeAtConstructorStart-block with newline", /*placeOpenBraceOnNewLineForFunctions*/ false, text3, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAtConstructorStart(sourceFile, findConstructor(sourceFile), createTestSuperCall()); - }); + runSingleFileTest( + "insertNodeAtConstructorStart-block with newline", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text3, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAtConstructorStart( + sourceFile, + findConstructor(sourceFile), + createTestSuperCall(), + ); + }, + ); } { const text = `var a = 1, b = 2, c = 3;`; - runSingleFileTest("deleteNodeInList1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList3", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = `var a = 1,b = 2,c = 3;`; - runSingleFileTest("deleteNodeInList1_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList2_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList3_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList1_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList2_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList3_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` @@ -403,15 +804,33 @@ namespace M { b = 2, c = 3; }`; - runSingleFileTest("deleteNodeInList4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList6", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList5", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList6", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` @@ -422,45 +841,99 @@ namespace M { // comment 4 c = 3; // comment 5 }`; - runSingleFileTest("deleteNodeInList4_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList5_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList6_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList4_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList5_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList6_1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` function foo(a: number, b: string, c = true) { return 1; }`; - runSingleFileTest("deleteNodeInList7", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList8", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList9", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList7", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList8", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList9", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` function foo(a: number,b: string,c = true) { return 1; }`; - runSingleFileTest("deleteNodeInList10", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList11", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList12", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList10", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList11", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList12", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` @@ -470,100 +943,309 @@ function foo( c = true) { return 1; }`; - runSingleFileTest("deleteNodeInList13", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("a", sourceFile)); - }); - runSingleFileTest("deleteNodeInList14", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("b", sourceFile)); - }); - runSingleFileTest("deleteNodeInList15", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.delete(sourceFile, findChild("c", sourceFile)); - }); + runSingleFileTest( + "deleteNodeInList13", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("a", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList14", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("b", sourceFile)); + }, + ); + runSingleFileTest( + "deleteNodeInList15", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.delete(sourceFile, findChild("c", sourceFile)); + }, + ); } { const text = ` const x = 1, y = 2;`; - runSingleFileTest("insertNodeInListAfter1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); - runSingleFileTest("insertNodeInListAfter2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); + runSingleFileTest( + "insertNodeInListAfter2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("y", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` const /*x*/ x = 1, /*y*/ y = 2;`; - runSingleFileTest("insertNodeInListAfter3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); - runSingleFileTest("insertNodeInListAfter4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter3", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); + runSingleFileTest( + "insertNodeInListAfter4", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("y", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` const x = 1;`; - runSingleFileTest("insertNodeInListAfter5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter5", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` const x = 1, y = 2;`; - runSingleFileTest("insertNodeInListAfter6", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); - runSingleFileTest("insertNodeInListAfter7", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter6", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); + runSingleFileTest( + "insertNodeInListAfter7", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("y", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` const /*x*/ x = 1, /*y*/ y = 2;`; - runSingleFileTest("insertNodeInListAfter8", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); - runSingleFileTest("insertNodeInListAfter9", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), ts.factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, ts.factory.createNumericLiteral(1))); - }); + runSingleFileTest( + "insertNodeInListAfter8", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); + runSingleFileTest( + "insertNodeInListAfter9", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("y", sourceFile), + ts.factory.createVariableDeclaration( + "z", + /*exclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createNumericLiteral(1), + ), + ); + }, + ); } { const text = ` import { x } from "bar"`; - runSingleFileTest("insertNodeInListAfter10", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, ts.factory.createIdentifier("b"), ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter10", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + ts.factory.createIdentifier("b"), + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` import { x // this is x } from "bar"`; - runSingleFileTest("insertNodeInListAfter11", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, ts.factory.createIdentifier("b"), ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter11", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + ts.factory.createIdentifier("b"), + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` import { x } from "bar"`; - runSingleFileTest("insertNodeInListAfter12", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter12", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` import { x // this is x } from "bar"`; - runSingleFileTest("insertNodeInListAfter13", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter13", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` @@ -571,9 +1253,23 @@ import { x0, x } from "bar"`; - runSingleFileTest("insertNodeInListAfter14", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, ts.factory.createIdentifier("b"), ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter14", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + ts.factory.createIdentifier("b"), + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` @@ -581,9 +1277,23 @@ import { x0, x // this is x } from "bar"`; - runSingleFileTest("insertNodeInListAfter15", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, ts.factory.createIdentifier("b"), ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter15", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + ts.factory.createIdentifier("b"), + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` @@ -591,9 +1301,23 @@ import { x0, x } from "bar"`; - runSingleFileTest("insertNodeInListAfter16", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter16", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` @@ -601,30 +1325,73 @@ import { x0, x // this is x } from "bar"`; - runSingleFileTest("insertNodeInListAfter17", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter17", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { const text = ` import { x0, x } from "bar"`; - runSingleFileTest("insertNodeInListAfter18", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, ts.factory.createIdentifier("a"))); - }); + runSingleFileTest( + "insertNodeInListAfter18", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + ts.factory.createIdentifier("a"), + ), + ); + }, + ); } { - const runTest = (name: string, text: string) => runSingleFileTest(name, /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - for (const specifier of ["x3", "x4", "x5"]) { - changeTracker.insertNodeInListAfter(sourceFile, findChild("x2", sourceFile), ts.factory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, ts.factory.createIdentifier(specifier))); - } - }); + const runTest = (name: string, text: string) => + runSingleFileTest( + name, + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + for (const specifier of ["x3", "x4", "x5"]) { + changeTracker.insertNodeInListAfter( + sourceFile, + findChild("x2", sourceFile), + ts.factory.createImportSpecifier( + /*isTypeOnly*/ false, + /*propertyName*/ undefined, + ts.factory.createIdentifier(specifier), + ), + ); + } + }, + ); - const crlfText = "import {\r\nx1,\r\nx2\r\n} from \"bar\";"; + const crlfText = 'import {\r\nx1,\r\nx2\r\n} from "bar";'; runTest("insertNodeInListAfter19", crlfText); - const lfText = "import {\nx1,\nx2\n} from \"bar\";"; + const lfText = 'import {\nx1,\nx2\n} from "bar";'; runTest("insertNodeInListAfter20", lfText); } { @@ -632,17 +1399,30 @@ import { class A { x; }`; - runSingleFileTest("insertNodeAfterMultipleNodes", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNodes = []; - for (let i = 0; i < 11 /*error doesn't occur with fewer nodes*/; ++i) { - newNodes.push( - ts.factory.createPropertyDeclaration(/*modifiers*/ undefined, i + "", /*questionOrExclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)); - } - const insertAfter = findChild("x", sourceFile); - for (const newNode of newNodes) { - changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode); - } - }); + runSingleFileTest( + "insertNodeAfterMultipleNodes", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNodes = []; + for (let i = 0; i < 11 /*error doesn't occur with fewer nodes*/; ++i) { + newNodes.push( + ts.factory.createPropertyDeclaration( + /*modifiers*/ undefined, + i + "", + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined, + ), + ); + } + const insertAfter = findChild("x", sourceFile); + for (const newNode of newNodes) { + changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode); + } + }, + ); } { const text = ` @@ -650,9 +1430,25 @@ class A { x } `; - runSingleFileTest("insertNodeAfterInClass1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), ts.factory.createPropertyDeclaration(/*modifiers*/ undefined, "a", /*questionOrExclamationToken*/ undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), /*initializer*/ undefined)); - }); + runSingleFileTest( + "insertNodeAfterInClass1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createPropertyDeclaration( + /*modifiers*/ undefined, + "a", + /*questionOrExclamationToken*/ undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), + /*initializer*/ undefined, + ), + ); + }, + ); } { const text = ` @@ -660,9 +1456,25 @@ class A { x; } `; - runSingleFileTest("insertNodeAfterInClass2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), ts.factory.createPropertyDeclaration(/*modifiers*/ undefined, "a", /*questionOrExclamationToken*/ undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), /*initializer*/ undefined)); - }); + runSingleFileTest( + "insertNodeAfterInClass2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + changeTracker.insertNodeAfter( + sourceFile, + findChild("x", sourceFile), + ts.factory.createPropertyDeclaration( + /*modifiers*/ undefined, + "a", + /*questionOrExclamationToken*/ undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), + /*initializer*/ undefined, + ), + ); + }, + ); } { const text = ` @@ -671,9 +1483,15 @@ class A { y = 1; } `; - runSingleFileTest("deleteNodeAfterInClass1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findChild("x", sourceFile)); - }); + runSingleFileTest( + "deleteNodeAfterInClass1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findChild("x", sourceFile)); + }, + ); } { const text = ` @@ -682,9 +1500,15 @@ class A { y = 1; } `; - runSingleFileTest("deleteNodeAfterInClass2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - deleteNode(changeTracker, sourceFile, findChild("x", sourceFile)); - }); + runSingleFileTest( + "deleteNodeAfterInClass2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + deleteNode(changeTracker, sourceFile, findChild("x", sourceFile)); + }, + ); } { const text = ` @@ -692,15 +1516,22 @@ class A { x = foo } `; - runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = ts.factory.createPropertyDeclaration( - /*modifiers*/ undefined, - ts.factory.createComputedPropertyName(ts.factory.createNumericLiteral(1)), - /*questionOrExclamationToken*/ undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - /*initializer*/ undefined); - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInClassAfterNodeWithoutSeparator1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = ts.factory.createPropertyDeclaration( + /*modifiers*/ undefined, + ts.factory.createComputedPropertyName(ts.factory.createNumericLiteral(1)), + /*questionOrExclamationToken*/ undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + /*initializer*/ undefined, + ); + changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); + }, + ); } { const text = ` @@ -709,15 +1540,22 @@ class A { } } `; - runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = ts.factory.createPropertyDeclaration( - /*modifiers*/ undefined, - ts.factory.createComputedPropertyName(ts.factory.createNumericLiteral(1)), - /*questionOrExclamationToken*/ undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - /*initializer*/ undefined); - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInClassAfterNodeWithoutSeparator2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = ts.factory.createPropertyDeclaration( + /*modifiers*/ undefined, + ts.factory.createComputedPropertyName(ts.factory.createNumericLiteral(1)), + /*questionOrExclamationToken*/ undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + /*initializer*/ undefined, + ); + changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); + }, + ); } { const text = ` @@ -725,15 +1563,22 @@ interface A { x } `; - runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = ts.factory.createPropertyDeclaration( - /*modifiers*/ undefined, - ts.factory.createComputedPropertyName(ts.factory.createNumericLiteral(1)), - /*questionOrExclamationToken*/ undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - /*initializer*/ undefined); - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInInterfaceAfterNodeWithoutSeparator1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = ts.factory.createPropertyDeclaration( + /*modifiers*/ undefined, + ts.factory.createComputedPropertyName(ts.factory.createNumericLiteral(1)), + /*questionOrExclamationToken*/ undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + /*initializer*/ undefined, + ); + changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); + }, + ); } { const text = ` @@ -741,23 +1586,38 @@ interface A { x() } `; - runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = ts.factory.createPropertyDeclaration( - /*modifiers*/ undefined, - ts.factory.createComputedPropertyName(ts.factory.createNumericLiteral(1)), - /*questionOrExclamationToken*/ undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - /*initializer*/ undefined); - changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInInterfaceAfterNodeWithoutSeparator2", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = ts.factory.createPropertyDeclaration( + /*modifiers*/ undefined, + ts.factory.createComputedPropertyName(ts.factory.createNumericLiteral(1)), + /*questionOrExclamationToken*/ undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + /*initializer*/ undefined, + ); + changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode); + }, + ); } { const text = ` let x = foo `; - runSingleFileTest("insertNodeInStatementListAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { - const newNode = ts.factory.createExpressionStatement(ts.factory.createParenthesizedExpression(ts.factory.createNumericLiteral(1))); - changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), newNode); - }); + runSingleFileTest( + "insertNodeInStatementListAfterNodeWithoutSeparator1", + /*placeOpenBraceOnNewLineForFunctions*/ false, + text, + /*validateNodes*/ false, + (sourceFile, changeTracker) => { + const newNode = ts.factory.createExpressionStatement( + ts.factory.createParenthesizedExpression(ts.factory.createNumericLiteral(1)), + ); + changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), newNode); + }, + ); } }); diff --git a/src/testRunner/unittests/services/transpile.ts b/src/testRunner/unittests/services/transpile.ts index ae05aaa9bcd92..b2d1383030438 100644 --- a/src/testRunner/unittests/services/transpile.ts +++ b/src/testRunner/unittests/services/transpile.ts @@ -2,7 +2,6 @@ import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; describe("unittests:: services:: Transpile", () => { - interface TranspileTestSettings { options?: ts.TranspileOptions; noSetFileName?: boolean; @@ -10,82 +9,102 @@ describe("unittests:: services:: Transpile", () => { } function transpilesCorrectly(nameIn: string, input: string, testSettings: TranspileTestSettings) { - const runOnce = (name: string, testSettings: TranspileTestSettings) => describe(name, () => { - let transpileResult: ts.TranspileOutput; - let oldTranspileResult: string; - let oldTranspileDiagnostics: ts.Diagnostic[]; - - const transpileOptions: ts.TranspileOptions = testSettings.options || {}; - if (!transpileOptions.compilerOptions) { - transpileOptions.compilerOptions = { }; - } - if (transpileOptions.compilerOptions.target === undefined) { - transpileOptions.compilerOptions.target = ts.ScriptTarget.ES3; - } - - if (transpileOptions.compilerOptions.newLine === undefined) { - // use \r\n as default new line - transpileOptions.compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed; - } - - transpileOptions.compilerOptions.sourceMap = true; - - let unitName = transpileOptions.fileName; - if (!unitName) { - unitName = transpileOptions.compilerOptions.jsx ? "file.tsx" : "file.ts"; - if (!testSettings.noSetFileName) { - transpileOptions.fileName = unitName; + const runOnce = (name: string, testSettings: TranspileTestSettings) => + describe(name, () => { + let transpileResult: ts.TranspileOutput; + let oldTranspileResult: string; + let oldTranspileDiagnostics: ts.Diagnostic[]; + + const transpileOptions: ts.TranspileOptions = testSettings.options || {}; + if (!transpileOptions.compilerOptions) { + transpileOptions.compilerOptions = {}; + } + if (transpileOptions.compilerOptions.target === undefined) { + transpileOptions.compilerOptions.target = ts.ScriptTarget.ES3; } - } - - transpileOptions.reportDiagnostics = true; - const justName = "transpile/" + name.replace(/[^a-z0-9\-. ()=]/ig, "") + (transpileOptions.compilerOptions.jsx ? ts.Extension.Tsx : ts.Extension.Ts); - const toBeCompiled = [{ - unitName, - content: input - }]; - const canUseOldTranspile = !transpileOptions.renamedDependencies; + if (transpileOptions.compilerOptions.newLine === undefined) { + // use \r\n as default new line + transpileOptions.compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed; + } - before(() => { - transpileResult = ts.transpileModule(input, transpileOptions); + transpileOptions.compilerOptions.sourceMap = true; - if (canUseOldTranspile) { - oldTranspileDiagnostics = []; - oldTranspileResult = ts.transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, oldTranspileDiagnostics, transpileOptions.moduleName); + let unitName = transpileOptions.fileName; + if (!unitName) { + unitName = transpileOptions.compilerOptions.jsx ? "file.tsx" : "file.ts"; + if (!testSettings.noSetFileName) { + transpileOptions.fileName = unitName; + } } - }); - after(() => { - transpileResult = undefined!; - oldTranspileResult = undefined!; - oldTranspileDiagnostics = undefined!; - }); + transpileOptions.reportDiagnostics = true; + + const justName = "transpile/" + name.replace(/[^a-z0-9\-. ()=]/ig, "") + + (transpileOptions.compilerOptions.jsx ? ts.Extension.Tsx : ts.Extension.Ts); + const toBeCompiled = [{ + unitName, + content: input, + }]; + const canUseOldTranspile = !transpileOptions.renamedDependencies; + + before(() => { + transpileResult = ts.transpileModule(input, transpileOptions); + + if (canUseOldTranspile) { + oldTranspileDiagnostics = []; + oldTranspileResult = ts.transpile( + input, + transpileOptions.compilerOptions, + transpileOptions.fileName, + oldTranspileDiagnostics, + transpileOptions.moduleName, + ); + } + }); - /* eslint-disable no-null/no-null */ - it("Correct errors for " + justName, () => { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"), - transpileResult.diagnostics!.length === 0 ? null : Harness.Compiler.getErrorBaseline(toBeCompiled, transpileResult.diagnostics!)); - }); + after(() => { + transpileResult = undefined!; + oldTranspileResult = undefined!; + oldTranspileDiagnostics = undefined!; + }); - if (canUseOldTranspile) { - it("Correct errors (old transpile) for " + justName, () => { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"), - oldTranspileDiagnostics.length === 0 ? null : Harness.Compiler.getErrorBaseline(toBeCompiled, oldTranspileDiagnostics)); + /* eslint-disable no-null/no-null */ + it("Correct errors for " + justName, () => { + Harness.Baseline.runBaseline( + justName.replace(/\.tsx?$/, ".errors.txt"), + transpileResult.diagnostics!.length === 0 ? null + : Harness.Compiler.getErrorBaseline(toBeCompiled, transpileResult.diagnostics!), + ); }); - } - /* eslint-enable no-null/no-null */ - it("Correct output for " + justName, () => { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ts.Extension.Js), transpileResult.outputText); - }); + if (canUseOldTranspile) { + it("Correct errors (old transpile) for " + justName, () => { + Harness.Baseline.runBaseline( + justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"), + oldTranspileDiagnostics.length === 0 ? null + : Harness.Compiler.getErrorBaseline(toBeCompiled, oldTranspileDiagnostics), + ); + }); + } + /* eslint-enable no-null/no-null */ - if (canUseOldTranspile) { - it("Correct output (old transpile) for " + justName, () => { - Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.js"), oldTranspileResult); + it("Correct output for " + justName, () => { + Harness.Baseline.runBaseline( + justName.replace(/\.tsx?$/, ts.Extension.Js), + transpileResult.outputText, + ); }); - } - }); + + if (canUseOldTranspile) { + it("Correct output (old transpile) for " + justName, () => { + Harness.Baseline.runBaseline( + justName.replace(/\.tsx?$/, ".oldTranspile.js"), + oldTranspileResult, + ); + }); + } + }); if (testSettings.testVerbatimModuleSyntax !== "only") { runOnce(nameIn, testSettings); @@ -97,92 +116,119 @@ describe("unittests:: services:: Transpile", () => { ...testSettings.options, compilerOptions: { ...testSettings.options?.compilerOptions, - verbatimModuleSyntax: true - } - } + verbatimModuleSyntax: true, + }, + }, }); } } transpilesCorrectly("Generates no diagnostics with valid inputs", `var x = 0;`, { options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); - transpilesCorrectly("Generates no diagnostics for missing file references", `/// -var x = 0;`, { - options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: true - }); + transpilesCorrectly( + "Generates no diagnostics for missing file references", + `/// +var x = 0;`, + { + options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, + testVerbatimModuleSyntax: true, + }, + ); transpilesCorrectly("Generates no diagnostics for missing module imports", `import {a} from "module2";`, { options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Generates expected syntactic diagnostics", `a b`, { options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Does not generate semantic diagnostics", `var x: string = 0;`, { options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Generates module output", `var x = 0; export {};`, { - options: { compilerOptions: { module: ts.ModuleKind.AMD } } + options: { compilerOptions: { module: ts.ModuleKind.AMD } }, }); transpilesCorrectly("Uses correct newLine character", `var x = 0;`, { options: { compilerOptions: { module: ts.ModuleKind.CommonJS, newLine: ts.NewLineKind.LineFeed } }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Sets module name", "var x = 1; export {};", { - options: { compilerOptions: { module: ts.ModuleKind.System, newLine: ts.NewLineKind.LineFeed }, moduleName: "NamedModule" } + options: { + compilerOptions: { module: ts.ModuleKind.System, newLine: ts.NewLineKind.LineFeed }, + moduleName: "NamedModule", + }, }); transpilesCorrectly("No extra errors for file without extension", `"use strict";\r\nvar x = 0;`, { options: { compilerOptions: { module: ts.ModuleKind.CommonJS }, fileName: "file" }, - testVerbatimModuleSyntax: true - }); - - transpilesCorrectly("Rename dependencies - System", - `import {foo} from "SomeName";\n` + - `declare function use(a: any);\n` + - `use(foo);`, { - options: { compilerOptions: { module: ts.ModuleKind.System, newLine: ts.NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } } - }); - - transpilesCorrectly("Rename dependencies - AMD", - `import {foo} from "SomeName";\n` + - `declare function use(a: any);\n` + - `use(foo);`, { - options: { compilerOptions: { module: ts.ModuleKind.AMD, newLine: ts.NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } } - }); - - transpilesCorrectly("Rename dependencies - UMD", - `import {foo} from "SomeName";\n` + - `declare function use(a: any);\n` + - `use(foo);`, { - options: { compilerOptions: { module: ts.ModuleKind.UMD, newLine: ts.NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } } - }); - - transpilesCorrectly("Transpile with emit decorators and emit metadata", - `import {db} from './db';\n` + - `function someDecorator(target) {\n` + - ` return target;\n` + - `} \n` + - `@someDecorator\n` + - `class MyClass {\n` + - ` db: db;\n` + - ` constructor(db: db) {\n` + - ` this.db = db;\n` + - ` this.db.doSomething(); \n` + - ` }\n` + - `}\n` + - `export {MyClass}; \n`, { + testVerbatimModuleSyntax: true, + }); + + transpilesCorrectly( + "Rename dependencies - System", + `import {foo} from "SomeName";\n` + + `declare function use(a: any);\n` + + `use(foo);`, + { + options: { + compilerOptions: { module: ts.ModuleKind.System, newLine: ts.NewLineKind.LineFeed }, + renamedDependencies: { SomeName: "SomeOtherName" }, + }, + }, + ); + + transpilesCorrectly( + "Rename dependencies - AMD", + `import {foo} from "SomeName";\n` + + `declare function use(a: any);\n` + + `use(foo);`, + { + options: { + compilerOptions: { module: ts.ModuleKind.AMD, newLine: ts.NewLineKind.LineFeed }, + renamedDependencies: { SomeName: "SomeOtherName" }, + }, + }, + ); + + transpilesCorrectly( + "Rename dependencies - UMD", + `import {foo} from "SomeName";\n` + + `declare function use(a: any);\n` + + `use(foo);`, + { + options: { + compilerOptions: { module: ts.ModuleKind.UMD, newLine: ts.NewLineKind.LineFeed }, + renamedDependencies: { SomeName: "SomeOtherName" }, + }, + }, + ); + + transpilesCorrectly( + "Transpile with emit decorators and emit metadata", + `import {db} from './db';\n` + + `function someDecorator(target) {\n` + + ` return target;\n` + + `} \n` + + `@someDecorator\n` + + `class MyClass {\n` + + ` db: db;\n` + + ` constructor(db: db) {\n` + + ` this.db = db;\n` + + ` this.db.doSomething(); \n` + + ` }\n` + + `}\n` + + `export {MyClass}; \n`, + { options: { compilerOptions: { module: ts.ModuleKind.CommonJS, @@ -191,25 +237,30 @@ var x = 0;`, { emitDecoratorMetadata: true, experimentalDecorators: true, target: ts.ScriptTarget.ES5, - } + }, }, - testVerbatimModuleSyntax: true - }); + testVerbatimModuleSyntax: true, + }, + ); transpilesCorrectly("Supports backslashes in file name", "var x", { - options: { fileName: "a\\b.ts" } + options: { fileName: "a\\b.ts" }, }); transpilesCorrectly("transpile file as 'tsx' if 'jsx' is specified", `var x =
`, { - options: { compilerOptions: { jsx: ts.JsxEmit.React, newLine: ts.NewLineKind.LineFeed } } + options: { compilerOptions: { jsx: ts.JsxEmit.React, newLine: ts.NewLineKind.LineFeed } }, }); transpilesCorrectly("transpile .js files", "const a = 10;", { - options: { compilerOptions: { newLine: ts.NewLineKind.LineFeed, module: ts.ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true } + options: { + compilerOptions: { newLine: ts.NewLineKind.LineFeed, module: ts.ModuleKind.CommonJS }, + fileName: "input.js", + reportDiagnostics: true, + }, }); transpilesCorrectly("Supports urls in file name", "var x", { - options: { fileName: "http://somewhere/directory//directory2/file.ts" } + options: { fileName: "http://somewhere/directory//directory2/file.ts" }, }); transpilesCorrectly("Accepts string as enum values for compile-options", "export const x = 0", { @@ -217,310 +268,368 @@ var x = 0;`, { compilerOptions: { module: "es6" as any as ts.ModuleKind, // Capitalization and spaces ignored - target: " Es6 " as any as ts.ScriptTarget - } - } + target: " Es6 " as any as ts.ScriptTarget, + }, + }, }); transpilesCorrectly("Report an error when compiler-options module-kind is out-of-range", "", { - options: { compilerOptions: { module: 123 as any as ts.ModuleKind } } + options: { compilerOptions: { module: 123 as any as ts.ModuleKind } }, }); transpilesCorrectly("Report an error when compiler-options target-script is out-of-range", "", { - options: { compilerOptions: { module: 123 as any as ts.ModuleKind } } + options: { compilerOptions: { module: 123 as any as ts.ModuleKind } }, }); transpilesCorrectly("Support options with lib values", "const a = 10;", { - options: { compilerOptions: { lib: ["es6", "dom"], module: ts.ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { lib: ["es6", "dom"], module: ts.ModuleKind.CommonJS }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Support options with types values", "const a = 10;", { - options: { compilerOptions: { types: ["jquery", "typescript"], module: ts.ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { types: ["jquery", "typescript"], module: ts.ModuleKind.CommonJS }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'allowJs'", "x;", { options: { compilerOptions: { allowJs: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'allowSyntheticDefaultImports'", "x;", { - options: { compilerOptions: { allowSyntheticDefaultImports: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { allowSyntheticDefaultImports: true }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'allowUnreachableCode'", "x;", { options: { compilerOptions: { allowUnreachableCode: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'allowUnusedLabels'", "x;", { options: { compilerOptions: { allowUnusedLabels: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'alwaysStrict'", "x;", { options: { compilerOptions: { alwaysStrict: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'baseUrl'", "x;", { options: { compilerOptions: { baseUrl: "./folder/baseUrl" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'charset'", "x;", { options: { compilerOptions: { charset: "en-us" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'declaration'", "x;", { options: { compilerOptions: { declaration: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'declarationDir'", "x;", { - options: { compilerOptions: { declarationDir: "out/declarations" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { declarationDir: "out/declarations" }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'emitBOM'", "x;", { options: { compilerOptions: { emitBOM: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'emitDecoratorMetadata'", "x;", { - options: { compilerOptions: { emitDecoratorMetadata: true, experimentalDecorators: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { emitDecoratorMetadata: true, experimentalDecorators: true }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'experimentalDecorators'", "x;", { options: { compilerOptions: { experimentalDecorators: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'forceConsistentCasingInFileNames'", "x;", { - options: { compilerOptions: { forceConsistentCasingInFileNames: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { forceConsistentCasingInFileNames: true }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'isolatedModules'", "x;", { - options: { compilerOptions: { isolatedModules: true }, fileName: "input.js", reportDiagnostics: true } + options: { compilerOptions: { isolatedModules: true }, fileName: "input.js", reportDiagnostics: true }, }); transpilesCorrectly("Does not support setting 'isolatedModules'", "x;", { options: { compilerOptions: { isolatedModules: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: "only" + testVerbatimModuleSyntax: "only", }); transpilesCorrectly("Supports setting 'jsx'", "x;", { options: { compilerOptions: { jsx: 1 }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'lib'", "x;", { options: { compilerOptions: { lib: ["es2015", "dom"] }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'locale'", "x;", { options: { compilerOptions: { locale: "en-us" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'module'", "x;", { options: { compilerOptions: { module: ts.ModuleKind.CommonJS }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'moduleResolution'", "x;", { - options: { compilerOptions: { moduleResolution: ts.ModuleResolutionKind.Node10 }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { moduleResolution: ts.ModuleResolutionKind.Node10 }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'newLine'", "x;", { - options: { compilerOptions: { newLine: ts.NewLineKind.CarriageReturnLineFeed }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { newLine: ts.NewLineKind.CarriageReturnLineFeed }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noEmit'", "x;", { options: { compilerOptions: { noEmit: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noEmitHelpers'", "x;", { options: { compilerOptions: { noEmitHelpers: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noEmitOnError'", "x;", { options: { compilerOptions: { noEmitOnError: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noErrorTruncation'", "x;", { options: { compilerOptions: { noErrorTruncation: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noFallthroughCasesInSwitch'", "x;", { - options: { compilerOptions: { noFallthroughCasesInSwitch: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { noFallthroughCasesInSwitch: true }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noImplicitAny'", "x;", { options: { compilerOptions: { noImplicitAny: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noImplicitReturns'", "x;", { options: { compilerOptions: { noImplicitReturns: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noImplicitThis'", "x;", { options: { compilerOptions: { noImplicitThis: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noImplicitUseStrict'", "x;", { options: { compilerOptions: { noImplicitUseStrict: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noLib'", "x;", { options: { compilerOptions: { noLib: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'noResolve'", "x;", { options: { compilerOptions: { noResolve: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'out'", "x;", { options: { compilerOptions: { out: "./out" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'outDir'", "x;", { options: { compilerOptions: { outDir: "./outDir" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'outFile'", "x;", { options: { compilerOptions: { outFile: "./outFile" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'paths'", "x;", { - options: { compilerOptions: { paths: { "*": ["./generated*"] } }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { paths: { "*": ["./generated*"] } }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'preserveConstEnums'", "x;", { options: { compilerOptions: { preserveConstEnums: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'reactNamespace'", "x;", { options: { compilerOptions: { reactNamespace: "react" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'jsxFactory'", "x;", { options: { compilerOptions: { jsxFactory: "createElement" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'jsxFragmentFactory'", "x;", { - options: { compilerOptions: { jsxFactory: "x", jsxFragmentFactory: "frag" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { jsxFactory: "x", jsxFragmentFactory: "frag" }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'removeComments'", "x;", { options: { compilerOptions: { removeComments: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'rootDir'", "x;", { options: { compilerOptions: { rootDir: "./rootDir" }, fileName: "./rootDir/input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'rootDirs'", "x;", { options: { compilerOptions: { rootDirs: ["./a", "./b"] }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'skipLibCheck'", "x;", { options: { compilerOptions: { skipLibCheck: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'skipDefaultLibCheck'", "x;", { options: { compilerOptions: { skipDefaultLibCheck: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'strictNullChecks'", "x;", { options: { compilerOptions: { strictNullChecks: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'stripInternal'", "x;", { options: { compilerOptions: { stripInternal: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'suppressExcessPropertyErrors'", "x;", { - options: { compilerOptions: { suppressExcessPropertyErrors: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { suppressExcessPropertyErrors: true }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'suppressImplicitAnyIndexErrors'", "x;", { - options: { compilerOptions: { suppressImplicitAnyIndexErrors: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + options: { + compilerOptions: { suppressImplicitAnyIndexErrors: true }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'target'", "x;", { options: { compilerOptions: { target: 2 }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'types'", "x;", { options: { compilerOptions: { types: ["jquery", "jasmine"] }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'typeRoots'", "x;", { options: { compilerOptions: { typeRoots: ["./folder"] }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'incremental'", "x;", { options: { compilerOptions: { incremental: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'composite'", "x;", { options: { compilerOptions: { composite: true }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports setting 'tsbuildinfo'", "x;", { - options: { compilerOptions: { incremental: true, tsBuildInfoFile: "./folder/config.tsbuildinfo" }, fileName: "input.js", reportDiagnostics: true }, - testVerbatimModuleSyntax: true - }); - - transpilesCorrectly("Correctly serialize metadata when transpile with CommonJS option", - `import * as ng from "angular2/core";` + - `declare function foo(...args: any[]);` + - `@foo` + - `export class MyClass1 {` + - ` constructor(private _elementRef: ng.ElementRef){}` + - `}`, { + options: { + compilerOptions: { incremental: true, tsBuildInfoFile: "./folder/config.tsbuildinfo" }, + fileName: "input.js", + reportDiagnostics: true, + }, + testVerbatimModuleSyntax: true, + }); + + transpilesCorrectly( + "Correctly serialize metadata when transpile with CommonJS option", + `import * as ng from "angular2/core";` + + `declare function foo(...args: any[]);` + + `@foo` + + `export class MyClass1 {` + + ` constructor(private _elementRef: ng.ElementRef){}` + + `}`, + { options: { compilerOptions: { target: ts.ScriptTarget.ES5, @@ -528,19 +637,21 @@ var x = 0;`, { moduleResolution: ts.ModuleResolutionKind.Node10, emitDecoratorMetadata: true, experimentalDecorators: true, - } + }, }, - testVerbatimModuleSyntax: true - } + testVerbatimModuleSyntax: true, + }, ); - transpilesCorrectly("Correctly serialize metadata when transpile with System option", - `import * as ng from "angular2/core";` + - `declare function foo(...args: any[]);` + - `@foo` + - `export class MyClass1 {` + - ` constructor(private _elementRef: ng.ElementRef){}` + - `}`, { + transpilesCorrectly( + "Correctly serialize metadata when transpile with System option", + `import * as ng from "angular2/core";` + + `declare function foo(...args: any[]);` + + `@foo` + + `export class MyClass1 {` + + ` constructor(private _elementRef: ng.ElementRef){}` + + `}`, + { options: { compilerOptions: { target: ts.ScriptTarget.ES5, @@ -548,88 +659,110 @@ var x = 0;`, { moduleResolution: ts.ModuleResolutionKind.Node10, emitDecoratorMetadata: true, experimentalDecorators: true, - isolatedModules: true - } - } - } + isolatedModules: true, + }, + }, + }, ); transpilesCorrectly("Supports readonly keyword for arrays", "let x: readonly string[];", { options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Supports 'as const' arrays", `([] as const).forEach(k => console.log(k));`, { options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); transpilesCorrectly("Infer correct file extension", `const fn = (a: T) => a`, { noSetFileName: true, - testVerbatimModuleSyntax: true + testVerbatimModuleSyntax: true, }); - transpilesCorrectly("Export star as ns conflict does not crash", ` + transpilesCorrectly( + "Export star as ns conflict does not crash", + ` var a; export { a as alias }; -export * as alias from './file';`, { - noSetFileName: true, - testVerbatimModuleSyntax: true - }); - - transpilesCorrectly("Elides import equals referenced only by export type", - `import IFoo = Namespace.IFoo;` + - `export type { IFoo };`, { - options: { compilerOptions: { module: ts.ModuleKind.CommonJS } } - } +export * as alias from './file';`, + { + noSetFileName: true, + testVerbatimModuleSyntax: true, + }, ); - transpilesCorrectly("Does not elide import equals referenced only by export type", - `import IFoo = Namespace.IFoo;` + - `export type { IFoo };`, { + transpilesCorrectly( + "Elides import equals referenced only by export type", + `import IFoo = Namespace.IFoo;` + + `export type { IFoo };`, + { options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: "only" - } + }, ); - transpilesCorrectly("Elides import equals referenced only by type only export specifier", - `import IFoo = Namespace.IFoo;` + - `export { type IFoo };`, { - options: { compilerOptions: { module: ts.ModuleKind.CommonJS } } - } + transpilesCorrectly( + "Does not elide import equals referenced only by export type", + `import IFoo = Namespace.IFoo;` + + `export type { IFoo };`, + { + options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, + testVerbatimModuleSyntax: "only", + }, ); - transpilesCorrectly("Does not elide import equals referenced only by type only export specifier", - `import IFoo = Namespace.IFoo;` + - `export { type IFoo };`, { + transpilesCorrectly( + "Elides import equals referenced only by type only export specifier", + `import IFoo = Namespace.IFoo;` + + `export { type IFoo };`, + { options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, - testVerbatimModuleSyntax: "only" - } + }, ); - transpilesCorrectly("Can transpile .ts extensions without error", - `import { foo } from "./foo.ts";`, { - options: { compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext } }, - testVerbatimModuleSyntax: true - } + transpilesCorrectly( + "Does not elide import equals referenced only by type only export specifier", + `import IFoo = Namespace.IFoo;` + + `export { type IFoo };`, + { + options: { compilerOptions: { module: ts.ModuleKind.CommonJS } }, + testVerbatimModuleSyntax: "only", + }, ); - transpilesCorrectly("Ignores `allowImportingTsExtensions` without `noEmit` error", - `import { foo } from "./foo.ts";`, { - options: { compilerOptions: { module: ts.ModuleKind.ESNext, allowImportingTsExtensions: true, target: ts.ScriptTarget.ESNext } }, - testVerbatimModuleSyntax: true - } + transpilesCorrectly("Can transpile .ts extensions without error", `import { foo } from "./foo.ts";`, { + options: { compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext } }, + testVerbatimModuleSyntax: true, + }); + + transpilesCorrectly( + "Ignores `allowImportingTsExtensions` without `noEmit` error", + `import { foo } from "./foo.ts";`, + { + options: { + compilerOptions: { + module: ts.ModuleKind.ESNext, + allowImportingTsExtensions: true, + target: ts.ScriptTarget.ESNext, + }, + }, + testVerbatimModuleSyntax: true, + }, ); - transpilesCorrectly("Preserves exported const merged with type-only import", ` + transpilesCorrectly( + "Preserves exported const merged with type-only import", + ` import fooValue from "./values"; import type {Foo} from "./types"; const Foo: Foo = fooValue as any as Foo; export {Foo}; - `, { - options: { compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext } }, - testVerbatimModuleSyntax: true - }); + `, + { + options: { compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ESNext } }, + testVerbatimModuleSyntax: true, + }, + ); }); diff --git a/src/testRunner/unittests/services/utilities.ts b/src/testRunner/unittests/services/utilities.ts index 72c7a7e61af22..60c5b928a2bf1 100644 --- a/src/testRunner/unittests/services/utilities.ts +++ b/src/testRunner/unittests/services/utilities.ts @@ -3,14 +3,22 @@ import * as ts from "../../_namespaces/ts"; describe("unittests:: services:: utilities", () => { describe("Test findPrecedingMatchingToken,", () => { it("should not infinite loop finding opening brace", () => { - const sourceFile = ts.createSourceFile("file.ts", `/// + const sourceFile = ts.createSourceFile( + "file.ts", + `/// (/** @window => { /** @type {Abcd123} */ const core = window.Abcd.core; -})();`, ts.ScriptTarget.ESNext, /*setParentNodes*/ true); +})();`, + ts.ScriptTarget.ESNext, + /*setParentNodes*/ true, + ); // can't use ts.getTokenAtPosition because it returns back the wrong token - const param = ts.forEachChildRecursively(sourceFile, node => node.kind === ts.SyntaxKind.Parameter ? node : undefined)!; + const param = ts.forEachChildRecursively( + sourceFile, + node => node.kind === ts.SyntaxKind.Parameter ? node : undefined, + )!; const jsDoc = param.getChildren()[0]; const token = jsDoc.getLastToken()!; const result = ts.findPrecedingMatchingToken(token, ts.SyntaxKind.OpenBraceToken, sourceFile); diff --git a/src/testRunner/unittests/transform.ts b/src/testRunner/unittests/transform.ts index aa277bd21f536..5bdbb8efac941 100644 --- a/src/testRunner/unittests/transform.ts +++ b/src/testRunner/unittests/transform.ts @@ -3,7 +3,11 @@ import * as evaluator from "../_namespaces/evaluator"; import * as fakes from "../_namespaces/fakes"; import * as Harness from "../_namespaces/Harness"; import * as ts from "../_namespaces/ts"; -import { NewLineKind, ScriptTarget, transpileModule } from "../_namespaces/ts"; +import { + NewLineKind, + ScriptTarget, + transpileModule, +} from "../_namespaces/ts"; import * as vfs from "../_namespaces/vfs"; describe("unittests:: TransformAPI", () => { @@ -17,8 +21,12 @@ describe("unittests:: TransformAPI", () => { ts.addSyntheticTrailingComment( ts.setTextRange( ts.factory.createVoidZero(), - node), - ts.SyntaxKind.MultiLineCommentTrivia, "undefined")); + node, + ), + ts.SyntaxKind.MultiLineCommentTrivia, + "undefined", + ), + ); } return node; }; @@ -34,7 +42,9 @@ describe("unittests:: TransformAPI", () => { return (file: ts.SourceFile) => ts.visitNode(file, visitor, ts.isSourceFile); } - function replaceIdentifiersNamedOldNameWithNewName(context: ts.TransformationContext) { + function replaceIdentifiersNamedOldNameWithNewName( + context: ts.TransformationContext, + ) { const previousOnSubstituteNode = context.onSubstituteNode; context.enableSubstitution(ts.SyntaxKind.Identifier); context.onSubstituteNode = (hint, node) => { @@ -58,20 +68,26 @@ describe("unittests:: TransformAPI", () => { } function createTaggedTemplateLiteral(): ts.Transformer { - return sourceFile => ts.factory.updateSourceFile(sourceFile, [ - ts.factory.createExpressionStatement( - ts.factory.createTaggedTemplateExpression( - ts.factory.createIdentifier("$tpl"), - /*typeArguments*/ undefined, - ts.factory.createNoSubstitutionTemplateLiteral("foo", "foo"))) - ]); + return sourceFile => + ts.factory.updateSourceFile(sourceFile, [ + ts.factory.createExpressionStatement( + ts.factory.createTaggedTemplateExpression( + ts.factory.createIdentifier("$tpl"), + /*typeArguments*/ undefined, + ts.factory.createNoSubstitutionTemplateLiteral("foo", "foo"), + ), + ), + ]); } function transformSourceFile(sourceText: string, transformers: ts.TransformerFactory[]) { - const transformed = ts.transform(ts.createSourceFile("source.ts", sourceText, ts.ScriptTarget.ES2015), transformers); + const transformed = ts.transform( + ts.createSourceFile("source.ts", sourceText, ts.ScriptTarget.ES2015), + transformers, + ); const printer = ts.createPrinter({ newLine: ts.NewLineKind.CarriageReturnLineFeed }, { onEmitNode: transformed.emitNodeWithNotification, - substituteNode: transformed.substituteNode + substituteNode: transformed.substituteNode, }); const result = printer.printBundle(ts.factory.createBundle(transformed.transformed)); transformed.dispose(); @@ -108,20 +124,22 @@ describe("unittests:: TransformAPI", () => { testBaseline("types", () => { return transformSourceFile(`let a: () => void`, [ - context => file => ts.visitNode(file, function visitor(node: ts.Node): ts.VisitResult { - return ts.visitEachChild(node, visitor, context); - }, ts.isSourceFile) + context => file => + ts.visitNode(file, function visitor(node: ts.Node): ts.VisitResult { + return ts.visitEachChild(node, visitor, context); + }, ts.isSourceFile), ]); }); testBaseline("transformDefiniteAssignmentAssertions", () => { return transformSourceFile(`let a!: () => void`, [ - context => file => ts.visitNode(file, function visitor(node: ts.Node): ts.VisitResult { - if (node.kind === ts.SyntaxKind.VoidKeyword) { - return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword); - } - return ts.visitEachChild(node, visitor, context); - }, ts.isSourceFile) + context => file => + ts.visitNode(file, function visitor(node: ts.Node): ts.VisitResult { + if (node.kind === ts.SyntaxKind.VoidKeyword) { + return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword); + } + return ts.visitEachChild(node, visitor, context); + }, ts.isSourceFile), ]); }); @@ -129,11 +147,11 @@ describe("unittests:: TransformAPI", () => { return ts.transpileModule(`var oldName = undefined;`, { transformers: { before: [replaceUndefinedWithVoid0], - after: [replaceIdentifiersNamedOldNameWithNewName] + after: [replaceIdentifiersNamedOldNameWithNewName], }, compilerOptions: { - newLine: ts.NewLineKind.CarriageReturnLineFeed - } + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }).outputText; }); @@ -144,41 +162,47 @@ describe("unittests:: TransformAPI", () => { }, compilerOptions: { target: ts.ScriptTarget.ES5, - newLine: ts.NewLineKind.CarriageReturnLineFeed - } + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }).outputText; }); testBaseline("issue27854", () => { return ts.transpileModule(`oldName<{ a: string; }>\` ... \`;`, { transformers: { - before: [replaceIdentifiersNamedOldNameWithNewName2] + before: [replaceIdentifiersNamedOldNameWithNewName2], }, compilerOptions: { newLine: ts.NewLineKind.CarriageReturnLineFeed, - target: ts.ScriptTarget.Latest - } + target: ts.ScriptTarget.Latest, + }, }).outputText; }); testBaseline("issue44068", () => { - return transformSourceFile(` + return transformSourceFile( + ` const FirstVar = null; const SecondVar = null; - `, [ - context => file => { - const firstVarName = (file.statements[0] as ts.VariableStatement) - .declarationList.declarations[0].name as ts.Identifier; - const secondVarName = (file.statements[0] as ts.VariableStatement) - .declarationList.declarations[0].name as ts.Identifier; - - return context.factory.updateSourceFile(file, file.statements.concat([ - context.factory.createExpressionStatement( - context.factory.createArrayLiteralExpression([firstVarName, secondVarName]) - ), - ])); - } - ]); + `, + [ + context => file => { + const firstVarName = (file.statements[0] as ts.VariableStatement) + .declarationList.declarations[0].name as ts.Identifier; + const secondVarName = (file.statements[0] as ts.VariableStatement) + .declarationList.declarations[0].name as ts.Identifier; + + return context.factory.updateSourceFile( + file, + file.statements.concat([ + context.factory.createExpressionStatement( + context.factory.createArrayLiteralExpression([firstVarName, secondVarName]), + ), + ]), + ); + }, + ], + ); }); testBaseline("rewrittenNamespace", () => { @@ -188,38 +212,44 @@ describe("unittests:: TransformAPI", () => { }, compilerOptions: { newLine: ts.NewLineKind.CarriageReturnLineFeed, - } + }, }).outputText; }); testBaseline("rewrittenNamespaceFollowingClass", () => { - return ts.transpileModule(` + return ts.transpileModule( + ` class C { foo = 10; static bar = 20 } namespace C { export let x = 10; } - `, { - transformers: { - before: [forceNamespaceRewrite], + `, + { + transformers: { + before: [forceNamespaceRewrite], + }, + compilerOptions: { + target: ts.ScriptTarget.ESNext, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + useDefineForClassFields: false, + }, }, - compilerOptions: { - target: ts.ScriptTarget.ESNext, - newLine: ts.NewLineKind.CarriageReturnLineFeed, - useDefineForClassFields: false, - } - }).outputText; + ).outputText; }); testBaseline("transformTypesInExportDefault", () => { - return ts.transpileModule(` + return ts.transpileModule( + ` export default (foo: string) => { return 1; } - `, { - transformers: { - before: [replaceNumberWith2], + `, + { + transformers: { + before: [replaceNumberWith2], + }, + compilerOptions: { + target: ts.ScriptTarget.ESNext, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ts.ScriptTarget.ESNext, - newLine: ts.NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); testBaseline("synthesizedClassAndNamespaceCombination", () => { @@ -230,7 +260,7 @@ describe("unittests:: TransformAPI", () => { compilerOptions: { target: ts.ScriptTarget.ESNext, newLine: ts.NewLineKind.CarriageReturnLineFeed, - } + }, }).outputText; function replaceWithClassAndNamespace() { @@ -239,9 +269,19 @@ describe("unittests:: TransformAPI", () => { const result = ts.factory.updateSourceFile( sourceFile, ts.factory.createNodeArray([ - ts.factory.createClassDeclaration(/*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, /*members*/ undefined!), // TODO: GH#18217 - ts.factory.createModuleDeclaration(/*modifiers*/ undefined, ts.factory.createIdentifier("Foo"), ts.factory.createModuleBlock([ts.factory.createEmptyStatement()])) - ]) + ts.factory.createClassDeclaration( + /*modifiers*/ undefined, + "Foo", + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + /*members*/ undefined!, + ), // TODO: GH#18217 + ts.factory.createModuleDeclaration( + /*modifiers*/ undefined, + ts.factory.createIdentifier("Foo"), + ts.factory.createModuleBlock([ts.factory.createEmptyStatement()]), + ), + ]), ); return result; }; @@ -271,7 +311,7 @@ describe("unittests:: TransformAPI", () => { compilerOptions: { target: ts.ScriptTarget.ESNext, newLine: ts.NewLineKind.CarriageReturnLineFeed, - } + }, }).outputText; function expandExportStar(context: ts.TransformationContext) { @@ -282,9 +322,18 @@ describe("unittests:: TransformAPI", () => { if (node.kind === ts.SyntaxKind.ExportDeclaration) { const ed = node as ts.Node as ts.ExportDeclaration; const exports = [{ name: "x" }]; - const exportSpecifiers = exports.map(e => ts.factory.createExportSpecifier(/*isTypeOnly*/ false, e.name, e.name)); + const exportSpecifiers = exports.map(e => + ts.factory.createExportSpecifier(/*isTypeOnly*/ false, e.name, e.name) + ); const exportClause = ts.factory.createNamedExports(exportSpecifiers); - const newEd = ts.factory.updateExportDeclaration(ed, ed.modifiers, ed.isTypeOnly, exportClause, ed.moduleSpecifier, ed.assertClause); + const newEd = ts.factory.updateExportDeclaration( + ed, + ed.modifiers, + ed.isTypeOnly, + exportClause, + ed.moduleSpecifier, + ed.assertClause, + ); return newEd as ts.Node as T; } @@ -305,7 +354,7 @@ describe("unittests:: TransformAPI", () => { module: ts.ModuleKind.System, newLine: ts.NewLineKind.CarriageReturnLineFeed, moduleDetection: ts.ModuleDetectionKind.Force, - } + }, }).outputText; function transformAddImportStar(_context: ts.TransformationContext) { @@ -319,10 +368,11 @@ describe("unittests:: TransformAPI", () => { /*importClause*/ ts.factory.createImportClause( /*isTypeOnly*/ false, /*name*/ undefined, - ts.factory.createNamespaceImport(ts.factory.createIdentifier("i0")) + ts.factory.createNamespaceImport(ts.factory.createIdentifier("i0")), ), /*moduleSpecifier*/ ts.factory.createStringLiteral("./comp1"), - /*assertClause*/ undefined); + /*assertClause*/ undefined, + ); return ts.factory.updateSourceFile(sf, [importStar]); } } @@ -338,7 +388,7 @@ describe("unittests:: TransformAPI", () => { target: ScriptTarget.ES5, experimentalDecorators: true, newLine: NewLineKind.CarriageReturnLineFeed, - } + }, }).outputText; function transformAddDecoratedNode(_context: ts.TransformationContext) { @@ -347,9 +397,24 @@ describe("unittests:: TransformAPI", () => { }; function visitNode(sf: ts.SourceFile) { // produce `class Foo { @Bar baz() {} }`; - const classDecl = ts.factory.createClassDeclaration(/*modifiers*/ undefined, "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [ - ts.factory.createMethodDeclaration([ts.factory.createDecorator(ts.factory.createIdentifier("Bar"))], /*asteriskToken*/ undefined, "baz", /*questionToken*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, ts.factory.createBlock([])) - ]); + const classDecl = ts.factory.createClassDeclaration( + /*modifiers*/ undefined, + "Foo", + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [ + ts.factory.createMethodDeclaration( + [ts.factory.createDecorator(ts.factory.createIdentifier("Bar"))], + /*asteriskToken*/ undefined, + "baz", + /*questionToken*/ undefined, + /*typeParameters*/ undefined, + [], + /*type*/ undefined, + ts.factory.createBlock([]), + ), + ], + ); return ts.factory.updateSourceFile(sf, [classDecl]); } } @@ -358,12 +423,12 @@ describe("unittests:: TransformAPI", () => { testBaseline("transformDeclarationFile", () => { return baselineDeclarationTransform(`var oldName = undefined;`, { transformers: { - afterDeclarations: [replaceIdentifiersNamedOldNameWithNewName] + afterDeclarations: [replaceIdentifiersNamedOldNameWithNewName], }, compilerOptions: { newLine: ts.NewLineKind.CarriageReturnLineFeed, - declaration: true - } + declaration: true, + }, }); }); @@ -377,7 +442,7 @@ describe("unittests:: TransformAPI", () => { target: ScriptTarget.ES5, newLine: NewLineKind.CarriageReturnLineFeed, experimentalDecorators: true, - } + }, }).outputText; function transformAddParameterProperty(_context: ts.TransformationContext) { @@ -387,20 +452,42 @@ describe("unittests:: TransformAPI", () => { function visitNode(sf: ts.SourceFile) { // produce `class Foo { constructor(@Dec private x) {} }`; // The decorator is required to trigger ts.ts transformations. - const classDecl = ts.factory.createClassDeclaration([], "Foo", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [ - ts.factory.createConstructorDeclaration(/*modifiers*/ undefined, [ - ts.factory.createParameterDeclaration([ts.factory.createDecorator(ts.factory.createIdentifier("Dec")), ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword)], /*dotDotDotToken*/ undefined, "x")], ts.factory.createBlock([])) - ]); + const classDecl = ts.factory.createClassDeclaration( + [], + "Foo", + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [ + ts.factory.createConstructorDeclaration(/*modifiers*/ undefined, [ + ts.factory.createParameterDeclaration( + [ + ts.factory.createDecorator(ts.factory.createIdentifier("Dec")), + ts.factory.createModifier(ts.SyntaxKind.PrivateKeyword), + ], + /*dotDotDotToken*/ undefined, + "x", + ), + ], ts.factory.createBlock([])), + ], + ); return ts.factory.updateSourceFile(sf, [classDecl]); } } }); function baselineDeclarationTransform(text: string, opts: ts.TranspileOptions) { - const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ true, { documents: [new documents.TextDocument("/.src/index.ts", text)] }); + const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ true, { + documents: [new documents.TextDocument("/.src/index.ts", text)], + }); const host = new fakes.CompilerHost(fs, opts.compilerOptions); const program = ts.createProgram(["/.src/index.ts"], opts.compilerOptions!, host); - program.emit(program.getSourceFile("/.src/index.ts"), (p, s, bom) => host.writeFile(p, s, bom), /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ true, opts.transformers); + program.emit( + program.getSourceFile("/.src/index.ts"), + (p, s, bom) => host.writeFile(p, s, bom), + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ true, + opts.transformers, + ); return fs.readFileSync("/.src/index.d.ts").toString(); } @@ -412,7 +499,13 @@ describe("unittests:: TransformAPI", () => { function rootTransform(node: T): ts.VisitResult { if (nodeFilter(node)) { ts.setEmitFlags(node, ts.EmitFlags.NoLeadingComments); - ts.setSyntheticLeadingComments(node, [{ kind: ts.SyntaxKind.MultiLineCommentTrivia, text: "comment", pos: -1, end: -1, hasTrailingNewLine: true }]); + ts.setSyntheticLeadingComments(node, [{ + kind: ts.SyntaxKind.MultiLineCommentTrivia, + text: "comment", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }]); } return ts.visitEachChild(node, rootTransform, context); } @@ -421,38 +514,45 @@ describe("unittests:: TransformAPI", () => { // https://github.com/Microsoft/TypeScript/issues/24096 testBaseline("transformAddCommentToArrowReturnValue", () => { - return ts.transpileModule(`const foo = () => + return ts.transpileModule( + `const foo = () => void 0 -`, { - transformers: { - before: [addSyntheticComment(ts.isVoidExpression)], +`, + { + transformers: { + before: [addSyntheticComment(ts.isVoidExpression)], + }, + compilerOptions: { + target: ts.ScriptTarget.ES5, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ts.ScriptTarget.ES5, - newLine: ts.NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); // https://github.com/Microsoft/TypeScript/issues/17594 testBaseline("transformAddCommentToExportedVar", () => { - return ts.transpileModule(`export const exportedDirectly = 1; + return ts.transpileModule( + `export const exportedDirectly = 1; const exportedSeparately = 2; export {exportedSeparately}; -`, { - transformers: { - before: [addSyntheticComment(ts.isVariableStatement)], +`, + { + transformers: { + before: [addSyntheticComment(ts.isVariableStatement)], + }, + compilerOptions: { + target: ts.ScriptTarget.ES5, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ts.ScriptTarget.ES5, - newLine: ts.NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); // https://github.com/Microsoft/TypeScript/issues/17594 testBaseline("transformAddCommentToImport", () => { - return ts.transpileModule(` + return ts.transpileModule( + ` // Previous comment on import. import {Value} from 'somewhere'; import * as X from 'somewhere'; @@ -460,20 +560,28 @@ import * as X from 'somewhere'; export { /* specifier comment */ X, Y} from 'somewhere'; export * from 'somewhere'; export {Value}; -`, { - transformers: { - before: [addSyntheticComment(n => ts.isImportDeclaration(n) || ts.isExportDeclaration(n) || ts.isImportSpecifier(n) || ts.isExportSpecifier(n))], +`, + { + transformers: { + before: [ + addSyntheticComment(n => + ts.isImportDeclaration(n) || ts.isExportDeclaration(n) || ts.isImportSpecifier(n) + || ts.isExportSpecifier(n) + ), + ], + }, + compilerOptions: { + target: ts.ScriptTarget.ES5, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ts.ScriptTarget.ES5, - newLine: ts.NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); // https://github.com/Microsoft/TypeScript/issues/17594 testBaseline("transformAddCommentToProperties", () => { - return ts.transpileModule(` + return ts.transpileModule( + ` // class comment. class Clazz { // original comment 1. @@ -483,19 +591,27 @@ class Clazz { // original comment 3. constructor(readonly field = 1) {} } -`, { - transformers: { - before: [addSyntheticComment(n => ts.isPropertyDeclaration(n) || ts.isParameterPropertyDeclaration(n, n.parent) || ts.isClassDeclaration(n) || ts.isConstructorDeclaration(n))], +`, + { + transformers: { + before: [ + addSyntheticComment(n => + ts.isPropertyDeclaration(n) || ts.isParameterPropertyDeclaration(n, n.parent) + || ts.isClassDeclaration(n) || ts.isConstructorDeclaration(n) + ), + ], + }, + compilerOptions: { + target: ts.ScriptTarget.ES2015, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ts.ScriptTarget.ES2015, - newLine: ts.NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); testBaseline("transformAddCommentToNamespace", () => { - return ts.transpileModule(` + return ts.transpileModule( + ` // namespace comment. namespace Foo { export const x = 1; @@ -504,50 +620,64 @@ namespace Foo { namespace Foo { export const y = 1; } -`, { - transformers: { - before: [addSyntheticComment(n => ts.isModuleDeclaration(n))], +`, + { + transformers: { + before: [addSyntheticComment(n => ts.isModuleDeclaration(n))], + }, + compilerOptions: { + target: ts.ScriptTarget.ES2015, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ts.ScriptTarget.ES2015, - newLine: ts.NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); testBaseline("transformUpdateModuleMember", () => { - return ts.transpileModule(` + return ts.transpileModule( + ` module MyModule { const myVariable = 1; function foo(param: string) {} } -`, { - transformers: { - before: [renameVariable], +`, + { + transformers: { + before: [renameVariable], + }, + compilerOptions: { + target: ts.ScriptTarget.ES2015, + newLine: ts.NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ts.ScriptTarget.ES2015, - newLine: ts.NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; function renameVariable(context: ts.TransformationContext) { - return (sourceFile: ts.SourceFile): ts.SourceFile => { - return ts.visitNode(sourceFile, rootTransform, ts.isSourceFile); - }; - function rootTransform(node: T): ts.Node { - if (ts.isVariableDeclaration(node)) { - return ts.factory.updateVariableDeclaration(node, ts.factory.createIdentifier("newName"), /*exclamationToken*/ undefined, /*type*/ undefined, node.initializer); - } - return ts.visitEachChild(node, rootTransform, context); + return (sourceFile: ts.SourceFile): ts.SourceFile => { + return ts.visitNode(sourceFile, rootTransform, ts.isSourceFile); + }; + function rootTransform(node: T): ts.Node { + if (ts.isVariableDeclaration(node)) { + return ts.factory.updateVariableDeclaration( + node, + ts.factory.createIdentifier("newName"), + /*exclamationToken*/ undefined, + /*type*/ undefined, + node.initializer, + ); } + return ts.visitEachChild(node, rootTransform, context); + } } }); // https://github.com/Microsoft/TypeScript/issues/24709 testBaseline("issue24709", () => { const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ true); - const transformed = ts.transform(ts.createSourceFile("source.ts", "class X { echo(x: string) { return x; } }", ts.ScriptTarget.ES3), [transformSourceFile]); + const transformed = ts.transform( + ts.createSourceFile("source.ts", "class X { echo(x: string) { return x; } }", ts.ScriptTarget.ES3), + [transformSourceFile], + ); const transformedSourceFile = transformed.transformed[0]; transformed.dispose(); const host = new fakes.CompilerHost(fs); @@ -555,7 +685,7 @@ module MyModule { const program = ts.createProgram(["source.ts"], { target: ts.ScriptTarget.ES3, module: ts.ModuleKind.None, - noLib: true + noLib: true, }, host); program.emit(transformedSourceFile, (_p, s, b) => host.writeFile("source.js", s, b)); return host.readFile("source.js")!.toString(); @@ -579,7 +709,6 @@ module MyModule { }; return (node: ts.SourceFile) => ts.visitNode(node, visitor, ts.isSourceFile); } - }); testBaselineAndEvaluate("templateSpans", () => { @@ -589,8 +718,8 @@ module MyModule { newLine: ts.NewLineKind.CarriageReturnLineFeed, }, transformers: { - before: [transformSourceFile] - } + before: [transformSourceFile], + }, }).outputText; function transformSourceFile(context: ts.TransformationContext): ts.Transformer { @@ -614,60 +743,82 @@ module MyModule { }; function rootTransform(node: T): ts.Node { if (ts.isClassLike(node)) { - const newMembers = [ts.factory.createPropertyDeclaration([ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)], "newField", /*questionOrExclamationToken*/ undefined, /*type*/ undefined, ts.factory.createStringLiteral("x"))]; - ts.setSyntheticLeadingComments(newMembers[0], [{ kind: ts.SyntaxKind.MultiLineCommentTrivia, text: "comment", pos: -1, end: -1, hasTrailingNewLine: true }]); - return ts.isClassDeclaration(node) ? - ts.factory.updateClassDeclaration( + const newMembers = [ + ts.factory.createPropertyDeclaration( + [ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)], + "newField", + /*questionOrExclamationToken*/ undefined, + /*type*/ undefined, + ts.factory.createStringLiteral("x"), + ), + ]; + ts.setSyntheticLeadingComments(newMembers[0], [{ + kind: ts.SyntaxKind.MultiLineCommentTrivia, + text: "comment", + pos: -1, + end: -1, + hasTrailingNewLine: true, + }]); + return ts.isClassDeclaration(node) + ? ts.factory.updateClassDeclaration( node, node.modifiers, node.name, node.typeParameters, node.heritageClauses, - newMembers) : - ts.factory.updateClassExpression( + newMembers, + ) + : ts.factory.updateClassExpression( node, node.modifiers, node.name, node.typeParameters, node.heritageClauses, - newMembers); + newMembers, + ); } return ts.visitEachChild(node, rootTransform, context); } } testBaseline("transformSyntheticCommentOnStaticFieldInClassDeclaration", () => { - return ts.transpileModule(` + return ts.transpileModule( + ` declare const Decorator: any; @Decorator class MyClass { } -`, { - transformers: { - before: [addStaticFieldWithComment], +`, + { + transformers: { + before: [addStaticFieldWithComment], + }, + compilerOptions: { + target: ScriptTarget.ES2015, + experimentalDecorators: true, + newLine: NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ScriptTarget.ES2015, - experimentalDecorators: true, - newLine: NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); testBaseline("transformSyntheticCommentOnStaticFieldInClassExpression", () => { - return ts.transpileModule(` + return ts.transpileModule( + ` const MyClass = class { }; -`, { - transformers: { - before: [addStaticFieldWithComment], +`, + { + transformers: { + before: [addStaticFieldWithComment], + }, + compilerOptions: { + target: ScriptTarget.ES2015, + experimentalDecorators: true, + newLine: NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - target: ScriptTarget.ES2015, - experimentalDecorators: true, - newLine: NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); testBaseline("jsxExpression", () => { @@ -678,23 +829,25 @@ const MyClass = class { return (node: ts.SourceFile) => ts.visitNode(node, visitor, ts.isSourceFile); } - return ts.transpileModule(` + return ts.transpileModule( + ` function test () { return <> {/* This comment breaks the transformer */} } -`, { - transformers: { - before: [doNothing], +`, + { + transformers: { + before: [doNothing], + }, + compilerOptions: { + jsx: ts.JsxEmit.React, + target: ScriptTarget.ES2015, + experimentalDecorators: true, + newLine: NewLineKind.CarriageReturnLineFeed, + }, }, - compilerOptions: { - jsx: ts.JsxEmit.React, - target: ScriptTarget.ES2015, - experimentalDecorators: true, - newLine: NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + ).outputText; }); }); - diff --git a/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts b/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts index 848b58933edef..a90cfc48c3b0b 100644 --- a/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts +++ b/src/testRunner/unittests/tsbuild/amdModulesWithOut.ts @@ -13,7 +13,7 @@ import { enableStrict, loadProjectFromDisk, removeRest, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => { @@ -34,7 +34,7 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => { function verifyOutFileScenario({ subScenario, modifyFs, - modifyAgainFs + modifyAgainFs, }: VerifyOutFileScenarioInput) { verifyTsc({ scenario: "amdModulesWithOut", @@ -46,13 +46,13 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => { edits: [ { caption: "incremental-declaration-doesnt-change", - edit: fs => appendText(fs, "/src/lib/file1.ts", "console.log(x);") + edit: fs => appendText(fs, "/src/lib/file1.ts", "console.log(x);"), }, ...(modifyAgainFs ? [{ caption: "incremental-headers-change-without-dts-changes", - edit: modifyAgainFs + edit: modifyAgainFs, }] : ts.emptyArray), - ] + ], }); } @@ -79,7 +79,7 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => { addTestPrologue(fs, "/src/app/file3.ts", `"myPrologue"`); addTestPrologue(fs, "/src/app/file4.ts", `"myPrologue2";`); }, - modifyAgainFs: fs => addTestPrologue(fs, "/src/lib/file1.ts", `"myPrologue5"`) + modifyAgainFs: fs => addTestPrologue(fs, "/src/lib/file1.ts", `"myPrologue5"`), }); }); @@ -106,7 +106,7 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => { addRest(fs, "app", "file3"); addSpread(fs, "app", "file4"); }, - modifyAgainFs: fs => removeRest(fs, "lib", "file1") + modifyAgainFs: fs => removeRest(fs, "lib", "file1"), }); }); @@ -118,17 +118,25 @@ describe("unittests:: tsbuild:: outFile:: on amd modules with --out", () => { modifyFs: fs => { addTripleSlashRef(fs, "lib", "file0"); addTripleSlashRef(fs, "app", "file4"); - } + }, }); }); describe("stripInternal", () => { function stripInternalScenario(fs: vfs.FileSystem) { const internal = "/*@internal*/"; - replaceText(fs, "/src/app/tsconfig.json", `"composite": true,`, `"composite": true, -"stripInternal": true,`); + replaceText( + fs, + "/src/app/tsconfig.json", + `"composite": true,`, + `"composite": true, +"stripInternal": true,`, + ); replaceText(fs, "/src/lib/file0.ts", "const", `${internal} const`); - appendText(fs, "/src/lib/file1.ts", ` + appendText( + fs, + "/src/lib/file1.ts", + ` export class normalC { ${internal} constructor() { } ${internal} prop: string; @@ -153,7 +161,8 @@ ${internal} export namespace internalOther.something { export class someClass {} ${internal} export import internalImport = internalNamespace.someClass; ${internal} export type internalType = internalC; ${internal} export const internalConst = 10; -${internal} export enum internalEnum { a, b, c }`); +${internal} export enum internalEnum { a, b, c }`, + ); } // Verify initial + incremental edits @@ -167,7 +176,12 @@ ${internal} export enum internalEnum { a, b, c }`); describe("when the module resolution finds original source file", () => { function modifyFs(fs: vfs.FileSystem) { // Make lib to output to parent dir - replaceText(fs, "/src/lib/tsconfig.json", `"outFile": "module.js"`, `"outFile": "../module.js", "rootDir": "../"`); + replaceText( + fs, + "/src/lib/tsconfig.json", + `"outFile": "module.js"`, + `"outFile": "../module.js", "rootDir": "../"`, + ); // Change reference to file1 module to resolve to lib/file1 replaceText(fs, "/src/app/file3.ts", "file1", "lib/file1"); } diff --git a/src/testRunner/unittests/tsbuild/clean.ts b/src/testRunner/unittests/tsbuild/clean.ts index 6b181ac59b381..e5643f4c39052 100644 --- a/src/testRunner/unittests/tsbuild/clean.ts +++ b/src/testRunner/unittests/tsbuild/clean.ts @@ -1,19 +1,22 @@ import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsbuild - clean", () => { verifyTsc({ scenario: "clean", subScenario: `file name and output name clashing`, commandLineArgs: ["--b", "/src/tsconfig.json", "-clean"], - fs: () => loadProjectFromFiles({ - "/src/index.js": "", - "/src/bar.ts": "", - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { allowJs: true }, + fs: () => + loadProjectFromFiles({ + "/src/index.js": "", + "/src/bar.ts": "", + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { allowJs: true }, + }), }), - }), }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuild/commandLine.ts b/src/testRunner/unittests/tsbuild/commandLine.ts index 6ad3d9a8ac5d9..b962ac9d4df79 100644 --- a/src/testRunner/unittests/tsbuild/commandLine.ts +++ b/src/testRunner/unittests/tsbuild/commandLine.ts @@ -1,5 +1,7 @@ import * as ts from "../../_namespaces/ts"; -import { compilerOptionsToConfigJson } from "../helpers/contents"; +import { + compilerOptionsToConfigJson, +} from "../helpers/contents"; import { noChangeRun, TestTscEdit, @@ -7,7 +9,8 @@ import { } from "../helpers/tsc"; import { appendText, - loadProjectFromFiles, replaceText + loadProjectFromFiles, + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: commandLine::", () => { @@ -16,7 +19,7 @@ describe("unittests:: tsbuild:: commandLine::", () => { return { caption, edit: ts.noop, - commandLineArgs: ["--b", "/src/project", "--verbose", ...options] + commandLineArgs: ["--b", "/src/project", "--verbose", ...options], }; } function noChangeWithSubscenario(caption: string): TestTscEdit { @@ -28,7 +31,7 @@ describe("unittests:: tsbuild:: commandLine::", () => { discrepancyExplanation: () => [ `Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/-/g, "")}`, `Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option composite only`, - ] + ], }; } function withEmitDeclarationOnlyChangeAndDiscrepancyExplanation(caption: string): TestTscEdit { @@ -37,7 +40,7 @@ describe("unittests:: tsbuild:: commandLine::", () => { edit.discrepancyExplanation = () => [ ...discrepancyExplanation(), `Clean build info does not have js section because its fresh build`, - `Incremental build info has js section from old build` + `Incremental build info has js section from old build`, ]; return edit; } @@ -87,7 +90,10 @@ describe("unittests:: tsbuild:: commandLine::", () => { noChangeRun, withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"), noChangeWithSubscenario("should re-emit only dts so they dont contain sourcemap"), - withOptionChangeAndDiscrepancyExplanation("with emitDeclarationOnly should not emit anything", "--emitDeclarationOnly"), + withOptionChangeAndDiscrepancyExplanation( + "with emitDeclarationOnly should not emit anything", + "--emitDeclarationOnly", + ), noChangeRun, localChange(), withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"), @@ -108,7 +114,9 @@ describe("unittests:: tsbuild:: commandLine::", () => { noChangeRun, withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"), noChangeWithSubscenario("should re-emit only dts so they dont contain sourcemap"), - withEmitDeclarationOnlyChangeAndDiscrepancyExplanation("with emitDeclarationOnly should not emit anything"), + withEmitDeclarationOnlyChangeAndDiscrepancyExplanation( + "with emitDeclarationOnly should not emit anything", + ), noChangeRun, localChange(), withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"), @@ -135,7 +143,11 @@ describe("unittests:: tsbuild:: commandLine::", () => { withOptionChange("with sourceMap", "--sourceMap"), noChangeWithSubscenario("emit js files"), withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"), - withOptionChange("with declaration and declarationMap, should not re-emit", "--declaration", "--declarationMap"), + withOptionChange( + "with declaration and declarationMap, should not re-emit", + "--declaration", + "--declarationMap", + ), ], baselinePrograms: true, }); @@ -157,7 +169,11 @@ describe("unittests:: tsbuild:: commandLine::", () => { withOptionChange("with sourceMap", "--sourceMap"), noChangeWithSubscenario("emit js files"), withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"), - withOptionChange("with declaration and declarationMap, should not re-emit", "--declaration", "--declarationMap"), + withOptionChange( + "with declaration and declarationMap, should not re-emit", + "--declaration", + "--declarationMap", + ), ], baselinePrograms: true, }); @@ -177,8 +193,12 @@ describe("unittests:: tsbuild:: commandLine::", () => { references: [{ path: "../../project1/src" }], }), "/src/project2/src/e.ts": `export const e = 10;`, - "/src/project2/src/f.ts": `import { a } from "${options.outFile ? "a" : "../../project1/src/a"}"; export const f = a;`, - "/src/project2/src/g.ts": `import { b } from "${options.outFile ? "b" : "../../project1/src/b"}"; export const g = b;`, + "/src/project2/src/f.ts": `import { a } from "${ + options.outFile ? "a" : "../../project1/src/a" + }"; export const f = a;`, + "/src/project2/src/g.ts": `import { b } from "${ + options.outFile ? "b" : "../../project1/src/b" + }"; export const g = b;`, }); } function verifyWithIncremental(options: ts.CompilerOptions) { @@ -207,7 +227,7 @@ describe("unittests:: tsbuild:: commandLine::", () => { discrepancyExplanation: () => [ `Clean build tsbuildinfo for both projects will have compilerOptions with composite and emitDeclarationOnly`, `Incremental build will detect that it doesnt need to rebuild so tsbuild info for projects is from before which has option composite only`, - ] + ], }, { caption: "js emit with change without emitDeclarationOnly", @@ -256,7 +276,7 @@ describe("unittests:: tsbuild:: commandLine::", () => { discrepancyExplanation: () => [ `Clean build tsbuildinfo for both projects will have compilerOptions with composite and emitDeclarationOnly`, `Incremental build will detect that it doesnt need to rebuild so tsbuild info for projects is from before which has option composite as true but emitDeclrationOnly as false`, - ] + ], }, { caption: "no change run with js emit", @@ -272,13 +292,20 @@ describe("unittests:: tsbuild:: commandLine::", () => { baselinePrograms: true, }); function subScenario(text: string) { - return `${text}${options.composite ? "" : " with declaration and incremental"}${options.outFile ? " with outFile" : ""}`; + return `${text}${options.composite ? "" : " with declaration and incremental"}${ + options.outFile ? " with outFile" : "" + }`; } } verifyWithIncremental({ composite: true }); verifyWithIncremental({ incremental: true, declaration: true }); verifyWithIncremental({ composite: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }); - verifyWithIncremental({ incremental: true, declaration: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }); + verifyWithIncremental({ + incremental: true, + declaration: true, + outFile: "../outFile.js", + module: ts.ModuleKind.AMD, + }); verifyTsc({ scenario: "commandLine", @@ -400,7 +427,13 @@ describe("unittests:: tsbuild:: commandLine::", () => { verifyTsc({ scenario: "commandLine", subScenario: "emitDeclarationOnly false on commandline with declaration with outFile", - fs: () => fs({ declaration: true, emitDeclarationOnly: true, outFile: "../outFile.js", module: ts.ModuleKind.AMD }), + fs: () => + fs({ + declaration: true, + emitDeclarationOnly: true, + outFile: "../outFile.js", + module: ts.ModuleKind.AMD, + }), commandLineArgs: ["--b", "/src/project2/src", "--verbose"], edits: [ noChangeRun, diff --git a/src/testRunner/unittests/tsbuild/configFileErrors.ts b/src/testRunner/unittests/tsbuild/configFileErrors.ts index 63d9c2bb70dd2..57d74d9f34fd1 100644 --- a/src/testRunner/unittests/tsbuild/configFileErrors.ts +++ b/src/testRunner/unittests/tsbuild/configFileErrors.ts @@ -1,4 +1,6 @@ -import { dedent } from "../../_namespaces/Utils"; +import { + dedent, +} from "../../_namespaces/Utils"; import { noChangeRun, verifyTsc, @@ -6,7 +8,8 @@ import { import { appendText, loadProjectFromDisk, - loadProjectFromFiles, replaceText + loadProjectFromFiles, + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: configFileErrors:: when tsconfig extends the missing file", () => { @@ -22,10 +25,11 @@ describe("unittests:: tsbuild:: configFileErrors:: reports syntax errors in conf verifyTsc({ scenario: "configFileErrors", subScenario: "reports syntax errors in config file", - fs: () => loadProjectFromFiles({ - "/src/a.ts": "export function foo() { }", - "/src/b.ts": "export function bar() { }", - "/src/tsconfig.json": dedent` + fs: () => + loadProjectFromFiles({ + "/src/a.ts": "export function foo() { }", + "/src/b.ts": "export function bar() { }", + "/src/tsconfig.json": dedent` { "compilerOptions": { "composite": true, @@ -34,13 +38,19 @@ describe("unittests:: tsbuild:: configFileErrors:: reports syntax errors in conf "a.ts" "b.ts" ] -}` - }), +}`, + }), commandLineArgs: ["--b", "/src/tsconfig.json"], edits: [ { - edit: fs => replaceText(fs, "/src/tsconfig.json", ",", `, - "declaration": true,`), + edit: fs => + replaceText( + fs, + "/src/tsconfig.json", + ",", + `, + "declaration": true,`, + ), caption: "reports syntax errors after change to config file", discrepancyExplanation: () => [ "During incremental build, tsbuildinfo is not emitted, so declaration option is not present", @@ -53,15 +63,16 @@ describe("unittests:: tsbuild:: configFileErrors:: reports syntax errors in conf }, noChangeRun, { - edit: fs => fs.writeFileSync( - "/src/tsconfig.json", - JSON.stringify({ - compilerOptions: { composite: true, declaration: true }, - files: ["a.ts", "b.ts"] - }) - ), - caption: "builds after fixing config file errors" + edit: fs => + fs.writeFileSync( + "/src/tsconfig.json", + JSON.stringify({ + compilerOptions: { composite: true, declaration: true }, + files: ["a.ts", "b.ts"], + }), + ), + caption: "builds after fixing config file errors", }, - ] + ], }); }); diff --git a/src/testRunner/unittests/tsbuild/configFileExtends.ts b/src/testRunner/unittests/tsbuild/configFileExtends.ts index 0344e78889721..ce0ac78d971ae 100644 --- a/src/testRunner/unittests/tsbuild/configFileExtends.ts +++ b/src/testRunner/unittests/tsbuild/configFileExtends.ts @@ -1,7 +1,9 @@ import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsbuild:: configFileExtends:: when tsconfig extends another config", () => { function getConfigExtendsWithIncludeFs() { @@ -9,12 +11,12 @@ describe("unittests:: tsbuild:: configFileExtends:: when tsconfig extends anothe "/src/tsconfig.json": JSON.stringify({ references: [ { path: "./shared/tsconfig.json" }, - { path: "./webpack/tsconfig.json" } + { path: "./webpack/tsconfig.json" }, ], - files: [] + files: [], }), "/src/shared/tsconfig-base.json": JSON.stringify({ - include: ["./typings-base/"] + include: ["./typings-base/"], }), "/src/shared/typings-base/globals.d.ts": `type Unrestricted = any;`, "/src/shared/tsconfig.json": JSON.stringify({ @@ -22,9 +24,9 @@ describe("unittests:: tsbuild:: configFileExtends:: when tsconfig extends anothe compilerOptions: { composite: true, outDir: "../target-tsc-build/", - rootDir: ".." + rootDir: "..", }, - files: ["./index.ts"] + files: ["./index.ts"], }), "/src/shared/index.ts": `export const a: Unrestricted = 1;`, "/src/webpack/tsconfig.json": JSON.stringify({ @@ -32,10 +34,10 @@ describe("unittests:: tsbuild:: configFileExtends:: when tsconfig extends anothe compilerOptions: { composite: true, outDir: "../target-tsc-build/", - rootDir: ".." + rootDir: "..", }, files: ["./index.ts"], - references: [{ path: "../shared/tsconfig.json" }] + references: [{ path: "../shared/tsconfig.json" }], }), "/src/webpack/index.ts": `export const b: Unrestricted = 1;`, }); @@ -52,4 +54,4 @@ describe("unittests:: tsbuild:: configFileExtends:: when tsconfig extends anothe fs: getConfigExtendsWithIncludeFs, commandLineArgs: ["--b", "/src/webpack/tsconfig.json", "--v", "--listFiles"], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts b/src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts index 7936c58b6672e..27fa3377b9780 100644 --- a/src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts +++ b/src/testRunner/unittests/tsbuild/containerOnlyReferenced.ts @@ -4,7 +4,8 @@ import { } from "../helpers/tsc"; import { loadProjectFromDisk, - loadProjectFromFiles, replaceText + loadProjectFromFiles, + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: when containerOnly project is referenced", () => { @@ -13,33 +14,34 @@ describe("unittests:: tsbuild:: when containerOnly project is referenced", () => subScenario: "verify that subsequent builds after initial build doesnt build anything", fs: () => loadProjectFromDisk("tests/projects/containerOnlyReferenced"), commandLineArgs: ["--b", "/src", "--verbose"], - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); verifyTsc({ scenario: "containerOnlyReferenced", subScenario: "when solution is referenced indirectly", - fs: () => loadProjectFromFiles({ - "/src/project1/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true }, - references: [], + fs: () => + loadProjectFromFiles({ + "/src/project1/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + references: [], + }), + "/src/project2/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + references: [], + }), + "/src/project2/src/b.ts": "export const b = 10;", + "/src/project3/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + references: [{ path: "../project1" }, { path: "../project2" }], + }), + "/src/project3/src/c.ts": "export const c = 10;", + "/src/project4/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + references: [{ path: "../project3" }], + }), + "/src/project4/src/d.ts": "export const d = 10;", }), - "/src/project2/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true }, - references: [], - }), - "/src/project2/src/b.ts": "export const b = 10;", - "/src/project3/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true }, - references: [{ path: "../project1", }, { path: "../project2" }], - }), - "/src/project3/src/c.ts": "export const c = 10;", - "/src/project4/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true }, - references: [{ path: "../project3" }] - }), - "/src/project4/src/d.ts": "export const d = 10;", - }), commandLineArgs: ["--b", "/src/project4", "--verbose", "--explainFiles"], edits: [{ caption: "modify project3 file", diff --git a/src/testRunner/unittests/tsbuild/declarationEmit.ts b/src/testRunner/unittests/tsbuild/declarationEmit.ts index 30c28dafd7c6f..acc0e3efadcfc 100644 --- a/src/testRunner/unittests/tsbuild/declarationEmit.ts +++ b/src/testRunner/unittests/tsbuild/declarationEmit.ts @@ -3,7 +3,9 @@ import * as vfs from "../../_namespaces/vfs"; import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsbuild:: declarationEmit", () => { function getFiles(): vfs.FileSet { @@ -11,24 +13,24 @@ describe("unittests:: tsbuild:: declarationEmit", () => { "/src/solution/tsconfig.base.json": JSON.stringify({ compilerOptions: { rootDir: "./", - outDir: "lib" - } + outDir: "lib", + }, }), "/src/solution/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true }, references: [{ path: "./src" }], - include: [] + include: [], }), "/src/solution/src/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true }, references: [{ path: "./subProject" }, { path: "./subProject2" }], - include: [] + include: [], }), "/src/solution/src/subProject/tsconfig.json": JSON.stringify({ extends: "../../tsconfig.base.json", compilerOptions: { composite: true }, references: [{ path: "../common" }], - include: ["./index.ts"] + include: ["./index.ts"], }), "/src/solution/src/subProject/index.ts": Utils.dedent` import { Nominal } from '../common/nominal'; @@ -37,7 +39,7 @@ export type MyNominal = Nominal;`, extends: "../../tsconfig.base.json", compilerOptions: { composite: true }, references: [{ path: "../subProject" }], - include: ["./index.ts"] + include: ["./index.ts"], }), "/src/solution/src/subProject2/index.ts": Utils.dedent` import { MyNominal } from '../subProject/index'; @@ -50,7 +52,7 @@ export function getVar(): keyof typeof variable { "/src/solution/src/common/tsconfig.json": JSON.stringify({ extends: "../../tsconfig.base.json", compilerOptions: { composite: true }, - include: ["./nominal.ts"] + include: ["./nominal.ts"], }), "/src/solution/src/common/nominal.ts": Utils.dedent` /// @@ -65,59 +67,61 @@ declare type MyNominal = T & { scenario: "declarationEmit", subScenario: "when declaration file is referenced through triple slash", fs: () => loadProjectFromFiles(getFiles()), - commandLineArgs: ["--b", "/src/solution/tsconfig.json", "--verbose"] + commandLineArgs: ["--b", "/src/solution/tsconfig.json", "--verbose"], }); verifyTsc({ scenario: "declarationEmit", subScenario: "when declaration file is referenced through triple slash but uses no references", - fs: () => loadProjectFromFiles({ - ...getFiles(), - "/src/solution/tsconfig.json": JSON.stringify({ - extends: "./tsconfig.base.json", - compilerOptions: { composite: true }, - include: ["./src/**/*.ts"] + fs: () => + loadProjectFromFiles({ + ...getFiles(), + "/src/solution/tsconfig.json": JSON.stringify({ + extends: "./tsconfig.base.json", + compilerOptions: { composite: true }, + include: ["./src/**/*.ts"], + }), }), - }), - commandLineArgs: ["--b", "/src/solution/tsconfig.json", "--verbose"] + commandLineArgs: ["--b", "/src/solution/tsconfig.json", "--verbose"], }); verifyTsc({ scenario: "declarationEmit", subScenario: "when declaration file used inferred type from referenced project", - fs: () => loadProjectFromFiles({ - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { - composite: true, - baseUrl: ".", - paths: { "@fluentui/*": ["packages/*/src"] } - } - }), - "/src/packages/pkg1/src/index.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { + composite: true, + baseUrl: ".", + paths: { "@fluentui/*": ["packages/*/src"] }, + }, + }), + "/src/packages/pkg1/src/index.ts": Utils.dedent` export interface IThing { a: string; } export interface IThings { thing1: IThing; }`, - "/src/packages/pkg1/tsconfig.json": JSON.stringify({ - extends: "../../tsconfig", - compilerOptions: { outDir: "lib" }, - include: ["src"] - }), - "/src/packages/pkg2/src/index.ts": Utils.dedent` + "/src/packages/pkg1/tsconfig.json": JSON.stringify({ + extends: "../../tsconfig", + compilerOptions: { outDir: "lib" }, + include: ["src"], + }), + "/src/packages/pkg2/src/index.ts": Utils.dedent` import { IThings } from '@fluentui/pkg1'; export function fn4() { const a: IThings = { thing1: { a: 'b' } }; return a.thing1; }`, - "/src/packages/pkg2/tsconfig.json": JSON.stringify({ - extends: "../../tsconfig", - compilerOptions: { outDir: "lib" }, - include: ["src"], - references: [{ path: "../pkg1" }] + "/src/packages/pkg2/tsconfig.json": JSON.stringify({ + extends: "../../tsconfig", + compilerOptions: { outDir: "lib" }, + include: ["src"], + references: [{ path: "../pkg1" }], + }), }), - }), - commandLineArgs: ["--b", "/src/packages/pkg2/tsconfig.json", "--verbose"] + commandLineArgs: ["--b", "/src/packages/pkg2/tsconfig.json", "--verbose"], }); }); diff --git a/src/testRunner/unittests/tsbuild/demo.ts b/src/testRunner/unittests/tsbuild/demo.ts index c05cff7be93d1..4c1def473bb8e 100644 --- a/src/testRunner/unittests/tsbuild/demo.ts +++ b/src/testRunner/unittests/tsbuild/demo.ts @@ -5,7 +5,7 @@ import { import { loadProjectFromDisk, prependText, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: on demo project", () => { @@ -22,7 +22,7 @@ describe("unittests:: tsbuild:: on demo project", () => { scenario: "demo", subScenario: "in master branch with everything setup correctly and reports no error", fs: () => projFs, - commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"] + commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"], }); verifyTsc({ @@ -30,28 +30,30 @@ describe("unittests:: tsbuild:: on demo project", () => { subScenario: "in circular branch reports the error about it by stopping build", fs: () => projFs, commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"], - modifyFs: fs => replaceText( - fs, - "/src/core/tsconfig.json", - "}", - `}, + modifyFs: fs => + replaceText( + fs, + "/src/core/tsconfig.json", + "}", + `}, "references": [ { "path": "../zoo" } - ]` - ) + ]`, + ), }); verifyTsc({ scenario: "demo", subScenario: "in bad-ref branch reports the error about files not in rootDir at the import location", fs: () => projFs, commandLineArgs: ["--b", "/src/tsconfig.json", "--verbose"], - modifyFs: fs => prependText( - fs, - "/src/core/utilities.ts", - `import * as A from '../animals'; -` - ) + modifyFs: fs => + prependText( + fs, + "/src/core/utilities.ts", + `import * as A from '../animals'; +`, + ), }); }); diff --git a/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts b/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts index 5c4324e80a360..f674ac7a65f82 100644 --- a/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts +++ b/src/testRunner/unittests/tsbuild/emitDeclarationOnly.ts @@ -4,7 +4,7 @@ import { } from "../helpers/tsc"; import { loadProjectFromDisk, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: on project with emitDeclarationOnly set to true", () => { @@ -18,13 +18,15 @@ describe("unittests:: tsbuild:: on project with emitDeclarationOnly set to true" function verifyEmitDeclarationOnly(disableMap?: true) { verifyTsc({ - subScenario: `only dts output in circular import project with emitDeclarationOnly${disableMap ? "" : " and declarationMap"}`, + subScenario: `only dts output in circular import project with emitDeclarationOnly${ + disableMap ? "" : " and declarationMap" + }`, fs: () => projFs, scenario: "emitDeclarationOnly", commandLineArgs: ["--b", "/src", "--verbose"], - modifyFs: disableMap ? - (fs => replaceText(fs, "/src/tsconfig.json", `"declarationMap": true,`, "")) : - undefined, + modifyFs: disableMap + ? (fs => replaceText(fs, "/src/tsconfig.json", `"declarationMap": true,`, "")) + : undefined, edits: [{ caption: "incremental-declaration-changes", edit: fs => replaceText(fs, "/src/src/a.ts", "b: B;", "b: B; foo: any;"), @@ -46,9 +48,14 @@ describe("unittests:: tsbuild:: on project with emitDeclarationOnly set to true" edits: [ { caption: "incremental-declaration-doesnt-change", - edit: fs => replaceText(fs, "/src/src/a.ts", "export interface A {", `class C { } -export interface A {`), - + edit: fs => + replaceText( + fs, + "/src/src/a.ts", + "export interface A {", + `class C { } +export interface A {`, + ), }, { caption: "incremental-declaration-changes", diff --git a/src/testRunner/unittests/tsbuild/emptyFiles.ts b/src/testRunner/unittests/tsbuild/emptyFiles.ts index 0c97fb04c10c8..db36b9f88cd28 100644 --- a/src/testRunner/unittests/tsbuild/emptyFiles.ts +++ b/src/testRunner/unittests/tsbuild/emptyFiles.ts @@ -2,7 +2,9 @@ import * as vfs from "../../_namespaces/vfs"; import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromDisk } from "../helpers/vfs"; +import { + loadProjectFromDisk, +} from "../helpers/vfs"; describe("unittests:: tsbuild - empty files option in tsconfig", () => { let projFs: vfs.FileSystem; diff --git a/src/testRunner/unittests/tsbuild/exitCodeOnBogusFile.ts b/src/testRunner/unittests/tsbuild/exitCodeOnBogusFile.ts index 7bdf03df92d98..1346f4e251400 100644 --- a/src/testRunner/unittests/tsbuild/exitCodeOnBogusFile.ts +++ b/src/testRunner/unittests/tsbuild/exitCodeOnBogusFile.ts @@ -1,7 +1,9 @@ import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; // https://github.com/microsoft/TypeScript/issues/33849 describe("unittests:: tsbuild:: exitCodeOnBogusFile:: test exit code", () => { @@ -9,6 +11,6 @@ describe("unittests:: tsbuild:: exitCodeOnBogusFile:: test exit code", () => { scenario: "exitCodeOnBogusFile", subScenario: `test exit code`, fs: () => loadProjectFromFiles({}), - commandLineArgs: ["-b", "bogus.json"] + commandLineArgs: ["-b", "bogus.json"], }); }); diff --git a/src/testRunner/unittests/tsbuild/extends.ts b/src/testRunner/unittests/tsbuild/extends.ts index 196561d58b00e..8605d1e8fbd43 100644 --- a/src/testRunner/unittests/tsbuild/extends.ts +++ b/src/testRunner/unittests/tsbuild/extends.ts @@ -1,5 +1,9 @@ -import { getSymlinkedExtendsSys } from "../helpers/extends"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + getSymlinkedExtendsSys, +} from "../helpers/extends"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; describe("unittests:: tsbuild:: extends::", () => { verifyTscWatch({ @@ -8,4 +12,4 @@ describe("unittests:: tsbuild:: extends::", () => { sys: getSymlinkedExtendsSys, commandLineArgs: ["-b", "src", "--extendedDiagnostics"], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuild/fileDelete.ts b/src/testRunner/unittests/tsbuild/fileDelete.ts index e8768911cad33..74419f2201d6a 100644 --- a/src/testRunner/unittests/tsbuild/fileDelete.ts +++ b/src/testRunner/unittests/tsbuild/fileDelete.ts @@ -1,12 +1,16 @@ import * as ts from "../../_namespaces/ts"; import { - dedent + dedent, } from "../../_namespaces/Utils"; -import { compilerOptionsToConfigJson } from "../helpers/contents"; +import { + compilerOptionsToConfigJson, +} from "../helpers/contents"; import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsbuild:: fileDelete::", () => { function fs(childOptions: ts.CompilerOptions, mainOptions?: ts.CompilerOptions) { @@ -54,7 +58,7 @@ describe("unittests:: tsbuild:: fileDelete::", () => { discrepancyExplanation: () => [ "Clean build will not have latestChangedDtsFile as there was no emit and emitSignatures as undefined for files", "Incremental will store the past latestChangedDtsFile and emitSignatures", - ] + ], }], }); @@ -62,10 +66,15 @@ describe("unittests:: tsbuild:: fileDelete::", () => { scenario: "fileDelete", subScenario: `detects deleted file with outFile`, commandLineArgs: ["--b", "/src/main/tsconfig.json", "-v", "--traceResolution", "--explainFiles"], - fs: () => fs({ composite: true, outFile: "../childResult.js", module: ts.ModuleKind.AMD }, { composite: true, outFile: "../mainResult.js", module: ts.ModuleKind.AMD }), + fs: () => + fs({ composite: true, outFile: "../childResult.js", module: ts.ModuleKind.AMD }, { + composite: true, + outFile: "../mainResult.js", + module: ts.ModuleKind.AMD, + }), edits: [{ caption: "delete child2 file", - edit: fs => fs.rimrafSync("/src/child/child2.ts") + edit: fs => fs.rimrafSync("/src/child/child2.ts"), }], }); @@ -79,7 +88,7 @@ describe("unittests:: tsbuild:: fileDelete::", () => { edit: fs => { fs.rimrafSync("/src/child/child2.ts"); fs.rimrafSync("/src/child/child2.js"); - } + }, }], }); @@ -93,4 +102,4 @@ describe("unittests:: tsbuild:: fileDelete::", () => { edit: fs => fs.rimrafSync("/src/child/child2.ts"), }], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuild/graphOrdering.ts b/src/testRunner/unittests/tsbuild/graphOrdering.ts index b5fefcf3386a7..4091783f35c36 100644 --- a/src/testRunner/unittests/tsbuild/graphOrdering.ts +++ b/src/testRunner/unittests/tsbuild/graphOrdering.ts @@ -15,7 +15,7 @@ describe("unittests:: tsbuild - graph-ordering", () => { ["H", "I"], ["I", "J"], ["J", "H"], - ["J", "E"] + ["J", "E"], ]; before(() => { @@ -50,7 +50,11 @@ describe("unittests:: tsbuild - graph-ordering", () => { }); function checkGraphOrdering(rootNames: string[], expectedBuildSet: string[], circular?: true) { - const builder = ts.createSolutionBuilder(host!, rootNames.map(getProjectFileName), { dry: true, force: false, verbose: false }); + const builder = ts.createSolutionBuilder(host!, rootNames.map(getProjectFileName), { + dry: true, + force: false, + verbose: false, + }); const buildOrder = builder.getBuildOrder(); assert.equal(ts.isCircularBuildOrder(buildOrder), !!circular); const buildQueue = ts.getBuildOrderFromAnyBuildOrder(buildOrder); @@ -61,7 +65,11 @@ describe("unittests:: tsbuild - graph-ordering", () => { const child = getProjectFileName(dep[0]); if (buildQueue.indexOf(child) < 0) continue; const parent = getProjectFileName(dep[1]); - assert.isAbove(buildQueue.indexOf(child), buildQueue.indexOf(parent), `Expecting child ${child} to be built after parent ${parent}`); + assert.isAbove( + buildQueue.indexOf(child), + buildQueue.indexOf(parent), + `Expecting child ${child} to be built after parent ${parent}`, + ); } } } @@ -73,18 +81,26 @@ describe("unittests:: tsbuild - graph-ordering", () => { function writeProjects(fileSystem: vfs.FileSystem, projectNames: string[], deps: [string, string][]): string[] { const projFileNames: string[] = []; for (const dep of deps) { - if (projectNames.indexOf(dep[0]) < 0) throw new Error(`Invalid dependency - project ${dep[0]} does not exist`); - if (projectNames.indexOf(dep[1]) < 0) throw new Error(`Invalid dependency - project ${dep[1]} does not exist`); + if (projectNames.indexOf(dep[0]) < 0) { + throw new Error(`Invalid dependency - project ${dep[0]} does not exist`); + } + if (projectNames.indexOf(dep[1]) < 0) { + throw new Error(`Invalid dependency - project ${dep[1]} does not exist`); + } } for (const proj of projectNames) { fileSystem.mkdirpSync(`/project/${proj}`); fileSystem.writeFileSync(`/project/${proj}/${proj}.ts`, "export {}"); const configFileName = getProjectFileName(proj); - const configContent = JSON.stringify({ - compilerOptions: { composite: true }, - files: [`./${proj}.ts`], - references: deps.filter(d => d[0] === proj).map(d => ({ path: `../${d[1]}` })) - }, undefined, 2); + const configContent = JSON.stringify( + { + compilerOptions: { composite: true }, + files: [`./${proj}.ts`], + references: deps.filter(d => d[0] === proj).map(d => ({ path: `../${d[1]}` })), + }, + undefined, + 2, + ); fileSystem.writeFileSync(configFileName, configContent); projFileNames.push(configFileName); } diff --git a/src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts b/src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts index 2c120f994aefe..52ac511c51769 100644 --- a/src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts +++ b/src/testRunner/unittests/tsbuild/inferredTypeFromTransitiveModule.ts @@ -5,7 +5,7 @@ import { import { appendText, loadProjectFromDisk, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: inferredTypeFromTransitiveModule::", () => { @@ -43,13 +43,13 @@ describe("unittests:: tsbuild:: inferredTypeFromTransitiveModule::", () => { edits: [ { caption: "incremental-declaration-changes", - edit: changeBarParam + edit: changeBarParam, }, { caption: "incremental-declaration-changes", edit: changeBarParamBack, }, - ] + ], }); verifyTsc({ @@ -59,14 +59,18 @@ describe("unittests:: tsbuild:: inferredTypeFromTransitiveModule::", () => { commandLineArgs: ["--b", "/src", "--verbose"], modifyFs: fs => { changeToIsolatedModules(fs); - appendText(fs, "/src/lazyIndex.ts", ` + appendText( + fs, + "/src/lazyIndex.ts", + ` import { default as bar } from './bar'; -bar("hello");`); +bar("hello");`, + ); }, edits: [ { caption: "incremental-declaration-changes", - edit: changeBarParam + edit: changeBarParam, }, { caption: "incremental-declaration-changes", @@ -74,13 +78,13 @@ bar("hello");`); }, { caption: "incremental-declaration-changes", - edit: changeBarParam + edit: changeBarParam, }, { caption: "Fix Error", - edit: fs => replaceText(fs, "/src/lazyIndex.ts", `bar("hello")`, "bar()") + edit: fs => replaceText(fs, "/src/lazyIndex.ts", `bar("hello")`, "bar()"), }, - ] + ], }); }); diff --git a/src/testRunner/unittests/tsbuild/javascriptProjectEmit.ts b/src/testRunner/unittests/tsbuild/javascriptProjectEmit.ts index d07751ec262d8..0dd59b5a0e800 100644 --- a/src/testRunner/unittests/tsbuild/javascriptProjectEmit.ts +++ b/src/testRunner/unittests/tsbuild/javascriptProjectEmit.ts @@ -1,26 +1,29 @@ import * as Utils from "../../_namespaces/Utils"; -import { symbolLibContent } from "../helpers/contents"; +import { + symbolLibContent, +} from "../helpers/contents"; import { verifyTsc, } from "../helpers/tsc"; import { loadProjectFromFiles, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { verifyTsc({ scenario: "javascriptProjectEmit", subScenario: `loads js-based projects and emits them correctly`, - fs: () => loadProjectFromFiles({ - "/src/common/nominal.js": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/common/nominal.js": Utils.dedent` /** * @template T, Name * @typedef {T & {[Symbol.species]: Name}} Nominal */ module.exports = {}; `, - "/src/common/tsconfig.json": Utils.dedent` + "/src/common/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -28,14 +31,14 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { }, "include": ["nominal.js"] }`, - "/src/sub-project/index.js": Utils.dedent` + "/src/sub-project/index.js": Utils.dedent` import { Nominal } from '../common/nominal'; /** * @typedef {Nominal} MyNominal */ `, - "/src/sub-project/tsconfig.json": Utils.dedent` + "/src/sub-project/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -46,7 +49,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": ["./index.js"] }`, - "/src/sub-project-2/index.js": Utils.dedent` + "/src/sub-project-2/index.js": Utils.dedent` import { MyNominal } from '../sub-project/index'; const variable = { @@ -60,7 +63,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { return 'key'; } `, - "/src/sub-project-2/tsconfig.json": Utils.dedent` + "/src/sub-project-2/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -71,7 +74,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": ["./index.js"] }`, - "/src/tsconfig.json": Utils.dedent` + "/src/tsconfig.json": Utils.dedent` { "compilerOptions": { "composite": true @@ -82,7 +85,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": [] }`, - "/src/tsconfig.base.json": Utils.dedent` + "/src/tsconfig.base.json": Utils.dedent` { "compilerOptions": { "skipLibCheck": true, @@ -93,21 +96,22 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { "declaration": true } }`, - }, symbolLibContent), - commandLineArgs: ["-b", "/src"] + }, symbolLibContent), + commandLineArgs: ["-b", "/src"], }); verifyTsc({ scenario: "javascriptProjectEmit", subScenario: `modifies outfile js projects and concatenates them correctly`, - fs: () => loadProjectFromFiles({ - "/src/common/nominal.js": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/common/nominal.js": Utils.dedent` /** * @template T, Name * @typedef {T & {[Symbol.species]: Name}} Nominal */ `, - "/src/common/tsconfig.json": Utils.dedent` + "/src/common/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -117,13 +121,13 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { }, "include": ["nominal.js"] }`, - "/src/sub-project/index.js": Utils.dedent` + "/src/sub-project/index.js": Utils.dedent` /** * @typedef {Nominal} MyNominal */ const c = /** @type {*} */(null); `, - "/src/sub-project/tsconfig.json": Utils.dedent` + "/src/sub-project/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -137,7 +141,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": ["./index.js"] }`, - "/src/sub-project-2/index.js": Utils.dedent` + "/src/sub-project-2/index.js": Utils.dedent` const variable = { key: /** @type {MyNominal} */('value'), }; @@ -149,7 +153,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { return 'key'; } `, - "/src/sub-project-2/tsconfig.json": Utils.dedent` + "/src/sub-project-2/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -163,7 +167,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": ["./index.js"] }`, - "/src/tsconfig.json": Utils.dedent` + "/src/tsconfig.json": Utils.dedent` { "compilerOptions": { "ignoreDeprecations":"5.0", @@ -176,7 +180,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": [] }`, - "/src/tsconfig.base.json": Utils.dedent` + "/src/tsconfig.base.json": Utils.dedent` { "compilerOptions": { "skipLibCheck": true, @@ -186,27 +190,28 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { "declaration": true } }`, - }, symbolLibContent), + }, symbolLibContent), commandLineArgs: ["-b", "/src"], edits: [{ caption: "incremental-declaration-doesnt-change", - edit: fs => replaceText(fs, "/src/sub-project/index.js", "null", "undefined") - }] + edit: fs => replaceText(fs, "/src/sub-project/index.js", "null", "undefined"), + }], }); verifyTsc({ scenario: "javascriptProjectEmit", subScenario: `loads js-based projects with non-moved json files and emits them correctly`, - fs: () => loadProjectFromFiles({ - "/src/common/obj.json": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/common/obj.json": Utils.dedent` { "val": 42 }`, - "/src/common/index.ts": Utils.dedent` + "/src/common/index.ts": Utils.dedent` import x = require("./obj.json"); export = x; `, - "/src/common/tsconfig.json": Utils.dedent` + "/src/common/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -215,12 +220,12 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { }, "include": ["index.ts", "obj.json"] }`, - "/src/sub-project/index.js": Utils.dedent` + "/src/sub-project/index.js": Utils.dedent` import mod from '../common'; export const m = mod; `, - "/src/sub-project/tsconfig.json": Utils.dedent` + "/src/sub-project/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -231,7 +236,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": ["./index.js"] }`, - "/src/sub-project-2/index.js": Utils.dedent` + "/src/sub-project-2/index.js": Utils.dedent` import { m } from '../sub-project/index'; const variable = { @@ -242,7 +247,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { return variable; } `, - "/src/sub-project-2/tsconfig.json": Utils.dedent` + "/src/sub-project-2/tsconfig.json": Utils.dedent` { "extends": "../tsconfig.base.json", "compilerOptions": { @@ -253,7 +258,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": ["./index.js"] }`, - "/src/tsconfig.json": Utils.dedent` + "/src/tsconfig.json": Utils.dedent` { "compilerOptions": { "composite": true @@ -264,7 +269,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { ], "include": [] }`, - "/src/tsconfig.base.json": Utils.dedent` + "/src/tsconfig.base.json": Utils.dedent` { "compilerOptions": { "skipLibCheck": true, @@ -277,7 +282,7 @@ describe("unittests:: tsbuild:: javascriptProjectEmit::", () => { "declaration": true } }`, - }, symbolLibContent), - commandLineArgs: ["-b", "/src"] + }, symbolLibContent), + commandLineArgs: ["-b", "/src"], }); }); diff --git a/src/testRunner/unittests/tsbuild/lateBoundSymbol.ts b/src/testRunner/unittests/tsbuild/lateBoundSymbol.ts index bee588739366e..3d47aaad0207d 100644 --- a/src/testRunner/unittests/tsbuild/lateBoundSymbol.ts +++ b/src/testRunner/unittests/tsbuild/lateBoundSymbol.ts @@ -4,7 +4,7 @@ import { import { appendText, loadProjectFromDisk, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: lateBoundSymbol:: interface is merged and contains late bound member", () => { @@ -22,6 +22,6 @@ describe("unittests:: tsbuild:: lateBoundSymbol:: interface is merged and contai caption: "incremental-declaration-doesnt-change", edit: fs => appendText(fs, "/src/src/main.ts", "const x = 10;"), }, - ] + ], }); }); diff --git a/src/testRunner/unittests/tsbuild/libraryResolution.ts b/src/testRunner/unittests/tsbuild/libraryResolution.ts index ed854616c3ac2..4fe269a2ea0fc 100644 --- a/src/testRunner/unittests/tsbuild/libraryResolution.ts +++ b/src/testRunner/unittests/tsbuild/libraryResolution.ts @@ -1,5 +1,9 @@ -import { getFsForLibResolution } from "../helpers/libraryResolution"; -import { verifyTsc } from "../helpers/tsc"; +import { + getFsForLibResolution, +} from "../helpers/libraryResolution"; +import { + verifyTsc, +} from "../helpers/tsc"; describe("unittests:: tsbuild:: libraryResolution:: library file resolution", () => { function verify(libRedirection?: true) { diff --git a/src/testRunner/unittests/tsbuild/moduleResolution.ts b/src/testRunner/unittests/tsbuild/moduleResolution.ts index e6e718526c94d..17880c167f8d0 100644 --- a/src/testRunner/unittests/tsbuild/moduleResolution.ts +++ b/src/testRunner/unittests/tsbuild/moduleResolution.ts @@ -4,8 +4,12 @@ import { noChangeOnlyRuns, verifyTsc, } from "../helpers/tsc"; -import { verifyTscWatch } from "../helpers/tscWatch"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; import { createWatchedSystem, libFile, @@ -18,22 +22,22 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio path: `/user/username/projects/myproject/packages/pkg1/index.ts`, content: Utils.dedent` import type { TheNum } from 'pkg2' - export const theNum: TheNum = 42;` + export const theNum: TheNum = 42;`, }, { path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`, content: JSON.stringify({ compilerOptions: { outDir: "build", ...optionsToExtend }, - references: [{ path: "../pkg2" }] - }) + references: [{ path: "../pkg2" }], + }), }, { path: `/user/username/projects/myproject/packages/pkg2/const.ts`, - content: `export type TheNum = 42;` + content: `export type TheNum = 42;`, }, { path: `/user/username/projects/myproject/packages/pkg2/index.ts`, - content: `export type { TheNum } from 'const';` + content: `export type { TheNum } from 'const';`, }, { path: `/user/username/projects/myproject/packages/pkg2/tsconfig.json`, @@ -42,9 +46,9 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio composite: true, outDir: "build", baseUrl: ".", - ...optionsToExtend - } - }) + ...optionsToExtend, + }, + }), }, { path: `/user/username/projects/myproject/packages/pkg2/package.json`, @@ -52,13 +56,13 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio name: "pkg2", version: "1.0.0", main: "build/index.js", - }) + }), }, { path: `/user/username/projects/myproject/node_modules/pkg2`, symLink: `/user/username/projects/myproject/packages/pkg2`, }, - libFile + libFile, ], { currentDirectory: "/user/username/projects/myproject" }); } @@ -71,29 +75,38 @@ describe("unittests:: tsbuild:: moduleResolution:: handles the modules and optio verifyTscWatch({ scenario: "moduleResolution", - subScenario: `resolves specifier in output declaration file from referenced project correctly with preserveSymlinks`, + subScenario: + `resolves specifier in output declaration file from referenced project correctly with preserveSymlinks`, sys: () => sys({ preserveSymlinks: true }), commandLineArgs: ["-b", "packages/pkg1", "--verbose", "--traceResolution"], }); verifyTsc({ scenario: "moduleResolution", - subScenario: `type reference resolution uses correct options for different resolution options referenced project`, - fs: () => loadProjectFromFiles({ - "/src/packages/pkg1_index.ts": `export const theNum: TheNum = "type1";`, - "/src/packages/pkg1.tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true, typeRoots: ["./typeroot1"] }, - files: ["./pkg1_index.ts"] + subScenario: + `type reference resolution uses correct options for different resolution options referenced project`, + fs: () => + loadProjectFromFiles({ + "/src/packages/pkg1_index.ts": `export const theNum: TheNum = "type1";`, + "/src/packages/pkg1.tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true, typeRoots: ["./typeroot1"] }, + files: ["./pkg1_index.ts"], + }), + "/src/packages/typeroot1/sometype/index.d.ts": Utils.dedent`declare type TheNum = "type1";`, + "/src/packages/pkg2_index.ts": `export const theNum: TheNum2 = "type2";`, + "/src/packages/pkg2.tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true, typeRoots: ["./typeroot2"] }, + files: ["./pkg2_index.ts"], + }), + "/src/packages/typeroot2/sometype/index.d.ts": Utils.dedent`declare type TheNum2 = "type2";`, }), - "/src/packages/typeroot1/sometype/index.d.ts": Utils.dedent`declare type TheNum = "type1";`, - "/src/packages/pkg2_index.ts": `export const theNum: TheNum2 = "type2";`, - "/src/packages/pkg2.tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true, typeRoots: ["./typeroot2"] }, - files: ["./pkg2_index.ts"] - }), - "/src/packages/typeroot2/sometype/index.d.ts": Utils.dedent`declare type TheNum2 = "type2";`, - }), - commandLineArgs: ["-b", "/src/packages/pkg1.tsconfig.json", "/src/packages/pkg2.tsconfig.json", "--verbose", "--traceResolution"], + commandLineArgs: [ + "-b", + "/src/packages/pkg1.tsconfig.json", + "/src/packages/pkg2.tsconfig.json", + "--verbose", + "--traceResolution", + ], }); }); @@ -101,30 +114,38 @@ describe("unittests:: tsbuild:: moduleResolution:: impliedNodeFormat differs bet verifyTsc({ scenario: "moduleResolution", subScenario: "impliedNodeFormat differs between projects for shared file", - fs: () => loadProjectFromFiles({ - "/src/projects/a/src/index.ts": "", - "/src/projects/a/tsconfig.json": JSON.stringify({ - compilerOptions: { strict: true } - }), - "/src/projects/b/src/index.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/projects/a/src/index.ts": "", + "/src/projects/a/tsconfig.json": JSON.stringify({ + compilerOptions: { strict: true }, + }), + "/src/projects/b/src/index.ts": Utils.dedent` import pg from "pg"; pg.foo(); `, - "/src/projects/b/tsconfig.json": JSON.stringify({ - compilerOptions: { strict: true, module: "node16" } + "/src/projects/b/tsconfig.json": JSON.stringify({ + compilerOptions: { strict: true, module: "node16" }, + }), + "/src/projects/b/package.json": JSON.stringify({ + name: "b", + type: "module", + }), + "/src/projects/node_modules/@types/pg/index.d.ts": "export function foo(): void;", + "/src/projects/node_modules/@types/pg/package.json": JSON.stringify({ + name: "@types/pg", + types: "index.d.ts", + }), }), - "/src/projects/b/package.json": JSON.stringify({ - name: "b", - type: "module" - }), - "/src/projects/node_modules/@types/pg/index.d.ts": "export function foo(): void;", - "/src/projects/node_modules/@types/pg/package.json": JSON.stringify({ - name: "@types/pg", - types: "index.d.ts", - }), - }), modifyFs: fs => fs.writeFileSync("/lib/lib.es2022.full.d.ts", libFile.content), - commandLineArgs: ["-b", "/src/projects/a", "/src/projects/b", "--verbose", "--traceResolution", "--explainFiles"], - edits: noChangeOnlyRuns + commandLineArgs: [ + "-b", + "/src/projects/a", + "/src/projects/b", + "--verbose", + "--traceResolution", + "--explainFiles", + ], + edits: noChangeOnlyRuns, }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuild/moduleSpecifiers.ts b/src/testRunner/unittests/tsbuild/moduleSpecifiers.ts index b42439f099569..0a872a15f2696 100644 --- a/src/testRunner/unittests/tsbuild/moduleSpecifiers.ts +++ b/src/testRunner/unittests/tsbuild/moduleSpecifiers.ts @@ -1,23 +1,30 @@ import * as Utils from "../../_namespaces/Utils"; -import { symbolLibContent } from "../helpers/contents"; +import { + symbolLibContent, +} from "../helpers/contents"; import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; -import { libFile } from "../helpers/virtualFileSystemWithWatch"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; +import { + libFile, +} from "../helpers/virtualFileSystemWithWatch"; // https://github.com/microsoft/TypeScript/issues/31696 describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers to referenced projects resolve correctly", () => { verifyTsc({ scenario: "moduleSpecifiers", subScenario: `synthesized module specifiers resolve correctly`, - fs: () => loadProjectFromFiles({ - "/src/solution/common/nominal.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/solution/common/nominal.ts": Utils.dedent` export declare type Nominal = T & { [Symbol.species]: Name; }; `, - "/src/solution/common/tsconfig.json": Utils.dedent` + "/src/solution/common/tsconfig.json": Utils.dedent` { "extends": "../../tsconfig.base.json", "compilerOptions": { @@ -25,12 +32,12 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers }, "include": ["nominal.ts"] }`, - "/src/solution/sub-project/index.ts": Utils.dedent` + "/src/solution/sub-project/index.ts": Utils.dedent` import { Nominal } from '../common/nominal'; export type MyNominal = Nominal; `, - "/src/solution/sub-project/tsconfig.json": Utils.dedent` + "/src/solution/sub-project/tsconfig.json": Utils.dedent` { "extends": "../../tsconfig.base.json", "compilerOptions": { @@ -41,7 +48,7 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers ], "include": ["./index.ts"] }`, - "/src/solution/sub-project-2/index.ts": Utils.dedent` + "/src/solution/sub-project-2/index.ts": Utils.dedent` import { MyNominal } from '../sub-project/index'; const variable = { @@ -52,7 +59,7 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers return 'key'; } `, - "/src/solution/sub-project-2/tsconfig.json": Utils.dedent` + "/src/solution/sub-project-2/tsconfig.json": Utils.dedent` { "extends": "../../tsconfig.base.json", "compilerOptions": { @@ -63,7 +70,7 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers ], "include": ["./index.ts"] }`, - "/src/solution/tsconfig.json": Utils.dedent` + "/src/solution/tsconfig.json": Utils.dedent` { "compilerOptions": { "composite": true @@ -74,7 +81,7 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers ], "include": [] }`, - "/src/tsconfig.base.json": Utils.dedent` + "/src/tsconfig.base.json": Utils.dedent` { "compilerOptions": { "skipLibCheck": true, @@ -82,7 +89,7 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers "outDir": "lib", } }`, - "/src/tsconfig.json": Utils.dedent`{ + "/src/tsconfig.json": Utils.dedent`{ "compilerOptions": { "composite": true }, @@ -90,9 +97,9 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers { "path": "./solution" } ], "include": [] - }` - }, symbolLibContent), - commandLineArgs: ["-b", "/src", "--verbose"] + }`, + }, symbolLibContent), + commandLineArgs: ["-b", "/src", "--verbose"], }); }); @@ -101,25 +108,26 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers verifyTsc({ scenario: "moduleSpecifiers", subScenario: `synthesized module specifiers across projects resolve correctly`, - fs: () => loadProjectFromFiles({ - "/src/src-types/index.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/src-types/index.ts": Utils.dedent` export * from './dogconfig.js';`, - "/src/src-types/dogconfig.ts": Utils.dedent` + "/src/src-types/dogconfig.ts": Utils.dedent` export interface DogConfig { name: string; }`, - "/src/src-dogs/index.ts": Utils.dedent` + "/src/src-dogs/index.ts": Utils.dedent` export * from 'src-types'; export * from './lassie/lassiedog.js'; `, - "/src/src-dogs/dogconfig.ts": Utils.dedent` + "/src/src-dogs/dogconfig.ts": Utils.dedent` import { DogConfig } from 'src-types'; export const DOG_CONFIG: DogConfig = { name: 'Default dog', }; `, - "/src/src-dogs/dog.ts": Utils.dedent` + "/src/src-dogs/dog.ts": Utils.dedent` import { DogConfig } from 'src-types'; import { DOG_CONFIG } from './dogconfig.js'; @@ -130,7 +138,7 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers } } `, - "/src/src-dogs/lassie/lassiedog.ts": Utils.dedent` + "/src/src-dogs/lassie/lassiedog.ts": Utils.dedent` import { Dog } from '../dog.js'; import { LASSIE_CONFIG } from './lassieconfig.js'; @@ -138,29 +146,29 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers protected static getDogConfig = () => LASSIE_CONFIG; } `, - "/src/src-dogs/lassie/lassieconfig.ts": Utils.dedent` + "/src/src-dogs/lassie/lassieconfig.ts": Utils.dedent` import { DogConfig } from 'src-types'; export const LASSIE_CONFIG: DogConfig = { name: 'Lassie' }; `, - "/src/tsconfig-base.json": Utils.dedent` + "/src/tsconfig-base.json": Utils.dedent` { "compilerOptions": { "declaration": true, "module": "node16" } }`, - "/src/src-types/package.json": Utils.dedent` + "/src/src-types/package.json": Utils.dedent` { "type": "module", "exports": "./index.js" }`, - "/src/src-dogs/package.json": Utils.dedent` + "/src/src-dogs/package.json": Utils.dedent` { "type": "module", "exports": "./index.js" }`, - "/src/src-types/tsconfig.json": Utils.dedent` + "/src/src-types/tsconfig.json": Utils.dedent` { "extends": "../tsconfig-base.json", "compilerOptions": { @@ -170,7 +178,7 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers "**/*" ] }`, - "/src/src-dogs/tsconfig.json": Utils.dedent` + "/src/src-dogs/tsconfig.json": Utils.dedent` { "extends": "../tsconfig-base.json", "compilerOptions": { @@ -183,12 +191,12 @@ describe("unittests:: tsbuild:: moduleSpecifiers:: synthesized module specifiers "**/*" ] }`, - }, ""), + }, ""), modifyFs: fs => { fs.writeFileSync("/lib/lib.es2022.full.d.ts", libFile.content); fs.symlinkSync("/src", "/src/src-types/node_modules"); fs.symlinkSync("/src", "/src/src-dogs/node_modules"); }, - commandLineArgs: ["-b", "src/src-types", "src/src-dogs", "--verbose"] + commandLineArgs: ["-b", "src/src-types", "src/src-dogs", "--verbose"], }); }); diff --git a/src/testRunner/unittests/tsbuild/noEmit.ts b/src/testRunner/unittests/tsbuild/noEmit.ts index 3f0e6f278d949..e574221b21517 100644 --- a/src/testRunner/unittests/tsbuild/noEmit.ts +++ b/src/testRunner/unittests/tsbuild/noEmit.ts @@ -2,19 +2,22 @@ import { noChangeRun, verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsbuild:: noEmit", () => { function verifyNoEmitWorker(subScenario: string, aTsContent: string, commandLineArgs: readonly string[]) { verifyTsc({ scenario: "noEmit", subScenario, - fs: () => loadProjectFromFiles({ - "/src/a.ts": aTsContent, - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { noEmit: true } - }) - }), + fs: () => + loadProjectFromFiles({ + "/src/a.ts": aTsContent, + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { noEmit: true }, + }), + }), commandLineArgs, edits: [ noChangeRun, @@ -30,9 +33,14 @@ describe("unittests:: tsbuild:: noEmit", () => { function verifyNoEmit(subScenario: string, aTsContent: string) { verifyNoEmitWorker(subScenario, aTsContent, ["--b", "/src/tsconfig.json", "-v"]); - verifyNoEmitWorker(`${subScenario} with incremental`, aTsContent, ["--b", "/src/tsconfig.json", "-v", "--incremental"]); + verifyNoEmitWorker(`${subScenario} with incremental`, aTsContent, [ + "--b", + "/src/tsconfig.json", + "-v", + "--incremental", + ]); } verifyNoEmit("syntax errors", `const a = "hello`); verifyNoEmit("semantic errors", `const a: number = "hello"`); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuild/noEmitOnError.ts b/src/testRunner/unittests/tsbuild/noEmitOnError.ts index 10fb8ebd0e8d9..182e6322ab5e3 100644 --- a/src/testRunner/unittests/tsbuild/noEmitOnError.ts +++ b/src/testRunner/unittests/tsbuild/noEmitOnError.ts @@ -3,7 +3,9 @@ import { noChangeRun, verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromDisk } from "../helpers/vfs"; +import { + loadProjectFromDisk, +} from "../helpers/vfs"; describe("unittests:: tsbuild - with noEmitOnError", () => { let projFs: vfs.FileSystem; @@ -23,10 +25,15 @@ describe("unittests:: tsbuild - with noEmitOnError", () => { noChangeRun, { caption: "Fix error", - edit: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; + edit: fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; const a = { lastName: 'sdsd' -};`, "utf-8"), +};`, + "utf-8", + ), }, noChangeRun, ], @@ -42,10 +49,15 @@ const a = { noChangeRun, { caption: "Fix error", - edit: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; + edit: fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; const a = { lastName: 'sdsd' -};`, "utf-8"), +};`, + "utf-8", + ), }, noChangeRun, ], @@ -56,15 +68,25 @@ const a = { scenario: "noEmitOnError", subScenario: "semantic errors", fs: () => projFs, - modifyFs: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; -const a: string = 10;`, "utf-8"), + modifyFs: fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; +const a: string = 10;`, + "utf-8", + ), commandLineArgs: ["--b", "/src/tsconfig.json"], edits: [ noChangeRun, { caption: "Fix error", - edit: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; -const a: string = "hello";`, "utf-8"), + edit: fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; +const a: string = "hello";`, + "utf-8", + ), }, noChangeRun, ], @@ -75,15 +97,25 @@ const a: string = "hello";`, "utf-8"), scenario: "noEmitOnError", subScenario: "semantic errors with incremental", fs: () => projFs, - modifyFs: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; -const a: string = 10;`, "utf-8"), + modifyFs: fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; +const a: string = 10;`, + "utf-8", + ), commandLineArgs: ["--b", "/src/tsconfig.json", "--incremental"], edits: [ noChangeRun, { caption: "Fix error", - edit: fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; -const a: string = "hello";`, "utf-8"), + edit: fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; +const a: string = "hello";`, + "utf-8", + ), }, noChangeRun, ], diff --git a/src/testRunner/unittests/tsbuild/outFile.ts b/src/testRunner/unittests/tsbuild/outFile.ts index 1c5a46885fee4..95531f85602be 100644 --- a/src/testRunner/unittests/tsbuild/outFile.ts +++ b/src/testRunner/unittests/tsbuild/outFile.ts @@ -1,7 +1,9 @@ import * as fakes from "../../_namespaces/fakes"; import * as ts from "../../_namespaces/ts"; import * as vfs from "../../_namespaces/vfs"; -import { createSolutionBuilderHostForBaseline } from "../helpers/solutionBuilder"; +import { + createSolutionBuilderHostForBaseline, +} from "../helpers/solutionBuilder"; import { noChangeOnlyRuns, testTscCompileLike, @@ -18,10 +20,12 @@ import { addTestPrologue, addTripleSlashRef, appendText, - changeStubToRest, enableStrict, - loadProjectFromDisk, prependText, + changeStubToRest, + enableStrict, + loadProjectFromDisk, + prependText, removeRest, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: outFile::", () => { @@ -70,7 +74,7 @@ describe("unittests:: tsbuild:: outFile::", () => { if (modifyAgainFs) { (edits ??= []).push({ caption: "incremental-headers-change-without-dts-changes", - edit: modifyAgainFs + edit: modifyAgainFs, }); } verifyTsc({ @@ -93,7 +97,7 @@ describe("unittests:: tsbuild:: outFile::", () => { verifyOutFileScenario({ subScenario: "explainFiles", additionalCommandLineArgs: ["--explainFiles"], - baselineOnly: true + baselineOnly: true, }); // Verify baseline with build info + dts unChanged @@ -101,7 +105,7 @@ describe("unittests:: tsbuild:: outFile::", () => { subScenario: "when final project is not composite but uses project references", modifyFs: fs => replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, ""), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify baseline with build info @@ -110,17 +114,23 @@ describe("unittests:: tsbuild:: outFile::", () => { modifyFs: fs => replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"incremental": true,`), ignoreDtsChanged: true, ignoreDtsUnchanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify baseline with build info verifyOutFileScenario({ subScenario: "when final project specifies tsBuildInfoFile", - modifyFs: fs => replaceText(fs, "/src/third/tsconfig.json", `"composite": true,`, `"composite": true, - "tsBuildInfoFile": "./thirdjs/output/third.tsbuildinfo",`), + modifyFs: fs => + replaceText( + fs, + "/src/third/tsconfig.json", + `"composite": true,`, + `"composite": true, + "tsBuildInfoFile": "./thirdjs/output/third.tsbuildinfo",`, + ), ignoreDtsChanged: true, ignoreDtsUnchanged: true, - baselineOnly: true + baselineOnly: true, }); function getOutFileFsAfterBuild() { @@ -139,7 +149,7 @@ describe("unittests:: tsbuild:: outFile::", () => { subScenario: "clean projects", fs: getOutFileFsAfterBuild, commandLineArgs: ["--b", "/src/third", "--clean"], - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); verifyTsc({ @@ -168,7 +178,7 @@ describe("unittests:: tsbuild:: outFile::", () => { const buildHost = createSolutionBuilderHostForBaseline(sys, "FakeTSCurrentVersion"); const builder = ts.createSolutionBuilder(buildHost, ["/src/third"], { verbose: true }); sys.exit(builder.build()); - } + }, }); verifyTsc({ @@ -189,8 +199,8 @@ describe("unittests:: tsbuild:: outFile::", () => { caption: "Make incremental build with change in file that doesnt affect dts", edit: fs => appendText(fs, "/src/first/first_PART1.ts", "console.log(s);"), commandLineArgs: ["--b", "/src/third", "--verbose", "--incremental"], - } - ] + }, + ], }); verifyTsc({ @@ -206,7 +216,7 @@ describe("unittests:: tsbuild:: outFile::", () => { fs.utimesSync("/src/first/first_PART1.ts", time, time); }, }, - ] + ], }); verifyTscCompileLike(testTscCompileLike, { @@ -218,7 +228,7 @@ describe("unittests:: tsbuild:: outFile::", () => { const buildHost = createSolutionBuilderHostForBaseline(sys); const builder = ts.createSolutionBuilder(buildHost, ["/src/third/tsconfig.json"], {}); sys.exit(builder.build("/src/second/tsconfig.json")); - } + }, }); verifyTscCompileLike(testTscCompileLike, { @@ -230,7 +240,7 @@ describe("unittests:: tsbuild:: outFile::", () => { const buildHost = createSolutionBuilderHostForBaseline(sys); const builder = ts.createSolutionBuilder(buildHost, ["/src/third/tsconfig.json"], { verbose: true }); sys.exit(builder.clean("/src/second/tsconfig.json")); - } + }, }); describe("Prepend output with .tsbuildinfo", () => { @@ -244,7 +254,7 @@ describe("unittests:: tsbuild:: outFile::", () => { enableStrict(fs, "/src/second/tsconfig.json"); enableStrict(fs, "/src/third/tsconfig.json"); }, - modifyAgainFs: fs => addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue"`) + modifyAgainFs: fs => addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue"`), }); // Verify ignore dtsChanged @@ -253,7 +263,7 @@ describe("unittests:: tsbuild:: outFile::", () => { modifyFs: fs => enableStrict(fs, "/src/second/tsconfig.json"), modifyAgainFs: fs => addTestPrologue(fs, "src/first/first_PART1.ts", `"myPrologue"`), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify initial + incremental edits - sourcemap verification @@ -269,7 +279,7 @@ describe("unittests:: tsbuild:: outFile::", () => { addTestPrologue(fs, "/src/third/third_part1.ts", `"myPrologue";`); addTestPrologue(fs, "/src/third/third_part1.ts", `"myPrologue3";`); }, - modifyAgainFs: fs => addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue5"`) + modifyAgainFs: fs => addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue5"`), }); // Verify ignore dtsChanged @@ -283,7 +293,7 @@ describe("unittests:: tsbuild:: outFile::", () => { }, modifyAgainFs: fs => addTestPrologue(fs, "/src/first/first_PART1.ts", `"myPrologue5"`), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); }); @@ -306,7 +316,7 @@ describe("unittests:: tsbuild:: outFile::", () => { subScenario: "shebang in only one dependency project", modifyFs: fs => addShebang(fs, "second", "second_part1"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); }); @@ -320,7 +330,7 @@ describe("unittests:: tsbuild:: outFile::", () => { addRest(fs, "second", "second_part1"); addRest(fs, "third", "third_part1"); }, - modifyAgainFs: fs => removeRest(fs, "first", "first_PART1") + modifyAgainFs: fs => removeRest(fs, "first", "first_PART1"), }); // Verify ignore dtsChanged @@ -332,7 +342,7 @@ describe("unittests:: tsbuild:: outFile::", () => { }, modifyAgainFs: fs => changeStubToRest(fs, "first", "first_PART1"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify ignore dtsChanged @@ -348,7 +358,7 @@ describe("unittests:: tsbuild:: outFile::", () => { }, modifyAgainFs: fs => removeRest(fs, "first", "first_PART1"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify ignore dtsChanged @@ -361,7 +371,7 @@ describe("unittests:: tsbuild:: outFile::", () => { }, modifyAgainFs: fs => removeRest(fs, "first", "first_PART1"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); }); @@ -375,7 +385,7 @@ describe("unittests:: tsbuild:: outFile::", () => { addTripleSlashRef(fs, "first", "first_part2"); addTripleSlashRef(fs, "second", "second_part1"); addTripleSlashRef(fs, "third", "third_part1"); - } + }, }); // Verify ignore dtsChanged @@ -383,7 +393,7 @@ describe("unittests:: tsbuild:: outFile::", () => { subScenario: "triple slash refs in one project", modifyFs: fs => addTripleSlashRef(fs, "second", "second_part1"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); }); @@ -399,8 +409,13 @@ describe("unittests:: tsbuild:: outFile::", () => { } function stripInternalOfThird(fs: vfs.FileSystem) { - replaceText(fs, "/src/third/tsconfig.json", `"declaration": true,`, `"declaration": true, - "stripInternal": true,`); + replaceText( + fs, + "/src/third/tsconfig.json", + `"declaration": true,`, + `"declaration": true, + "stripInternal": true,`, + ); } function stripInternalScenario(fs: vfs.FileSystem, removeCommentsDisabled?: boolean, jsDocStyle?: boolean) { @@ -410,7 +425,10 @@ describe("unittests:: tsbuild:: outFile::", () => { } stripInternalOfThird(fs); replaceText(fs, "/src/first/first_PART1.ts", "interface", `${internal} interface`); - appendText(fs, "/src/second/second_part1.ts", ` + appendText( + fs, + "/src/second/second_part1.ts", + ` class normalC { ${internal} constructor() { } ${internal} prop: string; @@ -435,32 +453,36 @@ ${internal} namespace internalOther.something { export class someClass {} } ${internal} import internalImport = internalNamespace.someClass; ${internal} type internalType = internalC; ${internal} const internalConst = 10; -${internal} enum internalEnum { a, b, c }`); +${internal} enum internalEnum { a, b, c }`, + ); } // Verify initial + incremental edits verifyOutFileScenario({ subScenario: "stripInternal", modifyFs: stripInternalScenario, - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), }); // Verify ignore dtsChanged verifyOutFileScenario({ subScenario: "stripInternal with comments emit enabled", modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ true), - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify ignore dtsChanged verifyOutFileScenario({ subScenario: "stripInternal jsdoc style comment", modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true), - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify ignore dtsChanged @@ -468,17 +490,26 @@ ${internal} enum internalEnum { a, b, c }`); subScenario: "stripInternal jsdoc style with comments emit enabled", modifyFs: fs => stripInternalScenario(fs, /*removeCommentsDisabled*/ true, /*jsDocStyle*/ true), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); describe("with three levels of project dependency", () => { function makeOneTwoThreeDependOrder(fs: vfs.FileSystem) { - replaceText(fs, "/src/second/tsconfig.json", "[", `[ - { "path": "../first", "prepend": true }`); + replaceText( + fs, + "/src/second/tsconfig.json", + "[", + `[ + { "path": "../first", "prepend": true }`, + ); replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../first", "prepend": true },`, ""); } - function stripInternalWithDependentOrder(fs: vfs.FileSystem, removeCommentsDisabled?: boolean, jsDocStyle?: boolean) { + function stripInternalWithDependentOrder( + fs: vfs.FileSystem, + removeCommentsDisabled?: boolean, + jsDocStyle?: boolean, + ) { stripInternalScenario(fs, removeCommentsDisabled, jsDocStyle); makeOneTwoThreeDependOrder(fs); } @@ -487,33 +518,39 @@ ${internal} enum internalEnum { a, b, c }`); verifyOutFileScenario({ subScenario: "stripInternal when one-two-three are prepended in order", modifyFs: stripInternalWithDependentOrder, - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), }); // Verify ignore dtsChanged verifyOutFileScenario({ subScenario: "stripInternal with comments emit enabled when one-two-three are prepended in order", modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true), - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/*@internal*/ interface`, "interface"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify ignore dtsChanged verifyOutFileScenario({ subScenario: "stripInternal jsdoc style comment when one-two-three are prepended in order", - modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true), - modifyAgainFs: fs => replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"), + modifyFs: fs => + stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ false, /*jsDocStyle*/ true), + modifyAgainFs: fs => + replaceText(fs, "/src/first/first_PART1.ts", `/**@internal*/ interface`, "interface"), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // Verify ignore dtsChanged verifyOutFileScenario({ - subScenario: "stripInternal jsdoc style with comments emit enabled when one-two-three are prepended in order", - modifyFs: fs => stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true, /*jsDocStyle*/ true), + subScenario: + "stripInternal jsdoc style with comments emit enabled when one-two-three are prepended in order", + modifyFs: fs => + stripInternalWithDependentOrder(fs, /*removeCommentsDisabled*/ true, /*jsDocStyle*/ true), ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); }); @@ -522,7 +559,10 @@ ${internal} enum internalEnum { a, b, c }`); subScenario: "stripInternal baseline when internal is inside another internal", modifyFs: fs => { stripInternalOfThird(fs); - prependText(fs, "/src/first/first_PART1.ts", `namespace ts { + prependText( + fs, + "/src/first/first_PART1.ts", + `namespace ts { /* @internal */ /** * Subset of properties from SourceFile that are used in multiple utility functions @@ -549,11 +589,12 @@ ${internal} enum internalEnum { a, b, c }`); export interface SourceFile { someProp: string; } -}`); +}`, + ); }, ignoreDtsChanged: true, ignoreDtsUnchanged: true, - baselineOnly: true + baselineOnly: true, }); // only baseline @@ -561,7 +602,10 @@ ${internal} enum internalEnum { a, b, c }`); subScenario: "stripInternal when few members of enum are internal", modifyFs: fs => { stripInternalOfThird(fs); - prependText(fs, "/src/first/first_PART1.ts", `enum TokenFlags { + prependText( + fs, + "/src/first/first_PART1.ts", + `enum TokenFlags { None = 0, /* @internal */ PrecedingLineBreak = 1 << 0, @@ -583,11 +627,12 @@ ${internal} enum internalEnum { a, b, c }`); /* @internal */ NumericLiteralFlags = Scientific | Octal | HexSpecifier | BinaryOrOctalSpecifier | ContainsSeparator } -`); +`, + ); }, ignoreDtsChanged: true, ignoreDtsUnchanged: true, - baselineOnly: true + baselineOnly: true, }); verifyOutFileScenario({ @@ -598,31 +643,37 @@ ${internal} enum internalEnum { a, b, c }`); modifyFs: fs => { fs.writeFileSync("/src/first/first_PART1.ts", "/* @internal */ const A = 1;"); fs.writeFileSync("/src/third/third_part1.ts", "const B = 2;"); - fs.writeFileSync("/src/first/tsconfig.json", JSON.stringify({ - compilerOptions: { - composite: true, - declaration: true, - declarationMap: true, - skipDefaultLibCheck: true, - sourceMap: true, - outFile: "./bin/first-output.js" - }, - files: ["/src/first/first_PART1.ts"] - })); - fs.writeFileSync("/src/third/tsconfig.json", JSON.stringify({ - compilerOptions: { - ignoreDeprecations: "5.0", - composite: true, - declaration: true, - declarationMap: false, - stripInternal: true, - sourceMap: true, - outFile: "./thirdjs/output/third-output.js", - }, - references: [{ path: "../first", prepend: true }], - files: ["/src/third/third_part1.ts"] - })); - } + fs.writeFileSync( + "/src/first/tsconfig.json", + JSON.stringify({ + compilerOptions: { + composite: true, + declaration: true, + declarationMap: true, + skipDefaultLibCheck: true, + sourceMap: true, + outFile: "./bin/first-output.js", + }, + files: ["/src/first/first_PART1.ts"], + }), + ); + fs.writeFileSync( + "/src/third/tsconfig.json", + JSON.stringify({ + compilerOptions: { + ignoreDeprecations: "5.0", + composite: true, + declaration: true, + declarationMap: false, + stripInternal: true, + sourceMap: true, + outFile: "./thirdjs/output/third-output.js", + }, + references: [{ path: "../first", prepend: true }], + files: ["/src/third/third_part1.ts"], + }), + ); + }, }); }); @@ -636,7 +687,7 @@ ${internal} enum internalEnum { a, b, c }`); subScenario: "when source files are empty in the own file", modifyFs: makeThirdEmptySourceFile, ignoreDtsChanged: true, - baselineOnly: true + baselineOnly: true, }); // only baseline @@ -650,7 +701,7 @@ ${internal} enum internalEnum { a, b, c }`); }, ignoreDtsChanged: true, ignoreDtsUnchanged: true, - baselineOnly: true + baselineOnly: true, }); }); }); @@ -662,8 +713,18 @@ ${internal} enum internalEnum { a, b, c }`); commandLineArgs: ["--b", "/src/third", "--verbose"], modifyFs: fs => { // No prepend - replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../first", "prepend": true }`, `{ "path": "../first" }`); - replaceText(fs, "/src/third/tsconfig.json", `{ "path": "../second", "prepend": true }`, `{ "path": "../second" }`); + replaceText( + fs, + "/src/third/tsconfig.json", + `{ "path": "../first", "prepend": true }`, + `{ "path": "../first" }`, + ); + replaceText( + fs, + "/src/third/tsconfig.json", + `{ "path": "../second", "prepend": true }`, + `{ "path": "../second" }`, + ); // Non Modules replaceText(fs, "/src/first/tsconfig.json", `"composite": true,`, `"composite": true, "module": "none",`); diff --git a/src/testRunner/unittests/tsbuild/outputPaths.ts b/src/testRunner/unittests/tsbuild/outputPaths.ts index 15686987c2239..db5654e15f172 100644 --- a/src/testRunner/unittests/tsbuild/outputPaths.ts +++ b/src/testRunner/unittests/tsbuild/outputPaths.ts @@ -7,7 +7,9 @@ import { verifyTsc, VerifyTscWithEditsInput, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsbuild - output file paths", () => { const noChangeProject: TestTscEdit = { @@ -20,96 +22,113 @@ describe("unittests:: tsbuild - output file paths", () => { noChangeProject, ]; - function verify(input: Pick, expectedOuptutNames: readonly string[]) { + function verify( + input: Pick, + expectedOuptutNames: readonly string[], + ) { verifyTsc({ scenario: "outputPaths", commandLineArgs: ["--b", "/src/tsconfig.json", "-v"], - ...input + ...input, }); it("verify getOutputFileNames", () => { - const sys = new fakes.System(input.fs().makeReadonly(), { executingFilePath: "/lib/tsc" }) as TscCompileSystem; + const sys = new fakes.System(input.fs().makeReadonly(), { + executingFilePath: "/lib/tsc", + }) as TscCompileSystem; assert.deepEqual( ts.getOutputFileNames( - ts.parseConfigFileWithSystem("/src/tsconfig.json", {}, /*extendedConfigCache*/ undefined, {}, sys, ts.noop)!, + ts.parseConfigFileWithSystem( + "/src/tsconfig.json", + {}, + /*extendedConfigCache*/ undefined, + {}, + sys, + ts.noop, + )!, "/src/src/index.ts", - /*ignoreCase*/ false + /*ignoreCase*/ false, ), - expectedOuptutNames + expectedOuptutNames, ); }); } verify({ subScenario: "when rootDir is not specified", - fs: () => loadProjectFromFiles({ - "/src/src/index.ts": "export const x = 10;", - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { - outDir: "dist" - } - }) - }), + fs: () => + loadProjectFromFiles({ + "/src/src/index.ts": "export const x = 10;", + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { + outDir: "dist", + }, + }), + }), edits, }, ["/src/dist/index.js"]); verify({ subScenario: "when rootDir is not specified and is composite", - fs: () => loadProjectFromFiles({ - "/src/src/index.ts": "export const x = 10;", - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { - outDir: "dist", - composite: true - } - }) - }), + fs: () => + loadProjectFromFiles({ + "/src/src/index.ts": "export const x = 10;", + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { + outDir: "dist", + composite: true, + }, + }), + }), edits, }, ["/src/dist/src/index.js", "/src/dist/src/index.d.ts"]); verify({ subScenario: "when rootDir is specified", - fs: () => loadProjectFromFiles({ - "/src/src/index.ts": "export const x = 10;", - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { - outDir: "dist", - rootDir: "src" - } - }) - }), + fs: () => + loadProjectFromFiles({ + "/src/src/index.ts": "export const x = 10;", + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { + outDir: "dist", + rootDir: "src", + }, + }), + }), edits, }, ["/src/dist/index.js"]); verify({ subScenario: "when rootDir is specified but not all files belong to rootDir", - fs: () => loadProjectFromFiles({ - "/src/src/index.ts": "export const x = 10;", - "/src/types/type.ts": "export type t = string;", - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { - outDir: "dist", - rootDir: "src" - } - }) - }), + fs: () => + loadProjectFromFiles({ + "/src/src/index.ts": "export const x = 10;", + "/src/types/type.ts": "export type t = string;", + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { + outDir: "dist", + rootDir: "src", + }, + }), + }), edits, }, ["/src/dist/index.js"]); verify({ subScenario: "when rootDir is specified but not all files belong to rootDir and is composite", - fs: () => loadProjectFromFiles({ - "/src/src/index.ts": "export const x = 10;", - "/src/types/type.ts": "export type t = string;", - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { - outDir: "dist", - rootDir: "src", - composite: true - } - }) - }), + fs: () => + loadProjectFromFiles({ + "/src/src/index.ts": "export const x = 10;", + "/src/types/type.ts": "export type t = string;", + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { + outDir: "dist", + rootDir: "src", + composite: true, + }, + }), + }), edits, }, ["/src/dist/index.js", "/src/dist/index.d.ts"]); }); diff --git a/src/testRunner/unittests/tsbuild/publicApi.ts b/src/testRunner/unittests/tsbuild/publicApi.ts index 0359a62a7a42a..a4a5db634a147 100644 --- a/src/testRunner/unittests/tsbuild/publicApi.ts +++ b/src/testRunner/unittests/tsbuild/publicApi.ts @@ -10,7 +10,9 @@ import { TscCompileSystem, verifyTscBaseline, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsbuild:: Public API with custom transformers when passed to build", () => { let sys: TscCompileSystem; @@ -19,9 +21,9 @@ describe("unittests:: tsbuild:: Public API with custom transformers when passed "/src/tsconfig.json": JSON.stringify({ references: [ { path: "./shared/tsconfig.json" }, - { path: "./webpack/tsconfig.json" } + { path: "./webpack/tsconfig.json" }, ], - files: [] + files: [], }), "/src/shared/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true }, @@ -35,7 +37,7 @@ export function f2() { } // trailing`, compilerOptions: { composite: true, }, - references: [{ path: "../shared/tsconfig.json" }] + references: [{ path: "../shared/tsconfig.json" }], }), "/src/webpack/index.ts": `export function f2() { } export class c2 { } @@ -62,15 +64,20 @@ export function f22() { } // trailing`, const { cb, getPrograms } = commandLineCallbacks(sys, /*originalReadCall*/ undefined); const buildHost = ts.createSolutionBuilderHost( sys, - /*createProgram*/ undefined, + /*createProgram*/ undefined, ts.createDiagnosticReporter(sys, /*pretty*/ true), ts.createBuilderStatusReporter(sys, /*pretty*/ true), - (errorCount, filesInError) => sys.write(ts.getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)) + (errorCount, filesInError) => sys.write(ts.getErrorSummaryText(errorCount, filesInError, sys.newLine, sys)), ); buildHost.afterProgramEmitAndDiagnostics = cb; buildHost.afterEmitBundle = cb; const builder = ts.createSolutionBuilder(buildHost, [commandLineArgs[1]], { verbose: true }); - const exitStatus = builder.build(/*project*/ undefined, /*cancellationToken*/ undefined, /*writeFile*/ undefined, getCustomTransformers); + const exitStatus = builder.build( + /*project*/ undefined, + /*cancellationToken*/ undefined, + /*writeFile*/ undefined, + getCustomTransformers, + ); sys.exit(exitStatus); sys.write(`exitCode:: ExitStatus.${ts.ExitStatus[sys.exitCode as ts.ExitStatus]}\n`); const baseline: string[] = []; @@ -88,7 +95,7 @@ ${baseFsPatch ? vfs.formatPatch(baseFsPatch) : ""} Output:: ${sys.output.join("")} -${patch ? vfs.formatPatch(patch) : ""}` +${patch ? vfs.formatPatch(patch) : ""}`, }; }; @@ -104,7 +111,12 @@ ${patch ? vfs.formatPatch(patch) : ""}` } } function visitFunction(node: ts.FunctionDeclaration) { - ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, `@before${project}`, /*hasTrailingNewLine*/ true); + ts.addSyntheticLeadingComment( + node, + ts.SyntaxKind.MultiLineCommentTrivia, + `@before${project}`, + /*hasTrailingNewLine*/ true, + ); return node; } }; diff --git a/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts b/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts index 63d2fbaa35286..db3a0bcda429e 100644 --- a/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts +++ b/src/testRunner/unittests/tsbuild/referencesWithRootDirInParent.ts @@ -4,7 +4,7 @@ import { } from "../helpers/tsc"; import { loadProjectFromDisk, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsbuild:: with rootDir of project reference in parentDirectory", () => { @@ -38,13 +38,19 @@ describe("unittests:: tsbuild:: with rootDir of project reference in parentDirec fs: () => projFs, commandLineArgs: ["--b", "/src/src/main", "--verbose"], modifyFs: fs => { - fs.writeFileSync("/src/src/main/tsconfig.json", JSON.stringify({ - compilerOptions: { composite: true, outDir: "../../dist/" }, - references: [{ path: "../other" }] - })); - fs.writeFileSync("/src/src/other/tsconfig.json", JSON.stringify({ - compilerOptions: { composite: true, outDir: "../../dist/" }, - })); + fs.writeFileSync( + "/src/src/main/tsconfig.json", + JSON.stringify({ + compilerOptions: { composite: true, outDir: "../../dist/" }, + references: [{ path: "../other" }], + }), + ); + fs.writeFileSync( + "/src/src/other/tsconfig.json", + JSON.stringify({ + compilerOptions: { composite: true, outDir: "../../dist/" }, + }), + ); }, }); @@ -56,13 +62,19 @@ describe("unittests:: tsbuild:: with rootDir of project reference in parentDirec modifyFs: fs => { fs.renameSync("/src/src/main/tsconfig.json", "/src/src/main/tsconfig.main.json"); fs.renameSync("/src/src/other/tsconfig.json", "/src/src/other/tsconfig.other.json"); - fs.writeFileSync("/src/src/main/tsconfig.main.json", JSON.stringify({ - compilerOptions: { composite: true, outDir: "../../dist/" }, - references: [{ path: "../other/tsconfig.other.json" }] - })); - fs.writeFileSync("/src/src/other/tsconfig.other.json", JSON.stringify({ - compilerOptions: { composite: true, outDir: "../../dist/" }, - })); + fs.writeFileSync( + "/src/src/main/tsconfig.main.json", + JSON.stringify({ + compilerOptions: { composite: true, outDir: "../../dist/" }, + references: [{ path: "../other/tsconfig.other.json" }], + }), + ); + fs.writeFileSync( + "/src/src/other/tsconfig.other.json", + JSON.stringify({ + compilerOptions: { composite: true, outDir: "../../dist/" }, + }), + ); }, }); }); diff --git a/src/testRunner/unittests/tsbuild/resolveJsonModule.ts b/src/testRunner/unittests/tsbuild/resolveJsonModule.ts index 7275c671f83ad..6a7df66ae6e09 100644 --- a/src/testRunner/unittests/tsbuild/resolveJsonModule.ts +++ b/src/testRunner/unittests/tsbuild/resolveJsonModule.ts @@ -3,7 +3,10 @@ import { noChangeOnlyRuns, verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromDisk, replaceText } from "../helpers/vfs"; +import { + loadProjectFromDisk, + replaceText, +} from "../helpers/vfs"; describe("unittests:: tsbuild:: with resolveJsonModule option on project resolveJsonModuleAndComposite", () => { let projFs: vfs.FileSystem; @@ -37,9 +40,12 @@ describe("unittests:: tsbuild:: with resolveJsonModule option on project resolve modifyFs: fs => { fs.rimrafSync("/src/src/hello.json"); fs.writeFileSync("/src/src/index.json", JSON.stringify({ hello: "world" })); - fs.writeFileSync("/src/src/index.ts", `import hello from "./index.json" + fs.writeFileSync( + "/src/src/index.ts", + `import hello from "./index.json" -export default hello.hello`); +export default hello.hello`, + ); }, }); @@ -62,8 +68,14 @@ export default hello.hello`); subScenario: "sourcemap", fs: () => projFs, commandLineArgs: ["--b", "src/tsconfig_withFiles.json", "--verbose", "--explainFiles"], - modifyFs: fs => replaceText(fs, "src/tsconfig_withFiles.json", `"composite": true,`, `"composite": true, "sourceMap": true,`), - edits: noChangeOnlyRuns + modifyFs: fs => + replaceText( + fs, + "src/tsconfig_withFiles.json", + `"composite": true,`, + `"composite": true, "sourceMap": true,`, + ), + edits: noChangeOnlyRuns, }); verifyTsc({ @@ -72,7 +84,7 @@ export default hello.hello`); fs: () => projFs, commandLineArgs: ["--b", "src/tsconfig_withFiles.json", "--verbose"], modifyFs: fs => replaceText(fs, "src/tsconfig_withFiles.json", `"outDir": "dist",`, ""), - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); }); @@ -82,6 +94,6 @@ describe("unittests:: tsbuild:: with resolveJsonModule option on project importJ subScenario: "importing json module from project reference", fs: () => loadProjectFromDisk("tests/projects/importJsonFromProjectReference"), commandLineArgs: ["--b", "src/tsconfig.json", "--verbose", "--explainFiles"], - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); }); diff --git a/src/testRunner/unittests/tsbuild/roots.ts b/src/testRunner/unittests/tsbuild/roots.ts index 6d824635fc08d..0be83bc907af9 100644 --- a/src/testRunner/unittests/tsbuild/roots.ts +++ b/src/testRunner/unittests/tsbuild/roots.ts @@ -1,22 +1,27 @@ -import { dedent } from "../../_namespaces/Utils"; +import { + dedent, +} from "../../_namespaces/Utils"; import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsbuild:: roots::", () => { verifyTsc({ scenario: "roots", subScenario: `when two root files are consecutive`, commandLineArgs: ["--b", "/src/tsconfig.json", "-v"], - fs: () => loadProjectFromFiles({ - "/src/file1.ts": `export const x = "hello";`, - "/src/file2.ts": `export const y = "world";`, - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true }, - include: ["*.ts"] - }) - }), + fs: () => + loadProjectFromFiles({ + "/src/file1.ts": `export const x = "hello";`, + "/src/file2.ts": `export const y = "world";`, + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + include: ["*.ts"], + }), + }), edits: [{ caption: "delete file1", edit: fs => { @@ -31,16 +36,17 @@ describe("unittests:: tsbuild:: roots::", () => { scenario: "roots", subScenario: `when multiple root files are consecutive`, commandLineArgs: ["--b", "/src/tsconfig.json", "-v"], - fs: () => loadProjectFromFiles({ - "/src/file1.ts": `export const x = "hello";`, - "/src/file2.ts": `export const y = "world";`, - "/src/file3.ts": `export const y = "world";`, - "/src/file4.ts": `export const y = "world";`, - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true }, - include: ["*.ts"] - }) - }), + fs: () => + loadProjectFromFiles({ + "/src/file1.ts": `export const x = "hello";`, + "/src/file2.ts": `export const y = "world";`, + "/src/file3.ts": `export const y = "world";`, + "/src/file4.ts": `export const y = "world";`, + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + include: ["*.ts"], + }), + }), edits: [{ caption: "delete file1", edit: fs => { @@ -55,18 +61,19 @@ describe("unittests:: tsbuild:: roots::", () => { scenario: "roots", subScenario: `when files are not consecutive`, commandLineArgs: ["--b", "/src/tsconfig.json", "-v"], - fs: () => loadProjectFromFiles({ - "/src/file1.ts": `export const x = "hello";`, - "/src/random.d.ts": `export const random = "world";`, - "/src/file2.ts": dedent` + fs: () => + loadProjectFromFiles({ + "/src/file1.ts": `export const x = "hello";`, + "/src/random.d.ts": `export const random = "world";`, + "/src/file2.ts": dedent` import { random } from "./random"; export const y = "world"; `, - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true }, - include: ["file*.ts"] - }) - }), + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + include: ["file*.ts"], + }), + }), edits: [{ caption: "delete file1", edit: fs => { @@ -81,31 +88,32 @@ describe("unittests:: tsbuild:: roots::", () => { scenario: "roots", subScenario: `when consecutive and non consecutive are mixed`, commandLineArgs: ["--b", "/src/tsconfig.json", "-v"], - fs: () => loadProjectFromFiles({ - "/src/file1.ts": `export const x = "hello";`, - "/src/file2.ts": `export const y = "world";`, - "/src/random.d.ts": `export const random = "hello";`, - "/src/nonconsecutive.ts": dedent` + fs: () => + loadProjectFromFiles({ + "/src/file1.ts": `export const x = "hello";`, + "/src/file2.ts": `export const y = "world";`, + "/src/random.d.ts": `export const random = "hello";`, + "/src/nonconsecutive.ts": dedent` import { random } from "./random"; export const nonConsecutive = "hello"; `, - "/src/random1.d.ts": `export const random = "hello";`, - "/src/asArray1.ts": dedent` + "/src/random1.d.ts": `export const random = "hello";`, + "/src/asArray1.ts": dedent` import { random } from "./random1"; export const x = "hello"; `, - "/src/asArray2.ts": `export const x = "hello";`, - "/src/asArray3.ts": `export const x = "hello";`, - "/src/random2.d.ts": `export const random = "hello";`, - "/src/anotherNonConsecutive.ts": dedent` + "/src/asArray2.ts": `export const x = "hello";`, + "/src/asArray3.ts": `export const x = "hello";`, + "/src/random2.d.ts": `export const random = "hello";`, + "/src/anotherNonConsecutive.ts": dedent` import { random } from "./random2"; export const nonConsecutive = "hello"; `, - "/src/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true }, - include: ["file*.ts", "nonconsecutive*.ts", "asArray*.ts", "anotherNonConsecutive.ts"] - }) - }), + "/src/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + include: ["file*.ts", "nonconsecutive*.ts", "asArray*.ts", "anotherNonConsecutive.ts"], + }), + }), edits: [{ caption: "delete file1", edit: fs => { @@ -115,4 +123,4 @@ describe("unittests:: tsbuild:: roots::", () => { }, }], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuild/sample.ts b/src/testRunner/unittests/tsbuild/sample.ts index 3eb0f4595bb2f..2b5fd66bbc9a7 100644 --- a/src/testRunner/unittests/tsbuild/sample.ts +++ b/src/testRunner/unittests/tsbuild/sample.ts @@ -2,8 +2,12 @@ import * as fakes from "../../_namespaces/fakes"; import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; import * as vfs from "../../_namespaces/vfs"; -import { libContent } from "../helpers/contents"; -import { createSolutionBuilderHostForBaseline } from "../helpers/solutionBuilder"; +import { + libContent, +} from "../helpers/contents"; +import { + createSolutionBuilderHostForBaseline, +} from "../helpers/solutionBuilder"; import { noChangeOnlyRuns, noChangeRun, @@ -14,9 +18,11 @@ import { verifyTscCompileLike, } from "../helpers/tsc"; import { - appendText, loadProjectFromDisk, - loadProjectFromFiles, prependText, - replaceText + appendText, + loadProjectFromDisk, + loadProjectFromFiles, + prependText, + replaceText, } from "../helpers/vfs"; import { changeToHostTrackingWrittenFiles, @@ -42,7 +48,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { function getTsBuildProjectFile(project: string, file: string): File { return { path: getTsBuildProjectFilePath(project, file), - content: projFs.readFileSync(`/src/${project}/${file}`, "utf8")! + content: projFs.readFileSync(`/src/${project}/${file}`, "utf8")!, }; } @@ -63,10 +69,14 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { subScenario: "builds correctly when outDir is specified", fs: () => projFs, commandLineArgs: ["--b", "/src/tests"], - modifyFs: fs => fs.writeFileSync("/src/logic/tsconfig.json", JSON.stringify({ - compilerOptions: { composite: true, declaration: true, sourceMap: true, outDir: "outDir" }, - references: [{ path: "../core" }] - })), + modifyFs: fs => + fs.writeFileSync( + "/src/logic/tsconfig.json", + JSON.stringify({ + compilerOptions: { composite: true, declaration: true, sourceMap: true, outDir: "outDir" }, + references: [{ path: "../core" }], + }), + ), }); verifyTsc({ @@ -74,10 +84,19 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { subScenario: "builds correctly when declarationDir is specified", fs: () => projFs, commandLineArgs: ["--b", "/src/tests"], - modifyFs: fs => fs.writeFileSync("/src/logic/tsconfig.json", JSON.stringify({ - compilerOptions: { composite: true, declaration: true, sourceMap: true, declarationDir: "out/decls" }, - references: [{ path: "../core" }] - })), + modifyFs: fs => + fs.writeFileSync( + "/src/logic/tsconfig.json", + JSON.stringify({ + compilerOptions: { + composite: true, + declaration: true, + sourceMap: true, + declarationDir: "out/decls", + }, + references: [{ path: "../core" }], + }), + ), }); verifyTsc({ @@ -104,7 +123,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { subScenario: "removes all files it built", fs: getSampleFsAfterBuild, commandLineArgs: ["--b", "/src/tests", "--clean"], - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); verifyTscCompileLike(testTscCompileLike, { @@ -116,7 +135,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const buildHost = createSolutionBuilderHostForBaseline(sys); const builder = ts.createSolutionBuilder(buildHost, ["/src/third/tsconfig.json"], {}); sys.exit(builder.clean("/src/logic")); - } + }, }); verifyTscCompileLike(testTscCompileLike, { @@ -128,7 +147,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const buildHost = createSolutionBuilderHostForBaseline(sys); const builder = ts.createSolutionBuilder(buildHost, ["/src/third/tsconfig.json"], {}); sys.exit(builder.clean("/src/logic2")); - } + }, }); }); @@ -138,7 +157,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { subScenario: "always builds under with force option", fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--force"], - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); }); @@ -162,11 +181,16 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { { caption: "rebuilds when tsconfig changes", edit: fs => { - replaceText(fs, "/src/tests/tsconfig.json", `"composite": true`, `"composite": true, "target": "es2020"`); + replaceText( + fs, + "/src/tests/tsconfig.json", + `"composite": true`, + `"composite": true, "target": "es2020"`, + ); fs.writeFileSync("/lib/lib.es2020.full.d.ts", libContent); }, }, - ] + ], }); verifyTsc({ @@ -182,7 +206,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { fs.utimesSync("/src/core/index.ts", time, time); }, }, - ] + ], }); verifyTsc({ @@ -193,13 +217,25 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { edits: [ { caption: "Disable declarationMap", - edit: fs => replaceText(fs, "/src/core/tsconfig.json", `"declarationMap": true,`, `"declarationMap": false,`), + edit: fs => + replaceText( + fs, + "/src/core/tsconfig.json", + `"declarationMap": true,`, + `"declarationMap": false,`, + ), }, { caption: "Enable declarationMap", - edit: fs => replaceText(fs, "/src/core/tsconfig.json", `"declarationMap": false,`, `"declarationMap": true,`), + edit: fs => + replaceText( + fs, + "/src/core/tsconfig.json", + `"declarationMap": false,`, + `"declarationMap": true,`, + ), }, - ] + ], }); verifyTsc({ @@ -219,16 +255,17 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { verifyTsc({ scenario: "sample1", subScenario: "tsbuildinfo has error", - fs: () => loadProjectFromFiles({ - "/src/project/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": "{}", - "/src/project/tsconfig.tsbuildinfo": "Some random string", - }), + fs: () => + loadProjectFromFiles({ + "/src/project/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": "{}", + "/src/project/tsconfig.tsbuildinfo": "Some random string", + }), commandLineArgs: ["--b", "src/project", "-i", "-v"], edits: [{ caption: "tsbuildinfo written has error", edit: fs => prependText(fs, "/src/project/tsconfig.tsbuildinfo", "Some random string"), - }] + }], }); verifyTscCompileLike(testTscCompileLike, { @@ -241,15 +278,21 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const buildHost = createSolutionBuilderHostForBaseline(sys, "FakeTSCurrentVersion"); const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], { verbose: true }); sys.exit(builder.build()); - } + }, }); verifyTscCompileLike(testTscCompileLike, { scenario: "sample1", - subScenario: "does not rebuild if there is no program and bundle in the ts build info event if version doesnt match ts version", + subScenario: + "does not rebuild if there is no program and bundle in the ts build info event if version doesnt match ts version", fs: () => { const fs = projFs.shadow(); - const host = fakes.SolutionBuilderHost.create(fs, /*options*/ undefined, /*setParentNodes*/ undefined, ts.createAbstractBuilder); + const host = fakes.SolutionBuilderHost.create( + fs, + /*options*/ undefined, + /*setParentNodes*/ undefined, + ts.createAbstractBuilder, + ); const builder = ts.createSolutionBuilder(host, ["/src/tests"], { verbose: true }); builder.build(); fs.makeReadonly(); @@ -270,13 +313,21 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--verbose"], modifyFs: fs => { - fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: { target: "es3" } })); - replaceText(fs, "/src/tests/tsconfig.json", `"references": [`, `"extends": "./tsconfig.base.json", "references": [`); + fs.writeFileSync( + "/src/tests/tsconfig.base.json", + JSON.stringify({ compilerOptions: { target: "es3" } }), + ); + replaceText( + fs, + "/src/tests/tsconfig.json", + `"references": [`, + `"extends": "./tsconfig.base.json", "references": [`, + ); }, edits: [{ caption: "incremental-declaration-changes", - edit: fs => fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: {} })) - }] + edit: fs => fs.writeFileSync("/src/tests/tsconfig.base.json", JSON.stringify({ compilerOptions: {} })), + }], }); verifyTscCompileLike(testTscCompileLike, { @@ -288,7 +339,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const buildHost = createSolutionBuilderHostForBaseline(sys); const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], {}); sys.exit(builder.build("/src/logic/tsconfig.json")); - } + }, }); verifyTscCompileLike(testTscCompileLike, { @@ -300,7 +351,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const buildHost = createSolutionBuilderHostForBaseline(sys); const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], {}); sys.exit(builder.build("/src/logic2/tsconfig.json")); - } + }, }); it("building using getNextInvalidatedProject", () => { @@ -317,12 +368,17 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const system = changeToHostTrackingWrittenFiles( fakes.patchHostForBuildInfoReadWrite( createWatchedSystem([ - coreConfig, coreIndex, coreDecl, coreAnotherModule, - logicConfig, logicIndex, - testsConfig, testsIndex, - libFile - ]) - ) + coreConfig, + coreIndex, + coreDecl, + coreAnotherModule, + logicConfig, + logicIndex, + testsConfig, + testsIndex, + libFile, + ]), + ), ); const host = createSolutionBuilderHostForBaseline(system); @@ -331,9 +387,12 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { baselineState(); verifyBuildNextResult(); // core verifyBuildNextResult(); // logic - verifyBuildNextResult();// tests + verifyBuildNextResult(); // tests verifyBuildNextResult(); // All Done - Harness.Baseline.runBaseline(`tsbuild/sample1/building-using-getNextInvalidatedProject.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tsbuild/sample1/building-using-getNextInvalidatedProject.js`, + baseline.join("\r\n"), + ); function verifyBuildNextResult() { const project = builder.getNextInvalidatedProject(); @@ -359,7 +418,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const buildHost = createSolutionBuilderHostForBaseline(sys); const builder = ts.createSolutionBuilder(buildHost, ["/src/tests"], { verbose: true }); sys.exit(builder.buildReferences("/src/tests")); - } + }, }); }); @@ -370,7 +429,7 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--verbose"], modifyFs: fs => replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`), - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); }); @@ -389,16 +448,25 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const system = changeToHostTrackingWrittenFiles( fakes.patchHostForBuildInfoReadWrite( createWatchedSystem([ - coreConfig, coreIndex, coreDecl, coreAnotherModule, - logicConfig, logicIndex, - testsConfig, testsIndex, - libFile - ]) - ) + coreConfig, + coreIndex, + coreDecl, + coreAnotherModule, + logicConfig, + logicIndex, + testsConfig, + testsIndex, + libFile, + ]), + ), ); const host = createSolutionBuilderHostForBaseline(system); - const builder = ts.createSolutionBuilder(host, [testsConfig.path], { dry: false, force: false, verbose: false }); + const builder = ts.createSolutionBuilder(host, [testsConfig.path], { + dry: false, + force: false, + verbose: false, + }); builder.build(); baselineState("Build of project"); @@ -439,13 +507,23 @@ describe("unittests:: tsbuild:: on 'sample1' project", () => { const coreChanges: TestTscEdit[] = [ { caption: "incremental-declaration-changes", - edit: fs => appendText(fs, "/src/core/index.ts", ` -export class someClass { }`), + edit: fs => + appendText( + fs, + "/src/core/index.ts", + ` +export class someClass { }`, + ), }, { caption: "incremental-declaration-doesnt-change", - edit: fs => appendText(fs, "/src/core/index.ts", ` -class someClass2 { }`), + edit: fs => + appendText( + fs, + "/src/core/index.ts", + ` +class someClass2 { }`, + ), }, noChangeRun, ]; @@ -456,21 +534,21 @@ class someClass2 { }`), subScenario: "listFiles", fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--listFiles"], - edits: coreChanges + edits: coreChanges, }); verifyTsc({ scenario: "sample1", subScenario: "listEmittedFiles", fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--listEmittedFiles"], - edits: coreChanges + edits: coreChanges, }); verifyTsc({ scenario: "sample1", subScenario: "explainFiles", fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--explainFiles", "--v"], - edits: coreChanges + edits: coreChanges, }); }); @@ -486,8 +564,14 @@ class someClass2 { }`), ...coreChanges, { caption: "when logic config changes declaration dir", - edit: fs => replaceText(fs, "/src/logic/tsconfig.json", `"declaration": true,`, `"declaration": true, - "declarationDir": "decls",`), + edit: fs => + replaceText( + fs, + "/src/logic/tsconfig.json", + `"declaration": true,`, + `"declaration": true, + "declarationDir": "decls",`, + ), }, noChangeRun, ], @@ -497,11 +581,17 @@ class someClass2 { }`), scenario: "sample1", subScenario: "when logic specifies tsBuildInfoFile", fs: () => projFs, - modifyFs: fs => replaceText(fs, "/src/logic/tsconfig.json", `"composite": true,`, `"composite": true, - "tsBuildInfoFile": "ownFile.tsbuildinfo",`), + modifyFs: fs => + replaceText( + fs, + "/src/logic/tsconfig.json", + `"composite": true,`, + `"composite": true, + "tsBuildInfoFile": "ownFile.tsbuildinfo",`, + ), commandLineArgs: ["--b", "/src/tests", "--verbose"], baselineSourceMap: true, - baselineReadFileCalls: true + baselineReadFileCalls: true, }); verifyTsc({ @@ -509,15 +599,25 @@ class someClass2 { }`), fs: () => projFs, scenario: "sample1", commandLineArgs: ["--b", "/src/core", "--verbose"], - modifyFs: fs => fs.writeFileSync("/src/core/tsconfig.json", `{ + modifyFs: fs => + fs.writeFileSync( + "/src/core/tsconfig.json", + `{ "compilerOptions": { "incremental": true, "skipDefaultLibCheck": true } -}`), +}`, + ), edits: [{ caption: "incremental-declaration-changes", - edit: fs => replaceText(fs, "/src/core/tsconfig.json", `"incremental": true,`, `"incremental": true, "declaration": true,`), + edit: fs => + replaceText( + fs, + "/src/core/tsconfig.json", + `"incremental": true,`, + `"incremental": true, "declaration": true,`, + ), }], }); @@ -527,19 +627,28 @@ class someClass2 { }`), scenario: "sample1", commandLineArgs: ["--b", "/src/core", "--verbose"], modifyFs: fs => { - fs.writeFileSync("/lib/lib.esnext.full.d.ts", `/// -/// `); + fs.writeFileSync( + "/lib/lib.esnext.full.d.ts", + `/// +/// `, + ); fs.writeFileSync("/lib/lib.esnext.d.ts", libContent); - fs.writeFileSync("/lib/lib.d.ts", `/// -/// `); - fs.writeFileSync("/src/core/tsconfig.json", `{ + fs.writeFileSync( + "/lib/lib.d.ts", + `/// +/// `, + ); + fs.writeFileSync( + "/src/core/tsconfig.json", + `{ "compilerOptions": { "incremental": true, "listFiles": true, "listEmittedFiles": true, "target": "esnext", } -}`); +}`, + ); }, edits: [{ caption: "incremental-declaration-changes", @@ -552,12 +661,16 @@ class someClass2 { }`), fs: () => projFs, scenario: "sample1", commandLineArgs: ["--b", "/src/core", "--verbose"], - modifyFs: fs => fs.writeFileSync("/src/core/tsconfig.json", `{ + modifyFs: fs => + fs.writeFileSync( + "/src/core/tsconfig.json", + `{ "compilerOptions": { "incremental": true, "module": "commonjs" } -}`), +}`, + ), edits: [{ caption: "incremental-declaration-changes", edit: fs => replaceText(fs, "/src/core/tsconfig.json", `"module": "commonjs"`, `"module": "amd"`), @@ -569,7 +682,10 @@ class someClass2 { }`), fs: () => projFs, scenario: "sample1", commandLineArgs: ["--b", "/src/tests", "--verbose"], - modifyFs: fs => fs.writeFileSync("/src/tests/tsconfig.json", `{ + modifyFs: fs => + fs.writeFileSync( + "/src/tests/tsconfig.json", + `{ "references": [ { "path": "../core" }, { "path": "../logic" } @@ -582,10 +698,12 @@ class someClass2 { }`), "skipDefaultLibCheck": true, "esModuleInterop": false } -}`), +}`, + ), edits: [{ caption: "incremental-declaration-changes", - edit: fs => replaceText(fs, "/src/tests/tsconfig.json", `"esModuleInterop": false`, `"esModuleInterop": true`), + edit: fs => + replaceText(fs, "/src/tests/tsconfig.json", `"esModuleInterop": false`, `"esModuleInterop": true`), }], }); @@ -595,12 +713,15 @@ class someClass2 { }`), fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--v"], modifyFs: fs => { - fs.writeFileSync("/src/core/tsconfig.json", JSON.stringify({ - compilerOptions: { composite: true }, - files: ["anotherModule.ts", "index.ts", "some_decl.d.ts"] - })); + fs.writeFileSync( + "/src/core/tsconfig.json", + JSON.stringify({ + compilerOptions: { composite: true }, + files: ["anotherModule.ts", "index.ts", "some_decl.d.ts"], + }), + ); fs.unlinkSync("/src/core/anotherModule.ts"); - } + }, }); verifyTsc({ @@ -609,12 +730,15 @@ class someClass2 { }`), fs: () => projFs, commandLineArgs: ["--b", "/src/tests", "--v", "--f"], modifyFs: fs => { - fs.writeFileSync("/src/core/tsconfig.json", JSON.stringify({ - compilerOptions: { composite: true }, - files: ["anotherModule.ts", "index.ts", "some_decl.d.ts"] - })); + fs.writeFileSync( + "/src/core/tsconfig.json", + JSON.stringify({ + compilerOptions: { composite: true }, + files: ["anotherModule.ts", "index.ts", "some_decl.d.ts"], + }), + ); fs.unlinkSync("/src/core/anotherModule.ts"); - } + }, }); }); }); diff --git a/src/testRunner/unittests/tsbuild/transitiveReferences.ts b/src/testRunner/unittests/tsbuild/transitiveReferences.ts index 37693c8eb5d5a..b75a98f0df8a1 100644 --- a/src/testRunner/unittests/tsbuild/transitiveReferences.ts +++ b/src/testRunner/unittests/tsbuild/transitiveReferences.ts @@ -2,7 +2,9 @@ import * as vfs from "../../_namespaces/vfs"; import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromDisk } from "../helpers/vfs"; +import { + loadProjectFromDisk, +} from "../helpers/vfs"; describe("unittests:: tsbuild:: when project reference is referenced transitively", () => { let projFs: vfs.FileSystem; @@ -14,16 +16,22 @@ describe("unittests:: tsbuild:: when project reference is referenced transitivel }); function modifyFsBTsToNonRelativeImport(fs: vfs.FileSystem, moduleResolution: "node" | "classic") { - fs.writeFileSync("/src/b.ts", `import {A} from 'a'; -export const b = new A();`); - fs.writeFileSync("/src/tsconfig.b.json", JSON.stringify({ - compilerOptions: { - composite: true, - moduleResolution - }, - files: ["b.ts"], - references: [{ path: "tsconfig.a.json" }] - })); + fs.writeFileSync( + "/src/b.ts", + `import {A} from 'a'; +export const b = new A();`, + ); + fs.writeFileSync( + "/src/tsconfig.b.json", + JSON.stringify({ + compilerOptions: { + composite: true, + moduleResolution, + }, + files: ["b.ts"], + references: [{ path: "tsconfig.a.json" }], + }), + ); } verifyTsc({ diff --git a/src/testRunner/unittests/tsbuildWatch/configFileErrors.ts b/src/testRunner/unittests/tsbuildWatch/configFileErrors.ts index 4059cfce11477..1c47250803a00 100644 --- a/src/testRunner/unittests/tsbuildWatch/configFileErrors.ts +++ b/src/testRunner/unittests/tsbuildWatch/configFileErrors.ts @@ -1,5 +1,9 @@ -import { dedent } from "../../_namespaces/Utils"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + dedent, +} from "../../_namespaces/Utils"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { createWatchedSystem, libFile, @@ -9,13 +13,14 @@ describe("unittests:: tsbuildWatch:: watchMode:: configFileErrors:: reports synt verifyTscWatch({ scenario: "configFileErrors", subScenario: "reports syntax errors in config file", - sys: () => createWatchedSystem( - [ - { path: `/user/username/projects/myproject/a.ts`, content: "export function foo() { }" }, - { path: `/user/username/projects/myproject/b.ts`, content: "export function bar() { }" }, - { - path: `/user/username/projects/myproject/tsconfig.json`, - content: dedent` + sys: () => + createWatchedSystem( + [ + { path: `/user/username/projects/myproject/a.ts`, content: "export function foo() { }" }, + { path: `/user/username/projects/myproject/b.ts`, content: "export function bar() { }" }, + { + path: `/user/username/projects/myproject/tsconfig.json`, + content: dedent` { "compilerOptions": { "composite": true, @@ -24,18 +29,23 @@ describe("unittests:: tsbuildWatch:: watchMode:: configFileErrors:: reports synt "a.ts" "b.ts" ] -}` - }, - libFile - ], - { currentDirectory: "/user/username/projects/myproject" } - ), +}`, + }, + libFile, + ], + { currentDirectory: "/user/username/projects/myproject" }, + ), commandLineArgs: ["--b", "-w"], edits: [ { caption: "reports syntax errors after change to config file", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/tsconfig.json`, ",", `, - "declaration": true,`), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/tsconfig.json`, + ",", + `, + "declaration": true,`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // build the project }, { @@ -50,12 +60,16 @@ describe("unittests:: tsbuildWatch:: watchMode:: configFileErrors:: reports synt }, { caption: "builds after fixing config file errors", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ - compilerOptions: { composite: true, declaration: true }, - files: ["a.ts", "b.ts"] - })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ + compilerOptions: { composite: true, declaration: true }, + files: ["a.ts", "b.ts"], + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // build the project - } - ] + }, + ], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/demo.ts b/src/testRunner/unittests/tsbuildWatch/demo.ts index 03b36bcd39cb4..3414d5e0270df 100644 --- a/src/testRunner/unittests/tsbuildWatch/demo.ts +++ b/src/testRunner/unittests/tsbuildWatch/demo.ts @@ -1,5 +1,9 @@ -import { libContent } from "../helpers/contents"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + libContent, +} from "../helpers/contents"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { createWatchedSystem, File, @@ -21,7 +25,10 @@ describe("unittests:: tsbuildWatch:: watchMode:: with demo project", () => { zooFiles = subProjectFiles("zoo", ["tsconfig.json", "zoo.ts"]); solutionFile = projectFile("tsconfig.json"); baseConfig = projectFile("tsconfig-base.json"); - allFiles = [...coreFiles, ...animalFiles, ...zooFiles, solutionFile, baseConfig, { path: libFile.path, content: libContent }]; + allFiles = [...coreFiles, ...animalFiles, ...zooFiles, solutionFile, baseConfig, { + path: libFile.path, + content: libContent, + }]; }); after(() => { @@ -39,15 +46,18 @@ describe("unittests:: tsbuildWatch:: watchMode:: with demo project", () => { commandLineArgs: ["-b", "-w", "-verbose"], sys: () => { const sys = createWatchedSystem(allFiles, { currentDirectory: projectLocation }); - sys.writeFile(coreFiles[0].path, coreFiles[0].content.replace( - "}", - `}, + sys.writeFile( + coreFiles[0].path, + coreFiles[0].content.replace( + "}", + `}, "references": [ { "path": "../zoo" } - ]` - )); + ]`, + ), + ); return sys; }, edits: [ @@ -58,8 +68,8 @@ describe("unittests:: tsbuildWatch:: watchMode:: with demo project", () => { sys.runQueuedTimeoutCallbacks(); // build core sys.runQueuedTimeoutCallbacks(); // build animals, zoo and solution }, - } - ] + }, + ], }); verifyTscWatch({ @@ -68,20 +78,27 @@ describe("unittests:: tsbuildWatch:: watchMode:: with demo project", () => { commandLineArgs: ["-b", "-w", "-verbose"], sys: () => { const sys = createWatchedSystem(allFiles, { currentDirectory: projectLocation }); - sys.writeFile(coreFiles[1].path, `import * as A from '../animals'; -${coreFiles[1].content}`); + sys.writeFile( + coreFiles[1].path, + `import * as A from '../animals'; +${coreFiles[1].content}`, + ); return sys; }, edits: [ { caption: "Prepend a line", - edit: sys => sys.writeFile(coreFiles[1].path, ` + edit: sys => + sys.writeFile( + coreFiles[1].path, + ` import * as A from '../animals'; -${coreFiles[1].content}`), +${coreFiles[1].content}`, + ), // build core timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); function subProjectFiles(subProject: string, fileNames: readonly string[]): File[] { @@ -91,4 +108,4 @@ ${coreFiles[1].content}`), function projectFile(fileName: string): File { return getTsBuildProjectFile("demo", fileName); } -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/libraryResolution.ts b/src/testRunner/unittests/tsbuildWatch/libraryResolution.ts index a6391cdb9b7ee..d34a3ea233be3 100644 --- a/src/testRunner/unittests/tsbuildWatch/libraryResolution.ts +++ b/src/testRunner/unittests/tsbuildWatch/libraryResolution.ts @@ -1,5 +1,9 @@ -import { getSysForLibResolution } from "../helpers/libraryResolution"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + getSysForLibResolution, +} from "../helpers/libraryResolution"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; describe("unittests:: tsbuildWatch:: watchMode:: libraryResolution:: library file resolution", () => { function verify(libRedirection?: true) { @@ -7,7 +11,17 @@ describe("unittests:: tsbuildWatch:: watchMode:: libraryResolution:: library fil scenario: "libraryResolution", subScenario: `with config${libRedirection ? " with redirection" : ""}`, sys: () => getSysForLibResolution(libRedirection), - commandLineArgs: ["-b", "-w", "project1", "project2", "project3", "project4", "--verbose", "--explainFiles", "--extendedDiagnostics"], + commandLineArgs: [ + "-b", + "-w", + "project1", + "project2", + "project3", + "project4", + "--verbose", + "--explainFiles", + "--extendedDiagnostics", + ], }); } verify(); diff --git a/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts b/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts index 141494295eb71..e402ed53be871 100644 --- a/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts +++ b/src/testRunner/unittests/tsbuildWatch/moduleResolution.ts @@ -1,5 +1,9 @@ -import { dedent } from "../../_namespaces/Utils"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + dedent, +} from "../../_namespaces/Utils"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { createWatchedSystem, libFile, @@ -9,42 +13,58 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => { verifyTscWatch({ scenario: "moduleResolutionCache", subScenario: "handles the cache correctly when two projects use different module resolution settings", - sys: () => createWatchedSystem( - [ - { path: `/user/username/projects/myproject/project1/index.ts`, content: `import { foo } from "file";` }, - { path: `/user/username/projects/myproject/project1/node_modules/file/index.d.ts`, content: "export const foo = 10;" }, - { - path: `/user/username/projects/myproject/project1/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { composite: true, types: ["foo", "bar"] }, - files: ["index.ts"] - }) - }, - { path: `/user/username/projects/myproject/project2/index.ts`, content: `import { foo } from "file";` }, - { path: `/user/username/projects/myproject/project2/file.d.ts`, content: "export const foo = 10;" }, - { - path: `/user/username/projects/myproject/project2/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { composite: true, types: ["foo"], moduleResolution: "classic" }, - files: ["index.ts"] - }) - }, - { path: `/user/username/projects/myproject/node_modules/@types/foo/index.d.ts`, content: "export const foo = 10;" }, - { path: `/user/username/projects/myproject/node_modules/@types/bar/index.d.ts`, content: "export const bar = 10;" }, - { - path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ - files: [], - references: [ - { path: "./project1" }, - { path: "./project2" } - ] - }) - }, - libFile - ], - { currentDirectory: "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + [ + { + path: `/user/username/projects/myproject/project1/index.ts`, + content: `import { foo } from "file";`, + }, + { + path: `/user/username/projects/myproject/project1/node_modules/file/index.d.ts`, + content: "export const foo = 10;", + }, + { + path: `/user/username/projects/myproject/project1/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { composite: true, types: ["foo", "bar"] }, + files: ["index.ts"], + }), + }, + { + path: `/user/username/projects/myproject/project2/index.ts`, + content: `import { foo } from "file";`, + }, + { path: `/user/username/projects/myproject/project2/file.d.ts`, content: "export const foo = 10;" }, + { + path: `/user/username/projects/myproject/project2/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { composite: true, types: ["foo"], moduleResolution: "classic" }, + files: ["index.ts"], + }), + }, + { + path: `/user/username/projects/myproject/node_modules/@types/foo/index.d.ts`, + content: "export const foo = 10;", + }, + { + path: `/user/username/projects/myproject/node_modules/@types/bar/index.d.ts`, + content: "export const bar = 10;", + }, + { + path: `/user/username/projects/myproject/tsconfig.json`, + content: JSON.stringify({ + files: [], + references: [ + { path: "./project1" }, + { path: "./project2" }, + ], + }), + }, + libFile, + ], + { currentDirectory: "/user/username/projects/myproject" }, + ), commandLineArgs: ["--b", "-w", "-v"], edits: [ { @@ -52,177 +72,212 @@ describe("unittests:: tsbuildWatch:: watchMode:: moduleResolution", () => { edit: sys => sys.appendFile(`/user/username/projects/myproject/project1/index.ts`, "const bar = 10;"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // build project1 and solution }, - ] + ], }); verifyTscWatch({ scenario: "moduleResolution", - subScenario: `resolves specifier in output declaration file from referenced project correctly with cts and mts extensions`, - sys: () => createWatchedSystem([ - { - path: `/user/username/projects/myproject/packages/pkg1/package.json`, - content: JSON.stringify({ - name: "pkg1", - version: "1.0.0", - main: "build/index.js", - type: "module" - }) - }, - { - path: `/user/username/projects/myproject/packages/pkg1/index.ts`, - content: dedent` + subScenario: + `resolves specifier in output declaration file from referenced project correctly with cts and mts extensions`, + sys: () => + createWatchedSystem([ + { + path: `/user/username/projects/myproject/packages/pkg1/package.json`, + content: JSON.stringify({ + name: "pkg1", + version: "1.0.0", + main: "build/index.js", + type: "module", + }), + }, + { + path: `/user/username/projects/myproject/packages/pkg1/index.ts`, + content: dedent` import type { TheNum } from 'pkg2' - export const theNum: TheNum = 42;` - }, - { - path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { - outDir: "build", - module: "node16", - }, - references: [{ path: "../pkg2" }] - }) - }, - { - path: `/user/username/projects/myproject/packages/pkg2/const.cts`, - content: `export type TheNum = 42;` - }, - { - path: `/user/username/projects/myproject/packages/pkg2/index.ts`, - content: `export type { TheNum } from './const.cjs';` - }, - { - path: `/user/username/projects/myproject/packages/pkg2/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { - composite: true, - outDir: "build", - module: "node16", - } - }) - }, - { - path: `/user/username/projects/myproject/packages/pkg2/package.json`, - content: JSON.stringify({ - name: "pkg2", - version: "1.0.0", - main: "build/index.js", - type: "module" - }) - }, - { - path: `/user/username/projects/myproject/node_modules/pkg2`, - symLink: `/user/username/projects/myproject/packages/pkg2`, - }, - { ...libFile, path: `/a/lib/lib.es2022.full.d.ts` } - ], { currentDirectory: "/user/username/projects/myproject" }), + export const theNum: TheNum = 42;`, + }, + { + path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + outDir: "build", + module: "node16", + }, + references: [{ path: "../pkg2" }], + }), + }, + { + path: `/user/username/projects/myproject/packages/pkg2/const.cts`, + content: `export type TheNum = 42;`, + }, + { + path: `/user/username/projects/myproject/packages/pkg2/index.ts`, + content: `export type { TheNum } from './const.cjs';`, + }, + { + path: `/user/username/projects/myproject/packages/pkg2/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + composite: true, + outDir: "build", + module: "node16", + }, + }), + }, + { + path: `/user/username/projects/myproject/packages/pkg2/package.json`, + content: JSON.stringify({ + name: "pkg2", + version: "1.0.0", + main: "build/index.js", + type: "module", + }), + }, + { + path: `/user/username/projects/myproject/node_modules/pkg2`, + symLink: `/user/username/projects/myproject/packages/pkg2`, + }, + { ...libFile, path: `/a/lib/lib.es2022.full.d.ts` }, + ], { currentDirectory: "/user/username/projects/myproject" }), commandLineArgs: ["-b", "packages/pkg1", "-w", "--verbose", "--traceResolution"], edits: [ { caption: "reports import errors after change to package file", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"module"`, `"commonjs"`), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/packages/pkg1/package.json`, + `"module"`, + `"commonjs"`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "removes those errors when a package file is changed back", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"commonjs"`, `"module"`), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/packages/pkg1/package.json`, + `"commonjs"`, + `"module"`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "reports import errors after change to package file", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg1/package.json`, `"module"`, `"commonjs"`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/packages/pkg1/package.json`, + `"module"`, + `"commonjs"`, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "removes those errors when a package file is changed to cjs extensions", edit: sys => { - sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `"build/index.js"`, `"build/index.cjs"`); - sys.renameFile(`/user/username/projects/myproject/packages/pkg2/index.ts`, `/user/username/projects/myproject/packages/pkg2/index.cts`); + sys.replaceFileText( + `/user/username/projects/myproject/packages/pkg2/package.json`, + `"build/index.js"`, + `"build/index.cjs"`, + ); + sys.renameFile( + `/user/username/projects/myproject/packages/pkg2/index.ts`, + `/user/username/projects/myproject/packages/pkg2/index.cts`, + ); }, timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // building pkg2 sys.runQueuedTimeoutCallbacks(); // building pkg1 }, }, - ] + ], }); verifyTscWatch({ scenario: "moduleResolution", subScenario: `build mode watches for changes to package-json main fields`, - sys: () => createWatchedSystem([ - { - path: `/user/username/projects/myproject/packages/pkg1/package.json`, - content: JSON.stringify({ - name: "pkg1", - version: "1.0.0", - main: "build/index.js", - }) - }, - { - path: `/user/username/projects/myproject/packages/pkg1/index.ts`, - content: dedent` + sys: () => + createWatchedSystem([ + { + path: `/user/username/projects/myproject/packages/pkg1/package.json`, + content: JSON.stringify({ + name: "pkg1", + version: "1.0.0", + main: "build/index.js", + }), + }, + { + path: `/user/username/projects/myproject/packages/pkg1/index.ts`, + content: dedent` import type { TheNum } from 'pkg2' - export const theNum: TheNum = 42;` - }, - { - path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { - outDir: "build", - }, - references: [{ path: "../pkg2" }] - }) - }, - { - path: `/user/username/projects/myproject/packages/pkg2/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { - composite: true, - outDir: "build", - baseUrl: ".", - } - }) - }, - { - path: `/user/username/projects/myproject/packages/pkg2/const.ts`, - content: `export type TheNum = 42;` - }, - { - path: `/user/username/projects/myproject/packages/pkg2/index.ts`, - content: `export type { TheNum } from './const.js';` - }, - { - path: `/user/username/projects/myproject/packages/pkg2/other.ts`, - content: `export type TheStr = string;` - }, - { - path: `/user/username/projects/myproject/packages/pkg2/package.json`, - content: JSON.stringify({ - name: "pkg2", - version: "1.0.0", - main: "build/index.js", - }) - }, - { - path: `/user/username/projects/myproject/node_modules/pkg2`, - symLink: `/user/username/projects/myproject/packages/pkg2`, - }, - libFile - ], { currentDirectory: "/user/username/projects/myproject" }), + export const theNum: TheNum = 42;`, + }, + { + path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + outDir: "build", + }, + references: [{ path: "../pkg2" }], + }), + }, + { + path: `/user/username/projects/myproject/packages/pkg2/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + composite: true, + outDir: "build", + baseUrl: ".", + }, + }), + }, + { + path: `/user/username/projects/myproject/packages/pkg2/const.ts`, + content: `export type TheNum = 42;`, + }, + { + path: `/user/username/projects/myproject/packages/pkg2/index.ts`, + content: `export type { TheNum } from './const.js';`, + }, + { + path: `/user/username/projects/myproject/packages/pkg2/other.ts`, + content: `export type TheStr = string;`, + }, + { + path: `/user/username/projects/myproject/packages/pkg2/package.json`, + content: JSON.stringify({ + name: "pkg2", + version: "1.0.0", + main: "build/index.js", + }), + }, + { + path: `/user/username/projects/myproject/node_modules/pkg2`, + symLink: `/user/username/projects/myproject/packages/pkg2`, + }, + libFile, + ], { currentDirectory: "/user/username/projects/myproject" }), commandLineArgs: ["-b", "packages/pkg1", "--verbose", "-w", "--traceResolution"], edits: [ { caption: "reports import errors after change to package file", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `index.js`, `other.js`), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/packages/pkg2/package.json`, + `index.js`, + `other.js`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "removes those errors when a package file is changed back", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `other.js`, `index.js`), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/packages/pkg2/package.json`, + `other.js`, + `index.js`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/noEmit.ts b/src/testRunner/unittests/tsbuildWatch/noEmit.ts index 68ebaa759e024..f8b43fb52e1cd 100644 --- a/src/testRunner/unittests/tsbuildWatch/noEmit.ts +++ b/src/testRunner/unittests/tsbuildWatch/noEmit.ts @@ -1,5 +1,9 @@ -import { libContent } from "../helpers/contents"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + libContent, +} from "../helpers/contents"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { createWatchedSystem, libFile, @@ -10,19 +14,27 @@ describe("unittests:: tsbuildWatch:: watchMode:: with noEmit", () => { scenario: "noEmit", subScenario: "does not go in loop when watching when no files are emitted", commandLineArgs: ["-b", "-w", "-verbose"], - sys: () => createWatchedSystem( - [ - { path: libFile.path, content: libContent }, - { path: `/user/username/projects/myproject/a.js`, content: "" }, - { path: `/user/username/projects/myproject/b.ts`, content: "" }, - { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { allowJs: true, noEmit: true } }) }, - ], - { currentDirectory: "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + [ + { path: libFile.path, content: libContent }, + { path: `/user/username/projects/myproject/a.js`, content: "" }, + { path: `/user/username/projects/myproject/b.ts`, content: "" }, + { + path: `/user/username/projects/myproject/tsconfig.json`, + content: JSON.stringify({ compilerOptions: { allowJs: true, noEmit: true } }), + }, + ], + { currentDirectory: "/user/username/projects/myproject" }, + ), edits: [ { caption: "No change", - edit: sys => sys.writeFile(`/user/username/projects/myproject/a.js`, sys.readFile(`/user/username/projects/myproject/a.js`)!), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/a.js`, + sys.readFile(`/user/username/projects/myproject/a.js`)!, + ), // build project timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, @@ -33,6 +45,6 @@ describe("unittests:: tsbuildWatch:: watchMode:: with noEmit", () => { timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], - baselineIncremental: true + baselineIncremental: true, }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts b/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts index 5a08e0cdbbdc2..c6dda491c3257 100644 --- a/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts +++ b/src/testRunner/unittests/tsbuildWatch/noEmitOnError.ts @@ -1,4 +1,6 @@ -import { libContent } from "../helpers/contents"; +import { + libContent, +} from "../helpers/contents"; import { TscWatchCompileChange, verifyTscWatch, @@ -21,7 +23,11 @@ describe("unittests:: tsbuildWatch:: watchMode:: with noEmitOnError", () => { const noChange: TscWatchCompileChange = { caption: "No change", - edit: sys => sys.writeFile(`/user/username/projects/noEmitOnError/src/main.ts`, sys.readFile(`/user/username/projects/noEmitOnError/src/main.ts`)!), + edit: sys => + sys.writeFile( + `/user/username/projects/noEmitOnError/src/main.ts`, + sys.readFile(`/user/username/projects/noEmitOnError/src/main.ts`)!, + ), // build project timeouts: sys => sys.runQueuedTimeoutCallbacks(), }; @@ -29,27 +35,37 @@ describe("unittests:: tsbuildWatch:: watchMode:: with noEmitOnError", () => { scenario: "noEmitOnError", subScenario: "does not emit any files on error", commandLineArgs: ["-b", "-w", "-verbose"], - sys: () => createWatchedSystem( - [ - ...["tsconfig.json", "shared/types/db.ts", "src/main.ts", "src/other.ts"] - .map(f => getTsBuildProjectFile("noEmitOnError", f)), - { path: libFile.path, content: libContent } - ], - { currentDirectory: `/user/username/projects/noEmitOnError` } - ), + sys: () => + createWatchedSystem( + [ + ...["tsconfig.json", "shared/types/db.ts", "src/main.ts", "src/other.ts"] + .map(f => getTsBuildProjectFile("noEmitOnError", f)), + { path: libFile.path, content: libContent }, + ], + { currentDirectory: `/user/username/projects/noEmitOnError` }, + ), edits: [ noChange, - change("Fix Syntax error", `import { A } from "../shared/types/db"; + change( + "Fix Syntax error", + `import { A } from "../shared/types/db"; const a = { lastName: 'sdsd' -};`), - change("Semantic Error", `import { A } from "../shared/types/db"; -const a: string = 10;`), +};`, + ), + change( + "Semantic Error", + `import { A } from "../shared/types/db"; +const a: string = 10;`, + ), noChange, - change("Fix Semantic Error", `import { A } from "../shared/types/db"; -const a: string = "hello";`), + change( + "Fix Semantic Error", + `import { A } from "../shared/types/db"; +const a: string = "hello";`, + ), noChange, ], - baselineIncremental: true + baselineIncremental: true, }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/programUpdates.ts b/src/testRunner/unittests/tsbuildWatch/programUpdates.ts index 0352a1b571147..2fb740fee2ef2 100644 --- a/src/testRunner/unittests/tsbuildWatch/programUpdates.ts +++ b/src/testRunner/unittests/tsbuildWatch/programUpdates.ts @@ -22,11 +22,16 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => { core = "core", logic = "logic", tests = "tests", - ui = "ui" + ui = "ui", } type ReadonlyFile = Readonly; /** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */ - type SubProjectFiles = [tsconfig: ReadonlyFile, index: ReadonlyFile] | [tsconfig: ReadonlyFile, index: ReadonlyFile, anotherModule: ReadonlyFile, someDecl: ReadonlyFile]; + type SubProjectFiles = [tsconfig: ReadonlyFile, index: ReadonlyFile] | [ + tsconfig: ReadonlyFile, + index: ReadonlyFile, + anotherModule: ReadonlyFile, + someDecl: ReadonlyFile, + ]; function projectFilePath(subProject: SubProject, baseFileName: string) { return `${getTsBuildProjectFilePath("sample1", subProject)}/${baseFileName.toLowerCase()}`; } @@ -46,10 +51,18 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => { return [tsconfig, index, anotherModule, someDecl]; } - function changeFile(fileName: string | (() => string), content: string | (() => string), caption: string): TscWatchCompileChange { + function changeFile( + fileName: string | (() => string), + content: string | (() => string), + caption: string, + ): TscWatchCompileChange { return { caption, - edit: sys => sys.writeFile(ts.isString(fileName) ? fileName : fileName(), ts.isString(content) ? content : content()), + edit: sys => + sys.writeFile( + ts.isString(fileName) ? fileName : fileName(), + ts.isString(content) ? content : content(), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Builds core }; } @@ -88,9 +101,13 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => { }); it("verify building references watches only those projects", () => { - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(allFiles, { currentDirectory: "/user/username/projects" })); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem(allFiles, { currentDirectory: "/user/username/projects" }), + ); const host = createSolutionBuilderWithWatchHostForBaseline(sys, cb); - const solutionBuilder = ts.createSolutionBuilderWithWatch(host, [`sample1/${SubProject.tests}`], { watch: true }); + const solutionBuilder = ts.createSolutionBuilderWithWatch(host, [`sample1/${SubProject.tests}`], { + watch: true, + }); solutionBuilder.buildReferences(`sample1/${SubProject.tests}`); runWatchBaseline({ scenario: "programUpdates", @@ -100,7 +117,7 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => { baseline, oldSnap, getPrograms, - watchOrSolution: solutionBuilder + watchOrSolution: solutionBuilder, }); }); @@ -108,7 +125,7 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => { const newFileWithoutExtension = "newFile"; const newFile: File = { path: projectFilePath(SubProject.core, `${newFileWithoutExtension}.ts`), - content: `export const newFileConst = 30;` + content: `export const newFileConst = 30;`, }; function verifyProjectChanges(subScenario: string, allFilesGetter: () => readonly File[]) { @@ -122,12 +139,14 @@ describe("unittests:: tsbuildWatch:: watchMode:: program updates", () => { scenario: "programUpdates", subScenario: `${subScenario}/change builds changes and reports found errors message`, commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], - sys: () => createWatchedSystem( - allFilesGetter(), - { currentDirectory: "/user/username/projects" } - ), + sys: () => + createWatchedSystem( + allFilesGetter(), + { currentDirectory: "/user/username/projects" }, + ), edits: [ - changeCore(() => `${core[1].content} + changeCore(() => + `${core[1].content} export class someClass { }`, "Make change to core"), buildLogicAndTests, // Another change requeues and builds it @@ -141,27 +160,32 @@ export class someClass { }`; sys.writeFile(core[1].path, change1); assert.equal(sys.writtenFiles.size, 1); sys.writtenFiles.clear(); - sys.writeFile(core[1].path, `${change1} -export class someClass2 { }`); + sys.writeFile( + core[1].path, + `${change1} +export class someClass2 { }`, + ); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Builds core }, buildLogicAndTests, - ] + ], }); verifyTscWatch({ scenario: "programUpdates", subScenario: `${subScenario}/non local change does not start build of referencing projects`, commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], - sys: () => createWatchedSystem( - allFilesGetter(), - { currentDirectory: "/user/username/projects" } - ), + sys: () => + createWatchedSystem( + allFilesGetter(), + { currentDirectory: "/user/username/projects" }, + ), edits: [ - changeCore(() => `${core[1].content} + changeCore(() => + `${core[1].content} function foo() { }`, "Make local change to core"), - ] + ], }); function changeNewFile(newFileContent: string) { @@ -171,24 +195,25 @@ function foo() { }`, "Make local change to core"), scenario: "programUpdates", subScenario: `${subScenario}/builds when new file is added, and its subsequent updates`, commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], - sys: () => createWatchedSystem( - allFilesGetter(), - { currentDirectory: "/user/username/projects" } - ), + sys: () => + createWatchedSystem( + allFilesGetter(), + { currentDirectory: "/user/username/projects" }, + ), edits: [ changeNewFile(newFile.content), buildLogicAndTests, changeNewFile(`${newFile.content} export class someClass2 { }`), buildLogicAndTests, - ] + ], }); } describe("with simple project reference graph", () => { verifyProjectChanges( "with simple project reference graph", - () => allFiles + () => allFiles, ); }); @@ -201,11 +226,11 @@ export class someClass2 { }`), path: coreTsconfig.path, content: JSON.stringify({ compilerOptions: { composite: true, declaration: true }, - references: [{ path: "../tests", circular: true }] - }) + references: [{ path: "../tests", circular: true }], + }), }; return [libFile, circularCoreConfig, ...otherCoreFiles, ...logic, ...tests]; - } + }, ); }); }); @@ -214,10 +239,11 @@ export class someClass2 { }`), scenario: "programUpdates", subScenario: "watches config files that are not present", commandLineArgs: ["-b", "-w", `sample1/${SubProject.tests}`], - sys: () => createWatchedSystem( - [libFile, ...core, logic[1], ...tests], - { currentDirectory: "/user/username/projects" } - ), + sys: () => + createWatchedSystem( + [libFile, ...core, logic[1], ...tests], + { currentDirectory: "/user/username/projects" }, + ), edits: [ { caption: "Write logic tsconfig and build logic", @@ -229,8 +255,8 @@ export class someClass2 { }`), edit: ts.noop, // Build tests timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); describe("when referenced using prepend, builds referencing project even for non local change", () => { @@ -238,7 +264,7 @@ export class someClass2 { }`), before(() => { coreIndex = { path: core[1].path, - content: `function foo() { return 10; }` + content: `function foo() { return 10; }`, }; }); after(() => { @@ -258,30 +284,39 @@ export class someClass2 { }`), const coreTsConfig: File = { path: core[0].path, content: JSON.stringify({ - compilerOptions: { composite: true, declaration: true, outFile: "index.js" } - }) + compilerOptions: { composite: true, declaration: true, outFile: "index.js" }, + }), }; const logicTsConfig: File = { path: logic[0].path, content: JSON.stringify({ - compilerOptions: { ignoreDeprecations: "5.0", composite: true, declaration: true, outFile: "index.js" }, - references: [{ path: "../core", prepend: true }] - }) + compilerOptions: { + ignoreDeprecations: "5.0", + composite: true, + declaration: true, + outFile: "index.js", + }, + references: [{ path: "../core", prepend: true }], + }), }; const logicIndex: File = { path: logic[1].path, - content: `function bar() { return foo() + 1 };` + content: `function bar() { return foo() + 1 };`, }; - return createWatchedSystem([libFile, coreTsConfig, coreIndex, logicTsConfig, logicIndex], { currentDirectory: "/user/username/projects" }); + return createWatchedSystem([libFile, coreTsConfig, coreIndex, logicTsConfig, logicIndex], { + currentDirectory: "/user/username/projects", + }); }, edits: [ - changeCore(() => `${coreIndex.content} + changeCore(() => + `${coreIndex.content} function myFunc() { return 10; }`, "Make non local change and build core"), buildLogic, - changeCore(() => `${coreIndex.content} + changeCore(() => + `${coreIndex.content} function myFunc() { return 100; }`, "Make local change and build core"), buildLogic, - ] + ], }); }); @@ -300,7 +335,7 @@ export function createSomeObject(): SomeObject return { message: "new Object" }; -}` +}`, }; verifyTscWatch({ scenario: "programUpdates", @@ -309,17 +344,17 @@ export function createSomeObject(): SomeObject sys: () => { const libraryTsconfig: File = { path: `${subProjectLibrary}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true } }) + content: JSON.stringify({ compilerOptions: { composite: true } }), }; const subProjectApp = `${"/user/username/projects"}/sample1/App`; const appTs: File = { path: `${subProjectApp}/app.ts`, content: `import { createSomeObject } from "../Library/library"; -createSomeObject().message;` +createSomeObject().message;`, }; const appTsconfig: File = { path: `${subProjectApp}/tsconfig.json`, - content: JSON.stringify({ references: [{ path: "../Library" }] }) + content: JSON.stringify({ references: [{ path: "../Library" }] }), }; const files = [libFile, libraryTs, libraryTsconfig, appTs, appTsconfig]; @@ -344,9 +379,8 @@ createSomeObject().message;` sys.runQueuedTimeoutCallbacks(); // Build App }, }, - ] + ], }); - }); describe("reports errors in all projects on incremental compile", () => { @@ -359,19 +393,27 @@ createSomeObject().message;` edits: [ { caption: "change logic", - edit: sys => sys.writeFile(logic[1].path, `${logic[1].content} -let y: string = 10;`), + edit: sys => + sys.writeFile( + logic[1].path, + `${logic[1].content} +let y: string = 10;`, + ), // Builds logic timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "change core", - edit: sys => sys.writeFile(core[1].path, `${core[1].content} -let x: string = 10;`), + edit: sys => + sys.writeFile( + core[1].path, + `${core[1].content} +let x: string = 10;`, + ), // Builds core timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); } verifyIncrementalErrors("when preserveWatchOutput is not used", ts.emptyArray); @@ -386,19 +428,19 @@ let x: string = 10;`), content: `export var myClassWithError = class { tags() { } private p = 12 - };` + };`, }; const fileWithFixedError: File = { path: fileWithError.path, - content: fileWithError.content.replace("private p = 12", "") + content: fileWithError.content.replace("private p = 12", ""), }; const fileWithoutError: File = { path: `${subProjectLocation}/fileWithoutError.ts`, - content: `export class myClass { }` + content: `export class myClass { }`, }; const tsconfig: File = { path: `${subProjectLocation}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true } }) + content: JSON.stringify({ compilerOptions: { composite: true } }), }; const fixError: TscWatchCompileChange = { @@ -410,7 +452,8 @@ let x: string = 10;`), const changeFileWithoutError: TscWatchCompileChange = { caption: "Change fileWithoutError", - edit: sys => sys.writeFile(fileWithoutError.path, fileWithoutError.content.replace(/myClass/g, "myClass2")), + edit: sys => + sys.writeFile(fileWithoutError.path, fileWithoutError.content.replace(/myClass/g, "myClass2")), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }; @@ -418,26 +461,28 @@ let x: string = 10;`), scenario: "programUpdates", subScenario: "reportErrors/declarationEmitErrors/when fixing error files all files are emitted", commandLineArgs: ["-b", "-w", subProject], - sys: () => createWatchedSystem( - [libFile, fileWithError, fileWithoutError, tsconfig], - { currentDirectory: `${"/user/username/projects"}/${solution}` } - ), + sys: () => + createWatchedSystem( + [libFile, fileWithError, fileWithoutError, tsconfig], + { currentDirectory: `${"/user/username/projects"}/${solution}` }, + ), edits: [ - fixError - ] + fixError, + ], }); verifyTscWatch({ scenario: "programUpdates", subScenario: "reportErrors/declarationEmitErrors/when file with no error changes", commandLineArgs: ["-b", "-w", subProject], - sys: () => createWatchedSystem( - [libFile, fileWithError, fileWithoutError, tsconfig], - { currentDirectory: `${"/user/username/projects"}/${solution}` } - ), + sys: () => + createWatchedSystem( + [libFile, fileWithError, fileWithoutError, tsconfig], + { currentDirectory: `${"/user/username/projects"}/${solution}` }, + ), edits: [ - changeFileWithoutError - ] + changeFileWithoutError, + ], }); describe("when reporting errors on introducing error", () => { @@ -449,30 +494,33 @@ let x: string = 10;`), verifyTscWatch({ scenario: "programUpdates", - subScenario: "reportErrors/declarationEmitErrors/introduceError/when fixing errors only changed file is emitted", + subScenario: + "reportErrors/declarationEmitErrors/introduceError/when fixing errors only changed file is emitted", commandLineArgs: ["-b", "-w", subProject], - sys: () => createWatchedSystem( - [libFile, fileWithFixedError, fileWithoutError, tsconfig], - { currentDirectory: `${"/user/username/projects"}/${solution}` } - ), + sys: () => + createWatchedSystem( + [libFile, fileWithFixedError, fileWithoutError, tsconfig], + { currentDirectory: `${"/user/username/projects"}/${solution}` }, + ), edits: [ introduceError, - fixError - ] + fixError, + ], }); verifyTscWatch({ scenario: "programUpdates", subScenario: "reportErrors/declarationEmitErrors/introduceError/when file with no error changes", commandLineArgs: ["-b", "-w", subProject], - sys: () => createWatchedSystem( - [libFile, fileWithFixedError, fileWithoutError, tsconfig], - { currentDirectory: `${"/user/username/projects"}/${solution}` } - ), + sys: () => + createWatchedSystem( + [libFile, fileWithFixedError, fileWithoutError, tsconfig], + { currentDirectory: `${"/user/username/projects"}/${solution}` }, + ), edits: [ introduceError, - changeFileWithoutError - ] + changeFileWithoutError, + ], }); }); }); @@ -486,19 +534,27 @@ let x: string = 10;`), edits: [ { caption: "Make non dts change", - edit: sys => sys.writeFile(logic[1].path, `${logic[1].content} -function someFn() { }`), + edit: sys => + sys.writeFile( + logic[1].path, + `${logic[1].content} +function someFn() { }`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // build logic and updates tests }, { caption: "Make dts change", - edit: sys => sys.writeFile(logic[1].path, `${logic[1].content} -export function someFn() { }`), + edit: sys => + sys.writeFile( + logic[1].path, + `${logic[1].content} +export function someFn() { }`, + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // build logic sys.runQueuedTimeoutCallbacks(); // build tests }, - } + }, ], }); @@ -509,29 +565,35 @@ export function someFn() { }`), sys: () => { const index: File = { path: `/user/username/projects/myproject/index.ts`, - content: `const fn = (a: string, b: string) => b;` + content: `const fn = (a: string, b: string) => b;`, }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - noUnusedParameters: true - } - }) + noUnusedParameters: true, + }, + }), }; - return createWatchedSystem([index, configFile, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([index, configFile, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Change tsconfig to set noUnusedParameters to false", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ - compilerOptions: { - noUnusedParameters: false - } - })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ + compilerOptions: { + noUnusedParameters: false, + }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -544,10 +606,10 @@ export function someFn() { }`), { caption: "Add new file", edit: sys => sys.writeFile(`sample1/${SubProject.core}/file3.ts`, `export const y = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, noopChange, - ] + ], }); verifyTscWatch({ @@ -556,28 +618,40 @@ export function someFn() { }`), commandLineArgs: ["-b", "-w", `sample1/${SubProject.core}`, "-verbose"], sys: () => { const [coreConfig, ...rest] = core; - const newCoreConfig: File = { path: coreConfig.path, content: JSON.stringify({ compilerOptions: { composite: true, outDir: "outDir" } }) }; - return createWatchedSystem([libFile, newCoreConfig, ...rest], { currentDirectory: "/user/username/projects" }); + const newCoreConfig: File = { + path: coreConfig.path, + content: JSON.stringify({ compilerOptions: { composite: true, outDir: "outDir" } }), + }; + return createWatchedSystem([libFile, newCoreConfig, ...rest], { + currentDirectory: "/user/username/projects", + }); }, edits: [ noopChange, { caption: "Add new file", edit: sys => sys.writeFile(`sample1/${SubProject.core}/file3.ts`, `export const y = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - noopChange - ] + noopChange, + ], }); verifyTscWatch({ scenario: "programUpdates", subScenario: "works with extended source files", - commandLineArgs: ["-b", "-w", "-v", "project1.tsconfig.json", "project2.tsconfig.json", "project3.tsconfig.json"], + commandLineArgs: [ + "-b", + "-w", + "-v", + "project1.tsconfig.json", + "project2.tsconfig.json", + "project3.tsconfig.json", + ], sys: () => { const alphaExtendedConfigFile: File = { path: "/a/b/alpha.tsconfig.json", - content: "{}" + content: "{}", }; const project1Config: File = { path: "/a/b/project1.tsconfig.json", @@ -586,14 +660,14 @@ export function someFn() { }`), compilerOptions: { composite: true, }, - files: [commonFile1.path, commonFile2.path] - }) + files: [commonFile1.path, commonFile2.path], + }), }; const bravoExtendedConfigFile: File = { path: "/a/b/bravo.tsconfig.json", content: JSON.stringify({ - extends: "./alpha.tsconfig.json" - }) + extends: "./alpha.tsconfig.json", + }), }; const otherFile: File = { path: "/a/b/other.ts", @@ -606,8 +680,8 @@ export function someFn() { }`), compilerOptions: { composite: true, }, - files: [otherFile.path] - }) + files: [otherFile.path], + }), }; const otherFile2: File = { path: "/a/b/other2.ts", @@ -618,49 +692,66 @@ export function someFn() { }`), content: JSON.stringify({ compilerOptions: { composite: true, - } - }) + }, + }), }; const extendsConfigFile2: File = { path: "/a/b/extendsConfig2.tsconfig.json", content: JSON.stringify({ compilerOptions: { strictNullChecks: false, - } - }) + }, + }), }; const extendsConfigFile3: File = { path: "/a/b/extendsConfig3.tsconfig.json", content: JSON.stringify({ compilerOptions: { noImplicitAny: true, - } - }) + }, + }), }; const project3Config: File = { path: "/a/b/project3.tsconfig.json", content: JSON.stringify({ - extends: ["./extendsConfig1.tsconfig.json", "./extendsConfig2.tsconfig.json", "./extendsConfig3.tsconfig.json"], + extends: [ + "./extendsConfig1.tsconfig.json", + "./extendsConfig2.tsconfig.json", + "./extendsConfig3.tsconfig.json", + ], compilerOptions: { composite: false, }, - files: [otherFile2.path] - }) + files: [otherFile2.path], + }), }; return createWatchedSystem([ libFile, - alphaExtendedConfigFile, project1Config, commonFile1, commonFile2, - bravoExtendedConfigFile, project2Config, otherFile, otherFile2, - extendsConfigFile1, extendsConfigFile2, extendsConfigFile3, project3Config + alphaExtendedConfigFile, + project1Config, + commonFile1, + commonFile2, + bravoExtendedConfigFile, + project2Config, + otherFile, + otherFile2, + extendsConfigFile1, + extendsConfigFile2, + extendsConfigFile3, + project3Config, ], { currentDirectory: "/a/b" }); }, edits: [ { caption: "Modify alpha config", - edit: sys => sys.writeFile("/a/b/alpha.tsconfig.json", JSON.stringify({ - compilerOptions: { strict: true } - })), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build project1 + edit: sys => + sys.writeFile( + "/a/b/alpha.tsconfig.json", + JSON.stringify({ + compilerOptions: { strict: true }, + }), + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build project1 }, { caption: "Build project 2", @@ -669,17 +760,25 @@ export function someFn() { }`), }, { caption: "change bravo config", - edit: sys => sys.writeFile("/a/b/bravo.tsconfig.json", JSON.stringify({ - extends: "./alpha.tsconfig.json", - compilerOptions: { strict: false } - })), + edit: sys => + sys.writeFile( + "/a/b/bravo.tsconfig.json", + JSON.stringify({ + extends: "./alpha.tsconfig.json", + compilerOptions: { strict: false }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build project2 }, { caption: "project 2 extends alpha", - edit: sys => sys.writeFile("/a/b/project2.tsconfig.json", JSON.stringify({ - extends: "./alpha.tsconfig.json", - })), + edit: sys => + sys.writeFile( + "/a/b/project2.tsconfig.json", + JSON.stringify({ + extends: "./alpha.tsconfig.json", + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build project2 }, { @@ -694,25 +793,33 @@ export function someFn() { }`), }, { caption: "Modify extendsConfigFile2", - edit: sys => sys.writeFile("/a/b/extendsConfig2.tsconfig.json", JSON.stringify({ - compilerOptions: { strictNullChecks: true } - })), + edit: sys => + sys.writeFile( + "/a/b/extendsConfig2.tsconfig.json", + JSON.stringify({ + compilerOptions: { strictNullChecks: true }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build project3 }, { caption: "Modify project 3", - edit: sys => sys.writeFile("/a/b/project3.tsconfig.json", JSON.stringify({ - extends: ["./extendsConfig1.tsconfig.json", "./extendsConfig2.tsconfig.json"], - compilerOptions: { composite: false }, - files: ["/a/b/other2.ts"] - })), + edit: sys => + sys.writeFile( + "/a/b/project3.tsconfig.json", + JSON.stringify({ + extends: ["./extendsConfig1.tsconfig.json", "./extendsConfig2.tsconfig.json"], + compilerOptions: { composite: false }, + files: ["/a/b/other2.ts"], + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build project3 }, { caption: "Delete extendedConfigFile2 and report error", edit: sys => sys.deleteFile("./extendsConfig2.tsconfig.json"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build project3 - } + }, ], }); @@ -725,9 +832,9 @@ export function someFn() { }`), path: "/a/b/alpha.tsconfig.json", content: JSON.stringify({ compilerOptions: { - strict: true - } - }) + strict: true, + }, + }), }; const project1Config: File = { path: "/a/b/project1.tsconfig.json", @@ -736,16 +843,16 @@ export function someFn() { }`), compilerOptions: { composite: true, }, - files: [commonFile1.path, commonFile2.path] - }) + files: [commonFile1.path, commonFile2.path], + }), }; const bravoExtendedConfigFile: File = { path: "/a/b/bravo.tsconfig.json", content: JSON.stringify({ compilerOptions: { - strict: true - } - }) + strict: true, + }, + }), }; const otherFile: File = { path: "/a/b/other.ts", @@ -758,8 +865,8 @@ export function someFn() { }`), compilerOptions: { composite: true, }, - files: [otherFile.path] - }) + files: [otherFile.path], + }), }; const configFile: File = { path: "/a/b/tsconfig.json", @@ -773,39 +880,50 @@ export function someFn() { }`), }, ], files: [], - }) + }), }; return createWatchedSystem([ - libFile, configFile, - alphaExtendedConfigFile, project1Config, commonFile1, commonFile2, - bravoExtendedConfigFile, project2Config, otherFile + libFile, + configFile, + alphaExtendedConfigFile, + project1Config, + commonFile1, + commonFile2, + bravoExtendedConfigFile, + project2Config, + otherFile, ], { currentDirectory: "/a/b" }); }, edits: [ { caption: "Remove project2 from base config", - edit: sys => sys.modifyFile("/a/b/tsconfig.json", JSON.stringify({ - references: [ - { - path: "./project1.tsconfig.json", - }, - ], - files: [], - })), + edit: sys => + sys.modifyFile( + "/a/b/tsconfig.json", + JSON.stringify({ + references: [ + { + path: "./project1.tsconfig.json", + }, + ], + files: [], + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ scenario: "programUpdates", subScenario: "tsbuildinfo has error", - sys: () => createWatchedSystem({ - "/src/project/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": "{}", - "/src/project/tsconfig.tsbuildinfo": "Some random string", - [libFile.path]: libFile.content, - }), + sys: () => + createWatchedSystem({ + "/src/project/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": "{}", + "/src/project/tsconfig.tsbuildinfo": "Some random string", + [libFile.path]: libFile.content, + }), commandLineArgs: ["--b", "src/project", "-i", "-w"], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts b/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts index 0968b40bdef0e..4648a2f6233c1 100644 --- a/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts +++ b/src/testRunner/unittests/tsbuildWatch/projectsBuilding.ts @@ -25,17 +25,17 @@ describe("unittests:: tsbuildWatch:: watchMode:: projectsBuilding", () => { return [ { path: `/user/username/projects/myproject/pkg${index}/index.ts`, - content: `export const pkg${index} = ${index};` + content: `export const pkg${index} = ${index};`, }, { path: `/user/username/projects/myproject/pkg${index}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true }, - references: index === 0 ? - undefined : - [{ path: `../pkg0` }] - }) - } + references: index === 0 + ? undefined + : [{ path: `../pkg0` }], + }), + }, ]; } function solution(maxPkgs: number): File { @@ -44,7 +44,7 @@ describe("unittests:: tsbuildWatch:: watchMode:: projectsBuilding", () => { content: JSON.stringify({ references: pkgs(createPkgReference, maxPkgs), files: [], - }) + }), }; } function checkBuildPkg(startIndex: number, count: number): TscWatchCompileChange { @@ -58,107 +58,121 @@ describe("unittests:: tsbuildWatch:: watchMode:: projectsBuilding", () => { scenario: "projectsBuilding", subScenario: `when there are 3 projects in a solution`, commandLineArgs: ["-b", "-w", "-v"], - sys: () => createWatchedSystem( - [libFile, ...ts.flatMap(pkgs(pkgFiles, 3), ts.identity), solution(3)], - { currentDirectory: "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + [libFile, ...ts.flatMap(pkgs(pkgFiles, 3), ts.identity), solution(3)], + { currentDirectory: "/user/username/projects/myproject" }, + ), edits: [ { caption: "dts doesn't change", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`), + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 and update timestamps }, noopChange, { caption: "dts change", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(1, 2), noopChange, - ] + ], }); verifyTscWatch({ scenario: "projectsBuilding", subScenario: `when there are 5 projects in a solution`, commandLineArgs: ["-b", "-w", "-v"], - sys: () => createWatchedSystem( - [libFile, ...ts.flatMap(pkgs(pkgFiles, 5), ts.identity), solution(5)], - { currentDirectory: "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + [libFile, ...ts.flatMap(pkgs(pkgFiles, 5), ts.identity), solution(5)], + { currentDirectory: "/user/username/projects/myproject" }, + ), edits: [ { caption: "dts doesn't change", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`), + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 and update timestamps }, noopChange, { caption: "dts change", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(1, 4), noopChange, - ] + ], }); verifyTscWatch({ scenario: "projectsBuilding", subScenario: `when there are 8 projects in a solution`, commandLineArgs: ["-b", "-w", "-v"], - sys: () => createWatchedSystem( - [libFile, ...ts.flatMap(pkgs(pkgFiles, 8), ts.identity), solution(8)], - { currentDirectory: "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + [libFile, ...ts.flatMap(pkgs(pkgFiles, 8), ts.identity), solution(8)], + { currentDirectory: "/user/username/projects/myproject" }, + ), edits: [ { caption: "dts doesn't change", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`), + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 and update timestamps }, noopChange, { caption: "dts change", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(1, 5), checkBuildPkg(6, 2), noopChange, { caption: "dts change2", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst3 = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst3 = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(1, 5), { caption: "change while building", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst4 = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst4 = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(6, 2), noopChange, - ] + ], }); verifyTscWatch({ scenario: "projectsBuilding", subScenario: `when there are 23 projects in a solution`, commandLineArgs: ["-b", "-w", "-v"], - sys: () => createWatchedSystem( - [libFile, ...ts.flatMap(pkgs(pkgFiles, 23), ts.identity), solution(23)], - { currentDirectory: "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + [libFile, ...ts.flatMap(pkgs(pkgFiles, 23), ts.identity), solution(23)], + { currentDirectory: "/user/username/projects/myproject" }, + ), edits: [ { caption: "dts doesn't change", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`), + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst2 = 10;`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 and update timestamps }, noopChange, { caption: "dts change", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(1, 5), checkBuildPkg(6, 5), @@ -168,21 +182,24 @@ describe("unittests:: tsbuildWatch:: watchMode:: projectsBuilding", () => { noopChange, { caption: "dts change2", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst3 = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst3 = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(1, 5), checkBuildPkg(6, 5), { caption: "change while building", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst4 = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `const someConst4 = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(11, 5), { caption: "change while building: dts changes", - edit: sys => sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst5 = 10;`), - timeouts: sys => sys.runQueuedTimeoutCallbacks() // Build pkg0 + edit: sys => + sys.appendFile(`/user/username/projects/myproject/pkg0/index.ts`, `export const someConst5 = 10;`), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Build pkg0 }, checkBuildPkg(1, 5), checkBuildPkg(6, 5), @@ -190,6 +207,6 @@ describe("unittests:: tsbuildWatch:: watchMode:: projectsBuilding", () => { checkBuildPkg(16, 5), checkBuildPkg(21, 3), noopChange, - ] + ], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/publicApi.ts b/src/testRunner/unittests/tsbuildWatch/publicApi.ts index a8b5a21152553..6caefdf5e37cc 100644 --- a/src/testRunner/unittests/tsbuildWatch/publicApi.ts +++ b/src/testRunner/unittests/tsbuildWatch/publicApi.ts @@ -16,16 +16,16 @@ it("unittests:: tsbuildWatch:: watchMode:: Public API with custom transformers", content: JSON.stringify({ references: [ { path: "./shared/tsconfig.json" }, - { path: "./webpack/tsconfig.json" } + { path: "./webpack/tsconfig.json" }, ], - files: [] - }) + files: [], + }), }; const sharedConfig: File = { path: `/user/username/projects/myproject/shared/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true }, - }) + }), }; const sharedIndex: File = { path: `/user/username/projects/myproject/shared/index.ts`, @@ -33,14 +33,14 @@ it("unittests:: tsbuildWatch:: watchMode:: Public API with custom transformers", export class c { } export enum e { } // leading -export function f2() { } // trailing` +export function f2() { } // trailing`, }; const webpackConfig: File = { path: `/user/username/projects/myproject/webpack/tsconfig.json`, content: JSON.stringify({ - compilerOptions: { composite: true, }, - references: [{ path: "../shared/tsconfig.json" }] - }) + compilerOptions: { composite: true }, + references: [{ path: "../shared/tsconfig.json" }], + }), }; const webpackIndex: File = { path: `/user/username/projects/myproject/webpack/index.ts`, @@ -48,10 +48,14 @@ export function f2() { } // trailing` export class c2 { } export enum e2 { } // leading -export function f22() { } // trailing` +export function f22() { } // trailing`, }; const commandLineArgs = ["--b", "--w"]; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([libFile, solution, sharedConfig, sharedIndex, webpackConfig, webpackIndex], { currentDirectory: "/user/username/projects/myproject" })); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([libFile, solution, sharedConfig, sharedIndex, webpackConfig, webpackIndex], { + currentDirectory: "/user/username/projects/myproject", + }), + ); const buildHost = createSolutionBuilderWithWatchHostForBaseline(sys, cb); buildHost.getCustomTransformers = getCustomTransformers; const builder = ts.createSolutionBuilderWithWatch(buildHost, [solution.path], { verbose: true }); @@ -71,10 +75,10 @@ export function f22() { } // trailing` timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // Shared sys.runQueuedTimeoutCallbacks(); // webpack and solution - } - } + }, + }, ], - watchOrSolution: builder + watchOrSolution: builder, }); function getCustomTransformers(project: string): ts.CustomTransformers { @@ -89,7 +93,12 @@ export function f22() { } // trailing` } } function visitFunction(node: ts.FunctionDeclaration) { - ts.addSyntheticLeadingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, `@before${project}`, /*hasTrailingNewLine*/ true); + ts.addSyntheticLeadingComment( + node, + ts.SyntaxKind.MultiLineCommentTrivia, + `@before${project}`, + /*hasTrailingNewLine*/ true, + ); return node; } }; @@ -111,4 +120,4 @@ export function f22() { } // trailing` }; return { before: [before], after: [after] }; } -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/reexport.ts b/src/testRunner/unittests/tsbuildWatch/reexport.ts index ff1f3b1f05bed..0bae309e5de4a 100644 --- a/src/testRunner/unittests/tsbuildWatch/reexport.ts +++ b/src/testRunner/unittests/tsbuildWatch/reexport.ts @@ -1,5 +1,9 @@ -import { libContent } from "../helpers/contents"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + libContent, +} from "../helpers/contents"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { createWatchedSystem, getTsBuildProjectFile, @@ -11,18 +15,22 @@ describe("unittests:: tsbuildWatch:: watchMode:: with reexport when referenced p scenario: "reexport", subScenario: "Reports errors correctly", commandLineArgs: ["-b", "-w", "-verbose", "src"], - sys: () => createWatchedSystem( - [ - ...[ - "src/tsconfig.json", - "src/main/tsconfig.json", "src/main/index.ts", - "src/pure/tsconfig.json", "src/pure/index.ts", "src/pure/session.ts" - ] - .map(f => getTsBuildProjectFile("reexport", f)), - { path: libFile.path, content: libContent } - ], - { currentDirectory: `/user/username/projects/reexport` } - ), + sys: () => + createWatchedSystem( + [ + ...[ + "src/tsconfig.json", + "src/main/tsconfig.json", + "src/main/index.ts", + "src/pure/tsconfig.json", + "src/pure/index.ts", + "src/pure/session.ts", + ] + .map(f => getTsBuildProjectFile("reexport", f)), + { path: libFile.path, content: libContent }, + ], + { currentDirectory: `/user/username/projects/reexport` }, + ), edits: [ { caption: "Introduce error", @@ -34,12 +42,13 @@ describe("unittests:: tsbuildWatch:: watchMode:: with reexport when referenced p }, { caption: "Fix error", - edit: sys => sys.replaceFileText(`/user/username/projects/reexport/src/pure/session.ts`, "bar: ", "// bar: "), + edit: sys => + sys.replaceFileText(`/user/username/projects/reexport/src/pure/session.ts`, "bar: ", "// bar: "), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // build src/pure sys.runQueuedTimeoutCallbacks(); // build src/main and src }, - } - ] + }, + ], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts b/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts index ca887c6699db1..0170fd29bb169 100644 --- a/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts +++ b/src/testRunner/unittests/tsbuildWatch/watchEnvironment.ts @@ -18,7 +18,7 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi const configPath = `${project}/tsconfig.json`; const typing: File = { path: `${project}/typings/xterm.d.ts`, - content: "export const typing = 10;" + content: "export const typing = 10;", }; const allPkgFiles = pkgs(pkgFiles); @@ -26,7 +26,10 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi writePkgReferences(system); const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(system); const host = createSolutionBuilderWithWatchHostForBaseline(sys, cb); - const solutionBuilder = ts.createSolutionBuilderWithWatch(host, ["tsconfig.json"], { watch: true, verbose: true }); + const solutionBuilder = ts.createSolutionBuilderWithWatch(host, ["tsconfig.json"], { + watch: true, + verbose: true, + }); solutionBuilder.build(); runWatchBaseline({ scenario: "watchEnvironment", @@ -43,7 +46,7 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); - } + }, }, { // Make change @@ -60,7 +63,7 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); - } + }, }, { // Make change to remove all watches @@ -77,7 +80,7 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi timeouts: sys => sys.logTimeoutQueueLength(), }, ], - watchOrSolution: solutionBuilder + watchOrSolution: solutionBuilder, }); function flatArray(arr: T[][]): readonly T[] { @@ -97,7 +100,7 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi return [ { path: `${project}/pkg${index}/index.ts`, - content: `export const pkg${index} = ${index};` + content: `export const pkg${index} = ${index};`, }, { path: `${project}/pkg${index}/tsconfig.json`, @@ -105,18 +108,21 @@ describe("unittests:: tsbuildWatch:: watchEnvironment:: tsbuild:: watchMode:: wi complerOptions: { composite: true }, include: [ "**/*.ts", - "../typings/xterm.d.ts" - ] - }) - } + "../typings/xterm.d.ts", + ], + }), + }, ]; } function writePkgReferences(system: TestServerHost) { - system.writeFile(configPath, JSON.stringify({ - files: [], - include: [], - references: pkgs(createPkgReference) - })); + system.writeFile( + configPath, + JSON.stringify({ + files: [], + include: [], + references: pkgs(createPkgReference), + }), + ); } }); }); diff --git a/src/testRunner/unittests/tsc/cancellationToken.ts b/src/testRunner/unittests/tsc/cancellationToken.ts index dfda4549902b4..d205d80898896 100644 --- a/src/testRunner/unittests/tsc/cancellationToken.ts +++ b/src/testRunner/unittests/tsc/cancellationToken.ts @@ -27,7 +27,7 @@ describe("unittests:: tsc:: builder cancellationToken", () => { import {B} from './b'; declare var console: any; let b = new B(); - console.log(b.c.d);` + console.log(b.c.d);`, }; const bFile: File = { path: `/user/username/projects/myproject/b.ts`, @@ -35,36 +35,36 @@ describe("unittests:: tsc:: builder cancellationToken", () => { import {C} from './c'; export class B { c = new C(); - }` + }`, }; const cFile: File = { path: `/user/username/projects/myproject/c.ts`, content: Utils.dedent` export class C { d = 1; - }` + }`, }; const dFile: File = { path: `/user/username/projects/myproject/d.ts`, - content: "export class D { }" + content: "export class D { }", }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { incremental: true, declaration: true } }) + content: JSON.stringify({ compilerOptions: { incremental: true, declaration: true } }), }; const { sys, baseline, oldSnap: originalSnap } = createBaseline(createWatchedSystem( [aFile, bFile, cFile, dFile, config, libFile], - { currentDirectory: "/user/username/projects/myproject" } + { currentDirectory: "/user/username/projects/myproject" }, )); sys.exit = exitCode => sys.exitCode = exitCode; const reportDiagnostic = ts.createDiagnosticReporter(sys, /*pretty*/ true); const parsedConfig = ts.parseConfigFileWithSystem( "tsconfig.json", {}, - /*extendedConfigCache*/ undefined, - /*watchOptionsToExtend*/ undefined, + /*extendedConfigCache*/ undefined, + /*watchOptionsToExtend*/ undefined, sys, - reportDiagnostic + reportDiagnostic, )!; const host = ts.createIncrementalCompilerHost(parsedConfig.options, sys); let programs: CommandLineProgram[] = ts.emptyArray; @@ -91,7 +91,7 @@ describe("unittests:: tsc:: builder cancellationToken", () => { sys, baseline, sys => sys.appendFile(cFile.path, "export function foo() {}"), - "Add change that affects d.ts" + "Add change that affects d.ts", ); createIncrementalProgram(); @@ -122,7 +122,10 @@ describe("unittests:: tsc:: builder cancellationToken", () => { noChange("Clean build"); baselineCleanBuild(); - Harness.Baseline.runBaseline(`tsc/cancellationToken/${scenario.split(" ").join("-")}.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tsc/cancellationToken/${scenario.split(" ").join("-")}.js`, + baseline.join("\r\n"), + ); function noChange(caption: string) { oldSnap = applyEdit(sys, baseline, ts.noop, caption); @@ -134,19 +137,19 @@ describe("unittests:: tsc:: builder cancellationToken", () => { } function createIncrementalProgram() { - builderProgram = useBuildInfo ? - ts.createIncrementalProgram({ + builderProgram = useBuildInfo + ? ts.createIncrementalProgram({ rootNames: parsedConfig.fileNames, options: parsedConfig.options, host, - }) : - builderProgram = builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram( + }) + : builderProgram = builderProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram( parsedConfig.fileNames, parsedConfig.options, host, builderProgram, - /*configFileParsingDiagnostics*/ undefined, - /*projectReferences*/ undefined, + /*configFileParsingDiagnostics*/ undefined, + /*projectReferences*/ undefined, ); updatePrograms(); } @@ -173,13 +176,13 @@ describe("unittests:: tsc:: builder cancellationToken", () => { parsedConfig.fileNames, parsedConfig.options, host, - /*oldProgram*/ undefined, - /*configFileParsingDiagnostics*/ undefined, - /*projectReferences*/ undefined, + /*oldProgram*/ undefined, + /*configFileParsingDiagnostics*/ undefined, + /*projectReferences*/ undefined, ); updatePrograms(); emitAndBaseline(); } }); } -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsc/composite.ts b/src/testRunner/unittests/tsc/composite.ts index 571ade2ab4235..d881cda28f9f2 100644 --- a/src/testRunner/unittests/tsc/composite.ts +++ b/src/testRunner/unittests/tsc/composite.ts @@ -4,16 +4,17 @@ import { } from "../helpers/tsc"; import { loadProjectFromFiles, - replaceText + replaceText, } from "../helpers/vfs"; describe("unittests:: tsc:: composite::", () => { verifyTsc({ scenario: "composite", subScenario: "when setting composite false on command line", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": Utils.dedent` { "compilerOptions": { "target": "es5", @@ -24,16 +25,17 @@ describe("unittests:: tsc:: composite::", () => { "src/**/*.ts" ] }`, - }), + }), commandLineArgs: ["--composite", "false", "--p", "src/project"], }); verifyTsc({ scenario: "composite", subScenario: "when setting composite null on command line", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": Utils.dedent` { "compilerOptions": { "target": "es5", @@ -44,16 +46,17 @@ describe("unittests:: tsc:: composite::", () => { "src/**/*.ts" ] }`, - }), + }), commandLineArgs: ["--composite", "null", "--p", "src/project"], }); verifyTsc({ scenario: "composite", subScenario: "when setting composite false on command line but has tsbuild info in config", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": Utils.dedent` { "compilerOptions": { "target": "es5", @@ -65,16 +68,18 @@ describe("unittests:: tsc:: composite::", () => { "src/**/*.ts" ] }`, - }), + }), commandLineArgs: ["--composite", "false", "--p", "src/project"], }); verifyTsc({ scenario: "composite", - subScenario: "when setting composite false and tsbuildinfo as null on command line but has tsbuild info in config", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": Utils.dedent` + subScenario: + "when setting composite false and tsbuildinfo as null on command line but has tsbuild info in config", + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": Utils.dedent` { "compilerOptions": { "target": "es5", @@ -86,28 +91,29 @@ describe("unittests:: tsc:: composite::", () => { "src/**/*.ts" ] }`, - }), + }), commandLineArgs: ["--composite", "false", "--p", "src/project", "--tsBuildInfoFile", "null"], }); verifyTsc({ scenario: "composite", subScenario: "converting to modules", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "const x = 10;", - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - module: "none", - composite: true, - }, + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "const x = 10;", + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "none", + composite: true, + }, + }), }), - }), commandLineArgs: ["-p", "/src/project"], edits: [ { caption: "convert to modules", edit: fs => replaceText(fs, "/src/project/tsconfig.json", "none", "es2015"), - } - ] + }, + ], }); }); diff --git a/src/testRunner/unittests/tsc/declarationEmit.ts b/src/testRunner/unittests/tsc/declarationEmit.ts index 55c5c3d3e8252..70b738cad5a2b 100644 --- a/src/testRunner/unittests/tsc/declarationEmit.ts +++ b/src/testRunner/unittests/tsc/declarationEmit.ts @@ -1,6 +1,8 @@ import * as ts from "../../_namespaces/ts"; import * as Utils from "../../_namespaces/Utils"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { createWatchedSystem, FileOrFolderOrSymLink, @@ -16,13 +18,19 @@ describe("unittests:: tsc:: declarationEmit::", () => { changeCaseFileTestPath: (path: string) => boolean; } - function changeCaseFile(file: FileOrFolderOrSymLink, testPath: (path: string) => boolean, replacePath: (path: string) => string): FileOrFolderOrSymLink { - return !isSymLink(file) || !testPath(file.symLink) ? - testPath(file.path) ? { ...file, path: replacePath(file.path) } : file : - { path: testPath(file.path) ? replacePath(file.path) : file.path, symLink: replacePath(file.symLink) }; + function changeCaseFile( + file: FileOrFolderOrSymLink, + testPath: (path: string) => boolean, + replacePath: (path: string) => string, + ): FileOrFolderOrSymLink { + return !isSymLink(file) || !testPath(file.symLink) + ? testPath(file.path) ? { ...file, path: replacePath(file.path) } : file + : { path: testPath(file.path) ? replacePath(file.path) : file.path, symLink: replacePath(file.symLink) }; } - function verifyDeclarationEmit({ subScenario, files, rootProject, changeCaseFileTestPath }: VerifyDeclarationEmitInput) { + function verifyDeclarationEmit( + { subScenario, files, rootProject, changeCaseFileTestPath }: VerifyDeclarationEmitInput, + ) { describe(subScenario, () => { verifyTscWatch({ scenario: "declarationEmit", @@ -37,10 +45,13 @@ describe("unittests:: tsc:: declarationEmit::", () => { verifyTscWatch({ scenario: "declarationEmit", subScenario: caseChangeScenario, - sys: () => createWatchedSystem( - files.map(f => changeCaseFile(f, changeCaseFileTestPath, str => str.replace("myproject", "myProject"))), - { currentDirectory: "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + files.map(f => + changeCaseFile(f, changeCaseFileTestPath, str => str.replace("myproject", "myProject")) + ), + { currentDirectory: "/user/username/projects/myproject" }, + ), commandLineArgs: ["-p", rootProject, "--explainFiles"], }); }); @@ -52,7 +63,7 @@ describe("unittests:: tsc:: declarationEmit::", () => { compilerOptions: { target: "es5", declaration: true, - traceResolution: true + traceResolution: true, }, }); } @@ -93,7 +104,7 @@ describe("unittests:: tsc:: declarationEmit::", () => { function fsaPackageJson() { return JSON.stringify({ name: "typescript-fsa", - version: "3.0.0-beta-2" + version: "3.0.0-beta-2", }); } function fsaIndex() { @@ -118,21 +129,37 @@ describe("unittests:: tsc:: declarationEmit::", () => { rootProject: "plugin-one", files: [ { path: `/user/username/projects/myproject/plugin-two/index.d.ts`, content: pluginTwoDts() }, - { path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() }, - { path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() }, + { + path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/package.json`, + content: fsaPackageJson(), + }, + { + path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/index.d.ts`, + content: fsaIndex(), + }, { path: `/user/username/projects/myproject/plugin-one/tsconfig.json`, content: pluginOneConfig() }, { path: `/user/username/projects/myproject/plugin-one/index.ts`, content: pluginOneIndex() }, { path: `/user/username/projects/myproject/plugin-one/action.ts`, content: pluginOneAction() }, - { path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() }, - { path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() }, - { path: `/user/username/projects/myproject/plugin-one/node_modules/plugin-two`, symLink: `/user/username/projects/myproject/plugin-two` }, - libFile + { + path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/package.json`, + content: fsaPackageJson(), + }, + { + path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/index.d.ts`, + content: fsaIndex(), + }, + { + path: `/user/username/projects/myproject/plugin-one/node_modules/plugin-two`, + symLink: `/user/username/projects/myproject/plugin-two`, + }, + libFile, ], changeCaseFileTestPath: str => ts.stringContains(str, "/plugin-two"), }); verifyDeclarationEmit({ - subScenario: "when same version is referenced through source and another symlinked package with indirect link", + subScenario: + "when same version is referenced through source and another symlinked package with indirect link", rootProject: "plugin-one", files: [ { @@ -140,23 +167,41 @@ describe("unittests:: tsc:: declarationEmit::", () => { content: JSON.stringify({ name: "plugin-two", version: "0.1.3", - main: "dist/commonjs/index.js" - }) + main: "dist/commonjs/index.js", + }), + }, + { + path: `/user/username/projects/myproject/plugin-two/dist/commonjs/index.d.ts`, + content: pluginTwoDts(), + }, + { + path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/package.json`, + content: fsaPackageJson(), + }, + { + path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/index.d.ts`, + content: fsaIndex(), }, - { path: `/user/username/projects/myproject/plugin-two/dist/commonjs/index.d.ts`, content: pluginTwoDts() }, - { path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() }, - { path: `/user/username/projects/myproject/plugin-two/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() }, { path: `/user/username/projects/myproject/plugin-one/tsconfig.json`, content: pluginOneConfig() }, { path: `/user/username/projects/myproject/plugin-one/index.ts`, content: `${pluginOneIndex()} -${pluginOneAction()}` +${pluginOneAction()}`, + }, + { + path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/package.json`, + content: fsaPackageJson(), + }, + { + path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/index.d.ts`, + content: fsaIndex(), }, - { path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/package.json`, content: fsaPackageJson() }, - { path: `/user/username/projects/myproject/plugin-one/node_modules/typescript-fsa/index.d.ts`, content: fsaIndex() }, { path: `/temp/yarn/data/link/plugin-two`, symLink: `/user/username/projects/myproject/plugin-two` }, - { path: `/user/username/projects/myproject/plugin-one/node_modules/plugin-two`, symLink: `/temp/yarn/data/link/plugin-two` }, - libFile + { + path: `/user/username/projects/myproject/plugin-one/node_modules/plugin-two`, + symLink: `/temp/yarn/data/link/plugin-two`, + }, + libFile, ], changeCaseFileTestPath: str => ts.stringContains(str, "/plugin-two"), }); @@ -169,7 +214,7 @@ ${pluginOneAction()}` { path: `/user/username/projects/myproject/pkg1/dist/index.d.ts`, content: Utils.dedent` - export * from './types';` + export * from './types';`, }, { path: `/user/username/projects/myproject/pkg1/dist/types.d.ts`, @@ -186,7 +231,7 @@ ${pluginOneAction()}` private constructor(); toString(): string; static create(key: string): MetadataAccessor; - }` + }`, }, { path: `/user/username/projects/myproject/pkg1/package.json`, @@ -194,18 +239,18 @@ ${pluginOneAction()}` name: "@raymondfeng/pkg1", version: "1.0.0", main: "dist/index.js", - typings: "dist/index.d.ts" - }) + typings: "dist/index.d.ts", + }), }, { path: `/user/username/projects/myproject/pkg2/dist/index.d.ts`, content: Utils.dedent` - export * from './types';` + export * from './types';`, }, { path: `/user/username/projects/myproject/pkg2/dist/types.d.ts`, content: Utils.dedent` - export {MetadataAccessor} from '@raymondfeng/pkg1';` + export {MetadataAccessor} from '@raymondfeng/pkg1';`, }, { path: `/user/username/projects/myproject/pkg2/package.json`, @@ -213,19 +258,19 @@ ${pluginOneAction()}` name: "@raymondfeng/pkg2", version: "1.0.0", main: "dist/index.js", - typings: "dist/index.d.ts" - }) + typings: "dist/index.d.ts", + }), }, { path: `/user/username/projects/myproject/pkg3/src/index.ts`, content: Utils.dedent` - export * from './keys';` + export * from './keys';`, }, { path: `/user/username/projects/myproject/pkg3/src/keys.ts`, content: Utils.dedent` import {MetadataAccessor} from "@raymondfeng/pkg2"; - export const ADMIN = MetadataAccessor.create('1');` + export const ADMIN = MetadataAccessor.create('1');`, }, { path: `/user/username/projects/myproject/pkg3/tsconfig.json`, @@ -237,19 +282,19 @@ ${pluginOneAction()}` module: "commonjs", strict: true, esModuleInterop: true, - declaration: true - } - }) + declaration: true, + }, + }), }, { path: `/user/username/projects/myproject/pkg2/node_modules/@raymondfeng/pkg1`, - symLink: `/user/username/projects/myproject/pkg1` + symLink: `/user/username/projects/myproject/pkg1`, }, { path: `/user/username/projects/myproject/pkg3/node_modules/@raymondfeng/pkg2`, - symLink: `/user/username/projects/myproject/pkg2` + symLink: `/user/username/projects/myproject/pkg2`, }, - libFile + libFile, ], changeCaseFileTestPath: str => ts.stringContains(str, "/pkg1"), }); diff --git a/src/testRunner/unittests/tsc/extends.ts b/src/testRunner/unittests/tsc/extends.ts index 9fb78d0384073..ebc16575046d9 100644 --- a/src/testRunner/unittests/tsc/extends.ts +++ b/src/testRunner/unittests/tsc/extends.ts @@ -1,5 +1,9 @@ -import { getSymlinkedExtendsSys } from "../helpers/extends"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + getSymlinkedExtendsSys, +} from "../helpers/extends"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; describe("unittests:: tsc:: extends::", () => { verifyTscWatch({ @@ -8,4 +12,4 @@ describe("unittests:: tsc:: extends::", () => { sys: getSymlinkedExtendsSys, commandLineArgs: ["-p", "src", "--extendedDiagnostics"], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsc/forceConsistentCasingInFileNames.ts b/src/testRunner/unittests/tsc/forceConsistentCasingInFileNames.ts index 7a1f9414ef8f6..0a765e6e3f193 100644 --- a/src/testRunner/unittests/tsc/forceConsistentCasingInFileNames.ts +++ b/src/testRunner/unittests/tsc/forceConsistentCasingInFileNames.ts @@ -2,21 +2,24 @@ import * as Utils from "../../_namespaces/Utils"; import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsc:: forceConsistentCasingInFileNames::", () => { verifyTsc({ scenario: "forceConsistentCasingInFileNames", subScenario: "with relative and non relative file resolutions", commandLineArgs: ["/src/project/src/struct.d.ts", "--forceConsistentCasingInFileNames", "--explainFiles"], - fs: () => loadProjectFromFiles({ - "/src/project/src/struct.d.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/struct.d.ts": Utils.dedent` import * as xs1 from "fp-ts/lib/Struct"; import * as xs2 from "fp-ts/lib/struct"; import * as xs3 from "./Struct"; import * as xs4 from "./struct"; `, - "/src/project/node_modules/fp-ts/lib/struct.d.ts": `export function foo(): void`, - }), + "/src/project/node_modules/fp-ts/lib/struct.d.ts": `export function foo(): void`, + }), }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsc/incremental.ts b/src/testRunner/unittests/tsc/incremental.ts index e3d6adefb50a4..d9a282276a070 100644 --- a/src/testRunner/unittests/tsc/incremental.ts +++ b/src/testRunner/unittests/tsc/incremental.ts @@ -3,7 +3,7 @@ import * as Utils from "../../_namespaces/Utils"; import * as vfs from "../../_namespaces/vfs"; import { compilerOptionsToConfigJson, - libContent + libContent, } from "../helpers/contents"; import { noChangeOnlyRuns, @@ -14,17 +14,19 @@ import { import { appendText, loadProjectFromDisk, - loadProjectFromFiles, prependText, - replaceText + loadProjectFromFiles, + prependText, + replaceText, } from "../helpers/vfs"; describe("unittests:: tsc:: incremental::", () => { verifyTsc({ scenario: "incremental", subScenario: "when passing filename for buildinfo on commandline", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": Utils.dedent` { "compilerOptions": { "target": "es5", @@ -34,52 +36,62 @@ describe("unittests:: tsc:: incremental::", () => { "src/**/*.ts" ] }`, - }), - commandLineArgs: ["--incremental", "--p", "src/project", "--tsBuildInfoFile", "src/project/.tsbuildinfo", "--explainFiles"], - edits: noChangeOnlyRuns + }), + commandLineArgs: [ + "--incremental", + "--p", + "src/project", + "--tsBuildInfoFile", + "src/project/.tsbuildinfo", + "--explainFiles", + ], + edits: noChangeOnlyRuns, }); verifyTsc({ scenario: "incremental", subScenario: "when passing rootDir from commandline", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": Utils.dedent` { "compilerOptions": { "incremental": true, "outDir": "dist", }, }`, - }), + }), commandLineArgs: ["--p", "src/project", "--rootDir", "src/project/src"], - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); verifyTsc({ scenario: "incremental", subScenario: "with only dts files", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.d.ts": "export const x = 10;", - "/src/project/src/another.d.ts": "export const y = 10;", - "/src/project/tsconfig.json": "{}", - }), + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.d.ts": "export const x = 10;", + "/src/project/src/another.d.ts": "export const y = 10;", + "/src/project/tsconfig.json": "{}", + }), commandLineArgs: ["--incremental", "--p", "src/project"], edits: [ noChangeRun, { caption: "incremental-declaration-doesnt-change", - edit: fs => appendText(fs, "/src/project/src/main.d.ts", "export const xy = 100;") - } - ] + edit: fs => appendText(fs, "/src/project/src/main.d.ts", "export const xy = 100;"), + }, + ], }); verifyTsc({ scenario: "incremental", subScenario: "when passing rootDir is in the tsconfig", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": Utils.dedent` { "compilerOptions": { "incremental": true, @@ -87,24 +99,25 @@ describe("unittests:: tsc:: incremental::", () => { "rootDir": "./" }, }`, - }), + }), commandLineArgs: ["--p", "src/project"], - edits: noChangeOnlyRuns + edits: noChangeOnlyRuns, }); verifyTsc({ scenario: "incremental", subScenario: "tsbuildinfo has error", - fs: () => loadProjectFromFiles({ - "/src/project/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": "{}", - "/src/project/tsconfig.tsbuildinfo": "Some random string", - }), + fs: () => + loadProjectFromFiles({ + "/src/project/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": "{}", + "/src/project/tsconfig.tsbuildinfo": "Some random string", + }), commandLineArgs: ["--p", "src/project", "-i"], edits: [{ caption: "tsbuildinfo written has error", edit: fs => prependText(fs, "/src/project/tsconfig.tsbuildinfo", "Some random string"), - }] + }], }); describe("with noEmitOnError", () => { @@ -116,7 +129,11 @@ describe("unittests:: tsc:: incremental::", () => { projFs = undefined!; }); - function verifyNoEmitOnError(subScenario: string, fixModifyFs: TestTscEdit["edit"], modifyFs?: TestTscEdit["edit"]) { + function verifyNoEmitOnError( + subScenario: string, + fixModifyFs: TestTscEdit["edit"], + modifyFs?: TestTscEdit["edit"], + ) { verifyTsc({ scenario: "incremental", subScenario, @@ -127,27 +144,42 @@ describe("unittests:: tsc:: incremental::", () => { noChangeRun, { caption: "incremental-declaration-doesnt-change", - edit: fixModifyFs + edit: fixModifyFs, }, noChangeRun, ], - baselinePrograms: true + baselinePrograms: true, }); } verifyNoEmitOnError( "with noEmitOnError syntax errors", - fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; + fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; const a = { lastName: 'sdsd' -};`, "utf-8") +};`, + "utf-8", + ), ); verifyNoEmitOnError( "with noEmitOnError semantic errors", - fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; -const a: string = "hello";`, "utf-8"), - fs => fs.writeFileSync("/src/src/main.ts", `import { A } from "../shared/types/db"; -const a: string = 10;`, "utf-8"), + fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; +const a: string = "hello";`, + "utf-8", + ), + fs => + fs.writeFileSync( + "/src/src/main.ts", + `import { A } from "../shared/types/db"; +const a: string = 10;`, + "utf-8", + ), ); }); @@ -165,9 +197,9 @@ const a: string = 10;`, "utf-8"), ...noChangeRun, caption: "No Change run with noEmit", commandLineArgs: ["--p", "src/project", "--noEmit"], - discrepancyExplanation: compilerOptions.composite ? - discrepancyExplanation : - undefined, + discrepancyExplanation: compilerOptions.composite + ? discrepancyExplanation + : undefined, }; const noChangeRunWithEmit: TestTscEdit = { ...noChangeRun, @@ -193,9 +225,9 @@ const a: string = 10;`, "utf-8"), caption: "Introduce error but still noEmit", commandLineArgs: ["--p", "src/project", "--noEmit"], edit: fs => replaceText(fs, "/src/project/src/class.ts", "prop", "prop1"), - discrepancyExplanation: compilerOptions.composite ? - discrepancyExplanation : - undefined, + discrepancyExplanation: compilerOptions.composite + ? discrepancyExplanation + : undefined, }, { caption: "Fix error and emit", @@ -217,9 +249,9 @@ const a: string = 10;`, "utf-8"), caption: "Fix error and no emit", commandLineArgs: ["--p", "src/project", "--noEmit"], edit: fs => replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"), - discrepancyExplanation: compilerOptions.composite ? - discrepancyExplanation : - undefined, + discrepancyExplanation: compilerOptions.composite + ? discrepancyExplanation + : undefined, }, noChangeRunWithEmit, noChangeRunWithNoEmit, @@ -243,9 +275,9 @@ const a: string = 10;`, "utf-8"), { caption: "Fix error and no emit", edit: fs => replaceText(fs, "/src/project/src/class.ts", "prop1", "prop"), - discrepancyExplanation: compilerOptions.composite ? - discrepancyExplanation : - undefined, + discrepancyExplanation: compilerOptions.composite + ? discrepancyExplanation + : undefined, }, noChangeRunWithEmit, ], @@ -283,23 +315,24 @@ const a: string = 10;`, "utf-8"), verifyTsc({ scenario: "incremental", subScenario: `when global file is added, the signatures are updated`, - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": Utils.dedent` /// /// function main() { } `, - "/src/project/src/anotherFileWithSameReferenes.ts": Utils.dedent` + "/src/project/src/anotherFileWithSameReferenes.ts": Utils.dedent` /// /// function anotherFileWithSameReferenes() { } `, - "/src/project/src/filePresent.ts": `function something() { return 10; }`, - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { composite: true, }, - include: ["src/**/*.ts"] + "/src/project/src/filePresent.ts": `function something() { return 10; }`, + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { composite: true }, + include: ["src/**/*.ts"], + }), }), - }), commandLineArgs: ["--p", "src/project"], edits: [ noChangeRun, @@ -315,14 +348,19 @@ const a: string = 10;`, "utf-8"), caption: "Add new file and update main file", edit: fs => { fs.writeFileSync(`/src/project/src/newFile.ts`, "function foo() { return 20; }"); - prependText(fs, `/src/project/src/main.ts`, `/// -`); + prependText( + fs, + `/src/project/src/main.ts`, + `/// +`, + ); appendText(fs, `/src/project/src/main.ts`, `foo();`); }, }, { caption: "Write file that could not be resolved", - edit: fs => fs.writeFileSync(`/src/project/src/fileNotFound.ts`, "function something2() { return 20; }"), + edit: fs => + fs.writeFileSync(`/src/project/src/fileNotFound.ts`, "function something2() { return 20; }"), }, { caption: "Modify main file", @@ -351,25 +389,41 @@ declare global { verifyTsc({ scenario: "react-jsx-emit-mode", subScenario: "with no backing types found doesn't crash", - fs: () => loadProjectFromFiles({ - "/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result - "/src/project/node_modules/@types/react/index.d.ts": getJsxLibraryContent(), // doesn't contain a jsx-runtime definition - "/src/project/src/index.tsx": `export const App = () =>
;`, - "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" } }) - }), - commandLineArgs: ["--p", "src/project"] + fs: () => + loadProjectFromFiles({ + "/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result + "/src/project/node_modules/@types/react/index.d.ts": getJsxLibraryContent(), // doesn't contain a jsx-runtime definition + "/src/project/src/index.tsx": `export const App = () =>
;`, + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "commonjs", + jsx: "react-jsx", + incremental: true, + jsxImportSource: "react", + }, + }), + }), + commandLineArgs: ["--p", "src/project"], }); verifyTsc({ scenario: "react-jsx-emit-mode", subScenario: "with no backing types found doesn't crash under --strict", - fs: () => loadProjectFromFiles({ - "/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result - "/src/project/node_modules/@types/react/index.d.ts": getJsxLibraryContent(), // doesn't contain a jsx-runtime definition - "/src/project/src/index.tsx": `export const App = () =>
;`, - "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" } }) - }), - commandLineArgs: ["--p", "src/project", "--strict"] + fs: () => + loadProjectFromFiles({ + "/src/project/node_modules/react/jsx-runtime.js": "export {}", // js needs to be present so there's a resolution result + "/src/project/node_modules/@types/react/index.d.ts": getJsxLibraryContent(), // doesn't contain a jsx-runtime definition + "/src/project/src/index.tsx": `export const App = () =>
;`, + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "commonjs", + jsx: "react-jsx", + incremental: true, + jsxImportSource: "react", + }, + }), + }), + commandLineArgs: ["--p", "src/project", "--strict"], }); }); @@ -377,27 +431,28 @@ declare global { scenario: "incremental", subScenario: "when new file is added to the referenced project", commandLineArgs: ["-i", "-p", `src/projects/project2`], - fs: () => loadProjectFromFiles({ - "/src/projects/project1/tsconfig.json": JSON.stringify({ - compilerOptions: { - module: "none", - composite: true - }, - exclude: ["temp"] - }), - "/src/projects/project1/class1.ts": `class class1 {}`, - "/src/projects/project1/class1.d.ts": `declare class class1 {}`, - "/src/projects/project2/tsconfig.json": JSON.stringify({ - compilerOptions: { - module: "none", - composite: true - }, - references: [ - { path: "../project1" } - ] + fs: () => + loadProjectFromFiles({ + "/src/projects/project1/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "none", + composite: true, + }, + exclude: ["temp"], + }), + "/src/projects/project1/class1.ts": `class class1 {}`, + "/src/projects/project1/class1.d.ts": `declare class class1 {}`, + "/src/projects/project2/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "none", + composite: true, + }, + references: [ + { path: "../project1" }, + ], + }), + "/src/projects/project2/class2.ts": `class class2 {}`, }), - "/src/projects/project2/class2.ts": `class class2 {}`, - }), edits: [ { caption: "Add class3 to project1 and build it", @@ -430,40 +485,42 @@ declare global { caption: "Create output for class3", edit: fs => fs.writeFileSync("/src/projects/project1/class3.d.ts", `declare class class3 {}`, "utf-8"), }, - ] + ], }); verifyTsc({ scenario: "incremental", subScenario: "when project has strict true", commandLineArgs: ["-noEmit", "-p", `src/project`], - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - incremental: true, - strict: true, - }, + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + incremental: true, + strict: true, + }, + }), + "/src/project/class1.ts": `export class class1 {}`, }), - "/src/project/class1.ts": `export class class1 {}`, - }), edits: noChangeOnlyRuns, - baselinePrograms: true + baselinePrograms: true, }); verifyTsc({ scenario: "incremental", subScenario: "serializing error chains", commandLineArgs: ["-p", `src/project`], - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - incremental: true, - strict: true, - jsx: "react", - module: "esnext", - }, - }), - "/src/project/index.tsx": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + incremental: true, + strict: true, + jsx: "react", + module: "esnext", + }, + }), + "/src/project/index.tsx": Utils.dedent` declare namespace JSX { interface ElementChildrenAttribute { children: {}; } interface IntrinsicElements { div: {} } @@ -476,16 +533,17 @@ declare global { (
- )` - }, `\ninterface ReadonlyArray { readonly length: number }`), + )`, + }, `\ninterface ReadonlyArray { readonly length: number }`), edits: noChangeOnlyRuns, }); verifyTsc({ scenario: "incremental", subScenario: "ts file with no-default-lib that augments the global scope", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": Utils.dedent` /// /// @@ -496,7 +554,7 @@ declare global { export {}; `, - "/src/project/tsconfig.json": Utils.dedent` + "/src/project/tsconfig.json": Utils.dedent` { "compilerOptions": { "target": "ESNext", @@ -505,24 +563,25 @@ declare global { "outDir": "dist", }, }`, - }), + }), commandLineArgs: ["--p", "src/project", "--rootDir", "src/project/src"], - modifyFs: (fs) => { + modifyFs: fs => { fs.writeFileSync("/lib/lib.esnext.d.ts", libContent); - } + }, }); verifyTsc({ scenario: "incremental", subScenario: "change to type that gets used as global through export in another file", commandLineArgs: ["-p", `src/project`], - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true }, }), - "/src/project/class1.ts": `const a: MagicNumber = 1; + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true } }), + "/src/project/class1.ts": `const a: MagicNumber = 1; console.log(a);`, - "/src/project/constants.ts": "export default 1;", - "/src/project/types.d.ts": `type MagicNumber = typeof import('./constants').default`, - }), + "/src/project/constants.ts": "export default 1;", + "/src/project/types.d.ts": `type MagicNumber = typeof import('./constants').default`, + }), edits: [{ caption: "Modify imports used in global file", edit: fs => fs.writeFileSync("/src/project/constants.ts", "export default 2;"), @@ -533,14 +592,15 @@ console.log(a);`, scenario: "incremental", subScenario: "change to type that gets used as global through export in another file through indirect import", commandLineArgs: ["-p", `src/project`], - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true }, }), - "/src/project/class1.ts": `const a: MagicNumber = 1; + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { composite: true } }), + "/src/project/class1.ts": `const a: MagicNumber = 1; console.log(a);`, - "/src/project/constants.ts": "export default 1;", - "/src/project/reexport.ts": `export { default as ConstantNumber } from "./constants"`, - "/src/project/types.d.ts": `type MagicNumber = typeof import('./reexport').ConstantNumber`, - }), + "/src/project/constants.ts": "export default 1;", + "/src/project/reexport.ts": `export { default as ConstantNumber } from "./constants"`, + "/src/project/types.d.ts": `type MagicNumber = typeof import('./reexport').ConstantNumber`, + }), edits: [{ caption: "Modify imports used in global file", edit: fs => fs.writeFileSync("/src/project/constants.ts", "export default 2;"), @@ -550,16 +610,19 @@ console.log(a);`, function verifyModifierChange(declaration: boolean) { verifyTsc({ scenario: "incremental", - subScenario: `change to modifier of class expression field${declaration ? " with declaration emit enabled" : ""}`, + subScenario: `change to modifier of class expression field${ + declaration ? " with declaration emit enabled" : "" + }`, commandLineArgs: ["-p", "src/project", "--incremental"], - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { declaration } }), - "/src/project/main.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { declaration } }), + "/src/project/main.ts": Utils.dedent` import MessageablePerson from './MessageablePerson.js'; function logMessage( person: MessageablePerson ) { console.log( person.message ); }`, - "/src/project/MessageablePerson.ts": Utils.dedent` + "/src/project/MessageablePerson.ts": Utils.dedent` const Messageable = () => { return class MessageableClass { public message = 'hello'; @@ -568,11 +631,15 @@ console.log(a);`, const wrapper = () => Messageable(); type MessageablePerson = InstanceType>; export default MessageablePerson;`, - }), - modifyFs: fs => appendText(fs, "/lib/lib.d.ts", Utils.dedent` + }), + modifyFs: fs => + appendText( + fs, + "/lib/lib.d.ts", + Utils.dedent` type ReturnType any> = T extends (...args: any) => infer R ? R : any; - type InstanceType any> = T extends abstract new (...args: any) => infer R ? R : any;` - ), + type InstanceType any> = T extends abstract new (...args: any) => infer R ? R : any;`, + ), edits: [ { caption: "modify public to protected", @@ -591,17 +658,18 @@ console.log(a);`, verifyTsc({ scenario: "incremental", subScenario: `when declarationMap changes`, - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - noEmitOnError: true, - declaration: true, - composite: true, - } + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + noEmitOnError: true, + declaration: true, + composite: true, + }, + }), + "/src/project/a.ts": "const x = 10;", + "/src/project/b.ts": "const y = 10;", }), - "/src/project/a.ts": "const x = 10;", - "/src/project/b.ts": "const y = 10;" - }), commandLineArgs: ["--p", "/src/project"], edits: [ { @@ -612,31 +680,32 @@ console.log(a);`, `Clean build does not emit any file so will have emitSignatures with all files since they are not emitted`, `Incremental build has emitSignatures from before, so it will have a.ts with signature since file.version isnt same`, `Incremental build will also have emitSignatureDtsMapDiffers for both files since the emitSignatures were without declarationMap but currentOptions have declrationMap`, - ] + ], }, { caption: "fix error declarationMap", edit: fs => replaceText(fs, "/src/project/a.ts", "x: 20", "x"), commandLineArgs: ["--p", "/src/project", "--declarationMap"], }, - ] + ], }); verifyTsc({ scenario: "incremental", subScenario: `when declarationMap changes with outFile`, - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - noEmitOnError: true, - declaration: true, - composite: true, - outFile: "../outFile.js", - } + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + noEmitOnError: true, + declaration: true, + composite: true, + outFile: "../outFile.js", + }, + }), + "/src/project/a.ts": "const x = 10;", + "/src/project/b.ts": "const y = 10;", }), - "/src/project/a.ts": "const x = 10;", - "/src/project/b.ts": "const y = 10;" - }), commandLineArgs: ["--p", "/src/project"], edits: [ { @@ -649,7 +718,7 @@ console.log(a);`, edit: fs => replaceText(fs, "/src/project/a.ts", "x: 20", "x"), commandLineArgs: ["--p", "/src/project", "--declarationMap"], }, - ] + ], }); describe("different options::", () => { @@ -669,7 +738,7 @@ console.log(a);`, discrepancyExplanation: () => [ `Clean build tsbuildinfo will have compilerOptions with composite and ${option.replace(/-/g, "")}`, `Incremental build will detect that it doesnt need to rebuild so tsbuild info is from before which has option composite only`, - ] + ], }; } function withEmitDeclarationOnlyChangeAndDiscrepancyExplanation(caption: string): TestTscEdit { @@ -678,7 +747,7 @@ console.log(a);`, edit.discrepancyExplanation = () => [ ...discrepancyExplanation(), `Clean build info does not have js section because its fresh build`, - `Incremental build info has js section from old build` + `Incremental build info has js section from old build`, ]; return edit; } @@ -738,7 +807,10 @@ console.log(a);`, noChangeRun, withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"), noChangeWithSubscenario("should re-emit only dts so they dont contain sourcemap"), - withOptionChangeAndDiscrepancyExplanation("with emitDeclarationOnly should not emit anything", "--emitDeclarationOnly"), + withOptionChangeAndDiscrepancyExplanation( + "with emitDeclarationOnly should not emit anything", + "--emitDeclarationOnly", + ), noChangeRun, localChange(), withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"), @@ -761,7 +833,9 @@ console.log(a);`, noChangeRun, withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"), noChangeWithSubscenario("should re-emit only dts so they dont contain sourcemap"), - withEmitDeclarationOnlyChangeAndDiscrepancyExplanation("with emitDeclarationOnly should not emit anything"), + withEmitDeclarationOnlyChangeAndDiscrepancyExplanation( + "with emitDeclarationOnly should not emit anything", + ), noChangeRun, localChange(), withOptionChangeAndDiscrepancyExplanation("with declaration should not emit anything", "--declaration"), @@ -790,7 +864,11 @@ console.log(a);`, withOptionChange("with sourceMap", "--sourceMap"), noChangeWithSubscenario("emit js files"), withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"), - withOptionChange("with declaration and declarationMap, should not re-emit", "--declaration", "--declarationMap"), + withOptionChange( + "with declaration and declarationMap, should not re-emit", + "--declaration", + "--declarationMap", + ), ], baselinePrograms: true, }); @@ -812,7 +890,11 @@ console.log(a);`, withOptionChange("with sourceMap", "--sourceMap"), noChangeWithSubscenario("emit js files"), withOptionChange("with declaration and declarationMap", "--declaration", "--declarationMap"), - withOptionChange("with declaration and declarationMap, should not re-emit", "--declaration", "--declarationMap"), + withOptionChange( + "with declaration and declarationMap, should not re-emit", + "--declaration", + "--declarationMap", + ), ], baselinePrograms: true, }); @@ -822,37 +904,39 @@ console.log(a);`, scenario: "incremental", subScenario: "when file is deleted", commandLineArgs: ["-p", `/src/project`], - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - composite: true, - outDir: "outDir", - }, + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + composite: true, + outDir: "outDir", + }, + }), + "/src/project/file1.ts": `export class C { }`, + "/src/project/file2.ts": `export class D { }`, }), - "/src/project/file1.ts": `export class C { }`, - "/src/project/file2.ts": `export class D { }`, - }), edits: [ { caption: "delete file with imports", edit: fs => fs.unlinkSync("/src/project/file2.ts"), }, - ] + ], }); verifyTsc({ scenario: "incremental", subScenario: "file deleted before fixing error with noEmitOnError", - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - outDir: "outDir", - noEmitOnError: true, - }, + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + outDir: "outDir", + noEmitOnError: true, + }, + }), + "/src/project/file1.ts": `export const x: 30 = "hello";`, + "/src/project/file2.ts": `export class D { }`, }), - "/src/project/file1.ts": `export const x: 30 = "hello";`, - "/src/project/file2.ts": `export class D { }`, - }), commandLineArgs: ["--p", "/src/project", "-i"], edits: [{ caption: "delete file without error", diff --git a/src/testRunner/unittests/tsc/libraryResolution.ts b/src/testRunner/unittests/tsc/libraryResolution.ts index c922ec87fa989..a2f7f49c05d60 100644 --- a/src/testRunner/unittests/tsc/libraryResolution.ts +++ b/src/testRunner/unittests/tsc/libraryResolution.ts @@ -1,5 +1,10 @@ -import { getCommandLineArgsForLibResolution, getFsForLibResolution } from "../helpers/libraryResolution"; -import { verifyTsc } from "../helpers/tsc"; +import { + getCommandLineArgsForLibResolution, + getFsForLibResolution, +} from "../helpers/libraryResolution"; +import { + verifyTsc, +} from "../helpers/tsc"; describe("unittests:: tsc:: libraryResolution:: library file resolution", () => { function verify(libRedirection?: true, withoutConfig?: true) { @@ -15,4 +20,4 @@ describe("unittests:: tsc:: libraryResolution:: library file resolution", () => verify(/*libRedirection*/ true); verify(/*libRedirection*/ undefined, /*withoutConfig*/ true); verify(/*libRedirection*/ true, /*withoutConfig*/ true); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsc/listFilesOnly.ts b/src/testRunner/unittests/tsc/listFilesOnly.ts index 1ff81276d2227..efff95327fa6e 100644 --- a/src/testRunner/unittests/tsc/listFilesOnly.ts +++ b/src/testRunner/unittests/tsc/listFilesOnly.ts @@ -3,36 +3,41 @@ import { noChangeRun, verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsc:: listFilesOnly::", () => { verifyTsc({ scenario: "listFilesOnly", subScenario: "combined with watch", - fs: () => loadProjectFromFiles({ - "/src/test.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/test.ts": Utils.dedent` export const x = 1;`, - }), - commandLineArgs: ["/src/test.ts", "--watch", "--listFilesOnly"] + }), + commandLineArgs: ["/src/test.ts", "--watch", "--listFilesOnly"], }); verifyTsc({ scenario: "listFilesOnly", subScenario: "loose file", - fs: () => loadProjectFromFiles({ - "/src/test.ts": Utils.dedent` + fs: () => + loadProjectFromFiles({ + "/src/test.ts": Utils.dedent` export const x = 1;`, - }), - commandLineArgs: ["/src/test.ts", "--listFilesOnly"] + }), + commandLineArgs: ["/src/test.ts", "--listFilesOnly"], }); verifyTsc({ scenario: "listFilesOnly", subScenario: "combined with incremental", - fs: () => loadProjectFromFiles({ - "/src/test.ts": `export const x = 1;`, - "/src/tsconfig.json": "{}" - }), + fs: () => + loadProjectFromFiles({ + "/src/test.ts": `export const x = 1;`, + "/src/tsconfig.json": "{}", + }), commandLineArgs: ["-p", "/src", "--incremental", "--listFilesOnly"], edits: [ { @@ -43,7 +48,7 @@ describe("unittests:: tsc:: listFilesOnly::", () => { { ...noChangeRun, commandLineArgs: ["-p", "/src", "--incremental"], - } - ] + }, + ], }); }); diff --git a/src/testRunner/unittests/tsc/moduleResolution.ts b/src/testRunner/unittests/tsc/moduleResolution.ts index 7be319098fcdc..4e235aec14c24 100644 --- a/src/testRunner/unittests/tsc/moduleResolution.ts +++ b/src/testRunner/unittests/tsc/moduleResolution.ts @@ -1,6 +1,15 @@ -import { getFsConentsForNode10ResultAtTypesPackageJson, getFsContentsForNode10Result, getFsContentsForNode10ResultDts, getFsContentsForNode10ResultPackageJson } from "../helpers/node10Result"; -import { verifyTsc } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + getFsConentsForNode10ResultAtTypesPackageJson, + getFsContentsForNode10Result, + getFsContentsForNode10ResultDts, + getFsContentsForNode10ResultPackageJson, +} from "../helpers/node10Result"; +import { + verifyTsc, +} from "../helpers/tsc"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsc:: moduleResolution::", () => { verifyTsc({ @@ -20,27 +29,51 @@ describe("unittests:: tsc:: moduleResolution::", () => { }, { caption: "add the node10Result in @types", - edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/@types/bar/index.d.ts", getFsContentsForNode10ResultDts("bar")), + edit: fs => + fs.writeFileSync( + "/home/src/projects/project/node_modules/@types/bar/index.d.ts", + getFsContentsForNode10ResultDts("bar"), + ), }, { caption: "add the ndoe10Result in package/types", - edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/foo/index.d.ts", getFsContentsForNode10ResultDts("foo")), + edit: fs => + fs.writeFileSync( + "/home/src/projects/project/node_modules/foo/index.d.ts", + getFsContentsForNode10ResultDts("foo"), + ), }, { caption: "update package.json from @types so error is fixed", - edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/@types/bar/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true)), + edit: fs => + fs.writeFileSync( + "/home/src/projects/project/node_modules/@types/bar/package.json", + getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true), + ), }, { caption: "update package.json so error is fixed", - edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/foo/package.json", getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true)), + edit: fs => + fs.writeFileSync( + "/home/src/projects/project/node_modules/foo/package.json", + getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true), + ), }, { caption: "update package.json from @types so error is introduced", - edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/@types/bar2/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false)), + edit: fs => + fs.writeFileSync( + "/home/src/projects/project/node_modules/@types/bar2/package.json", + getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false), + ), }, { caption: "update package.json so error is introduced", - edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/foo2/package.json", getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false)), + edit: fs => + fs.writeFileSync( + "/home/src/projects/project/node_modules/foo2/package.json", + getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false), + ), }, { caption: "delete the node10Result in @types", @@ -52,12 +85,20 @@ describe("unittests:: tsc:: moduleResolution::", () => { }, { caption: "add the node10Result in @types", - edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/@types/bar2/index.d.ts", getFsContentsForNode10ResultDts("bar2")), + edit: fs => + fs.writeFileSync( + "/home/src/projects/project/node_modules/@types/bar2/index.d.ts", + getFsContentsForNode10ResultDts("bar2"), + ), }, { caption: "add the ndoe10Result in package/types", - edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/foo2/index.d.ts", getFsContentsForNode10ResultDts("foo2")), + edit: fs => + fs.writeFileSync( + "/home/src/projects/project/node_modules/foo2/index.d.ts", + getFsContentsForNode10ResultDts("foo2"), + ), }, - ] + ], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsc/projectReferences.ts b/src/testRunner/unittests/tsc/projectReferences.ts index e6bd7ce6caf20..bd3df222617d7 100644 --- a/src/testRunner/unittests/tsc/projectReferences.ts +++ b/src/testRunner/unittests/tsc/projectReferences.ts @@ -1,45 +1,49 @@ import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsc:: projectReferences::", () => { verifyTsc({ scenario: "projectReferences", subScenario: "when project contains invalid project reference", - fs: () => loadProjectFromFiles({ - "/src/project/src/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - module: "amd", - outFile: "theApp.js" - }, - references: [ - { path: "../Util/Dates" } - ] + fs: () => + loadProjectFromFiles({ + "/src/project/src/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "amd", + outFile: "theApp.js", + }, + references: [ + { path: "../Util/Dates" }, + ], + }), }), - }), commandLineArgs: ["--p", "src/project"], }); verifyTsc({ scenario: "projectReferences", subScenario: "when project references composite project with noEmit", - fs: () => loadProjectFromFiles({ - "/src/utils/index.ts": "export const x = 10;", - "/src/utils/tsconfig.json": JSON.stringify({ - compilerOptions: { - composite: true, - noEmit: true, - } - }), - "/src/project/index.ts": `import { x } from "../utils";`, - "/src/project/tsconfig.json": JSON.stringify({ - references: [ - { path: "../utils" } - ] + fs: () => + loadProjectFromFiles({ + "/src/utils/index.ts": "export const x = 10;", + "/src/utils/tsconfig.json": JSON.stringify({ + compilerOptions: { + composite: true, + noEmit: true, + }, + }), + "/src/project/index.ts": `import { x } from "../utils";`, + "/src/project/tsconfig.json": JSON.stringify({ + references: [ + { path: "../utils" }, + ], + }), }), - }), - commandLineArgs: ["--p", "src/project"] + commandLineArgs: ["--p", "src/project"], }); }); diff --git a/src/testRunner/unittests/tsc/projectReferencesConfig.ts b/src/testRunner/unittests/tsc/projectReferencesConfig.ts index ae2f4c736cc39..4a631c946702f 100644 --- a/src/testRunner/unittests/tsc/projectReferencesConfig.ts +++ b/src/testRunner/unittests/tsc/projectReferencesConfig.ts @@ -1,6 +1,10 @@ import * as ts from "../../_namespaces/ts"; -import { verifyTsc } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + verifyTsc, +} from "../helpers/tsc"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; function emptyModule() { return "export { };"; @@ -17,37 +21,42 @@ function moduleImporting(...names: string[]) { function getConfig({ references, options, config }: { references?: (string | ts.ProjectReference)[]; options?: ts.CompilerOptions; - config?: object + config?: object; } = {}) { - return JSON.stringify({ - compilerOptions: { - composite: true, - outDir: "bin", - ...options + return JSON.stringify( + { + compilerOptions: { + composite: true, + outDir: "bin", + ...options, + }, + references: references?.map(r => { + if (typeof r === "string") { + return { path: r }; + } + return r; + }) || [], + ...config, }, - references: references?.map(r => { - if (typeof r === "string") { - return { path: r }; - } - return r; - }) || [], - ...config, - }, undefined, " "); + undefined, + " ", + ); } describe("unittests:: config:: project-references meta check", () => { verifyTsc({ scenario: "projectReferencesConfig", subScenario: "default setup was created correctly", - fs: () => loadProjectFromFiles({ - "/primary/tsconfig.json": getConfig(), - "/primary/a.ts": emptyModule(), - "/secondary/tsconfig.json": getConfig({ - references: ["../primary"] + fs: () => + loadProjectFromFiles({ + "/primary/tsconfig.json": getConfig(), + "/primary/a.ts": emptyModule(), + "/secondary/tsconfig.json": getConfig({ + references: ["../primary"], + }), + "/secondary/b.ts": moduleImporting("../primary/a"), }), - "/secondary/b.ts": moduleImporting("../primary/a"), - }), - commandLineArgs: ["--p", "/primary/tsconfig.json"] + commandLineArgs: ["--p", "/primary/tsconfig.json"], }); }); @@ -58,114 +67,121 @@ describe("unittests:: config:: project-references constraint checking for settin verifyTsc({ scenario: "projectReferencesConfig", subScenario: "errors when declaration = false", - fs: () => loadProjectFromFiles({ - "/primary/tsconfig.json": getConfig({ - options: { - declaration: false - } + fs: () => + loadProjectFromFiles({ + "/primary/tsconfig.json": getConfig({ + options: { + declaration: false, + }, + }), + "/primary/a.ts": emptyModule(), }), - "/primary/a.ts": emptyModule(), - }), - commandLineArgs: ["--p", "/primary/tsconfig.json"] + commandLineArgs: ["--p", "/primary/tsconfig.json"], }); verifyTsc({ scenario: "projectReferencesConfig", subScenario: "errors when the referenced project doesnt have composite", - fs: () => loadProjectFromFiles({ - "/primary/tsconfig.json": getConfig({ - options: { - composite: false - } + fs: () => + loadProjectFromFiles({ + "/primary/tsconfig.json": getConfig({ + options: { + composite: false, + }, + }), + "/primary/a.ts": emptyModule(), + "/reference/tsconfig.json": getConfig({ + references: ["../primary"], + config: { + files: ["b.ts"], + }, + }), + "/reference/b.ts": moduleImporting("../primary/a"), }), - "/primary/a.ts": emptyModule(), - "/reference/tsconfig.json": getConfig({ - references: ["../primary"], - config: { - files: ["b.ts"] - } - }), - "/reference/b.ts": moduleImporting("../primary/a"), - }), - commandLineArgs: ["--p", "/reference/tsconfig.json"] + commandLineArgs: ["--p", "/reference/tsconfig.json"], }); verifyTsc({ scenario: "projectReferencesConfig", subScenario: "does not error when the referenced project doesnt have composite if its a container project", - fs: () => loadProjectFromFiles({ - "/primary/tsconfig.json": getConfig({ - options: { - composite: false - } + fs: () => + loadProjectFromFiles({ + "/primary/tsconfig.json": getConfig({ + options: { + composite: false, + }, + }), + "/primary/a.ts": emptyModule(), + "/reference/tsconfig.json": getConfig({ + references: ["../primary"], + config: { + files: [], + }, + }), + "/reference/b.ts": moduleImporting("../primary/a"), }), - "/primary/a.ts": emptyModule(), - "/reference/tsconfig.json": getConfig({ - references: ["../primary"], - config: { - files: [] - } - }), - "/reference/b.ts": moduleImporting("../primary/a"), - }), - commandLineArgs: ["--p", "/reference/tsconfig.json"] + commandLineArgs: ["--p", "/reference/tsconfig.json"], }); verifyTsc({ scenario: "projectReferencesConfig", subScenario: "errors when the file list is not exhaustive", - fs: () => loadProjectFromFiles({ - "/primary/tsconfig.json": getConfig({ - config: { - files: ["a.ts"] - } + fs: () => + loadProjectFromFiles({ + "/primary/tsconfig.json": getConfig({ + config: { + files: ["a.ts"], + }, + }), + "/primary/a.ts": "import * as b from './b'", + "/primary/b.ts": "export {}", }), - "/primary/a.ts": "import * as b from './b'", - "/primary/b.ts": "export {}", - }), - commandLineArgs: ["--p", "/primary/tsconfig.json"] + commandLineArgs: ["--p", "/primary/tsconfig.json"], }); verifyTsc({ scenario: "projectReferencesConfig", subScenario: "errors when the referenced project doesnt exist", - fs: () => loadProjectFromFiles({ - "/primary/tsconfig.json": getConfig({ - references: ["../foo"] + fs: () => + loadProjectFromFiles({ + "/primary/tsconfig.json": getConfig({ + references: ["../foo"], + }), + "/primary/a.ts": emptyModule(), }), - "/primary/a.ts": emptyModule(), - }), - commandLineArgs: ["--p", "/primary/tsconfig.json"] + commandLineArgs: ["--p", "/primary/tsconfig.json"], }); verifyTsc({ scenario: "projectReferencesConfig", subScenario: "errors when a prepended project reference doesnt set outFile", - fs: () => loadProjectFromFiles({ - "/primary/tsconfig.json": getConfig({ - references: [{ path: "../someProj", prepend: true }], + fs: () => + loadProjectFromFiles({ + "/primary/tsconfig.json": getConfig({ + references: [{ path: "../someProj", prepend: true }], + }), + "/primary/a.ts": emptyModule(), + "/someProj/tsconfig.json": getConfig(), + "/someProj/b.ts": "const x = 100;", }), - "/primary/a.ts": emptyModule(), - "/someProj/tsconfig.json": getConfig(), - "/someProj/b.ts": "const x = 100;", - }), - commandLineArgs: ["--p", "/primary/tsconfig.json", "--ignoreDeprecations", "5.0"] + commandLineArgs: ["--p", "/primary/tsconfig.json", "--ignoreDeprecations", "5.0"], }); verifyTsc({ scenario: "projectReferencesConfig", subScenario: "errors when a prepended project reference output doesnt exist", - fs: () => loadProjectFromFiles({ - "/primary/tsconfig.json": getConfig({ - references: [{ path: "../someProj", prepend: true }], - }), - "/primary/a.ts": "const y = x;", - "/someProj/tsconfig.json": getConfig({ - options: { outFile: "foo.js" } + fs: () => + loadProjectFromFiles({ + "/primary/tsconfig.json": getConfig({ + references: [{ path: "../someProj", prepend: true }], + }), + "/primary/a.ts": "const y = x;", + "/someProj/tsconfig.json": getConfig({ + options: { outFile: "foo.js" }, + }), + "/someProj/b.ts": "const x = 100;", }), - "/someProj/b.ts": "const x = 100;", - }), - commandLineArgs: ["--p", "/primary/tsconfig.json", "--ignoreDeprecations", "5.0"] + commandLineArgs: ["--p", "/primary/tsconfig.json", "--ignoreDeprecations", "5.0"], }); }); @@ -176,16 +192,17 @@ describe("unittests:: config:: project-references path mapping", () => { verifyTsc({ scenario: "projectReferencesConfig", subScenario: "redirects to the output dts file", - fs: () => loadProjectFromFiles({ - "/alpha/tsconfig.json": getConfig(), - "/alpha/a.ts": "export const m: number = 3;", - "/alpha/bin/a.d.ts": emptyModule(), - "/beta/tsconfig.json": getConfig({ - references: ["../alpha"] + fs: () => + loadProjectFromFiles({ + "/alpha/tsconfig.json": getConfig(), + "/alpha/a.ts": "export const m: number = 3;", + "/alpha/bin/a.d.ts": emptyModule(), + "/beta/tsconfig.json": getConfig({ + references: ["../alpha"], + }), + "/beta/b.ts": "import { m } from '../alpha/a'", }), - "/beta/b.ts": "import { m } from '../alpha/a'", - }), - commandLineArgs: ["--p", "/beta/tsconfig.json", "--explainFiles"] + commandLineArgs: ["--p", "/beta/tsconfig.json", "--explainFiles"], }); }); @@ -193,35 +210,37 @@ describe("unittests:: config:: project-references nice-behavior", () => { verifyTsc({ scenario: "projectReferencesConfig", subScenario: "issues a nice error when the input file is missing", - fs: () => loadProjectFromFiles({ - "/alpha/tsconfig.json": getConfig(), - "/alpha/a.ts": "export const m: number = 3;", - "/beta/tsconfig.json": getConfig({ - references: ["../alpha"] + fs: () => + loadProjectFromFiles({ + "/alpha/tsconfig.json": getConfig(), + "/alpha/a.ts": "export const m: number = 3;", + "/beta/tsconfig.json": getConfig({ + references: ["../alpha"], + }), + "/beta/b.ts": "import { m } from '../alpha/a'", }), - "/beta/b.ts": "import { m } from '../alpha/a'", - }), - commandLineArgs: ["--p", "/beta/tsconfig.json"] + commandLineArgs: ["--p", "/beta/tsconfig.json"], }); verifyTsc({ scenario: "projectReferencesConfig", subScenario: "issues a nice error when the input file is missing when module reference is not relative", - fs: () => loadProjectFromFiles({ - "/alpha/tsconfig.json": getConfig(), - "/alpha/a.ts": "export const m: number = 3;", - "/beta/tsconfig.json": getConfig({ - references: ["../alpha"], - options: { - baseUrl: "./", - paths: { - "@alpha/*": ["/alpha/*"] - } - } + fs: () => + loadProjectFromFiles({ + "/alpha/tsconfig.json": getConfig(), + "/alpha/a.ts": "export const m: number = 3;", + "/beta/tsconfig.json": getConfig({ + references: ["../alpha"], + options: { + baseUrl: "./", + paths: { + "@alpha/*": ["/alpha/*"], + }, + }, + }), + "/beta/b.ts": "import { m } from '@alpha/a'", }), - "/beta/b.ts": "import { m } from '@alpha/a'", - }), - commandLineArgs: ["--p", "/beta/tsconfig.json"] + commandLineArgs: ["--p", "/beta/tsconfig.json"], }); }); @@ -232,11 +251,12 @@ describe("unittests:: config:: project-references behavior changes under composi verifyTsc({ scenario: "projectReferencesConfig", subScenario: "doesnt infer the rootDir from source paths", - fs: () => loadProjectFromFiles({ - "/alpha/tsconfig.json": getConfig(), - "/alpha/src/a.ts": "export const m: number = 3;", - }), - commandLineArgs: ["--p", "/alpha/tsconfig.json"] + fs: () => + loadProjectFromFiles({ + "/alpha/tsconfig.json": getConfig(), + "/alpha/src/a.ts": "export const m: number = 3;", + }), + commandLineArgs: ["--p", "/alpha/tsconfig.json"], }); }); @@ -244,11 +264,12 @@ describe("unittests:: config:: project-references errors when a file in a compos verifyTsc({ scenario: "projectReferencesConfig", subScenario: "errors when a file is outside the rootdir", - fs: () => loadProjectFromFiles({ - "/alpha/tsconfig.json": getConfig(), - "/alpha/src/a.ts": "import * as b from '../../beta/b'", - "/beta/b.ts": "export { }", - }), - commandLineArgs: ["--p", "/alpha/tsconfig.json"] + fs: () => + loadProjectFromFiles({ + "/alpha/tsconfig.json": getConfig(), + "/alpha/src/a.ts": "import * as b from '../../beta/b'", + "/beta/b.ts": "export { }", + }), + commandLineArgs: ["--p", "/alpha/tsconfig.json"], }); }); diff --git a/src/testRunner/unittests/tsc/redirect.ts b/src/testRunner/unittests/tsc/redirect.ts index bd56f7aafdc53..83328e47c052f 100644 --- a/src/testRunner/unittests/tsc/redirect.ts +++ b/src/testRunner/unittests/tsc/redirect.ts @@ -1,37 +1,40 @@ import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsc:: redirect::", () => { verifyTsc({ scenario: "redirect", subScenario: "when redirecting ts file", - fs: () => loadProjectFromFiles({ - "/src/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - outDir: "out" - }, - include: [ - "copy1/node_modules/target/*", - "copy2/node_modules/target/*", - ] - }), - "/src/project/copy1/node_modules/target/index.ts": "export const a = 1;", - "/src/project/copy1/node_modules/target/import.ts": `import {} from "./";`, - "/src/project/copy1/node_modules/target/package.json": JSON.stringify({ - name: "target", - version: "1.0.0", - main: "index.js", - }), - "/src/project/copy2/node_modules/target/index.ts": "export const a = 1;", - "/src/project/copy2/node_modules/target/import.ts": `import {} from "./";`, - "/src/project/copy2/node_modules/target/package.json": JSON.stringify({ - name: "target", - version: "1.0.0", - main: "index.js", + fs: () => + loadProjectFromFiles({ + "/src/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + outDir: "out", + }, + include: [ + "copy1/node_modules/target/*", + "copy2/node_modules/target/*", + ], + }), + "/src/project/copy1/node_modules/target/index.ts": "export const a = 1;", + "/src/project/copy1/node_modules/target/import.ts": `import {} from "./";`, + "/src/project/copy1/node_modules/target/package.json": JSON.stringify({ + name: "target", + version: "1.0.0", + main: "index.js", + }), + "/src/project/copy2/node_modules/target/index.ts": "export const a = 1;", + "/src/project/copy2/node_modules/target/import.ts": `import {} from "./";`, + "/src/project/copy2/node_modules/target/package.json": JSON.stringify({ + name: "target", + version: "1.0.0", + main: "index.js", + }), }), - }), commandLineArgs: ["-p", "src/project"], }); }); diff --git a/src/testRunner/unittests/tsc/runWithoutArgs.ts b/src/testRunner/unittests/tsc/runWithoutArgs.ts index ee4c7a8ae0a41..5947dd1c99f7f 100644 --- a/src/testRunner/unittests/tsc/runWithoutArgs.ts +++ b/src/testRunner/unittests/tsc/runWithoutArgs.ts @@ -1,7 +1,9 @@ import { verifyTsc, } from "../helpers/tsc"; -import { loadProjectFromFiles } from "../helpers/vfs"; +import { + loadProjectFromFiles, +} from "../helpers/vfs"; describe("unittests:: tsc:: runWithoutArgs::", () => { verifyTsc({ @@ -9,12 +11,13 @@ describe("unittests:: tsc:: runWithoutArgs::", () => { subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped", fs: () => loadProjectFromFiles({}), commandLineArgs: [], - environmentVariables: { TS_TEST_TERMINAL_WIDTH: "120" } + environmentVariables: { TS_TEST_TERMINAL_WIDTH: "120" }, }); verifyTsc({ scenario: "runWithoutArgs", - subScenario: "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped when host can't provide terminal width", + subScenario: + "show help with ExitStatus.DiagnosticsPresent_OutputsSkipped when host can't provide terminal width", fs: () => loadProjectFromFiles({}), commandLineArgs: [], }); @@ -24,7 +27,6 @@ describe("unittests:: tsc:: runWithoutArgs::", () => { subScenario: "does not add color when NO_COLOR is set", fs: () => loadProjectFromFiles({}), commandLineArgs: [], - environmentVariables: { NO_COLOR: "true" } + environmentVariables: { NO_COLOR: "true" }, }); - }); diff --git a/src/testRunner/unittests/tscWatch/consoleClearing.ts b/src/testRunner/unittests/tscWatch/consoleClearing.ts index f48ea56bd5060..8e233fc15f820 100644 --- a/src/testRunner/unittests/tscWatch/consoleClearing.ts +++ b/src/testRunner/unittests/tscWatch/consoleClearing.ts @@ -16,7 +16,7 @@ describe("unittests:: tsc-watch:: console clearing", () => { const scenario = "consoleClearing"; const file: File = { path: "/f.ts", - content: "" + content: "", }; const makeChangeToFile: TscWatchCompileChange[] = [{ @@ -42,11 +42,11 @@ describe("unittests:: tsc-watch:: console clearing", () => { describe("when preserveWatchOutput is true in config file", () => { const compilerOptions: ts.CompilerOptions = { - preserveWatchOutput: true + preserveWatchOutput: true, }; const configFile: File = { path: "/tsconfig.json", - content: JSON.stringify({ compilerOptions }) + content: JSON.stringify({ compilerOptions }), }; const files = [file, configFile, libFile]; it("using createWatchOfConfigFile ", () => { @@ -64,12 +64,13 @@ describe("unittests:: tsc-watch:: console clearing", () => { ...baseline, getPrograms: () => [[watch.getCurrentProgram().getProgram(), watch.getCurrentProgram()]], edits: makeChangeToFile, - watchOrSolution: watch + watchOrSolution: watch, }); }); verifyTscWatch({ scenario, - subScenario: "when preserveWatchOutput is true in config file/when createWatchProgram is invoked with configFileParseResult on WatchCompilerHostOfConfigFile", + subScenario: + "when preserveWatchOutput is true in config file/when createWatchProgram is invoked with configFileParseResult on WatchCompilerHostOfConfigFile", commandLineArgs: ["--w", "-p", configFile.path], sys: () => createWatchedSystem(files), edits: makeChangeToFile, diff --git a/src/testRunner/unittests/tscWatch/emit.ts b/src/testRunner/unittests/tscWatch/emit.ts index 4cd7a3b591920..2c370e7044515 100644 --- a/src/testRunner/unittests/tscWatch/emit.ts +++ b/src/testRunner/unittests/tscWatch/emit.ts @@ -17,24 +17,25 @@ describe("unittests:: tsc-watch:: emit with outFile or out setting", () => { scenario, subScenario: `emit with outFile or out setting/${subScenario}`, commandLineArgs: ["--w", "-p", "/a/tsconfig.json"], - sys: () => createWatchedSystem({ - "/a/a.ts": "let x = 1", - "/a/b.ts": "let y = 1", - "/a/tsconfig.json": JSON.stringify({ compilerOptions: { out, outFile } }), - [libFile.path]: libFile.content, - }), + sys: () => + createWatchedSystem({ + "/a/a.ts": "let x = 1", + "/a/b.ts": "let y = 1", + "/a/tsconfig.json": JSON.stringify({ compilerOptions: { out, outFile } }), + [libFile.path]: libFile.content, + }), edits: [ { caption: "Make change in the file", edit: sys => sys.writeFile("/a/a.ts", "let x = 11"), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Make change in the file again", edit: sys => sys.writeFile("/a/a.ts", "let xy = 11"), - timeouts: sys => sys.runQueuedTimeoutCallbacks() - } - ] + timeouts: sys => sys.runQueuedTimeoutCallbacks(), + }, + ], }); } verifyOutAndOutFileSetting("config does not have out or outFile"); @@ -49,28 +50,31 @@ describe("unittests:: tsc-watch:: emit with outFile or out setting", () => { sys: () => { const file1: File = { path: "/a/b/output/AnotherDependency/file1.d.ts", - content: "declare namespace Common.SomeComponent.DynamicMenu { enum Z { Full = 0, Min = 1, Average = 2, } }" + content: + "declare namespace Common.SomeComponent.DynamicMenu { enum Z { Full = 0, Min = 1, Average = 2, } }", }; const file2: File = { path: "/a/b/dependencies/file2.d.ts", - content: "declare namespace Dependencies.SomeComponent { export class SomeClass { version: string; } }" + content: + "declare namespace Dependencies.SomeComponent { export class SomeClass { version: string; } }", }; const file3: File = { path: "/a/b/project/src/main.ts", - content: "namespace Main { export function fooBar() {} }" + content: "namespace Main { export function fooBar() {} }", }; const file4: File = { path: "/a/b/project/src/main2.ts", - content: "namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }" + content: + "namespace main.file4 { import DynamicMenu = Common.SomeComponent.DynamicMenu; export function foo(a: DynamicMenu.z) { } }", }; const configFile: File = { path: "/a/b/project/tsconfig.json", content: JSON.stringify({ - compilerOptions: useOutFile ? - { outFile: "../output/common.js", target: "es5" } : - { outDir: "../output", target: "es5" }, - files: [file1.path, file2.path, file3.path, file4.path] - }) + compilerOptions: useOutFile + ? { outFile: "../output/common.js", target: "es5" } + : { outDir: "../output", target: "es5" }, + files: [file1.path, file2.path, file3.path, file4.path], + }), }; return createWatchedSystem([file1, file2, file3, file4, libFile, configFile]); }, @@ -95,14 +99,14 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { getAdditionalFileOrFolder?: () => File[]; /** initial list of files to emit if not the default list */ firstReloadFileList?: string[]; - changes: TscWatchCompileChange[] + changes: TscWatchCompileChange[]; } function verifyTscWatchEmit({ subScenario, configObj, getAdditionalFileOrFolder, firstReloadFileList, - changes + changes, }: VerifyTscWatchEmit) { verifyTscWatch({ scenario, @@ -131,20 +135,30 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { const globalFile3: File = { path: globalFilePath, - content: `interface GlobalFoo { age: number }` + content: `interface GlobalFoo { age: number }`, }; const configFile: File = { path: configFilePath, - content: JSON.stringify(configObj || {}) + content: JSON.stringify(configObj || {}), }; const additionalFiles = getAdditionalFileOrFolder?.() || ts.emptyArray; - const files = [moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile, ...additionalFiles]; - return createWatchedSystem(firstReloadFileList ? - ts.map(firstReloadFileList, fileName => ts.find(files, file => file.path === fileName)!) : - files + const files = [ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ...additionalFiles, + ]; + return createWatchedSystem( + firstReloadFileList + ? ts.map(firstReloadFileList, fileName => ts.find(files, file => file.path === fileName)!) + : files, ); }, - edits: changes + edits: changes, }); } @@ -158,15 +172,21 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { }; verifyTscWatchEmit({ - subScenario: "should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", + subScenario: + "should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", changes: [ changeModuleFile1Shape, { - caption: "Change the content of moduleFile1 to `export var T: number;export function Foo() { console.log('hi'); };`", - edit: sys => sys.writeFile(moduleFile1Path, `export var T: number;export function Foo() { console.log('hi'); };`), + caption: + "Change the content of moduleFile1 to `export var T: number;export function Foo() { console.log('hi'); };`", + edit: sys => + sys.writeFile( + moduleFile1Path, + `export var T: number;export function Foo() { console.log('hi'); };`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ @@ -184,7 +204,8 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { - caption: "Change the content of moduleFile1 to `export var T: number;export var T2: string;export function Foo() { };`", + caption: + "Change the content of moduleFile1 to `export var T: number;export var T2: string;export function Foo() { };`", edit: sys => sys.writeFile(moduleFile1Path, `export let y = Foo();`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, @@ -197,8 +218,8 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { modifyModuleFile1Shape(sys); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ @@ -211,8 +232,8 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { sys.deleteFile(file1Consumer2Path); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ @@ -225,8 +246,8 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { modifyModuleFile1Shape(sys); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ @@ -238,8 +259,8 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { caption: "change file1 internal, and verify only file1 is affected", edit: sys => sys.appendFile(moduleFile1Path, "var T1: number;"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ @@ -249,31 +270,31 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { caption: "change shape of global file", edit: sys => sys.appendFile(globalFilePath, "var T2: string;"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ subScenario: "should always return the file itself if '--isolatedModules' is specified", configObj: { compilerOptions: { isolatedModules: true } }, changes: [ - changeModuleFile1Shape - ] + changeModuleFile1Shape, + ], }); verifyTscWatchEmit({ subScenario: "should always return the file itself if '--out' or '--outFile' is specified", configObj: { compilerOptions: { module: "system", outFile: "/a/b/out.js" } }, changes: [ - changeModuleFile1Shape - ] + changeModuleFile1Shape, + ], }); verifyTscWatchEmit({ subScenario: "should return cascaded affected file list", getAdditionalFileOrFolder: () => [{ path: "/a/b/file1Consumer1Consumer1.ts", - content: `import {y} from "./file1Consumer1";` + content: `import {y} from "./file1Consumer1";`, }], changes: [ { @@ -289,8 +310,8 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { sys.writeFile(moduleFile1Path, `export var T2: number;export function Foo() { };`); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ @@ -299,13 +320,13 @@ describe("unittests:: tsc-watch:: emit for configured projects", () => { { path: "/a/b/file1.ts", content: `/// -export var t1 = 10;` +export var t1 = 10;`, }, { path: "/a/b/file2.ts", content: `/// -export var t2 = 10;` - } +export var t2 = 10;`, + }, ], firstReloadFileList: [libFile.path, "/a/b/file1.ts", "/a/b/file2.ts", configFilePath], changes: [ @@ -313,8 +334,8 @@ export var t2 = 10;` caption: "change file1", edit: sys => sys.appendFile("/a/b/file1.ts", "export var t3 = 10;"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ @@ -322,7 +343,7 @@ export var t2 = 10;` getAdditionalFileOrFolder: () => [{ path: "/a/b/referenceFile1.ts", content: `/// -export var x = Foo();` +export var x = Foo();`, }], firstReloadFileList: [libFile.path, "/a/b/referenceFile1.ts", moduleFile1Path, configFilePath], changes: [ @@ -330,8 +351,8 @@ export var x = Foo();` caption: "delete moduleFile1", edit: sys => sys.deleteFile(moduleFile1Path), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatchEmit({ @@ -339,7 +360,7 @@ export var x = Foo();` getAdditionalFileOrFolder: () => [{ path: "/a/b/referenceFile1.ts", content: `/// -export var x = Foo();` +export var x = Foo();`, }], firstReloadFileList: [libFile.path, "/a/b/referenceFile1.ts", configFilePath], changes: [ @@ -352,8 +373,8 @@ export var x = Foo();` caption: "create moduleFile2", edit: sys => sys.writeFile(moduleFile2Path, "export var Foo4 = 10;"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); }); @@ -363,22 +384,23 @@ describe("unittests:: tsc-watch:: emit file content", () => { scenario, subScenario: `emit file content/${subScenario}`, commandLineArgs: ["--w", "/a/app.ts"], - sys: () => createWatchedSystem( - [ - { - path: "/a/app.ts", - content: ["var x = 1;", "var y = 2;"].join(newLine) - }, - libFile - ], - { newLine } - ), + sys: () => + createWatchedSystem( + [ + { + path: "/a/app.ts", + content: ["var x = 1;", "var y = 2;"].join(newLine), + }, + libFile, + ], + { newLine }, + ), edits: [ { caption: "Append a line", edit: sys => sys.appendFile("/a/app.ts", newLine + "var z = 3;"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); } @@ -392,22 +414,22 @@ describe("unittests:: tsc-watch:: emit file content", () => { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: `export function Foo() { return 10; }` + content: `export function Foo() { return 10; }`, }; const file2 = { path: "/a/b/f2.ts", - content: `import {Foo} from "./f1"; export let y = Foo();` + content: `import {Foo} from "./f1"; export let y = Foo();`, }; const file3 = { path: "/a/b/f3.ts", - content: `import {y} from "./f2"; let x = y;` + content: `import {y} from "./f2"; let x = y;`, }; const configFile = { path: "/a/b/tsconfig.json", - content: "{}" + content: "{}", }; return createWatchedSystem([file1, file2, file3, configFile, libFile]); }, @@ -421,7 +443,7 @@ describe("unittests:: tsc-watch:: emit file content", () => { caption: "Again Append content to f1", edit: sys => sys.appendFile("/a/b/f1.ts", "export function fooN() { return 2; }"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); @@ -433,24 +455,25 @@ describe("unittests:: tsc-watch:: emit file content", () => { const currentDirectory = "/user/someone/projects/myproject"; const file1: File = { path: `${currentDirectory}/file1.ts`, - content: "export const enum E1 { V = 1 }" + content: "export const enum E1 { V = 1 }", }; const file2: File = { path: `${currentDirectory}/file2.ts`, - content: `import { E1 } from "./file1"; export const enum E2 { V = E1.V }` + content: `import { E1 } from "./file1"; export const enum E2 { V = E1.V }`, }; const file3: File = { path: `${currentDirectory}/file3.ts`, - content: `import { E2 } from "./file2"; const v: E2 = E2.V;` + content: `import { E2 } from "./file2"; const v: E2 = E2.V;`, }; return createWatchedSystem([file1, file2, file3, libFile]); }, edits: [ { caption: "Append content to file3", - edit: sys => sys.appendFile("/user/someone/projects/myproject/file3.ts", "function foo2() { return 2; }"), + edit: sys => + sys.appendFile("/user/someone/projects/myproject/file3.ts", "function foo2() { return 2; }"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); @@ -462,15 +485,15 @@ describe("unittests:: tsc-watch:: emit file content", () => { const projectLocation = "/home/username/project"; const file: File = { path: `${projectLocation}/app/file.ts`, - content: "var a = 10;" + content: "var a = 10;", }; const configFile: File = { path: `${projectLocation}/tsconfig.json`, content: JSON.stringify({ include: [ - "app/**/*.ts" - ] - }) + "app/**/*.ts", + ], + }), }; const files = [file, configFile, libFile]; return createWatchedSystem(files, { currentDirectory: projectLocation, useCaseSensitiveFileNames: true }); @@ -478,17 +501,21 @@ describe("unittests:: tsc-watch:: emit file content", () => { edits: [ { caption: "file is deleted and then created to modify content", - edit: sys => sys.appendFile("/home/username/project/app/file.ts", "\nvar b = 10;", { invokeFileDeleteCreateAsPartInsteadOfChange: true }), + edit: sys => + sys.appendFile("/home/username/project/app/file.ts", "\nvar b = 10;", { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + }), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); }); describe("unittests:: tsc-watch:: emit with when module emit is specified as node", () => { verifyTscWatch({ scenario, - subScenario: "when module emit is specified as node/when instead of filechanged recursive directory watcher is invoked", + subScenario: + "when module emit is specified as node/when instead of filechanged recursive directory watcher is invoked", commandLineArgs: ["--w", "--p", "/a/rootFolder/project/tsconfig.json"], sys: () => { const configFile: File = { @@ -497,33 +524,34 @@ describe("unittests:: tsc-watch:: emit with when module emit is specified as nod compilerOptions: { module: "none", allowJs: true, - outDir: "Static/scripts/" + outDir: "Static/scripts/", }, include: [ - "Scripts/**/*" + "Scripts/**/*", ], - }) + }), }; const file1: File = { path: "/a/rootFolder/project/Scripts/TypeScript.ts", - content: "var z = 10;" + content: "var z = 10;", }; const file2: File = { path: "/a/rootFolder/project/Scripts/Javascript.js", - content: "var zz = 10;" + content: "var zz = 10;", }; return createWatchedSystem([configFile, file1, file2, libFile]); }, edits: [ { caption: "Modify typescript file", - edit: sys => sys.modifyFile( - "/a/rootFolder/project/Scripts/TypeScript.ts", - "var zz30 = 100;", - { invokeDirectoryWatcherInsteadOfFileChanged: true }, - ), + edit: sys => + sys.modifyFile( + "/a/rootFolder/project/Scripts/TypeScript.ts", + "var zz30 = 100;", + { invokeDirectoryWatcherInsteadOfFileChanged: true }, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); }); diff --git a/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts b/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts index 926cf99ec5c4f..f397acb5c8a67 100644 --- a/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts +++ b/src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts @@ -1,4 +1,6 @@ -import { libContent } from "../helpers/contents"; +import { + libContent, +} from "../helpers/contents"; import { TscWatchCompileChange, verifyTscWatch, @@ -13,10 +15,10 @@ import { describe("unittests:: tsc-watch:: Emit times and Error updates in builder after program changes", () => { const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: `{}` + content: `{}`, }; interface VerifyEmitAndErrorUpdates { - subScenario: string + subScenario: string; files: () => File[]; currentDirectory?: string; changes: TscWatchCompileChange[]; @@ -31,72 +33,78 @@ describe("unittests:: tsc-watch:: Emit times and Error updates in builder after scenario: "emitAndErrorUpdates", subScenario: `default/${subScenario}`, commandLineArgs: ["--w"], - sys: () => createWatchedSystem( - files(), - { currentDirectory: currentDirectory || "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + files(), + { currentDirectory: currentDirectory || "/user/username/projects/myproject" }, + ), edits: changes, - baselineIncremental: true + baselineIncremental: true, }); verifyTscWatch({ scenario: "emitAndErrorUpdates", subScenario: `defaultAndD/${subScenario}`, commandLineArgs: ["--w", "--d"], - sys: () => createWatchedSystem( - files(), - { currentDirectory: currentDirectory || "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + files(), + { currentDirectory: currentDirectory || "/user/username/projects/myproject" }, + ), edits: changes, - baselineIncremental: true + baselineIncremental: true, }); verifyTscWatch({ scenario: "emitAndErrorUpdates", subScenario: `isolatedModules/${subScenario}`, commandLineArgs: ["--w", "--isolatedModules"], - sys: () => createWatchedSystem( - files(), - { currentDirectory: currentDirectory || "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + files(), + { currentDirectory: currentDirectory || "/user/username/projects/myproject" }, + ), edits: changes, - baselineIncremental: true + baselineIncremental: true, }); verifyTscWatch({ scenario: "emitAndErrorUpdates", subScenario: `isolatedModulesAndD/${subScenario}`, commandLineArgs: ["--w", "--isolatedModules", "--d"], - sys: () => createWatchedSystem( - files(), - { currentDirectory: currentDirectory || "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + files(), + { currentDirectory: currentDirectory || "/user/username/projects/myproject" }, + ), edits: changes, - baselineIncremental: true + baselineIncremental: true, }); verifyTscWatch({ scenario: "emitAndErrorUpdates", subScenario: `assumeChangesOnlyAffectDirectDependencies/${subScenario}`, commandLineArgs: ["--w", "--assumeChangesOnlyAffectDirectDependencies"], - sys: () => createWatchedSystem( - files(), - { currentDirectory: currentDirectory || "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + files(), + { currentDirectory: currentDirectory || "/user/username/projects/myproject" }, + ), edits: changes, - baselineIncremental: true + baselineIncremental: true, }); verifyTscWatch({ scenario: "emitAndErrorUpdates", subScenario: `assumeChangesOnlyAffectDirectDependenciesAndD/${subScenario}`, commandLineArgs: ["--w", "--assumeChangesOnlyAffectDirectDependencies", "--d"], - sys: () => createWatchedSystem( - files(), - { currentDirectory: currentDirectory || "/user/username/projects/myproject" } - ), + sys: () => + createWatchedSystem( + files(), + { currentDirectory: currentDirectory || "/user/username/projects/myproject" }, + ), edits: changes, - baselineIncremental: true + baselineIncremental: true, }); } @@ -106,7 +114,7 @@ describe("unittests:: tsc-watch:: Emit times and Error updates in builder after content: `import {B} from './b'; declare var console: any; let b = new B(); -console.log(b.c.d);` +console.log(b.c.d);`, }; function verifyDeepImportChange(subScenario: string, bFile: File, cFile: File) { @@ -128,7 +136,7 @@ console.log(b.c.d);` caption: "Rename property d to d2 of class C", edit: sys => sys.writeFile(cFile.path, cFile.content.replace("d", "d2")), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); } @@ -139,19 +147,19 @@ console.log(b.c.d);` export class B { c = new C(); -}` +}`, }; const cFile: File = { path: `/user/username/projects/myproject/c.ts`, content: `export class C { d = 1; -}` +}`, }; verifyDeepImportChange( "errors for .ts change", bFile, - cFile + cFile, ); }); describe("updates errors when deep import through declaration file changes", () => { @@ -161,19 +169,19 @@ export class B export class B { c: C; -}` +}`, }; const cFile: File = { path: `/user/username/projects/myproject/c.d.ts`, content: `export class C { d: number; -}` +}`, }; verifyDeepImportChange( "errors for .d.ts change", bFile, - cFile + cFile, ); }); }); @@ -188,13 +196,13 @@ export class B export interface Coords { x2: number; y: number; -}` +}`, }; const bFile: File = { path: `/user/username/projects/myproject/b.ts`, content: `import { Point } from "./a"; export interface PointWrapper extends Point { -}` +}`, }; const cFile: File = { path: `/user/username/projects/myproject/c.ts`, @@ -207,16 +215,16 @@ export function getPoint(): PointWrapper { y: 2 } } -};` +};`, }; const dFile: File = { path: `/user/username/projects/myproject/d.ts`, content: `import { getPoint } from "./c"; -getPoint().c.x;` +getPoint().c.x;`, }; const eFile: File = { path: `/user/username/projects/myproject/e.ts`, - content: `import "./d";` + content: `import "./d";`, }; verifyEmitAndErrorUpdates({ subScenario: "file not exporting a deep multilevel import that changes", @@ -237,7 +245,7 @@ getPoint().c.x;` edit: sys => sys.writeFile(aFile.path, aFile.content.replace("x2", "x")), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); }); describe("updates errors when file transitively exported file changes", () => { @@ -245,8 +253,8 @@ getPoint().c.x;` path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ files: ["app.ts"], - compilerOptions: { baseUrl: "." } - }) + compilerOptions: { baseUrl: "." }, + }), }; const app: File = { path: `/user/username/projects/myproject/app.ts`, @@ -255,11 +263,11 @@ export class App { public constructor() { new Data().test(); } -}` +}`, }; const lib2Public: File = { path: `/user/username/projects/myproject/lib2/public.ts`, - content: `export * from "./data";` + content: `export * from "./data";`, }; const lib2Data: File = { path: `/user/username/projects/myproject/lib2/data.ts`, @@ -271,50 +279,63 @@ export class Data { } return result; } -}` +}`, }; const lib1Public: File = { path: `/user/username/projects/myproject/lib1/public.ts`, - content: `export * from "./tools/public";` + content: `export * from "./tools/public";`, }; const lib1ToolsPublic: File = { path: `/user/username/projects/myproject/lib1/tools/public.ts`, - content: `export * from "./toolsinterface";` + content: `export * from "./toolsinterface";`, }; const lib1ToolsInterface: File = { path: `/user/username/projects/myproject/lib1/tools/toolsinterface.ts`, content: `export interface ITest { title: string; -}` +}`, }; function verifyTransitiveExports(subScenario: string, files: readonly File[]) { verifyEmitAndErrorUpdates({ subScenario: `transitive exports/${subScenario}`, - files: () => [lib1ToolsInterface, lib1ToolsPublic, app, lib2Public, lib1Public, ...files, config, libFile], + files: + () => [lib1ToolsInterface, lib1ToolsPublic, app, lib2Public, lib1Public, ...files, config, libFile], changes: [ { caption: "Rename property title to title2 of interface ITest to initialize signatures", - edit: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2")), + edit: sys => + sys.writeFile( + lib1ToolsInterface.path, + lib1ToolsInterface.content.replace("title", "title2"), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Rename property title2 to title of interface ITest to revert back to original text", - edit: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title2", "title")), + edit: sys => + sys.writeFile( + lib1ToolsInterface.path, + lib1ToolsInterface.content.replace("title2", "title"), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Rename property title to title2 of interface ITest", - edit: sys => sys.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2")), + edit: sys => + sys.writeFile( + lib1ToolsInterface.path, + lib1ToolsInterface.content.replace("title", "title2"), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); } describe("when there are no circular import and exports", () => { verifyTransitiveExports( "no circular import/export", - [lib2Data] + [lib2Data], ); }); describe("when there are circular import and exports", () => { @@ -328,18 +349,18 @@ export class Data { } return result; } -}` +}`, }; const lib2Data2: File = { path: `/user/username/projects/myproject/lib2/data2.ts`, content: `import { Data } from "./data"; export class Data2 { public dat?: Data; -}` +}`, }; verifyTransitiveExports( "yes circular import/exports", - [lib2Data, lib2Data2] + [lib2Data, lib2Data2], ); }); }); @@ -350,31 +371,48 @@ export class Data2 { caption, edit: sys => sys.writeFile(`/user/username/projects/noEmitOnError/src/main.ts`, content), // build project - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }; } const noChange: TscWatchCompileChange = { caption: "No change", - edit: sys => sys.writeFile(`/user/username/projects/noEmitOnError/src/main.ts`, sys.readFile(`/user/username/projects/noEmitOnError/src/main.ts`)!), + edit: sys => + sys.writeFile( + `/user/username/projects/noEmitOnError/src/main.ts`, + sys.readFile(`/user/username/projects/noEmitOnError/src/main.ts`)!, + ), // build project timeouts: sys => sys.runQueuedTimeoutCallbacks(), }; verifyEmitAndErrorUpdates({ subScenario: "with noEmitOnError", currentDirectory: `/user/username/projects/noEmitOnError`, - files: () => ["shared/types/db.ts", "src/main.ts", "src/other.ts", "tsconfig.json"] - .map(f => getTsBuildProjectFile("noEmitOnError", f)).concat({ path: libFile.path, content: libContent }), + files: () => + ["shared/types/db.ts", "src/main.ts", "src/other.ts", "tsconfig.json"] + .map(f => getTsBuildProjectFile("noEmitOnError", f)).concat({ + path: libFile.path, + content: libContent, + }), changes: [ noChange, - change("Fix Syntax error", `import { A } from "../shared/types/db"; + change( + "Fix Syntax error", + `import { A } from "../shared/types/db"; const a = { lastName: 'sdsd' -};`), - change("Semantic Error", `import { A } from "../shared/types/db"; -const a: string = 10;`), +};`, + ), + change( + "Semantic Error", + `import { A } from "../shared/types/db"; +const a: string = 10;`, + ), noChange, - change("Fix Semantic Error", `import { A } from "../shared/types/db"; -const a: string = "hello";`), + change( + "Fix Semantic Error", + `import { A } from "../shared/types/db"; +const a: string = "hello";`, + ), noChange, ], }); diff --git a/src/testRunner/unittests/tscWatch/extends.ts b/src/testRunner/unittests/tscWatch/extends.ts index d70f05d9830a9..db8ff56cd72d4 100644 --- a/src/testRunner/unittests/tscWatch/extends.ts +++ b/src/testRunner/unittests/tscWatch/extends.ts @@ -1,5 +1,9 @@ -import { getSymlinkedExtendsSys } from "../helpers/extends"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + getSymlinkedExtendsSys, +} from "../helpers/extends"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; describe("unittests:: tsc-watch:: extends::", () => { verifyTscWatch({ @@ -8,4 +12,4 @@ describe("unittests:: tsc-watch:: extends::", () => { sys: getSymlinkedExtendsSys, commandLineArgs: ["-w", "-p", "src", "--extendedDiagnostics"], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts b/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts index da9db45871b84..303b7c5f0cea5 100644 --- a/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts +++ b/src/testRunner/unittests/tscWatch/forceConsistentCasingInFileNames.ts @@ -13,26 +13,28 @@ import { describe("unittests:: tsc-watch:: forceConsistentCasingInFileNames", () => { const loggerFile: File = { path: `/user/username/projects/myproject/logger.ts`, - content: `export class logger { }` + content: `export class logger { }`, }; const anotherFile: File = { path: `/user/username/projects/myproject/another.ts`, - content: `import { logger } from "./logger"; new logger();` + content: `import { logger } from "./logger"; new logger();`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ - compilerOptions: { forceConsistentCasingInFileNames: true } - }) + compilerOptions: { forceConsistentCasingInFileNames: true }, + }), }; - function verifyConsistentFileNames({ subScenario, changes }: { subScenario: string; changes: TscWatchCompileChange[]; }) { + function verifyConsistentFileNames( + { subScenario, changes }: { subScenario: string; changes: TscWatchCompileChange[]; }, + ) { verifyTscWatch({ scenario: "forceConsistentCasingInFileNames", subScenario, commandLineArgs: ["--w", "--p", tsconfig.path], sys: () => createWatchedSystem([loggerFile, anotherFile, tsconfig, libFile]), - edits: changes + edits: changes, }); } @@ -43,8 +45,8 @@ describe("unittests:: tsc-watch:: forceConsistentCasingInFileNames", () => { caption: "Change module name from logger to Logger", edit: sys => sys.writeFile(anotherFile.path, anotherFile.content.replace("./logger", "./Logger")), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyConsistentFileNames({ @@ -54,8 +56,8 @@ describe("unittests:: tsc-watch:: forceConsistentCasingInFileNames", () => { caption: "Change name of file from logger to Logger", edit: sys => sys.renameFile(loggerFile.path, `/user/username/projects/myproject/Logger.ts`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -65,29 +67,35 @@ describe("unittests:: tsc-watch:: forceConsistentCasingInFileNames", () => { sys: () => { const moduleA: File = { path: `/user/username/projects/myproject/moduleA.ts`, - content: `import a = require("./ModuleC")` + content: `import a = require("./ModuleC")`, }; const moduleB: File = { path: `/user/username/projects/myproject/moduleB.ts`, - content: `import a = require("./moduleC")` + content: `import a = require("./moduleC")`, }; const moduleC: File = { path: `/user/username/projects/myproject/moduleC.ts`, - content: `export const x = 10;` + content: `export const x = 10;`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }) + content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }), }; - return createWatchedSystem([moduleA, moduleB, moduleC, libFile, tsconfig], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([moduleA, moduleB, moduleC, libFile, tsconfig], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Prepend a line to moduleA", - edit: sys => sys.prependFile(`/user/username/projects/myproject/moduleA.ts`, `// some comment - `), + edit: sys => + sys.prependFile( + `/user/username/projects/myproject/moduleA.ts`, + `// some comment + `, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); @@ -95,11 +103,12 @@ describe("unittests:: tsc-watch:: forceConsistentCasingInFileNames", () => { scenario: "forceConsistentCasingInFileNames", subScenario: "jsxImportSource option changed", commandLineArgs: ["--w", "--p", ".", "--explainFiles"], - sys: () => createWatchedSystem([ - libFile, - { - path: `/user/username/projects/myproject/node_modules/react/Jsx-runtime/index.d.ts`, - content: `export namespace JSX { + sys: () => + createWatchedSystem([ + libFile, + { + path: `/user/username/projects/myproject/node_modules/react/Jsx-runtime/index.d.ts`, + content: `export namespace JSX { interface Element {} interface IntrinsicElements { div: { @@ -111,23 +120,27 @@ export function jsx(...args: any[]): void; export function jsxs(...args: any[]): void; export const Fragment: unique symbol; `, - }, - { - path: `/user/username/projects/myproject/node_modules/react/package.json`, - content: JSON.stringify({ name: "react", version: "0.0.1" }) - }, - { - path: `/user/username/projects/myproject/index.tsx`, - content: `export const App = () =>
;` - }, - { - path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { jsx: "react-jsx", jsxImportSource: "react", forceConsistentCasingInFileNames: true }, - files: ["node_modules/react/Jsx-Runtime/index.d.ts", "index.tsx"] - }) - } - ], { currentDirectory: "/user/username/projects/myproject" }), + }, + { + path: `/user/username/projects/myproject/node_modules/react/package.json`, + content: JSON.stringify({ name: "react", version: "0.0.1" }), + }, + { + path: `/user/username/projects/myproject/index.tsx`, + content: `export const App = () =>
;`, + }, + { + path: `/user/username/projects/myproject/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + jsx: "react-jsx", + jsxImportSource: "react", + forceConsistentCasingInFileNames: true, + }, + files: ["node_modules/react/Jsx-Runtime/index.d.ts", "index.tsx"], + }), + }, + ], { currentDirectory: "/user/username/projects/myproject" }), }); function verifyWindowsStyleRoot(subScenario: string, windowsStyleRoot: string, projectRootRelative: string) { @@ -141,7 +154,7 @@ export const Fragment: unique symbol; content: ` export const a = 1; export const b = 2; -` +`, }; const moduleB: File = { path: `${windowsStyleRoot}/${projectRootRelative}/b.ts`, @@ -150,21 +163,28 @@ import { a } from "${windowsStyleRoot.toLocaleUpperCase()}/${projectRootRelative import { b } from "${windowsStyleRoot.toLocaleLowerCase()}/${projectRootRelative}/a" a;b; -` +`, }; const tsconfig: File = { path: `${windowsStyleRoot}/${projectRootRelative}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }) + content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }), }; - return createWatchedSystem([moduleA, moduleB, libFile, tsconfig], { windowsStyleRoot, useCaseSensitiveFileNames: false }); + return createWatchedSystem([moduleA, moduleB, libFile, tsconfig], { + windowsStyleRoot, + useCaseSensitiveFileNames: false, + }); }, edits: [ { caption: "Prepend a line to moduleA", - edit: sys => sys.prependFile(`${windowsStyleRoot}/${projectRootRelative}/a.ts`, `// some comment - `), + edit: sys => + sys.prependFile( + `${windowsStyleRoot}/${projectRootRelative}/a.ts`, + `// some comment + `, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); } @@ -179,12 +199,11 @@ a;b; commandLineArgs: ["--w", "--p", ".", "--explainFiles"], sys: () => { const moduleA: File = { - path: diskPath, content: ` export const a = 1; export const b = 2; -` +`, }; const symlinkA: SymLink = { path: `/user/username/projects/myproject/link.ts`, @@ -197,30 +216,61 @@ import { a } from "${importedPath}"; import { b } from "./link"; a;b; -` +`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }) + content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }), }; - return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Prepend a line to moduleA", - edit: sys => sys.prependFile(diskPath, `// some comment - `), + edit: sys => + sys.prependFile( + diskPath, + `// some comment + `, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); } - verifyFileSymlink("when both file symlink target and import match disk", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/XY.ts`, `./XY`); - verifyFileSymlink("when file symlink target matches disk but import does not", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/Xy.ts`, `./XY`); - verifyFileSymlink("when import matches disk but file symlink target does not", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/XY.ts`, `./Xy`); - verifyFileSymlink("when import and file symlink target agree but do not match disk", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/Xy.ts`, `./Xy`); - verifyFileSymlink("when import, file symlink target, and disk are all different", `/user/username/projects/myproject/XY.ts`, `/user/username/projects/myproject/Xy.ts`, `./yX`); + verifyFileSymlink( + "when both file symlink target and import match disk", + `/user/username/projects/myproject/XY.ts`, + `/user/username/projects/myproject/XY.ts`, + `./XY`, + ); + verifyFileSymlink( + "when file symlink target matches disk but import does not", + `/user/username/projects/myproject/XY.ts`, + `/user/username/projects/myproject/Xy.ts`, + `./XY`, + ); + verifyFileSymlink( + "when import matches disk but file symlink target does not", + `/user/username/projects/myproject/XY.ts`, + `/user/username/projects/myproject/XY.ts`, + `./Xy`, + ); + verifyFileSymlink( + "when import and file symlink target agree but do not match disk", + `/user/username/projects/myproject/XY.ts`, + `/user/username/projects/myproject/Xy.ts`, + `./Xy`, + ); + verifyFileSymlink( + "when import, file symlink target, and disk are all different", + `/user/username/projects/myproject/XY.ts`, + `/user/username/projects/myproject/Xy.ts`, + `./yX`, + ); function verifyDirSymlink(subScenario: string, diskPath: string, targetPath: string, importedPath: string) { verifyTscWatch({ @@ -229,12 +279,11 @@ a;b; commandLineArgs: ["--w", "--p", ".", "--explainFiles"], sys: () => { const moduleA: File = { - path: `${diskPath}/a.ts`, content: ` export const a = 1; export const b = 2; -` +`, }; const symlinkA: SymLink = { path: `/user/username/projects/myproject/link`, @@ -247,121 +296,160 @@ import { a } from "${importedPath}/a"; import { b } from "./link/a"; a;b; -` +`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, // Use outFile because otherwise the real and linked files will have the same output path - content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true, outFile: "out.js", module: "system" } }) + content: JSON.stringify({ + compilerOptions: { + forceConsistentCasingInFileNames: true, + outFile: "out.js", + module: "system", + }, + }), }; - return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([moduleA, symlinkA, moduleB, libFile, tsconfig], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Prepend a line to moduleA", - edit: sys => sys.prependFile(`${diskPath}/a.ts`, `// some comment - `), + edit: sys => + sys.prependFile( + `${diskPath}/a.ts`, + `// some comment + `, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); } - verifyDirSymlink("when both directory symlink target and import match disk", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/XY`, `./XY`); - verifyDirSymlink("when directory symlink target matches disk but import does not", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/Xy`, `./XY`); - verifyDirSymlink("when import matches disk but directory symlink target does not", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/XY`, `./Xy`); - verifyDirSymlink("when import and directory symlink target agree but do not match disk", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/Xy`, `./Xy`); - verifyDirSymlink("when import, directory symlink target, and disk are all different", `/user/username/projects/myproject/XY`, `/user/username/projects/myproject/Xy`, `./yX`); + verifyDirSymlink( + "when both directory symlink target and import match disk", + `/user/username/projects/myproject/XY`, + `/user/username/projects/myproject/XY`, + `./XY`, + ); + verifyDirSymlink( + "when directory symlink target matches disk but import does not", + `/user/username/projects/myproject/XY`, + `/user/username/projects/myproject/Xy`, + `./XY`, + ); + verifyDirSymlink( + "when import matches disk but directory symlink target does not", + `/user/username/projects/myproject/XY`, + `/user/username/projects/myproject/XY`, + `./Xy`, + ); + verifyDirSymlink( + "when import and directory symlink target agree but do not match disk", + `/user/username/projects/myproject/XY`, + `/user/username/projects/myproject/Xy`, + `./Xy`, + ); + verifyDirSymlink( + "when import, directory symlink target, and disk are all different", + `/user/username/projects/myproject/XY`, + `/user/username/projects/myproject/Xy`, + `./yX`, + ); verifyTscWatch({ scenario: "forceConsistentCasingInFileNames", subScenario: "with nodeNext resolution", commandLineArgs: ["--w", "--explainFiles"], - sys: () => createWatchedSystem({ - "/Users/name/projects/web/src/bin.ts": `import { foo } from "yargs";`, - "/Users/name/projects/web/node_modules/@types/yargs/index.d.ts": "export function foo(): void;", - "/Users/name/projects/web/node_modules/@types/yargs/index.d.mts": "export function foo(): void;", - "/Users/name/projects/web/node_modules/@types/yargs/package.json": JSON.stringify({ - name: "yargs", - version: "17.0.12", - exports: { - ".": { - types: { - import: "./index.d.mts", - default: "./index.d.ts" - } + sys: () => + createWatchedSystem({ + "/Users/name/projects/web/src/bin.ts": `import { foo } from "yargs";`, + "/Users/name/projects/web/node_modules/@types/yargs/index.d.ts": "export function foo(): void;", + "/Users/name/projects/web/node_modules/@types/yargs/index.d.mts": "export function foo(): void;", + "/Users/name/projects/web/node_modules/@types/yargs/package.json": JSON.stringify({ + name: "yargs", + version: "17.0.12", + exports: { + ".": { + types: { + import: "./index.d.mts", + default: "./index.d.ts", + }, + }, }, - } - }), - "/Users/name/projects/web/tsconfig.json": JSON.stringify({ - compilerOptions: { - moduleResolution: "nodenext", - forceConsistentCasingInFileNames: true, - traceResolution: true, - } - }), - [libFile.path]: libFile.content, - }, { currentDirectory: "/Users/name/projects/web" }), + }), + "/Users/name/projects/web/tsconfig.json": JSON.stringify({ + compilerOptions: { + moduleResolution: "nodenext", + forceConsistentCasingInFileNames: true, + traceResolution: true, + }, + }), + [libFile.path]: libFile.content, + }, { currentDirectory: "/Users/name/projects/web" }), }); verifyTscWatch({ scenario: "forceConsistentCasingInFileNames", subScenario: "self name package reference", commandLineArgs: ["-w", "--explainFiles"], - sys: () => createWatchedSystem({ - "/Users/name/projects/web/package.json": JSON.stringify({ - name: "@this/package", - type: "module", - exports: { - ".": "./dist/index.js" - } - }), - "/Users/name/projects/web/index.ts": Utils.dedent` + sys: () => + createWatchedSystem({ + "/Users/name/projects/web/package.json": JSON.stringify({ + name: "@this/package", + type: "module", + exports: { + ".": "./dist/index.js", + }, + }), + "/Users/name/projects/web/index.ts": Utils.dedent` import * as me from "@this/package"; me.thing(); export function thing(): void {} `, - "/Users/name/projects/web/tsconfig.json": JSON.stringify({ - compilerOptions: { - module: "nodenext", - outDir: "./dist", - declarationDir: "./types", - composite: true, - forceConsistentCasingInFileNames: true, - traceResolution: true, - } - }), - "/a/lib/lib.esnext.full.d.ts": libFile.content, - }, { currentDirectory: "/Users/name/projects/web" }), + "/Users/name/projects/web/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "nodenext", + outDir: "./dist", + declarationDir: "./types", + composite: true, + forceConsistentCasingInFileNames: true, + traceResolution: true, + }, + }), + "/a/lib/lib.esnext.full.d.ts": libFile.content, + }, { currentDirectory: "/Users/name/projects/web" }), }); - verifyTscWatch({ scenario: "forceConsistentCasingInFileNames", subScenario: "package json is looked up for file", commandLineArgs: ["-w", "--explainFiles"], - sys: () => createWatchedSystem({ - "/Users/name/projects/lib-boilerplate/package.json": JSON.stringify({ - name: "lib-boilerplate", - version: "0.0.2", - type: "module", - exports: "./src/index.ts", - }), - "/Users/name/projects/lib-boilerplate/src/index.ts": Utils.dedent` + sys: () => + createWatchedSystem({ + "/Users/name/projects/lib-boilerplate/package.json": JSON.stringify({ + name: "lib-boilerplate", + version: "0.0.2", + type: "module", + exports: "./src/index.ts", + }), + "/Users/name/projects/lib-boilerplate/src/index.ts": Utils.dedent` export function thing(): void {} `, - "/Users/name/projects/lib-boilerplate/test/basic.spec.ts": Utils.dedent` + "/Users/name/projects/lib-boilerplate/test/basic.spec.ts": Utils.dedent` import { thing } from 'lib-boilerplate' `, - "/Users/name/projects/lib-boilerplate/tsconfig.json": JSON.stringify({ - compilerOptions: { - module: "node16", - target: "es2021", - forceConsistentCasingInFileNames: true, - traceResolution: true, - } - }), - "/a/lib/lib.es2021.full.d.ts": libFile.content, - }, { currentDirectory: "/Users/name/projects/lib-boilerplate" }), + "/Users/name/projects/lib-boilerplate/tsconfig.json": JSON.stringify({ + compilerOptions: { + module: "node16", + target: "es2021", + forceConsistentCasingInFileNames: true, + traceResolution: true, + }, + }), + "/a/lib/lib.es2021.full.d.ts": libFile.content, + }, { currentDirectory: "/Users/name/projects/lib-boilerplate" }), }); }); diff --git a/src/testRunner/unittests/tscWatch/incremental.ts b/src/testRunner/unittests/tscWatch/incremental.ts index 4bef1da5b5d87..0d119bde3968e 100644 --- a/src/testRunner/unittests/tscWatch/incremental.ts +++ b/src/testRunner/unittests/tscWatch/incremental.ts @@ -1,7 +1,11 @@ import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; -import { CommandLineProgram } from "../helpers/baseline"; -import { libContent } from "../helpers/contents"; +import { + CommandLineProgram, +} from "../helpers/baseline"; +import { + libContent, +} from "../helpers/contents"; import { applyEdit, createBaseline, @@ -21,7 +25,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { const configFile: File = { path: `${project}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { incremental: true } }) + content: JSON.stringify({ compilerOptions: { incremental: true } }), }; interface VerifyIncrementalWatchEmitInput { @@ -43,9 +47,11 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { function verifyIncrementalWatchEmitWorker( { subScenario, files, optionsToExtend, modifyFs }: VerifyIncrementalWatchEmitInput, - incremental: boolean + incremental: boolean, ) { - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(files(), { currentDirectory: project })); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem(files(), { currentDirectory: project }), + ); if (incremental) sys.exit = exitCode => sys.exitCode = exitCode; const argsToPass = [incremental ? "-i" : "-w", ...(optionsToExtend || ts.emptyArray)]; baseline.push(`${sys.getExecutingFilePath()} ${argsToPass.join(" ")}`); @@ -57,7 +63,12 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { build(oldSnap); } - Harness.Baseline.runBaseline(`${ts.isBuild(argsToPass) ? "tsbuild/watchMode" : "tscWatch"}/incremental/${subScenario.split(" ").join("-")}-${incremental ? "incremental" : "watch"}.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `${ts.isBuild(argsToPass) ? "tsbuild/watchMode" : "tscWatch"}/incremental/${ + subScenario.split(" ").join("-") + }-${incremental ? "incremental" : "watch"}.js`, + baseline.join("\r\n"), + ); function build(oldSnap: SystemSnap) { const closer = ts.executeCommandLine( @@ -70,7 +81,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { getPrograms, oldPrograms, sys, - oldSnap + oldSnap, }); if (closer) closer.close(); } @@ -79,11 +90,11 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { describe("non module compilation", () => { const file1: File = { path: `${project}/file1.ts`, - content: "const x = 10;" + content: "const x = 10;", }; const file2: File = { path: `${project}/file2.ts`, - content: "const y = 20;" + content: "const y = 20;", }; describe("own file emit without errors", () => { function verify(subScenario: string, optionsToExtend?: readonly string[]) { @@ -102,7 +113,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { verifyIncrementalWatchEmit({ files: () => [libFile, file1, configFile, { path: file2.path, - content: `const y: string = 20;` + content: `const y: string = 20;`, }], subScenario: "own file emit with errors", modifyFs: host => host.writeFile(file1.path, file1.content.replace("x", "z")), @@ -111,7 +122,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { verifyIncrementalWatchEmit({ files: () => [libFile, file1, file2, { path: configFile.path, - content: JSON.stringify({ compilerOptions: { incremental: true, outFile: "out.js" } }) + content: JSON.stringify({ compilerOptions: { incremental: true, outFile: "out.js" } }), }], subScenario: "with --out", }); @@ -120,15 +131,15 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { describe("module compilation", () => { const file1: File = { path: `${project}/file1.ts`, - content: "export const x = 10;" + content: "export const x = 10;", }; const file2: File = { path: `${project}/file2.ts`, - content: "export const y = 20;" + content: "export const y = 20;", }; const config: File = { path: configFile.path, - content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd" } }) + content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd" } }), }; verifyIncrementalWatchEmit({ @@ -140,7 +151,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { describe("own file emit with errors", () => { const fileModified: File = { path: file2.path, - content: `export const y: string = 20;` + content: `export const y: string = 20;`, }; verifyIncrementalWatchEmit({ @@ -150,25 +161,41 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { }); it("verify that state is read correctly", () => { - const system = createWatchedSystem([libFile, file1, fileModified, config], { currentDirectory: project }); + const system = createWatchedSystem([libFile, file1, fileModified, config], { + currentDirectory: project, + }); const reportDiagnostic = ts.createDiagnosticReporter(system); - const parsedConfig = ts.parseConfigFileWithSystem("tsconfig.json", {}, /*extendedConfigCache*/ undefined, /*watchOptionsToExtend*/ undefined, system, reportDiagnostic)!; + const parsedConfig = ts.parseConfigFileWithSystem( + "tsconfig.json", + {}, + /*extendedConfigCache*/ undefined, + /*watchOptionsToExtend*/ undefined, + system, + reportDiagnostic, + )!; ts.performIncrementalCompilation({ rootNames: parsedConfig.fileNames, options: parsedConfig.options, projectReferences: parsedConfig.projectReferences, configFileParsingDiagnostics: ts.getConfigFileParsingDiagnostics(parsedConfig), reportDiagnostic, - system + system, }); - const command = ts.parseConfigFileWithSystem("tsconfig.json", {}, /*extendedConfigCache*/ undefined, /*watchOptionsToExtend*/ undefined, system, ts.noop)!; + const command = ts.parseConfigFileWithSystem( + "tsconfig.json", + {}, + /*extendedConfigCache*/ undefined, + /*watchOptionsToExtend*/ undefined, + system, + ts.noop, + )!; const builderProgram = ts.createIncrementalProgram({ rootNames: command.fileNames, options: command.options, projectReferences: command.projectReferences, configFileParsingDiagnostics: ts.getConfigFileParsingDiagnostics(command), - host: ts.createIncrementalCompilerHost(command.options, system) + host: ts.createIncrementalCompilerHost(command.options, system), }); const state = builderProgram.getState(); @@ -197,7 +224,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { assert.deepEqual(state.compilerOptions, { incremental: true, module: ts.ModuleKind.AMD, - configFilePath: config.path + configFilePath: config.path, }); assert.equal(ts.arrayFrom(state.referencedMap!.keys()).length, 0); @@ -225,7 +252,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { verifyIncrementalWatchEmit({ files: () => [libFile, file1, file2, { path: configFile.path, - content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd", outFile: "out.js" } }) + content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd", outFile: "out.js" } }), }], subScenario: "module compilation/with --out", }); @@ -241,9 +268,9 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { target: "es5", module: "commonjs", declaration: true, - emitDeclarationOnly: true - } - }) + emitDeclarationOnly: true, + }, + }), }; const aTs: File = { path: `${project}/a.ts`, @@ -251,7 +278,7 @@ describe("unittests:: tsc-watch:: emit file --incremental", () => { export interface A { b: B; } -` +`, }; const bTs: File = { path: `${project}/b.ts`, @@ -259,7 +286,7 @@ export interface A { export interface B { b: C; } -` +`, }; const cTs: File = { path: `${project}/c.ts`, @@ -267,24 +294,28 @@ export interface B { export interface C { a: A; } -` +`, }; const indexTs: File = { path: `${project}/index.ts`, content: `export { A } from "./a"; export { B } from "./b"; export { C } from "./c"; -` +`, }; return [libFile, aTs, bTs, cTs, indexTs, config]; }, subScenario: "incremental with circular references", - modifyFs: host => host.writeFile(`${project}/a.ts`, `import { B } from "./b"; + modifyFs: host => + host.writeFile( + `${project}/a.ts`, + `import { B } from "./b"; export interface A { b: B; foo: any; } -`) +`, + ), }); verifyIncrementalWatchEmit({ @@ -293,13 +324,18 @@ export interface A { { path: libFile.path, content: libContent }, { path: `${project}/globals.d.ts`, content: `declare namespace Config { const value: string;} ` }, { path: `${project}/index.ts`, content: `console.log(Config.value);` }, - { path: configFile.path, content: JSON.stringify({ compilerOptions: { incremental: true, } }) } + { path: configFile.path, content: JSON.stringify({ compilerOptions: { incremental: true } }) }, ], - modifyFs: host => host.deleteFile(`${project}/globals.d.ts`) + modifyFs: host => host.deleteFile(`${project}/globals.d.ts`), }); describe("with option jsxImportSource", () => { - const jsxImportSourceOptions = { module: "commonjs", jsx: "react-jsx", incremental: true, jsxImportSource: "react" }; + const jsxImportSourceOptions = { + module: "commonjs", + jsx: "react-jsx", + incremental: true, + jsxImportSource: "react", + }; const jsxLibraryContent = `export namespace JSX { interface Element {} interface IntrinsicElements { @@ -318,14 +354,27 @@ export const Fragment: unique symbol; files: () => [ { path: libFile.path, content: libContent }, { path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent }, - { path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) }, - { path: `${project}/node_modules/preact/jsx-runtime/index.d.ts`, content: jsxLibraryContent.replace("propA", "propB") }, - { path: `${project}/node_modules/preact/package.json`, content: JSON.stringify({ name: "preact", version: "0.0.1" }) }, + { + path: `${project}/node_modules/react/package.json`, + content: JSON.stringify({ name: "react", version: "0.0.1" }), + }, + { + path: `${project}/node_modules/preact/jsx-runtime/index.d.ts`, + content: jsxLibraryContent.replace("propA", "propB"), + }, + { + path: `${project}/node_modules/preact/package.json`, + content: JSON.stringify({ name: "preact", version: "0.0.1" }), + }, { path: `${project}/index.tsx`, content: `export const App = () =>
;` }, - { path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) } + { path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }, ], - modifyFs: host => host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { ...jsxImportSourceOptions, jsxImportSource: "preact" } })), - optionsToExtend: ["--explainFiles"] + modifyFs: host => + host.writeFile( + configFile.path, + JSON.stringify({ compilerOptions: { ...jsxImportSourceOptions, jsxImportSource: "preact" } }), + ), + optionsToExtend: ["--explainFiles"], }); verifyIncrementalWatchEmit({ @@ -333,15 +382,18 @@ export const Fragment: unique symbol; files: () => [ { path: libFile.path, content: libContent }, { path: `${project}/index.tsx`, content: `export const App = () =>
;` }, - { path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) } + { path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }, ], modifyFs: host => { host.createDirectory(`${project}/node_modules`); host.createDirectory(`${project}/node_modules/react`); host.createDirectory(`${project}/node_modules/react/jsx-runtime`); host.writeFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`, jsxLibraryContent); - host.writeFile(`${project}/node_modules/react/package.json`, JSON.stringify({ name: "react", version: "0.0.1" })); - } + host.writeFile( + `${project}/node_modules/react/package.json`, + JSON.stringify({ name: "react", version: "0.0.1" }), + ); + }, }); verifyIncrementalWatchEmit({ @@ -349,29 +401,38 @@ export const Fragment: unique symbol; files: () => [ { path: libFile.path, content: libContent }, { path: `${project}/node_modules/react/jsx-runtime/index.d.ts`, content: jsxLibraryContent }, - { path: `${project}/node_modules/react/package.json`, content: JSON.stringify({ name: "react", version: "0.0.1" }) }, + { + path: `${project}/node_modules/react/package.json`, + content: JSON.stringify({ name: "react", version: "0.0.1" }), + }, { path: `${project}/index.tsx`, content: `export const App = () =>
;` }, - { path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) } + { path: configFile.path, content: JSON.stringify({ compilerOptions: jsxImportSourceOptions }) }, ], modifyFs: host => { host.deleteFile(`${project}/node_modules/react/jsx-runtime/index.d.ts`); host.deleteFile(`${project}/node_modules/react/package.json`); - } + }, }); verifyIncrementalWatchEmit({ subScenario: "importHelpers backing types removed", files: () => [ { path: libFile.path, content: libContent }, - { path: `${project}/node_modules/tslib/index.d.ts`, content: "export function __assign(...args: any[]): any;" }, - { path: `${project}/node_modules/tslib/package.json`, content: JSON.stringify({ name: "tslib", version: "0.0.1" }) }, + { + path: `${project}/node_modules/tslib/index.d.ts`, + content: "export function __assign(...args: any[]): any;", + }, + { + path: `${project}/node_modules/tslib/package.json`, + content: JSON.stringify({ name: "tslib", version: "0.0.1" }), + }, { path: `${project}/index.tsx`, content: `export const x = {...{}};` }, - { path: configFile.path, content: JSON.stringify({ compilerOptions: { importHelpers: true } }) } + { path: configFile.path, content: JSON.stringify({ compilerOptions: { importHelpers: true } }) }, ], modifyFs: host => { host.deleteFile(`${project}/node_modules/tslib/index.d.ts`); host.deleteFile(`${project}/node_modules/tslib/package.json`); - } + }, }); }); @@ -380,14 +441,26 @@ export const Fragment: unique symbol; subScenario: "editing module augmentation", files: () => [ { path: libFile.path, content: libContent }, - { path: `${project}/node_modules/classnames/index.d.ts`, content: `export interface Result {} export default function classNames(): Result;` }, - { path: `${project}/src/types/classnames.d.ts`, content: `export {}; declare module "classnames" { interface Result { foo } }` }, + { + path: `${project}/node_modules/classnames/index.d.ts`, + content: `export interface Result {} export default function classNames(): Result;`, + }, + { + path: `${project}/src/types/classnames.d.ts`, + content: `export {}; declare module "classnames" { interface Result { foo } }`, + }, { path: `${project}/src/index.ts`, content: `import classNames from "classnames"; classNames().foo;` }, - { path: configFile.path, content: JSON.stringify({ compilerOptions: { module: "commonjs", incremental: true } }) }, + { + path: configFile.path, + content: JSON.stringify({ compilerOptions: { module: "commonjs", incremental: true } }), + }, ], modifyFs: host => { // delete 'foo' - host.writeFile(`${project}/src/types/classnames.d.ts`, `export {}; declare module "classnames" { interface Result {} }`); + host.writeFile( + `${project}/src/types/classnames.d.ts`, + `export {}; declare module "classnames" { interface Result {} }`, + ); }, }); }); @@ -395,12 +468,13 @@ export const Fragment: unique symbol; verifyTscWatch({ scenario: "incremental", subScenario: "tsbuildinfo has error", - sys: () => createWatchedSystem({ - "/src/project/main.ts": "export const x = 10;", - "/src/project/tsconfig.json": "{}", - "/src/project/tsconfig.tsbuildinfo": "Some random string", - [libFile.path]: libFile.content, - }), + sys: () => + createWatchedSystem({ + "/src/project/main.ts": "export const x = 10;", + "/src/project/tsconfig.json": "{}", + "/src/project/tsconfig.tsbuildinfo": "Some random string", + [libFile.path]: libFile.content, + }), commandLineArgs: ["--p", "src/project", "-i", "-w"], }); }); diff --git a/src/testRunner/unittests/tscWatch/libraryResolution.ts b/src/testRunner/unittests/tscWatch/libraryResolution.ts index 9605491eca0f6..5ef3f57a3ee0f 100644 --- a/src/testRunner/unittests/tscWatch/libraryResolution.ts +++ b/src/testRunner/unittests/tscWatch/libraryResolution.ts @@ -1,8 +1,11 @@ -import { getCommandLineArgsForLibResolution, getSysForLibResolution } from "../helpers/libraryResolution"; +import { + getCommandLineArgsForLibResolution, + getSysForLibResolution, +} from "../helpers/libraryResolution"; import { TscWatchCompileChange, TscWatchSystem, - verifyTscWatch + verifyTscWatch, } from "../helpers/tscWatch"; describe("unittests:: tsc-watch:: libraryResolution", () => { @@ -10,35 +13,45 @@ describe("unittests:: tsc-watch:: libraryResolution", () => { return ["-w", ...getCommandLineArgsForLibResolution(withoutConfig), "--extendedDiagnostics"]; } - function editOptions(withoutConfig: true | undefined, changeLib: (sys: TscWatchSystem) => void): TscWatchCompileChange[] { + function editOptions( + withoutConfig: true | undefined, + changeLib: (sys: TscWatchSystem) => void, + ): TscWatchCompileChange[] { return withoutConfig ? [] : [ { caption: "change program options to update module resolution", - edit: sys => sys.writeFile("/home/src/projects/project1/tsconfig.json", JSON.stringify({ - compilerOptions: { - composite: true, - typeRoots: ["./typeroot1", "./typeroot2"], - lib: ["es5", "dom"], - traceResolution: true, - }, - })), + edit: sys => + sys.writeFile( + "/home/src/projects/project1/tsconfig.json", + JSON.stringify({ + compilerOptions: { + composite: true, + typeRoots: ["./typeroot1", "./typeroot2"], + lib: ["es5", "dom"], + traceResolution: true, + }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "change program options to update module resolution and also update lib file", edit: sys => { - sys.writeFile("/home/src/projects/project1/tsconfig.json", JSON.stringify({ - compilerOptions: { - composite: true, - typeRoots: ["./typeroot1"], - lib: ["es5", "dom"], - traceResolution: true, - }, - })); + sys.writeFile( + "/home/src/projects/project1/tsconfig.json", + JSON.stringify({ + compilerOptions: { + composite: true, + typeRoots: ["./typeroot1"], + lib: ["es5", "dom"], + traceResolution: true, + }, + }), + ); changeLib(sys); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ]; } function verify(withoutConfig?: true) { @@ -50,11 +63,15 @@ describe("unittests:: tsc-watch:: libraryResolution", () => { edits: [ { caption: "write redirect file dom", - edit: sys => sys.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", content: "interface DOMInterface { }" }), + edit: sys => + sys.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", + content: "interface DOMInterface { }", + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); - } + }, }, { caption: "edit index", @@ -71,21 +88,32 @@ describe("unittests:: tsc-watch:: libraryResolution", () => { edit: sys => sys.deleteFile("/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ...editOptions(withoutConfig, sys => sys.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", content: "interface DOMInterface { }" })), + ...editOptions( + withoutConfig, + sys => + sys.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", + content: "interface DOMInterface { }", + }), + ), { caption: "write redirect file webworker", - edit: sys => sys.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts", content: "interface WebworkerInterface { }" }), + edit: sys => + sys.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts", + content: "interface WebworkerInterface { }", + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); - } + }, }, { caption: "delete redirect file webworker", edit: sys => sys.deleteFile("/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -111,13 +139,20 @@ describe("unittests:: tsc-watch:: libraryResolution", () => { }, { caption: "write redirect file dom", - edit: sys => sys.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", content: "interface DOMInterface { }" }), + edit: sys => + sys.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", + content: "interface DOMInterface { }", + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); - } + }, }, - ...editOptions(withoutConfig, sys => sys.deleteFile("/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts")), + ...editOptions( + withoutConfig, + sys => sys.deleteFile("/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts"), + ), { caption: "delete redirect file webworker", edit: sys => sys.deleteFile("/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts"), @@ -125,13 +160,17 @@ describe("unittests:: tsc-watch:: libraryResolution", () => { }, { caption: "write redirect file webworker", - edit: sys => sys.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts", content: "interface WebworkerInterface { }" }), + edit: sys => + sys.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts", + content: "interface WebworkerInterface { }", + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); - } + }, }, - ] + ], }); } verify(); diff --git a/src/testRunner/unittests/tscWatch/moduleResolution.ts b/src/testRunner/unittests/tscWatch/moduleResolution.ts index 2512116a46ab1..d94617f22f77e 100644 --- a/src/testRunner/unittests/tscWatch/moduleResolution.ts +++ b/src/testRunner/unittests/tscWatch/moduleResolution.ts @@ -1,6 +1,13 @@ import * as Utils from "../../_namespaces/Utils"; -import { getFsConentsForNode10ResultAtTypesPackageJson, getFsContentsForNode10Result, getFsContentsForNode10ResultDts, getFsContentsForNode10ResultPackageJson } from "../helpers/node10Result"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + getFsConentsForNode10ResultAtTypesPackageJson, + getFsContentsForNode10Result, + getFsContentsForNode10ResultDts, + getFsContentsForNode10ResultPackageJson, +} from "../helpers/node10Result"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { createWatchedSystem, File, @@ -11,60 +18,66 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { verifyTscWatch({ scenario: "moduleResolution", subScenario: `watches for changes to package-json main fields`, - sys: () => createWatchedSystem([ - { - path: `/user/username/projects/myproject/packages/pkg1/package.json`, - content: JSON.stringify({ - name: "pkg1", - version: "1.0.0", - main: "build/index.js", - }) - }, - { - path: `/user/username/projects/myproject/packages/pkg1/index.ts`, - content: Utils.dedent` + sys: () => + createWatchedSystem([ + { + path: `/user/username/projects/myproject/packages/pkg1/package.json`, + content: JSON.stringify({ + name: "pkg1", + version: "1.0.0", + main: "build/index.js", + }), + }, + { + path: `/user/username/projects/myproject/packages/pkg1/index.ts`, + content: Utils.dedent` import type { TheNum } from 'pkg2' - export const theNum: TheNum = 42;` - }, - { - path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { - outDir: "build", - }, - }) - }, - { - path: `/user/username/projects/myproject/packages/pkg2/build/const.d.ts`, - content: `export type TheNum = 42;` - }, - { - path: `/user/username/projects/myproject/packages/pkg2/build/index.d.ts`, - content: `export type { TheNum } from './const.js';` - }, - { - path: `/user/username/projects/myproject/packages/pkg2/build/other.d.ts`, - content: `export type TheStr = string;` - }, - { - path: `/user/username/projects/myproject/packages/pkg2/package.json`, - content: JSON.stringify({ - name: "pkg2", - version: "1.0.0", - main: "build/index.js", - }) - }, - { - path: `/user/username/projects/myproject/node_modules/pkg2`, - symLink: `/user/username/projects/myproject/packages/pkg2`, - }, - libFile - ], { currentDirectory: "/user/username/projects/myproject" }), + export const theNum: TheNum = 42;`, + }, + { + path: `/user/username/projects/myproject/packages/pkg1/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + outDir: "build", + }, + }), + }, + { + path: `/user/username/projects/myproject/packages/pkg2/build/const.d.ts`, + content: `export type TheNum = 42;`, + }, + { + path: `/user/username/projects/myproject/packages/pkg2/build/index.d.ts`, + content: `export type { TheNum } from './const.js';`, + }, + { + path: `/user/username/projects/myproject/packages/pkg2/build/other.d.ts`, + content: `export type TheStr = string;`, + }, + { + path: `/user/username/projects/myproject/packages/pkg2/package.json`, + content: JSON.stringify({ + name: "pkg2", + version: "1.0.0", + main: "build/index.js", + }), + }, + { + path: `/user/username/projects/myproject/node_modules/pkg2`, + symLink: `/user/username/projects/myproject/packages/pkg2`, + }, + libFile, + ], { currentDirectory: "/user/username/projects/myproject" }), commandLineArgs: ["--project", "./packages/pkg1/tsconfig.json", "-w", "--traceResolution"], edits: [ { caption: "reports import errors after change to package file", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `index.js`, `other.js`), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/packages/pkg2/package.json`, + `index.js`, + `other.js`, + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // invalidates failed lookups sys.runQueuedTimeoutCallbacks(); // actual update @@ -72,65 +85,72 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "removes those errors when a package file is changed back", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/packages/pkg2/package.json`, `other.js`, `index.js`), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/packages/pkg2/package.json`, + `other.js`, + `index.js`, + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // invalidates failed lookups sys.runQueuedTimeoutCallbacks(); // actual update }, }, - ] + ], }); verifyTscWatch({ scenario: "moduleResolution", subScenario: "diagnostics from cache", - sys: () => createWatchedSystem([ - { - path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { - moduleResolution: "nodenext", - outDir: "./dist", - declaration: true, - declarationDir: "./types" - }, - }) - }, - { - path: `/user/username/projects/myproject/package.json`, - content: JSON.stringify({ - name: "@this/package", - type: "module", - exports: { - ".": { - default: "./dist/index.js", - types: "./types/index.d.ts" - } - } - }) - }, - { - path: `/user/username/projects/myproject/index.ts`, - content: Utils.dedent` + sys: () => + createWatchedSystem([ + { + path: `/user/username/projects/myproject/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + moduleResolution: "nodenext", + outDir: "./dist", + declaration: true, + declarationDir: "./types", + }, + }), + }, + { + path: `/user/username/projects/myproject/package.json`, + content: JSON.stringify({ + name: "@this/package", + type: "module", + exports: { + ".": { + default: "./dist/index.js", + types: "./types/index.d.ts", + }, + }, + }), + }, + { + path: `/user/username/projects/myproject/index.ts`, + content: Utils.dedent` import * as me from "@this/package"; me.thing() export function thing(): void {} - ` - }, - { - path: `/user/username/projects/myproject/index2.ts`, - content: Utils.dedent` + `, + }, + { + path: `/user/username/projects/myproject/index2.ts`, + content: Utils.dedent` export function thing(): void {} - ` - }, - libFile - ], { currentDirectory: "/user/username/projects/myproject" }), + `, + }, + libFile, + ], { currentDirectory: "/user/username/projects/myproject" }), commandLineArgs: ["-w", "--traceResolution"], edits: [{ caption: "Add import to index2", - edit: sys => sys.prependFile(`/user/username/projects/myproject/index2.ts`, `import * as me from "./index.js";`), + edit: sys => + sys.prependFile(`/user/username/projects/myproject/index2.ts`, `import * as me from "./index.js";`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - }] + }], }); describe("package json file is edited", () => { @@ -141,31 +161,31 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { compilerOptions: { target: "es2016", module: "Node16", - outDir: "../out" - } - }) + outDir: "../out", + }, + }), }; const packageFile: File = { path: `/user/username/projects/myproject/package.json`, - content: packageFileContents + content: packageFileContents, }; const fileA: File = { path: `/user/username/projects/myproject/src/fileA.ts`, content: Utils.dedent` import { foo } from "./fileB.mjs"; foo(); - ` + `, }; const fileB: File = { path: `/user/username/projects/myproject/project/src/fileB.mts`, content: Utils.dedent` export function foo() { } - ` + `, }; return createWatchedSystem( [configFile, fileA, fileB, packageFile, { ...libFile, path: "/a/lib/lib.es2016.full.d.ts" }], - { currentDirectory: "/user/username/projects/myproject" } + { currentDirectory: "/user/username/projects/myproject" }, ); } verifyTscWatch({ @@ -176,9 +196,15 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { edits: [ { caption: "Modify package json file to add type module", - edit: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ - name: "app", version: "1.0.0", type: "module", - })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/package.json`, + JSON.stringify({ + name: "app", + version: "1.0.0", + type: "module", + }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update @@ -186,7 +212,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "Modify package.json file to remove type module", - edit: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/package.json`, + JSON.stringify({ name: "app", version: "1.0.0" }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update @@ -202,9 +232,15 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "Modify package json file to add type module", - edit: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ - name: "app", version: "1.0.0", type: "module", - })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/package.json`, + JSON.stringify({ + name: "app", + version: "1.0.0", + type: "module", + }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update @@ -225,13 +261,20 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { scenario: "moduleResolution", subScenario: "package json file is edited when package json with type module exists", commandLineArgs: ["--w", "--p", "src", "--extendedDiagnostics", "-traceResolution", "--explainFiles"], - sys: () => getSys(JSON.stringify({ - name: "app", version: "1.0.0", type: "module", - })), + sys: () => + getSys(JSON.stringify({ + name: "app", + version: "1.0.0", + type: "module", + })), edits: [ { caption: "Modify package.json file to remove type module", - edit: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/package.json`, + JSON.stringify({ name: "app", version: "1.0.0" }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update @@ -239,9 +282,15 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "Modify package json file to add type module", - edit: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ - name: "app", version: "1.0.0", type: "module", - })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/package.json`, + JSON.stringify({ + name: "app", + version: "1.0.0", + type: "module", + }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update @@ -257,7 +306,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "Modify package json file to without type module", - edit: sys => sys.writeFile(`/user/username/projects/myproject/package.json`, JSON.stringify({ name: "app", version: "1.0.0" })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/package.json`, + JSON.stringify({ name: "app", version: "1.0.0" }), + ), timeouts: host => { host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update @@ -278,166 +331,177 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { verifyTscWatch({ scenario: "moduleResolution", subScenario: "module resolutions from file are partially used", - sys: () => createWatchedSystem([ - { - path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { moduleResolution: "node16" }, - }) - }, - { - path: `/user/username/projects/myproject/index.ts`, - content: Utils.dedent` + sys: () => + createWatchedSystem([ + { + path: `/user/username/projects/myproject/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { moduleResolution: "node16" }, + }), + }, + { + path: `/user/username/projects/myproject/index.ts`, + content: Utils.dedent` import type { ImportInterface } from "pkg" assert { "resolution-mode": "import" }; import type { RequireInterface } from "pkg1" assert { "resolution-mode": "require" }; import {x} from "./a"; - ` - }, - { - path: `/user/username/projects/myproject/a.ts`, - content: Utils.dedent` + `, + }, + { + path: `/user/username/projects/myproject/a.ts`, + content: Utils.dedent` export const x = 10; - ` - }, - { - path: `/user/username/projects/myproject/node_modules/pkg/package.json`, - content: JSON.stringify({ - name: "pkg", - version: "0.0.1", - exports: { - import: "./import.js", - require: "./require.js" - } - }) - }, - { - path: `/user/username/projects/myproject/node_modules/pkg/import.d.ts`, - content: `export interface ImportInterface {}` - }, - { - path: `/user/username/projects/myproject/node_modules/pkg/require.d.ts`, - content: `export interface RequireInterface {}` - }, - { - path: `/user/username/projects/myproject/node_modules/pkg1/package.json`, - content: JSON.stringify({ - name: "pkg1", - version: "0.0.1", - exports: { - import: "./import.js", - require: "./require.js" - } - }) - }, - { - path: `/user/username/projects/myproject/node_modules/pkg1/import.d.ts`, - content: `export interface ImportInterface {}` - }, - libFile - ], { currentDirectory: "/user/username/projects/myproject" }), + `, + }, + { + path: `/user/username/projects/myproject/node_modules/pkg/package.json`, + content: JSON.stringify({ + name: "pkg", + version: "0.0.1", + exports: { + import: "./import.js", + require: "./require.js", + }, + }), + }, + { + path: `/user/username/projects/myproject/node_modules/pkg/import.d.ts`, + content: `export interface ImportInterface {}`, + }, + { + path: `/user/username/projects/myproject/node_modules/pkg/require.d.ts`, + content: `export interface RequireInterface {}`, + }, + { + path: `/user/username/projects/myproject/node_modules/pkg1/package.json`, + content: JSON.stringify({ + name: "pkg1", + version: "0.0.1", + exports: { + import: "./import.js", + require: "./require.js", + }, + }), + }, + { + path: `/user/username/projects/myproject/node_modules/pkg1/import.d.ts`, + content: `export interface ImportInterface {}`, + }, + libFile, + ], { currentDirectory: "/user/username/projects/myproject" }), commandLineArgs: ["-w", "--traceResolution"], edits: [ { caption: "modify aFile by adding import", - edit: sys => sys.appendFile(`/user/username/projects/myproject/a.ts`, `import type { ImportInterface } from "pkg" assert { "resolution-mode": "import" }`), + edit: sys => + sys.appendFile( + `/user/username/projects/myproject/a.ts`, + `import type { ImportInterface } from "pkg" assert { "resolution-mode": "import" }`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ scenario: "moduleResolution", subScenario: "type reference resolutions reuse", - sys: () => createWatchedSystem([ - { - path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ - compilerOptions: { moduleResolution: "node16" }, - }) - }, - { - path: `/user/username/projects/myproject/index.ts`, - content: Utils.dedent` + sys: () => + createWatchedSystem([ + { + path: `/user/username/projects/myproject/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { moduleResolution: "node16" }, + }), + }, + { + path: `/user/username/projects/myproject/index.ts`, + content: Utils.dedent` /// /// export interface LocalInterface extends RequireInterface {} - ` - }, - { - path: `/user/username/projects/myproject/a.ts`, - content: Utils.dedent` + `, + }, + { + path: `/user/username/projects/myproject/a.ts`, + content: Utils.dedent` export const x = 10; - ` - }, - { - path: `/user/username/projects/myproject/node_modules/pkg/package.json`, - content: JSON.stringify({ - name: "pkg", - version: "0.0.1", - exports: { - import: "./import.js", - require: "./require.js" - } - }) - }, - { - path: `/user/username/projects/myproject/node_modules/pkg/import.d.ts`, - content: Utils.dedent` + `, + }, + { + path: `/user/username/projects/myproject/node_modules/pkg/package.json`, + content: JSON.stringify({ + name: "pkg", + version: "0.0.1", + exports: { + import: "./import.js", + require: "./require.js", + }, + }), + }, + { + path: `/user/username/projects/myproject/node_modules/pkg/import.d.ts`, + content: Utils.dedent` export {}; declare global { interface ImportInterface {} } - ` - }, - { - path: `/user/username/projects/myproject/node_modules/pkg/require.d.ts`, - content: Utils.dedent` + `, + }, + { + path: `/user/username/projects/myproject/node_modules/pkg/require.d.ts`, + content: Utils.dedent` export {}; declare global { interface RequireInterface {} } - ` - }, - { - path: `/user/username/projects/myproject/node_modules/pkg1/package.json`, - content: JSON.stringify({ - name: "pkg1", - version: "0.0.1", - exports: { - import: "./import.js", - require: "./require.js" - } - }) - }, - { - path: `/user/username/projects/myproject/node_modules/pkg1/import.d.ts`, - content: Utils.dedent` + `, + }, + { + path: `/user/username/projects/myproject/node_modules/pkg1/package.json`, + content: JSON.stringify({ + name: "pkg1", + version: "0.0.1", + exports: { + import: "./import.js", + require: "./require.js", + }, + }), + }, + { + path: `/user/username/projects/myproject/node_modules/pkg1/import.d.ts`, + content: Utils.dedent` export {}; declare global { interface ImportInterface {} } - ` - }, - { - path: `/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts`, - content: `export const x = 10;` - }, - libFile - ], { currentDirectory: "/user/username/projects/myproject" }), + `, + }, + { + path: `/user/username/projects/myproject/node_modules/@types/pkg2/index.d.ts`, + content: `export const x = 10;`, + }, + libFile, + ], { currentDirectory: "/user/username/projects/myproject" }), commandLineArgs: ["-w", "--traceResolution"], edits: [ { caption: "modify aFile by adding import", - edit: sys => sys.prependFile(`/user/username/projects/myproject/a.ts`, `/// \n`), + edit: sys => + sys.prependFile( + `/user/username/projects/myproject/a.ts`, + `/// \n`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ scenario: "moduleResolution", subScenario: "node10Result", - sys: () => createWatchedSystem(getFsContentsForNode10Result(), { currentDirectory: "/home/src/projects/project" }), + sys: () => + createWatchedSystem(getFsContentsForNode10Result(), { currentDirectory: "/home/src/projects/project" }), commandLineArgs: ["-w", "--extendedDiagnostics"], edits: [ { @@ -458,7 +522,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "add the node10Result in @types", - edit: sys => sys.writeFile("/home/src/projects/project/node_modules/@types/bar/index.d.ts", getFsContentsForNode10ResultDts("bar")), + edit: sys => + sys.writeFile( + "/home/src/projects/project/node_modules/@types/bar/index.d.ts", + getFsContentsForNode10ResultDts("bar"), + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -466,7 +534,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "add the ndoe10Result in package/types", - edit: sys => sys.writeFile("/home/src/projects/project/node_modules/foo/index.d.ts", getFsContentsForNode10ResultDts("foo")), + edit: sys => + sys.writeFile( + "/home/src/projects/project/node_modules/foo/index.d.ts", + getFsContentsForNode10ResultDts("foo"), + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -474,7 +546,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "update package.json from @types so error is fixed", - edit: sys => sys.writeFile("/home/src/projects/project/node_modules/@types/bar/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true)), + edit: sys => + sys.writeFile( + "/home/src/projects/project/node_modules/@types/bar/package.json", + getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true), + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -482,7 +558,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "update package.json so error is fixed", - edit: sys => sys.writeFile("/home/src/projects/project/node_modules/foo/package.json", getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true)), + edit: sys => + sys.writeFile( + "/home/src/projects/project/node_modules/foo/package.json", + getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true), + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -490,7 +570,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "update package.json from @types so error is introduced", - edit: sys => sys.writeFile("/home/src/projects/project/node_modules/@types/bar2/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false)), + edit: sys => + sys.writeFile( + "/home/src/projects/project/node_modules/@types/bar2/package.json", + getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false), + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -498,7 +582,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "update package.json so error is introduced", - edit: sys => sys.writeFile("/home/src/projects/project/node_modules/foo2/package.json", getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false)), + edit: sys => + sys.writeFile( + "/home/src/projects/project/node_modules/foo2/package.json", + getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false), + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -522,7 +610,11 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "add the node10Result in @types", - edit: sys => sys.writeFile("/home/src/projects/project/node_modules/@types/bar2/index.d.ts", getFsContentsForNode10ResultDts("bar2")), + edit: sys => + sys.writeFile( + "/home/src/projects/project/node_modules/@types/bar2/index.d.ts", + getFsContentsForNode10ResultDts("bar2"), + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -530,12 +622,16 @@ describe("unittests:: tsc-watch:: moduleResolution", () => { }, { caption: "add the ndoe10Result in package/types", - edit: sys => sys.writeFile("/home/src/projects/project/node_modules/foo2/index.d.ts", getFsContentsForNode10ResultDts("foo2")), + edit: sys => + sys.writeFile( + "/home/src/projects/project/node_modules/foo2/index.d.ts", + getFsContentsForNode10ResultDts("foo2"), + ), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); }, }, - ] + ], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tscWatch/nodeNextWatch.ts b/src/testRunner/unittests/tscWatch/nodeNextWatch.ts index 38f5b340a8643..476fec768425f 100644 --- a/src/testRunner/unittests/tscWatch/nodeNextWatch.ts +++ b/src/testRunner/unittests/tscWatch/nodeNextWatch.ts @@ -1,5 +1,7 @@ import * as Utils from "../../_namespaces/Utils"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { createWatchedSystem, File, @@ -20,9 +22,9 @@ describe("unittests:: tsc-watch:: nodeNextWatch:: emit when module emit is speci target: "es2020", module: "nodenext", moduleResolution: "nodenext", - outDir: "../dist" - } - }) + outDir: "../dist", + }, + }), }; const packageFile: File = { path: "/project/package.json", @@ -32,33 +34,37 @@ describe("unittests:: tsc-watch:: nodeNextWatch:: emit when module emit is speci description: "", type: "module", main: "index.js", - }) + }), }; const file1: File = { path: "/project/src/index.ts", content: Utils.dedent` import * as Thing from "thing"; - Thing.fn();` + Thing.fn();`, }; const declFile: File = { path: "/project/src/deps.d.ts", - content: `declare module "thing";` + content: `declare module "thing";`, }; - return createWatchedSystem([configFile, file1, declFile, packageFile, { ...libFile, path: "/a/lib/lib.es2020.full.d.ts" }]); + return createWatchedSystem([configFile, file1, declFile, packageFile, { + ...libFile, + path: "/a/lib/lib.es2020.full.d.ts", + }]); }, edits: [ { caption: "Modify typescript file", - edit: sys => sys.modifyFile( - "/project/src/index.ts", - Utils.dedent` + edit: sys => + sys.modifyFile( + "/project/src/index.ts", + Utils.dedent` import * as Thing from "thing"; Thing.fn();`, - {}, - ), + {}, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } + }, ], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index 196056480048f..7d2bc00d9a230 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -1,7 +1,11 @@ import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; -import { commandLineCallbacks } from "../helpers/baseline"; -import { compilerOptionsToConfigJson } from "../helpers/contents"; +import { + commandLineCallbacks, +} from "../helpers/baseline"; +import { + compilerOptionsToConfigJson, +} from "../helpers/contents"; import { commonFile1, commonFile2, @@ -26,7 +30,7 @@ describe("unittests:: tsc-watch:: program updates", () => { const configFilePath = "/a/b/tsconfig.json"; const configFile: File = { path: configFilePath, - content: `{}` + content: `{}`, }; verifyTscWatch({ scenario, @@ -38,12 +42,12 @@ describe("unittests:: tsc-watch:: program updates", () => { content: ` import {f} from "./module" console.log(f) - ` + `, }; const moduleFile: File = { path: "/a/b/c/module.d.ts", - content: `export let x: number` + content: `export let x: number`, }; return createWatchedSystem([appFile, moduleFile, libFile]); }, @@ -56,13 +60,13 @@ describe("unittests:: tsc-watch:: program updates", () => { sys: () => { const f1 = { path: "/a/b/app.ts", - content: "let x = 1" + content: "let x = 1", }; const config = { path: configFilePath, content: JSON.stringify({ - include: ["app.ts"] - }) + include: ["app.ts"], + }), }; return createWatchedSystem([f1, libFile, config], { useCaseSensitiveFileNames: false }); }, @@ -81,19 +85,19 @@ describe("unittests:: tsc-watch:: program updates", () => { "exclude": [ "e" ] - }` + }`, }; const file1: File = { path: "/a/b/c/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2: File = { path: "/a/b/d/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const file3: File = { path: "/a/b/e/f3.ts", - content: "let z = 1" + content: "let z = 1", }; return createWatchedSystem([configFile, libFile, file1, file2, file3]); }, @@ -109,8 +113,8 @@ describe("unittests:: tsc-watch:: program updates", () => { caption: "Create commonFile2", edit: sys => sys.writeFile(commonFile2.path, commonFile2.content), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -126,7 +130,7 @@ describe("unittests:: tsc-watch:: program updates", () => { "commonFile1.ts", "commonFile3.ts" ] - }` + }`, }; return createWatchedSystem([commonFile1, commonFile2, libFile, configFile]); }, @@ -154,19 +158,20 @@ describe("unittests:: tsc-watch:: program updates", () => { caption: "recreate file2", edit: sys => sys.writeFile(commonFile2.path, commonFile2.content), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ scenario, - subScenario: "handles the missing files - that were added to program because they were added with tripleSlashRefs", + subScenario: + "handles the missing files - that were added to program because they were added with tripleSlashRefs", commandLineArgs: ["-w", "/a/b/commonFile1.ts"], sys: () => { const file1: File = { path: commonFile1.path, content: `/// - let x = y` + let x = y`, }; return createWatchedSystem([file1, libFile]); }, @@ -175,8 +180,8 @@ describe("unittests:: tsc-watch:: program updates", () => { caption: "create file2", edit: sys => sys.writeFile(commonFile2.path, commonFile2.content), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -189,7 +194,7 @@ describe("unittests:: tsc-watch:: program updates", () => { content: `{ "compilerOptions": {}, "files": ["${commonFile1.path}", "${commonFile2.path}"] - }` + }`, }; return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]); }, @@ -201,13 +206,17 @@ describe("unittests:: tsc-watch:: program updates", () => { }, { caption: "Change config", - edit: sys => sys.writeFile(configFilePath, `{ + edit: sys => + sys.writeFile( + configFilePath, + `{ "compilerOptions": {}, "files": ["${commonFile1.path}"] - }`), + }`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -220,20 +229,24 @@ describe("unittests:: tsc-watch:: program updates", () => { content: `{ "compilerOptions": {}, "files": ["${commonFile1.path}", "${commonFile2.path}"] - }` + }`, }; return createWatchedSystem([libFile, commonFile1, commonFile2, configFile]); }, edits: [ { caption: "Modify config without changing content", - edit: sys => sys.modifyFile(configFilePath, `{ + edit: sys => + sys.modifyFile( + configFilePath, + `{ "compilerOptions": {}, "files": ["${commonFile1.path}", "${commonFile2.path}"] - }`), + }`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -243,32 +256,40 @@ describe("unittests:: tsc-watch:: program updates", () => { sys: () => { const aTs: File = { path: "/a.ts", - content: "label: while (1) {}" + content: "label: while (1) {}", }; const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ - compilerOptions: { allowUnusedLabels: true } - }) + compilerOptions: { allowUnusedLabels: true }, + }), }; return createWatchedSystem([libFile, aTs, tsconfig]); }, edits: [ { caption: "Disable allowUnsusedLabels", - edit: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ - compilerOptions: { allowUnusedLabels: false } - })), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.modifyFile( + "/tsconfig.json", + JSON.stringify({ + compilerOptions: { allowUnusedLabels: false }, + }), + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Enable allowUnsusedLabels", - edit: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ - compilerOptions: { allowUnusedLabels: true } - })), + edit: sys => + sys.modifyFile( + "/tsconfig.json", + JSON.stringify({ + compilerOptions: { allowUnusedLabels: true }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -278,39 +299,47 @@ describe("unittests:: tsc-watch:: program updates", () => { sys: () => { const aTs: File = { path: "/a.ts", - content: "import {} from './b.css'" + content: "import {} from './b.css'", }; const bCssTs: File = { path: "/b.d.css.ts", - content: "declare const style: string;" + content: "declare const style: string;", }; const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ compilerOptions: { allowArbitraryExtensions: true }, files: ["/a.ts"], - }) + }), }; return createWatchedSystem([libFile, aTs, bCssTs, tsconfig]); }, edits: [ { caption: "Disable allowArbitraryExtensions", - edit: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ - compilerOptions: { allowArbitraryExtensions: false }, - files: ["/a.ts"], - })), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.modifyFile( + "/tsconfig.json", + JSON.stringify({ + compilerOptions: { allowArbitraryExtensions: false }, + files: ["/a.ts"], + }), + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Enable allowArbitraryExtensions", - edit: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ - compilerOptions: { allowArbitraryExtensions: true }, - files: ["/a.ts"], - })), + edit: sys => + sys.modifyFile( + "/tsconfig.json", + JSON.stringify({ + compilerOptions: { allowArbitraryExtensions: true }, + files: ["/a.ts"], + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -333,28 +362,44 @@ export class A { const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ - compilerOptions: { target: "es6", importsNotUsedAsValues: "error" } - }) + compilerOptions: { target: "es6", importsNotUsedAsValues: "error" }, + }), }; return createWatchedSystem([libFile, aTs, bTs, tsconfig]); }, edits: [ { caption: "Enable experimentalDecorators", - edit: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ - compilerOptions: { target: "es6", importsNotUsedAsValues: "error", experimentalDecorators: true } - })), + edit: sys => + sys.modifyFile( + "/tsconfig.json", + JSON.stringify({ + compilerOptions: { + target: "es6", + importsNotUsedAsValues: "error", + experimentalDecorators: true, + }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - }, { caption: "Enable emitDecoratorMetadata", - edit: sys => sys.modifyFile("/tsconfig.json", JSON.stringify({ - compilerOptions: { target: "es6", importsNotUsedAsValues: "error", experimentalDecorators: true, emitDecoratorMetadata: true } - })), + edit: sys => + sys.modifyFile( + "/tsconfig.json", + JSON.stringify({ + compilerOptions: { + target: "es6", + importsNotUsedAsValues: "error", + experimentalDecorators: true, + emitDecoratorMetadata: true, + }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -367,11 +412,11 @@ export class A { content: `{ "compilerOptions": {}, "exclude": ["/a/c"] - }` + }`, }; const excludedFile1: File = { path: "/a/c/excluedFile1.ts", - content: `let t = 1;` + content: `let t = 1;`, }; return createWatchedSystem([libFile, commonFile1, commonFile2, excludedFile1, configFile]); }, @@ -384,15 +429,15 @@ export class A { sys: () => { const file1: File = { path: "/a/b/file1.ts", - content: `import { T } from "module1";` + content: `import { T } from "module1";`, }; const nodeModuleFile: File = { path: "/a/b/node_modules/module1.ts", - content: `export interface T {}` + content: `export interface T {}`, }; const classicModuleFile: File = { path: "/a/module1.ts", - content: `export interface T {}` + content: `export interface T {}`, }; const configFile: File = { path: configFilePath, @@ -401,22 +446,26 @@ export class A { "moduleResolution": "node" }, "files": ["${file1.path}"] - }` + }`, }; return createWatchedSystem([libFile, file1, nodeModuleFile, classicModuleFile, configFile]); }, edits: [ { caption: "Change module resolution to classic", - edit: sys => sys.writeFile(configFile.path, `{ + edit: sys => + sys.writeFile( + configFile.path, + `{ "compilerOptions": { "moduleResolution": "classic" }, "files": ["/a/b/file1.ts"] - }`), + }`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -432,7 +481,7 @@ export class A { "allowAnything": true }, "someOtherProperty": {} - }` + }`, }; return createWatchedSystem([commonFile1, commonFile2, libFile, configFile]); }, @@ -445,15 +494,15 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: `export * from "./f2"` + content: `export * from "./f2"`, }; const file2 = { path: "/a/b/f2.ts", - content: `export let x = 1` + content: `export let x = 1`, }; const file3 = { path: "/a/c/f3.ts", - content: `export let y = 1;` + content: `export let y = 1;`, }; return createWatchedSystem([file1, file2, file3, libFile]); }, @@ -463,8 +512,8 @@ export class A { // now inferred project should inclule file3 edit: sys => sys.modifyFile("/a/b/f2.ts", `export * from "../c/f3"`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -474,15 +523,15 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: `export * from "./f2"` + content: `export * from "./f2"`, }; const file2 = { path: "/a/b/f2.ts", - content: `export * from "../c/f3"` + content: `export * from "../c/f3"`, }; const file3 = { path: "/a/c/f3.ts", - content: `export let y = 1;` + content: `export let y = 1;`, }; return createWatchedSystem([file1, file2, file3, libFile]); }, @@ -491,8 +540,8 @@ export class A { caption: "Delete f2", edit: sys => sys.deleteFile("/a/b/f2.ts"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -502,15 +551,15 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: `export * from "./f2"` + content: `export * from "./f2"`, }; const file2 = { path: "/a/b/f2.ts", - content: `export * from "../c/f3"` + content: `export * from "../c/f3"`, }; const file3 = { path: "/a/c/f3.ts", - content: `export let y = 1;` + content: `export let y = 1;`, }; return createWatchedSystem([file1, file2, file3, libFile]); }, @@ -519,8 +568,8 @@ export class A { caption: "Delete f2", edit: sys => sys.deleteFile("/a/b/f2.ts"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -530,19 +579,19 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: "export let x = 5" + content: "export let x = 5", }; const file2 = { path: "/a/c/f2.ts", - content: `import {x} from "../b/f1"` + content: `import {x} from "../b/f1"`, }; const file3 = { path: "/a/c/f3.ts", - content: "export let y = 1" + content: "export let y = 1", }; const configFile = { path: "/a/c/tsconfig.json", - content: JSON.stringify({ compilerOptions: {}, files: ["f2.ts", "f3.ts"] }) + content: JSON.stringify({ compilerOptions: {}, files: ["f2.ts", "f3.ts"] }), }; return createWatchedSystem([file1, file2, file3, libFile, configFile]); }, @@ -555,7 +604,7 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: "export {}\ndeclare global {}" + content: "export {}\ndeclare global {}", }; return createWatchedSystem([file1, libFile, configFile]); }, @@ -564,8 +613,8 @@ export class A { timeouts: sys => sys.runQueuedTimeoutCallbacks(), edit: sys => { sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: { module: "none" } })); - } - }] + }, + }], }); it("two watch programs are not affected by each other", () => { @@ -573,23 +622,25 @@ export class A { path: "/a/b/f1.ts", content: ` export * from "../c/f2"; - export * from "../d/f3";` + export * from "../d/f3";`, }; const file2 = { path: "/a/c/f2.ts", - content: "export let x = 1;" + content: "export let x = 1;", }; const file3 = { path: "/a/d/f3.ts", - content: "export let y = 1;" + content: "export let y = 1;", }; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([libFile, file1, file2, file3])); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([libFile, file1, file2, file3]), + ); const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles: [file2.path, file3.path], system: sys, options: { allowNonTsExtensions: true }, cb, - watchOptions: undefined + watchOptions: undefined, }); ts.createWatchProgram(host); baseline.push(`${sys.getExecutingFilePath()} --w ${file2.path} ${file3.path}`); @@ -601,15 +652,15 @@ export class A { oldSnap, }); - const {cb: cb2, getPrograms: getPrograms2 } = commandLineCallbacks(sys); + const { cb: cb2, getPrograms: getPrograms2 } = commandLineCallbacks(sys); const oldSnap2 = sys.snap(); baseline.push("createing separate watcher"); ts.createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ - rootFiles:[file1.path], + rootFiles: [file1.path], system: sys, options: { allowNonTsExtensions: true }, cb: cb2, - watchOptions: undefined + watchOptions: undefined, })); watchBaseline({ baseline, @@ -622,7 +673,10 @@ export class A { sys.logTimeoutQueueLength(); baseline.push(`First program is not updated:: ${getPrograms() === ts.emptyArray}`); baseline.push(`Second program is not updated:: ${getPrograms2() === ts.emptyArray}`); - Harness.Baseline.runBaseline(`tscWatch/${scenario}/two-watch-programs-are-not-affected-by-each-other.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/${scenario}/two-watch-programs-are-not-affected-by-each-other.js`, + baseline.join("\r\n"), + ); }); verifyTscWatch({ @@ -632,7 +686,7 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; return createWatchedSystem([file1, libFile, configFile]); }, @@ -641,56 +695,61 @@ export class A { caption: "Write f2", edit: sys => sys.writeFile("/a/b/f2.ts", "let y = 1"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ scenario, - subScenario: "can correctly update configured project when set of root files has changed (new file in list of files)", + subScenario: + "can correctly update configured project when set of root files has changed (new file in list of files)", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const configFile = { path: configFilePath, - content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts"] }) + content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts"] }), }; return createWatchedSystem([file1, file2, libFile, configFile]); }, edits: [ { caption: "Modify config to make f2 as root too", - edit: sys => sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })), + edit: sys => + sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ scenario, - subScenario: "correctly parses wild card directories from implicit glob when two keys differ only in directory seperator", + subScenario: + "correctly parses wild card directories from implicit glob when two keys differ only in directory seperator", commandLineArgs: ["-w", "--extendedDiagnostics"], sys: () => { const file1 = { path: `/user/username/projects/myproject/f1.ts`, - content: "export const x = 1" + content: "export const x = 1", }; const file2 = { path: `/user/username/projects/myproject/f2.ts`, - content: "export const y = 1" + content: "export const y = 1", }; const configFile = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true }, include: ["./", "./**/*.json"] }) + content: JSON.stringify({ compilerOptions: { composite: true }, include: ["./", "./**/*.json"] }), }; - return createWatchedSystem([file1, file2, libFile, configFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([file1, file2, libFile, configFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { @@ -700,10 +759,11 @@ export class A { }, { caption: "Import new file", - edit: sys => sys.prependFile(`/user/username/projects/myproject/f1.ts`, `import { z } from "./new-file";`), + edit: sys => + sys.prependFile(`/user/username/projects/myproject/f1.ts`, `import { z } from "./new-file";`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -713,21 +773,24 @@ export class A { sys: () => { const file1 = { path: `/user/username/projects/myproject/Project/file1.ts`, - content: "export const x = 10;" + content: "export const x = 10;", }; const configFile = { path: `/user/username/projects/myproject/Project/tsconfig.json`, - content: JSON.stringify({ include: [".", "./**/*.json"] }) + content: JSON.stringify({ include: [".", "./**/*.json"] }), }; - return createWatchedSystem([file1, libFile, configFile], { currentDirectory: `/user/username/projects/myproject/Project` }); + return createWatchedSystem([file1, libFile, configFile], { + currentDirectory: `/user/username/projects/myproject/Project`, + }); }, edits: [ { caption: "Write file2", - edit: sys => sys.writeFile(`/user/username/projects/myproject/Project/file2.ts`, "export const y = 10;"), - timeouts: sys => sys.runQueuedTimeoutCallbacks() - } - ] + edit: sys => + sys.writeFile(`/user/username/projects/myproject/Project/file2.ts`, "export const y = 10;"), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), + }, + ], }); verifyTscWatch({ @@ -737,25 +800,29 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const configFile = { path: configFilePath, - content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }) + content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }), }; return createWatchedSystem([file1, file2, libFile, configFile]); }, edits: [ { caption: "Modify config to set outFile option", - edit: sys => sys.writeFile(configFilePath, JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] })), + edit: sys => + sys.writeFile( + configFilePath, + JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -765,15 +832,15 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const configFile = { path: configFilePath, - content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }) + content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }), }; return createWatchedSystem([file1, file2, libFile, configFile]); }, @@ -782,8 +849,8 @@ export class A { caption: "Delete f2", edit: sys => sys.deleteFile("/a/b/f2.ts"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -793,11 +860,11 @@ export class A { sys: () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1;" + content: "let x = 1;", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 2;" + content: "let y = 2;", }; return createWatchedSystem([file1, file2, libFile, configFile]); }, @@ -806,8 +873,8 @@ export class A { caption: "Delete config file", edit: sys => sys.deleteFile(configFilePath), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -817,11 +884,11 @@ export class A { sys: () => { const file1 = { path: "/a/b/app.ts", - content: "" + content: "", }; const corruptedConfig = { path: configFilePath, - content: "{" + content: "{", }; return createWatchedSystem([file1, libFile, corruptedConfig]); }, @@ -835,15 +902,15 @@ export class A { const libES5 = { path: "/compiler/lib.es5.d.ts", content: `${libFile.content} -declare const eval: any` +declare const eval: any`, }; const libES2015Promise = { path: "/compiler/lib.es2015.promise.d.ts", - content: `declare class Promise {}` + content: `declare class Promise {}`, }; const app = { path: "/src/app.ts", - content: "var x: Promise;" + content: "var x: Promise;", }; const config1 = { path: "/src/tsconfig.json", @@ -855,33 +922,40 @@ declare const eval: any` noImplicitAny: true, sourceMap: false, lib: [ - "es5" - ] - } - }) + "es5", + ], + }, + }, + ), }; - return createWatchedSystem([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" }); + return createWatchedSystem([libES5, libES2015Promise, app, config1], { + executingFilePath: "/compiler/tsc.js", + }); }, edits: [ { caption: "Change the lib in config", - edit: sys => sys.writeFile("/src/tsconfig.json", JSON.stringify( - { - compilerOptions: { - module: "commonjs", - target: "es5", - noImplicitAny: true, - sourceMap: false, - lib: [ - "es5", - "es2015.promise" - ] - } - }) - ), + edit: sys => + sys.writeFile( + "/src/tsconfig.json", + JSON.stringify( + { + compilerOptions: { + module: "commonjs", + target: "es5", + noImplicitAny: true, + sourceMap: false, + lib: [ + "es5", + "es2015.promise", + ], + }, + }, + ), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -891,7 +965,7 @@ declare const eval: any` sys: () => { const f = { path: "/a/src/app.ts", - content: "let x = 1;" + content: "let x = 1;", }; const config = { path: "/a/tsconfig.json", @@ -899,9 +973,9 @@ declare const eval: any` compilerOptions: {}, include: [ "src/**/*", - "notexistingfolder/*" - ] - }) + "notexistingfolder/*", + ], + }), }; return createWatchedSystem([f, config, libFile]); }, @@ -915,14 +989,21 @@ declare const eval: any` const changeModuleFileToModuleFile1: TscWatchCompileChange = { caption: "Rename moduleFile to moduleFile1", edit: sys => { - sys.renameFile("/users/username/projects/project/moduleFile.ts", "/users/username/projects/project/moduleFile1.ts"); + sys.renameFile( + "/users/username/projects/project/moduleFile.ts", + "/users/username/projects/project/moduleFile1.ts", + ); sys.deleteFile("/users/username/projects/project/moduleFile.js"); }, - timeouts: runQueuedTimeoutCallbacksTwice + timeouts: runQueuedTimeoutCallbacksTwice, }; const changeModuleFile1ToModuleFile: TscWatchCompileChange = { caption: "Rename moduleFile1 back to moduleFile", - edit: sys => sys.renameFile("/users/username/projects/project/moduleFile1.ts", "/users/username/projects/project/moduleFile.ts"), + edit: sys => + sys.renameFile( + "/users/username/projects/project/moduleFile1.ts", + "/users/username/projects/project/moduleFile.ts", + ), timeouts: runQueuedTimeoutCallbacksTwice, }; @@ -933,18 +1014,18 @@ declare const eval: any` sys: () => { const moduleFile = { path: "/users/username/projects/project/moduleFile.ts", - content: "export function bar() { };" + content: "export function bar() { };", }; const file1 = { path: "/users/username/projects/project/file1.ts", - content: 'import * as T from "./moduleFile"; T.bar();' + content: 'import * as T from "./moduleFile"; T.bar();', }; return createWatchedSystem([moduleFile, file1, libFile]); }, edits: [ changeModuleFileToModuleFile1, - changeModuleFile1ToModuleFile - ] + changeModuleFile1ToModuleFile, + ], }); verifyTscWatch({ @@ -954,47 +1035,49 @@ declare const eval: any` sys: () => { const moduleFile = { path: "/users/username/projects/project/moduleFile.ts", - content: "export function bar() { };" + content: "export function bar() { };", }; const file1 = { path: "/users/username/projects/project/file1.ts", - content: 'import * as T from "./moduleFile"; T.bar();' + content: 'import * as T from "./moduleFile"; T.bar();', }; const configFile = { path: "/users/username/projects/project/tsconfig.json", - content: `{}` + content: `{}`, }; return createWatchedSystem([moduleFile, file1, configFile, libFile]); }, edits: [ changeModuleFileToModuleFile1, - changeModuleFile1ToModuleFile - ] + changeModuleFile1ToModuleFile, + ], }); describe("types from config file", () => { function verifyTypesLoad(includeTypeRoots: boolean) { verifyTscWatch({ scenario, - subScenario: includeTypeRoots ? - "types should not load from config file path if config exists but does not specifies typeRoots" : - "types should load from config file path if config exists", + subScenario: includeTypeRoots + ? "types should not load from config file path if config exists but does not specifies typeRoots" + : "types should load from config file path if config exists", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { const f1 = { path: "/a/b/app.ts", - content: "let x = 1" + content: "let x = 1", }; const config = { path: configFilePath, - content: JSON.stringify({ compilerOptions: { types: ["node"], typeRoots: includeTypeRoots ? [] : undefined } }) + content: JSON.stringify({ + compilerOptions: { types: ["node"], typeRoots: includeTypeRoots ? [] : undefined }, + }), }; const node = { path: "/a/b/node_modules/@types/node/index.d.ts", - content: "declare var process: any" + content: "declare var process: any", }; const cwd = { - path: "/a/c" + path: "/a/c", }; return createWatchedSystem([f1, config, node, cwd, libFile], { currentDirectory: cwd.path }); }, @@ -1011,17 +1094,18 @@ declare const eval: any` sys: () => { const file1 = { path: "/users/username/projects/project/file1.ts", - content: 'import * as T from "./moduleFile"; T.bar();' + content: 'import * as T from "./moduleFile"; T.bar();', }; return createWatchedSystem([file1, libFile]); }, edits: [ { caption: "Create module file", - edit: sys => sys.writeFile("/users/username/projects/project/moduleFile.ts", "export function bar() { }"), + edit: sys => + sys.writeFile("/users/username/projects/project/moduleFile.ts", "export function bar() { }"), timeouts: runQueuedTimeoutCallbacksTwice, - } - ] + }, + ], }); verifyTscWatch({ @@ -1031,7 +1115,7 @@ declare const eval: any` sys: () => { const file = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const configFile = { path: configFilePath, @@ -1040,7 +1124,7 @@ declare const eval: any` "foo": "bar", "allowJS": true } - }` + }`, }; return createWatchedSystem([file, configFile, libFile]); }, @@ -1053,13 +1137,13 @@ declare const eval: any` sys: () => { const file = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const configFile = { path: configFilePath, content: `{ "compilerOptions": {} - }` + }`, }; return createWatchedSystem([file, configFile, libFile]); }, @@ -1072,34 +1156,43 @@ declare const eval: any` sys: () => { const file = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; return createWatchedSystem([file, configFile, libFile]); }, edits: [ { caption: "change config file to add error", - edit: sys => sys.writeFile(configFilePath, `{ + edit: sys => + sys.writeFile( + configFilePath, + `{ "compilerOptions": { "haha": 123 } - }`), + }`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "change config file to remove error", - edit: sys => sys.writeFile(configFilePath, `{ + edit: sys => + sys.writeFile( + configFilePath, + `{ "compilerOptions": { } - }`), + }`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ scenario, - subScenario: "non-existing directories listed in config file input array should be tolerated without crashing the server", + subScenario: + "non-existing directories listed in config file input array should be tolerated without crashing the server", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { const configFile = { @@ -1107,11 +1200,11 @@ declare const eval: any` content: `{ "compilerOptions": {}, "include": ["app/*", "test/**/*", "something"] - }` + }`, }; const file1 = { path: "/a/b/file1.ts", - content: "let t = 10;" + content: "let t = 10;", }; return createWatchedSystem([file1, configFile, libFile]); }, @@ -1119,27 +1212,28 @@ declare const eval: any` verifyTscWatch({ scenario, - subScenario: "non-existing directories listed in config file input array should be able to handle @types if input file list is empty", + subScenario: + "non-existing directories listed in config file input array should be able to handle @types if input file list is empty", commandLineArgs: ["-w", "-p", "/a/tsconfig.json"], sys: () => { const f = { path: "/a/app.ts", - content: "let x = 1" + content: "let x = 1", }; const config = { path: "/a/tsconfig.json", content: JSON.stringify({ compiler: {}, - files: [] - }) + files: [], + }), }; const t1 = { path: "/a/node_modules/@types/typings/index.d.ts", - content: `export * from "./lib"` + content: `export * from "./lib"`, }; const t2 = { path: "/a/node_modules/@types/typings/lib.d.ts", - content: `export const x: number` + content: `export const x: number`, }; return createWatchedSystem([f, config, t1, t2, libFile], { currentDirectory: ts.getDirectoryPath(f.path) }); }, @@ -1148,7 +1242,7 @@ declare const eval: any` it("should support files without extensions", () => { const f = { path: "/a/compile", - content: "let x = 1" + content: "let x = 1", }; const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([f, libFile])); const watch = ts.createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ @@ -1156,7 +1250,7 @@ declare const eval: any` system: sys, options: { allowNonTsExtensions: true }, cb, - watchOptions: undefined + watchOptions: undefined, })); runWatchBaseline({ scenario, @@ -1166,18 +1260,19 @@ declare const eval: any` baseline, oldSnap, getPrograms, - watchOrSolution: watch + watchOrSolution: watch, }); }); verifyTscWatch({ scenario, - subScenario: "Options Diagnostic locations reported correctly with changes in configFile contents when options change", + subScenario: + "Options Diagnostic locations reported correctly with changes in configFile contents when options change", commandLineArgs: ["-w", "-p", configFilePath], sys: () => { const file = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const configFile = { path: configFilePath, @@ -1189,23 +1284,27 @@ declare const eval: any` "inlineSourceMap": true, "mapRoot": "./" } -}` +}`, }; return createWatchedSystem([file, libFile, configFile]); }, edits: [ { caption: "Remove the comment from config file", - edit: sys => sys.writeFile(configFilePath, ` + edit: sys => + sys.writeFile( + configFilePath, + ` { "compilerOptions": { "inlineSourceMap": true, "mapRoot": "./" } -}`), +}`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); describe("should not trigger recompilation because of program emit", () => { @@ -1217,60 +1316,63 @@ declare const eval: any` sys: () => { const file1: File = { path: `/user/username/projects/myproject/file1.ts`, - content: "export const c = 30;" + content: "export const c = 30;", }; const file2: File = { path: `/user/username/projects/myproject/src/file2.ts`, - content: `import {c} from "file1"; export const d = 30;` + content: `import {c} from "file1"; export const d = 30;`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ - compilerOptions: compilerOptionsToConfigJson(options) - }) + compilerOptions: compilerOptionsToConfigJson(options), + }), }; - return createWatchedSystem([file1, file2, libFile, tsconfig], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([file1, file2, libFile, tsconfig], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ noopChange, { caption: "Add new file", - edit: sys => sys.writeFile(`/user/username/projects/myproject/src/file3.ts`, `export const y = 10;`), + edit: sys => + sys.writeFile(`/user/username/projects/myproject/src/file3.ts`, `export const y = 10;`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // To update program and failed lookups }, noopChange, - ] + ], }); } verifyWithOptions( "without outDir or outFile is specified", - { module: ts.ModuleKind.AMD } + { module: ts.ModuleKind.AMD }, ); verifyWithOptions( "with outFile", - { module: ts.ModuleKind.AMD, outFile: "build/outFile.js" } + { module: ts.ModuleKind.AMD, outFile: "build/outFile.js" }, ); verifyWithOptions( "when outDir is specified", - { module: ts.ModuleKind.AMD, outDir: "build" } + { module: ts.ModuleKind.AMD, outDir: "build" }, ); verifyWithOptions( "without outDir or outFile is specified with declaration enabled", - { module: ts.ModuleKind.AMD, declaration: true } + { module: ts.ModuleKind.AMD, declaration: true }, ); verifyWithOptions( "when outDir and declarationDir is specified", - { module: ts.ModuleKind.AMD, outDir: "build", declaration: true, declarationDir: "decls" } + { module: ts.ModuleKind.AMD, outDir: "build", declaration: true, declarationDir: "decls" }, ); verifyWithOptions( "declarationDir is specified", - { module: ts.ModuleKind.AMD, declaration: true, declarationDir: "decls" } + { module: ts.ModuleKind.AMD, declaration: true, declarationDir: "decls" }, ); }); @@ -1286,23 +1388,26 @@ function two() { return function three() { one(); } -}` +}`, }; return createWatchedSystem([file, libFile]); }, edits: [ { caption: "Change file to module", - edit: sys => sys.writeFile("/a/b/file.ts", `function one() {} + edit: sys => + sys.writeFile( + "/a/b/file.ts", + `function one() {} export function two() { return function three() { one(); } -}`), +}`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - - } - ] + }, + ], }); verifyTscWatch({ @@ -1313,27 +1418,33 @@ export function two() { const projectLocation = "/home/username/project"; const file: File = { path: `${projectLocation}/src/file1.ts`, - content: "var a = 10;" + content: "var a = 10;", }; const configFile: File = { path: `${projectLocation}/tsconfig.json`, - content: "{}" + content: "{}", }; return createWatchedSystem([file, libFile, configFile]); }, edits: [ { caption: "Rename file1 to file2", - edit: sys => sys.renameFile("/home/username/project/src/file1.ts", "/home/username/project/src/file2.ts"), + edit: sys => + sys.renameFile("/home/username/project/src/file1.ts", "/home/username/project/src/file2.ts"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); function changeParameterTypeOfBFile(parameterName: string, toType: string): TscWatchCompileChange { return { caption: `Changed ${parameterName} type to ${toType}`, - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/b.ts`, new RegExp(`${parameterName}: [a-z]*`), `${parameterName}: ${toType}`), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/b.ts`, + new RegExp(`${parameterName}: [a-z]*`), + `${parameterName}: ${toType}`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }; } @@ -1346,14 +1457,14 @@ export function two() { const aFile: File = { path: `/user/username/projects/myproject/a.ts`, content: `import test from './b'; -test(4, 5);` +test(4, 5);`, }; const bFile: File = { path: `/user/username/projects/myproject/b.ts`, content: `function test(x: number, y: number) { return x + y / 5; } -export default test;` +export default test;`, }; const tsconfigFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, @@ -1362,17 +1473,19 @@ export default test;` module: "commonjs", noEmit: true, strict: true, - } - }) + }, + }), }; - return createWatchedSystem([aFile, bFile, libFile, tsconfigFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, bFile, libFile, tsconfigFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ changeParameterTypeOfBFile("x", "string"), changeParameterTypeOfBFile("x", "number"), changeParameterTypeOfBFile("y", "string"), changeParameterTypeOfBFile("y", "number"), - ] + ], }); verifyTscWatch({ @@ -1383,31 +1496,45 @@ export default test;` const aFile: File = { path: `/user/username/projects/myproject/a.ts`, content: `declare function foo(): null | { hello: any }; -foo().hello` +foo().hello`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: {} }) + content: JSON.stringify({ compilerOptions: {} }), }; - return createWatchedSystem([aFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, config, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Enable strict null checks", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { strictNullChecks: true } })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ compilerOptions: { strictNullChecks: true } }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Set always strict false", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } })), // Avoid changing 'alwaysStrict' or must re-bind + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } }), + ), // Avoid changing 'alwaysStrict' or must re-bind timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Disable strict", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: {} })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ compilerOptions: {} }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1426,21 +1553,27 @@ foo().hello` reallyLongPropertyName6: string | number | boolean | object | symbol | bigint; reallyLongPropertyName7: string | number | boolean | object | symbol | bigint; }; -v === 'foo';` +v === 'foo';`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: {} }) + content: JSON.stringify({ compilerOptions: {} }), }; - return createWatchedSystem([aFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, config, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Enable noErrorTruncation", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { noErrorTruncation: true } })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ compilerOptions: { noErrorTruncation: true } }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1451,21 +1584,25 @@ v === 'foo';` const aFile: File = { path: `/a.ts`, content: `class C { get prop() { return 1; } } -class D extends C { prop = 1; }` +class D extends C { prop = 1; }`, }; const config: File = { path: `/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { target: "es6" } }) + content: JSON.stringify({ compilerOptions: { target: "es6" } }), }; return createWatchedSystem([aFile, config, libFile]); }, edits: [ { caption: "Enable useDefineForClassFields", - edit: sys => sys.writeFile(`/tsconfig.json`, JSON.stringify({ compilerOptions: { target: "es6", useDefineForClassFields: true } })), + edit: sys => + sys.writeFile( + `/tsconfig.json`, + JSON.stringify({ compilerOptions: { target: "es6", useDefineForClassFields: true } }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1475,39 +1612,52 @@ class D extends C { prop = 1; }` sys: () => { const aFile: File = { path: `/user/username/projects/myproject/a.ts`, - content: `export class C {}` + content: `export class C {}`, }; const bFile: File = { path: `/user/username/projects/myproject/b.ts`, content: `import {C} from './a'; -export function f(p: C) { return p; }` +export function f(p: C) { return p; }`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: {} }) + content: JSON.stringify({ compilerOptions: {} }), }; - return createWatchedSystem([aFile, bFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, bFile, config, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: 'Set to "remove"', - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "remove" } })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "remove" } }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: 'Set to "error"', - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "error" } })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "error" } }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: 'Set to "preserve"', - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "preserve" } })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ compilerOptions: { importsNotUsedAsValues: "preserve" } }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); - verifyTscWatch({ scenario, subScenario: "updates errors when forceConsistentCasingInFileNames changes", @@ -1515,25 +1665,29 @@ export function f(p: C) { return p; }` sys: () => { const aFile: File = { path: `/a.ts`, - content: `export class C {}` + content: `export class C {}`, }; const bFile: File = { path: `/b.ts`, - content: `import {C} from './a'; import * as A from './A';` + content: `import {C} from './a'; import * as A from './A';`, }; const config: File = { path: `/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: false } }) + content: JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: false } }), }; return createWatchedSystem([aFile, bFile, config, libFile], { useCaseSensitiveFileNames: false }); }, edits: [ { caption: "Enable forceConsistentCasingInFileNames", - edit: sys => sys.writeFile(`/tsconfig.json`, JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } })), + edit: sys => + sys.writeFile( + `/tsconfig.json`, + JSON.stringify({ compilerOptions: { forceConsistentCasingInFileNames: true } }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1543,25 +1697,31 @@ export function f(p: C) { return p; }` sys: () => { const aFile: File = { path: `/user/username/projects/myproject/a.ts`, - content: `import * as data from './data.json'` + content: `import * as data from './data.json'`, }; const jsonFile: File = { path: `/user/username/projects/myproject/data.json`, - content: `{ "foo": 1 }` + content: `{ "foo": 1 }`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { moduleResolution: "node" } }) + content: JSON.stringify({ compilerOptions: { moduleResolution: "node" } }), }; - return createWatchedSystem([aFile, jsonFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, jsonFile, config, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Enable resolveJsonModule", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ compilerOptions: { moduleResolution: "node", resolveJsonModule: true } })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ compilerOptions: { moduleResolution: "node", resolveJsonModule: true } }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1573,21 +1733,27 @@ export function f(p: C) { return p; }` path: `/user/username/projects/myproject/a.ts`, content: `declare module 'a' { type foo = number; -}` +}`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; - return createWatchedSystem([aFile, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, config, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Create b.ts with same content", // Create bts with same file contents - edit: sys => sys.writeFile(`/user/username/projects/myproject/b.ts`, `declare module 'a' { + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/b.ts`, + `declare module 'a' { type foo = number; -}`), +}`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { @@ -1595,7 +1761,7 @@ export function f(p: C) { return p; }` edit: sys => sys.deleteFile(`/user/username/projects/myproject/b.ts`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); describe("updates errors in lib file", () => { @@ -1609,7 +1775,7 @@ export function f(p: C) { return p; }` content: `${libFile.content} interface Document { readonly ${field}: boolean; -}` +}`, }; function verifyLibFileErrorsWith(subScenario: string, aFile: File) { @@ -1618,11 +1784,18 @@ interface Document { scenario, subScenario: `updates errors in lib file/${subScenario}`, commandLineArgs: ["-w", aFile.path, ...commandLineOptions], - sys: () => createWatchedSystem([aFile, libFileWithDocument], { currentDirectory: "/user/username/projects/myproject" }), + sys: () => + createWatchedSystem([aFile, libFileWithDocument], { + currentDirectory: "/user/username/projects/myproject", + }), edits: [ { caption: "Remove document declaration from file", - edit: sys => sys.writeFile(aFile.path, aFile.content.replace(fieldWithoutReadonly, "var x: string;")), + edit: sys => + sys.writeFile( + aFile.path, + aFile.content.replace(fieldWithoutReadonly, "var x: string;"), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { @@ -1630,7 +1803,7 @@ interface Document { edit: sys => sys.writeFile(aFile.path, aFile.content), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); } @@ -1643,7 +1816,7 @@ interface Document { const aFile: File = { path: `/user/username/projects/myproject/a.ts`, content: `${fieldWithoutReadonly} -var y: number;` +var y: number;`, }; verifyLibFileErrorsWith("when non module file changes", aFile); }); @@ -1655,7 +1828,7 @@ var y: number;` declare global { ${fieldWithoutReadonly} var y: number; -}` +}`, }; verifyLibFileErrorsWith("when module file with global definitions changes", aFile); }); @@ -1680,26 +1853,28 @@ var y: number; path: `/user/username/projects/myproject/a.ts`, content: `interface Document { ${field}: boolean; -}` +}`, }; const bFile: File = { path: `/user/username/projects/myproject/b.d.ts`, content: `interface Document { ${field}: boolean; -}` +}`, }; const libFileWithDocument: File = { path: libFile.path, content: `${libFile.content} interface Document { readonly ${field}: boolean; -}` +}`, }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; - return createWatchedSystem([aFile, bFile, configFile, libFileWithDocument], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, bFile, configFile, libFileWithDocument], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ changeWhenLibCheckChanges({ skipLibCheck: true }), @@ -1708,7 +1883,7 @@ interface Document { changeWhenLibCheckChanges({ skipDefaultLibCheck: true }), changeWhenLibCheckChanges({ skipLibCheck: true }), changeWhenLibCheckChanges({}), - ] + ], }); verifyTscWatch({ @@ -1718,22 +1893,24 @@ interface Document { sys: () => { const aFile: File = { path: `/user/username/projects/myproject/a.ts`, - content: `export const a: string = "";` + content: `export const a: string = "";`, }; const bFile: File = { path: `/user/username/projects/myproject/b.ts`, content: `import { a } from "./a"; -const b: string = a;` +const b: string = a;`, }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - isolatedModules: true - } - }) + isolatedModules: true, + }, + }), }; - return createWatchedSystem([aFile, bFile, configFile, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, bFile, configFile, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { @@ -1741,7 +1918,7 @@ const b: string = a;` edit: sys => sys.writeFile(`/user/username/projects/myproject/a.ts`, `export const a: number = 1`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1751,32 +1928,38 @@ const b: string = a;` sys: () => { const aFile: File = { path: `/user/username/projects/myproject/a.ts`, - content: `import { x } from "../b";` + content: `import { x } from "../b";`, }; const bFile: File = { path: `/user/username/projects/b.ts`, - content: `export const x = 10;` + content: `export const x = 10;`, }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { rootDir: ".", - outDir: "lib" - } - }) + outDir: "lib", + }, + }), }; - return createWatchedSystem([aFile, bFile, configFile, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([aFile, bFile, configFile, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Make changes to file a", - edit: sys => sys.writeFile(`/user/username/projects/myproject/a.ts`, ` + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/a.ts`, + ` -import { x } from "../b";`), +import { x } from "../b";`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1786,25 +1969,31 @@ import { x } from "../b";`), sys: () => { const index: File = { path: `/user/username/projects/myproject/index.tsx`, - content: `declare var React: any;\nconst d =
;` + content: `declare var React: any;\nconst d =
;`, }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - jsx: "preserve" - } - }) + jsx: "preserve", + }, + }), }; - return createWatchedSystem([index, configFile, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([index, configFile, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Update 'jsx' to 'react'", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, '{ "compilerOptions": { "jsx": "react" } }'), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + '{ "compilerOptions": { "jsx": "react" } }', + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1816,65 +2005,86 @@ import { x } from "../b";`), path: "/a/b/first.tsconfig.json", content: JSON.stringify({ compilerOptions: { - strict: true - } - }) + strict: true, + }, + }), }; const secondExtendedConfigFile: File = { path: "/a/b/second.tsconfig.json", content: JSON.stringify({ - extends: "./first.tsconfig.json" - }) + extends: "./first.tsconfig.json", + }), }; const configFile: File = { path: configFilePath, content: JSON.stringify({ compilerOptions: {}, - files: [commonFile1.path, commonFile2.path] - }) + files: [commonFile1.path, commonFile2.path], + }), }; return createWatchedSystem([ - libFile, commonFile1, commonFile2, configFile, firstExtendedConfigFile, secondExtendedConfigFile + libFile, + commonFile1, + commonFile2, + configFile, + firstExtendedConfigFile, + secondExtendedConfigFile, ]); }, edits: [ { caption: "Change config to extend another config", - edit: sys => sys.modifyFile(configFilePath, JSON.stringify({ - extends: "./second.tsconfig.json", - compilerOptions: {}, - files: [commonFile1.path, commonFile2.path] - })), + edit: sys => + sys.modifyFile( + configFilePath, + JSON.stringify({ + extends: "./second.tsconfig.json", + compilerOptions: {}, + files: [commonFile1.path, commonFile2.path], + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Change first extended config", - edit: sys => sys.modifyFile("/a/b/first.tsconfig.json", JSON.stringify({ - compilerOptions: { - strict: false, - } - })), + edit: sys => + sys.modifyFile( + "/a/b/first.tsconfig.json", + JSON.stringify({ + compilerOptions: { + strict: false, + }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Change second extended config", - edit: sys => sys.modifyFile("/a/b/second.tsconfig.json", JSON.stringify({ - extends: "./first.tsconfig.json", - compilerOptions: { - strictNullChecks: true, - } - })), + edit: sys => + sys.modifyFile( + "/a/b/second.tsconfig.json", + JSON.stringify({ + extends: "./first.tsconfig.json", + compilerOptions: { + strictNullChecks: true, + }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Change config to stop extending another config", - edit: sys => sys.modifyFile(configFilePath, JSON.stringify({ - compilerOptions: {}, - files: [commonFile1.path, commonFile2.path] - })), + edit: sys => + sys.modifyFile( + configFilePath, + JSON.stringify({ + compilerOptions: {}, + files: [commonFile1.path, commonFile2.path], + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1884,11 +2094,11 @@ import { x } from "../b";`), sys: () => { const module1: File = { path: `/user/username/projects/myproject/client/folder1/module1.ts`, - content: `export class Module1Class { }` + content: `export class Module1Class { }`, }; const module2: File = { path: `/user/username/projects/myproject/folder2/module2.ts`, - content: `import * as M from "folder1/module1";` + content: `import * as M from "folder1/module1";`, }; const symlink: SymLink = { path: `/user/username/projects/myproject/client/linktofolder2`, @@ -1901,76 +2111,96 @@ import { x } from "../b";`), baseUrl: "client", paths: { "*": ["*"] }, }, - include: ["client/**/*", "folder2"] - }) + include: ["client/**/*", "folder2"], + }), }; - return createWatchedSystem([module1, module2, symlink, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([module1, module2, symlink, config, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Add module3 to folder2", - edit: sys => sys.writeFile(`/user/username/projects/myproject/client/linktofolder2/module3.ts`, `import * as M from "folder1/module1";`), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/client/linktofolder2/module3.ts`, + `import * as M from "folder1/module1";`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ scenario, subScenario: "when new file is added to the referenced project", - commandLineArgs: ["-w", "-p", `/user/username/projects/myproject/projects/project2/tsconfig.json`, "--extendedDiagnostics"], + commandLineArgs: [ + "-w", + "-p", + `/user/username/projects/myproject/projects/project2/tsconfig.json`, + "--extendedDiagnostics", + ], sys: () => { const config1: File = { path: `/user/username/projects/myproject/projects/project1/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "none", - composite: true + composite: true, }, - exclude: ["temp"] - }) + exclude: ["temp"], + }), }; const class1: File = { path: `/user/username/projects/myproject/projects/project1/class1.ts`, - content: `class class1 {}` + content: `class class1 {}`, }; // Built file const class1Dt: File = { path: `/user/username/projects/myproject/projects/project1/class1.d.ts`, - content: `declare class class1 {}` + content: `declare class class1 {}`, }; const config2: File = { path: `/user/username/projects/myproject/projects/project2/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "none", - composite: true + composite: true, }, references: [ - { path: "../project1" } - ] - }) + { path: "../project1" }, + ], + }), }; const class2: File = { path: `/user/username/projects/myproject/projects/project2/class2.ts`, - content: `class class2 {}` + content: `class class2 {}`, }; return createWatchedSystem([config1, class1, config2, class2, libFile, class1Dt]); }, edits: [ { caption: "Add class3 to project1", - edit: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.ts`, `class class3 {}`), + edit: sys => + sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.ts`, `class class3 {}`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Add output of class3", - edit: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/projects/project1/class3.d.ts`, + `declare class class3 {}`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Add excluded file to project1", - edit: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }), + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }), timeouts: sys => sys.logTimeoutQueueLength(), }, { @@ -1980,10 +2210,14 @@ import { x } from "../b";`), }, { caption: "Add output of class3", - edit: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/projects/project1/class3.d.ts`, + `declare class class3 {}`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -1993,13 +2227,15 @@ import { x } from "../b";`), sys: () => { const module1: File = { path: `/user/username/projects/myproject/index.ts`, - content: `` + content: ``, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: `{}` + content: `{}`, }; - return createWatchedSystem([module1, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([module1, config, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { @@ -2007,7 +2243,7 @@ import { x } from "../b";`), edit: sys => sys.writeFile(`/user/username/projects/myproject/foo`, ``), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ @@ -2017,34 +2253,40 @@ import { x } from "../b";`), sys: () => { const module1: File = { path: `/user/username/projects/myproject/a.ts`, - content: `` + content: ``, }; const module2: File = { path: `/user/username/projects/myproject/b.ts`, - content: `import "./a.ts";` + content: `import "./a.ts";`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { noEmit: true, - allowImportingTsExtensions: false - } + allowImportingTsExtensions: false, + }, }), }; - return createWatchedSystem([module1, module2, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([module1, module2, config, libFile], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "Change allowImportingTsExtensions to true", - edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ - compilerOptions: { - noEmit: true, - allowImportingTsExtensions: true - } - })), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/tsconfig.json`, + JSON.stringify({ + compilerOptions: { + noEmit: true, + allowImportingTsExtensions: true, + }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); }); diff --git a/src/testRunner/unittests/tscWatch/projectsWithReferences.ts b/src/testRunner/unittests/tscWatch/projectsWithReferences.ts index 8c091768df202..c15001a5d5459 100644 --- a/src/testRunner/unittests/tscWatch/projectsWithReferences.ts +++ b/src/testRunner/unittests/tscWatch/projectsWithReferences.ts @@ -2,7 +2,9 @@ import { createSolutionBuilder, createSystemWithSolutionBuild, } from "../helpers/solutionBuilder"; -import { verifyTscWatch } from "../helpers/tscWatch"; +import { + verifyTscWatch, +} from "../helpers/tscWatch"; import { getTsBuildProjectFile, getTsBuildProjectFilePath, @@ -14,21 +16,22 @@ describe("unittests:: tsc-watch:: projects with references: invoking when refere verifyTscWatch({ scenario: "projectsWithReferences", subScenario: "on sample project", - sys: () => createSystemWithSolutionBuild( - ["tests"], - [ - libFile, - getTsBuildProjectFile("sample1", "core/tsconfig.json"), - getTsBuildProjectFile("sample1", "core/index.ts"), - getTsBuildProjectFile("sample1", "core/anotherModule.ts"), - getTsBuildProjectFile("sample1", "core/some_decl.d.ts"), - getTsBuildProjectFile("sample1", "logic/tsconfig.json"), - getTsBuildProjectFile("sample1", "logic/index.ts"), - getTsBuildProjectFile("sample1", "tests/tsconfig.json"), - getTsBuildProjectFile("sample1", "tests/index.ts"), - ], - { currentDirectory: `/user/username/projects/sample1` } - ), + sys: () => + createSystemWithSolutionBuild( + ["tests"], + [ + libFile, + getTsBuildProjectFile("sample1", "core/tsconfig.json"), + getTsBuildProjectFile("sample1", "core/index.ts"), + getTsBuildProjectFile("sample1", "core/anotherModule.ts"), + getTsBuildProjectFile("sample1", "core/some_decl.d.ts"), + getTsBuildProjectFile("sample1", "logic/tsconfig.json"), + getTsBuildProjectFile("sample1", "logic/index.ts"), + getTsBuildProjectFile("sample1", "tests/tsconfig.json"), + getTsBuildProjectFile("sample1", "tests/index.ts"), + ], + { currentDirectory: `/user/username/projects/sample1` }, + ), commandLineArgs: ["-w", "-p", "tests", "--traceResolution", "--explainFiles"], edits: [ { @@ -45,26 +48,32 @@ describe("unittests:: tsc-watch:: projects with references: invoking when refere { caption: "non local edit in logic ts, and build logic", edit: sys => { - sys.appendFile(getTsBuildProjectFilePath("sample1", "logic/index.ts"), `export function gfoo() { }`); + sys.appendFile( + getTsBuildProjectFilePath("sample1", "logic/index.ts"), + `export function gfoo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["logic"]); solutionBuilder.build(); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "change in project reference config file builds correctly", edit: sys => { - sys.writeFile(getTsBuildProjectFilePath("sample1", "logic/tsconfig.json"), JSON.stringify({ - compilerOptions: { composite: true, declaration: true, declarationDir: "decls" }, - references: [{ path: "../core" }] - })); + sys.writeFile( + getTsBuildProjectFilePath("sample1", "logic/tsconfig.json"), + JSON.stringify({ + compilerOptions: { composite: true, declaration: true, declarationDir: "decls" }, + references: [{ path: "../core" }], + }), + ); const solutionBuilder = createSolutionBuilder(sys, ["logic"]); solutionBuilder.build(); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], - baselineDependencies: true + baselineDependencies: true, }); function changeCompilerOpitonsPaths(sys: TestServerHost, config: string, newPaths: object) { @@ -76,76 +85,99 @@ describe("unittests:: tsc-watch:: projects with references: invoking when refere verifyTscWatch({ scenario: "projectsWithReferences", subScenario: "on transitive references", - sys: () => createSystemWithSolutionBuild( - ["tsconfig.c.json"], - [ - libFile, - getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"), - getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json"), - getTsBuildProjectFile("transitiveReferences", "tsconfig.c.json"), - getTsBuildProjectFile("transitiveReferences", "a.ts"), - getTsBuildProjectFile("transitiveReferences", "b.ts"), - getTsBuildProjectFile("transitiveReferences", "c.ts"), - getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"), - ], - { currentDirectory: `/user/username/projects/transitiveReferences` } - ), + sys: () => + createSystemWithSolutionBuild( + ["tsconfig.c.json"], + [ + libFile, + getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"), + getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json"), + getTsBuildProjectFile("transitiveReferences", "tsconfig.c.json"), + getTsBuildProjectFile("transitiveReferences", "a.ts"), + getTsBuildProjectFile("transitiveReferences", "b.ts"), + getTsBuildProjectFile("transitiveReferences", "c.ts"), + getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"), + ], + { currentDirectory: `/user/username/projects/transitiveReferences` }, + ), commandLineArgs: ["-w", "-p", "tsconfig.c.json", "--traceResolution", "--explainFiles"], edits: [ { caption: "non local edit b ts, and build b", edit: sys => { - sys.appendFile(getTsBuildProjectFilePath("transitiveReferences", "b.ts"), `export function gfoo() { }`); + sys.appendFile( + getTsBuildProjectFilePath("transitiveReferences", "b.ts"), + `export function gfoo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["tsconfig.b.json"]); solutionBuilder.build(); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "edit on config file", edit: sys => { sys.ensureFileOrFolder({ path: getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"), - content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))! + content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!, }); - changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), { "@ref/*": ["./nrefs/*"] }); + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), + { "@ref/*": ["./nrefs/*"] }, + ); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert config file edit", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), { "@ref/*": ["./refs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "tsconfig.c.json"), + { "@ref/*": ["./refs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "edit in referenced config file", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), { "@ref/*": ["./nrefs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), + { "@ref/*": ["./nrefs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert referenced config file edit", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), { "@ref/*": ["./refs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), + { "@ref/*": ["./refs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "deleting referenced config file", edit: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json")), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert deleting referenced config file", edit: sys => sys.ensureFileOrFolder(getTsBuildProjectFile("transitiveReferences", "tsconfig.b.json")), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "deleting transitively referenced config file", edit: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "tsconfig.a.json")), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert deleting transitively referenced config file", edit: sys => sys.ensureFileOrFolder(getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json")), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], baselineDependencies: true, @@ -154,30 +186,31 @@ describe("unittests:: tsc-watch:: projects with references: invoking when refere verifyTscWatch({ scenario: "projectsWithReferences", subScenario: "when referenced project uses different module resolution", - sys: () => createSystemWithSolutionBuild( - ["tsconfig.c.json"], - [ - libFile, - getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"), - { - path: getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), - content: JSON.stringify({ - compilerOptions: { composite: true, moduleResolution: "classic" }, - files: ["b.ts"], - references: [{ path: "tsconfig.a.json" }] - }) - }, - getTsBuildProjectFile("transitiveReferences", "tsconfig.c.json"), - getTsBuildProjectFile("transitiveReferences", "a.ts"), - { - path: getTsBuildProjectFilePath("transitiveReferences", "b.ts"), - content: `import {A} from "a";export const b = new A();` - }, - getTsBuildProjectFile("transitiveReferences", "c.ts"), - getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"), - ], - { currentDirectory: `/user/username/projects/transitiveReferences` } - ), + sys: () => + createSystemWithSolutionBuild( + ["tsconfig.c.json"], + [ + libFile, + getTsBuildProjectFile("transitiveReferences", "tsconfig.a.json"), + { + path: getTsBuildProjectFilePath("transitiveReferences", "tsconfig.b.json"), + content: JSON.stringify({ + compilerOptions: { composite: true, moduleResolution: "classic" }, + files: ["b.ts"], + references: [{ path: "tsconfig.a.json" }], + }), + }, + getTsBuildProjectFile("transitiveReferences", "tsconfig.c.json"), + getTsBuildProjectFile("transitiveReferences", "a.ts"), + { + path: getTsBuildProjectFilePath("transitiveReferences", "b.ts"), + content: `import {A} from "a";export const b = new A();`, + }, + getTsBuildProjectFile("transitiveReferences", "c.ts"), + getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"), + ], + { currentDirectory: `/user/username/projects/transitiveReferences` }, + ), commandLineArgs: ["-w", "-p", "tsconfig.c.json", "--traceResolution", "--explainFiles"], baselineDependencies: true, }); @@ -185,122 +218,147 @@ describe("unittests:: tsc-watch:: projects with references: invoking when refere verifyTscWatch({ scenario: "projectsWithReferences", subScenario: "on transitive references in different folders", - sys: () => createSystemWithSolutionBuild( - ["c"], - [ - libFile, - { - path: getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), - content: JSON.stringify({ - compilerOptions: { composite: true }, - files: ["index.ts"] - }), - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), - content: JSON.stringify({ - compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, - files: ["index.ts"], - references: [{ path: `../a` }] - }), - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), - content: JSON.stringify({ - compilerOptions: { baseUrl: "./", paths: { "@ref/*": ["../refs/*"] } }, - files: ["index.ts"], - references: [{ path: `../b` }] - }), - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "a/index.ts"), - content: `export class A {}`, - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), - content: `import {A} from '@ref/a'; + sys: () => + createSystemWithSolutionBuild( + ["c"], + [ + libFile, + { + path: getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), + content: JSON.stringify({ + compilerOptions: { composite: true }, + files: ["index.ts"], + }), + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + content: JSON.stringify({ + compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, + files: ["index.ts"], + references: [{ path: `../a` }], + }), + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + content: JSON.stringify({ + compilerOptions: { baseUrl: "./", paths: { "@ref/*": ["../refs/*"] } }, + files: ["index.ts"], + references: [{ path: `../b` }], + }), + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "a/index.ts"), + content: `export class A {}`, + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), + content: `import {A} from '@ref/a'; export const b = new A();`, - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "c/index.ts"), - content: `import {b} from '../b'; + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "c/index.ts"), + content: `import {b} from '../b'; import {X} from "@ref/a"; b; X;`, - }, - getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"), - ], - { currentDirectory: `/user/username/projects/transitiveReferences` } - ), + }, + getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"), + ], + { currentDirectory: `/user/username/projects/transitiveReferences` }, + ), commandLineArgs: ["-w", "-p", "c", "--traceResolution", "--explainFiles"], edits: [ { caption: "non local edit b ts, and build b", edit: sys => { - sys.appendFile(getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), `export function gfoo() { }`); + sys.appendFile( + getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), + `export function gfoo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["b"]); solutionBuilder.build(); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "edit on config file", edit: sys => { sys.ensureFileOrFolder({ path: getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"), - content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))! + content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!, }); - changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }); + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + { "@ref/*": ["../nrefs/*"] }, + ); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert config file edit", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../refs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + { "@ref/*": ["../refs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "edit in referenced config file", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + { "@ref/*": ["../nrefs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert referenced config file edit", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../refs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + { "@ref/*": ["../refs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "deleting referenced config file", edit: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json")), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert deleting referenced config file", - edit: sys => sys.writeFile( - getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), - JSON.stringify({ - compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, - files: ["index.ts"], - references: [{ path: `../a` }] - }) - ), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.writeFile( + getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + JSON.stringify({ + compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, + files: ["index.ts"], + references: [{ path: `../a` }], + }), + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "deleting transitively referenced config file", edit: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json")), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert deleting transitively referenced config file", - edit: sys => sys.writeFile( - getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), - JSON.stringify({ - compilerOptions: { composite: true }, - files: ["index.ts"] - }), - ), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.writeFile( + getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), + JSON.stringify({ + compilerOptions: { composite: true }, + files: ["index.ts"], + }), + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], baselineDependencies: true, @@ -309,113 +367,138 @@ X;`, verifyTscWatch({ scenario: "projectsWithReferences", subScenario: "on transitive references in different folders with no files clause", - sys: () => createSystemWithSolutionBuild( - ["c"], - [ - libFile, - { - path: getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), - content: JSON.stringify({ compilerOptions: { composite: true } }), - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), - content: JSON.stringify({ - compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, - references: [{ path: `../a` }] - }), - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), - content: JSON.stringify({ - compilerOptions: { baseUrl: "./", paths: { "@ref/*": ["../refs/*"] } }, - references: [{ path: `../b` }] - }), - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "a/index.ts"), - content: `export class A {}`, - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), - content: `import {A} from '@ref/a'; + sys: () => + createSystemWithSolutionBuild( + ["c"], + [ + libFile, + { + path: getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), + content: JSON.stringify({ compilerOptions: { composite: true } }), + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + content: JSON.stringify({ + compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, + references: [{ path: `../a` }], + }), + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + content: JSON.stringify({ + compilerOptions: { baseUrl: "./", paths: { "@ref/*": ["../refs/*"] } }, + references: [{ path: `../b` }], + }), + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "a/index.ts"), + content: `export class A {}`, + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), + content: `import {A} from '@ref/a'; export const b = new A();`, - }, - { - path: getTsBuildProjectFilePath("transitiveReferences", "c/index.ts"), - content: `import {b} from '../b'; + }, + { + path: getTsBuildProjectFilePath("transitiveReferences", "c/index.ts"), + content: `import {b} from '../b'; import {X} from "@ref/a"; b; X;`, - }, - getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"), - ], - { currentDirectory: `/user/username/projects/transitiveReferences` } - ), + }, + getTsBuildProjectFile("transitiveReferences", "refs/a.d.ts"), + ], + { currentDirectory: `/user/username/projects/transitiveReferences` }, + ), commandLineArgs: ["-w", "-p", "c", "--traceResolution", "--explainFiles"], edits: [ { caption: "non local edit b ts, and build b", edit: sys => { - sys.appendFile(getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), `export function gfoo() { }`); + sys.appendFile( + getTsBuildProjectFilePath("transitiveReferences", "b/index.ts"), + `export function gfoo() { }`, + ); const solutionBuilder = createSolutionBuilder(sys, ["b"]); solutionBuilder.build(); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "edit on config file", edit: sys => { sys.ensureFileOrFolder({ path: getTsBuildProjectFilePath("transitiveReferences", "nrefs/a.d.ts"), - content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))! + content: sys.readFile(getTsBuildProjectFilePath("transitiveReferences", "refs/a.d.ts"))!, }); - changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }); + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + { "@ref/*": ["../nrefs/*"] }, + ); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert config file edit", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), { "@ref/*": ["../refs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "c/tsconfig.json"), + { "@ref/*": ["../refs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "edit in referenced config file", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../nrefs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + { "@ref/*": ["../nrefs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert referenced config file edit", - edit: sys => changeCompilerOpitonsPaths(sys, getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), { "@ref/*": ["../refs/*"] }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + changeCompilerOpitonsPaths( + sys, + getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + { "@ref/*": ["../refs/*"] }, + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "deleting referenced config file", edit: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json")), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert deleting referenced config file", - edit: sys => sys.writeFile( - getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), - JSON.stringify({ - compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, - references: [{ path: `../a` }] - }) - ), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.writeFile( + getTsBuildProjectFilePath("transitiveReferences", "b/tsconfig.json"), + JSON.stringify({ + compilerOptions: { composite: true, baseUrl: "./", paths: { "@ref/*": ["../*"] } }, + references: [{ path: `../a` }], + }), + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "deleting transitively referenced config file", edit: sys => sys.deleteFile(getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json")), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Revert deleting transitively referenced config file", - edit: sys => sys.writeFile( - getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), - JSON.stringify({ compilerOptions: { composite: true } }), - ), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.writeFile( + getTsBuildProjectFilePath("transitiveReferences", "a/tsconfig.json"), + JSON.stringify({ compilerOptions: { composite: true } }), + ), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], baselineDependencies: true, @@ -424,31 +507,36 @@ X;`, verifyTscWatch({ scenario: "projectsWithReferences", subScenario: "when declarationMap changes for dependency", - sys: () => createSystemWithSolutionBuild( - ["core"], - [ - libFile, - getTsBuildProjectFile("sample1", "core/tsconfig.json"), - getTsBuildProjectFile("sample1", "core/index.ts"), - getTsBuildProjectFile("sample1", "core/anotherModule.ts"), - getTsBuildProjectFile("sample1", "core/some_decl.d.ts"), - getTsBuildProjectFile("sample1", "logic/tsconfig.json"), - getTsBuildProjectFile("sample1", "logic/index.ts"), - ], - { currentDirectory: `/user/username/projects/sample1` } - ), + sys: () => + createSystemWithSolutionBuild( + ["core"], + [ + libFile, + getTsBuildProjectFile("sample1", "core/tsconfig.json"), + getTsBuildProjectFile("sample1", "core/index.ts"), + getTsBuildProjectFile("sample1", "core/anotherModule.ts"), + getTsBuildProjectFile("sample1", "core/some_decl.d.ts"), + getTsBuildProjectFile("sample1", "logic/tsconfig.json"), + getTsBuildProjectFile("sample1", "logic/index.ts"), + ], + { currentDirectory: `/user/username/projects/sample1` }, + ), commandLineArgs: ["-w", "-p", "logic", "--traceResolution", "--explainFiles"], edits: [ { caption: "change declration map in core", edit: sys => { - sys.replaceFileText(getTsBuildProjectFilePath("sample1", "core/tsconfig.json"), `"declarationMap": true,`, `"declarationMap": false,`); + sys.replaceFileText( + getTsBuildProjectFilePath("sample1", "core/tsconfig.json"), + `"declarationMap": true,`, + `"declarationMap": false,`, + ); const solutionBuilder = createSolutionBuilder(sys, ["core"]); solutionBuilder.build(); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], - baselineDependencies: true + baselineDependencies: true, }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tscWatch/resolutionCache.ts b/src/testRunner/unittests/tscWatch/resolutionCache.ts index e40425630e63a..a95413585f136 100644 --- a/src/testRunner/unittests/tscWatch/resolutionCache.ts +++ b/src/testRunner/unittests/tscWatch/resolutionCache.ts @@ -1,6 +1,8 @@ import * as ts from "../../_namespaces/ts"; import * as Utils from "../../_namespaces/Utils"; -import { libContent } from "../helpers/contents"; +import { + libContent, +} from "../helpers/contents"; import { createBaseline, createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline, @@ -19,20 +21,22 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution it("caching works", () => { const root = { path: "/users/username/projects/project/d/f0.ts", - content: `import {x} from "f1"` + content: `import {x} from "f1"`, }; const imported = { path: "/users/username/projects/project/f1.ts", - content: `foo()` + content: `foo()`, }; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([root, imported, libFile])); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([root, imported, libFile]), + ); const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles: [root.path], system: sys, options: { module: ts.ModuleKind.AMD }, cb, - watchOptions: undefined + watchOptions: undefined, }); const originalFileExists = host.fileExists; const watch = ts.createWatchProgram(host); @@ -51,10 +55,13 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution edit: sys => { // patch fileExists to make sure that disk is not touched host.fileExists = ts.notImplemented; - sys.writeFile(root.path, `import {x} from "f1" - var x: string = 1;`); + sys.writeFile( + root.path, + `import {x} from "f1" + var x: string = 1;`, + ); }, - timeouts: sys => sys.runQueuedTimeoutCallbacks() + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Resolves f2", @@ -91,22 +98,22 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution timeouts: sys => { sys.runQueuedTimeoutCallbacks(); assert.isTrue(fileExistsIsCalled); - } + }, }, ], - watchOrSolution: watch + watchOrSolution: watch, }); }); it("loads missing files from disk", () => { const root = { path: `/users/username/projects/project/foo.ts`, - content: `import {x} from "bar"` + content: `import {x} from "bar"`, }; const imported = { path: `/users/username/projects/project/bar.d.ts`, - content: `export const y = 1;` + content: `export const y = 1;`, }; const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([root, libFile])); @@ -115,7 +122,7 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution system: sys, options: { module: ts.ModuleKind.AMD }, cb, - watchOptions: undefined + watchOptions: undefined, }); const originalFileExists = host.fileExists; let fileExistsCalledForBar = false; @@ -144,36 +151,38 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution caption: "write imported file", edit: sys => { fileExistsCalledForBar = false; - sys.writeFile(root.path,`import {y} from "bar"`); + sys.writeFile(root.path, `import {y} from "bar"`); sys.writeFile(imported.path, imported.content); }, timeouts: sys => { sys.runQueuedTimeoutCallbacks(); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); - } + }, }], - watchOrSolution: watch + watchOrSolution: watch, }); }); it("should compile correctly when resolved module goes missing and then comes back (module is not part of the root)", () => { const root = { path: `/users/username/projects/project/foo.ts`, - content: `import {x} from "bar"` + content: `import {x} from "bar"`, }; const imported = { path: `/users/username/projects/project/bar.d.ts`, - content: `export const y = 1;export const x = 10;` + content: `export const y = 1;export const x = 10;`, }; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([root, imported, libFile])); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([root, imported, libFile]), + ); const host = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ rootFiles: [root.path], system: sys, options: { module: ts.ModuleKind.AMD }, cb, - watchOptions: undefined + watchOptions: undefined, }); const originalFileExists = host.fileExists; let fileExistsCalledForBar = false; @@ -221,7 +230,7 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution }, }, ], - watchOrSolution: watch + watchOrSolution: watch, }); }); @@ -229,10 +238,11 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution scenario, subScenario: "works when module resolution changes to ambient module", commandLineArgs: ["-w", "/users/username/projects/project/foo.ts"], - sys: () => createWatchedSystem([{ - path: "/users/username/projects/project/foo.ts", - content: `import * as fs from "fs";` - }, libFile], { currentDirectory: "/users/username/projects/project" }), + sys: () => + createWatchedSystem([{ + path: "/users/username/projects/project/foo.ts", + content: `import * as fs from "fs";`, + }, libFile], { currentDirectory: "/users/username/projects/project" }), edits: [ { caption: "npm install node types", @@ -243,7 +253,7 @@ describe("unittests:: tsc-watch:: resolutionCache:: tsc-watch module resolution { "main": "" } -` +`, }); sys.ensureFileOrFolder({ path: "/users/username/projects/project/node_modules/@types/node/index.d.ts", @@ -252,25 +262,29 @@ declare module "fs" { export interface Stats { isFile(): boolean; } -}` +}`, }); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ scenario, subScenario: "works when included file with ambient module changes", - commandLineArgs: ["--w", "/users/username/projects/project/foo.ts", "/users/username/projects/project/bar.d.ts"], + commandLineArgs: [ + "--w", + "/users/username/projects/project/foo.ts", + "/users/username/projects/project/bar.d.ts", + ], sys: () => { const root = { path: "/users/username/projects/project/foo.ts", content: ` import * as fs from "fs"; import * as u from "url"; -` +`, }; const file = { @@ -281,23 +295,27 @@ declare module "url" { href?: string; } } -` +`, }; return createWatchedSystem([root, file, libFile], { currentDirectory: "/users/username/projects/project" }); }, edits: [ { caption: "Add fs definition", - edit: sys => sys.appendFile("/users/username/projects/project/bar.d.ts", ` + edit: sys => + sys.appendFile( + "/users/username/projects/project/bar.d.ts", + ` declare module "fs" { export interface Stats { isFile(): boolean; } } -`), +`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -308,15 +326,15 @@ declare module "fs" { const configDir = "/a/b/projects/myProject/src/"; const file1: File = { path: configDir + "file1.ts", - content: 'import module1 = require("module1");\nmodule1("hello");' + content: 'import module1 = require("module1");\nmodule1("hello");', }; const file2: File = { path: configDir + "file2.ts", - content: 'import module11 = require("module1");\nmodule11("hello");' + content: 'import module11 = require("module1");\nmodule11("hello");', }; const module1: File = { path: "/a/b/projects/myProject/node_modules/module1/index.js", - content: "module.exports = options => { return options.toString(); }" + content: "module.exports = options => { return options.toString(); }", }; const configFile: File = { path: configDir + "tsconfig.json", @@ -326,19 +344,21 @@ declare module "fs" { rootDir: ".", outDir: "../dist", moduleResolution: "node", - maxNodeModuleJsDepth: 1 - } - }) + maxNodeModuleJsDepth: 1, + }, + }), }; - return createWatchedSystem([file1, file2, module1, libFile, configFile], { currentDirectory: "/a/b/projects/myProject/" }); + return createWatchedSystem([file1, file2, module1, libFile, configFile], { + currentDirectory: "/a/b/projects/myProject/", + }); }, edits: [ { caption: "Add new line to file1", edit: sys => sys.appendFile("/a/b/projects/myProject/src/file1.ts", "\n;"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); verifyTscWatch({ @@ -348,21 +368,27 @@ declare module "fs" { sys: () => { const file: File = { path: `/user/username/projects/myproject/a.ts`, - content: `import * as q from "qqq";` + content: `import * as q from "qqq";`, }; const module: File = { path: `/user/username/projects/myproject/node_modules2/@types/qqq/index.d.ts`, - content: "export {}" + content: "export {}", }; - return createWatchedSystem([file, libFile, module], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([file, libFile, module], { + currentDirectory: "/user/username/projects/myproject", + }); }, edits: [ { caption: "npm install", - edit: sys => sys.renameFolder(`/user/username/projects/myproject/node_modules2`, `/user/username/projects/myproject/node_modules`), + edit: sys => + sys.renameFolder( + `/user/username/projects/myproject/node_modules2`, + `/user/username/projects/myproject/node_modules`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); describe("ignores files/folder changes in node_modules that start with '.'", () => { @@ -374,28 +400,30 @@ declare module "fs" { sys: () => { const file1: File = { path: `/user/username/projects/myproject/test.ts`, - content: `import { x } from "somemodule";` + content: `import { x } from "somemodule";`, }; const file2: File = { path: `/user/username/projects/myproject/node_modules/somemodule/index.d.ts`, - content: `export const x = 10;` + content: `export const x = 10;`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; return createWatchedSystem([libFile, file1, file2, config]); }, edits: [ { caption: "npm install file and folder that start with '.'", - edit: sys => sys.ensureFileOrFolder({ - path: `/user/username/projects/myproject/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`, - content: JSON.stringify({ something: 10 }) - }), + edit: sys => + sys.ensureFileOrFolder({ + path: + `/user/username/projects/myproject/node_modules/.cache/babel-loader/89c02171edab901b9926470ba6d5677e.ts`, + content: JSON.stringify({ something: 10 }), + }), timeouts: sys => sys.logTimeoutQueueLength(), - } - ] + }, + ], }); } verifyIgnore("watch without configFile", ["--w", `/user/username/projects/myproject/test.ts`]); @@ -409,16 +437,16 @@ declare module "fs" { sys: () => { const app: File = { path: `/user/username/projects/myproject/lib/app.ts`, - content: `myapp.component("hello");` + content: `myapp.component("hello");`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "none", - types: ["@myapp/ts-types"] - } - }) + types: ["@myapp/ts-types"], + }, + }), }; return createWatchedSystem([app, tsconfig, libFile]); }, @@ -430,15 +458,16 @@ declare module "fs" { path: `/user/username/projects/myproject/node_modules/@myapp/ts-types/package.json`, content: JSON.stringify({ version: "1.65.1", - types: "types/somefile.define.d.ts" - }) + types: "types/somefile.define.d.ts", + }), }); sys.ensureFileOrFolder({ - path: `/user/username/projects/myproject/node_modules/@myapp/ts-types/types/somefile.define.d.ts`, + path: + `/user/username/projects/myproject/node_modules/@myapp/ts-types/types/somefile.define.d.ts`, content: ` declare namespace myapp { function component(str: string): number; -}` +}`, }); }, timeouts: sys => { @@ -451,12 +480,14 @@ declare namespace myapp { edit: ts.noop, timeouts: (sys, [[oldProgram, oldBuilderProgram]], watchorSolution) => { sys.logTimeoutQueueLength(); - const newProgram = (watchorSolution as ts.WatchOfConfigFile).getProgram(); + const newProgram = + (watchorSolution as ts.WatchOfConfigFile) + .getProgram(); assert.strictEqual(newProgram, oldBuilderProgram, "No change so builder program should be same"); assert.strictEqual(newProgram.getProgram(), oldProgram, "No change so program should be same"); - } - } - ] + }, + }, + ], }); verifyTscWatch({ @@ -468,32 +499,45 @@ declare namespace myapp { const linkedPackageRoot = `/user/username/projects/myproject/linked-package`; const mainFile: File = { path: `${mainPackageRoot}/index.ts`, - content: "import { Foo } from '@scoped/linked-package'" + content: "import { Foo } from '@scoped/linked-package'", }; const config: File = { path: `${mainPackageRoot}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "commonjs", moduleResolution: "node", baseUrl: ".", rootDir: "." }, - files: ["index.ts"] - }) + files: ["index.ts"], + }), }; const linkedPackageInMain: SymLink = { path: `${mainPackageRoot}/node_modules/@scoped/linked-package`, - symLink: `${linkedPackageRoot}` + symLink: `${linkedPackageRoot}`, }; const linkedPackageJson: File = { path: `${linkedPackageRoot}/package.json`, - content: JSON.stringify({ name: "@scoped/linked-package", version: "0.0.1", types: "dist/index.d.ts", main: "dist/index.js" }) + content: JSON.stringify({ + name: "@scoped/linked-package", + version: "0.0.1", + types: "dist/index.d.ts", + main: "dist/index.js", + }), }; const linkedPackageIndex: File = { path: `${linkedPackageRoot}/dist/index.d.ts`, - content: "export * from './other';" + content: "export * from './other';", }; const linkedPackageOther: File = { path: `${linkedPackageRoot}/dist/other.d.ts`, - content: 'export declare const Foo = "BAR";' + content: 'export declare const Foo = "BAR";', }; - const files = [libFile, mainFile, config, linkedPackageInMain, linkedPackageJson, linkedPackageIndex, linkedPackageOther]; + const files = [ + libFile, + mainFile, + config, + linkedPackageInMain, + linkedPackageJson, + linkedPackageIndex, + linkedPackageOther, + ]; return createWatchedSystem(files, { currentDirectory: mainPackageRoot }); }, }); @@ -502,16 +546,16 @@ declare namespace myapp { function getNodeAtTypes() { const nodeAtTypesIndex: File = { path: `/user/username/projects/myproject/node_modules/@types/node/index.d.ts`, - content: `/// ` + content: `/// `, }; const nodeAtTypesBase: File = { path: `/user/username/projects/myproject/node_modules/@types/node/base.d.ts`, content: `// Base definitions for all NodeJS modules that are not specific to any version of TypeScript: -/// ` +/// `, }; const nodeAtTypes36Base: File = { path: `/user/username/projects/myproject/node_modules/@types/node/ts3.6/base.d.ts`, - content: `/// ` + content: `/// `, }; const nodeAtTypesGlobals: File = { path: `/user/username/projects/myproject/node_modules/@types/node/globals.d.ts`, @@ -520,49 +564,63 @@ declare namespace NodeJS { interface Process { on(msg: string): void; } -}` +}`, }; return { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals }; } verifyTscWatch({ scenario, - subScenario: "works when installing something in node_modules or @types when there is no notification from fs for index file", + subScenario: + "works when installing something in node_modules or @types when there is no notification from fs for index file", commandLineArgs: ["--w", `--extendedDiagnostics`], sys: () => { const file: File = { path: `/user/username/projects/myproject/worker.ts`, - content: `process.on("uncaughtException");` + content: `process.on("uncaughtException");`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals } = getNodeAtTypes(); - return createWatchedSystem([file, libFile, tsconfig, nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals], { currentDirectory: "/user/username/projects/myproject" }); + return createWatchedSystem([ + file, + libFile, + tsconfig, + nodeAtTypesIndex, + nodeAtTypesBase, + nodeAtTypes36Base, + nodeAtTypesGlobals, + ], { currentDirectory: "/user/username/projects/myproject" }); }, edits: [ { caption: "npm ci step one: remove all node_modules files", - edit: sys => sys.deleteFolder(`/user/username/projects/myproject/node_modules/@types`, /*recursive*/ true), + edit: sys => + sys.deleteFolder(`/user/username/projects/myproject/node_modules/@types`, /*recursive*/ true), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: `npm ci step two: create atTypes but something else in the @types folder`, - edit: sys => sys.ensureFileOrFolder({ - path: `/user/username/projects/myproject/node_modules/@types/mocha/index.d.ts`, - content: `export const foo = 10;` - }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/node_modules/@types/mocha/index.d.ts`, + content: `export const foo = 10;`, + }), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: `npm ci step three: create atTypes node folder`, - edit: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/node_modules/@types/node` }), - timeouts: sys => sys.runQueuedTimeoutCallbacks() + edit: sys => + sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/node_modules/@types/node` }), + timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { - caption: `npm ci step four: create atTypes write all the files but dont invoke watcher for index.d.ts`, + caption: + `npm ci step four: create atTypes write all the files but dont invoke watcher for index.d.ts`, edit: sys => { - const { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals } = getNodeAtTypes(); + const { nodeAtTypesIndex, nodeAtTypesBase, nodeAtTypes36Base, nodeAtTypesGlobals } = + getNodeAtTypes(); sys.ensureFileOrFolder(nodeAtTypesBase); sys.ensureFileOrFolder(nodeAtTypesIndex, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true); sys.ensureFileOrFolder(nodeAtTypes36Base, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true); @@ -573,75 +631,86 @@ declare namespace NodeJS { sys.runQueuedTimeoutCallbacks(); // actual program update }, }, - ] + ], }); }); verifyTscWatch({ scenario, subScenario: "reusing type ref resolution", - sys: () => createWatchedSystem({ - "/users/username/projects/project/tsconfig.json": JSON.stringify({ - compilerOptions: { - composite: true, - traceResolution: true, - outDir: "outDir", - }, - }), - "/users/username/projects/project/fileWithImports.ts": Utils.dedent` + sys: () => + createWatchedSystem({ + "/users/username/projects/project/tsconfig.json": JSON.stringify({ + compilerOptions: { + composite: true, + traceResolution: true, + outDir: "outDir", + }, + }), + "/users/username/projects/project/fileWithImports.ts": Utils.dedent` import type { Import0 } from "pkg0"; import type { Import1 } from "pkg1"; `, - "/users/username/projects/project/node_modules/pkg0/index.d.ts": `export interface Import0 {}`, - "/users/username/projects/project/fileWithTypeRefs.ts": Utils.dedent` + "/users/username/projects/project/node_modules/pkg0/index.d.ts": `export interface Import0 {}`, + "/users/username/projects/project/fileWithTypeRefs.ts": Utils.dedent` /// /// interface LocalInterface extends Import2, Import3 {} export {} `, - "/users/username/projects/project/node_modules/pkg2/index.d.ts": `interface Import2 {}`, - [libFile.path]: libFile.content, - }, { currentDirectory: "/users/username/projects/project" }), + "/users/username/projects/project/node_modules/pkg2/index.d.ts": `interface Import2 {}`, + [libFile.path]: libFile.content, + }, { currentDirectory: "/users/username/projects/project" }), commandLineArgs: ["-w", "--explainFiles", "--extendedDiagnostics"], edits: [ { caption: "write file not resolved by import", - edit: sys => sys.ensureFileOrFolder({ path: "/users/username/projects/project/node_modules/pkg1/index.d.ts", content: `export interface Import1 {}` }), + edit: sys => + sys.ensureFileOrFolder({ + path: "/users/username/projects/project/node_modules/pkg1/index.d.ts", + content: `export interface Import1 {}`, + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // failed lookup sys.runQueuedTimeoutCallbacks(); // actual update - } + }, }, { caption: "write file not resolved by typeRef", - edit: sys => sys.ensureFileOrFolder({ path: "/users/username/projects/project/node_modules/pkg3/index.d.ts", content: `export interface Import3 {}` }), + edit: sys => + sys.ensureFileOrFolder({ + path: "/users/username/projects/project/node_modules/pkg3/index.d.ts", + content: `export interface Import3 {}`, + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); // failed lookup sys.runQueuedTimeoutCallbacks(); // actual update - } + }, }, - ] + ], }); verifyTscWatch({ scenario, subScenario: "scoped package installation", commandLineArgs: ["--w", "-p", `.`, "--traceResolution", "--extendedDiagnostics"], - sys: () => createWatchedSystem({ - "/user/username/projects/myproject/lib/app.ts": Utils.dedent` + sys: () => + createWatchedSystem({ + "/user/username/projects/myproject/lib/app.ts": Utils.dedent` import { myapp } from "@myapp/ts-types"; const x: 10 = myapp; `, - "/user/username/projects/myproject/tsconfig.json": "{}", - [libFile.path]: libContent, - }, { currentDirectory: "/user/username/projects/myproject" }), + "/user/username/projects/myproject/tsconfig.json": "{}", + [libFile.path]: libContent, + }, { currentDirectory: "/user/username/projects/myproject" }), edits: [ { caption: "npm install unrelated non scoped", - edit: sys => sys.ensureFileOrFolder({ - path: `/user/username/projects/myproject/node_modules/unrelated/index.d.ts`, - content: `export const unrelated = 10;` - }), + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/node_modules/unrelated/index.d.ts`, + content: `export const unrelated = 10;`, + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -649,10 +718,11 @@ declare namespace NodeJS { }, { caption: "npm install unrelated scoped in myapp", - edit: sys => sys.ensureFileOrFolder({ - path: `/user/username/projects/myproject/node_modules/@myapp/unrelated/index.d.ts`, - content: `export const myappUnrelated = 10;` - }), + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/node_modules/@myapp/unrelated/index.d.ts`, + content: `export const myappUnrelated = 10;`, + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -660,10 +730,11 @@ declare namespace NodeJS { }, { caption: "npm install unrelated2 scoped in myapp", - edit: sys => sys.ensureFileOrFolder({ - path: `/user/username/projects/myproject/node_modules/@myapp/unrelated2/index.d.ts`, - content: `export const myappUnrelated2 = 10;` - }), + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/node_modules/@myapp/unrelated2/index.d.ts`, + content: `export const myappUnrelated2 = 10;`, + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); @@ -671,15 +742,16 @@ declare namespace NodeJS { }, { caption: "npm install ts-types", - edit: sys => sys.ensureFileOrFolder({ - path: `/user/username/projects/myproject/node_modules/@myapp/ts-types/index.d.ts`, - content: `export const myapp = 10;` - }), + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/node_modules/@myapp/ts-types/index.d.ts`, + content: `export const myapp = 10;`, + }), timeouts: sys => { sys.runQueuedTimeoutCallbacks(); sys.runQueuedTimeoutCallbacks(); }, }, - ] + ], }); }); diff --git a/src/testRunner/unittests/tscWatch/resolveJsonModuleWithIncremental.ts b/src/testRunner/unittests/tscWatch/resolveJsonModuleWithIncremental.ts index e4a1d09ac2019..d0d5b9c2aa09d 100644 --- a/src/testRunner/unittests/tscWatch/resolveJsonModuleWithIncremental.ts +++ b/src/testRunner/unittests/tscWatch/resolveJsonModuleWithIncremental.ts @@ -10,18 +10,23 @@ describe("unittests:: tsc-watch:: resolveJsonModuleWithIncremental:: emit file - verifyTscWatch({ scenario: "resolveJsonModule", subScenario: "incremental always prefers declaration file over document", - sys: () => createWatchedSystem({ - "/src/project/main.ts": `import data from "./data.json"; let x: string = data;`, - "/src/project/data.json": `{}`, // this file intentionally left blank - "/src/project/data.d.json.ts": `declare var val: string; export default val;`, - "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { resolveJsonModule: true } }, null, 4), // eslint-disable-line no-null/no-null - [libFile.path]: libFile.content, - }), + sys: () => + createWatchedSystem({ + "/src/project/main.ts": `import data from "./data.json"; let x: string = data;`, + "/src/project/data.json": `{}`, // this file intentionally left blank + "/src/project/data.d.json.ts": `declare var val: string; export default val;`, + "/src/project/tsconfig.json": JSON.stringify({ compilerOptions: { resolveJsonModule: true } }, null, 4), // eslint-disable-line no-null/no-null + [libFile.path]: libFile.content, + }), commandLineArgs: ["--p", "src/project", "-i", "-w"], edits: [{ caption: "Change json setting", - edit: sys => sys.writeFile("/src/project/tsconfig.json", JSON.stringify({ compilerOptions: { resolveJsonModule: false } }, null, 4)), // eslint-disable-line no-null/no-null + edit: sys => + sys.writeFile( + "/src/project/tsconfig.json", + JSON.stringify({ compilerOptions: { resolveJsonModule: false } }, null, 4), + ), // eslint-disable-line no-null/no-null timeouts: sys => sys.runQueuedTimeoutCallbacks(), - }] + }], }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts b/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts index e8f6810564ca4..15caef25c48a6 100644 --- a/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts +++ b/src/testRunner/unittests/tscWatch/sourceOfProjectReferenceRedirect.ts @@ -1,6 +1,10 @@ import * as ts from "../../_namespaces/ts"; -import { libContent } from "../helpers/contents"; -import { solutionBuildWithBaseline } from "../helpers/solutionBuilder"; +import { + libContent, +} from "../helpers/contents"; +import { + solutionBuildWithBaseline, +} from "../helpers/solutionBuilder"; import { createBaseline, createWatchCompilerHostOfConfigFileForBaseline, @@ -28,7 +32,7 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire alreadyBuilt ? (sys, originalRead) => { solutionBuildWithBaseline(sys, [config], originalRead); sys.clearOutput(); - } : undefined + } : undefined, ); const host = createWatchCompilerHostOfConfigFileForBaseline({ configFileName: config, @@ -45,7 +49,7 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire baseline, oldSnap, getPrograms, - watchOrSolution: watch + watchOrSolution: watch, }); } @@ -69,9 +73,18 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire const indexTs = getTsBuildProjectFile("demo", "animals/index.ts"); const animalsConfig = getTsBuildProjectFile("demo", "animals/tsconfig.json"); return { - files: [{ path: libFile.path, content: libContent }, baseConfig, coreTs, coreConfig, animalTs, dogTs, indexTs, animalsConfig], + files: [ + { path: libFile.path, content: libContent }, + baseConfig, + coreTs, + coreConfig, + animalTs, + dogTs, + indexTs, + animalsConfig, + ], config: animalsConfig.path, - subScenario: "with simple project" + subScenario: "with simple project", }; }); }); @@ -102,7 +115,7 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire return { files: [libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink], config: aConfig.path, - subScenario: `${subScenario}${extraOptions.preserveSymlinks ? " with preserveSymlinks" : ""}` + subScenario: `${subScenario}${extraOptions.preserveSymlinks ? " with preserveSymlinks" : ""}`, }; }); } @@ -115,18 +128,18 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire outDir: "lib", rootDir: "src", composite: true, - ...extraOptions + ...extraOptions, }, include: ["src"], - ...(references ? { references: references.map(path => ({ path })) } : {}) - }) + ...(references ? { references: references.map(path => ({ path })) } : {}), + }), }; } function file(packageName: string, fileName: string, content: string): File { return { path: `/user/username/projects/myproject/packages/${packageName}/src/${fileName}`, - content + content, }; } @@ -137,21 +150,25 @@ describe("unittests:: tsc-watch:: watchAPI:: with sourceOfProjectReferenceRedire path: `/user/username/projects/myproject/packages/B/package.json`, content: JSON.stringify({ main: "lib/index.js", - types: "lib/index.d.ts" - }) + types: "lib/index.d.ts", + }), }, - aTest: file("A", "index.ts", `import { foo } from '${scope}b'; + aTest: file( + "A", + "index.ts", + `import { foo } from '${scope}b'; import { bar } from '${scope}b/lib/bar'; foo(); bar(); -`), +`, + ), bFoo: file("B", "index.ts", `export function foo() { }`), bBar: file("B", "bar.ts", `export function bar() { }`), bSymlink: { path: `/user/username/projects/myproject/node_modules/${scope}b`, - symLink: `/user/username/projects/myproject/packages/B` + symLink: `/user/username/projects/myproject/packages/B`, }, - subScenario: `when packageJson has types field${scope ? " with scoped package" : ""}` + subScenario: `when packageJson has types field${scope ? " with scoped package" : ""}`, })); }); @@ -159,20 +176,24 @@ bar(); verifySymlinkScenario(() => ({ bPackageJson: { path: `/user/username/projects/myproject/packages/B/package.json`, - content: "{}" + content: "{}", }, - aTest: file("A", "test.ts", `import { foo } from '${scope}b/lib/foo'; + aTest: file( + "A", + "test.ts", + `import { foo } from '${scope}b/lib/foo'; import { bar } from '${scope}b/lib/bar/foo'; foo(); bar(); -`), +`, + ), bFoo: file("B", "foo.ts", `export function foo() { }`), bBar: file("B", "bar/foo.ts", `export function bar() { }`), bSymlink: { path: `/user/username/projects/myproject/node_modules/${scope}b`, - symLink: `/user/username/projects/myproject/packages/B` + symLink: `/user/username/projects/myproject/packages/B`, }, - subScenario: `when referencing file from subFolder${scope ? " with scoped package" : ""}` + subScenario: `when referencing file from subFolder${scope ? " with scoped package" : ""}`, })); }); } diff --git a/src/testRunner/unittests/tscWatch/watchApi.ts b/src/testRunner/unittests/tscWatch/watchApi.ts index 81274cbbf1932..b927f278d5a0f 100644 --- a/src/testRunner/unittests/tscWatch/watchApi.ts +++ b/src/testRunner/unittests/tscWatch/watchApi.ts @@ -1,8 +1,14 @@ import * as Harness from "../../_namespaces/Harness"; import * as ts from "../../_namespaces/ts"; -import { dedent } from "../../_namespaces/Utils"; -import { commandLineCallbacks } from "../helpers/baseline"; -import { libContent } from "../helpers/contents"; +import { + dedent, +} from "../../_namespaces/Utils"; +import { + commandLineCallbacks, +} from "../helpers/baseline"; +import { + libContent, +} from "../helpers/contents"; import { applyEdit, createBaseline, @@ -22,39 +28,40 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu it("verify that module resolution with json extension works when returned without extension", () => { const configFileJson: any = { compilerOptions: { module: "commonjs", resolveJsonModule: true }, - files: ["index.ts"] + files: ["index.ts"], }; const mainFile: File = { path: `/user/username/projects/myproject/index.ts`, - content: "import settings from './settings.json';" + content: "import settings from './settings.json';", }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify(configFileJson) + content: JSON.stringify(configFileJson), }; const settingsJson: File = { path: `/user/username/projects/myproject/settings.json`, - content: JSON.stringify({ content: "Print this" }) + content: JSON.stringify({ content: "Print this" }), }; const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem( [libFile, mainFile, config, settingsJson], - { currentDirectory: "/user/username/projects/myproject" }), - ); + { currentDirectory: "/user/username/projects/myproject" }, + )); const host = createWatchCompilerHostOfConfigFileForBaseline({ configFileName: config.path, system: sys, cb, }); const parsedCommandResult = ts.parseJsonConfigFileContent(configFileJson, sys, config.path); - host.resolveModuleNames = (moduleNames, containingFile) => moduleNames.map(m => { - const result = ts.resolveModuleName(m, containingFile, parsedCommandResult.options, host); - const resolvedModule = result.resolvedModule!; - return { - resolvedFileName: resolvedModule.resolvedFileName, - isExternalLibraryImport: resolvedModule.isExternalLibraryImport, - originalFileName: resolvedModule.originalPath, - }; - }); + host.resolveModuleNames = (moduleNames, containingFile) => + moduleNames.map(m => { + const result = ts.resolveModuleName(m, containingFile, parsedCommandResult.options, host); + const resolvedModule = result.resolvedModule!; + return { + resolvedFileName: resolvedModule.resolvedFileName, + isExternalLibraryImport: resolvedModule.isExternalLibraryImport, + originalFileName: resolvedModule.originalPath, + }; + }); const watch = ts.createWatchProgram(host); runWatchBaseline({ scenario: "watchApi", @@ -64,7 +71,7 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu baseline, oldSnap, getPrograms, - watchOrSolution: watch + watchOrSolution: watch, }); }); @@ -74,7 +81,7 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem({ [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ compilerOptions: { traceResolution: true, extendedDiagnostics: true }, - files: ["main.ts"] + files: ["main.ts"], }), [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./other";`, [`/user/username/projects/myproject/other.d.ts`]: "export function foo(): void;", @@ -88,7 +95,9 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu host.resolveModuleNames = (moduleNames, containingFile, _reusedNames, _redirectedReference, options) => moduleNames.map(m => ts.resolveModuleName(m, containingFile, options, host).resolvedModule); // Invalidate resolutions only when ts file is created - if (implementHasInvalidatedResolution) host.hasInvalidatedResolutions = () => sys.fileExists(`/user/username/projects/myproject/other.ts`); + if (implementHasInvalidatedResolution) { + host.hasInvalidatedResolutions = () => sys.fileExists(`/user/username/projects/myproject/other.ts`); + } const watch = ts.createWatchProgram(host); runWatchBaseline({ scenario: "watchApi", @@ -106,7 +115,11 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu }, { caption: "change other file", - edit: sys => sys.appendFile(`/user/username/projects/myproject/other.d.ts`, "export function bar(): void;"), + edit: sys => + sys.appendFile( + `/user/username/projects/myproject/other.d.ts`, + "export function bar(): void;", + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { @@ -118,11 +131,14 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolu timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], - watchOrSolution: watch + watchOrSolution: watch, }); }); } - verifyWatch("host implements does not implement hasInvalidatedResolutions", /*implementHasInvalidatedResolution*/ false); + verifyWatch( + "host implements does not implement hasInvalidatedResolutions", + /*implementHasInvalidatedResolution*/ false, + ); verifyWatch("host implements hasInvalidatedResolutions", /*implementHasInvalidatedResolution*/ true); }); }); @@ -133,17 +149,17 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch expose error count to wat path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "commonjs" }, - files: ["index.ts"] - }) + files: ["index.ts"], + }), }; const mainFile: File = { path: `/user/username/projects/myproject/index.ts`, - content: "let compiler = new Compiler(); for (let i = 0; j < 5; i++) {}" + content: "let compiler = new Compiler(); for (let i = 0; j < 5; i++) {}", }; const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem( [libFile, mainFile, config], - { currentDirectory: "/user/username/projects/myproject" }), - ); + { currentDirectory: "/user/username/projects/myproject" }, + )); const host = createWatchCompilerHostOfConfigFileForBaseline({ configFileName: config.path, system: sys, @@ -165,7 +181,7 @@ describe("unittests:: tsc-watch:: watchAPI:: tsc-watch expose error count to wat baseline, oldSnap, getPrograms, - watchOrSolution: watch + watchOrSolution: watch, }); }); }); @@ -174,13 +190,15 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost does not implement s it("verifies that getProgram gets updated program if new file is added to the program", () => { const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const mainFile: File = { path: `/user/username/projects/myproject/main.ts`, - content: "const x = 10;" + content: "const x = 10;", }; - const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem([config, mainFile, libFile])); + const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( + createWatchedSystem([config, mainFile, libFile]), + ); const host = createWatchCompilerHostOfConfigFileForBaseline({ configFileName: config.path, system: sys, @@ -203,9 +221,9 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost does not implement s timeouts: sys => { sys.logTimeoutQueueLength(); watch.getProgram(); - } + }, }], - watchOrSolution: watch + watchOrSolution: watch, }); }); }); @@ -214,18 +232,18 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost can add extraFileExt it("verifies that extraFileExtensions are supported to get the program with other extensions", () => { const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const mainFile: File = { path: `/user/username/projects/myproject/main.ts`, - content: "const x = 10;" + content: "const x = 10;", }; const otherFile: File = { path: `/user/username/projects/myproject/other.vue`, - content: "" + content: "", }; const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline( - createWatchedSystem([config, mainFile, otherFile, libFile]) + createWatchedSystem([config, mainFile, otherFile, libFile]), ); const host = createWatchCompilerHostOfConfigFileForBaseline({ configFileName: config.path, @@ -248,7 +266,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost can add extraFileExt edit: sys => sys.writeFile(`/user/username/projects/myproject/other2.vue`, otherFile.content), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }], - watchOrSolution: watch + watchOrSolution: watch, }); }); }); @@ -257,15 +275,15 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD function createSystem(configText: string, mainText: string) { const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: configText + content: configText, }; const mainFile: File = { path: `/user/username/projects/myproject/main.ts`, - content: mainText + content: mainText, }; const otherFile: File = { path: `/user/username/projects/myproject/other.ts`, - content: "export const y = 10;" + content: "export const y = 10;", }; return { ...createBaseline(createWatchedSystem([config, mainFile, otherFile, libFile])), @@ -305,8 +323,18 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD function verifyOutputs(baseline: string[], sys: ts.System, emitSys: ts.System) { baseline.push("Checking if output is same as EmitAndSemanticDiagnosticsBuilderProgram::"); - for (const output of [`/user/username/projects/myproject/main.js`, `/user/username/projects/myproject/main.d.ts`, `/user/username/projects/myproject/other.js`, `/user/username/projects/myproject/other.d.ts`, `/user/username/projects/myproject/tsconfig.tsbuildinfo`]) { - baseline.push(`Output file text for ${output} is same:: ${sys.readFile(output) === emitSys.readFile(output)}`); + for ( + const output of [ + `/user/username/projects/myproject/main.js`, + `/user/username/projects/myproject/main.d.ts`, + `/user/username/projects/myproject/other.js`, + `/user/username/projects/myproject/other.d.ts`, + `/user/username/projects/myproject/tsconfig.tsbuildinfo`, + ] + ) { + baseline.push( + `Output file text for ${output} is same:: ${sys.readFile(output) === emitSys.readFile(output)}`, + ); } baseline.push(""); } @@ -323,7 +351,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD sys: TscWatchSystem, emitSys: TscWatchSystem, change: (sys: TscWatchSystem) => void, - caption: string + caption: string, ) { // Change file applyEdit(sys, baseline, change, caption); @@ -337,14 +365,18 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD sys: TscWatchSystem, emitSys: TscWatchSystem, createProgram: ts.CreateProgram, - optionsToExtend?: ts.CompilerOptions) { + optionsToExtend?: ts.CompilerOptions, + ) { createWatch(baseline, config, sys, createProgram, optionsToExtend); createWatch(emitBaseline, config, emitSys, ts.createEmitAndSemanticDiagnosticsBuilderProgram, optionsToExtend); verifyOutputs(baseline, sys, emitSys); } it("verifies that noEmit is handled on createSemanticDiagnosticsBuilderProgram and typechecking happens only on affected files", () => { - const { sys, baseline, oldSnap, cb, getPrograms, config, mainFile } = createSystem("{}", "export const x = 10;"); + const { sys, baseline, oldSnap, cb, getPrograms, config, mainFile } = createSystem( + "{}", + "export const x = 10;", + ); const host = createWatchCompilerHostOfConfigFileForBaseline({ configFileName: config.path, optionsToExtend: { noEmit: true }, @@ -366,7 +398,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD edit: sys => sys.appendFile(mainFile.path, "\n// SomeComment"), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }], - watchOrSolution: watch + watchOrSolution: watch, }); }); @@ -382,22 +414,60 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD const { sys, config, mainFile, emitSys } = result; // No Emit - verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createEmitAndSemanticDiagnosticsBuilderProgram, { noEmit: true }); + verifyBuilder( + baseline, + emitBaseline, + config, + sys, + emitSys, + ts.createEmitAndSemanticDiagnosticsBuilderProgram, + { noEmit: true }, + ); // Emit on both sys should result in same output - verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createEmitAndSemanticDiagnosticsBuilderProgram); + verifyBuilder( + baseline, + emitBaseline, + config, + sys, + emitSys, + ts.createEmitAndSemanticDiagnosticsBuilderProgram, + ); // Change file - applyChangeForBuilderTest(baseline, emitBaseline, sys, emitSys, sys => sys.appendFile(mainFile.path, "\n// SomeComment"), "Add comment"); + applyChangeForBuilderTest( + baseline, + emitBaseline, + sys, + emitSys, + sys => sys.appendFile(mainFile.path, "\n// SomeComment"), + "Add comment", + ); // Verify noEmit results in same output - verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createSemanticDiagnosticsBuilderProgram, { noEmit: true }); + verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createSemanticDiagnosticsBuilderProgram, { + noEmit: true, + }); // Emit on both sys should result in same output - verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createEmitAndSemanticDiagnosticsBuilderProgram); + verifyBuilder( + baseline, + emitBaseline, + config, + sys, + emitSys, + ts.createEmitAndSemanticDiagnosticsBuilderProgram, + ); // Change file - applyChangeForBuilderTest(baseline, emitBaseline, sys, emitSys, sys => sys.appendFile(mainFile.path, "\n// SomeComment"), "Add comment"); + applyChangeForBuilderTest( + baseline, + emitBaseline, + sys, + emitSys, + sys => sys.appendFile(mainFile.path, "\n// SomeComment"), + "Add comment", + ); // Emit on both the builders should result in same files verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createSemanticDiagnosticsBuilderProgram); @@ -407,10 +477,16 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD emitBaseline = undefined!; }); it("noEmit with composite writes the tsbuildinfo with pending affected files correctly", () => { - Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmit-with-composite-with-semantic-builder.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/watchApi/noEmit-with-composite-with-semantic-builder.js`, + baseline.join("\r\n"), + ); }); it("baseline in createEmitAndSemanticDiagnosticsBuilderProgram:: noEmit with composite writes the tsbuildinfo with pending affected files correctly", () => { - Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmit-with-composite-with-emit-builder.js`, emitBaseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/watchApi/noEmit-with-composite-with-emit-builder.js`, + emitBaseline.join("\r\n"), + ); }); }); @@ -429,30 +505,53 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createSemanticDiagnosticsBuilderProgram); // Change file - applyChangeForBuilderTest(baseline, emitBaseline, sys, emitSys, sys => sys.appendFile(mainFile.path, "\n// SomeComment"), "Add comment"); + applyChangeForBuilderTest( + baseline, + emitBaseline, + sys, + emitSys, + sys => sys.appendFile(mainFile.path, "\n// SomeComment"), + "Add comment", + ); // Verify noEmit results in same output verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createSemanticDiagnosticsBuilderProgram); // Fix error const fixed = "export const x = 10;"; - applyChangeForBuilderTest(baseline, emitBaseline, sys, emitSys, sys => sys.writeFile(mainFile.path, fixed), "Fix error"); + applyChangeForBuilderTest( + baseline, + emitBaseline, + sys, + emitSys, + sys => sys.writeFile(mainFile.path, fixed), + "Fix error", + ); // Emit on both the builders should result in same files verifyBuilder(baseline, emitBaseline, config, sys, emitSys, ts.createSemanticDiagnosticsBuilderProgram); }); it("noEmitOnError with composite writes the tsbuildinfo with pending affected files correctly", () => { - Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmitOnError-with-composite-with-semantic-builder.js`, baseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/watchApi/noEmitOnError-with-composite-with-semantic-builder.js`, + baseline.join("\r\n"), + ); }); it("baseline in createEmitAndSemanticDiagnosticsBuilderProgram:: noEmitOnError with composite writes the tsbuildinfo with pending affected files correctly", () => { - Harness.Baseline.runBaseline(`tscWatch/watchApi/noEmitOnError-with-composite-with-emit-builder.js`, emitBaseline.join("\r\n")); + Harness.Baseline.runBaseline( + `tscWatch/watchApi/noEmitOnError-with-composite-with-emit-builder.js`, + emitBaseline.join("\r\n"), + ); }); }); it("SemanticDiagnosticsBuilderProgram emitDtsOnly does not update affected files pending emit", () => { // Initial - const { sys, baseline, config, mainFile } = createSystem(JSON.stringify({ compilerOptions: { composite: true, noEmitOnError: true } }), "export const x: string = 10;"); + const { sys, baseline, config, mainFile } = createSystem( + JSON.stringify({ compilerOptions: { composite: true, noEmitOnError: true } }), + "export const x: string = 10;", + ); createWatch(baseline, config, sys, ts.createSemanticDiagnosticsBuilderProgram); // Fix error and emit @@ -473,12 +572,20 @@ describe("unittests:: tsc-watch:: watchAPI:: when watchHost uses createSemanticD const diagnostics = ts.sortAndDeduplicateDiagnostics(program.getSemanticDiagnostics()); diagnostics.forEach(reportDiagnostic); // Buildinfo should still have affectedFilesPendingEmit since we are only emitting dts files - program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ true); + program.emit( + /*targetSourceFile*/ undefined, + /*writeFile*/ undefined, + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ true, + ); reportWatchStatus( - ts.createCompilerDiagnostic(ts.getWatchErrorSummaryDiagnosticMessage(diagnostics.length), diagnostics.length), + ts.createCompilerDiagnostic( + ts.getWatchErrorSummaryDiagnosticMessage(diagnostics.length), + diagnostics.length, + ), sys.newLine, program.getCompilerOptions(), - diagnostics.length + diagnostics.length, ); cb(program); }; @@ -501,34 +608,34 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem content: JSON.stringify({ compilerOptions: { module: "none", - composite: true + composite: true, }, - exclude: ["temp"] - }) + exclude: ["temp"], + }), }; const class1: File = { path: `/user/username/projects/myproject/projects/project1/class1.ts`, - content: `class class1 {}` + content: `class class1 {}`, }; const class1Dts: File = { path: `/user/username/projects/myproject/projects/project1/class1.d.ts`, - content: `declare class class1 {}` + content: `declare class class1 {}`, }; const config2: File = { path: `/user/username/projects/myproject/projects/project2/tsconfig.json`, content: JSON.stringify({ compilerOptions: { module: "none", - composite: true + composite: true, }, references: [ - { path: "../project1" } - ] - }) + { path: "../project1" }, + ], + }), }; const class2: File = { path: `/user/username/projects/myproject/projects/project2/class2.ts`, - content: `class class2 {}` + content: `class class2 {}`, }; const system = createWatchedSystem([config1, class1, class1Dts, config2, class2, libFile]); const baseline = createBaseline(system); @@ -536,7 +643,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem cb: baseline.cb, system, configFileName: config2.path, - optionsToExtend: { extendedDiagnostics: true } + optionsToExtend: { extendedDiagnostics: true }, }); compilerHost.useSourceOfProjectReferenceRedirect = useSourceOfProjectReferenceRedirect; const calledGetParsedCommandLine = new Set(); @@ -548,7 +655,8 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem fileExists: path => system.fileExists(path), readFile: path => system.readFile(path), getCurrentDirectory: () => system.getCurrentDirectory(), - readDirectory: (path, extensions, excludes, includes, depth) => system.readDirectory(path, extensions, excludes, includes, depth), + readDirectory: (path, extensions, excludes, includes, depth) => + system.readDirectory(path, extensions, excludes, includes, depth), onUnRecoverableConfigFileDiagnostic: ts.noop, }); }; @@ -568,22 +676,33 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem caption: "Add class3 to project1", edit: sys => { calledGetParsedCommandLine.clear(); - sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.ts`, `class class3 {}`); + sys.writeFile( + `/user/username/projects/myproject/projects/project1/class3.ts`, + `class class3 {}`, + ); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Add excluded file to project1", - edit: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }), + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }), timeouts: sys => sys.logTimeoutQueueLength(), }, { caption: "Add output of class3", - edit: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/projects/project1/class3.d.ts`, + `declare class class3 {}`, + ), timeouts: sys => sys.logTimeoutQueueLength(), }, ], - watchOrSolution: watch + watchOrSolution: watch, }); }); @@ -591,7 +710,8 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem const { watch, baseline, config2, calledGetParsedCommandLine } = setup(); runWatchBaseline({ scenario: "watchApi", - subScenario: "when new file is added to the referenced project with host implementing getParsedCommandLine without implementing useSourceOfProjectReferenceRedirect", + subScenario: + "when new file is added to the referenced project with host implementing getParsedCommandLine without implementing useSourceOfProjectReferenceRedirect", commandLineArgs: ["--w", "-p", config2.path, "--extendedDiagnostics"], ...baseline, edits: [ @@ -599,18 +719,29 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem caption: "Add class3 to project1", edit: sys => { calledGetParsedCommandLine.clear(); - sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.ts`, `class class3 {}`); + sys.writeFile( + `/user/username/projects/myproject/projects/project1/class3.ts`, + `class class3 {}`, + ); }, timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Add class3 output to project1", - edit: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/projects/project1/class3.d.ts`, + `declare class class3 {}`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Add excluded file to project1", - edit: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }), + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }), timeouts: sys => sys.logTimeoutQueueLength(), }, { @@ -620,11 +751,15 @@ describe("unittests:: tsc-watch:: watchAPI:: when getParsedCommandLine is implem }, { caption: "Add output of class3", - edit: sys => sys.writeFile(`/user/username/projects/myproject/projects/project1/class3.d.ts`, `declare class class3 {}`), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/projects/project1/class3.d.ts`, + `declare class class3 {}`, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], - watchOrSolution: watch + watchOrSolution: watch, }); }); }); @@ -646,7 +781,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when builder emit occurs with emitO cb: baseline.cb, system, configFileName: `/user/username/projects/myproject/tsconfig.json`, - optionsToExtend: { extendedDiagnostics: true } + optionsToExtend: { extendedDiagnostics: true }, }); const originalEmitProgram = compilerHost.afterProgramCreate; compilerHost.afterProgramCreate = myAfterProgramCreate; @@ -670,7 +805,12 @@ describe("unittests:: tsc-watch:: watchAPI:: when builder emit occurs with emitO caption: "Emit with emitOnlyDts shouldnt emit anything", edit: () => { const program = watch.getCurrentProgram(); - program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ true); + program.emit( + /*targetSourceFile*/ undefined, + /*writeFile*/ undefined, + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ true, + ); baseline.cb(program); }, timeouts: sys => sys.logTimeoutQueueLength(), @@ -688,7 +828,12 @@ describe("unittests:: tsc-watch:: watchAPI:: when builder emit occurs with emitO caption: "Emit with emitOnlyDts shouldnt emit anything", edit: () => { const program = watch.getCurrentProgram(); - program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ true); + program.emit( + /*targetSourceFile*/ undefined, + /*writeFile*/ undefined, + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ true, + ); baseline.cb(program); }, timeouts: sys => sys.logTimeoutQueueLength(), @@ -703,7 +848,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when builder emit occurs with emitO timeouts: sys => sys.logTimeoutQueueLength(), }, ], - watchOrSolution: watch + watchOrSolution: watch, }); function myAfterProgramCreate(program: ts.EmitAndSemanticDiagnosticsBuilderProgram) { @@ -712,7 +857,12 @@ describe("unittests:: tsc-watch:: watchAPI:: when builder emit occurs with emitO } else { program.getSemanticDiagnostics(); // Get Diagnostics - program.emit(/*targetSourceFile*/ undefined, /*writeFile*/ undefined, /*cancellationToken*/ undefined, /*emitOnlyDtsFiles*/ true); + program.emit( + /*targetSourceFile*/ undefined, + /*writeFile*/ undefined, + /*cancellationToken*/ undefined, + /*emitOnlyDtsFiles*/ true, + ); baseline.cb(program); } } @@ -728,7 +878,7 @@ describe("unittests:: tsc-watch:: watchAPI:: when creating program with project "/user/username/projects/project/tsconfig.json": JSON.stringify({ compilerOptions: { types: [] }, files: ["app.ts"], - references: [{ path: "./lib" }] + references: [{ path: "./lib" }], }), "/user/username/projects/project/app.ts": dedent` import { one } from './lib'; @@ -755,9 +905,10 @@ describe("unittests:: tsc-watch:: watchAPI:: when creating program with project fileExists: path => system.fileExists(path), readFile: path => system.readFile(path), getCurrentDirectory: () => system.getCurrentDirectory(), - readDirectory: (path, extensions, excludes, includes, depth) => system.readDirectory(path, extensions, excludes, includes, depth), + readDirectory: (path, extensions, excludes, includes, depth) => + system.readDirectory(path, extensions, excludes, includes, depth), onUnRecoverableConfigFileDiagnostic: ts.noop, - } + }, )!; const compilerHost = createWatchCompilerHostOfFilesAndCompilerOptionsForBaseline({ cb: baseline.cb, @@ -781,14 +932,18 @@ describe("unittests:: tsc-watch:: watchAPI:: when creating program with project edits: [ { caption: "Modify lib tsconfig", - edit: sys => sys.writeFile(`/user/username/projects/project/lib/tsconfig.json`, JSON.stringify({ - compilerOptions: { composite: true }, - files: ["index.ts"], - })), + edit: sys => + sys.writeFile( + `/user/username/projects/project/lib/tsconfig.json`, + JSON.stringify({ + compilerOptions: { composite: true }, + files: ["index.ts"], + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], - watchOrSolution: watch + watchOrSolution: watch, }); }); @@ -802,22 +957,30 @@ describe("unittests:: tsc-watch:: watchAPI:: when creating program with project edits: [ { caption: "Modify lib tsconfig", - edit: sys => sys.writeFile(`/user/username/projects/project/lib/tsconfig.json`, JSON.stringify({ - extends: "./tsconfig.base.json", - compilerOptions: { typeRoots: [] }, - files: ["index.ts"], - })), + edit: sys => + sys.writeFile( + `/user/username/projects/project/lib/tsconfig.json`, + JSON.stringify({ + extends: "./tsconfig.base.json", + compilerOptions: { typeRoots: [] }, + files: ["index.ts"], + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Modify lib extends", - edit: sys => sys.writeFile(`/user/username/projects/project/lib/tsconfig.base.json`, JSON.stringify({ - compilerOptions: { composite: true }, - })), + edit: sys => + sys.writeFile( + `/user/username/projects/project/lib/tsconfig.base.json`, + JSON.stringify({ + compilerOptions: { composite: true }, + }), + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, ], - watchOrSolution: watch + watchOrSolution: watch, }); }); }); diff --git a/src/testRunner/unittests/tscWatch/watchEnvironment.ts b/src/testRunner/unittests/tscWatch/watchEnvironment.ts index 79afff507cf16..23ad8b46c2071 100644 --- a/src/testRunner/unittests/tscWatch/watchEnvironment.ts +++ b/src/testRunner/unittests/tscWatch/watchEnvironment.ts @@ -25,7 +25,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po const projectFolder = "/a/username/project"; const file1: File = { path: `${projectFolder}/typescript.ts`, - content: "var z = 10;" + content: "var z = 10;", }; const environmentVariables = new Map(); environmentVariables.set("TSC_WATCHFILE", Tsc_WatchFile.DynamicPolling); @@ -66,7 +66,8 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po timeouts: (sys, programs) => { const initialProgram = programs[0][0]; const mediumPollingIntervalThreshold = ts.unchangedPollThresholds[ts.PollingInterval.Medium]; - const newThreshold = ts.unchangedPollThresholds[ts.PollingInterval.Low] + mediumPollingIntervalThreshold; + const newThreshold = ts.unchangedPollThresholds[ts.PollingInterval.Low] + + mediumPollingIntervalThreshold; for (let fileUnchangeDetected = 1; fileUnchangeDetected < newThreshold; fileUnchangeDetected++) { // For high + Medium/low polling interval sys.runQueuedTimeoutCallbacks(); @@ -77,8 +78,8 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po sys.runQueuedTimeoutCallbacks(); return; }, - } - ] + }, + ], }); verifyTscWatch({ @@ -90,9 +91,9 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po path: "/a/b/tsconfig.json", content: JSON.stringify({ watchOptions: { - watchFile: "FixedChunkSizePolling" - } - }) + watchFile: "FixedChunkSizePolling", + }, + }), }; const files = [libFile, commonFile1, commonFile2, configFile]; return createWatchedSystem(files); @@ -132,7 +133,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po assert.deepEqual(programs[0][0], initialProgram); }, }, - ] + ], }); describe("tsc-watch when watchDirectories implementation", () => { @@ -143,13 +144,13 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po path: `${projectFolder}/tsconfig.json`, content: JSON.stringify({ watchOptions: { - synchronousWatchDirectory: true - } - }) + synchronousWatchDirectory: true, + }, + }), }; const file: File = { path: `${projectSrcFolder}/file1.ts`, - content: "" + content: "", }; verifyTscWatch({ scenario, @@ -182,9 +183,15 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po verifyRenamingFileInSubFolder("uses watchFile when renaming file in subfolder", Tsc_WatchDirectory.WatchFile); - verifyRenamingFileInSubFolder("uses non recursive watchDirectory when renaming file in subfolder", Tsc_WatchDirectory.NonRecursiveWatchDirectory); + verifyRenamingFileInSubFolder( + "uses non recursive watchDirectory when renaming file in subfolder", + Tsc_WatchDirectory.NonRecursiveWatchDirectory, + ); - verifyRenamingFileInSubFolder("uses non recursive dynamic polling when renaming file in subfolder", Tsc_WatchDirectory.DynamicPolling); + verifyRenamingFileInSubFolder( + "uses non recursive dynamic polling when renaming file in subfolder", + Tsc_WatchDirectory.DynamicPolling, + ); verifyTscWatch({ scenario, @@ -194,35 +201,35 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po const cwd = "/home/user/projects/myproject"; const file1: File = { path: `${cwd}/src/file.ts`, - content: `import * as a from "a"` + content: `import * as a from "a"`, }; const tsconfig: File = { path: `${cwd}/tsconfig.json`, - content: `{ "compilerOptions": { "extendedDiagnostics": true, "traceResolution": true }}` + content: `{ "compilerOptions": { "extendedDiagnostics": true, "traceResolution": true }}`, }; const realA: File = { path: `${cwd}/node_modules/reala/index.d.ts`, - content: `export {}` + content: `export {}`, }; const realB: File = { path: `${cwd}/node_modules/realb/index.d.ts`, - content: `export {}` + content: `export {}`, }; const symLinkA: SymLink = { path: `${cwd}/node_modules/a`, - symLink: `${cwd}/node_modules/reala` + symLink: `${cwd}/node_modules/reala`, }; const symLinkB: SymLink = { path: `${cwd}/node_modules/b`, - symLink: `${cwd}/node_modules/realb` + symLink: `${cwd}/node_modules/realb`, }; const symLinkBInA: SymLink = { path: `${cwd}/node_modules/reala/node_modules/b`, - symLink: `${cwd}/node_modules/b` + symLink: `${cwd}/node_modules/b`, }; const symLinkAInB: SymLink = { path: `${cwd}/node_modules/realb/node_modules/a`, - symLink: `${cwd}/node_modules/a` + symLink: `${cwd}/node_modules/a`, }; const files = [libFile, file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB]; const environmentVariables = new Map(); @@ -238,15 +245,15 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po sys: () => { const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const file1: File = { path: `/user/username/projects/myproject/src/file1.ts`, - content: `import { x } from "file2";` + content: `import { x } from "file2";`, }; const file2: File = { path: `/user/username/projects/myproject/node_modules/file2/index.d.ts`, - content: `export const x = 10;` + content: `export const x = 10;`, }; const files = [libFile, file1, file2, configFile]; return createWatchedSystem(files, { runWithoutRecursiveWatches: true }); @@ -288,7 +295,11 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po }, { caption: "npm install index file in file2", - edit: sys => sys.writeFile(`/user/username/projects/myproject/node_modules/file2/index.d.ts`, `export const x = 10;`), + edit: sys => + sys.writeFile( + `/user/username/projects/myproject/node_modules/file2/index.d.ts`, + `export const x = 10;`, + ), timeouts: sys => sys.logTimeoutQueueLength(), // To update folder structure }, { @@ -316,15 +327,15 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po sys: () => { const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { outDir: "dist", declaration: true } }) + content: JSON.stringify({ compilerOptions: { outDir: "dist", declaration: true } }), }; const file1: File = { path: `/user/username/projects/myproject/src/file1.ts`, - content: `import { x } from "file2";` + content: `import { x } from "file2";`, }; const file2: File = { path: `/user/username/projects/myproject/node_modules/file2/index.d.ts`, - content: `export const x = 10;` + content: `export const x = 10;`, }; const files = [libFile, file1, file2, configFile]; return createWatchedSystem(files, { runWithoutRecursiveWatches: true }); @@ -333,7 +344,8 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po noopChange, { caption: "Add new file, should schedule and run timeout to update directory watcher", - edit: sys => sys.writeFile(`/user/username/projects/myproject/src/file3.ts`, `export const y = 10;`), + edit: sys => + sys.writeFile(`/user/username/projects/myproject/src/file3.ts`, `export const y = 10;`), timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Update the child watch }, { @@ -342,7 +354,8 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Scheduling failed lookup update and program update }, { - caption: "After program emit with new file, should schedule and run timeout to update directory watcher", + caption: + "After program emit with new file, should schedule and run timeout to update directory watcher", edit: ts.noop, timeouts: sys => sys.runQueuedTimeoutCallbacks(), // Update the child watch }, @@ -357,15 +370,15 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po sys: () => { const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { outDir: "dist" } }) + content: JSON.stringify({ compilerOptions: { outDir: "dist" } }), }; const file1: File = { path: `/user/username/projects/myproject/src/file1.ts`, - content: `import { x } from "./file2";` + content: `import { x } from "./file2";`, }; const file2: File = { path: `/user/username/projects/myproject/src/file2.ts`, - content: `export const x = 10;` + content: `export const x = 10;`, }; const files = [libFile, file1, file2, configFile]; return createWatchedSystem(files, { runWithoutRecursiveWatches: true }); @@ -374,7 +387,11 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po noopChange, { caption: "rename the file", - edit: sys => sys.renameFile(`/user/username/projects/myproject/src/file2.ts`, `/user/username/projects/myproject/src/renamed.ts`), + edit: sys => + sys.renameFile( + `/user/username/projects/myproject/src/file2.ts`, + `/user/username/projects/myproject/src/renamed.ts`, + ), // 1. For updating program and 2. for updating child watches timeouts: sys => sys.runQueuedTimeoutCallbacks(1), // Update program }, @@ -401,9 +418,9 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po path: "/a/b/tsconfig.json", content: JSON.stringify({ watchOptions: { - watchFile: "UseFsEvents" - } - }) + watchFile: "UseFsEvents", + }, + }), }; const files = [libFile, commonFile1, commonFile2, configFile]; return createWatchedSystem(files); @@ -419,9 +436,9 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po path: "/a/b/tsconfig.json", content: JSON.stringify({ watchOptions: { - watchDirectory: "UseFsEvents" - } - }) + watchDirectory: "UseFsEvents", + }, + }), }; const files = [libFile, commonFile1, commonFile2, configFile]; return createWatchedSystem(files, { runWithoutRecursiveWatches: true }); @@ -437,9 +454,9 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po path: "/a/b/tsconfig.json", content: JSON.stringify({ watchOptions: { - fallbackPolling: "PriorityInterval" - } - }) + fallbackPolling: "PriorityInterval", + }, + }), }; const files = [libFile, commonFile1, commonFile2, configFile]; return createWatchedSystem(files, { runWithoutRecursiveWatches: true, runWithFallbackPolling: true }); @@ -453,7 +470,7 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po sys: () => { const configFile: File = { path: "/a/b/tsconfig.json", - content: "{}" + content: "{}", }; const files = [libFile, commonFile1, commonFile2, configFile]; return createWatchedSystem(files); @@ -464,30 +481,33 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po function sys(watchOptions: ts.WatchOptions, runWithoutRecursiveWatches?: boolean): TestServerHost { const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ exclude: ["node_modules"], watchOptions }) + content: JSON.stringify({ exclude: ["node_modules"], watchOptions }), }; const main: File = { path: `/user/username/projects/myproject/src/main.ts`, - content: `import { foo } from "bar"; foo();` + content: `import { foo } from "bar"; foo();`, }; const bar: File = { path: `/user/username/projects/myproject/node_modules/bar/index.d.ts`, - content: `export { foo } from "./foo";` + content: `export { foo } from "./foo";`, }; const foo: File = { path: `/user/username/projects/myproject/node_modules/bar/foo.d.ts`, - content: `export function foo(): string;` + content: `export function foo(): string;`, }; const fooBar: File = { path: `/user/username/projects/myproject/node_modules/bar/fooBar.d.ts`, - content: `export function fooBar(): string;` + content: `export function fooBar(): string;`, }; const temp: File = { path: `/user/username/projects/myproject/node_modules/bar/temp/index.d.ts`, - content: "export function temp(): string;" + content: "export function temp(): string;", }; const files = [libFile, main, bar, foo, fooBar, temp, configFile]; - return createWatchedSystem(files, { currentDirectory: "/user/username/projects/myproject", runWithoutRecursiveWatches }); + return createWatchedSystem(files, { + currentDirectory: "/user/username/projects/myproject", + runWithoutRecursiveWatches, + }); } function verifyWorker(...additionalFlags: string[]) { @@ -499,10 +519,15 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po edits: [ { caption: "Change foo", - edit: sys => sys.replaceFileText(`/user/username/projects/myproject/node_modules/bar/foo.d.ts`, "foo", "fooBar"), + edit: sys => + sys.replaceFileText( + `/user/username/projects/myproject/node_modules/bar/foo.d.ts`, + "foo", + "fooBar", + ), timeouts: sys => sys.logTimeoutQueueLength(), - } - ] + }, + ], }); verifyTscWatch({ @@ -513,14 +538,18 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po edits: [ { caption: "delete fooBar", - edit: sys => sys.deleteFile(`/user/username/projects/myproject/node_modules/bar/fooBar.d.ts`), - timeouts: sys => sys.logTimeoutQueueLength(), } - ] + edit: sys => + sys.deleteFile(`/user/username/projects/myproject/node_modules/bar/fooBar.d.ts`), + timeouts: sys => sys.logTimeoutQueueLength(), + }, + ], }); verifyTscWatch({ scenario, - subScenario: `watchOptions/with excludeDirectories option with recursive directory watching${additionalFlags.join("")}`, + subScenario: `watchOptions/with excludeDirectories option with recursive directory watching${ + additionalFlags.join("") + }`, commandLineArgs: ["-w", ...additionalFlags], sys: () => sys({ excludeDirectories: ["**/temp"] }, /*runWithoutRecursiveWatches*/ true), edits: [ @@ -531,10 +560,14 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po }, { caption: "add new folder to temp", - edit: sys => sys.ensureFileOrFolder({ path: `/user/username/projects/myproject/node_modules/bar/temp/fooBar/index.d.ts`, content: "export function temp(): string;" }), + edit: sys => + sys.ensureFileOrFolder({ + path: `/user/username/projects/myproject/node_modules/bar/temp/fooBar/index.d.ts`, + content: "export function temp(): string;", + }), timeouts: sys => sys.logTimeoutQueueLength(), - } - ] + }, + ], }); } @@ -547,35 +580,46 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po scenario, subScenario: `fsWatch/when using file watching thats when rename occurs when file is still on the disk`, commandLineArgs: ["-w", "--extendedDiagnostics"], - sys: () => createWatchedSystem( - { - [libFile.path]: libFile.content, - [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`, - [`/user/username/projects/myproject/foo.ts`]: `export declare function foo(): string;`, - [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ - watchOptions: { watchFile: "useFsEvents" }, - files: ["foo.ts", "main.ts"] - }), - }, - { currentDirectory: "/user/username/projects/myproject", } - ), + sys: () => + createWatchedSystem( + { + [libFile.path]: libFile.content, + [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`, + [`/user/username/projects/myproject/foo.ts`]: `export declare function foo(): string;`, + [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ + watchOptions: { watchFile: "useFsEvents" }, + files: ["foo.ts", "main.ts"], + }), + }, + { currentDirectory: "/user/username/projects/myproject" }, + ), edits: [ { caption: "Introduce error such that when callback happens file is already appeared", // vm's wq generates this kind of event // Skip delete event so inode changes but when the create's rename occurs file is on disk - edit: sys => sys.modifyFile(`/user/username/projects/myproject/foo.ts`, `export declare function foo2(): string;`, { - invokeFileDeleteCreateAsPartInsteadOfChange: true, - ignoreDelete: true, - }), + edit: sys => + sys.modifyFile( + `/user/username/projects/myproject/foo.ts`, + `export declare function foo2(): string;`, + { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + ignoreDelete: true, + }, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Replace file with rename event that fixes error", - edit: sys => sys.modifyFile(`/user/username/projects/myproject/foo.ts`, `export declare function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, }), + edit: sys => + sys.modifyFile( + `/user/username/projects/myproject/foo.ts`, + `export declare function foo(): string;`, + { invokeFileDeleteCreateAsPartInsteadOfChange: true }, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); describe("with fsWatch on inodes", () => { @@ -583,99 +627,139 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po scenario, subScenario: `fsWatch/when using file watching thats on inode`, commandLineArgs: ["-w", "--extendedDiagnostics"], - sys: () => createWatchedSystem( - { - [libFile.path]: libFile.content, - [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`, - [`/user/username/projects/myproject/foo.d.ts`]: `export function foo(): string;`, - [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ watchOptions: { watchFile: "useFsEvents" }, files: ["foo.d.ts", "main.ts"] }), - }, - { - currentDirectory: "/user/username/projects/myproject", - inodeWatching: true - } - ), + sys: () => + createWatchedSystem( + { + [libFile.path]: libFile.content, + [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`, + [`/user/username/projects/myproject/foo.d.ts`]: `export function foo(): string;`, + [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ + watchOptions: { watchFile: "useFsEvents" }, + files: ["foo.d.ts", "main.ts"], + }), + }, + { + currentDirectory: "/user/username/projects/myproject", + inodeWatching: true, + }, + ), edits: [ { caption: "Replace file with rename event that introduces error", - edit: sys => sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo2(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }), + edit: sys => + sys.modifyFile( + `/user/username/projects/myproject/foo.d.ts`, + `export function foo2(): string;`, + { invokeFileDeleteCreateAsPartInsteadOfChange: true }, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Replace file with rename event that fixes error", - edit: sys => sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true }), + edit: sys => + sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo(): string;`, { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + }), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ scenario, subScenario: `fsWatch/when using file watching thats on inode when rename event ends with tilde`, commandLineArgs: ["-w", "--extendedDiagnostics"], - sys: () => createWatchedSystem( - { - [libFile.path]: libFile.content, - [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`, - [`/user/username/projects/myproject/foo.d.ts`]: `export function foo(): string;`, - [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ watchOptions: { watchFile: "useFsEvents" }, files: ["foo.d.ts", "main.ts"] }), - }, - { - currentDirectory: "/user/username/projects/myproject", - inodeWatching: true - } - ), + sys: () => + createWatchedSystem( + { + [libFile.path]: libFile.content, + [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`, + [`/user/username/projects/myproject/foo.d.ts`]: `export function foo(): string;`, + [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ + watchOptions: { watchFile: "useFsEvents" }, + files: ["foo.d.ts", "main.ts"], + }), + }, + { + currentDirectory: "/user/username/projects/myproject", + inodeWatching: true, + }, + ), edits: [ { caption: "Replace file with rename event that introduces error", - edit: sys => sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo2(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, useTildeAsSuffixInRenameEventFileName: true }), + edit: sys => + sys.modifyFile( + `/user/username/projects/myproject/foo.d.ts`, + `export function foo2(): string;`, + { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + useTildeAsSuffixInRenameEventFileName: true, + }, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Replace file with rename event that fixes error", - edit: sys => sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, useTildeAsSuffixInRenameEventFileName: true }), + edit: sys => + sys.modifyFile(`/user/username/projects/myproject/foo.d.ts`, `export function foo(): string;`, { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + useTildeAsSuffixInRenameEventFileName: true, + }), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); verifyTscWatch({ scenario, - subScenario: `fsWatch/when using file watching thats on inode when rename occurs when file is still on the disk`, + subScenario: + `fsWatch/when using file watching thats on inode when rename occurs when file is still on the disk`, commandLineArgs: ["-w", "--extendedDiagnostics"], - sys: () => createWatchedSystem( - { - [libFile.path]: libFile.content, - [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`, - [`/user/username/projects/myproject/foo.ts`]: `export declare function foo(): string;`, - [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ - watchOptions: { watchFile: "useFsEvents" }, - files: ["foo.ts", "main.ts"] - }), - }, - { - currentDirectory: "/user/username/projects/myproject", - inodeWatching: true, - } - ), + sys: () => + createWatchedSystem( + { + [libFile.path]: libFile.content, + [`/user/username/projects/myproject/main.ts`]: `import { foo } from "./foo"; foo();`, + [`/user/username/projects/myproject/foo.ts`]: `export declare function foo(): string;`, + [`/user/username/projects/myproject/tsconfig.json`]: JSON.stringify({ + watchOptions: { watchFile: "useFsEvents" }, + files: ["foo.ts", "main.ts"], + }), + }, + { + currentDirectory: "/user/username/projects/myproject", + inodeWatching: true, + }, + ), edits: [ { caption: "Introduce error such that when callback happens file is already appeared", // vm's wq generates this kind of event // Skip delete event so inode changes but when the create's rename occurs file is on disk - edit: sys => sys.modifyFile(`/user/username/projects/myproject/foo.ts`, `export declare function foo2(): string;`, { - invokeFileDeleteCreateAsPartInsteadOfChange: true, - ignoreDelete: true, - skipInodeCheckOnCreate: true - }), + edit: sys => + sys.modifyFile( + `/user/username/projects/myproject/foo.ts`, + `export declare function foo2(): string;`, + { + invokeFileDeleteCreateAsPartInsteadOfChange: true, + ignoreDelete: true, + skipInodeCheckOnCreate: true, + }, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { caption: "Replace file with rename event that fixes error", - edit: sys => sys.modifyFile(`/user/username/projects/myproject/foo.ts`, `export declare function foo(): string;`, { invokeFileDeleteCreateAsPartInsteadOfChange: true, }), + edit: sys => + sys.modifyFile( + `/user/username/projects/myproject/foo.ts`, + `export declare function foo(): string;`, + { invokeFileDeleteCreateAsPartInsteadOfChange: true }, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, - ] + ], }); }); @@ -683,10 +767,11 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po scenario, subScenario: "fsEvent for change is repeated", commandLineArgs: ["-w", "main.ts", "--extendedDiagnostics"], - sys: () => createWatchedSystem({ - "/user/username/projects/project/main.ts": `let a: string = "Hello"`, - [libFile.path]: libFile.content, - }, { currentDirectory: "/user/username/projects/project" }), + sys: () => + createWatchedSystem({ + "/user/username/projects/project/main.ts": `let a: string = "Hello"`, + [libFile.path]: libFile.content, + }, { currentDirectory: "/user/username/projects/project" }), edits: [ { caption: "change main.ts", @@ -695,7 +780,13 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po }, { caption: "receive another change event without modifying the file", - edit: sys => sys.invokeFsWatches("/user/username/projects/project/main.ts", "change", /*modifiedTime*/ undefined, /*useTildeSuffix*/ undefined), + edit: sys => + sys.invokeFsWatches( + "/user/username/projects/project/main.ts", + "change", + /*modifiedTime*/ undefined, + /*useTildeSuffix*/ undefined, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), }, { @@ -705,9 +796,15 @@ describe("unittests:: tsc-watch:: watchEnvironment:: tsc-watch with different po }, { caption: "receive another change event without modifying the file", - edit: sys => sys.invokeFsWatches("/user/username/projects/project/main.ts", "change", /*modifiedTime*/ undefined, /*useTildeSuffix*/ undefined), + edit: sys => + sys.invokeFsWatches( + "/user/username/projects/project/main.ts", + "change", + /*modifiedTime*/ undefined, + /*useTildeSuffix*/ undefined, + ), timeouts: sys => sys.runQueuedTimeoutCallbacks(), - } - ] + }, + ], }); }); diff --git a/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts b/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts index d78e6168b0470..03cbe2c5cebee 100644 --- a/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts +++ b/src/testRunner/unittests/tsserver/applyChangesToOpenFiles.ts @@ -23,28 +23,28 @@ ${file.content}`; function setup() { const configFile: File = { path: "/a/b/tsconfig.json", - content: "{}" + content: "{}", }; const file3: File = { path: "/a/b/file3.ts", - content: "let xyz = 1;" + content: "let xyz = 1;", }; const app: File = { path: "/a/b/app.ts", - content: "let z = 1;" + content: "let z = 1;", }; const host = createServerHost([app, file3, commonFile1, commonFile2, libFile, configFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Open, - arguments: { file: app.path } + arguments: { file: app.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Open, arguments: { file: file3.path, - fileContent: fileContentWithComment(file3) - } + fileContent: fileContentWithComment(file3), + }, }); return { session, file3, app }; } @@ -58,12 +58,12 @@ ${file.content}`; openFiles: [ { fileName: commonFile1.path, - content: fileContentWithComment(commonFile1) + content: fileContentWithComment(commonFile1), }, { fileName: commonFile2.path, - content: fileContentWithComment(commonFile2) - } + content: fileContentWithComment(commonFile2), + }, ], changedFiles: [ { @@ -71,19 +71,19 @@ ${file.content}`; changes: [ { span: { start: 0, length: 0 }, - newText: "let zzz = 10;" + newText: "let zzz = 10;", }, { span: { start: 0, length: 0 }, - newText: "let zz = 10;" - } - ] - } + newText: "let zz = 10;", + }, + ], + }, ], closedFiles: [ - file3.path - ] - } + file3.path, + ], + }, }); // Open file1 again session.executeCommandSeq({ @@ -91,9 +91,9 @@ ${file.content}`; arguments: { openFiles: [{ fileName: commonFile1.path, - content: commonFile1.content - }] - } + content: commonFile1.content, + }], + }, }); baselineTsserverLogs("applyChangesToOpenFiles", "with applyChangedToOpenFiles request", session); }); @@ -107,12 +107,12 @@ ${file.content}`; openFiles: [ { file: commonFile1.path, - fileContent: fileContentWithComment(commonFile1) + fileContent: fileContentWithComment(commonFile1), }, { file: commonFile2.path, - fileContent: fileContentWithComment(commonFile2) - } + fileContent: fileContentWithComment(commonFile2), + }, ], changedFiles: [ { @@ -127,14 +127,14 @@ ${file.content}`; start: { line: 1, offset: 1 }, end: { line: 1, offset: 1 }, newText: "let zz = 10;", - } - ] - } + }, + ], + }, ], closedFiles: [ - file3.path - ] - } + file3.path, + ], + }, }); // Open file1 again session.executeCommandSeq({ @@ -142,9 +142,9 @@ ${file.content}`; arguments: { openFiles: [{ file: commonFile1.path, - fileContent: commonFile1.content - }] - } + fileContent: commonFile1.content, + }], + }, }); baselineTsserverLogs("applyChangesToOpenFiles", "with updateOpen request", session); }); diff --git a/src/testRunner/unittests/tsserver/autoImportProvider.ts b/src/testRunner/unittests/tsserver/autoImportProvider.ts index f07a52f9112eb..c42c6b23cb89a 100644 --- a/src/testRunner/unittests/tsserver/autoImportProvider.ts +++ b/src/testRunner/unittests/tsserver/autoImportProvider.ts @@ -32,11 +32,11 @@ const tsconfig: File = { }; const packageJson: File = { path: "/package.json", - content: `{ "dependencies": { "@angular/forms": "*", "@angular/core": "*" } }` + content: `{ "dependencies": { "@angular/forms": "*", "@angular/core": "*" } }`, }; const indexTs: File = { path: "/index.ts", - content: "" + content: "", }; describe("unittests:: tsserver:: autoImportProvider", () => { @@ -46,10 +46,12 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularFormsPackageJson, tsconfig, { path: packageJson.path, content: `{ "dependencies": {} }` }, - indexTs + indexTs, ]); openFilesForSession([indexTs], session); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); baselineTsserverLogs("autoImportProvider", "without dependencies listed", session); }); @@ -59,10 +61,12 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularFormsPackageJson, tsconfig, packageJson, - { path: indexTs.path, content: "import '@angular/forms';" } + { path: indexTs.path, content: "import '@angular/forms';" }, ]); openFilesForSession([indexTs], session); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); baselineTsserverLogs("autoImportProvider", "dependencies are already in main program", session); }); @@ -77,23 +81,47 @@ describe("unittests:: tsserver:: autoImportProvider", () => { ]); openFilesForSession([angularFormsDts], session); - assert.isUndefined(projectService - .getDefaultProjectForFile(angularFormsDts.path as ts.server.NormalizedPath, /*ensureProject*/ true)! - .getLanguageService() - .getAutoImportProvider()); + assert.isUndefined( + projectService + .getDefaultProjectForFile(angularFormsDts.path as ts.server.NormalizedPath, /*ensureProject*/ true)! + .getLanguageService() + .getAutoImportProvider(), + ); baselineTsserverLogs("autoImportProvider", "projects already inside node_modules", session); }); it("Auto-importable file is in inferred project until imported", () => { - const { projectService, session, updateFile } = setup([angularFormsDts, angularFormsPackageJson, tsconfig, packageJson, indexTs]); + const { projectService, session, updateFile } = setup([ + angularFormsDts, + angularFormsPackageJson, + tsconfig, + packageJson, + indexTs, + ]); openFilesForSession([angularFormsDts], session); - session.logger.log(`Default Project for ${angularFormsDts.path}:: ${projectService.getDefaultProjectForFile(angularFormsDts.path as ts.server.NormalizedPath, /*ensureProject*/ true)?.projectName}`); + session.logger.log( + `Default Project for ${angularFormsDts.path}:: ${projectService.getDefaultProjectForFile( + angularFormsDts.path as ts.server.NormalizedPath, + /*ensureProject*/ true, + )?.projectName}`, + ); updateFile(indexTs.path, "import '@angular/forms'"); - session.logger.log(`Default Project for ${angularFormsDts.path}:: ${projectService.getDefaultProjectForFile(angularFormsDts.path as ts.server.NormalizedPath, /*ensureProject*/ true)?.projectName}`); - - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); - baselineTsserverLogs("autoImportProvider", "Auto-importable file is in inferred project until imported", session); + session.logger.log( + `Default Project for ${angularFormsDts.path}:: ${projectService.getDefaultProjectForFile( + angularFormsDts.path as ts.server.NormalizedPath, + /*ensureProject*/ true, + )?.projectName}`, + ); + + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); + baselineTsserverLogs( + "autoImportProvider", + "Auto-importable file is in inferred project until imported", + session, + ); }); it("Responds to package.json changes", () => { @@ -102,11 +130,13 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularFormsPackageJson, tsconfig, { path: "/package.json", content: "{}" }, - indexTs + indexTs, ]); openFilesForSession([indexTs], session); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); host.writeFile(packageJson.path, packageJson.content); assert.ok(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); @@ -119,18 +149,24 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularFormsPackageJson, tsconfig, packageJson, - indexTs + indexTs, ]); openFilesForSession([indexTs], session); - const autoImportProvider = projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(); + const autoImportProvider = projectService.configuredProjects.get(tsconfig.path)!.getLanguageService() + .getAutoImportProvider(); assert.ok(autoImportProvider); updateFile(indexTs.path, "console.log(0)"); assert.strictEqual( projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), - autoImportProvider); - baselineTsserverLogs("autoImportProvider", "Reuses autoImportProvider when program structure is unchanged", session); + autoImportProvider, + ); + baselineTsserverLogs( + "autoImportProvider", + "Reuses autoImportProvider when program structure is unchanged", + session, + ); }); it("Closes AutoImportProviderProject when host project closes", () => { @@ -139,7 +175,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularFormsPackageJson, tsconfig, packageJson, - indexTs + indexTs, ]); openFilesForSession([indexTs], session); @@ -151,7 +187,11 @@ describe("unittests:: tsserver:: autoImportProvider", () => { hostProject.close(); assert.ok(autoImportProviderProject && autoImportProviderProject.isClosed()); assert.isUndefined(hostProject.autoImportProviderHost); - baselineTsserverLogs("autoImportProvider", "Closes AutoImportProviderProject when host project closes", session); + baselineTsserverLogs( + "autoImportProvider", + "Closes AutoImportProviderProject when host project closes", + session, + ); }); it("Does not schedule ensureProjectForOpenFiles on AutoImportProviderProject creation", () => { @@ -159,7 +199,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularFormsDts, angularFormsPackageJson, tsconfig, - indexTs + indexTs, ]); // Create configured project only, ensure !projectService.pendingEnsureProjectForOpenFiles @@ -173,7 +213,11 @@ describe("unittests:: tsserver:: autoImportProvider", () => { host.writeFile(packageJson.path, packageJson.content); hostProject.getPackageJsonAutoImportProvider(); assert.isFalse(projectService.pendingEnsureProjectForOpenFiles); - baselineTsserverLogs("autoImportProvider", "Does not schedule ensureProjectForOpenFiles on AutoImportProviderProject creation", session); + baselineTsserverLogs( + "autoImportProvider", + "Does not schedule ensureProjectForOpenFiles on AutoImportProviderProject creation", + session, + ); }); it("Responds to automatic changes in node_modules", () => { @@ -184,12 +228,14 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularCorePackageJson, tsconfig, packageJson, - indexTs + indexTs, ]); openFilesForSession([indexTs], session); const project = projectService.configuredProjects.get(tsconfig.path)!; - const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true }); + const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { + includeCompletionsForModuleExports: true, + }); assert.isTrue(completionsBefore?.entries.some(c => c.name === "PatternValidator")); // Directory watchers only fire for add/remove, not change. @@ -198,7 +244,9 @@ describe("unittests:: tsserver:: autoImportProvider", () => { host.writeFile(angularFormsDts.path, ""); const autoImportProvider = project.getLanguageService().getAutoImportProvider(); - const completionsAfter = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true }); + const completionsAfter = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { + includeCompletionsForModuleExports: true, + }); assert.equal(autoImportProvider!.getSourceFile(angularFormsDts.path)!.getText(), ""); assert.isFalse(completionsAfter?.entries.some(c => c.name === "PatternValidator")); baselineTsserverLogs("autoImportProvider", "Responds to automatic changes in node_modules", session); @@ -212,16 +260,20 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularCorePackageJson, tsconfig, packageJson, - indexTs + indexTs, ]); openFilesForSession([indexTs, angularFormsDts], session); const project = projectService.configuredProjects.get(tsconfig.path)!; - const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true }); + const completionsBefore = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { + includeCompletionsForModuleExports: true, + }); assert.isTrue(completionsBefore?.entries.some(c => c.name === "PatternValidator")); updateFile(angularFormsDts.path, "export class ValidatorPattern {}"); - const completionsAfter = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { includeCompletionsForModuleExports: true }); + const completionsAfter = project.getLanguageService().getCompletionsAtPosition(indexTs.path, 0, { + includeCompletionsForModuleExports: true, + }); assert.isFalse(completionsAfter?.entries.some(c => c.name === "PatternValidator")); assert.isTrue(completionsAfter?.entries.some(c => c.name === "ValidatorPattern")); baselineTsserverLogs("autoImportProvider", "Responds to manual changes in node_modules", session); @@ -233,11 +285,13 @@ describe("unittests:: tsserver:: autoImportProvider", () => { angularFormsPackageJson, tsconfig, { path: packageJson.path, content: "{" }, - indexTs + indexTs, ]); openFilesForSession([indexTs], session); - assert.isUndefined(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); + assert.isUndefined( + projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider(), + ); host.writeFile(packageJson.path, packageJson.content); assert.ok(projectService.configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider()); @@ -245,10 +299,10 @@ describe("unittests:: tsserver:: autoImportProvider", () => { }); it("Does not create an auto import provider if there are too many dependencies", () => { - const createPackage = (i: number): File[] => ([ + const createPackage = (i: number): File[] => [ { path: `/node_modules/package${i}/package.json`, content: `{ "name": "package${i}" }` }, - { path: `/node_modules/package${i}/index.d.ts`, content: `` } - ]); + { path: `/node_modules/package${i}/index.d.ts`, content: `` }, + ]; const packages = []; for (let i = 0; i < 11; i++) { @@ -262,21 +316,37 @@ describe("unittests:: tsserver:: autoImportProvider", () => { openFilesForSession([indexTs], session); const project = projectService.configuredProjects.get(tsconfig.path)!; assert.isUndefined(project.getPackageJsonAutoImportProvider()); - baselineTsserverLogs("autoImportProvider", "Does not create an auto import provider if there are too many dependencies", session); + baselineTsserverLogs( + "autoImportProvider", + "Does not create an auto import provider if there are too many dependencies", + session, + ); }); it("Shared source files between AutoImportProvider and main program do not cause duplicate entries in export info map", () => { const files = [ // node_modules/memfs - AutoImportProvider only - { path: "/node_modules/memfs/package.json", content: `{ "name": "memfs", "version": "1.0.0", "types": "lib/index.d.ts" }` }, - { path: "/node_modules/memfs/lib/index.d.ts", content: `/// \nexport declare class Volume {}` }, + { + path: "/node_modules/memfs/package.json", + content: `{ "name": "memfs", "version": "1.0.0", "types": "lib/index.d.ts" }`, + }, + { + path: "/node_modules/memfs/lib/index.d.ts", + content: `/// \nexport declare class Volume {}`, + }, // node_modules/@types/node - AutoImportProvider and main program - { path: "/node_modules/@types/node/package.json", content: `{ "name": "@types/node", "version": "1.0.0" }` }, + { + path: "/node_modules/@types/node/package.json", + content: `{ "name": "@types/node", "version": "1.0.0" }`, + }, { path: "/node_modules/@types/node/index.d.ts", content: `export declare class Stats {}` }, // root - { path: "/package.json", content: `{ "dependencies": { "memfs": "*" }, "devDependencies": { "@types/node": "*" } }` }, + { + path: "/package.json", + content: `{ "dependencies": { "memfs": "*" }, "devDependencies": { "@types/node": "*" } }`, + }, { path: "/tsconfig.json", content: `{ "compilerOptions": { "types": ["node"] }` }, { path: "/index.ts", content: `export {};` }, ]; @@ -298,7 +368,11 @@ describe("unittests:: tsserver:: autoImportProvider", () => { assert.equal(seenSymbolNames.size, 2); assert.ok(seenSymbolNames.has("Stats")); assert.ok(seenSymbolNames.has("Volume")); - baselineTsserverLogs("autoImportProvider", "Shared source files between AutoImportProvider and main program", session); + baselineTsserverLogs( + "autoImportProvider", + "Shared source files between AutoImportProvider and main program", + session, + ); }); }); @@ -315,13 +389,16 @@ describe("unittests:: tsserver:: autoImportProvider - monorepo", () => { // packages/a { path: "/packages/a/package.json", content: packageJson.content }, - { path: "/packages/a/tsconfig.json", content: `{ "compilerOptions": { "composite": true }, "references": [{ "path": "../b" }] }` }, + { + path: "/packages/a/tsconfig.json", + content: `{ "compilerOptions": { "composite": true }, "references": [{ "path": "../b" }] }`, + }, { path: "/packages/a/index.ts", content: "import { B } from '../b';" }, // packages/b { path: "/packages/b/package.json", content: packageJson.content }, { path: "/packages/b/tsconfig.json", content: `{ "compilerOptions": { "composite": true } }` }, - { path: "/packages/b/index.ts", content: `export class B {}` } + { path: "/packages/b/index.ts", content: `export class B {}` }, ]; const { projectService, session, findAllReferences } = setup(files); @@ -330,35 +407,56 @@ describe("unittests:: tsserver:: autoImportProvider - monorepo", () => { findAllReferences("/packages/b/index.ts", 1, "export class B".length - 1); // Project for A is created - ensure it doesn't have an autoImportProvider - assert.isUndefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getLanguageService().getAutoImportProvider()); - baselineTsserverLogs("autoImportProvider", "Does not create auto import providers upon opening projects for find-all-references", session); + assert.isUndefined( + projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getLanguageService() + .getAutoImportProvider(), + ); + baselineTsserverLogs( + "autoImportProvider", + "Does not create auto import providers upon opening projects for find-all-references", + session, + ); }); it("Does not close when root files are redirects that don't actually exist", () => { const files = [ // packages/a { path: "/packages/a/package.json", content: `{ "dependencies": { "b": "*" } }` }, - { path: "/packages/a/tsconfig.json", content: `{ "compilerOptions": { "composite": true }, "references": [{ "path": "./node_modules/b" }] }` }, + { + path: "/packages/a/tsconfig.json", + content: `{ "compilerOptions": { "composite": true }, "references": [{ "path": "./node_modules/b" }] }`, + }, { path: "/packages/a/index.ts", content: "" }, // packages/b { path: "/packages/a/node_modules/b/package.json", content: `{ "types": "dist/index.d.ts" }` }, - { path: "/packages/a/node_modules/b/tsconfig.json", content: `{ "compilerOptions": { "composite": true, "outDir": "dist" } }` }, - { path: "/packages/a/node_modules/b/index.ts", content: `export class B {}` } + { + path: "/packages/a/node_modules/b/tsconfig.json", + content: `{ "compilerOptions": { "composite": true, "outDir": "dist" } }`, + }, + { path: "/packages/a/node_modules/b/index.ts", content: `export class B {}` }, ]; const { projectService, session } = setup(files); openFilesForSession([files[2]], session); - assert.isDefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider()); - assert.isDefined(projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider()); - baselineTsserverLogs("autoImportProvider", "Does not close when root files are redirects that dont actually exist", session); + assert.isDefined( + projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider(), + ); + assert.isDefined( + projectService.configuredProjects.get("/packages/a/tsconfig.json")!.getPackageJsonAutoImportProvider(), + ); + baselineTsserverLogs( + "autoImportProvider", + "Does not close when root files are redirects that dont actually exist", + session, + ); }); it("Can use the same document registry bucket key as main program", () => { for (const option of ts.sourceFileAffectingCompilerOptions) { assert( !ts.hasProperty(ts.server.AutoImportProviderProject.compilerOptionsOverrides, option.name), - `'${option.name}' may cause AutoImportProviderProject not to share source files with main program` + `'${option.name}' may cause AutoImportProviderProject not to share source files with main program`, ); } }); @@ -384,9 +482,9 @@ function setup(files: File[]) { arguments: { openFiles: [{ fileName: path, - content: newText - }] - } + content: newText, + }], + }, }); } @@ -397,8 +495,8 @@ function setup(files: File[]) { arguments: { file, line, - offset - } + offset, + }, }); } @@ -413,7 +511,7 @@ function setup(files: File[]) { arguments: { ...requestLocation, includeExternalModuleExports: true, - } + }, }); } } diff --git a/src/testRunner/unittests/tsserver/auxiliaryProject.ts b/src/testRunner/unittests/tsserver/auxiliaryProject.ts index 36f0e6cb45a69..65f99d06f0a29 100644 --- a/src/testRunner/unittests/tsserver/auxiliaryProject.ts +++ b/src/testRunner/unittests/tsserver/auxiliaryProject.ts @@ -12,15 +12,15 @@ import { const aTs: File = { path: "/a.ts", - content: `import { B } from "./b";` + content: `import { B } from "./b";`, }; const bDts: File = { path: "/b.d.ts", - content: `export declare class B {}` + content: `export declare class B {}`, }; const bJs: File = { path: "/b.js", - content: `export class B {}` + content: `export class B {}`, }; describe("unittests:: tsserver:: auxiliaryProject", () => { it("AuxiliaryProject does not remove scrips from InferredProject", () => { diff --git a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts index 250a9ffc94a8f..72a74fbf9d629 100644 --- a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts +++ b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts @@ -23,21 +23,23 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS fileExists = "fileExists", directoryExists = "directoryExists", getDirectories = "getDirectories", - readFile = "readFile" + readFile = "readFile", } enum CalledMapsWithFiveArgs { - readDirectory = "readDirectory" + readDirectory = "readDirectory", } type CalledMaps = CalledMapsWithSingleArg | CalledMapsWithFiveArgs; type CalledWithFiveArgs = [readonly string[], readonly string[], readonly string[], number]; function createLoggerTrackingHostCalls(host: TestServerHost) { - const calledMaps: Record> & Record> = { - fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists), - directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists), - getDirectories: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.getDirectories), - readFile: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.readFile), - readDirectory: setCallsTrackingWithFiveArgFn(CalledMapsWithFiveArgs.readDirectory) - }; + const calledMaps: + & Record> + & Record> = { + fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists), + directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists), + getDirectories: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.getDirectories), + readFile: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.readFile), + readDirectory: setCallsTrackingWithFiveArgFn(CalledMapsWithFiveArgs.readDirectory), + }; return logCacheAndClear; @@ -62,7 +64,10 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS } function logCacheEntry(logger: Logger, callback: CalledMaps) { - const result = Array.from<[string, (true | CalledWithFiveArgs)[]], { key: string, count: number }>(calledMaps[callback].entries(), ([key, arr]) => ({ key, count: arr.length })); + const result = Array.from<[string, (true | CalledWithFiveArgs)[]], { key: string; count: number; }>( + calledMaps[callback].entries(), + ([key, arr]) => ({ key, count: arr.length }), + ); logger.info(`${callback}:: ${JSON.stringify(result)}`); calledMaps[callback].clear(); } @@ -89,12 +94,12 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS let rootContent = `import {x} from "f1"`; const root: File = { path: "/c/d/f0.ts", - content: rootContent + content: rootContent, }; const imported: File = { path: "/c/f1.ts", - content: `foo()` + content: `foo()`, }; const host = createServerHost([root, imported]); @@ -133,7 +138,11 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS logCacheAndClear(projectService.logger); // setting compiler options discards module resolution cache - projectService.setCompilerOptionsForInferredProjects({ module: ts.ModuleKind.AMD, noLib: true, target: ts.ScriptTarget.ES5 }); + projectService.setCompilerOptionsForInferredProjects({ + module: ts.ModuleKind.AMD, + noLib: true, + target: ts.ScriptTarget.ES5, + }); logSemanticDiagnostics(projectService, project, imported); logCacheAndClear(projectService.logger); baselineTsserverLogs("cachingFileSystemInformation", "works using legacy resolution logic", projectService); @@ -147,12 +156,12 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS it("loads missing files from disk", () => { const root: File = { path: "/users/username/projects/project/foo.ts", - content: `import {y} from "bar"` + content: `import {y} from "bar"`, }; const imported: File = { path: "/users/username/projects/project/bar.d.ts", - content: `export var y = 1` + content: `export var y = 1`, }; const host = createServerHost([root]); @@ -180,18 +189,18 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS content: ` import { Vessel } from '~/models/vessel'; const v = new Vessel(); - ` + `, }; const anotherModuleFile: File = { path: "/a/b/utils/db.ts", - content: "export class Bookshelf { }" + content: "export class Bookshelf { }", }; const moduleFile: File = { path: "/a/b/models/vessel.ts", content: ` import { Bookshelf } from '~/utils/db'; export class Vessel extends Bookshelf {} - ` + `, }; const tsconfigFile: File = { path: "/a/b/tsconfig.json", @@ -199,10 +208,10 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS compilerOptions: { target: "es6", module: "es6", - baseUrl: "./", // all paths are relative to the baseUrl + baseUrl: "./", // all paths are relative to the baseUrl paths: { - "~/*": ["*"] // resolve any `~/foo/bar` to `/foo/bar` - } + "~/*": ["*"], // resolve any `~/foo/bar` to `/foo/bar` + }, }, exclude: [ "api", @@ -211,9 +220,9 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS "public", "seeds", "sql_updates", - "tests.build" - ] - }) + "tests.build", + ], + }), }; const projectFiles = [clientFile, anotherModuleFile, moduleFile, tsconfigFile]; const host = createServerHost(projectFiles); @@ -228,8 +237,8 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS file: clientFile.path, position: clientFile.content.indexOf("/vessel") + 1, line: undefined!, // TODO: GH#18217 - offset: undefined! // TODO: GH#18217 - } + offset: undefined!, // TODO: GH#18217 + }, }); logCacheAndClear(session.logger); @@ -246,19 +255,19 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS const frontendDir = "/Users/someuser/work/applications/frontend"; const file1: File = { path: `${frontendDir}/src/app/utils/Analytic.ts`, - content: "export class SomeClass { };" + content: "export class SomeClass { };", }; const file2: File = { path: `${frontendDir}/src/app/redux/configureStore.ts`, - content: "export class configureStore { }" + content: "export class configureStore { }", }; const file3: File = { path: `${frontendDir}/src/app/utils/Cookie.ts`, - content: "export class Cookie { }" + content: "export class Cookie { }", }; const es2016LibFile: File = { path: "/a/lib/lib.es2016.full.d.ts", - content: libFile.content + content: libFile.content, }; const typeRoots = ["types", "node_modules/@types"]; const types = ["node", "jest"]; @@ -282,18 +291,18 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS baseUrl: ".", paths: { "*": [ - "types/*" - ] - } + "types/*", + ], + }, }, include: [ - "src/**/*" + "src/**/*", ], exclude: [ "node_modules", - "compiled" - ] - }) + "compiled", + ], + }), }; const projectFiles = [file1, file2, es2016LibFile, tsconfigFile]; const host = createServerHost(projectFiles, { useCaseSensitiveFileNames }); @@ -309,7 +318,13 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS projectService.openClientFile(file3.path); logCacheAndClear(projectService.logger); - baselineTsserverLogs("cachingFileSystemInformation", `watchDirectories for config file with case ${useCaseSensitiveFileNames ? "" : "in"}sensitive file system`, projectService); + baselineTsserverLogs( + "cachingFileSystemInformation", + `watchDirectories for config file with case ${ + useCaseSensitiveFileNames ? "" : "in" + }sensitive file system`, + projectService, + ); }); } verifyWatchDirectoriesCaseSensitivity(/*useCaseSensitiveFileNames*/ false); @@ -321,18 +336,18 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS const projectLocation = "/users/username/projects/proj"; const file1: File = { path: `${projectLocation}/foo/boo/app.ts`, - content: `import * as debug from "debug"` + content: `import * as debug from "debug"`, }; const file2: File = { path: `${projectLocation}/foo/boo/moo/app.ts`, - content: `import * as debug from "debug"` + content: `import * as debug from "debug"`, }; const tsconfig: File = { path: `${projectLocation}/tsconfig.json`, content: JSON.stringify({ files: ["foo/boo/app.ts", "foo/boo/moo/app.ts"], - moduleResolution: resolution - }) + moduleResolution: resolution, + }), }; const files = [file1, file2, tsconfig, libFile]; @@ -346,7 +361,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS const debugTypesFile: File = { path: `${projectLocation}/node_modules/debug/index.d.ts`, - content: "export {}" + content: "export {}", }; host.writeFile(debugTypesFile.path, debugTypesFile.content); host.runQueuedTimeoutCallbacks(); // Scheduled invalidation of resolutions @@ -354,7 +369,11 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS logSemanticDiagnostics(service, project, file1); logSemanticDiagnostics(service, project, file2); - baselineTsserverLogs("cachingFileSystemInformation", `includes the parent folder FLLs in ${resolution} module resolution mode`, service); + baselineTsserverLogs( + "cachingFileSystemInformation", + `includes the parent folder FLLs in ${resolution} module resolution mode`, + service, + ); } it("Includes the parent folder FLLs in node module resolution mode", () => { @@ -374,11 +393,11 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS }; const app: File = getRootedFileOrFolder({ path: "/a/b/app.ts", - content: "import _ from 'lodash';" + content: "import _ from 'lodash';", }); const tsconfigJson: File = getRootedFileOrFolder({ path: "/a/b/tsconfig.json", - content: '{ "compilerOptions": { } }' + content: '{ "compilerOptions": { } }', }); const packageJson: File = getRootedFileOrFolder({ path: "/a/b/package.json", @@ -403,7 +422,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS "author": "", "license": "ISC" } -` +`, }); const host = createServerHost([app, libFile, tsconfigJson, packageJson]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -421,23 +440,56 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61" }, { path: "/a/b/node_modules/.staging/typescript-8493ea5d" }, - { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/package.json", content: "{\n \"name\": \"symbol-observable\",\n \"version\": \"1.0.4\",\n \"description\": \"Symbol.observable ponyfill\",\n \"license\": \"MIT\",\n \"repository\": \"blesh/symbol-observable\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"engines\": {\n \"node\": \">=0.10.0\"\n },\n \"scripts\": {\n \"test\": \"npm run build && mocha && tsc ./ts-test/test.ts && node ./ts-test/test.js && check-es3-syntax -p lib/ --kill\",\n \"build\": \"babel es --out-dir lib\",\n \"prepublish\": \"npm test\"\n },\n \"files\": [\n \"" }, - { path: "/a/b/node_modules/.staging/lodash-b0733faa/package.json", content: "{\n \"name\": \"lodash\",\n \"version\": \"4.17.4\",\n \"description\": \"Lodash modular utilities.\",\n \"keywords\": \"modules, stdlib, util\",\n \"homepage\": \"https://lodash.com/\",\n \"repository\": \"lodash/lodash\",\n \"icon\": \"https://lodash.com/icon.svg\",\n \"license\": \"MIT\",\n \"main\": \"lodash.js\",\n \"author\": \"John-David Dalton (http://allyoucanleet.com/)\",\n \"contributors\": [\n \"John-David Dalton (http://allyoucanleet.com/)\",\n \"Mathias Bynens \",\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"eslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"typings\": \"Rx.d.ts\",\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n }\n}" }, - { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json", content: "{\n \"name\": \"typescript\",\n \"author\": \"Microsoft Corp.\",\n \"homepage\": \"http://typescriptlang.org/\",\n \"version\": \"2.4.2\",\n \"license\": \"Apache-2.0\",\n \"description\": \"TypeScript is a language for application scale JavaScript development\",\n \"keywords\": [\n \"TypeScript\",\n \"Microsoft\",\n \"compiler\",\n \"language\",\n \"javascript\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/Microsoft/TypeScript/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/Microsoft/TypeScript.git\"\n },\n \"main\": \"./lib/typescript.js\",\n \"typings\": \"./lib/typescript.d.ts\",\n \"bin\": {\n \"tsc\": \"./bin/tsc\",\n \"tsserver\": \"./bin/tsserver\"\n },\n \"engines\": {\n \"node\": \">=4.2.0\"\n },\n \"devDependencies\": {\n \"@types/browserify\": \"latest\",\n \"@types/chai\": \"latest\",\n \"@types/convert-source-map\": \"latest\",\n \"@types/del\": \"latest\",\n \"@types/glob\": \"latest\",\n \"@types/gulp\": \"latest\",\n \"@types/gulp-concat\": \"latest\",\n \"@types/gulp-help\": \"latest\",\n \"@types/gulp-newer\": \"latest\",\n \"@types/gulp-sourcemaps\": \"latest\",\n \"@types/merge2\": \"latest\",\n \"@types/minimatch\": \"latest\",\n \"@types/minimist\": \"latest\",\n \"@types/mkdirp\": \"latest\",\n \"@types/mocha\": \"latest\",\n \"@types/node\": \"latest\",\n \"@types/q\": \"latest\",\n \"@types/run-sequence\": \"latest\",\n \"@types/through2\": \"latest\",\n \"browserify\": \"latest\",\n \"chai\": \"latest\",\n \"convert-source-map\": \"latest\",\n \"del\": \"latest\",\n \"gulp\": \"latest\",\n \"gulp-clone\": \"latest\",\n \"gulp-concat\": \"latest\",\n \"gulp-help\": \"latest\",\n \"gulp-insert\": \"latest\",\n \"gulp-newer\": \"latest\",\n \"gulp-sourcemaps\": \"latest\",\n \"gulp-typescript\": \"latest\",\n \"into-stream\": \"latest\",\n \"istanbul\": \"latest\",\n \"jake\": \"latest\",\n \"merge2\": \"latest\",\n \"minimist\": \"latest\",\n \"mkdirp\": \"latest\",\n \"mocha\": \"latest\",\n \"mocha-fivemat-progress-reporter\": \"latest\",\n \"q\": \"latest\",\n \"run-sequence\": \"latest\",\n \"sorcery\": \"latest\",\n \"through2\": \"latest\",\n \"travis-fold\": \"latest\",\n \"ts-node\": \"latest\",\n \"eslint\": \"5.16.0\",\n \"typescript\": \"^2.4\"\n },\n \"scripts\": {\n \"pretest\": \"jake tests\",\n \"test\": \"jake runtests-parallel\",\n \"build\": \"npm run build:compiler && npm run build:tests\",\n \"build:compiler\": \"jake local\",\n \"build:tests\": \"jake tests\",\n \"start\": \"node lib/tsc\",\n \"clean\": \"jake clean\",\n \"gulp\": \"gulp\",\n \"jake\": \"jake\",\n \"lint\": \"jake lint\",\n \"setup-hooks\": \"node scripts/link-hooks.js\"\n },\n \"browser\": {\n \"buffer\": false,\n \"fs\": false,\n \"os\": false,\n \"path\": false\n }\n}" }, - { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.js", content: "module.exports = require('./lib/index');\n" }, - { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.d.ts", content: "declare const observableSymbol: symbol;\nexport default observableSymbol;\n" }, + { + path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/package.json", + content: + '{\n "name": "symbol-observable",\n "version": "1.0.4",\n "description": "Symbol.observable ponyfill",\n "license": "MIT",\n "repository": "blesh/symbol-observable",\n "author": {\n "name": "Ben Lesh",\n "email": "ben@benlesh.com"\n },\n "engines": {\n "node": ">=0.10.0"\n },\n "scripts": {\n "test": "npm run build && mocha && tsc ./ts-test/test.ts && node ./ts-test/test.js && check-es3-syntax -p lib/ --kill",\n "build": "babel es --out-dir lib",\n "prepublish": "npm test"\n },\n "files": [\n "', + }, + { + path: "/a/b/node_modules/.staging/lodash-b0733faa/package.json", + content: + '{\n "name": "lodash",\n "version": "4.17.4",\n "description": "Lodash modular utilities.",\n "keywords": "modules, stdlib, util",\n "homepage": "https://lodash.com/",\n "repository": "lodash/lodash",\n "icon": "https://lodash.com/icon.svg",\n "license": "MIT",\n "main": "lodash.js",\n "author": "John-David Dalton (http://allyoucanleet.com/)",\n "contributors": [\n "John-David Dalton (http://allyoucanleet.com/)",\n "Mathias Bynens ",\n "contributors": [\n {\n "name": "Ben Lesh",\n "email": "ben@benlesh.com"\n },\n {\n "name": "Paul Taylor",\n "email": "paul.e.taylor@me.com"\n },\n {\n "name": "Jeff Cross",\n "email": "crossj@google.com"\n },\n {\n "name": "Matthew Podwysocki",\n "email": "matthewp@microsoft.com"\n },\n {\n "name": "OJ Kwon",\n "email": "kwon.ohjoong@gmail.com"\n },\n {\n "name": "Andre Staltz",\n "email": "andre@staltz.com"\n }\n ],\n "license": "Apache-2.0",\n "bugs": {\n "url": "https://github.com/ReactiveX/RxJS/issues"\n },\n "homepage": "https://github.com/ReactiveX/RxJS",\n "devDependencies": {\n "babel-polyfill": "^6.23.0",\n "benchmark": "^2.1.0",\n "benchpress": "2.0.0-beta.1",\n "chai": "^3.5.0",\n "color": "^0.11.1",\n "colors": "1.1.2",\n "commitizen": "^2.8.6",\n "coveralls": "^2.11.13",\n "cz-conventional-changelog": "^1.2.0",\n "danger": "^1.1.0",\n "doctoc": "^1.0.0",\n "escape-string-regexp": "^1.0.5 ",\n "esdoc": "^0.4.7",\n "eslint": "^3.8.0",\n "fs-extra": "^2.1.2",\n "get-folder-size": "^1.0.0",\n "glob": "^7.0.3",\n "gm": "^1.22.0",\n "google-closure-compiler-js": "^20170218.0.0",\n "gzip-size": "^3.0.0",\n "http-server": "^0.9.0",\n "husky": "^0.13.3",\n "lint-staged": "3.2.5",\n "lodash": "^4.15.0",\n "madge": "^1.4.3",\n "markdown-doctest": "^0.9.1",\n "minimist": "^1.2.0",\n "mkdirp": "^0.5.1",\n "mocha": "^3.0.2",\n "mocha-in-sauce": "0.0.1",\n "npm-run-all": "^4.0.2",\n "npm-scripts-info": "^0.3.4",\n "nyc": "^10.2.0",\n "opn-cli": "^3.1.0",\n "platform": "^1.3.1",\n "promise": "^7.1.1",\n "protractor": "^3.1.1",\n "rollup": "0.36.3",\n "rollup-plugin-inject": "^2.0.0",\n "rollup-plugin-node-resolve": "^2.0.0",\n "rx": "latest",\n "rxjs": "latest",\n "shx": "^0.2.2",\n "sinon": "^2.1.0",\n "sinon-chai": "^2.9.0",\n "source-map-support": "^0.4.0",\n "tslib": "^1.5.0",\n "eslint": "^4.4.2",\n "typescript": "~2.0.6",\n "typings": "^2.0.0",\n "validate-commit-msg": "^2.14.0",\n "watch": "^1.0.1",\n "webpack": "^1.13.1",\n "xmlhttprequest": "1.8.0"\n },\n "engines": {\n "npm": ">=2.0.0"\n },\n "typings": "Rx.d.ts",\n "dependencies": {\n "symbol-observable": "^1.0.1"\n }\n}', + }, + { + path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json", + content: + '{\n "name": "typescript",\n "author": "Microsoft Corp.",\n "homepage": "http://typescriptlang.org/",\n "version": "2.4.2",\n "license": "Apache-2.0",\n "description": "TypeScript is a language for application scale JavaScript development",\n "keywords": [\n "TypeScript",\n "Microsoft",\n "compiler",\n "language",\n "javascript"\n ],\n "bugs": {\n "url": "https://github.com/Microsoft/TypeScript/issues"\n },\n "repository": {\n "type": "git",\n "url": "https://github.com/Microsoft/TypeScript.git"\n },\n "main": "./lib/typescript.js",\n "typings": "./lib/typescript.d.ts",\n "bin": {\n "tsc": "./bin/tsc",\n "tsserver": "./bin/tsserver"\n },\n "engines": {\n "node": ">=4.2.0"\n },\n "devDependencies": {\n "@types/browserify": "latest",\n "@types/chai": "latest",\n "@types/convert-source-map": "latest",\n "@types/del": "latest",\n "@types/glob": "latest",\n "@types/gulp": "latest",\n "@types/gulp-concat": "latest",\n "@types/gulp-help": "latest",\n "@types/gulp-newer": "latest",\n "@types/gulp-sourcemaps": "latest",\n "@types/merge2": "latest",\n "@types/minimatch": "latest",\n "@types/minimist": "latest",\n "@types/mkdirp": "latest",\n "@types/mocha": "latest",\n "@types/node": "latest",\n "@types/q": "latest",\n "@types/run-sequence": "latest",\n "@types/through2": "latest",\n "browserify": "latest",\n "chai": "latest",\n "convert-source-map": "latest",\n "del": "latest",\n "gulp": "latest",\n "gulp-clone": "latest",\n "gulp-concat": "latest",\n "gulp-help": "latest",\n "gulp-insert": "latest",\n "gulp-newer": "latest",\n "gulp-sourcemaps": "latest",\n "gulp-typescript": "latest",\n "into-stream": "latest",\n "istanbul": "latest",\n "jake": "latest",\n "merge2": "latest",\n "minimist": "latest",\n "mkdirp": "latest",\n "mocha": "latest",\n "mocha-fivemat-progress-reporter": "latest",\n "q": "latest",\n "run-sequence": "latest",\n "sorcery": "latest",\n "through2": "latest",\n "travis-fold": "latest",\n "ts-node": "latest",\n "eslint": "5.16.0",\n "typescript": "^2.4"\n },\n "scripts": {\n "pretest": "jake tests",\n "test": "jake runtests-parallel",\n "build": "npm run build:compiler && npm run build:tests",\n "build:compiler": "jake local",\n "build:tests": "jake tests",\n "start": "node lib/tsc",\n "clean": "jake clean",\n "gulp": "gulp",\n "jake": "jake",\n "lint": "jake lint",\n "setup-hooks": "node scripts/link-hooks.js"\n },\n "browser": {\n "buffer": false,\n "fs": false,\n "os": false,\n "path": false\n }\n}', + }, + { + path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.js", + content: "module.exports = require('./lib/index');\n", + }, + { + path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.d.ts", + content: "declare const observableSymbol: symbol;\nexport default observableSymbol;\n", + }, { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib" }, - { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib/index.js", content: "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _ponyfill = require('./ponyfill');\n\nvar _ponyfill2 = _interopRequireDefault(_ponyfill);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar root; /* global window */\n\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = (0, _ponyfill2['default'])(root);\nexports['default'] = result;" }, + { + path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib/index.js", + content: + "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _ponyfill = require('./ponyfill');\n\nvar _ponyfill2 = _interopRequireDefault(_ponyfill);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar root; /* global window */\n\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = (0, _ponyfill2['default'])(root);\nexports['default'] = result;", + }, ].map(getRootedFileOrFolder); verifyAfterPartialOrCompleteNpmInstall(); filesAndFoldersToAdd.push(...[ { path: "/a/b/node_modules/.staging/typescript-8493ea5d/lib" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61/add/operator" }, - { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/package.json", content: "{\n \"name\": \"@types/lodash\",\n \"version\": \"4.14.74\",\n \"description\": \"TypeScript definitions for Lo-Dash\",\n \"license\": \"MIT\",\n \"contributors\": [\n {\n \"name\": \"Brian Zengel\",\n \"url\": \"https://github.com/bczengel\"\n },\n {\n \"name\": \"Ilya Mochalov\",\n \"url\": \"https://github.com/chrootsu\"\n },\n {\n \"name\": \"Stepan Mikhaylyuk\",\n \"url\": \"https://github.com/stepancar\"\n },\n {\n \"name\": \"Eric L Anderson\",\n \"url\": \"https://github.com/ericanderson\"\n },\n {\n \"name\": \"AJ Richardson\",\n \"url\": \"https://github.com/aj-r\"\n },\n {\n \"name\": \"Junyoung Clare Jang\",\n \"url\": \"https://github.com/ailrun\"\n }\n ],\n \"main\": \"\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://www.github.com/DefinitelyTyped/DefinitelyTyped.git\"\n },\n \"scripts\": {},\n \"dependencies\": {},\n \"typesPublisherContentHash\": \"12af578ffaf8d86d2df37e591857906a86b983fa9258414326544a0fe6af0de8\",\n \"typeScriptVersion\": \"2.2\"\n}" }, - { path: "/a/b/node_modules/.staging/lodash-b0733faa/index.js", content: "module.exports = require('./lodash');" }, - { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594", content: "" } + { + path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/package.json", + content: + '{\n "name": "@types/lodash",\n "version": "4.14.74",\n "description": "TypeScript definitions for Lo-Dash",\n "license": "MIT",\n "contributors": [\n {\n "name": "Brian Zengel",\n "url": "https://github.com/bczengel"\n },\n {\n "name": "Ilya Mochalov",\n "url": "https://github.com/chrootsu"\n },\n {\n "name": "Stepan Mikhaylyuk",\n "url": "https://github.com/stepancar"\n },\n {\n "name": "Eric L Anderson",\n "url": "https://github.com/ericanderson"\n },\n {\n "name": "AJ Richardson",\n "url": "https://github.com/aj-r"\n },\n {\n "name": "Junyoung Clare Jang",\n "url": "https://github.com/ailrun"\n }\n ],\n "main": "",\n "repository": {\n "type": "git",\n "url": "https://www.github.com/DefinitelyTyped/DefinitelyTyped.git"\n },\n "scripts": {},\n "dependencies": {},\n "typesPublisherContentHash": "12af578ffaf8d86d2df37e591857906a86b983fa9258414326544a0fe6af0de8",\n "typeScriptVersion": "2.2"\n}', + }, + { + path: "/a/b/node_modules/.staging/lodash-b0733faa/index.js", + content: "module.exports = require('./lodash');", + }, + { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594", content: "" }, ].map(getRootedFileOrFolder)); // Since we added/removed in .staging no timeout verifyAfterPartialOrCompleteNpmInstall(); @@ -451,7 +503,11 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS { path: "/a/b/node_modules/.staging/rxjs-22375c61/bundles" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61/operator" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/add/observable/dom" }, - { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/index.d.ts", content: "\n// Stub for lodash\nexport = _;\nexport as namespace _;\ndeclare var _: _.LoDashStatic;\ndeclare namespace _ {\n interface LoDashStatic {\n someProp: string;\n }\n class SomeClass {\n someMethod(): void;\n }\n}" } + { + path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/index.d.ts", + content: + "\n// Stub for lodash\nexport = _;\nexport as namespace _;\ndeclare var _: _.LoDashStatic;\ndeclare namespace _ {\n interface LoDashStatic {\n someProp: string;\n }\n class SomeClass {\n someMethod(): void;\n }\n}", + }, ].map(getRootedFileOrFolder)); verifyAfterPartialOrCompleteNpmInstall(); @@ -460,7 +516,11 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/util" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61/symbol" }, { path: "/a/b/node_modules/.staging/rxjs-22375c61/testing" }, - { path: "/a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041", content: "{\n \"_args\": [\n [\n {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\"\n ]\n ],\n \"_from\": \"rxjs@>=5.4.2 <6.0.0\",\n \"_id\": \"rxjs@5.4.3\",\n \"_inCache\": true,\n \"_location\": \"/rxjs\",\n \"_nodeVersion\": \"7.7.2\",\n \"_npmOperationalInternal\": {\n \"host\": \"s3://npm-registry-packages\",\n \"tmp\": \"tmp/rxjs-5.4.3.tgz_1502407898166_0.6800217325799167\"\n },\n \"_npmUser\": {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"_npmVersion\": \"5.3.0\",\n \"_phantomChildren\": {},\n \"_requested\": {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"_requiredBy\": [\n \"/\"\n ],\n \"_resolved\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\",\n \"_shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"_shrinkwrap\": null,\n \"_spec\": \"rxjs@^5.4.2\",\n \"_where\": \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"config\": {\n \"commitizen\": {\n \"path\": \"cz-conventional-changelog\"\n }\n },\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n },\n \"description\": \"Reactive Extensions for modern JavaScript\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"eslint\": \"^5.16.0\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"directories\": {},\n \"dist\": {\n \"integrity\": \"sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==\",\n \"shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"tarball\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"keywords\": [\n \"Rx\",\n \"RxJS\",\n \"ReactiveX\",\n \"ReactiveExtensions\",\n \"Streams\",\n \"Observables\",\n \"Observable\",\n \"Stream\",\n \"ES6\",\n \"ES2015\"\n ],\n \"license\": \"Apache-2.0\",\n \"lint-staged\": {\n \"*.@(js)\": [\n \"eslint --fix\",\n \"git add\"\n ],\n \"*.@(ts)\": [\n \"eslint -c .eslintrc --ext .ts . --fix\",\n \"git add\"\n ]\n },\n \"main\": \"Rx.js\",\n \"maintainers\": [\n {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n }\n ],\n \"name\": \"rxjs\",\n \"optionalDependencies\": {},\n \"readme\": \"ERROR: No README data found!\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+ssh://git@github.com/ReactiveX/RxJS.git\"\n },\n \"scripts-info\": {\n \"info\": \"List available script\",\n \"build_all\": \"Build all packages (ES6, CJS, UMD) and generate packages\",\n \"build_cjs\": \"Build CJS package with clean up existing build, copy source into dist\",\n \"build_es6\": \"Build ES6 package with clean up existing build, copy source into dist\",\n \"build_closure_core\": \"Minify Global core build using closure compiler\",\n \"build_global\": \"Build Global package, then minify build\",\n \"build_perf\": \"Build CJS & Global build, run macro performance test\",\n \"build_test\": \"Build CJS package & test spec, execute mocha test runner\",\n \"build_cover\": \"Run lint to current code, build CJS & test spec, execute test coverage\",\n \"build_docs\": \"Build ES6 & global package, create documentation using it\",\n \"build_spec\": \"Build test specs\",\n \"check_circular_dependencies\": \"Check codebase has circular dependencies\",\n \"clean_spec\": \"Clean up existing test spec build output\",\n \"clean_dist_cjs\": \"Clean up existing CJS package output\",\n \"clean_dist_es6\": \"Clean up existing ES6 package output\",\n \"clean_dist_global\": \"Clean up existing Global package output\",\n \"commit\": \"Run git commit wizard\",\n \"compile_dist_cjs\": \"Compile codebase into CJS module\",\n \"compile_module_es6\": \"Compile codebase into ES6\",\n \"cover\": \"Execute test coverage\",\n \"lint_perf\": \"Run lint against performance test suite\",\n \"lint_spec\": \"Run lint against test spec\",\n \"lint_src\": \"Run lint against source\",\n \"lint\": \"Run lint against everything\",\n \"perf\": \"Run macro performance benchmark\",\n \"perf_micro\": \"Run micro performance benchmark\",\n \"test_mocha\": \"Execute mocha test runner against existing test spec build\",\n \"test_browser\": \"Execute mocha test runner on browser against existing test spec build\",\n \"test\": \"Clean up existing test spec build, build test spec and execute mocha test runner\",\n \"tests2png\": \"Generate marble diagram image from test spec\",\n \"watch\": \"Watch codebase, trigger compile when source code changes\"\n },\n \"typings\": \"Rx.d.ts\",\n \"version\": \"5.4.3\"\n}\n" } + { + path: "/a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041", + content: + '{\n "_args": [\n [\n {\n "raw": "rxjs@^5.4.2",\n "scope": null,\n "escapedName": "rxjs",\n "name": "rxjs",\n "rawSpec": "^5.4.2",\n "spec": ">=5.4.2 <6.0.0",\n "type": "range"\n },\n "C:\\\\Users\\\\shkamat\\\\Desktop\\\\app"\n ]\n ],\n "_from": "rxjs@>=5.4.2 <6.0.0",\n "_id": "rxjs@5.4.3",\n "_inCache": true,\n "_location": "/rxjs",\n "_nodeVersion": "7.7.2",\n "_npmOperationalInternal": {\n "host": "s3://npm-registry-packages",\n "tmp": "tmp/rxjs-5.4.3.tgz_1502407898166_0.6800217325799167"\n },\n "_npmUser": {\n "name": "blesh",\n "email": "ben@benlesh.com"\n },\n "_npmVersion": "5.3.0",\n "_phantomChildren": {},\n "_requested": {\n "raw": "rxjs@^5.4.2",\n "scope": null,\n "escapedName": "rxjs",\n "name": "rxjs",\n "rawSpec": "^5.4.2",\n "spec": ">=5.4.2 <6.0.0",\n "type": "range"\n },\n "_requiredBy": [\n "/"\n ],\n "_resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz",\n "_shasum": "0758cddee6033d68e0fd53676f0f3596ce3d483f",\n "_shrinkwrap": null,\n "_spec": "rxjs@^5.4.2",\n "_where": "C:\\\\Users\\\\shkamat\\\\Desktop\\\\app",\n "author": {\n "name": "Ben Lesh",\n "email": "ben@benlesh.com"\n },\n "bugs": {\n "url": "https://github.com/ReactiveX/RxJS/issues"\n },\n "config": {\n "commitizen": {\n "path": "cz-conventional-changelog"\n }\n },\n "contributors": [\n {\n "name": "Ben Lesh",\n "email": "ben@benlesh.com"\n },\n {\n "name": "Paul Taylor",\n "email": "paul.e.taylor@me.com"\n },\n {\n "name": "Jeff Cross",\n "email": "crossj@google.com"\n },\n {\n "name": "Matthew Podwysocki",\n "email": "matthewp@microsoft.com"\n },\n {\n "name": "OJ Kwon",\n "email": "kwon.ohjoong@gmail.com"\n },\n {\n "name": "Andre Staltz",\n "email": "andre@staltz.com"\n }\n ],\n "dependencies": {\n "symbol-observable": "^1.0.1"\n },\n "description": "Reactive Extensions for modern JavaScript",\n "devDependencies": {\n "babel-polyfill": "^6.23.0",\n "benchmark": "^2.1.0",\n "benchpress": "2.0.0-beta.1",\n "chai": "^3.5.0",\n "color": "^0.11.1",\n "colors": "1.1.2",\n "commitizen": "^2.8.6",\n "coveralls": "^2.11.13",\n "cz-conventional-changelog": "^1.2.0",\n "danger": "^1.1.0",\n "doctoc": "^1.0.0",\n "escape-string-regexp": "^1.0.5 ",\n "esdoc": "^0.4.7",\n "eslint": "^3.8.0",\n "fs-extra": "^2.1.2",\n "get-folder-size": "^1.0.0",\n "glob": "^7.0.3",\n "gm": "^1.22.0",\n "google-closure-compiler-js": "^20170218.0.0",\n "gzip-size": "^3.0.0",\n "http-server": "^0.9.0",\n "husky": "^0.13.3",\n "lint-staged": "3.2.5",\n "lodash": "^4.15.0",\n "madge": "^1.4.3",\n "markdown-doctest": "^0.9.1",\n "minimist": "^1.2.0",\n "mkdirp": "^0.5.1",\n "mocha": "^3.0.2",\n "mocha-in-sauce": "0.0.1",\n "npm-run-all": "^4.0.2",\n "npm-scripts-info": "^0.3.4",\n "nyc": "^10.2.0",\n "opn-cli": "^3.1.0",\n "platform": "^1.3.1",\n "promise": "^7.1.1",\n "protractor": "^3.1.1",\n "rollup": "0.36.3",\n "rollup-plugin-inject": "^2.0.0",\n "rollup-plugin-node-resolve": "^2.0.0",\n "rx": "latest",\n "rxjs": "latest",\n "shx": "^0.2.2",\n "sinon": "^2.1.0",\n "sinon-chai": "^2.9.0",\n "source-map-support": "^0.4.0",\n "tslib": "^1.5.0",\n "eslint": "^5.16.0",\n "typescript": "~2.0.6",\n "typings": "^2.0.0",\n "validate-commit-msg": "^2.14.0",\n "watch": "^1.0.1",\n "webpack": "^1.13.1",\n "xmlhttprequest": "1.8.0"\n },\n "directories": {},\n "dist": {\n "integrity": "sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==",\n "shasum": "0758cddee6033d68e0fd53676f0f3596ce3d483f",\n "tarball": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz"\n },\n "engines": {\n "npm": ">=2.0.0"\n },\n "homepage": "https://github.com/ReactiveX/RxJS",\n "keywords": [\n "Rx",\n "RxJS",\n "ReactiveX",\n "ReactiveExtensions",\n "Streams",\n "Observables",\n "Observable",\n "Stream",\n "ES6",\n "ES2015"\n ],\n "license": "Apache-2.0",\n "lint-staged": {\n "*.@(js)": [\n "eslint --fix",\n "git add"\n ],\n "*.@(ts)": [\n "eslint -c .eslintrc --ext .ts . --fix",\n "git add"\n ]\n },\n "main": "Rx.js",\n "maintainers": [\n {\n "name": "blesh",\n "email": "ben@benlesh.com"\n }\n ],\n "name": "rxjs",\n "optionalDependencies": {},\n "readme": "ERROR: No README data found!",\n "repository": {\n "type": "git",\n "url": "git+ssh://git@github.com/ReactiveX/RxJS.git"\n },\n "scripts-info": {\n "info": "List available script",\n "build_all": "Build all packages (ES6, CJS, UMD) and generate packages",\n "build_cjs": "Build CJS package with clean up existing build, copy source into dist",\n "build_es6": "Build ES6 package with clean up existing build, copy source into dist",\n "build_closure_core": "Minify Global core build using closure compiler",\n "build_global": "Build Global package, then minify build",\n "build_perf": "Build CJS & Global build, run macro performance test",\n "build_test": "Build CJS package & test spec, execute mocha test runner",\n "build_cover": "Run lint to current code, build CJS & test spec, execute test coverage",\n "build_docs": "Build ES6 & global package, create documentation using it",\n "build_spec": "Build test specs",\n "check_circular_dependencies": "Check codebase has circular dependencies",\n "clean_spec": "Clean up existing test spec build output",\n "clean_dist_cjs": "Clean up existing CJS package output",\n "clean_dist_es6": "Clean up existing ES6 package output",\n "clean_dist_global": "Clean up existing Global package output",\n "commit": "Run git commit wizard",\n "compile_dist_cjs": "Compile codebase into CJS module",\n "compile_module_es6": "Compile codebase into ES6",\n "cover": "Execute test coverage",\n "lint_perf": "Run lint against performance test suite",\n "lint_spec": "Run lint against test spec",\n "lint_src": "Run lint against source",\n "lint": "Run lint against everything",\n "perf": "Run macro performance benchmark",\n "perf_micro": "Run micro performance benchmark",\n "test_mocha": "Execute mocha test runner against existing test spec build",\n "test_browser": "Execute mocha test runner on browser against existing test spec build",\n "test": "Clean up existing test spec build, build test spec and execute mocha test runner",\n "tests2png": "Generate marble diagram image from test spec",\n "watch": "Watch codebase, trigger compile when source code changes"\n },\n "typings": "Rx.d.ts",\n "version": "5.4.3"\n}\n', + }, ].map(getRootedFileOrFolder)); verifyAfterPartialOrCompleteNpmInstall(); @@ -475,7 +535,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS { path: "/a/b/node_modules/lodash" }, { path: "/a/b/node_modules/rxjs" }, { path: "/a/b/node_modules/typescript" }, - { path: "/a/b/node_modules/.bin" } + { path: "/a/b/node_modules/.bin" }, ].map(getRootedFileOrFolder)); // From the type root update verifyAfterPartialOrCompleteNpmInstall(); @@ -493,8 +553,11 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS baselineTsserverLogs( "cachingFileSystemInformation", - `npm install works when ${timeoutDuringPartialInstallation ? "timeout occurs inbetween installation" : "timeout occurs after installation"}`, - projectService + `npm install works when ${ + timeoutDuringPartialInstallation ? "timeout occurs inbetween installation" + : "timeout occurs after installation" + }`, + projectService, ); function verifyAfterPartialOrCompleteNpmInstall() { @@ -521,11 +584,11 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS const projectLocation = "/user/username/folder/myproject"; const app: File = { path: `${projectLocation}/app.ts`, - content: `import * as debug from "debug"` + content: `import * as debug from "debug"`, }; const tsconfig: File = { path: `${projectLocation}/tsconfig.json`, - content: "" + content: "", }; const files = [app, tsconfig, libFile]; @@ -538,7 +601,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS const debugTypesFile: File = { path: `${projectLocation}/node_modules/@types/debug/index.d.ts`, - content: "export {}" + content: "export {}", }; // Do not invoke recursive directory watcher for anything other than node_module/@types const invoker = host.invokeFsWatchesRecursiveCallbacks; @@ -550,17 +613,21 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS host.writeFile(debugTypesFile.path, debugTypesFile.content); host.runQueuedTimeoutCallbacks(); logSemanticDiagnostics(service, project, app); - baselineTsserverLogs("cachingFileSystemInformation", "when node_modules dont receive event for the @types file addition", service); + baselineTsserverLogs( + "cachingFileSystemInformation", + "when node_modules dont receive event for the @types file addition", + service, + ); }); it("when creating new file in symlinked folder", () => { const module1: File = { path: `/user/username/projects/myproject/client/folder1/module1.ts`, - content: `export class Module1Class { }` + content: `export class Module1Class { }`, }; const module2: File = { path: `/user/username/projects/myproject/folder2/module2.ts`, - content: `import * as M from "folder1/module1";` + content: `import * as M from "folder1/module1";`, }; const symlink: SymLink = { path: `/user/username/projects/myproject/client/linktofolder2`, @@ -573,8 +640,8 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS baseUrl: "client", paths: { "*": ["*"] }, }, - include: ["client/**/*", "folder2"] - }) + include: ["client/**/*", "folder2"], + }), }; const host = createServerHost([module1, module2, symlink, config, libFile]); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); diff --git a/src/testRunner/unittests/tsserver/cancellationToken.ts b/src/testRunner/unittests/tsserver/cancellationToken.ts index b095bd690de59..67643a4d02143 100644 --- a/src/testRunner/unittests/tsserver/cancellationToken.ts +++ b/src/testRunner/unittests/tsserver/cancellationToken.ts @@ -6,7 +6,9 @@ import { TestServerCancellationToken, TestSessionRequest, } from "../helpers/tsserver"; -import { createServerHost } from "../helpers/virtualFileSystemWithWatch"; +import { + createServerHost, +} from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: tsserver:: cancellationToken", () => { // Disable sourcemap support for the duration of the test, as sourcemapping the errors generated during this test is slow and not something we care to test @@ -23,30 +25,31 @@ describe("unittests:: tsserver:: cancellationToken", () => { it("is attached to request", () => { const f1 = { path: "/a/b/app.ts", - content: "let xyz = 1;" + content: "let xyz = 1;", }; const host = createServerHost([f1]); const cancellationToken: ts.server.ServerCancellationToken = { isCancellationRequested: () => false, - setRequest: requestId => session.logger.log(`ServerCancellationToken:: Cancellation Request id:: ${requestId}`), - resetRequest: ts.noop + setRequest: requestId => + session.logger.log(`ServerCancellationToken:: Cancellation Request id:: ${requestId}`), + resetRequest: ts.noop, }; const session = createSession(host, { cancellationToken, logger: createLoggerWithInMemoryLogs(host) }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Open, - arguments: { file: f1.path } + arguments: { file: f1.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Geterr, - arguments: { files: [f1.path], delay: 0 } + arguments: { files: [f1.path], delay: 0 }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DocumentHighlights, - arguments: { file: f1.path, line: 1, offset: 6, filesToSearch: [f1.path] } + arguments: { file: f1.path, line: 1, offset: 6, filesToSearch: [f1.path] }, }); host.runQueuedTimeoutCallbacks(); @@ -58,13 +61,13 @@ describe("unittests:: tsserver:: cancellationToken", () => { it("Geterr is cancellable", () => { const f1 = { path: "/a/app.ts", - content: "let x = 1" + content: "let x = 1", }; const config = { path: "/a/tsconfig.json", content: JSON.stringify({ - compilerOptions: {} - }) + compilerOptions: {}, + }), }; const host = createServerHost([f1, config]); @@ -79,12 +82,12 @@ describe("unittests:: tsserver:: cancellationToken", () => { { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Open, - arguments: { file: f1.path } + arguments: { file: f1.path }, }); // send geterr for missing file session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Geterr, - arguments: { files: ["/a/missing"], delay: 0 } + arguments: { files: ["/a/missing"], delay: 0 }, }); // Queued files host.runQueuedTimeoutCallbacks(); @@ -95,13 +98,13 @@ describe("unittests:: tsserver:: cancellationToken", () => { // send geterr for a valid file session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Geterr, - arguments: { files: [f1.path], delay: 0 } + arguments: { files: [f1.path], delay: 0 }, }); // run new request session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.ProjectInfo, - arguments: { file: f1.path, needFileNameList: false } + arguments: { file: f1.path, needFileNameList: false }, }); // cancel previously issued Geterr @@ -113,7 +116,7 @@ describe("unittests:: tsserver:: cancellationToken", () => { const getErrId = session.getNextSeq(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Geterr, - arguments: { files: [f1.path], delay: 0 } + arguments: { files: [f1.path], delay: 0 }, }); // run first step @@ -127,7 +130,7 @@ describe("unittests:: tsserver:: cancellationToken", () => { { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Geterr, - arguments: { files: [f1.path], delay: 0 } + arguments: { files: [f1.path], delay: 0 }, }); // run first step host.runQueuedTimeoutCallbacks(); @@ -139,13 +142,13 @@ describe("unittests:: tsserver:: cancellationToken", () => { { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Geterr, - arguments: { files: [f1.path], delay: 0 } + arguments: { files: [f1.path], delay: 0 }, }); // run first step host.runQueuedTimeoutCallbacks(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Geterr, - arguments: { files: [f1.path], delay: 0 } + arguments: { files: [f1.path], delay: 0 }, }); // make sure that getErr1 is completed } @@ -155,13 +158,13 @@ describe("unittests:: tsserver:: cancellationToken", () => { it("Lower priority tasks are cancellable", () => { const f1 = { path: "/a/app.ts", - content: `{ let x = 1; } var foo = "foo"; var bar = "bar"; var fooBar = "fooBar";` + content: `{ let x = 1; } var foo = "foo"; var bar = "bar"; var fooBar = "fooBar";`, }; const config = { path: "/a/tsconfig.json", content: JSON.stringify({ - compilerOptions: {} - }) + compilerOptions: {}, + }), }; const host = createServerHost([f1, config]); const logger = createLoggerWithInMemoryLogs(host); @@ -176,36 +179,38 @@ describe("unittests:: tsserver:: cancellationToken", () => { { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Open, - arguments: { file: f1.path } + arguments: { file: f1.path }, }); // send navbar request (normal priority) session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.NavBar, - arguments: { file: f1.path } + arguments: { file: f1.path }, }); // ensure the nav bar request can be canceled verifyExecuteCommandSeqIsCancellable({ command: ts.server.protocol.CommandTypes.NavBar, - arguments: { file: f1.path } + arguments: { file: f1.path }, }); // send outlining spans request (normal priority) session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetOutliningSpansFull, - arguments: { file: f1.path } + arguments: { file: f1.path }, }); // ensure the outlining spans request can be canceled verifyExecuteCommandSeqIsCancellable({ command: ts.server.protocol.CommandTypes.GetOutliningSpansFull, - arguments: { file: f1.path } + arguments: { file: f1.path }, }); } baselineTsserverLogs("cancellationT", "Lower priority tasks are cancellable", session); - function verifyExecuteCommandSeqIsCancellable(request: TestSessionRequest) { + function verifyExecuteCommandSeqIsCancellable( + request: TestSessionRequest, + ) { // Set the next request to be cancellable // The cancellation token will cancel the request the third time // isCancellationRequested() is called. @@ -216,10 +221,14 @@ describe("unittests:: tsserver:: cancellationToken", () => { session.executeCommandSeq(request); } catch (e) { - session.logger.log(`Exception is OperationCanceledException: ${e instanceof ts.OperationCanceledException}`); + session.logger.log( + `Exception is OperationCanceledException: ${e instanceof ts.OperationCanceledException}`, + ); operationCanceledExceptionThrown = true; } - if (!operationCanceledExceptionThrown) session.logger.log("Operation Canceled Exception not thrown for request: " + JSON.stringify(request)); + if (!operationCanceledExceptionThrown) { + session.logger.log("Operation Canceled Exception not thrown for request: " + JSON.stringify(request)); + } } }); }); diff --git a/src/testRunner/unittests/tsserver/compileOnSave.ts b/src/testRunner/unittests/tsserver/compileOnSave.ts index 9e8f783d65186..16f50af26f1ee 100644 --- a/src/testRunner/unittests/tsserver/compileOnSave.ts +++ b/src/testRunner/unittests/tsserver/compileOnSave.ts @@ -21,41 +21,49 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { function files() { const moduleFile1: File = { path: "/a/b/moduleFile1.ts", - content: "export function Foo() { };" + content: "export function Foo() { };", }; const file1Consumer1: File = { path: "/a/b/file1Consumer1.ts", - content: `import {Foo} from "./moduleFile1"; export var y = 10;` + content: `import {Foo} from "./moduleFile1"; export var y = 10;`, }; const file1Consumer2: File = { path: "/a/b/file1Consumer2.ts", - content: `import {Foo} from "./moduleFile1"; let z = 10;` + content: `import {Foo} from "./moduleFile1"; let z = 10;`, }; const moduleFile2: File = { path: "/a/b/moduleFile2.ts", - content: `export var Foo4 = 10;` + content: `export var Foo4 = 10;`, }; const globalFile3: File = { path: "/a/b/globalFile3.ts", - content: `interface GlobalFoo { age: number }` + content: `interface GlobalFoo { age: number }`, }; const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compileOnSave": true - }` + }`, }; return { moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile }; } it("should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", () => { const { moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile } = files(); - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([moduleFile1, file1Consumer1], session); @@ -63,7 +71,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { // Send an initial compileOnSave request session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Change, @@ -73,12 +81,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `export var T: number;` - } + insertString: `export var T: number;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); // Change the content of file1 to `export var T: number;export function Foo() { console.log('hi'); };` @@ -90,19 +98,27 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 46, endLine: 1, endOffset: 46, - insertString: `console.log('hi');` - } + insertString: `console.log('hi');`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects module shape changed", session); }); it("should be up-to-date with the reference map changes", () => { const { moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile } = files(); - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([moduleFile1, file1Consumer1], session); @@ -110,7 +126,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { // Send an initial compileOnSave request session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); // Change file2 content to `let y = Foo();` @@ -122,8 +138,8 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 28, - insertString: "" - } + insertString: "", + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Change, @@ -133,12 +149,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `export var T: number;` - } + insertString: `export var T: number;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); // Add the import statements back to file2 @@ -150,8 +166,8 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `import {Foo} from "./moduleFile1";` - } + insertString: `import {Foo} from "./moduleFile1";`, + }, }); // Change the content of file1 to `export var T2: string;export var T: number;export function Foo() { };` @@ -163,19 +179,27 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `export var T2: string;` - } + insertString: `export var T2: string;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects uptodate with reference map changes", session); }); it("should be up-to-date with changes made in non-open files", () => { const { moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile } = files(); - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([moduleFile1], session); @@ -183,7 +207,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { // Send an initial compileOnSave request session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); host.writeFile(file1Consumer1.path, `let y = 10;`); @@ -196,25 +220,33 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `export var T: number;` - } + insertString: `export var T: number;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects uptodate with changes in non open files", session); }); it("should be up-to-date with deleted files", () => { const { moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile } = files(); - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([moduleFile1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); session.executeCommandSeq({ @@ -225,32 +257,40 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `export var T: number;` - } + insertString: `export var T: number;`, + }, }); // Delete file1Consumer2 host.deleteFile(file1Consumer2.path); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects uptodate with deleted files", session); }); it("should be up-to-date with newly created files", () => { const { moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile } = files(); - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([moduleFile1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); const file1Consumer3: File = { path: "/a/b/file1Consumer3.ts", - content: `import {Foo} from "./moduleFile1"; let y = Foo();` + content: `import {Foo} from "./moduleFile1"; let y = Foo();`, }; host.writeFile(file1Consumer3.path, file1Consumer3.content); host.runQueuedTimeoutCallbacks(); @@ -262,12 +302,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `export var T: number;` - } + insertString: `export var T: number;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects uptodate with new files", session); }); @@ -275,12 +315,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { it("should detect changes in non-root files", () => { const moduleFile1: File = { path: "/a/b/moduleFile1.ts", - content: "export function Foo() { };" + content: "export function Foo() { };", }; const file1Consumer1: File = { path: "/a/b/file1Consumer1.ts", - content: `import {Foo} from "./moduleFile1"; let y = Foo();` + content: `import {Foo} from "./moduleFile1"; let y = Foo();`, }; const configFile: File = { @@ -288,7 +328,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { content: `{ "compileOnSave": true, "files": ["${file1Consumer1.path}"] - }` + }`, }; const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]); @@ -297,7 +337,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { openFilesForSession([moduleFile1, file1Consumer1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); // change file1 shape now, and verify both files are affected @@ -309,12 +349,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `export var T: number;` - } + insertString: `export var T: number;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); // change file1 internal, and verify only file1 is affected @@ -326,19 +366,27 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `var T1: number;` - } + insertString: `var T1: number;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects detect changes in non-root files", session); }); it("should return all files if a global file changed shape", () => { const { moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile } = files(); - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + globalFile3, + moduleFile2, + configFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([globalFile3], session); @@ -352,12 +400,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `var T2: string;` - } + insertString: `var T2: string;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: globalFile3.path } + arguments: { file: globalFile3.path }, }); baselineTsserverLogs("compileOnSave", "configProjects global file shape changed", session); }); @@ -366,7 +414,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { const { moduleFile1, file1Consumer1, file1Consumer2 } = files(); const configFile: File = { path: "/a/b/tsconfig.json", - content: `{}` + content: `{}`, }; const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]); @@ -374,7 +422,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { openFilesForSession([moduleFile1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects compileOnSave disabled", session); }); @@ -388,7 +436,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { "compilerOptions": { "noEmit": true } - }` + }`, }; const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile, libFile]); @@ -396,7 +444,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { openFilesForSession([moduleFile1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects noEmit", session); }); @@ -407,23 +455,30 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { path: "/a/b/tsconfig.json", content: `{ "extends": "/a/tsconfig.json" - }` + }`, }; const configFile2: File = { path: "/a/tsconfig.json", content: `{ "compileOnSave": true - }` + }`, }; - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer2, configFile2, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer2, + configFile2, + configFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([moduleFile1, file1Consumer1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects compileOnSave in base tsconfig", session); }); @@ -437,7 +492,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { "compilerOptions": { "isolatedModules": true } - }` + }`, }; const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]); @@ -452,12 +507,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 27, endLine: 1, endOffset: 27, - insertString: `Point,` - } + insertString: `Point,`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects isolatedModules", session); }); @@ -472,7 +527,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { "module": "system", "outFile": "/a/b/out.js" } - }` + }`, }; const host = createServerHost([moduleFile1, file1Consumer1, configFile, libFile]); @@ -487,12 +542,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 27, endLine: 1, endOffset: 27, - insertString: `Point,` - } + insertString: `Point,`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects outFile", session); }); @@ -501,15 +556,22 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { const { moduleFile1, file1Consumer1, globalFile3, configFile } = files(); const file1Consumer1Consumer1: File = { path: "/a/b/file1Consumer1Consumer1.ts", - content: `import {y} from "./file1Consumer1";` + content: `import {y} from "./file1Consumer1";`, }; - const host = createServerHost([moduleFile1, file1Consumer1, file1Consumer1Consumer1, globalFile3, configFile, libFile]); + const host = createServerHost([ + moduleFile1, + file1Consumer1, + file1Consumer1Consumer1, + globalFile3, + configFile, + libFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([moduleFile1, file1Consumer1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); session.executeCommandSeq({ @@ -520,8 +582,8 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 1, endOffset: 1, - insertString: `export var T: number;` - } + insertString: `export var T: number;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Change, @@ -531,12 +593,12 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { offset: 1, endLine: 2, endOffset: 1, - insertString: `export var T: number;` - } + insertString: `export var T: number;`, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path, projectFileName: configFile.path } + arguments: { file: moduleFile1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "configProjects cascaded affected file list", session); }); @@ -547,13 +609,13 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { path: "/a/b/file1.ts", content: ` /// - export var t1 = 10;` + export var t1 = 10;`, }; const file2: File = { path: "/a/b/file2.ts", content: ` /// - export var t2 = 10;` + export var t2 = 10;`, }; const host = createServerHost([file1, file2, configFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -561,7 +623,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { openFilesForSession([file1, file2], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); baselineTsserverLogs("compileOnSave", "configProjects circular references", session); }); @@ -579,7 +641,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { openFilesForSession([file1, file2, file3], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); baselineTsserverLogs("compileOnSave", "configProjects all projects without projectPath", session); }); @@ -590,7 +652,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { path: "/a/b/referenceFile1.ts", content: ` /// - export var x = Foo();` + export var x = Foo();`, }; const host = createServerHost([moduleFile1, referenceFile1, configFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -600,11 +662,11 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: referenceFile1.path } + arguments: { file: referenceFile1.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: moduleFile1.path } + arguments: { file: moduleFile1.path }, }); baselineTsserverLogs("compileOnSave", "configProjects removed code", session); }); @@ -615,7 +677,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { path: "/a/b/referenceFile1.ts", content: ` /// - export var x = Foo();` + export var x = Foo();`, }; const host = createServerHost([referenceFile1, configFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -623,29 +685,34 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { openFilesForSession([referenceFile1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: referenceFile1.path } + arguments: { file: referenceFile1.path }, }); baselineTsserverLogs("compileOnSave", "configProjects non existing code", session); }); }); describe("for changes in declaration files", () => { - function testDTS(subScenario: string, dtsFileContents: string, tsFileContents: string, opts: ts.CompilerOptions) { + function testDTS( + subScenario: string, + dtsFileContents: string, + tsFileContents: string, + opts: ts.CompilerOptions, + ) { it(subScenario, () => { const dtsFile = { path: "/a/runtime/a.d.ts", - content: dtsFileContents + content: dtsFileContents, }; const f2 = { path: "/a/b.ts", - content: tsFileContents + content: tsFileContents, }; const config = { path: "/a/tsconfig.json", content: JSON.stringify({ compilerOptions: opts, - compileOnSave: true - }) + compileOnSave: true, + }), }; const host = createServerHost([dtsFile, f2, config]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -653,11 +720,11 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { openFilesForSession([f2], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dtsFile.path } + arguments: { file: dtsFile.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: f2.path } + arguments: { file: f2.path }, }); baselineTsserverLogs("compileOnSave", subScenario, session); }); @@ -673,7 +740,7 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { testDTS( "dtsFileChange in module file", /*dtsFileContents*/ "export const x: string;", - /*tsFileContents*/ "import { x } from './runtime/a;", + /*tsFileContents*/ "import { x } from './runtime/a;", /*opts*/ {}, ); @@ -704,38 +771,40 @@ describe("unittests:: tsserver:: compileOnSave:: affected list", () => { it(subScenario, () => { const f1 = { path: "/a/a.ts", - content: "let x = 1" + content: "let x = 1", }; const f2 = { path: "/a/b.ts", - content: "let y = 1" + content: "let y = 1", }; const config = { path: "/a/tsconfig.json", content: JSON.stringify({ compilerOptions: opts, - compileOnSave: true - }) + compileOnSave: true, + }), }; const host = createServerHost([f1, f2, config]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([f1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: f1.path } + arguments: { file: f1.path }, }); baselineTsserverLogs("compileOnSave", subScenario, session); }); } test("compileOnSaveAffectedFileList projectUsesOutFile should not be returned if not set", {}); - test("compileOnSaveAffectedFileList projectUsesOutFile should be true if outFile is set", { outFile: "/a/out.js" }); + test("compileOnSaveAffectedFileList projectUsesOutFile should be true if outFile is set", { + outFile: "/a/out.js", + }); test("compileOnSaveAffectedFileList projectUsesOutFile should be true if out is set", { out: "/a/out.js" }); }); }); describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { it("should respect line endings", () => { - const logger = createLoggerWithInMemoryLogs(/*host*/ undefined!); //special handling + const logger = createLoggerWithInMemoryLogs(/*host*/ undefined!); // special handling test("\n", logger); test("\r\n", logger); baselineTsserverLogs("compileOnSave", "line endings", { logger }); @@ -745,16 +814,18 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { const path = "/a/app"; const f = { path: path + ts.Extension.Ts, - content: lines.join(newLine) + content: lines.join(newLine), }; const host = createServerHost([f], { newLine }); logger.host = host; - logger.log(`currentDirectory:: ${host.getCurrentDirectory()} useCaseSensitiveFileNames: ${host.useCaseSensitiveFileNames} newLine: ${host.newLine}`); + logger.log( + `currentDirectory:: ${host.getCurrentDirectory()} useCaseSensitiveFileNames: ${host.useCaseSensitiveFileNames} newLine: ${host.newLine}`, + ); const session = createSession(host, { logger }); openFilesForSession([f], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: f.path } + arguments: { file: f.path }, }); return logger; } @@ -763,15 +834,15 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { it("should emit specified file", () => { const file1 = { path: "/a/b/f1.ts", - content: `export function Foo() { return 10; }` + content: `export function Foo() { return 10; }`, }; const file2 = { path: "/a/b/f2.ts", - content: `import {Foo} from "./f1"; let y = Foo();` + content: `import {Foo} from "./f1"; let y = Foo();`, }; const configFile = { path: "/a/b/tsconfig.json", - content: `{}` + content: `{}`, }; const host = createServerHost([file1, file2, configFile, libFile], { newLine: "\r\n" }); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -779,7 +850,7 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { openFilesForSession([file1, file2], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: file1.path, projectFileName: configFile.path } + arguments: { file: file1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("compileOnSave", "emit specified file", session); @@ -788,16 +859,16 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { it("shoud not emit js files in external projects", () => { const file1 = { path: "/a/b/file1.ts", - content: "consonle.log('file1');" + content: "consonle.log('file1');", }; // file2 has errors. The emitting should not be blocked. const file2 = { path: "/a/b/file2.js", - content: "console.log'file2');" + content: "console.log'file2');", }; const file3 = { path: "/a/b/file3.js", - content: "console.log('file3');" + content: "console.log('file3');", }; const externalProjectName = "/a/b/externalproject"; const host = createServerHost([file1, file2, file3, libFile]); @@ -807,14 +878,14 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { options: { allowJs: true, outFile: "dist.js", - compileOnSave: true + compileOnSave: true, }, - projectFileName: externalProjectName + projectFileName: externalProjectName, }, session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); baselineTsserverLogs("compileOnSave", "should not emit js files in external projects", session); @@ -824,7 +895,7 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { const inputFileName = "Foo.ts"; const file1 = { path: `/root/TypeScriptProject3/TypeScriptProject3/${inputFileName}`, - content: "consonle.log('file1');" + content: "consonle.log('file1');", }; const externalProjectName = "/root/TypeScriptProject3/TypeScriptProject3/TypeScriptProject3.csproj"; const host = createServerHost([file1, libFile]); @@ -834,13 +905,13 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { options: { outFile: "bar.js", sourceMap: true, - compileOnSave: true + compileOnSave: true, }, - projectFileName: externalProjectName + projectFileName: externalProjectName, }, session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); baselineTsserverLogs("compileOnSave", "use projectRoot as current directory", session); }); @@ -866,16 +937,16 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { noEmitOnError: true, declaration: true, }, - exclude: ["node_modules"] - }) + exclude: ["node_modules"], + }), }; const file1: File = { path: `/user/username/projects/myproject/file1.ts`, - content: "const x = 1;" + content: "const x = 1;", }; const file2: File = { path: `/user/username/projects/myproject/file2.ts`, - content: "const y = 2;" + content: "const y = 2;", }; const host = createServerHost([file1, file2, config, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -883,15 +954,15 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: file1.path, richResponse } + arguments: { file: file1.path, richResponse }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: file2.path, richResponse } + arguments: { file: file2.path, richResponse }, }); baselineTsserverLogs("compileOnSave", `emit with richRepsonse as ${richResponse}`, session); } @@ -921,31 +992,31 @@ describe("unittests:: tsserver:: compileOnSave:: EmitFile test", () => { compileOnSave: true, compilerOptions: { declaration, - module: hasModule ? undefined : "none" + module: hasModule ? undefined : "none", }, - }) + }), }; const file1: File = { path: `/user/username/projects/myproject/file1.ts`, content: `const x = 1; function foo() { return "hello"; -}` +}`, }; const file2: File = { path: `/user/username/projects/myproject/file2.ts`, content: `const y = 2; function bar() { return "world"; -}` +}`, }; const file3: File = { path: `/user/username/projects/myproject/file3.ts`, - content: "const xy = 3;" + content: "const xy = 3;", }; const module: File = { path: `/user/username/projects/myproject/module.ts`, - content: "export const xyz = 4;" + content: "export const xyz = 4;", }; const files = [file1, file2, file3, ...(hasModule ? [module] : ts.emptyArray)]; const host = createServerHost([...files, config, libFile]); @@ -954,7 +1025,7 @@ function bar() { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); verifyFileSave(file1); @@ -969,12 +1040,16 @@ function bar() { // Change file2 get affected file list = will return only file2 if --declaration otherwise all files verifyLocalEdit(file2, "world", "hello"); - baselineTsserverLogs("compileOnSave", `emit in project${hasModule ? " with module" : ""}${declaration ? " with dts emit" : ""}`, session); + baselineTsserverLogs( + "compileOnSave", + `emit in project${hasModule ? " with module" : ""}${declaration ? " with dts emit" : ""}`, + session, + ); function verifyFileSave(file: File) { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: file.path } + arguments: { file: file.path }, }); } @@ -987,14 +1062,14 @@ function bar() { fileName: file.path, textChanges: [{ newText, - ...protocolTextSpanFromSubstring(file.content, oldText) - }] - }] - } + ...protocolTextSpanFromSubstring(file.content, oldText), + }], + }], + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: file.path } + arguments: { file: file.path }, }); file.content = file.content.replace(oldText, newText); verifyFileSave(file); @@ -1013,45 +1088,57 @@ describe("unittests:: tsserver:: compileOnSave:: CompileOnSaveAffectedFileListRe offset: 1, endLine: 1, endOffset: 1, - insertString: "let k = 1" - } + insertString: "let k = 1", + }, }); } function logDirtyOfProjects(session: TestSession) { - session.logger.log(`Project1 is dirty: ${session.getProjectService().configuredProjects.get(`/user/username/projects/myproject/app1/tsconfig.json`)!.dirty}`); - session.logger.log(`Project2 is dirty: ${session.getProjectService().configuredProjects.get(`/user/username/projects/myproject/app2/tsconfig.json`)!.dirty}`); + session.logger.log( + `Project1 is dirty: ${ + session.getProjectService().configuredProjects.get( + `/user/username/projects/myproject/app1/tsconfig.json`, + )!.dirty + }`, + ); + session.logger.log( + `Project2 is dirty: ${ + session.getProjectService().configuredProjects.get( + `/user/username/projects/myproject/app2/tsconfig.json`, + )!.dirty + }`, + ); } function verify(subScenario: string, commandArgs: ts.server.protocol.FileRequestArgs) { it(subScenario, () => { const core: File = { path: `/user/username/projects/myproject/core/core.ts`, - content: "let z = 10;" + content: "let z = 10;", }; const app1: File = { path: `/user/username/projects/myproject/app1/app.ts`, - content: "let x = 10;" + content: "let x = 10;", }; const app2: File = { path: `/user/username/projects/myproject/app2/app.ts`, - content: "let y = 10;" + content: "let y = 10;", }; const app1Config: File = { path: `/user/username/projects/myproject/app1/tsconfig.json`, content: JSON.stringify({ files: ["app.ts", "../core/core.ts"], compilerOptions: { outFile: "build/output.js" }, - compileOnSave: true - }) + compileOnSave: true, + }), }; const app2Config: File = { path: `/user/username/projects/myproject/app2/tsconfig.json`, content: JSON.stringify({ files: ["app.ts", "../core/core.ts"], compilerOptions: { outFile: "build/output.js" }, - compileOnSave: true - }) + compileOnSave: true, + }), }; const files = [libFile, core, app1, app2, app1Config, app2Config]; const host = createServerHost(files); @@ -1062,7 +1149,7 @@ describe("unittests:: tsserver:: compileOnSave:: CompileOnSaveAffectedFileListRe logDirtyOfProjects(session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: commandArgs + arguments: commandArgs, }); logDirtyOfProjects(session); baselineTsserverLogs("compileOnSave", subScenario, session); @@ -1070,7 +1157,7 @@ describe("unittests:: tsserver:: compileOnSave:: CompileOnSaveAffectedFileListRe } verify("CompileOnSaveAffectedFileListRequest when projectFile is specified", { file: `/user/username/projects/myproject/core/core.ts`, - projectFileName: `/user/username/projects/myproject/app1/tsconfig.json` + projectFileName: `/user/username/projects/myproject/app1/tsconfig.json`, }); verify("CompileOnSaveAffectedFileListRequest when projectFile is not specified", { file: `/user/username/projects/myproject/core/core.ts`, diff --git a/src/testRunner/unittests/tsserver/completions.ts b/src/testRunner/unittests/tsserver/completions.ts index e385dad6c06e6..5ac9cd1ca0623 100644 --- a/src/testRunner/unittests/tsserver/completions.ts +++ b/src/testRunner/unittests/tsserver/completions.ts @@ -43,15 +43,19 @@ describe("unittests:: tsserver:: completions", () => { ...requestLocation, includeExternalModuleExports: true, prefix: "foo", - } + }, }).response as ts.server.protocol.CompletionInfo; const exportMapKey = (response?.entries[0].data as any)?.exportMapKey; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompletionDetails, arguments: { ...requestLocation, - entryNames: [{ name: "foo", source: "/a", data: { exportName: "foo", fileName: "/a.ts", exportMapKey } }], - } + entryNames: [{ + name: "foo", + source: "/a", + data: { exportName: "foo", fileName: "/a.ts", exportMapKey }, + }], + }, }); interface CompletionDetailsFullRequest extends ts.server.protocol.FileLocationRequest { @@ -62,8 +66,12 @@ describe("unittests:: tsserver:: completions", () => { command: ts.server.protocol.CommandTypes.CompletionDetailsFull, arguments: { ...requestLocation, - entryNames: [{ name: "foo", source: "/a", data: { exportName: "foo", fileName: "/a.ts", exportMapKey } }], - } + entryNames: [{ + name: "foo", + source: "/a", + data: { exportName: "foo", fileName: "/a.ts", exportMapKey }, + }], + }, }); baselineTsserverLogs("completions", "works", session); }); @@ -78,8 +86,8 @@ describe("unittests:: tsserver:: completions", () => { dependencies: { "react": "^16.12.0", "react-router-dom": "^5.1.2", - } - }) + }, + }), }; const appFile: File = { path: `${projectRoot}/src/app.js`, @@ -87,7 +95,7 @@ describe("unittests:: tsserver:: completions", () => { import { BrowserRouter as Router, } from "react-router-dom"; -` +`, }; const localNodeModules = `${projectRoot}/node_modules`; const localAtTypes = `${localNodeModules}/@types`; @@ -96,30 +104,30 @@ import { content: JSON.stringify({ name: "@types/react", version: "16.9.14", - }) + }), }; const localReact: File = { path: `${localAtTypes}/react/index.d.ts`, content: `import * as PropTypes from 'prop-types'; -` +`, }; const localReactRouterDomPackage: File = { path: `${localNodeModules}/react-router-dom/package.json`, content: JSON.stringify({ name: "react-router-dom", version: "5.1.2", - }) + }), }; const localReactRouterDom: File = { path: `${localNodeModules}/react-router-dom/index.js`, - content: `export function foo() {}` + content: `export function foo() {}`, }; const localPropTypesPackage: File = { path: `${localAtTypes}/prop-types/package.json`, content: JSON.stringify({ name: "@types/prop-types", version: "15.7.3", - }) + }), }; const localPropTypes: File = { path: `${localAtTypes}/prop-types/index.d.ts`, @@ -127,7 +135,7 @@ import { | string | ((props: any, context?: any) => any) | (new (props: any, context?: any) => any); -` +`, }; const globalCacheLocation = `c:/typescript`; @@ -137,7 +145,7 @@ import { content: JSON.stringify({ name: "@types/react-router-dom", version: "5.1.2", - }) + }), }; const globalReactRouterDom: File = { path: `${globalAtTypes}/react-router-dom/index.d.ts`, @@ -147,15 +155,15 @@ export interface BrowserRouterProps { getUserConfirmation?: ((message: string, callback: (ok: boolean) => void) => void); forceRefresh?: boolean; keyLength?: number; -}` +}`, }; const globalReactPackage: File = { path: `${globalAtTypes}/react/package.json`, - content: localReactPackage.content + content: localReactPackage.content, }; const globalReact: File = { path: `${globalAtTypes}/react/index.d.ts`, - content: localReact.content + content: localReact.content, }; const filesInProject = [ @@ -167,9 +175,11 @@ export interface BrowserRouterProps { ]; const files = [ ...filesInProject, - appPackage, libFile, + appPackage, + libFile, localReactPackage, - localReactRouterDomPackage, localReactRouterDom, + localReactRouterDomPackage, + localReactRouterDom, localPropTypesPackage, globalReactRouterDomPackage, globalReactPackage, @@ -189,9 +199,13 @@ export interface BrowserRouterProps { line: 5, offset: 1, includeExternalModuleExports: true, - includeInsertTextCompletions: true - } + includeInsertTextCompletions: true, + }, }); - baselineTsserverLogs("completions", "works when files are included from two different drives of windows", session); + baselineTsserverLogs( + "completions", + "works when files are included from two different drives of windows", + session, + ); }); }); diff --git a/src/testRunner/unittests/tsserver/completionsIncomplete.ts b/src/testRunner/unittests/tsserver/completionsIncomplete.ts index ad52b6ebe3c16..026060c495d33 100644 --- a/src/testRunner/unittests/tsserver/completionsIncomplete.ts +++ b/src/testRunner/unittests/tsserver/completionsIncomplete.ts @@ -17,15 +17,32 @@ function createExportingModuleFile(path: string, exportPrefix: string, exportCou }; } -function createExportingModuleFiles(pathPrefix: string, fileCount: number, exportCount: number, getExportPrefix: (fileIndex: number) => string): File[] { - return ts.arrayOf(fileCount, fileIndex => createExportingModuleFile( - `${pathPrefix}_${fileIndex}.ts`, - getExportPrefix(fileIndex), - exportCount)); +function createExportingModuleFiles( + pathPrefix: string, + fileCount: number, + exportCount: number, + getExportPrefix: (fileIndex: number) => string, +): File[] { + return ts.arrayOf(fileCount, fileIndex => + createExportingModuleFile( + `${pathPrefix}_${fileIndex}.ts`, + getExportPrefix(fileIndex), + exportCount, + )); } -function createNodeModulesPackage(packageName: string, fileCount: number, exportCount: number, getExportPrefix: (fileIndex: number) => string): File[] { - const exportingFiles = createExportingModuleFiles(`/node_modules/${packageName}/file`, fileCount, exportCount, getExportPrefix); +function createNodeModulesPackage( + packageName: string, + fileCount: number, + exportCount: number, + getExportPrefix: (fileIndex: number) => string, +): File[] { + const exportingFiles = createExportingModuleFiles( + `/node_modules/${packageName}/file`, + fileCount, + exportCount, + getExportPrefix, + ); return [ { path: `/node_modules/${packageName}/package.json`, @@ -34,7 +51,13 @@ function createNodeModulesPackage(packageName: string, fileCount: number, export { path: `/node_modules/${packageName}/index.d.ts`, content: exportingFiles - .map(f => `export * from "./${ts.removeFileExtension(ts.convertToRelativePath(f.path, `/node_modules/${packageName}/`, ts.identity))}";`) + .map(f => + `export * from "./${ + ts.removeFileExtension( + ts.convertToRelativePath(f.path, `/node_modules/${packageName}/`, ts.identity), + ) + }";` + ) .join("\n") + `\nexport default function main(): void;`, }, ...exportingFiles, @@ -43,12 +66,12 @@ function createNodeModulesPackage(packageName: string, fileCount: number, export const indexFile: File = { path: "/index.ts", - content: "" + content: "", }; const tsconfigFile: File = { path: "/tsconfig.json", - content: `{ "compilerOptions": { "module": "commonjs" } }` + content: `{ "compilerOptions": { "module": "commonjs" } }`, }; const packageJsonFile: File = { @@ -59,24 +82,47 @@ const packageJsonFile: File = { describe("unittests:: tsserver:: completionsIncomplete", () => { it("works", () => { const excessFileCount = ts.Completions.moduleSpecifierResolutionLimit + 50; - const exportingFiles = createExportingModuleFiles(`/lib/a`, ts.Completions.moduleSpecifierResolutionLimit + excessFileCount, 1, i => `aa_${i}_`); + const exportingFiles = createExportingModuleFiles( + `/lib/a`, + ts.Completions.moduleSpecifierResolutionLimit + excessFileCount, + 1, + i => `aa_${i}_`, + ); const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles]); openFilesForSession([indexFile], session); typeToTriggerCompletions(indexFile.path, "a", completions => { assert(completions.isIncomplete); - assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), ts.Completions.moduleSpecifierResolutionLimit); - assert.lengthOf(completions.entries.filter(entry => entry.source && !(entry.data as any)?.moduleSpecifier), excessFileCount); - assert.deepEqual(completions.optionalReplacementSpan, { start: { line: 1, offset: 1 }, end: { line: 1, offset: 2 } }); + assert.lengthOf( + completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), + ts.Completions.moduleSpecifierResolutionLimit, + ); + assert.lengthOf( + completions.entries.filter(entry => entry.source && !(entry.data as any)?.moduleSpecifier), + excessFileCount, + ); + assert.deepEqual(completions.optionalReplacementSpan, { + start: { line: 1, offset: 1 }, + end: { line: 1, offset: 2 }, + }); }) .continueTyping("a", completions => { assert(completions.isIncomplete); - assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), ts.Completions.moduleSpecifierResolutionLimit * 2); - assert.deepEqual(completions.optionalReplacementSpan, { start: { line: 1, offset: 1 }, end: { line: 1, offset: 3 } }); + assert.lengthOf( + completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), + ts.Completions.moduleSpecifierResolutionLimit * 2, + ); + assert.deepEqual(completions.optionalReplacementSpan, { + start: { line: 1, offset: 1 }, + end: { line: 1, offset: 3 }, + }); }) .continueTyping("_", completions => { assert(!completions.isIncomplete); - assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), exportingFiles.length); + assert.lengthOf( + completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier), + exportingFiles.length, + ); }); baselineTsserverLogs("completionsIncomplete", "works", session); }); @@ -89,19 +135,32 @@ describe("unittests:: tsserver:: completionsIncomplete", () => { typeToTriggerCompletions(indexFile.path, "a", completions => { assert(!completions.isIncomplete); }); - baselineTsserverLogs("completionsIncomplete", "resolves more when available from module specifier cache (1)", session); + baselineTsserverLogs( + "completionsIncomplete", + "resolves more when available from module specifier cache (1)", + session, + ); }); it("resolves more when available from module specifier cache (2)", () => { const excessFileCount = 50; - const exportingFiles = createExportingModuleFiles(`/lib/a`, ts.Completions.moduleSpecifierResolutionLimit + excessFileCount, 1, i => `aa_${i}_`); + const exportingFiles = createExportingModuleFiles( + `/lib/a`, + ts.Completions.moduleSpecifierResolutionLimit + excessFileCount, + 1, + i => `aa_${i}_`, + ); const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles]); openFilesForSession([indexFile], session); typeToTriggerCompletions(indexFile.path, "a", completions => assert(completions.isIncomplete)) .backspace() .type("a", completions => assert(!completions.isIncomplete)); - baselineTsserverLogs("completionsIncomplete", "resolves more when available from module specifier cache (2)", session); + baselineTsserverLogs( + "completionsIncomplete", + "resolves more when available from module specifier cache (2)", + session, + ); }); it("ambient module specifier resolutions do not count against the resolution limit", () => { @@ -110,30 +169,62 @@ describe("unittests:: tsserver:: completionsIncomplete", () => { content: `declare module "ambient_${i}" { export const aa_${i} = ${i}; }`, })); - const exportingFiles = createExportingModuleFiles(`/lib/a`, ts.Completions.moduleSpecifierResolutionLimit, 5, i => `aa_${i}_`); - const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...ambientFiles, ...exportingFiles]); + const exportingFiles = createExportingModuleFiles( + `/lib/a`, + ts.Completions.moduleSpecifierResolutionLimit, + 5, + i => `aa_${i}_`, + ); + const { typeToTriggerCompletions, session } = setup([ + tsconfigFile, + indexFile, + ...ambientFiles, + ...exportingFiles, + ]); openFilesForSession([indexFile], session); typeToTriggerCompletions(indexFile.path, "a", completions => { assert(!completions.isIncomplete); - assert.lengthOf(completions.entries.filter(e => (e.data as any)?.moduleSpecifier), ambientFiles.length * 5 + exportingFiles.length); + assert.lengthOf( + completions.entries.filter(e => (e.data as any)?.moduleSpecifier), + ambientFiles.length * 5 + exportingFiles.length, + ); }); - baselineTsserverLogs("completionsIncomplete", "ambient module specifier resolutions do not count against the resolution limit", session); + baselineTsserverLogs( + "completionsIncomplete", + "ambient module specifier resolutions do not count against the resolution limit", + session, + ); }); it("works with PackageJsonAutoImportProvider", () => { - const exportingFiles = createExportingModuleFiles(`/lib/a`, ts.Completions.moduleSpecifierResolutionLimit, 1, i => `aa_${i}_`); + const exportingFiles = createExportingModuleFiles( + `/lib/a`, + ts.Completions.moduleSpecifierResolutionLimit, + 1, + i => `aa_${i}_`, + ); const nodeModulesPackage = createNodeModulesPackage("dep-a", 50, 1, i => `depA_${i}_`); - const { typeToTriggerCompletions, assertCompletionDetailsOk, session } = setup([tsconfigFile, packageJsonFile, indexFile, ...exportingFiles, ...nodeModulesPackage]); + const { typeToTriggerCompletions, assertCompletionDetailsOk, session } = setup([ + tsconfigFile, + packageJsonFile, + indexFile, + ...exportingFiles, + ...nodeModulesPackage, + ]); openFilesForSession([indexFile], session); typeToTriggerCompletions(indexFile.path, "a", completions => assert(completions.isIncomplete)) .continueTyping("_", completions => { assert(!completions.isIncomplete); - assert.lengthOf(completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier?.startsWith("dep-a")), 50); + assert.lengthOf( + completions.entries.filter(entry => (entry.data as any)?.moduleSpecifier?.startsWith("dep-a")), + 50, + ); assertCompletionDetailsOk( indexFile.path, - completions.entries.find(entry => (entry.data as any)?.moduleSpecifier?.startsWith("dep-a"))!); + completions.entries.find(entry => (entry.data as any)?.moduleSpecifier?.startsWith("dep-a"))!, + ); }); baselineTsserverLogs("completionsIncomplete", "works with PackageJsonAutoImportProvider", session); }); @@ -146,7 +237,12 @@ describe("unittests:: tsserver:: completionsIncomplete", () => { declare const exp: {} & { [K in Signals]: K }; export = exp;`, }; - const exportingFiles = createExportingModuleFiles("/lib/a", ts.Completions.moduleSpecifierResolutionLimit, 1, i => `S${i}`); + const exportingFiles = createExportingModuleFiles( + "/lib/a", + ts.Completions.moduleSpecifierResolutionLimit, + 1, + i => `S${i}`, + ); const { typeToTriggerCompletions, session } = setup([tsconfigFile, indexFile, ...exportingFiles, constantsDts]); openFilesForSession([indexFile], session); @@ -176,18 +272,31 @@ function setup(files: File[]) { includeCompletionsWithInsertText: true, includeCompletionsForImportStatements: true, includePackageJsonAutoImports: "auto", - } - } + }, + }, }); return { host, session, projectService, typeToTriggerCompletions, assertCompletionDetailsOk }; - function typeToTriggerCompletions(fileName: string, typedCharacters: string, cb?: (completions: ts.server.protocol.CompletionInfo) => void) { - const project = projectService.getDefaultProjectForFile(ts.server.toNormalizedPath(fileName), /*ensureProject*/ true)!; + function typeToTriggerCompletions( + fileName: string, + typedCharacters: string, + cb?: (completions: ts.server.protocol.CompletionInfo) => void, + ) { + const project = projectService.getDefaultProjectForFile( + ts.server.toNormalizedPath(fileName), + /*ensureProject*/ true, + )!; return type(typedCharacters, cb, /*isIncompleteContinuation*/ false); - function type(typedCharacters: string, cb: ((completions: ts.server.protocol.CompletionInfo) => void) | undefined, isIncompleteContinuation: boolean) { - const file = ts.Debug.checkDefined(project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName)); + function type( + typedCharacters: string, + cb: ((completions: ts.server.protocol.CompletionInfo) => void) | undefined, + isIncompleteContinuation: boolean, + ) { + const file = ts.Debug.checkDefined( + project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName), + ); const { line, character } = ts.getLineAndCharacterOfPosition(file, file.text.length); const oneBasedEditPosition = { line: line + 1, offset: character + 1 }; session.executeCommandSeq({ @@ -213,23 +322,31 @@ function setup(files: File[]) { triggerKind: isIncompleteContinuation ? ts.server.protocol.CompletionTriggerKind.TriggerForIncompleteCompletions : undefined, - } + }, }).response as ts.server.protocol.CompletionInfo; cb?.(ts.Debug.checkDefined(response)); return { backspace, - continueTyping: (typedCharacters: string, cb: (completions: ts.server.protocol.CompletionInfo) => void) => { + continueTyping: ( + typedCharacters: string, + cb: (completions: ts.server.protocol.CompletionInfo) => void, + ) => { return type(typedCharacters, cb, !!response.isIncomplete); }, }; } function backspace(n = 1) { - const file = ts.Debug.checkDefined(project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName)); + const file = ts.Debug.checkDefined( + project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName), + ); const startLineCharacter = ts.getLineAndCharacterOfPosition(file, file.text.length - n); const endLineCharacter = ts.getLineAndCharacterOfPosition(file, file.text.length); - const oneBasedStartPosition = { line: startLineCharacter.line + 1, offset: startLineCharacter.character + 1 }; + const oneBasedStartPosition = { + line: startLineCharacter.line + 1, + offset: startLineCharacter.character + 1, + }; const oneBasedEndPosition = { line: endLineCharacter.line + 1, offset: endLineCharacter.character + 1 }; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.UpdateOpen, @@ -255,8 +372,13 @@ function setup(files: File[]) { } function assertCompletionDetailsOk(fileName: string, entry: ts.server.protocol.CompletionEntry) { - const project = projectService.getDefaultProjectForFile(ts.server.toNormalizedPath(fileName), /*ensureProject*/ true)!; - const file = ts.Debug.checkDefined(project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName)); + const project = projectService.getDefaultProjectForFile( + ts.server.toNormalizedPath(fileName), + /*ensureProject*/ true, + )!; + const file = ts.Debug.checkDefined( + project.getLanguageService(/*ensureSynchronized*/ true).getProgram()?.getSourceFile(fileName), + ); const { line, character } = ts.getLineAndCharacterOfPosition(file, file.text.length - 1); const details = session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompletionDetails, @@ -268,13 +390,17 @@ function setup(files: File[]) { name: entry.name, source: entry.source, data: entry.data, - }] - } + }], + }, }).response as ts.server.protocol.CompletionEntryDetails[]; assert(details[0]); assert(details[0].codeActions); - assert(details[0].codeActions[0].changes[0].textChanges[0].newText.includes(`"${(entry.data as any).moduleSpecifier}"`)); + assert( + details[0].codeActions[0].changes[0].textChanges[0].newText.includes( + `"${(entry.data as any).moduleSpecifier}"`, + ), + ); return details; } } diff --git a/src/testRunner/unittests/tsserver/configFileSearch.ts b/src/testRunner/unittests/tsserver/configFileSearch.ts index 17682e3042056..6e95d8c1f608b 100644 --- a/src/testRunner/unittests/tsserver/configFileSearch.ts +++ b/src/testRunner/unittests/tsserver/configFileSearch.ts @@ -13,11 +13,11 @@ describe("unittests:: tsserver:: configFileSearch:: searching for config file", it("should stop at projectRootPath if given", () => { const f1 = { path: "/a/file1.ts", - content: "" + content: "", }; const configFile = { path: "/tsconfig.json", - content: "{}" + content: "{}", }; const host = createServerHost([f1, configFile]); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -33,15 +33,15 @@ describe("unittests:: tsserver:: configFileSearch:: searching for config file", const configFileLocation = `${projectDir}/src`; const f1 = { path: `${configFileLocation}/file1.ts`, - content: "" + content: "", }; const configFile = { path: `${configFileLocation}/tsconfig.json`, - content: "{}" + content: "{}", }; const configFile2 = { path: "/a/b/projects/tsconfig.json", - content: "{}" + content: "{}", }; const host = createServerHost([f1, libFile, configFile, configFile2]); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -50,7 +50,11 @@ describe("unittests:: tsserver:: configFileSearch:: searching for config file", // Delete config file - should create inferred project and not configured project host.deleteFile(configFile.path); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("configFileSearch", "should use projectRootPath when searching for inferred project again", service); + baselineTsserverLogs( + "configFileSearch", + "should use projectRootPath when searching for inferred project again", + service, + ); }); it("should use projectRootPath when searching for inferred project again 2", () => { @@ -58,15 +62,15 @@ describe("unittests:: tsserver:: configFileSearch:: searching for config file", const configFileLocation = `${projectDir}/src`; const f1 = { path: `${configFileLocation}/file1.ts`, - content: "" + content: "", }; const configFile = { path: `${configFileLocation}/tsconfig.json`, - content: "{}" + content: "{}", }; const configFile2 = { path: "/a/b/projects/tsconfig.json", - content: "{}" + content: "{}", }; const host = createServerHost([f1, libFile, configFile, configFile2]); const service = createProjectService(host, { @@ -79,23 +83,32 @@ describe("unittests:: tsserver:: configFileSearch:: searching for config file", // Delete config file - should create inferred project with project root path set host.deleteFile(configFile.path); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("configFileSearch", "should use projectRootPath when searching for inferred project again 2", service); + baselineTsserverLogs( + "configFileSearch", + "should use projectRootPath when searching for inferred project again 2", + service, + ); }); describe("when the opened file is not from project root", () => { const projectRoot = "/a/b/projects/project"; const file: File = { path: `${projectRoot}/src/index.ts`, - content: "let y = 10" + content: "let y = 10", }; const tsconfig: File = { path: `${projectRoot}/tsconfig.json`, - content: "{}" + content: "{}", }; function openClientFile(files: File[]) { const host = createServerHost(files); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); - projectService.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a/b/projects/proj"); + projectService.openClientFile( + file.path, + /*fileContent*/ undefined, + /*scriptKind*/ undefined, + "/a/b/projects/proj", + ); return { host, projectService }; } @@ -128,7 +141,9 @@ describe("unittests:: tsserver:: configFileSearch:: searching for config file", function verifyConfigFileWatch(scenario: string, projectRootPath: string | undefined) { it(scenario, () => { const path = `/root/teams/VSCode68/Shared Documents/General/jt-ts-test-workspace/x.js`; - const host = createServerHost([libFile, { path, content: "const x = 10" }], { useCaseSensitiveFileNames: true }); + const host = createServerHost([libFile, { path, content: "const x = 10" }], { + useCaseSensitiveFileNames: true, + }); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); service.openClientFile(path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectRootPath); baselineTsserverLogs("configFileSearch", scenario, service); diff --git a/src/testRunner/unittests/tsserver/configuredProjects.ts b/src/testRunner/unittests/tsserver/configuredProjects.ts index a496d5612849c..38d46e6850fb0 100644 --- a/src/testRunner/unittests/tsserver/configuredProjects.ts +++ b/src/testRunner/unittests/tsserver/configuredProjects.ts @@ -1,5 +1,7 @@ import * as ts from "../../_namespaces/ts"; -import { ensureErrorFreeBuild } from "../helpers/solutionBuilder"; +import { + ensureErrorFreeBuild, +} from "../helpers/solutionBuilder"; import { commonFile1, commonFile2, @@ -31,19 +33,19 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "exclude": [ "e" ] - }` + }`, }; const file1: File = { path: "/a/b/c/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2: File = { path: "/a/b/d/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const file3: File = { path: "/a/b/e/f3.ts", - content: "let z = 1" + content: "let z = 1", }; const host = createServerHost([configFile, libFile, file1, file2, file3]); @@ -51,7 +53,10 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { const { configFileName, configFileErrors } = projectService.openClientFile(file1.path); assert(configFileName, "should find config file"); - assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); + assert.isTrue( + !configFileErrors || configFileErrors.length === 0, + `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`, + ); baselineTsserverLogs("configuredProjects", "create configured project without file list", projectService); }); @@ -63,19 +68,19 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { { "compilerOptions": {}, "include": ["*.ts"] - }` + }`, }; const file1: File = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2: File = { path: "/a/b/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const file3: File = { path: "/a/b/c/f3.ts", - content: "let z = 1" + content: "let z = 1", }; const host = createServerHost([configFile, libFile, file1, file2, file3]); @@ -83,7 +88,10 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { const { configFileName, configFileErrors } = projectService.openClientFile(file1.path); assert(configFileName, "should find config file"); - assert.isTrue(!configFileErrors || configFileErrors.length === 0, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`); + assert.isTrue( + !configFileErrors || configFileErrors.length === 0, + `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`, + ); baselineTsserverLogs("configuredProjects", "create configured project with the file list", projectService); }); @@ -93,15 +101,15 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { path: `/user/username/projects/myproject/tsconfig.json`, content: `{ "files": ["commonFile1.ts"] - }` + }`, }; const commonFile1: File = { path: `/user/username/projects/myproject/commonFile1.ts`, - content: "let x = 1" + content: "let x = 1", }; const commonFile2: File = { path: `/user/username/projects/myproject/commonFile2.ts`, - content: "let y = 1" + content: "let y = 1", }; const host = createServerHost([libFile, commonFile1, commonFile2]); @@ -118,13 +126,17 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { host.deleteFile(configFile.path); host.runQueuedTimeoutCallbacks(); // Refresh inferred projects - baselineTsserverLogs("configuredProjects", "add and then remove a config file in a folder with loose files", projectService); + baselineTsserverLogs( + "configuredProjects", + "add and then remove a config file in a folder with loose files", + projectService, + ); }); it("add new files to a configured project without file list", () => { const configFile: File = { path: "/a/b/tsconfig.json", - content: `{}` + content: `{}`, }; const host = createServerHost([commonFile1, libFile, configFile]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -133,7 +145,11 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { // add a new ts file host.writeFile(commonFile2.path, commonFile2.content); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("configuredProjects", "add new files to a configured project without file list", projectService); + baselineTsserverLogs( + "configuredProjects", + "add new files to a configured project without file list", + projectService, + ); }); it("should ignore non-existing files specified in the config file", () => { @@ -145,19 +161,23 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "commonFile1.ts", "commonFile3.ts" ] - }` + }`, }; const host = createServerHost([commonFile1, commonFile2, configFile]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(commonFile1.path); projectService.openClientFile(commonFile2.path); - baselineTsserverLogs("configuredProjects", "should ignore non-existing files specified in the config file", projectService); + baselineTsserverLogs( + "configuredProjects", + "should ignore non-existing files specified in the config file", + projectService, + ); }); it("handle recreated files correctly", () => { const configFile: File = { path: "/a/b/tsconfig.json", - content: `{}` + content: `{}`, }; const host = createServerHost([commonFile1, commonFile2, configFile]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -179,11 +199,11 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { content: `{ "compilerOptions": {}, "exclude": ["/a/c"] - }` + }`, }; const excludedFile1: File = { path: "/a/c/excluedFile1.ts", - content: `let t = 1;` + content: `let t = 1;`, }; const host = createServerHost([commonFile1, commonFile2, excludedFile1, configFile]); @@ -197,19 +217,19 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { it("should properly handle module resolution changes in config file", () => { const file1: File = { path: "/a/b/file1.ts", - content: `import { T } from "module1";` + content: `import { T } from "module1";`, }; const nodeModuleFile: File = { path: "/a/b/node_modules/module1.ts", - content: `export interface T {}` + content: `export interface T {}`, }; const classicModuleFile: File = { path: "/a/module1.ts", - content: `export interface T {}` + content: `export interface T {}`, }; const randomFile: File = { path: "/a/file1.ts", - content: `export interface T {}` + content: `export interface T {}`, }; const configFile: File = { path: "/a/b/tsconfig.json", @@ -218,7 +238,7 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "moduleResolution": "node" }, "files": ["${file1.path}"] - }` + }`, }; const files = [file1, nodeModuleFile, classicModuleFile, configFile, randomFile]; const host = createServerHost(files); @@ -227,13 +247,15 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { projectService.openClientFile(nodeModuleFile.path); projectService.openClientFile(classicModuleFile.path); - - host.writeFile(configFile.path, `{ + host.writeFile( + configFile.path, + `{ "compilerOptions": { "moduleResolution": "classic" }, "files": ["${file1.path}"] - }`); + }`, + ); host.runQueuedTimeoutCallbacks(); // will not remove project 1 @@ -241,17 +263,21 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { // Open random file and it will reuse first inferred project projectService.openClientFile(randomFile.path); - baselineTsserverLogs("configuredProjects", "should properly handle module resolution changes in config file", projectService); + baselineTsserverLogs( + "configuredProjects", + "should properly handle module resolution changes in config file", + projectService, + ); }); it("should keep the configured project when the opened file is referenced by the project but not its root", () => { const file1: File = { path: "/a/b/main.ts", - content: "import { objA } from './obj-a';" + content: "import { objA } from './obj-a';", }; const file2: File = { path: "/a/b/obj-a.ts", - content: `export const objA = Object.assign({foo: "bar"}, {bar: "baz"});` + content: `export const objA = Object.assign({foo: "bar"}, {bar: "baz"});`, }; const configFile: File = { path: "/a/b/tsconfig.json", @@ -260,14 +286,18 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "target": "es6" }, "files": [ "main.ts" ] - }` + }`, }; const host = createServerHost([file1, file2, configFile]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(file1.path); projectService.closeClientFile(file1.path); projectService.openClientFile(file2.path); - baselineTsserverLogs("configuredProjects", "should keep the configured project when the opened file is referenced by the project but not its root", projectService); + baselineTsserverLogs( + "configuredProjects", + "should keep the configured project when the opened file is referenced by the project but not its root", + projectService, + ); }); it("should tolerate config file errors and still try to build a project", () => { @@ -279,22 +309,26 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "allowAnything": true }, "someOtherProperty": {} - }` + }`, }; const host = createServerHost([commonFile1, commonFile2, libFile, configFile]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(commonFile1.path); - baselineTsserverLogs("configuredProjects", "should tolerate config file errors and still try to build a project", projectService); + baselineTsserverLogs( + "configuredProjects", + "should tolerate config file errors and still try to build a project", + projectService, + ); }); it("should reuse same project if file is opened from the configured project that has no open files", () => { const file1 = { path: "/a/b/main.ts", - content: "let x =1;" + content: "let x =1;", }; const file2 = { path: "/a/b/main2.ts", - content: "let y =1;" + content: "let y =1;", }; const configFile: File = { path: "/a/b/tsconfig.json", @@ -303,10 +337,13 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "target": "es6" }, "files": [ "main.ts", "main2.ts" ] - }` + }`, }; const host = createServerHost([file1, file2, configFile, libFile]); - const projectService = createProjectService(host, { useSingleInferredProject: true, logger: createLoggerWithInMemoryLogs(host) }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + logger: createLoggerWithInMemoryLogs(host), + }); projectService.openClientFile(file1.path); logConfiguredProjectsHasOpenRefStatus(projectService); // file1 @@ -315,13 +352,17 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { projectService.openClientFile(file2.path); logConfiguredProjectsHasOpenRefStatus(projectService); // file2 - baselineTsserverLogs("configuredProjects", "should reuse same project if file is opened from the configured project that has no open files", projectService); + baselineTsserverLogs( + "configuredProjects", + "should reuse same project if file is opened from the configured project that has no open files", + projectService, + ); }); it("should not close configured project after closing last open file, but should be closed on next file open if its not the file from same project", () => { const file1 = { path: "/a/b/main.ts", - content: "let x =1;" + content: "let x =1;", }; const configFile: File = { path: "/a/b/tsconfig.json", @@ -330,10 +371,13 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { "target": "es6" }, "files": [ "main.ts" ] - }` + }`, }; const host = createServerHost([file1, configFile, libFile]); - const projectService = createProjectService(host, { useSingleInferredProject: true, logger: createLoggerWithInMemoryLogs(host) }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + logger: createLoggerWithInMemoryLogs(host), + }); projectService.openClientFile(file1.path); logConfiguredProjectsHasOpenRefStatus(projectService); // file1 @@ -342,25 +386,29 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { projectService.openClientFile(libFile.path); logConfiguredProjectsHasOpenRefStatus(projectService); // No files + project closed - baselineTsserverLogs("configuredProjects", "should not close configured project after closing last open file, but should be closed on next file open if its not the file from same project", projectService); + baselineTsserverLogs( + "configuredProjects", + "should not close configured project after closing last open file, but should be closed on next file open if its not the file from same project", + projectService, + ); }); it("open file become a part of configured project if it is referenced from root file", () => { const file1 = { path: `/user/username/projects/myproject/a/b/f1.ts`, - content: "export let x = 5" + content: "export let x = 5", }; const file2 = { path: `/user/username/projects/myproject/a/c/f2.ts`, - content: `import {x} from "../b/f1"` + content: `import {x} from "../b/f1"`, }; const file3 = { path: `/user/username/projects/myproject/a/c/f3.ts`, - content: "export let y = 1" + content: "export let y = 1", }; const configFile = { path: `/user/username/projects/myproject/a/c/tsconfig.json`, - content: JSON.stringify({ compilerOptions: {}, files: ["f2.ts", "f3.ts"] }) + content: JSON.stringify({ compilerOptions: {}, files: ["f2.ts", "f3.ts"] }), }; const host = createServerHost([file1, file2, file3]); @@ -373,21 +421,25 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { host.writeFile(configFile.path, configFile.content); host.runQueuedTimeoutCallbacks(); // load configured project from disk + ensureProjectsForOpenFiles logInferredProjectsOrphanStatus(projectService); - baselineTsserverLogs("configuredProjects", "open file become a part of configured project if it is referenced from root file", projectService); + baselineTsserverLogs( + "configuredProjects", + "open file become a part of configured project if it is referenced from root file", + projectService, + ); }); it("can correctly update configured project when set of root files has changed (new file on disk)", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const configFile = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: {} }) + content: JSON.stringify({ compilerOptions: {} }), }; const host = createServerHost([file1, configFile]); @@ -399,21 +451,25 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("configuredProjects", "can correctly update configured project when set of root files has changed (new file on disk)", projectService); + baselineTsserverLogs( + "configuredProjects", + "can correctly update configured project when set of root files has changed (new file on disk)", + projectService, + ); }); it("can correctly update configured project when set of root files has changed (new file in list of files)", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const configFile = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts"] }) + content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts"] }), }; const host = createServerHost([file1, file2, configFile]); @@ -424,21 +480,25 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { host.writeFile(configFile.path, JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] })); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("configuredProjects", "can correctly update configured project when set of root files has changed (new file in list of files)", projectService); + baselineTsserverLogs( + "configuredProjects", + "can correctly update configured project when set of root files has changed (new file in list of files)", + projectService, + ); }); it("can update configured project when set of root files was not changed", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const configFile = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }) + content: JSON.stringify({ compilerOptions: {}, files: ["f1.ts", "f2.ts"] }), }; const host = createServerHost([file1, file2, configFile]); @@ -446,32 +506,39 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { projectService.openClientFile(file1.path); - host.writeFile(configFile.path, JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] })); + host.writeFile( + configFile.path, + JSON.stringify({ compilerOptions: { outFile: "out.js" }, files: ["f1.ts", "f2.ts"] }), + ); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("configuredProjects", "can update configured project when set of root files was not changed", projectService); + baselineTsserverLogs( + "configuredProjects", + "can update configured project when set of root files was not changed", + projectService, + ); }); it("Open ref of configured project when open file gets added to the project as part of configured file update", () => { const file1: File = { path: "/a/b/src/file1.ts", - content: "let x = 1;" + content: "let x = 1;", }; const file2: File = { path: "/a/b/src/file2.ts", - content: "let y = 1;" + content: "let y = 1;", }; const file3: File = { path: "/a/b/file3.ts", - content: "let z = 1;" + content: "let z = 1;", }; const file4: File = { path: "/a/file4.ts", - content: "let z = 1;" + content: "let z = 1;", }; const configFile = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ files: ["src/file1.ts", "file3.ts"] }) + content: JSON.stringify({ files: ["src/file1.ts", "file3.ts"] }), }; const files = [file1, file2, file3, file4]; @@ -506,35 +573,39 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { const file5: File = { path: "/file5.ts", - content: "let zz = 1;" + content: "let zz = 1;", }; host.writeFile(file5.path, file5.content); projectService.testhost.baselineHost("File5 written"); projectService.openClientFile(file5.path); - baselineTsserverLogs("configuredProjects", "Open ref of configured project when open file gets added to the project as part of configured file update", projectService); + baselineTsserverLogs( + "configuredProjects", + "Open ref of configured project when open file gets added to the project as part of configured file update", + projectService, + ); }); it("Open ref of configured project when open file gets added to the project as part of configured file update buts its open file references are all closed when the update happens", () => { const file1: File = { path: "/a/b/src/file1.ts", - content: "let x = 1;" + content: "let x = 1;", }; const file2: File = { path: "/a/b/src/file2.ts", - content: "let y = 1;" + content: "let y = 1;", }; const file3: File = { path: "/a/b/file3.ts", - content: "let z = 1;" + content: "let z = 1;", }; const file4: File = { path: "/a/file4.ts", - content: "let z = 1;" + content: "let z = 1;", }; const configFile = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ files: ["src/file1.ts", "file3.ts"] }) + content: JSON.stringify({ files: ["src/file1.ts", "file3.ts"] }), }; const files = [file1, file2, file3]; @@ -563,25 +634,29 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { host.runQueuedTimeoutCallbacks(); logConfiguredProjectsHasOpenRefStatus(projectService); // file2 logInferredProjectsOrphanStatus(projectService); - baselineTsserverLogs("configuredProjects", "Open ref of configured project when open file gets added to the project as part of configured file update buts its open file references are all closed when the update happens", projectService); + baselineTsserverLogs( + "configuredProjects", + "Open ref of configured project when open file gets added to the project as part of configured file update buts its open file references are all closed when the update happens", + projectService, + ); }); it("files are properly detached when language service is disabled", () => { const f1 = { path: "/a/app.js", - content: "var x = 1" + content: "var x = 1", }; const f2 = { path: "/a/largefile.js", - content: "" + content: "", }; const f3 = { path: "/a/lib.js", - content: "var x = 1" + content: "var x = 1", }; const config = { path: "/a/tsconfig.json", - content: JSON.stringify({ compilerOptions: { allowJs: true } }) + content: JSON.stringify({ compilerOptions: { allowJs: true } }), }; const host = createServerHost([f1, f2, f3, config]); const originalGetFileSize = host.getFileSize; @@ -598,12 +673,16 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { for (const f of [f1, f2, f3]) { // All the script infos should be present and contain the project since it is still alive. const scriptInfo = projectService.getScriptInfoForNormalizedPath(ts.server.toNormalizedPath(f.path))!; - projectService.logger.log(`Containing projects for ${f.path}:: ${scriptInfo.containingProjects.map(p => p.projectName).join(",")}`); + projectService.logger.log( + `Containing projects for ${f.path}:: ${ + scriptInfo.containingProjects.map(p => p.projectName).join(",") + }`, + ); } const f4 = { path: "/aa.js", - content: "var x = 1" + content: "var x = 1", }; host.writeFile(f4.path, f4.content); projectService.openClientFile(f4.path); @@ -613,21 +692,25 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { // All the script infos should not be present since the project is closed and orphan script infos are collected assert.isUndefined(projectService.getScriptInfoForNormalizedPath(ts.server.toNormalizedPath(f.path))); } - baselineTsserverLogs("configuredProjects", "files are properly detached when language service is disabled", projectService); + baselineTsserverLogs( + "configuredProjects", + "files are properly detached when language service is disabled", + projectService, + ); }); it("syntactic features work even if language service is disabled", () => { const f1 = { path: "/a/app.js", - content: "let x = 1;" + content: "let x = 1;", }; const f2 = { path: "/a/largefile.js", - content: "" + content: "", }; const config = { path: "/a/jsconfig.json", - content: "{}" + content: "{}", }; const host = createServerHost([f1, f2, config]); const originalGetFileSize = host.getFileSize; @@ -635,15 +718,23 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { filePath === f2.path ? ts.server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([f1], session); - session.logger.log(`Language languageServiceEnabled:: ${session.getProjectService().configuredProjects.get(config.path)!.languageServiceEnabled}`); + session.logger.log( + `Language languageServiceEnabled:: ${ + session.getProjectService().configuredProjects.get(config.path)!.languageServiceEnabled + }`, + ); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.FormatFull, arguments: { file: f1.path, - } + }, }); - baselineTsserverLogs("configuredProjects", "syntactic features work even if language service is disabled", session); + baselineTsserverLogs( + "configuredProjects", + "syntactic features work even if language service is disabled", + session, + ); }); it("when multiple projects are open, detects correct default project", () => { @@ -652,67 +743,71 @@ describe("unittests:: tsserver:: ConfiguredProjects", () => { content: JSON.stringify({ include: ["index.ts"], compilerOptions: { - lib: ["dom", "es2017"] - } - }) + lib: ["dom", "es2017"], + }, + }), }; const barIndex: File = { path: `/user/username/projects/myproject/bar/index.ts`, content: ` export function bar() { console.log("hello world"); -}` +}`, }; const fooConfig: File = { path: `/user/username/projects/myproject/foo/tsconfig.json`, content: JSON.stringify({ include: ["index.ts"], compilerOptions: { - lib: ["es2017"] - } - }) + lib: ["es2017"], + }, + }), }; const fooIndex: File = { path: `/user/username/projects/myproject/foo/index.ts`, content: ` import { bar } from "bar"; -bar();` +bar();`, }; const barSymLink: SymLink = { path: `/user/username/projects/myproject/foo/node_modules/bar`, - symLink: `/user/username/projects/myproject/bar` + symLink: `/user/username/projects/myproject/bar`, }; const lib2017: File = { path: `${ts.getDirectoryPath(libFile.path)}/lib.es2017.d.ts`, - content: libFile.content + content: libFile.content, }; const libDom: File = { path: `${ts.getDirectoryPath(libFile.path)}/lib.dom.d.ts`, content: ` declare var console: { log(...args: any[]): void; -};` +};`, }; const host = createServerHost([barConfig, barIndex, fooConfig, fooIndex, barSymLink, lib2017, libDom]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([fooIndex, barIndex], session); verifyGetErrRequest({ session, files: [barIndex, fooIndex] }); - baselineTsserverLogs("configuredProjects", "when multiple projects are open detects correct default project", session); + baselineTsserverLogs( + "configuredProjects", + "when multiple projects are open detects correct default project", + session, + ); }); it("when file name starts with ^", () => { const file: File = { path: `/user/username/projects/myproject/file.ts`, - content: "const x = 10;" + content: "const x = 10;", }; const app: File = { path: `/user/username/projects/myproject/^app.ts`, - content: "const y = 10;" + content: "const y = 10;", }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const host = createServerHost([file, app, tsconfig, libFile]); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -723,34 +818,40 @@ declare var console: { describe("when creating new file", () => { const foo: File = { path: `/user/username/projects/myproject/src/foo.ts`, - content: "export function foo() { }" + content: "export function foo() { }", }; const bar: File = { path: `/user/username/projects/myproject/src/bar.ts`, - content: "export function bar() { }" + content: "export function bar() { }", }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ - include: ["./src"] - }) + include: ["./src"], + }), }; const fooBar: File = { path: `/user/username/projects/myproject/src/sub/fooBar.ts`, - content: "export function fooBar() { }" + content: "export function fooBar() { }", }; - function verifySessionWorker({ withExclude, openFileBeforeCreating }: VerifySession, errorOnNewFileBeforeOldFile: boolean) { + function verifySessionWorker( + { withExclude, openFileBeforeCreating }: VerifySession, + errorOnNewFileBeforeOldFile: boolean, + ) { const host = createServerHost([ - foo, bar, libFile, { path: `/user/username/projects/myproject/src/sub` }, - withExclude ? - { + foo, + bar, + libFile, + { path: `/user/username/projects/myproject/src/sub` }, + withExclude + ? { path: config.path, content: JSON.stringify({ include: ["./src"], - exclude: ["./src/sub"] - }) - } : - config + exclude: ["./src/sub"], + }), + } + : config, ]); const session = createSession(host, { canUseEvents: true, @@ -761,8 +862,8 @@ declare var console: { arguments: { file: foo.path, fileContent: foo.content, - projectRootPath: "/user/username/projects/myproject" - } + projectRootPath: "/user/username/projects/myproject", + }, }); if (!openFileBeforeCreating) { host.writeFile(fooBar.path, fooBar.content); @@ -772,20 +873,28 @@ declare var console: { arguments: { file: fooBar.path, fileContent: fooBar.content, - projectRootPath: "/user/username/projects/myproject" - } + projectRootPath: "/user/username/projects/myproject", + }, }); if (openFileBeforeCreating) { host.writeFile(fooBar.path, fooBar.content); } verifyGetErrRequest({ session, - files: errorOnNewFileBeforeOldFile ? - [fooBar, foo] : - [foo, fooBar], - existingTimeouts: !withExclude + files: errorOnNewFileBeforeOldFile + ? [fooBar, foo] + : [foo, fooBar], + existingTimeouts: !withExclude, }); - baselineTsserverLogs("configuredProjects", `creating new file and then open it ${openFileBeforeCreating ? "before" : "after"} watcher is invoked, ask errors on it ${errorOnNewFileBeforeOldFile ? "before" : "after"} old one${withExclude ? " without file being in config" : ""}`, session); + baselineTsserverLogs( + "configuredProjects", + `creating new file and then open it ${ + openFileBeforeCreating ? "before" : "after" + } watcher is invoked, ask errors on it ${errorOnNewFileBeforeOldFile ? "before" : "after"} old one${ + withExclude ? " without file being in config" : "" + }`, + session, + ); } interface VerifySession { withExclude?: boolean; @@ -828,20 +937,20 @@ declare var console: { it("when default configured project does not contain the file", () => { const barConfig: File = { path: `/user/username/projects/myproject/bar/tsconfig.json`, - content: "{}" + content: "{}", }; const barIndex: File = { path: `/user/username/projects/myproject/bar/index.ts`, content: `import {foo} from "../foo/lib"; -foo();` +foo();`, }; const fooBarConfig: File = { path: `/user/username/projects/myproject/foobar/tsconfig.json`, - content: barConfig.path + content: barConfig.path, }; const fooBarIndex: File = { path: `/user/username/projects/myproject/foobar/index.ts`, - content: barIndex.content + content: barIndex.content, }; const fooConfig: File = { path: `/user/username/projects/myproject/foo/tsconfig.json`, @@ -849,13 +958,13 @@ foo();` include: ["index.ts"], compilerOptions: { declaration: true, - outDir: "lib" - } - }) + outDir: "lib", + }, + }), }; const fooIndex: File = { path: `/user/username/projects/myproject/foo/index.ts`, - content: `export function foo() {}` + content: `export function foo() {}`, }; const host = createServerHost([barConfig, barIndex, fooBarConfig, fooBarIndex, fooConfig, fooIndex, libFile]); ensureErrorFreeBuild(host, [fooConfig.path]); @@ -870,92 +979,122 @@ foo();` startLine: 1, startOffset: 1, endLine: 1, - endOffset: 1 - } + endOffset: 1, + }, }); - session.logger.log(`Default project for file: ${fooDts}: ${service.tryGetDefaultProjectForFile(ts.server.toNormalizedPath(fooDts))?.projectName}`); - baselineTsserverLogs("configuredProjects", "when default configured project does not contain the file", session); + session.logger.log( + `Default project for file: ${fooDts}: ${service.tryGetDefaultProjectForFile( + ts.server.toNormalizedPath(fooDts), + )?.projectName}`, + ); + baselineTsserverLogs( + "configuredProjects", + "when default configured project does not contain the file", + session, + ); }); describe("watches extended config files", () => { function getService(additionalFiles?: File[]) { const alphaExtendedConfig: File = { path: `/user/username/projects/myproject/extended/alpha.tsconfig.json`, - content: "{}" + content: "{}", }; const bravoExtendedConfig: File = { path: `/user/username/projects/myproject/extended/bravo.tsconfig.json`, content: JSON.stringify({ - extends: "./alpha.tsconfig.json" - }) + extends: "./alpha.tsconfig.json", + }), }; const aConfig: File = { path: `/user/username/projects/myproject/a/tsconfig.json`, content: JSON.stringify({ extends: "../extended/alpha.tsconfig.json", - files: ["a.ts"] - }) + files: ["a.ts"], + }), }; const aFile: File = { path: `/user/username/projects/myproject/a/a.ts`, - content: `let a = 1;` + content: `let a = 1;`, }; const bConfig: File = { path: `/user/username/projects/myproject/b/tsconfig.json`, content: JSON.stringify({ extends: "../extended/bravo.tsconfig.json", - files: ["b.ts"] - }) + files: ["b.ts"], + }), }; const bFile: File = { path: `/user/username/projects/myproject/b/b.ts`, - content: `let b = 1;` + content: `let b = 1;`, }; - const host = createServerHost([alphaExtendedConfig, aConfig, aFile, bravoExtendedConfig, bConfig, bFile, ...(additionalFiles || ts.emptyArray)]); + const host = createServerHost([ + alphaExtendedConfig, + aConfig, + aFile, + bravoExtendedConfig, + bConfig, + bFile, + ...(additionalFiles || ts.emptyArray), + ]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); return { host, projectService, aFile, bFile, aConfig, bConfig, alphaExtendedConfig, bravoExtendedConfig }; } it("should watch the extended configs of multiple projects", () => { - const { host, projectService, aFile, bFile, bConfig, alphaExtendedConfig, bravoExtendedConfig } = getService(); + const { host, projectService, aFile, bFile, bConfig, alphaExtendedConfig, bravoExtendedConfig } = + getService(); projectService.openClientFile(aFile.path); projectService.openClientFile(bFile.path); - host.writeFile(alphaExtendedConfig.path, JSON.stringify({ - compilerOptions: { - strict: true - } - })); + host.writeFile( + alphaExtendedConfig.path, + JSON.stringify({ + compilerOptions: { + strict: true, + }, + }), + ); host.runQueuedTimeoutCallbacks(); - host.writeFile(bravoExtendedConfig.path, JSON.stringify({ - extends: "./alpha.tsconfig.json", - compilerOptions: { - strict: false - } - })); + host.writeFile( + bravoExtendedConfig.path, + JSON.stringify({ + extends: "./alpha.tsconfig.json", + compilerOptions: { + strict: false, + }, + }), + ); host.runQueuedTimeoutCallbacks(); - host.writeFile(bConfig.path, JSON.stringify({ - extends: "../extended/alpha.tsconfig.json", - })); + host.writeFile( + bConfig.path, + JSON.stringify({ + extends: "../extended/alpha.tsconfig.json", + }), + ); host.runQueuedTimeoutCallbacks(); host.writeFile(alphaExtendedConfig.path, "{}"); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("configuredProjects", "should watch the extended configs of multiple projects", projectService); + baselineTsserverLogs( + "configuredProjects", + "should watch the extended configs of multiple projects", + projectService, + ); }); it("should stop watching the extended configs of closed projects", () => { const dummy: File = { path: `/user/username/projects/myproject/dummy/dummy.ts`, - content: `let dummy = 1;` + content: `let dummy = 1;`, }; const dummyConfig: File = { path: `/user/username/projects/myproject/dummy/tsconfig.json`, - content: "{}" + content: "{}", }; const { projectService, aFile, bFile } = getService([dummy, dummyConfig]); @@ -967,11 +1106,14 @@ foo();` projectService.closeClientFile(dummy.path); projectService.openClientFile(dummy.path); - projectService.closeClientFile(aFile.path); projectService.closeClientFile(dummy.path); projectService.openClientFile(dummy.path); - baselineTsserverLogs("configuredProjects", "should stop watching the extended configs of closed projects", projectService); + baselineTsserverLogs( + "configuredProjects", + "should stop watching the extended configs of closed projects", + projectService, + ); }); }); }); @@ -983,11 +1125,11 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l content: `{ "compilerOptions": {}, "include": ["app/*", "test/**/*", "something"] - }` + }`, }; const file1 = { path: "/a/b/file1.ts", - content: "let t = 10;" + content: "let t = 10;", }; const host = createServerHost([file1, configFile]); @@ -1002,72 +1144,80 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l it("should be able to handle @types if input file list is empty", () => { const f = { path: "/a/app.ts", - content: "let x = 1" + content: "let x = 1", }; const config = { path: "/a/tsconfig.json", content: JSON.stringify({ compiler: {}, - files: [] - }) + files: [], + }), }; const t1 = { path: "/a/node_modules/@types/typings/index.d.ts", - content: `export * from "./lib"` + content: `export * from "./lib"`, }; const t2 = { path: "/a/node_modules/@types/typings/lib.d.ts", - content: `export const x: number` + content: `export const x: number`, }; const host = createServerHost([f, config, t1, t2], { currentDirectory: ts.getDirectoryPath(f.path) }); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(f.path); // Since f refers to config file as the default project, it needs to be kept alive - baselineTsserverLogs("configuredProjects", "should be able to handle @types if input file list is empty", projectService); + baselineTsserverLogs( + "configuredProjects", + "should be able to handle @types if input file list is empty", + projectService, + ); }); it("should tolerate invalid include files that start in subDirectory", () => { const f = { path: `/user/username/projects/myproject/src/server/index.ts`, - content: "let x = 1" + content: "let x = 1", }; const config = { path: `/user/username/projects/myproject/src/server/tsconfig.json`, content: JSON.stringify({ compiler: { module: "commonjs", - outDir: "../../build" + outDir: "../../build", }, include: [ - "../src/**/*.ts" - ] - }) + "../src/**/*.ts", + ], + }), }; const host = createServerHost([f, config, libFile], { useCaseSensitiveFileNames: true }); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(f.path); // Since f refers to config file as the default project, it needs to be kept alive - baselineTsserverLogs("configuredProjects", "should tolerate invalid include files that start in subDirectory", projectService); + baselineTsserverLogs( + "configuredProjects", + "should tolerate invalid include files that start in subDirectory", + projectService, + ); }); it("Changed module resolution reflected when specifying files list", () => { const file1: File = { path: "/users/username/projects/project/file1.ts", - content: 'import classc from "file2"' + content: 'import classc from "file2"', }; const file2a: File = { path: "/users/username/projects/file2.ts", - content: "export classc { method2a() { return 10; } }" + content: "export classc { method2a() { return 10; } }", }; const file2: File = { path: "/users/username/projects/project/file2.ts", - content: "export classc { method2() { return 10; } }" + content: "export classc { method2() { return 10; } }", }; const configFile: File = { path: "/users/username/projects/project/tsconfig.json", - content: JSON.stringify({ files: [file1.path], compilerOptions: { module: "amd" } }) + content: JSON.stringify({ files: [file1.path], compilerOptions: { module: "amd" } }), }; const files = [file1, file2a, configFile, libFile]; const host = createServerHost(files); @@ -1080,31 +1230,35 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l // On next file open the files file2a should be closed and not watched any more projectService.openClientFile(file2.path); - baselineTsserverLogs("configuredProjects", "changed module resolution reflected when specifying files list", projectService); + baselineTsserverLogs( + "configuredProjects", + "changed module resolution reflected when specifying files list", + projectService, + ); }); it("Failed lookup locations uses parent most node_modules directory", () => { const root = "/user/username/rootfolder"; const file1: File = { path: "/a/b/src/file1.ts", - content: 'import { classc } from "module1"' + content: 'import { classc } from "module1"', }; const module1: File = { path: "/a/b/node_modules/module1/index.d.ts", content: `import { class2 } from "module2"; - export classc { method2a(): class2; }` + export classc { method2a(): class2; }`, }; const module2: File = { path: "/a/b/node_modules/module2/index.d.ts", - content: "export class2 { method2() { return 10; } }" + content: "export class2 { method2() { return 10; } }", }; const module3: File = { path: "/a/b/node_modules/module/node_modules/module3/index.d.ts", - content: "export class3 { method2() { return 10; } }" + content: "export class3 { method2() { return 10; } }", }; const configFile: File = { path: "/a/b/src/tsconfig.json", - content: JSON.stringify({ files: ["file1.ts"] }) + content: JSON.stringify({ files: ["file1.ts"] }), }; const nonLibFiles = [file1, module1, module2, module3, configFile]; nonLibFiles.forEach(f => f.path = root + f.path); @@ -1112,7 +1266,11 @@ describe("unittests:: tsserver:: ConfiguredProjects:: non-existing directories l const host = createServerHost(files); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(file1.path); - baselineTsserverLogs("configuredProjects", "failed lookup locations uses parent most node_modules directory", projectService); + baselineTsserverLogs( + "configuredProjects", + "failed lookup locations uses parent most node_modules directory", + projectService, + ); }); }); @@ -1120,23 +1278,27 @@ describe("unittests:: tsserver:: ConfiguredProjects:: when reading tsconfig file it("should be tolerated without crashing the server", () => { const configFile = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "" + content: "", }; const file1 = { path: `/user/username/projects/myproject/file1.ts`, - content: "let t = 10;" + content: "let t = 10;", }; const host = createServerHost([file1, libFile, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); const originalReadFile = host.readFile; host.readFile = f => { - return f === configFile.path ? - undefined : - originalReadFile.call(host, f); + return f === configFile.path + ? undefined + : originalReadFile.call(host, f); }; openFilesForSession([file1], session); - baselineTsserverLogs("configuredProjects", "should be tolerated without crashing the server when reading tsconfig file fails", session); + baselineTsserverLogs( + "configuredProjects", + "should be tolerated without crashing the server when reading tsconfig file fails", + session, + ); }); }); diff --git a/src/testRunner/unittests/tsserver/declarationFileMaps.ts b/src/testRunner/unittests/tsserver/declarationFileMaps.ts index 1539380be3728..a301bbefeff37 100644 --- a/src/testRunner/unittests/tsserver/declarationFileMaps.ts +++ b/src/testRunner/unittests/tsserver/declarationFileMaps.ts @@ -15,9 +15,18 @@ import { function checkDeclarationFiles(file: File, session: TestSession): void { openFilesForSession([file], session); - const project = ts.Debug.checkDefined(session.getProjectService().getDefaultProjectForFile(file.path as ts.server.NormalizedPath, /*ensureProject*/ false)); + const project = ts.Debug.checkDefined( + session.getProjectService().getDefaultProjectForFile( + file.path as ts.server.NormalizedPath, + /*ensureProject*/ false, + ), + ); const program = project.getCurrentProgram()!; - const output = ts.getFileEmitOutput(program, ts.Debug.checkDefined(program.getSourceFile(file.path)), /*emitOnlyDtsFiles*/ true); + const output = ts.getFileEmitOutput( + program, + ts.Debug.checkDefined(program.getSourceFile(file.path)), + /*emitOnlyDtsFiles*/ true, + ); session.logger.log(`ts.getFileEmitOutput: ${file.path}: ${JSON.stringify(output, undefined, " ")}`); closeFilesForSession([file], session); } @@ -42,7 +51,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references sourceRoot: "", sources: ["../a.ts"], names: [], - mappings: "AAAA,wBAAgB,GAAG,SAAK;AACxB,MAAM,WAAW,MAAM;CAAG;AAC1B,eAAO,MAAM,SAAS,EAAE,MAAW,CAAC" + mappings: "AAAA,wBAAgB,GAAG,SAAK;AACxB,MAAM,WAAW,MAAM;CAAG;AAC1B,eAAO,MAAM,SAAS,EAAE,MAAW,CAAC", }; const aDtsMap: File = { path: "/a/bin/a.d.ts.map", @@ -51,7 +60,8 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const aDts: File = { path: "/a/bin/a.d.ts", // ${""} is needed to mangle the sourceMappingURL part or it breaks the build - content: `export declare function fnA(): void;\nexport interface IfaceA {\n}\nexport declare const instanceA: IfaceA;\n//# source${""}MappingURL=a.d.ts.map`, + content: + `export declare function fnA(): void;\nexport interface IfaceA {\n}\nexport declare const instanceA: IfaceA;\n//# source${""}MappingURL=a.d.ts.map`, }; const bTs: File = { @@ -80,29 +90,42 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const dummyFile: File = { path: "/dummy/dummy.ts", - content: "let a = 10;" + content: "let a = 10;", }; const userTs: File = { path: "/user/user.ts", - content: 'import * as a from "../a/bin/a";\nimport * as b from "../b/bin/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }', + content: + 'import * as a from "../a/bin/a";\nimport * as b from "../b/bin/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }', }; const userTsForConfigProject: File = { path: "/user/user.ts", - content: 'import * as a from "../a/a";\nimport * as b from "../b/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }', + content: + 'import * as a from "../a/a";\nimport * as b from "../b/b";\nexport function fnUser() { a.fnA(); b.fnB(); a.instanceA; }', }; const userTsconfig: File = { path: "/user/tsconfig.json", content: JSON.stringify({ file: ["user.ts"], - references: [{ path: "../a" }, { path: "../b" }] - }) + references: [{ path: "../a" }, { path: "../b" }], + }), }; function makeSampleProjects(addUserTsConfig?: boolean, keepAllFiles?: boolean) { - const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, ...(addUserTsConfig ? [userTsForConfigProject, userTsconfig] : [userTs]), dummyFile]); + const host = createServerHost([ + aTs, + aTsconfig, + aDtsMap, + aDts, + bTsconfig, + bTs, + bDtsMap, + bDts, + ...(addUserTsConfig ? [userTsForConfigProject, userTsconfig] : [userTs]), + dummyFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); checkDeclarationFiles(aTs, session); @@ -138,7 +161,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Definition, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "goToDefinition", session); @@ -148,7 +171,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "getDefinitionAndBoundSpan", session); @@ -158,7 +181,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(/*addUserTsConfig*/ true); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); // Navigate to the definition @@ -175,7 +198,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.TypeDefinition, - arguments: protocolFileLocationFromSubstring(userTs, "instanceA") + arguments: protocolFileLocationFromSubstring(userTs, "instanceA"), }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "goToType", session); @@ -185,7 +208,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Implementation, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "goToImplementation", session); @@ -195,7 +218,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Definition, - arguments: protocolFileLocationFromSubstring(userTs, "fnB()") + arguments: protocolFileLocationFromSubstring(userTs, "fnB()"), }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "goToDefinition target does not exist", session); @@ -205,7 +228,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Navto, - arguments: { file: userTs.path, searchValue: "fn" } + arguments: { file: userTs.path, searchValue: "fn" }, }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "navigateTo", session); @@ -215,7 +238,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(/*addUserTsConfig*/ true, /*keepAllFiles*/ true); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Navto, - arguments: { file: undefined, searchValue: "fn" } + arguments: { file: undefined, searchValue: "fn" }, }); baselineTsserverLogs("declarationFileMaps", "navigateToAll neither file not project is specified", session); }); @@ -224,7 +247,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(/*addUserTsConfig*/ true, /*keepAllFiles*/ true); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Navto, - arguments: { projectFileName: bTsconfig.path, file: undefined, searchValue: "fn" } + arguments: { projectFileName: bTsconfig.path, file: undefined, searchValue: "fn" }, }); baselineTsserverLogs("declarationFileMaps", "navigateToAll file is not specified but project is", session); }); @@ -233,7 +256,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); verifyATsConfigOriginalProject(session); @@ -245,19 +268,21 @@ describe("unittests:: tsserver:: with declaration file maps:: project references openFilesForSession([aTs], session); // If it's not opened, the reference isn't found. session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(aTs, "fnA") + arguments: protocolFileLocationFromSubstring(aTs, "fnA"), }); verifyATsConfigWhenOpened(session); baselineTsserverLogs("declarationFileMaps", "findAllReferences starting at definition", session); }); - interface ReferencesFullRequest extends ts.server.protocol.FileLocationRequest { readonly command: ts.server.protocol.CommandTypes.ReferencesFull; } + interface ReferencesFullRequest extends ts.server.protocol.FileLocationRequest { + readonly command: ts.server.protocol.CommandTypes.ReferencesFull; + } it("findAllReferencesFull", () => { const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.ReferencesFull, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); verifyATsConfigOriginalProject(session); baselineTsserverLogs("declarationFileMaps", "findAllReferencesFull", session); @@ -267,14 +292,29 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const aTs: File = { path: "/a/a.ts", content: `function f() {}` }; const aTsconfig: File = { path: "/a/tsconfig.json", - content: JSON.stringify({ compilerOptions: { declaration: true, declarationMap: true, outFile: "../bin/a.js" } }), + content: JSON.stringify({ + compilerOptions: { declaration: true, declarationMap: true, outFile: "../bin/a.js" }, + }), }; const bTs: File = { path: "/b/b.ts", content: `f();` }; - const bTsconfig: File = { path: "/b/tsconfig.json", content: JSON.stringify({ references: [{ path: "../a" }] }) }; - const aDts: File = { path: "/bin/a.d.ts", content: `declare function f(): void;\n//# sourceMappingURL=a.d.ts.map` }; + const bTsconfig: File = { + path: "/b/tsconfig.json", + content: JSON.stringify({ references: [{ path: "../a" }] }), + }; + const aDts: File = { + path: "/bin/a.d.ts", + content: `declare function f(): void;\n//# sourceMappingURL=a.d.ts.map`, + }; const aDtsMap: File = { path: "/bin/a.d.ts.map", - content: JSON.stringify({ version: 3, file: "a.d.ts", sourceRoot: "", sources: ["../a/a.ts"], names: [], mappings: "AAAA,iBAAS,CAAC,SAAK" }), + content: JSON.stringify({ + version: 3, + file: "a.d.ts", + sourceRoot: "", + sources: ["../a/a.ts"], + names: [], + mappings: "AAAA,iBAAS,CAAC,SAAK", + }), }; const host = createServerHost([aTs, aTsconfig, bTs, bTsconfig, aDts, aDtsMap]); @@ -284,7 +324,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.ReferencesFull, - arguments: protocolFileLocationFromSubstring(bTs, "f()") + arguments: protocolFileLocationFromSubstring(bTs, "f()"), }); baselineTsserverLogs("declarationFileMaps", "findAllReferencesFull definition is in mapped file", session); }); @@ -293,7 +333,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(userTs, "fnB()") + arguments: protocolFileLocationFromSubstring(userTs, "fnB()"), }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "findAllReferences target does not exist", session); @@ -303,7 +343,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Rename, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); verifyATsConfigOriginalProject(session); baselineTsserverLogs("declarationFileMaps", "renameLocations", session); @@ -314,7 +354,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references openFilesForSession([aTs], session); // If it's not opened, the reference isn't found. session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Rename, - arguments: protocolFileLocationFromSubstring(aTs, "fnA") + arguments: protocolFileLocationFromSubstring(aTs, "fnA"), }); verifyATsConfigWhenOpened(session); baselineTsserverLogs("declarationFileMaps", "renameLocations starting at definition", session); @@ -324,7 +364,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.RenameLocationsFull, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); verifyATsConfigOriginalProject(session); baselineTsserverLogs("declarationFileMaps", "renameLocationsFull", session); @@ -334,7 +374,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references const session = makeSampleProjects(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Rename, - arguments: protocolFileLocationFromSubstring(userTs, "fnB()") + arguments: protocolFileLocationFromSubstring(userTs, "fnB()"), }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "renameLocations target does not exist", session); @@ -347,7 +387,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references arguments: { oldFilePath: aTs.path, newFilePath: "/a/aNew.ts", - } + }, }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "getEditsForFileRename", session); @@ -363,7 +403,7 @@ describe("unittests:: tsserver:: with declaration file maps:: project references declaration: true, declarationMap: true, outDir: "./build", - } + }, }), }; const bTs: File = { path: "/b/src/b.ts", content: "" }; @@ -387,19 +427,23 @@ describe("unittests:: tsserver:: with declaration file maps:: project references arguments: { oldFilePath: aTs.path, newFilePath: "/a/src/a1.ts", - } + }, }); - baselineTsserverLogs("declarationFileMaps", "getEditsForFileRename when referencing project doesnt include file and its renamed", session); + baselineTsserverLogs( + "declarationFileMaps", + "getEditsForFileRename when referencing project doesnt include file and its renamed", + session, + ); }); it("does not jump to source if inlined sources", () => { const aDtsInlinedSources: ts.RawSourceMap = { ...aDtsMapContent, - sourcesContent: [aTs.content] + sourcesContent: [aTs.content], }; const aDtsMapInlinedSources: File = { path: aDtsMap.path, - content: JSON.stringify(aDtsInlinedSources) + content: JSON.stringify(aDtsInlinedSources), }; const host = createServerHost([aTs, aDtsMapInlinedSources, aDts, bTs, bDtsMap, bDts, userTs, dummyFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -410,13 +454,13 @@ describe("unittests:: tsserver:: with declaration file maps:: project references // Inlined so does not jump to aTs session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: protocolFileLocationFromSubstring(userTs, "fnA()") + arguments: protocolFileLocationFromSubstring(userTs, "fnA()"), }); // Not inlined, jumps to bTs session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: protocolFileLocationFromSubstring(userTs, "fnB()") + arguments: protocolFileLocationFromSubstring(userTs, "fnB()"), }); verifySingleInferredProject(session); baselineTsserverLogs("declarationFileMaps", "does not jump to source if inlined sources", session); diff --git a/src/testRunner/unittests/tsserver/documentRegistry.ts b/src/testRunner/unittests/tsserver/documentRegistry.ts index 3b3a5b63150dd..0b71a8b01fa1f 100644 --- a/src/testRunner/unittests/tsserver/documentRegistry.ts +++ b/src/testRunner/unittests/tsserver/documentRegistry.ts @@ -1,4 +1,6 @@ -import { reportDocumentRegistryStats } from "../../../harness/incrementalUtils"; +import { + reportDocumentRegistryStats, +} from "../../../harness/incrementalUtils"; import * as ts from "../../_namespaces/ts"; import { baselineTsserverLogs, @@ -19,15 +21,15 @@ describe("unittests:: tsserver:: documentRegistry:: document registry in project const importModuleContent = `import {a} from "./module1"`; const file: File = { path: `/user/username/projects/myproject/index.ts`, - content: importModuleContent + content: importModuleContent, }; const moduleFile: File = { path: `/user/username/projects/myproject/module1.d.ts`, - content: "export const a: number;" + content: "export const a: number;", }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ files: ["index.ts"] }) + content: JSON.stringify({ files: ["index.ts"] }), }; function getProject(service: TestProjectService) { @@ -55,13 +57,19 @@ describe("unittests:: tsserver:: documentRegistry:: document registry in project function changeFileToNotImportModule(service: TestProjectService) { const info = service.getScriptInfo(file.path)!; - service.applyChangesToFile(info, ts.singleIterator({ span: { start: 0, length: importModuleContent.length }, newText: "" })); + service.applyChangesToFile( + info, + ts.singleIterator({ span: { start: 0, length: importModuleContent.length }, newText: "" }), + ); checkProject(service, /*moduleIsOrphan*/ true); } function changeFileToImportModule(service: TestProjectService) { const info = service.getScriptInfo(file.path)!; - service.applyChangesToFile(info, ts.singleIterator({ span: { start: 0, length: 0 }, newText: importModuleContent })); + service.applyChangesToFile( + info, + ts.singleIterator({ span: { start: 0, length: 0 }, newText: importModuleContent }), + ); checkProject(service, /*moduleIsOrphan*/ false); } @@ -104,14 +112,21 @@ describe("unittests:: tsserver:: documentRegistry:: document registry in project assert.notEqual(moduleInfo.cacheSourceFile!.sourceFile, sourceFile); assert.equal(project.getSourceFile(moduleInfo.path), moduleInfo.cacheSourceFile!.sourceFile); assert.equal(moduleInfo.cacheSourceFile!.sourceFile.text, updatedModuleContent); - baselineTsserverLogs("documentRegistry", "Caches the source file if script info is orphan, and orphan script info changes", service); + baselineTsserverLogs( + "documentRegistry", + "Caches the source file if script info is orphan, and orphan script info changes", + service, + ); }); }); describe("unittests:: tsserver:: documentRegistry:: works when reusing orphan script info with different scriptKind", () => { it("works when reusing orphan script info with different scriptKind", () => { const host = createServerHost({}); - const session = createSession(host, { useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + useInferredProjectPerProjectRoot: true, + logger: createLoggerWithInMemoryLogs(host), + }); const newText = "exrpot const x = 10;"; const content = `import x from 'react';\n${newText}`; openFilesForSession([ @@ -127,19 +142,23 @@ describe("unittests:: tsserver:: documentRegistry:: works when reusing orphan sc textChanges: [{ newText, start: { line: 1, offset: 1 }, - end: { line: 2, offset: newText.length + 1 } // Remove the import so that structure is not reused - }] + end: { line: 2, offset: newText.length + 1 }, // Remove the import so that structure is not reused + }], }], openFiles: [ { file: "^/inmemory/model/4", fileContent: newText, projectRootPath: "/users/user/projects/san", // Add same document with different script kind - scriptKindName: "TS" + scriptKindName: "TS", }, - ] - } + ], + }, }); - baselineTsserverLogs("documentRegistry", "works when reusing orphan script info with different scriptKind", session); + baselineTsserverLogs( + "documentRegistry", + "works when reusing orphan script info with different scriptKind", + session, + ); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/duplicatePackages.ts b/src/testRunner/unittests/tsserver/duplicatePackages.ts index 3d4f31cba11e1..4a957d481ae01 100644 --- a/src/testRunner/unittests/tsserver/duplicatePackages.ts +++ b/src/testRunner/unittests/tsserver/duplicatePackages.ts @@ -43,7 +43,7 @@ describe("unittests:: tsserver:: duplicate packages", () => { endLine: 2, endOffset: 4, errorCodes: [ts.Diagnostics.Cannot_find_name_0.code], - } + }, }); } baselineTsserverLogs("duplicatePackages", "works with import fixes", session); diff --git a/src/testRunner/unittests/tsserver/dynamicFiles.ts b/src/testRunner/unittests/tsserver/dynamicFiles.ts index 4d1c79c582891..42bc1c298f3ea 100644 --- a/src/testRunner/unittests/tsserver/dynamicFiles.ts +++ b/src/testRunner/unittests/tsserver/dynamicFiles.ts @@ -21,7 +21,7 @@ function verifyPathRecognizedAsDynamic(subscenario: string, path: string) { path, content: `/// /// -var x = 10;` +var x = 10;`, }; const host = createServerHost([libFile]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -38,7 +38,10 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => { const aTs: File = { path: "/proj/a.ts", content: "" }; const tsconfig: File = { path: "/proj/tsconfig.json", content: "{}" }; const host = createServerHost([aTs, tsconfig]); - const session = createSession(host, { useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + useInferredProjectPerProjectRoot: true, + logger: createLoggerWithInMemoryLogs(host), + }); openFilesForSession([aTs], session); @@ -46,7 +49,8 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => { command: ts.server.protocol.CommandTypes.Open, arguments: { file: untitledFile, - fileContent: `/// \nlet foo = 1;\nfooo/**/`, + fileContent: + `/// \nlet foo = 1;\nfooo/**/`, scriptKindName: "TS", projectRootPath: "/proj", }, @@ -61,7 +65,7 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => { endLine: 3, endOffset: 5, errorCodes: [ts.Diagnostics.Cannot_find_name_0_Did_you_mean_1.code], - } + }, }); baselineTsserverLogs("dynamicFiles", "untitled can convert positions to locations", session); }); @@ -69,24 +73,42 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => { it("opening untitled files", () => { const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; - const host = createServerHost([config, libFile], { useCaseSensitiveFileNames: true, currentDirectory: "/user/username/projects/myproject" }); + const host = createServerHost([config, libFile], { + useCaseSensitiveFileNames: true, + currentDirectory: "/user/username/projects/myproject", + }); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); - service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, "/user/username/projects/myproject"); + service.openClientFile( + untitledFile, + "const x = 10;", + /*scriptKind*/ undefined, + "/user/username/projects/myproject", + ); verifyDynamic(service, `/user/username/projects/myproject/${untitledFile}`); const untitled: File = { path: `/user/username/projects/myproject/Untitled-1.ts`, - content: "const x = 10;" + content: "const x = 10;", }; host.writeFile(untitled.path, untitled.content); service.testhost.logTimeoutQueueLength(); - service.openClientFile(untitled.path, untitled.content, /*scriptKind*/ undefined, "/user/username/projects/myproject"); + service.openClientFile( + untitled.path, + untitled.content, + /*scriptKind*/ undefined, + "/user/username/projects/myproject", + ); service.closeClientFile(untitledFile); - service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, "/user/username/projects/myproject"); + service.openClientFile( + untitledFile, + "const x = 10;", + /*scriptKind*/ undefined, + "/user/username/projects/myproject", + ); verifyDynamic(service, `/user/username/projects/myproject/${untitledFile}`); baselineTsserverLogs("dynamicFiles", "opening untitled files", service); }); @@ -94,15 +116,23 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => { it("opening and closing untitled files when projectRootPath is different from currentDirectory", () => { const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const file: File = { path: `/user/username/projects/myproject/file.ts`, - content: "const y = 10" + content: "const y = 10", }; const host = createServerHost([config, file, libFile], { useCaseSensitiveFileNames: true }); - const service = createProjectService(host, { useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) }); - service.openClientFile(untitledFile, "const x = 10;", /*scriptKind*/ undefined, "/user/username/projects/myproject"); + const service = createProjectService(host, { + useInferredProjectPerProjectRoot: true, + logger: createLoggerWithInMemoryLogs(host), + }); + service.openClientFile( + untitledFile, + "const x = 10;", + /*scriptKind*/ undefined, + "/user/username/projects/myproject", + ); verifyDynamic(service, `/user/username/projects/myproject/${untitledFile}`); // Close untitled file @@ -110,12 +140,19 @@ describe("unittests:: tsserver:: dynamicFiles:: Untitled files", () => { // Open file from configured project which should collect inferredProject service.openClientFile(file.path); - baselineTsserverLogs("dynamicFiles", "opening and closing untitled files when projectRootPath is different from currentDirectory", service); + baselineTsserverLogs( + "dynamicFiles", + "opening and closing untitled files when projectRootPath is different from currentDirectory", + service, + ); }); it("when changing scriptKind of the untitled files", () => { const host = createServerHost([libFile], { useCaseSensitiveFileNames: true }); - const service = createProjectService(host, { useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) }); + const service = createProjectService(host, { + useInferredProjectPerProjectRoot: true, + logger: createLoggerWithInMemoryLogs(host), + }); service.openClientFile(untitledFile, "const x = 10;", ts.ScriptKind.TS, "/user/username/projects/myproject"); const program = service.inferredProjects[0].getCurrentProgram()!; const sourceFile = program.getSourceFile(untitledFile)!; @@ -137,7 +174,7 @@ describe("unittests:: tsserver:: dynamicFiles:: ", () => { it("dynamic file without external project", () => { const file: File = { path: "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js", - content: "var x = 10;" + content: "var x = 10;", }; const host = createServerHost([libFile], { useCaseSensitiveFileNames: true }); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -145,7 +182,7 @@ describe("unittests:: tsserver:: dynamicFiles:: ", () => { module: ts.ModuleKind.CommonJS, allowJs: true, allowSyntheticDefaultImports: true, - allowNonTsExtensions: true + allowNonTsExtensions: true, }, session); openFilesForSession([{ file: file.path, content: "var x = 10;" }], session); @@ -153,29 +190,37 @@ describe("unittests:: tsserver:: dynamicFiles:: ", () => { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Quickinfo, - arguments: protocolFileLocationFromSubstring(file, "x") + arguments: protocolFileLocationFromSubstring(file, "x"), }); baselineTsserverLogs("dynamicFiles", "dynamic file without external project", session); }); - verifyPathRecognizedAsDynamic("dynamic file with reference paths without external project", "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js"); + verifyPathRecognizedAsDynamic( + "dynamic file with reference paths without external project", + "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js", + ); describe("dynamic file with projectRootPath", () => { const file: File = { path: "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js", - content: "var x = 10;" + content: "var x = 10;", }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const configProjectFile: File = { path: `/user/username/projects/myproject/a.ts`, - content: "let y = 10;" + content: "let y = 10;", }; it("with useInferredProjectPerProjectRoot", () => { - const host = createServerHost([libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true }); - const session = createSession(host, { useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) }); + const host = createServerHost([libFile, configFile, configProjectFile], { + useCaseSensitiveFileNames: true, + }); + const session = createSession(host, { + useInferredProjectPerProjectRoot: true, + logger: createLoggerWithInMemoryLogs(host), + }); openFilesForSession([{ file: file.path, projectRootPath: "/user/username/projects/myproject" }], session); const projectService = session.getProjectService(); @@ -184,36 +229,54 @@ describe("unittests:: tsserver:: dynamicFiles:: ", () => { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetOutliningSpans, arguments: { - file: file.path - } + file: file.path, + }, }); // Without project root const file2Path = file.path.replace("#1", "#2"); openFilesForSession([{ file: file2Path, content: file.content }], session); - baselineTsserverLogs("dynamicFiles", "dynamic file with projectRootPath with useInferredProjectPerProjectRoot", session); + baselineTsserverLogs( + "dynamicFiles", + "dynamic file with projectRootPath with useInferredProjectPerProjectRoot", + session, + ); }); it("fails when useInferredProjectPerProjectRoot is false", () => { - const host = createServerHost([libFile, configFile, configProjectFile], { useCaseSensitiveFileNames: true }); + const host = createServerHost([libFile, configFile, configProjectFile], { + useCaseSensitiveFileNames: true, + }); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); try { - projectService.openClientFile(file.path, file.content, /*scriptKind*/ undefined, "/user/username/projects/myproject"); + projectService.openClientFile( + file.path, + file.content, + /*scriptKind*/ undefined, + "/user/username/projects/myproject", + ); } catch (e) { assert.strictEqual( e.message.replace(/\r?\n/, "\n"), - `Debug Failure. False expression.\nVerbose Debug Information: {"fileName":"^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js","currentDirectory":"/user/username/projects/myproject","hostCurrentDirectory":"/","openKeys":[]}\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.` + `Debug Failure. False expression.\nVerbose Debug Information: {"fileName":"^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js","currentDirectory":"/user/username/projects/myproject","hostCurrentDirectory":"/","openKeys":[]}\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.`, ); } const file2Path = file.path.replace("#1", "#2"); projectService.openClientFile(file2Path, file.content); - baselineTsserverLogs("dynamicFiles", "dynamic file with projectRootPath fails when useInferredProjectPerProjectRoot is false", projectService); + baselineTsserverLogs( + "dynamicFiles", + "dynamic file with projectRootPath fails when useInferredProjectPerProjectRoot is false", + projectService, + ); }); }); describe("verify accepts known schemas as dynamic file", () => { - verifyPathRecognizedAsDynamic("walkThroughSnippet", "walkThroughSnippet:/usr/share/code/resources/app/out/vs/workbench/contrib/welcome/walkThrough/browser/editor/^vs_code_editor_walkthrough.md#1.ts"); + verifyPathRecognizedAsDynamic( + "walkThroughSnippet", + "walkThroughSnippet:/usr/share/code/resources/app/out/vs/workbench/contrib/welcome/walkThrough/browser/editor/^vs_code_editor_walkthrough.md#1.ts", + ); verifyPathRecognizedAsDynamic("untitled", "untitled:/Users/matb/projects/san/^newFile.ts"); }); }); diff --git a/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts b/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts index c62579832b33e..dfddd0ef63516 100644 --- a/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts +++ b/src/testRunner/unittests/tsserver/events/largeFileReferenced.ts @@ -23,7 +23,7 @@ describe("unittests:: tsserver:: events:: LargeFileReferencedEvent with large fi const largeFile: File = { path: `/user/username/projects/myproject/${getLargeFile(useLargeTsFile)}`, content: "export var x = 10;", - fileSize: ts.server.maxFileSize + 1 + fileSize: ts.server.maxFileSize + 1, }; files.push(largeFile); const host = createServerHost(files); @@ -36,27 +36,38 @@ describe("unittests:: tsserver:: events:: LargeFileReferencedEvent with large fi it("when large file is included by tsconfig", () => { const file: File = { path: `/user/username/projects/myproject/src/file.ts`, - content: "export var y = 10;" + content: "export var y = 10;", }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: JSON.stringify({ files: ["src/file.ts", getLargeFile(useLargeTsFile)], compilerOptions: { target: 1, allowJs: true } }) + content: JSON.stringify({ + files: ["src/file.ts", getLargeFile(useLargeTsFile)], + compilerOptions: { target: 1, allowJs: true }, + }), }; const files = [file, libFile, tsconfig]; const session = createSessionWithEventHandler(files, useLargeTsFile); openFilesForSession([file], session); - baselineTsserverLogs("events/largeFileReferenced", `when large ${getFileType(useLargeTsFile)} file is included by tsconfig`, session); + baselineTsserverLogs( + "events/largeFileReferenced", + `when large ${getFileType(useLargeTsFile)} file is included by tsconfig`, + session, + ); }); it("when large file is included by module resolution", () => { const file: File = { path: `/user/username/projects/myproject/src/file.ts`, - content: `export var y = 10;import {x} from "./large"` + content: `export var y = 10;import {x} from "./large"`, }; const files = [file, libFile]; const session = createSessionWithEventHandler(files, useLargeTsFile); openFilesForSession([file], session); - baselineTsserverLogs("events/largeFileReferenced", `when large ${getFileType(useLargeTsFile)} file is included by module resolution`, session); + baselineTsserverLogs( + "events/largeFileReferenced", + `when large ${getFileType(useLargeTsFile)} file is included by module resolution`, + session, + ); }); } diff --git a/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts b/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts index 6ce697771b67a..704b2bbf75295 100644 --- a/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts +++ b/src/testRunner/unittests/tsserver/events/projectLanguageServiceState.ts @@ -16,7 +16,7 @@ describe("unittests:: tsserver:: events:: ProjectLanguageServiceStateEvent", () it("language service disabled events are triggered", () => { const f1 = { path: "/a/app.js", - content: "let x = 1;" + content: "let x = 1;", }; const f2 = { path: "/a/largefile.js", @@ -24,11 +24,11 @@ describe("unittests:: tsserver:: events:: ProjectLanguageServiceStateEvent", () }; const config = { path: "/a/jsconfig.json", - content: "{}" + content: "{}", }; const configWithExclude = { path: config.path, - content: JSON.stringify({ exclude: ["largefile.js"] }) + content: JSON.stringify({ exclude: ["largefile.js"] }), }; const host = createServerHost([f1, f2, config]); const originalGetFileSize = host.getFileSize; @@ -37,32 +37,44 @@ describe("unittests:: tsserver:: events:: ProjectLanguageServiceStateEvent", () const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([f1], session); - session.logger.log(`Language service enabled: ${session.getProjectService().configuredProjects.get(config.path)!.languageServiceEnabled}`); + session.logger.log( + `Language service enabled: ${ + session.getProjectService().configuredProjects.get(config.path)!.languageServiceEnabled + }`, + ); host.writeFile(configWithExclude.path, configWithExclude.content); host.runQueuedTimeoutCallbacks(); - session.logger.log(`Language service enabled: ${session.getProjectService().configuredProjects.get(config.path)!.languageServiceEnabled}`); - baselineTsserverLogs("events/projectLanguageServiceState", "language service disabled events are triggered", session); + session.logger.log( + `Language service enabled: ${ + session.getProjectService().configuredProjects.get(config.path)!.languageServiceEnabled + }`, + ); + baselineTsserverLogs( + "events/projectLanguageServiceState", + "language service disabled events are triggered", + session, + ); }); it("Large file size is determined correctly", () => { const f1: File = { path: "/a/app.js", - content: "let x = 1;" + content: "let x = 1;", }; const f2: File = { path: "/a/largefile.js", content: "", - fileSize: ts.server.maxProgramSizeForNonTsFiles + 1 + fileSize: ts.server.maxProgramSizeForNonTsFiles + 1, }; const f3: File = { path: "/a/extremlylarge.d.ts", content: "", - fileSize: ts.server.maxProgramSizeForNonTsFiles + 100 + fileSize: ts.server.maxProgramSizeForNonTsFiles + 100, }; const config = { path: "/a/jsconfig.json", - content: "{}" + content: "{}", }; const host = createServerHost([f1, f2, f3, libFile, config]); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); diff --git a/src/testRunner/unittests/tsserver/events/projectLoading.ts b/src/testRunner/unittests/tsserver/events/projectLoading.ts index 90781f75c8bba..90c1e27f1c38e 100644 --- a/src/testRunner/unittests/tsserver/events/projectLoading.ts +++ b/src/testRunner/unittests/tsserver/events/projectLoading.ts @@ -20,32 +20,39 @@ import { describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoadingFinish events", () => { const aTs: File = { path: `/user/username/projects/a/a.ts`, - content: "export class A { }" + content: "export class A { }", }; const configA: File = { path: `/user/username/projects/a/tsconfig.json`, - content: "{}" + content: "{}", }; const bTsPath = `/user/username/projects/b/b.ts`; const configBPath = `/user/username/projects/b/tsconfig.json`; const files = [libFile, aTs, configA]; - function verifyProjectLoadingStartAndFinish(sessionType: string, createSession: (host: TestServerHost) => TestSession) { + function verifyProjectLoadingStartAndFinish( + sessionType: string, + createSession: (host: TestServerHost) => TestSession, + ) { describe(sessionType, () => { it("when project is created by open file", () => { const bTs: File = { path: bTsPath, - content: "export class B {}" + content: "export class B {}", }; const configB: File = { path: configBPath, - content: "{}" + content: "{}", }; const host = createServerHost(files.concat(bTs, configB)); const session = createSession(host); openFilesForSession([aTs], session); openFilesForSession([bTs], session); - baselineTsserverLogs("events/projectLoading", `project is created by open file ${sessionType}`, session); + baselineTsserverLogs( + "events/projectLoading", + `project is created by open file ${sessionType}`, + session, + ); }); it("when change is detected in the config file", () => { @@ -55,19 +62,23 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading host.writeFile(configA.path, configA.content); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectLoading", `change is detected in the config file ${sessionType}`, session); + baselineTsserverLogs( + "events/projectLoading", + `change is detected in the config file ${sessionType}`, + session, + ); }); it("when change is detected in an extended config file", () => { const bTs: File = { path: bTsPath, - content: "export class B {}" + content: "export class B {}", }; const configB: File = { path: configBPath, content: JSON.stringify({ extends: "../a/tsconfig.json", - }) + }), }; const host = createServerHost(files.concat(bTs, configB)); const session = createSession(host); @@ -75,7 +86,11 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading host.writeFile(configA.path, configA.content); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectLoading", `change is detected in an extended config file ${sessionType}`, session); + baselineTsserverLogs( + "events/projectLoading", + `change is detected in an extended config file ${sessionType}`, + session, + ); }); describe("when opening original location project", () => { @@ -93,26 +108,27 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading content: `export declare class A { } //# sourceMappingURL=a.d.ts.map -` +`, }; const aDTsMap: File = { path: `/user/username/projects/a/a.d.ts.map`, - content: `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}` + content: + `{"version":3,"file":"a.d.ts","sourceRoot":"","sources":["./a.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;CAAI"}`, }; const bTs: File = { path: bTsPath, - content: `import {A} from "../a/a"; new A();` + content: `import {A} from "../a/a"; new A();`, }; const configB: File = { path: configBPath, content: JSON.stringify({ ...(disableSourceOfProjectReferenceRedirect && { compilerOptions: { - disableSourceOfProjectReferenceRedirect - } + disableSourceOfProjectReferenceRedirect, + }, }), - references: [{ path: "../a" }] - }) + references: [{ path: "../a" }], + }), }; const host = createServerHost(files.concat(aDTs, aDTsMap, bTs, configB)); @@ -123,10 +139,16 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading command: ts.server.protocol.CommandTypes.References, arguments: { file: bTs.path, - ...protocolLocationFromSubstring(bTs.content, "A()") - } + ...protocolLocationFromSubstring(bTs.content, "A()"), + }, }); - baselineTsserverLogs("events/projectLoading", `opening original location project${disableSourceOfProjectReferenceRedirect ? " disableSourceOfProjectReferenceRedirect" : ""} ${sessionType}`, session); + baselineTsserverLogs( + "events/projectLoading", + `opening original location project${ + disableSourceOfProjectReferenceRedirect ? " disableSourceOfProjectReferenceRedirect" : "" + } ${sessionType}`, + session, + ); } }); @@ -139,26 +161,34 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, arguments: { - preferences: { lazyConfiguredProjectsFromExternalProject } - } + preferences: { lazyConfiguredProjectsFromExternalProject }, + }, }); openExternalProjectForSession({ projectFileName, rootFiles: toExternalFiles([aTs.path, configA.path]), - options: {} + options: {}, }, session); return session; } it("when lazyConfiguredProjectsFromExternalProject is false", () => { const session = createSessionAndOpenProject(/*lazyConfiguredProjectsFromExternalProject*/ false); - baselineTsserverLogs("events/projectLoading", `lazyConfiguredProjectsFromExternalProject is false ${sessionType}`, session); + baselineTsserverLogs( + "events/projectLoading", + `lazyConfiguredProjectsFromExternalProject is false ${sessionType}`, + session, + ); }); it("when lazyConfiguredProjectsFromExternalProject is true and file is opened", () => { const session = createSessionAndOpenProject(/*lazyConfiguredProjectsFromExternalProject*/ true); openFilesForSession([aTs], session); - baselineTsserverLogs("events/projectLoading", `lazyConfiguredProjectsFromExternalProject is true and file is opened ${sessionType}`, session); + baselineTsserverLogs( + "events/projectLoading", + `lazyConfiguredProjectsFromExternalProject is true and file is opened ${sessionType}`, + session, + ); }); it("when lazyConfiguredProjectsFromExternalProject is disabled", () => { @@ -166,18 +196,23 @@ describe("unittests:: tsserver:: events:: ProjectLoadingStart and ProjectLoading session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, arguments: { - preferences: { lazyConfiguredProjectsFromExternalProject: false } - } + preferences: { lazyConfiguredProjectsFromExternalProject: false }, + }, }); - baselineTsserverLogs("events/projectLoading", `lazyConfiguredProjectsFromExternalProject is disabled ${sessionType}`, session); + baselineTsserverLogs( + "events/projectLoading", + `lazyConfiguredProjectsFromExternalProject is disabled ${sessionType}`, + session, + ); }); }); }); } verifyProjectLoadingStartAndFinish("when using event handler", host => createSessionWithCustomEventHandler(host)); - verifyProjectLoadingStartAndFinish("when using default event handler", host => createSession( - host, - { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) } - )); + verifyProjectLoadingStartAndFinish("when using default event handler", host => + createSession( + host, + { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }, + )); }); diff --git a/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts b/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts index 19be7628c980b..5d5b85762004e 100644 --- a/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts +++ b/src/testRunner/unittests/tsserver/events/projectUpdatedInBackground.ts @@ -15,23 +15,26 @@ import { } from "../../helpers/virtualFileSystemWithWatch"; describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { - function verifyProjectsUpdatedInBackgroundEvent(scenario: string, createSession: (host: TestServerHost) => TestSession) { + function verifyProjectsUpdatedInBackgroundEvent( + scenario: string, + createSession: (host: TestServerHost) => TestSession, + ) { it("when adding new file", () => { const commonFile1: File = { path: "/users/username/projects/project/file1.ts", - content: "export var x = 10;" + content: "export var x = 10;", }; const commonFile2: File = { path: "/users/username/projects/project/file2.ts", - content: "export var y = 10;" + content: "export var y = 10;", }; const commonFile3: File = { path: "/users/username/projects/project/file3.ts", - content: "export var z = 10;" + content: "export var z = 10;", }; const configFile: File = { path: "/users/username/projects/project/tsconfig.json", - content: `{}` + content: `{}`, }; const host = createServerHost([commonFile1, libFile, configFile]); const session = createSession(host); @@ -51,17 +54,17 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { const config: File = { path: "/users/username/projects/project/tsconfig.json", content: JSON.stringify({ - compilerOptions - }) + compilerOptions, + }), }; const f1: File = { path: "/users/username/projects/project/a.ts", - content: "export let x = 1" + content: "export let x = 1", }; const f2: File = { path: "/users/username/projects/project/b.ts", - content: "export let y = 1" + content: "export let y = 1", }; const files = [f1, config, libFile]; @@ -74,7 +77,11 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { host.writeFile(f2.path, "export let x = 11"); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and ${subScenario}`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and ${subScenario}`, + session, + ); }); } verifyEventWithOutSettings("when both options are not set"); @@ -94,7 +101,9 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { /** initial list of files to reload in fs and first file in this list being the file to open */ firstReloadFileList?: string[]; } - function getInitialState({ configObj = {}, getAdditionalFileOrFolder, firstReloadFileList }: InitialStateParams = {}) { + function getInitialState( + { configObj = {}, getAdditionalFileOrFolder, firstReloadFileList }: InitialStateParams = {}, + ) { const moduleFile1: File = { path: moduleFile1Path, content: "export function Foo() { };", @@ -117,18 +126,28 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { const globalFile3: File = { path: "/users/username/projects/project/globalFile3.ts", - content: `interface GlobalFoo { age: number }` + content: `interface GlobalFoo { age: number }`, }; const additionalFiles = getAdditionalFileOrFolder ? getAdditionalFileOrFolder() : []; const configFile = { path: configFilePath, - content: JSON.stringify(configObj || { compilerOptions: {} }) + content: JSON.stringify(configObj || { compilerOptions: {} }), }; - const files: File[] = [file1Consumer1, moduleFile1, file1Consumer2, moduleFile2, ...additionalFiles, globalFile3, libFile, configFile]; - - const filesToReload = firstReloadFileList?.map(fileName => ts.find(files, file => file.path === fileName)!) || files; + const files: File[] = [ + file1Consumer1, + moduleFile1, + file1Consumer2, + moduleFile2, + ...additionalFiles, + globalFile3, + libFile, + configFile, + ]; + + const filesToReload = + firstReloadFileList?.map(fileName => ts.find(files, file => file.path === fileName)!) || files; const host = createServerHost([filesToReload[0], configFile]); // Initial project creation @@ -140,8 +159,14 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { if (!firstReloadFileList) host.runQueuedTimeoutCallbacks(); // Invalidated module resolutions to schedule project update return { - host, session, - moduleFile1, file1Consumer1, file1Consumer2, moduleFile2, globalFile3, configFile, + host, + session, + moduleFile1, + file1Consumer1, + file1Consumer2, + moduleFile2, + globalFile3, + configFile, updateContentOfOpenFile, }; @@ -154,8 +179,8 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { endLine: 1, endOffset: file.content.length, line: 1, - offset: 1 - } + offset: 1, + }, }); file.content = newContent; } @@ -171,7 +196,11 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { // Change the content of moduleFile1 to `export var T: number;export function Foo() { console.log('hi'); };` host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { console.log('hi'); };`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should contains only itself`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should contains only itself`, + session, + ); }); it("should be up-to-date with the reference map changes", () => { @@ -190,7 +219,10 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { host.runQueuedTimeoutCallbacks(); // Change the content of moduleFile1 to `export var T: number;export var T2: string;export function Foo() { };` - host.writeFile(moduleFile1.path, `export var T: number;export var T2: string;export function Foo() { };`); + host.writeFile( + moduleFile1.path, + `export var T: number;export var T2: string;export function Foo() { };`, + ); host.runQueuedTimeoutCallbacks(); // Multiple file edits in one go: @@ -200,7 +232,11 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { updateContentOfOpenFile(file1Consumer1, `export let y = Foo();`); host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should be up-to-date with the reference map changes`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should be up-to-date with the reference map changes`, + session, + ); }); it("should be up-to-date with deleted files", () => { @@ -212,16 +248,27 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { // Delete file1Consumer2 host.deleteFile(file1Consumer2.path); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should be up-to-date with deleted files`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should be up-to-date with deleted files`, + session, + ); }); it("should be up-to-date with newly created files", () => { - const { host, moduleFile1, session, } = getInitialState(); + const { host, moduleFile1, session } = getInitialState(); host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); - host.writeFile("/users/username/projects/project/file1Consumer3.ts", `import {Foo} from "./moduleFile1"; let y = Foo();`); + host.writeFile( + "/users/username/projects/project/file1Consumer3.ts", + `import {Foo} from "./moduleFile1"; let y = Foo();`, + ); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should be up-to-date with newly created files`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should be up-to-date with newly created files`, + session, + ); }); it("should detect changes in non-root files", () => { @@ -235,7 +282,11 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { // change file1 internal, and verify only file1 is affected host.writeFile(moduleFile1.path, moduleFile1.content + "var T1: number;"); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should detect changes in non-root files`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should detect changes in non-root files`, + session, + ); }); it("should return all files if a global file changed shape", () => { @@ -243,37 +294,49 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { host.writeFile(globalFile3.path, globalFile3.content + "var T2: string;"); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should return all files if a global file changed shape`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should return all files if a global file changed shape`, + session, + ); }); it("should always return the file itself if '--isolatedModules' is specified", () => { const { host, moduleFile1, session } = getInitialState({ - configObj: { compilerOptions: { isolatedModules: true } } + configObj: { compilerOptions: { isolatedModules: true } }, }); host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should always return the file itself if --isolatedModules is specified`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should always return the file itself if --isolatedModules is specified`, + session, + ); }); it("should always return the file itself if '--out' or '--outFile' is specified", () => { const outFilePath = "/users/username/projects/project/out.js"; const { host, moduleFile1, session } = getInitialState({ - configObj: { compilerOptions: { module: "system", outFile: outFilePath } } + configObj: { compilerOptions: { module: "system", outFile: outFilePath } }, }); host.writeFile(moduleFile1.path, `export var T: number;export function Foo() { };`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should always return the file itself if --out or --outFile is specified`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should always return the file itself if --out or --outFile is specified`, + session, + ); }); it("should return cascaded affected file list", () => { const file1Consumer1Consumer1: File = { path: "/users/username/projects/project/file1Consumer1Consumer1.ts", - content: `import {y} from "./file1Consumer1";` + content: `import {y} from "./file1Consumer1";`, }; const { host, moduleFile1, file1Consumer1, updateContentOfOpenFile, session } = getInitialState({ - getAdditionalFileOrFolder: () => [file1Consumer1Consumer1] + getAdditionalFileOrFolder: () => [file1Consumer1Consumer1], }); updateContentOfOpenFile(file1Consumer1, file1Consumer1.content + "export var T: number;"); @@ -287,7 +350,11 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { updateContentOfOpenFile(file1Consumer1, file1Consumer1.content + "export var T2: number;"); host.writeFile(moduleFile1.path, `export var T2: number;export function Foo() { };`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should return cascaded affected file list`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should return cascaded affected file list`, + session, + ); }); it("should work fine for files with circular references", () => { @@ -295,22 +362,26 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { path: "/users/username/projects/project/file1.ts", content: ` /// - export var t1 = 10;` + export var t1 = 10;`, }; const file2: File = { path: "/users/username/projects/project/file2.ts", content: ` /// - export var t2 = 10;` + export var t2 = 10;`, }; const { host, session } = getInitialState({ getAdditionalFileOrFolder: () => [file1, file2], - firstReloadFileList: [file1.path, libFile.path, file2.path, configFilePath] + firstReloadFileList: [file1.path, libFile.path, file2.path, configFilePath], }); host.writeFile(file2.path, file2.content + "export var t3 = 10;"); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should work fine for files with circular references`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should work fine for files with circular references`, + session, + ); }); it("should detect removed code file", () => { @@ -318,16 +389,20 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { path: "/users/username/projects/project/referenceFile1.ts", content: ` /// - export var x = Foo();` + export var x = Foo();`, }; const { host, session } = getInitialState({ getAdditionalFileOrFolder: () => [referenceFile1], - firstReloadFileList: [referenceFile1.path, libFile.path, moduleFile1Path, configFilePath] + firstReloadFileList: [referenceFile1.path, libFile.path, moduleFile1Path, configFilePath], }); host.deleteFile(moduleFile1Path); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should detect removed code file`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should detect removed code file`, + session, + ); }); it("should detect non-existing code file", () => { @@ -335,11 +410,11 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { path: "/users/username/projects/project/referenceFile1.ts", content: ` /// - export var x = Foo();` + export var x = Foo();`, }; const { host, moduleFile2, updateContentOfOpenFile, session } = getInitialState({ getAdditionalFileOrFolder: () => [referenceFile1], - firstReloadFileList: [referenceFile1.path, libFile.path, configFilePath] + firstReloadFileList: [referenceFile1.path, libFile.path, configFilePath], }); updateContentOfOpenFile(referenceFile1, referenceFile1.content + "export var yy = Foo();"); @@ -348,29 +423,37 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { // Create module File2 and see both files are saved host.writeFile(moduleFile2.path, moduleFile2.content); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and should detect non-existing code file`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and should detect non-existing code file`, + session, + ); }); }); describe("resolution when resolution cache size", () => { - function verifyWithMaxCacheLimit(subScenario: string, useSlashRootAsSomeNotRootFolderInUserDirectory: boolean) { + function verifyWithMaxCacheLimit( + subScenario: string, + useSlashRootAsSomeNotRootFolderInUserDirectory: boolean, + ) { it(subScenario, () => { - const rootFolder = useSlashRootAsSomeNotRootFolderInUserDirectory ? "/user/username/rootfolder/otherfolder/" : "/"; + const rootFolder = useSlashRootAsSomeNotRootFolderInUserDirectory + ? "/user/username/rootfolder/otherfolder/" : "/"; const file1: File = { path: rootFolder + "a/b/project/file1.ts", - content: 'import a from "file2"' + content: 'import a from "file2"', }; const file2: File = { path: rootFolder + "a/b/node_modules/file2.d.ts", - content: "export class a { }" + content: "export class a { }", }; const file3: File = { path: rootFolder + "a/b/project/file3.ts", - content: "export class c { }" + content: "export class c { }", }; const configFile: File = { path: rootFolder + "a/b/project/tsconfig.json", - content: JSON.stringify({ compilerOptions: { typeRoots: [] } }) + content: JSON.stringify({ compilerOptions: { typeRoots: [] } }), }; const host = createServerHost([file1, file3, libFile, configFile]); @@ -385,32 +468,47 @@ describe("unittests:: tsserver:: events:: ProjectsUpdatedInBackground", () => { host.runQueuedTimeoutCallbacks(); // For invalidation host.runQueuedTimeoutCallbacks(); // For actual update - baselineTsserverLogs("events/projectUpdatedInBackground", `${scenario} and ${subScenario}`, session); + baselineTsserverLogs( + "events/projectUpdatedInBackground", + `${scenario} and ${subScenario}`, + session, + ); }); } - verifyWithMaxCacheLimit("project is not at root level", /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ true); - verifyWithMaxCacheLimit("project is at root level", /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ false); + verifyWithMaxCacheLimit( + "project is not at root level", + /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ true, + ); + verifyWithMaxCacheLimit( + "project is at root level", + /*useSlashRootAsSomeNotRootFolderInUserDirectory*/ false, + ); }); } describe("when event handler is set in the session", () => { - verifyProjectsUpdatedInBackgroundEvent("when event handler is set in the session", createSessionWithCustomEventHandler); + verifyProjectsUpdatedInBackgroundEvent( + "when event handler is set in the session", + createSessionWithCustomEventHandler, + ); }); describe("when event handler is not set but session is created with canUseEvents = true", () => { describe("without noGetErrOnBackgroundUpdate, diagnostics for open files are queued", () => { - verifyProjectsUpdatedInBackgroundEvent("without noGetErrOnBackgroundUpdate", host => createSession(host, { - canUseEvents: true, - logger: createLoggerWithInMemoryLogs(host) - })); + verifyProjectsUpdatedInBackgroundEvent("without noGetErrOnBackgroundUpdate", host => + createSession(host, { + canUseEvents: true, + logger: createLoggerWithInMemoryLogs(host), + })); }); describe("with noGetErrOnBackgroundUpdate, diagnostics for open file are not queued", () => { - verifyProjectsUpdatedInBackgroundEvent("with noGetErrOnBackgroundUpdate", host => createSession(host, { - canUseEvents: true, - logger: createLoggerWithInMemoryLogs(host), - noGetErrOnBackgroundUpdate: true - })); + verifyProjectsUpdatedInBackgroundEvent("with noGetErrOnBackgroundUpdate", host => + createSession(host, { + canUseEvents: true, + logger: createLoggerWithInMemoryLogs(host), + noGetErrOnBackgroundUpdate: true, + })); }); }); }); diff --git a/src/testRunner/unittests/tsserver/exportMapCache.ts b/src/testRunner/unittests/tsserver/exportMapCache.ts index 601be84a76f4a..2759cd7214bba 100644 --- a/src/testRunner/unittests/tsserver/exportMapCache.ts +++ b/src/testRunner/unittests/tsserver/exportMapCache.ts @@ -12,7 +12,7 @@ import { const packageJson: File = { path: "/package.json", - content: `{ "dependencies": { "mobx": "*" } }` + content: `{ "dependencies": { "mobx": "*" } }`, }; const aTs: File = { path: "/a.ts", @@ -28,15 +28,15 @@ const tsconfig: File = { }; const ambientDeclaration: File = { path: "/ambient.d.ts", - content: "declare module 'ambient' {}" + content: "declare module 'ambient' {}", }; const mobxPackageJson: File = { path: "/node_modules/mobx/package.json", - content: `{ "name": "mobx", "version": "1.0.0" }` + content: `{ "name": "mobx", "version": "1.0.0" }`, }; const mobxDts: File = { path: "/node_modules/mobx/index.d.ts", - content: "export declare function observable(): unknown;" + content: "export declare function observable(): unknown;", }; const exportEqualsMappedType: File = { path: "/lib/foo/constants.d.ts", @@ -80,7 +80,11 @@ describe("unittests:: tsserver:: exportMapCache", () => { project.getPackageJsonAutoImportProvider(); assert.ok(exportMapCache.isUsableByFile(bTs.path as ts.Path)); assert.ok(!exportMapCache.isEmpty()); - baselineTsserverLogs("exportMapCache", "does not invalidate the cache when package.json is changed inconsequentially", session); + baselineTsserverLogs( + "exportMapCache", + "does not invalidate the cache when package.json is changed inconsequentially", + session, + ); }); it("invalidates the cache when package.json change results in AutoImportProvider change", () => { @@ -90,7 +94,11 @@ describe("unittests:: tsserver:: exportMapCache", () => { project.getPackageJsonAutoImportProvider(); assert.ok(!exportMapCache.isUsableByFile(bTs.path as ts.Path)); assert.ok(exportMapCache.isEmpty()); - baselineTsserverLogs("exportMapCache", "invalidates the cache when package.json change results in AutoImportProvider change", session); + baselineTsserverLogs( + "exportMapCache", + "invalidates the cache when package.json change results in AutoImportProvider change", + session, + ); }); it("does not store transient symbols through program updates", () => { @@ -120,9 +128,9 @@ describe("unittests:: tsserver:: exportMapCache", () => { newText: " ", start: { line: 1, offset: 1 }, end: { line: 1, offset: 1 }, - }] - }] - } + }], + }], + }, }); project.getLanguageService(/*ensureSynchronized*/ true); assert.notEqual(programBefore, project.getCurrentProgram()!); @@ -146,7 +154,7 @@ describe("unittests:: tsserver:: exportMapCache", () => { export abstract class Component { abstract render(): Element; - }` + }`, }; const classesTs: File = { path: "/classes.ts", @@ -154,7 +162,7 @@ describe("unittests:: tsserver:: exportMapCache", () => { export class MyComponent extends Component { render/**/ - }` + }`, }; const host = createServerHost([utilsTs, classesTs, tsconfig]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -168,7 +176,7 @@ describe("unittests:: tsserver:: exportMapCache", () => { includeCompletionsWithClassMemberSnippets: true, includeCompletionsWithInsertText: true, }, - } + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompletionInfo, @@ -179,7 +187,7 @@ describe("unittests:: tsserver:: exportMapCache", () => { prefix: "render", includeExternalModuleExports: true, includeInsertTextCompletions: true, - } + }, }); const project = projectService.configuredProjects.get(tsconfig.path)!; @@ -197,9 +205,9 @@ describe("unittests:: tsserver:: exportMapCache", () => { newText: "", start: { line: 4, offset: 22 }, end: { line: 4, offset: 23 }, - }] - }] - } + }], + }], + }, }); host.runQueuedTimeoutCallbacks(); @@ -219,22 +227,43 @@ describe("unittests:: tsserver:: exportMapCache", () => { prefix: "rende", includeExternalModuleExports: true, includeInsertTextCompletions: true, - } + }, }); - baselineTsserverLogs("exportMapCache", "invalidates the cache when a file is opened with different contents", session); + baselineTsserverLogs( + "exportMapCache", + "invalidates the cache when a file is opened with different contents", + session, + ); }); }); function setup() { - const host = createServerHost([aTs, bTs, ambientDeclaration, tsconfig, packageJson, mobxPackageJson, mobxDts, exportEqualsMappedType]); + const host = createServerHost([ + aTs, + bTs, + ambientDeclaration, + tsconfig, + packageJson, + mobxPackageJson, + mobxDts, + exportEqualsMappedType, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([aTs, bTs], session); const projectService = session.getProjectService(); const project = projectService.configuredProjects.get(tsconfig.path)!; triggerCompletions(); const checker = project.getLanguageService().getProgram()!.getTypeChecker(); - return { host, project, projectService, session, exportMapCache: project.getCachedExportInfoMap(), checker, triggerCompletions }; + return { + host, + project, + projectService, + session, + exportMapCache: project.getCachedExportInfoMap(), + checker, + triggerCompletions, + }; function triggerCompletions() { const requestLocation: ts.server.protocol.FileLocationRequestArgs = { @@ -248,7 +277,7 @@ function setup() { ...requestLocation, includeExternalModuleExports: true, prefix: "foo", - } + }, }); } } diff --git a/src/testRunner/unittests/tsserver/extends.ts b/src/testRunner/unittests/tsserver/extends.ts index da16b435cd1d8..91676f0da2a26 100644 --- a/src/testRunner/unittests/tsserver/extends.ts +++ b/src/testRunner/unittests/tsserver/extends.ts @@ -1,4 +1,6 @@ -import { getSymlinkedExtendsSys } from "../helpers/extends"; +import { + getSymlinkedExtendsSys, +} from "../helpers/extends"; import { baselineTsserverLogs, createLoggerWithInMemoryLogs, @@ -13,4 +15,4 @@ describe("unittests:: tsserver:: extends::", () => { openFilesForSession(["/users/user/projects/myproject/src/index.ts"], session); baselineTsserverLogs("tsserver", "resolves the symlink path", session); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/externalProjects.ts b/src/testRunner/unittests/tsserver/externalProjects.ts index ff20e0c081fb1..405f405b7f2d1 100644 --- a/src/testRunner/unittests/tsserver/externalProjects.ts +++ b/src/testRunner/unittests/tsserver/externalProjects.ts @@ -25,13 +25,13 @@ describe("unittests:: tsserver:: externalProjects", () => { function verifyConfigFileCasing(lazyConfiguredProjectsFromExternalProject: boolean) { const f1 = { path: "/a/b/app.ts", - content: "let x = 1" + content: "let x = 1", }; const config = { path: "/a/b/tsconfig.json", content: JSON.stringify({ - include: [] - }) + include: [], + }), }; const host = createServerHost([f1, config], { useCaseSensitiveFileNames: false }); @@ -39,18 +39,27 @@ describe("unittests:: tsserver:: externalProjects", () => { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, arguments: { - preferences: { lazyConfiguredProjectsFromExternalProject } - } + preferences: { lazyConfiguredProjectsFromExternalProject }, + }, }); - const upperCaseConfigFilePath = ts.combinePaths(ts.getDirectoryPath(config.path).toUpperCase(), ts.getBaseFileName(config.path)); + const upperCaseConfigFilePath = ts.combinePaths( + ts.getDirectoryPath(config.path).toUpperCase(), + ts.getBaseFileName(config.path), + ); openExternalProjectForSession({ projectFileName: "/a/b/project.csproj", rootFiles: toExternalFiles([f1.path, upperCaseConfigFilePath]), - options: {} + options: {}, }, session); openFilesForSession([f1], session); - baselineTsserverLogs("externalProjects", `can handle tsconfig file name with difference casing${lazyConfiguredProjectsFromExternalProject ? " with lazyConfiguredProjectsFromExternalProject" : ""}`, session); + baselineTsserverLogs( + "externalProjects", + `can handle tsconfig file name with difference casing${ + lazyConfiguredProjectsFromExternalProject ? " with lazyConfiguredProjectsFromExternalProject" : "" + }`, + session, + ); } it("when lazyConfiguredProjectsFromExternalProject not set", () => { @@ -65,7 +74,7 @@ describe("unittests:: tsserver:: externalProjects", () => { it("load global plugins", () => { const f1 = { path: "/a/file1.ts", - content: "let x = [1, 2];" + content: "let x = [1, 2];", }; const p1 = { projectFileName: "/a/proj1.csproj", rootFiles: [toExternalFile(f1.path)], options: {} }; @@ -78,32 +87,41 @@ describe("unittests:: tsserver:: externalProjects", () => { const proxy = Harness.LanguageService.makeDefaultProxy(info); proxy.getSemanticDiagnostics = filename => { const prev = info.languageService.getSemanticDiagnostics(filename); - const sourceFile: ts.SourceFile = info.project.getSourceFile(ts.toPath(filename, /*basePath*/ undefined, ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames)))!; + const sourceFile: ts.SourceFile = info.project.getSourceFile( + ts.toPath( + filename, + /*basePath*/ undefined, + ts.createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames), + ), + )!; prev.push({ category: ts.DiagnosticCategory.Warning, file: sourceFile, code: 9999, length: 3, messageText: `Plugin diagnostic`, - start: 0 + start: 0, }); return prev; }; return proxy; - } + }, }), - error: undefined + error: undefined, }; }; - const session = createSession(host, { globalPlugins: ["myplugin"], logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + globalPlugins: ["myplugin"], + logger: createLoggerWithInMemoryLogs(host), + }); openExternalProjectsForSession([p1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, arguments: { file: f1.path, - projectFileName: p1.projectFileName - } + projectFileName: p1.projectFileName, + }, }); baselineTsserverLogs("externalProjects", "load global plugins", session); }); @@ -111,17 +129,21 @@ describe("unittests:: tsserver:: externalProjects", () => { it("remove not-listed external projects", () => { const f1 = { path: "/a/app.ts", - content: "let x = 1" + content: "let x = 1", }; const f2 = { path: "/b/app.ts", - content: "let x = 1" + content: "let x = 1", }; const f3 = { path: "/c/app.ts", - content: "let x = 1" + content: "let x = 1", }; - const makeProject = (f: File) => ({ projectFileName: f.path + ".csproj", rootFiles: [toExternalFile(f.path)], options: {} }); + const makeProject = (f: File) => ({ + projectFileName: f.path + ".csproj", + rootFiles: [toExternalFile(f.path)], + options: {}, + }); const p1 = makeProject(f1); const p2 = makeProject(f2); const p3 = makeProject(f3); @@ -138,11 +160,11 @@ describe("unittests:: tsserver:: externalProjects", () => { it("should not close external project with no open files", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x =1;" + content: "let x =1;", }; const file2 = { path: "/a/b/f2.ts", - content: "let y =1;" + content: "let y =1;", }; const externalProjectName = "externalproject"; const host = createServerHost([file1, file2]); @@ -150,14 +172,18 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path, file2.path]), options: {}, - projectFileName: externalProjectName + projectFileName: externalProjectName, }); // open client file - should not lead to creation of inferred project projectService.openClientFile(file1.path, file1.content); // close client file - external project should still exists projectService.closeClientFile(file1.path); projectService.closeExternalProject(externalProjectName); - baselineTsserverLogs("externalProjects", "should not close external project with no open files", projectService); + baselineTsserverLogs( + "externalProjects", + "should not close external project with no open files", + projectService, + ); }); it("external project for dynamic file", () => { @@ -168,7 +194,7 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ rootFiles: externalFiles, options: {}, - projectFileName: externalProjectName + projectFileName: externalProjectName, }); verifyDynamic(projectService, "/^scriptdocument1 file1.ts"); @@ -181,11 +207,11 @@ describe("unittests:: tsserver:: externalProjects", () => { it("when file name starts with ^", () => { const file: File = { path: `/user/username/projects/myproject/file.ts`, - content: "const x = 10;" + content: "const x = 10;", }; const app: File = { path: `/user/username/projects/myproject/^app.ts`, - content: "const y = 10;" + content: "const y = 10;", }; const host = createServerHost([file, app, libFile]); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -193,7 +219,7 @@ describe("unittests:: tsserver:: externalProjects", () => { projectFileName: `/user/username/projects/myproject/myproject.njsproj`, rootFiles: [ toExternalFile(file.path), - toExternalFile(app.path) + toExternalFile(app.path), ], options: {}, }]); @@ -203,33 +229,33 @@ describe("unittests:: tsserver:: externalProjects", () => { it("external project that included config files", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x =1;" + content: "let x =1;", }; const config1 = { path: "/a/b/tsconfig.json", content: JSON.stringify( { compilerOptions: {}, - files: ["f1.ts"] - } - ) + files: ["f1.ts"], + }, + ), }; const file2 = { path: "/a/c/f2.ts", - content: "let y =1;" + content: "let y =1;", }; const config2 = { path: "/a/c/tsconfig.json", content: JSON.stringify( { compilerOptions: {}, - files: ["f2.ts"] - } - ) + files: ["f2.ts"], + }, + ), }; const file3 = { path: "/a/d/f3.ts", - content: "let z =1;" + content: "let z =1;", }; const externalProjectName = "externalproject"; const host = createServerHost([file1, file2, file3, config1, config2]); @@ -237,7 +263,7 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ rootFiles: toExternalFiles([config1.path, config2.path, file3.path]), options: {}, - projectFileName: externalProjectName + projectFileName: externalProjectName, }); // open client file - should not lead to creation of inferred project @@ -264,11 +290,11 @@ describe("unittests:: tsserver:: externalProjects", () => { it("external project with included config file opened after configured project", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const configFile = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: {} }) + content: JSON.stringify({ compilerOptions: {} }), }; const externalProjectName = "externalproject"; const host = createServerHost([file1, configFile]); @@ -279,29 +305,32 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ rootFiles: toExternalFiles([configFile.path]), options: {}, - projectFileName: externalProjectName + projectFileName: externalProjectName, }); - projectService.closeClientFile(file1.path); // configured project is alive since it is opened as part of external project projectService.closeExternalProject(externalProjectName); - baselineTsserverLogs("externalProjects", "external project with included config file opened after configured project", projectService); + baselineTsserverLogs( + "externalProjects", + "external project with included config file opened after configured project", + projectService, + ); }); it("external project with included config file opened after configured project and then closed", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2 = { path: "/a/f2.ts", - content: "let x = 1" + content: "let x = 1", }; const configFile = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: {} }) + content: JSON.stringify({ compilerOptions: {} }), }; const externalProjectName = "externalproject"; const host = createServerHost([file1, file2, libFile, configFile]); @@ -312,7 +341,7 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ rootFiles: toExternalFiles([configFile.path]), options: {}, - projectFileName: externalProjectName + projectFileName: externalProjectName, }); projectService.closeExternalProject(externalProjectName); @@ -321,58 +350,86 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.closeClientFile(file1.path); projectService.openClientFile(file2.path); - baselineTsserverLogs("externalProjects", "external project with included config file opened after configured project and then closed", projectService); + baselineTsserverLogs( + "externalProjects", + "external project with included config file opened after configured project and then closed", + projectService, + ); }); it("can correctly update external project when set of root files has changed", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1" + content: "let x = 1", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 1" + content: "let y = 1", }; const host = createServerHost([file1, file2]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path]) }); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles([file1.path]), + }); - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]) }); - baselineTsserverLogs("externalProjects", "can correctly update external project when set of root files has changed", projectService); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles([file1.path, file2.path]), + }); + baselineTsserverLogs( + "externalProjects", + "can correctly update external project when set of root files has changed", + projectService, + ); }); it("can update external project when set of root files was not changed", () => { const file1 = { path: "/a/b/f1.ts", - content: `export * from "m"` + content: `export * from "m"`, }; const file2 = { path: "/a/b/f2.ts", - content: "export let y = 1" + content: "export let y = 1", }; const file3 = { path: "/a/m.ts", - content: "export let y = 1" + content: "export let y = 1", }; const host = createServerHost([file1, file2, file3]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); - projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ts.ModuleResolutionKind.Node10 }, rootFiles: toExternalFiles([file1.path, file2.path]) }); + projectService.openExternalProject({ + projectFileName: "project", + options: { moduleResolution: ts.ModuleResolutionKind.Node10 }, + rootFiles: toExternalFiles([file1.path, file2.path]), + }); - projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ts.ModuleResolutionKind.Classic }, rootFiles: toExternalFiles([file1.path, file2.path]) }); - baselineTsserverLogs("externalProjects", "can update external project when set of root files was not changed", projectService); + projectService.openExternalProject({ + projectFileName: "project", + options: { moduleResolution: ts.ModuleResolutionKind.Classic }, + rootFiles: toExternalFiles([file1.path, file2.path]), + }); + baselineTsserverLogs( + "externalProjects", + "can update external project when set of root files was not changed", + projectService, + ); }); it("language service disabled state is updated in external projects", () => { const f1 = { path: "/a/app.js", - content: "var x = 1" + content: "var x = 1", }; const f2 = { path: "/a/largefile.js", - content: "" + content: "", }; const host = createServerHost([f1, f2]); const originalGetFileSize = host.getFileSize; @@ -385,35 +442,39 @@ describe("unittests:: tsserver:: externalProjects", () => { service.openExternalProject({ projectFileName, rootFiles: toExternalFiles([f1.path, f2.path]), - options: {} + options: {}, }); assert.isFalse(service.externalProjects[0].languageServiceEnabled, "language service should be disabled - 1"); service.openExternalProject({ projectFileName, rootFiles: toExternalFiles([f1.path]), - options: {} + options: {}, }); assert.isTrue(service.externalProjects[0].languageServiceEnabled, "language service should be enabled"); service.openExternalProject({ projectFileName, rootFiles: toExternalFiles([f1.path, f2.path]), - options: {} + options: {}, }); assert.isFalse(service.externalProjects[0].languageServiceEnabled, "language service should be disabled - 2"); - baselineTsserverLogs("externalProjects", "language service disabled state is updated in external projects", service); + baselineTsserverLogs( + "externalProjects", + "language service disabled state is updated in external projects", + service, + ); }); describe("deleting config file opened from the external project works", () => { function verifyDeletingConfigFile(lazyConfiguredProjectsFromExternalProject: boolean) { const site = { path: "/user/someuser/project/js/site.js", - content: "" + content: "", }; const configFile = { path: "/user/someuser/project/tsconfig.json", - content: "{}" + content: "{}", }; const projectFileName = "/user/someuser/project/WebApplication6.csproj"; const host = createServerHost([libFile, site, configFile]); @@ -424,7 +485,7 @@ describe("unittests:: tsserver:: externalProjects", () => { projectFileName, rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)], options: { allowJs: false }, - typeAcquisition: { include: [] } + typeAcquisition: { include: [] }, }; projectService.openExternalProjects([externalProject]); @@ -438,7 +499,13 @@ describe("unittests:: tsserver:: externalProjects", () => { externalProject.rootFiles.length = 1; projectService.openExternalProjects([externalProject]); - baselineTsserverLogs("externalProjects", `deleting config file opened from the external project works${lazyConfiguredProjectsFromExternalProject ? " with lazyConfiguredProjectsFromExternalProject" : ""}`, projectService); + baselineTsserverLogs( + "externalProjects", + `deleting config file opened from the external project works${ + lazyConfiguredProjectsFromExternalProject ? " with lazyConfiguredProjectsFromExternalProject" : "" + }`, + projectService, + ); } it("when lazyConfiguredProjectsFromExternalProject not set", () => { verifyDeletingConfigFile(/*lazyConfiguredProjectsFromExternalProject*/ false); @@ -452,15 +519,15 @@ describe("unittests:: tsserver:: externalProjects", () => { function verifyAddRemoveConfig(lazyConfiguredProjectsFromExternalProject: boolean) { const f1 = { path: "/a/b/app.ts", - content: "let x = 1;" + content: "let x = 1;", }; const f2 = { path: "/a/b/lib.ts", - content: "" + content: "", }; const tsconfig = { path: "/a/b/tsconfig.json", - content: "" + content: "", }; const host = createServerHost([f1, f2]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -471,7 +538,7 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path, f2.path]), - options: {} + options: {}, }); projectService.openClientFile(f1.path); @@ -480,7 +547,7 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path, tsconfig.path]), - options: {} + options: {}, }); if (lazyConfiguredProjectsFromExternalProject) { projectService.ensureInferredProjectsUpToDate_TestOnly(); @@ -491,9 +558,15 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path, f2.path]), - options: {} + options: {}, }); - baselineTsserverLogs("externalProjects", `correctly handling add or remove tsconfig - 1${lazyConfiguredProjectsFromExternalProject ? " with lazyConfiguredProjectsFromExternalProject" : ""}`, projectService); + baselineTsserverLogs( + "externalProjects", + `correctly handling add or remove tsconfig - 1${ + lazyConfiguredProjectsFromExternalProject ? " with lazyConfiguredProjectsFromExternalProject" : "" + }`, + projectService, + ); } it("when lazyConfiguredProjectsFromExternalProject not set", () => { verifyAddRemoveConfig(/*lazyConfiguredProjectsFromExternalProject*/ false); @@ -507,23 +580,23 @@ describe("unittests:: tsserver:: externalProjects", () => { function verifyAddRemoveConfig(lazyConfiguredProjectsFromExternalProject: boolean) { const f1 = { path: "/a/b/app.ts", - content: "let x = 1;" + content: "let x = 1;", }; const cLib = { path: "/a/b/c/lib.ts", - content: "" + content: "", }; const cTsconfig = { path: "/a/b/c/tsconfig.json", - content: "{}" + content: "{}", }; const dLib = { path: "/a/b/d/lib.ts", - content: "" + content: "", }; const dTsconfig = { path: "/a/b/d/tsconfig.json", - content: "{}" + content: "{}", }; const host = createServerHost([f1, cLib, cTsconfig, dLib, dTsconfig]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -534,14 +607,14 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path]), - options: {} + options: {}, }); // add two config file as root files projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]), - options: {} + options: {}, }); if (lazyConfiguredProjectsFromExternalProject) { projectService.ensureInferredProjectsUpToDate_TestOnly(); @@ -551,14 +624,14 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path, dTsconfig.path]), - options: {} + options: {}, }); // remove second config file projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path]), - options: {} + options: {}, }); // open two config files @@ -566,7 +639,7 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openExternalProject({ projectFileName: projectName, rootFiles: toExternalFiles([f1.path, cTsconfig.path, dTsconfig.path]), - options: {} + options: {}, }); if (lazyConfiguredProjectsFromExternalProject) { projectService.ensureInferredProjectsUpToDate_TestOnly(); @@ -574,7 +647,13 @@ describe("unittests:: tsserver:: externalProjects", () => { // close all projects - no projects should be opened projectService.closeExternalProject(projectName); - baselineTsserverLogs("externalProjects", `correctly handling add or remove tsconfig - 2${lazyConfiguredProjectsFromExternalProject ? " with lazyConfiguredProjectsFromExternalProject" : ""}`, projectService); + baselineTsserverLogs( + "externalProjects", + `correctly handling add or remove tsconfig - 2${ + lazyConfiguredProjectsFromExternalProject ? " with lazyConfiguredProjectsFromExternalProject" : "" + }`, + projectService, + ); } it("when lazyConfiguredProjectsFromExternalProject not set", () => { @@ -588,15 +667,15 @@ describe("unittests:: tsserver:: externalProjects", () => { it("correctly handles changes in lib section of config file", () => { const libES5 = { path: "/compiler/lib.es5.d.ts", - content: "declare const eval: any" + content: "declare const eval: any", }; const libES2015Promise = { path: "/compiler/lib.es2015.promise.d.ts", - content: "declare class Promise {}" + content: "declare class Promise {}", }; const app = { path: "/src/app.ts", - content: "var x: Promise;" + content: "var x: Promise;", }; const config1 = { path: "/src/tsconfig.json", @@ -608,10 +687,11 @@ describe("unittests:: tsserver:: externalProjects", () => { noImplicitAny: true, sourceMap: false, lib: [ - "es5" - ] - } - }) + "es5", + ], + }, + }, + ), }; const config2 = { path: config1.path, @@ -624,25 +704,32 @@ describe("unittests:: tsserver:: externalProjects", () => { sourceMap: false, lib: [ "es5", - "es2015.promise" - ] - } - }) + "es2015.promise", + ], + }, + }, + ), }; - const host = createServerHost([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" }); + const host = createServerHost([libES5, libES2015Promise, app, config1], { + executingFilePath: "/compiler/tsc.js", + }); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(app.path); host.writeFile(config2.path, config2.content); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("externalProjects", "correctly handles changes in lib section of config file", projectService); + baselineTsserverLogs( + "externalProjects", + "correctly handles changes in lib section of config file", + projectService, + ); }); it("should handle non-existing directories in config file", () => { const f = { path: "/a/src/app.ts", - content: "let x = 1;" + content: "let x = 1;", }; const config = { path: "/a/tsconfig.json", @@ -650,9 +737,9 @@ describe("unittests:: tsserver:: externalProjects", () => { compilerOptions: {}, include: [ "src/**/*", - "notexistingfolder/*" - ] - }) + "notexistingfolder/*", + ], + }), }; const host = createServerHost([f, config]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -663,17 +750,21 @@ describe("unittests:: tsserver:: externalProjects", () => { projectService.openClientFile(f.path); logConfiguredProjectsHasOpenRefStatus(projectService); - baselineTsserverLogs("externalProjects", "should handle non-existing directories in config file", projectService); + baselineTsserverLogs( + "externalProjects", + "should handle non-existing directories in config file", + projectService, + ); }); it("handles loads existing configured projects of external projects when lazyConfiguredProjectsFromExternalProject is disabled", () => { const f1 = { path: "/a/b/app.ts", - content: "let x = 1" + content: "let x = 1", }; const config = { path: "/a/b/tsconfig.json", - content: JSON.stringify({}) + content: JSON.stringify({}), }; const projectFileName = "/a/b/project.csproj"; const host = createServerHost([f1, config]); @@ -682,7 +773,7 @@ describe("unittests:: tsserver:: externalProjects", () => { service.openExternalProject({ projectFileName, rootFiles: toExternalFiles([f1.path, config.path]), - options: {} + options: {}, } as ts.server.protocol.ExternalProject); const project = service.configuredProjects.get(config.path)!; assert.equal(project.pendingReload, ts.ConfigFileProgramReloadLevel.Full); // External project referenced configured project pending to be reloaded @@ -695,18 +786,22 @@ describe("unittests:: tsserver:: externalProjects", () => { service.openExternalProject({ projectFileName, rootFiles: toExternalFiles([f1.path, config.path]), - options: {} + options: {}, } as ts.server.protocol.ExternalProject); const project2 = service.configuredProjects.get(config.path)!; assert.equal(project2.pendingReload, ts.ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded - baselineTsserverLogs("externalProjects", "handles loads existing configured projects of external projects when lazyConfiguredProjectsFromExternalProject is disabled", service); + baselineTsserverLogs( + "externalProjects", + "handles loads existing configured projects of external projects when lazyConfiguredProjectsFromExternalProject is disabled", + service, + ); }); it("handles creation of external project with jsconfig before jsconfig creation watcher is invoked", () => { const projectFileName = `/user/username/projects/myproject/WebApplication36.csproj`; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const files = [libFile, tsconfig]; const host = createServerHost(files); @@ -716,7 +811,7 @@ describe("unittests:: tsserver:: externalProjects", () => { service.openExternalProjects([{ projectFileName, rootFiles: [{ fileName: tsconfig.path }], - options: { allowJs: false } + options: { allowJs: false }, }]); // write js file, open external project and open it for edit @@ -725,14 +820,16 @@ describe("unittests:: tsserver:: externalProjects", () => { service.openExternalProjects([{ projectFileName, rootFiles: [{ fileName: tsconfig.path }, { fileName: jsFilePath }], - options: { allowJs: false } + options: { allowJs: false }, }]); - service.applyChangesInOpenFiles(ts.singleIterator({ fileName: jsFilePath, scriptKind: ts.ScriptKind.JS, content: "" })); + service.applyChangesInOpenFiles( + ts.singleIterator({ fileName: jsFilePath, scriptKind: ts.ScriptKind.JS, content: "" }), + ); // write jsconfig file const jsConfig: File = { path: `/user/username/projects/myproject/jsconfig.json`, - content: "{}" + content: "{}", }; // Dont invoke file creation watchers as the repro suggests host.ensureFileOrFolder(jsConfig, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true); @@ -741,10 +838,14 @@ describe("unittests:: tsserver:: externalProjects", () => { service.openExternalProjects([{ projectFileName, rootFiles: [{ fileName: jsConfig.path }, { fileName: tsconfig.path }, { fileName: jsFilePath }], - options: { allowJs: false } + options: { allowJs: false }, }]); logInferredProjectsOrphanStatus(service); - baselineTsserverLogs("externalProjects", "handles creation of external project with jsconfig before jsconfig creation watcher is invoked", service); + baselineTsserverLogs( + "externalProjects", + "handles creation of external project with jsconfig before jsconfig creation watcher is invoked", + service, + ); }); it("does not crash if external file does not exist", () => { diff --git a/src/testRunner/unittests/tsserver/findAllReferences.ts b/src/testRunner/unittests/tsserver/findAllReferences.ts index 85b1b4b05fcaa..d807cd6fe798b 100644 --- a/src/testRunner/unittests/tsserver/findAllReferences.ts +++ b/src/testRunner/unittests/tsserver/findAllReferences.ts @@ -1,14 +1,22 @@ -import { protocol } from "../../_namespaces/ts.server"; -import { baselineTsserverLogs, createLoggerWithInMemoryLogs, createSession } from "../helpers/tsserver"; -import { createServerHost, File } from "../helpers/virtualFileSystemWithWatch"; +import { + protocol, +} from "../../_namespaces/ts.server"; +import { + baselineTsserverLogs, + createLoggerWithInMemoryLogs, + createSession, +} from "../helpers/tsserver"; +import { + createServerHost, + File, +} from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: services:: findAllReferences", () => { it("does not try to open a file in a project that was updated and no longer has the file", () => { const files: File[] = [ { path: "/packages/babel-loader/tsconfig.json", - content: -` + content: ` { "compilerOptions": { "target": "ES2018", @@ -22,19 +30,17 @@ describe("unittests:: services:: findAllReferences", () => { "include": ["src"], "references": [{"path": "../core"}] } -` +`, }, { path: "/packages/babel-loader/src/index.ts", - content: -` + content: ` import type { Foo } from "../../core/src/index.js"; -` +`, }, { path: "/packages/core/tsconfig.json", - content: -` + content: ` { "compilerOptions": { "target": "ES2018", @@ -47,30 +53,28 @@ import type { Foo } from "../../core/src/index.js"; }, "include": ["./src"] } -` +`, }, { path: "/packages/core/src/index.ts", - content: -` + content: ` import { Bar } from "./loading-indicator.js"; export type Foo = {}; const bar: Bar = { prop: 0 } -` +`, }, { path: "/packages/core/src/loading-indicator.ts", - content: -` + content: ` export interface Bar { prop: number; } const bar: Bar = { prop: 1 } -` +`, }, ]; const host = createServerHost(files); @@ -83,9 +87,9 @@ const bar: Bar = { { file: files[1].path, // babel-loader/src/index.ts fileContent: files[1].content, - } - ] - } + }, + ], + }, }); session.executeCommandSeq({ command: protocol.CommandTypes.UpdateOpen, @@ -94,9 +98,9 @@ const bar: Bar = { { file: files[3].path, // core/src/index.ts fileContent: files[3].content, - } - ] - } + }, + ], + }, }); // Now change `babel-loader` project to no longer import `core` project session.executeCommandSeq({ @@ -109,33 +113,41 @@ const bar: Bar = { { start: { line: 1, - offset: 26 + offset: 26, }, end: { line: 1, - offset: 26 + offset: 26, }, newText: "// comment", - } - ] - } - ] - } + }, + ], + }, + ], + }, }); const loadingIndicatorScriptInfo = session.getProjectService().getScriptInfo(files[3].path)!; // At this point, we haven't updated `babel-loader` project yet, // so `babel-loader` is still a containing project of `loading-indicator` file. - assert(loadingIndicatorScriptInfo.containingProjects.find(p => p.projectName === "/packages/babel-loader/tsconfig.json")); + assert( + loadingIndicatorScriptInfo.containingProjects.find(p => + p.projectName === "/packages/babel-loader/tsconfig.json" + ), + ); // When calling find all references, // we shouldn't crash due to using outdated information on a file's containig projects. session.executeCommandSeq({ command: protocol.CommandTypes.References, arguments: { file: files[3].path, // core/src/index.ts - line: 5, // `prop` + line: 5, // `prop` offset: 5, - } + }, }); - baselineTsserverLogs("findAllReferences", "does not try to open a file in a project that was updated and no longer has the file", session); + baselineTsserverLogs( + "findAllReferences", + "does not try to open a file in a project that was updated and no longer has the file", + session, + ); }); }); diff --git a/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts b/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts index 6dbfe687f421e..84f1fe513a095 100644 --- a/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts +++ b/src/testRunner/unittests/tsserver/forceConsistentCasingInFileNames.ts @@ -45,33 +45,39 @@ describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => { content: JSON.stringify({ extends: "./tsconfig.all.json" }), }; - const host = createServerHost([file1, file2, file2Dts, libFile, tsconfig, tsconfigAll], { useCaseSensitiveFileNames: false }); + const host = createServerHost([file1, file2, file2Dts, libFile, tsconfig, tsconfigAll], { + useCaseSensitiveFileNames: false, + }); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, arguments: { - projectFileName: tsconfig.path - } + projectFileName: tsconfig.path, + }, }); - baselineTsserverLogs("forceConsistentCasingInFileNames", "works when extends is specified with a case insensitive file system", session); + baselineTsserverLogs( + "forceConsistentCasingInFileNames", + "works when extends is specified with a case insensitive file system", + session, + ); }); it("works when renaming file with different casing", () => { const loggerFile: File = { path: `/user/username/projects/myproject/Logger.ts`, - content: `export class logger { }` + content: `export class logger { }`, }; const anotherFile: File = { path: `/user/username/projects/myproject/another.ts`, - content: `import { logger } from "./Logger"; new logger();` + content: `import { logger } from "./Logger"; new logger();`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ - compilerOptions: { forceConsistentCasingInFileNames: true } - }) + compilerOptions: { forceConsistentCasingInFileNames: true }, + }), }; const host = createServerHost([loggerFile, anotherFile, tsconfig, libFile, tsconfig]); @@ -82,7 +88,11 @@ describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => { const newLoggerPath = loggerFile.path.toLowerCase(); host.renameFile(loggerFile.path, newLoggerPath); closeFilesForSession([loggerFile], session); - openFilesForSession([{ file: newLoggerPath, content: loggerFile.content, projectRootPath: "/user/username/projects/myproject" }], session); + openFilesForSession([{ + file: newLoggerPath, + content: loggerFile.content, + projectRootPath: "/user/username/projects/myproject", + }], session); // Apply edits for rename openFilesForSession([{ file: anotherFile, projectRootPath: "/user/username/projects/myproject" }], session); @@ -95,32 +105,36 @@ describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => { newText: "./logger", ...protocolTextSpanFromSubstring( anotherFile.content, - "./Logger" - ) - }] - }] - } + "./Logger", + ), + }], + }], + }, }); // Check errors in both files verifyGetErrRequest({ session, files: [newLoggerPath, anotherFile] }); - baselineTsserverLogs("forceConsistentCasingInFileNames", "works when renaming file with different casing", session); + baselineTsserverLogs( + "forceConsistentCasingInFileNames", + "works when renaming file with different casing", + session, + ); }); it("when changing module name with different casing", () => { const loggerFile: File = { path: `/user/username/projects/myproject/Logger.ts`, - content: `export class logger { }` + content: `export class logger { }`, }; const anotherFile: File = { path: `/user/username/projects/myproject/another.ts`, - content: `import { logger } from "./Logger"; new logger();` + content: `import { logger } from "./Logger"; new logger();`, }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ - compilerOptions: { forceConsistentCasingInFileNames: true } - }) + compilerOptions: { forceConsistentCasingInFileNames: true }, + }), }; const host = createServerHost([loggerFile, anotherFile, tsconfig, libFile, tsconfig]); @@ -137,15 +151,19 @@ describe("unittests:: tsserver:: forceConsistentCasingInFileNames", () => { newText: "./logger", ...protocolTextSpanFromSubstring( anotherFile.content, - "./Logger" - ) - }] - }] - } + "./Logger", + ), + }], + }], + }, }); // Check errors in both files verifyGetErrRequest({ session, files: [anotherFile] }); - baselineTsserverLogs("forceConsistentCasingInFileNames", "when changing module name with different casing", session); + baselineTsserverLogs( + "forceConsistentCasingInFileNames", + "when changing module name with different casing", + session, + ); }); }); diff --git a/src/testRunner/unittests/tsserver/formatSettings.ts b/src/testRunner/unittests/tsserver/formatSettings.ts index 2978804b91d8a..aca29c7674607 100644 --- a/src/testRunner/unittests/tsserver/formatSettings.ts +++ b/src/testRunner/unittests/tsserver/formatSettings.ts @@ -1,12 +1,19 @@ import * as ts from "../../_namespaces/ts"; -import { baselineTsserverLogs, createLoggerWithInMemoryLogs, createSession, openFilesForSession } from "../helpers/tsserver"; -import { createServerHost } from "../helpers/virtualFileSystemWithWatch"; +import { + baselineTsserverLogs, + createLoggerWithInMemoryLogs, + createSession, + openFilesForSession, +} from "../helpers/tsserver"; +import { + createServerHost, +} from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: tsserver:: formatSettings", () => { it("can be set globally", () => { const f1 = { path: "/a/b/app.ts", - content: "let x;" + content: "let x;", }; const host = createServerHost([f1]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -15,34 +22,71 @@ describe("unittests:: tsserver:: formatSettings", () => { const defaultSettings = session.getProjectService().getFormatCodeOptions(f1.path as ts.server.NormalizedPath); // set global settings - const newGlobalSettings1 = { ...defaultSettings, placeOpenBraceOnNewLineForControlBlocks: !defaultSettings.placeOpenBraceOnNewLineForControlBlocks }; + const newGlobalSettings1 = { + ...defaultSettings, + placeOpenBraceOnNewLineForControlBlocks: !defaultSettings.placeOpenBraceOnNewLineForControlBlocks, + }; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { formatOptions: newGlobalSettings1 } + arguments: { formatOptions: newGlobalSettings1 }, }); // get format options for file - should be equal to new global settings - session.logger.log(`FormatCodeOptions should be global:: ${f1.path}:: ${JSON.stringify(session.getProjectService().getFormatCodeOptions(ts.server.toNormalizedPath(f1.path)), undefined, " ")}`); + session.logger.log( + `FormatCodeOptions should be global:: ${f1.path}:: ${ + JSON.stringify( + session.getProjectService().getFormatCodeOptions(ts.server.toNormalizedPath(f1.path)), + undefined, + " ", + ) + }`, + ); // set per file format options - const newPerFileSettings = { ...defaultSettings, insertSpaceAfterCommaDelimiter: !defaultSettings.insertSpaceAfterCommaDelimiter }; + const newPerFileSettings = { + ...defaultSettings, + insertSpaceAfterCommaDelimiter: !defaultSettings.insertSpaceAfterCommaDelimiter, + }; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { formatOptions: newPerFileSettings, file: f1.path } + arguments: { formatOptions: newPerFileSettings, file: f1.path }, }); // get format options for file - should be equal to new per-file settings - session.logger.log(`FormatCodeOptions should be per file:: ${f1.path}:: ${JSON.stringify(session.getProjectService().getFormatCodeOptions(ts.server.toNormalizedPath(f1.path)), undefined, " ")}`); + session.logger.log( + `FormatCodeOptions should be per file:: ${f1.path}:: ${ + JSON.stringify( + session.getProjectService().getFormatCodeOptions(ts.server.toNormalizedPath(f1.path)), + undefined, + " ", + ) + }`, + ); // set new global settings - they should not affect ones that were set per-file - const newGlobalSettings2 = { ...defaultSettings, insertSpaceAfterSemicolonInForStatements: !defaultSettings.insertSpaceAfterSemicolonInForStatements }; + const newGlobalSettings2 = { + ...defaultSettings, + insertSpaceAfterSemicolonInForStatements: !defaultSettings.insertSpaceAfterSemicolonInForStatements, + }; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { formatOptions: newGlobalSettings2 } + arguments: { formatOptions: newGlobalSettings2 }, }); // get format options for file - should be equal to new per-file settings - session.logger.log(`FormatCodeOptions should be per file:: ${f1.path}:: ${JSON.stringify(session.getProjectService().getFormatCodeOptions(ts.server.toNormalizedPath(f1.path)), undefined, " ")}`); - baselineTsserverLogs("formatSettings", "works when extends is specified with a case insensitive file system", session); + session.logger.log( + `FormatCodeOptions should be per file:: ${f1.path}:: ${ + JSON.stringify( + session.getProjectService().getFormatCodeOptions(ts.server.toNormalizedPath(f1.path)), + undefined, + " ", + ) + }`, + ); + baselineTsserverLogs( + "formatSettings", + "works when extends is specified with a case insensitive file system", + session, + ); }); }); diff --git a/src/testRunner/unittests/tsserver/getApplicableRefactors.ts b/src/testRunner/unittests/tsserver/getApplicableRefactors.ts index 793ee5cfd0979..03ed1542cfb8f 100644 --- a/src/testRunner/unittests/tsserver/getApplicableRefactors.ts +++ b/src/testRunner/unittests/tsserver/getApplicableRefactors.ts @@ -18,7 +18,7 @@ describe("unittests:: tsserver:: getApplicableRefactors", () => { openFilesForSession([aTs], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetApplicableRefactors, - arguments: { file: aTs.path, line: 1, offset: 1 } + arguments: { file: aTs.path, line: 1, offset: 1 }, }); baselineTsserverLogs("getApplicableRefactors", "works when taking position", session); }); diff --git a/src/testRunner/unittests/tsserver/getEditsForFileRename.ts b/src/testRunner/unittests/tsserver/getEditsForFileRename.ts index e9e717cce003b..3fb0f97d22c62 100644 --- a/src/testRunner/unittests/tsserver/getEditsForFileRename.ts +++ b/src/testRunner/unittests/tsserver/getEditsForFileRename.ts @@ -28,7 +28,11 @@ describe("unittests:: tsserver:: getEditsForFileRename", () => { const host = createServerHost([userTs, newTs, tsconfig]); const options: ts.CompilerOptions = {}; - const moduleResolutionCache = ts.createModuleResolutionCache(host.getCurrentDirectory(), ts.createGetCanonicalFileName(host.useCaseSensitiveFileNames), options); + const moduleResolutionCache = ts.createModuleResolutionCache( + host.getCurrentDirectory(), + ts.createGetCanonicalFileName(host.useCaseSensitiveFileNames), + options, + ); const lsHost: ts.LanguageServiceHost = { getCompilationSettings: () => options, getScriptFileNames: () => [newTs.path, userTs.path], @@ -41,8 +45,17 @@ describe("unittests:: tsserver:: getEditsForFileRename", () => { getDefaultLibFileName: options => ts.getDefaultLibFileName(options), readFile: path => host.readFile(path), fileExists: path => host.fileExists(path), - resolveModuleNames: (moduleNames, containingFile) => moduleNames.map(name => ts.resolveModuleName(name, containingFile, options, lsHost, moduleResolutionCache).resolvedModule), - getResolvedModuleWithFailedLookupLocationsFromCache: (moduleName, containingFile, mode) => moduleResolutionCache.getFromDirectoryCache(moduleName, mode, ts.getDirectoryPath(containingFile), /*redirectedReference*/ undefined), + resolveModuleNames: (moduleNames, containingFile) => + moduleNames.map(name => + ts.resolveModuleName(name, containingFile, options, lsHost, moduleResolutionCache).resolvedModule + ), + getResolvedModuleWithFailedLookupLocationsFromCache: (moduleName, containingFile, mode) => + moduleResolutionCache.getFromDirectoryCache( + moduleName, + mode, + ts.getDirectoryPath(containingFile), + /*redirectedReference*/ undefined, + ), }; const service = ts.createLanguageService(lsHost); const edits = service.getEditsForFileRename("/old.ts", "/new.ts", ts.testFormatSettings, ts.emptyOptions); @@ -86,7 +99,7 @@ describe("unittests:: tsserver:: getEditsForFileRename", () => { arguments: { oldFilePath: aOldTs.path, newFilePath: "/a/new.ts", - } + }, }); baselineTsserverLogs("getEditsForFileRename", "works with multiple projects", session); }); @@ -105,7 +118,7 @@ describe("unittests:: tsserver:: getEditsForFileRename", () => { arguments: { oldFilePath: "/b.ts", newFilePath: cTs.path, - } + }, }); baselineTsserverLogs("getEditsForFileRename", "works with file moved to inferred project", session); }); diff --git a/src/testRunner/unittests/tsserver/getExportReferences.ts b/src/testRunner/unittests/tsserver/getExportReferences.ts index 1219a07c2f3b1..c8347e7f67282 100644 --- a/src/testRunner/unittests/tsserver/getExportReferences.ts +++ b/src/testRunner/unittests/tsserver/getExportReferences.ts @@ -68,7 +68,11 @@ export const { nest: [valueE, { valueF }] } = { nest: [0, { valueF: 1 }] }; command: ts.server.protocol.CommandTypes.References, arguments: protocolFileLocationFromSubstring(modTs, "renamedD"), }); - baselineTsserverLogs("getExportReferences", "object declaration references that renames destructured property", session); + baselineTsserverLogs( + "getExportReferences", + "object declaration references that renames destructured property", + session, + ); }); it("should get nested object declaration references", () => { diff --git a/src/testRunner/unittests/tsserver/getFileReferences.ts b/src/testRunner/unittests/tsserver/getFileReferences.ts index 147f9091c3f1d..057ab0dcb2240 100644 --- a/src/testRunner/unittests/tsserver/getFileReferences.ts +++ b/src/testRunner/unittests/tsserver/getFileReferences.ts @@ -26,11 +26,11 @@ describe("unittests:: tsserver:: getFileReferences", () => { }; const cTs: File = { path: "/project/c.ts", - content: importCurlyFromA + content: importCurlyFromA, }; const dTs: File = { path: "/project/d.ts", - content: [importAFromA, typeofImportA].join("\n") + content: [importAFromA, typeofImportA].join("\n"), }; const tsconfig: File = { path: "/project/tsconfig.json", @@ -59,8 +59,8 @@ describe("unittests:: tsserver:: getFileReferences", () => { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, arguments: { - preferences: { disableLineTextInReferences: true } - } + preferences: { disableLineTextInReferences: true }, + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.FileReferences, diff --git a/src/testRunner/unittests/tsserver/getMoveToRefactoringFileSuggestions.ts b/src/testRunner/unittests/tsserver/getMoveToRefactoringFileSuggestions.ts index e70ab769cb052..bf958bcd1cd2f 100644 --- a/src/testRunner/unittests/tsserver/getMoveToRefactoringFileSuggestions.ts +++ b/src/testRunner/unittests/tsserver/getMoveToRefactoringFileSuggestions.ts @@ -3,11 +3,11 @@ import { baselineTsserverLogs, createLoggerWithInMemoryLogs, createSession, - openFilesForSession + openFilesForSession, } from "../helpers/tsserver"; import { createServerHost, - File + File, } from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: tsserver:: getMoveToRefactoringFileSuggestions", () => { @@ -17,35 +17,48 @@ describe("unittests:: tsserver:: getMoveToRefactoringFileSuggestions", () => { content: `interface ka { name: string; } - ` + `, }; const file2: File = { path: "/project/b/file2.ts", content: "" }; const file3: File = { path: "/project/d/e/file3.ts", content: "" }; const file4: File = { path: "/project/a/file4.ts", content: `import { value } from "../node_modules/@types/node/someFile.d.ts"; -import { value1 } from "../node_modules/.cache/someFile.d.ts";` +import { value1 } from "../node_modules/.cache/someFile.d.ts";`, }; const nodeModulesFile1: File = { path: "project/node_modules/@types/node/someFile.d.ts", - content: `export const value = 0;` + content: `export const value = 0;`, }; const nodeModulesFile2: File = { path: "project/node_modules/.cache/someFile.d.ts", - content: `export const value1 = 0;` + content: `export const value1 = 0;`, }; const tsconfig: File = { path: "/project/tsconfig.json", content: "{}", }; - const host = createServerHost([file1, file2, file3, file3, file4, nodeModulesFile1, nodeModulesFile2, tsconfig]); + const host = createServerHost([ + file1, + file2, + file3, + file3, + file4, + nodeModulesFile1, + nodeModulesFile2, + tsconfig, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetMoveToRefactoringFileSuggestions, - arguments: { file: file1.path, line: 1, offset: 11 } + arguments: { file: file1.path, line: 1, offset: 11 }, }); - baselineTsserverLogs("getMoveToRefactoringFileSuggestions", "works for suggesting a list of files, excluding node_modules within a project", session); + baselineTsserverLogs( + "getMoveToRefactoringFileSuggestions", + "works for suggesting a list of files, excluding node_modules within a project", + session, + ); }); it("suggests only .ts file for a .ts filepath", () => { const file1: File = { @@ -53,7 +66,7 @@ import { value1 } from "../node_modules/.cache/someFile.d.ts";` content: `interface ka { name: string; } - ` + `, }; const file2: File = { path: "/file2.tsx", content: "" }; const file3: File = { path: "/file3.mts", content: "" }; @@ -61,7 +74,20 @@ import { value1 } from "../node_modules/.cache/someFile.d.ts";` const file5: File = { path: "/file5.js", content: "" }; const file6: File = { path: "/file6.d.ts", content: "" }; const file7: File = { path: "/file7.ts", content: "" }; - const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ files: ["./file1.ts", "./file2.tsx", "./file3.mts", "./file4.cts", "./file5.js", "./file6.d.ts", "./file7.ts"] }) }; + const tsconfig: File = { + path: "/tsconfig.json", + content: JSON.stringify({ + files: [ + "./file1.ts", + "./file2.tsx", + "./file3.mts", + "./file4.cts", + "./file5.js", + "./file6.d.ts", + "./file7.ts", + ], + }), + }; const host = createServerHost([file1, file2, file3, file4, file5, file6, file7, tsconfig]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -69,20 +95,27 @@ import { value1 } from "../node_modules/.cache/someFile.d.ts";` session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetMoveToRefactoringFileSuggestions, - arguments: { file: file1.path, line: 1, offset: 11 } + arguments: { file: file1.path, line: 1, offset: 11 }, }); - baselineTsserverLogs("getMoveToRefactoringFileSuggestions", "suggests only .ts file for a .ts filepath", session); + baselineTsserverLogs( + "getMoveToRefactoringFileSuggestions", + "suggests only .ts file for a .ts filepath", + session, + ); }); it("suggests only .js file for a .js filepath", () => { const file1: File = { path: "/file1.js", - content: `class C {}` + content: `class C {}`, }; const file2: File = { path: "/file2.js", content: "" }; const file3: File = { path: "/file3.mts", content: "" }; const file4: File = { path: "/file4.ts", content: "" }; const file5: File = { path: "/file5.js", content: "" }; - const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ files: ["./file1.js", "./file2.js", "./file3.mts", "./file4.ts", "./file5.js"] }) }; + const tsconfig: File = { + path: "/tsconfig.json", + content: JSON.stringify({ files: ["./file1.js", "./file2.js", "./file3.mts", "./file4.ts", "./file5.js"] }), + }; const host = createServerHost([file1, file2, file3, file4, file5, tsconfig]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -90,19 +123,26 @@ import { value1 } from "../node_modules/.cache/someFile.d.ts";` session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetMoveToRefactoringFileSuggestions, - arguments: { file: file1.path, line: 1, offset: 7 } + arguments: { file: file1.path, line: 1, offset: 7 }, }); - baselineTsserverLogs("getMoveToRefactoringFileSuggestions", "suggests only .js file for a .js filepath", session); + baselineTsserverLogs( + "getMoveToRefactoringFileSuggestions", + "suggests only .js file for a .js filepath", + session, + ); }); it("skips lib.d.ts files", () => { const file1: File = { path: "/file1.d.ts", - content: `class C {}` + content: `class C {}`, }; const file2: File = { path: "/a/lib.d.ts", content: "" }; const file3: File = { path: "/a/file3.d.ts", content: "" }; const file4: File = { path: "/a/lib.es6.d.ts", content: "" }; - const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ files: ["./file1.d.ts", "./a/lib.d.ts", "./a/file3.d.ts", "/a/lib.es6.d.ts"] }) }; + const tsconfig: File = { + path: "/tsconfig.json", + content: JSON.stringify({ files: ["./file1.d.ts", "./a/lib.d.ts", "./a/file3.d.ts", "/a/lib.es6.d.ts"] }), + }; const host = createServerHost([file1, file2, file3, file4, tsconfig]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -110,8 +150,8 @@ import { value1 } from "../node_modules/.cache/someFile.d.ts";` session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetMoveToRefactoringFileSuggestions, - arguments: { file: file1.path, line: 1, offset: 7 } + arguments: { file: file1.path, line: 1, offset: 7 }, }); baselineTsserverLogs("getMoveToRefactoringFileSuggestions", "skips lib.d.ts files", session); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/goToDefinition.ts b/src/testRunner/unittests/tsserver/goToDefinition.ts index 852fc7d5588b3..f078d677694e3 100644 --- a/src/testRunner/unittests/tsserver/goToDefinition.ts +++ b/src/testRunner/unittests/tsserver/goToDefinition.ts @@ -1,14 +1,22 @@ -import { protocol } from "../../_namespaces/ts.server"; -import { baselineTsserverLogs, createLoggerWithInMemoryLogs, createSession } from "../helpers/tsserver"; -import { createServerHost, File } from "../helpers/virtualFileSystemWithWatch"; +import { + protocol, +} from "../../_namespaces/ts.server"; +import { + baselineTsserverLogs, + createLoggerWithInMemoryLogs, + createSession, +} from "../helpers/tsserver"; +import { + createServerHost, + File, +} from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: services:: goToDefinition", () => { it("does not issue errors on jsdoc in TS", () => { const files: File[] = [ { path: "/packages/babel-loader/tsconfig.json", - content: - ` + content: ` { "compilerOptions": { "target": "ES2018", @@ -20,19 +28,18 @@ describe("unittests:: services:: goToDefinition", () => { }, "include": ["src"], } -` +`, }, { path: "/packages/babel-loader/src/index.ts", - content: - ` + content: ` declare class Stuff { /** For more thorough tests, use {@link checkFooIs} */ checkFooLengthIs(len: number): void; checkFooIs(value: object): void; } -` +`, }, ]; const host = createServerHost(files); @@ -45,9 +52,9 @@ declare class Stuff { { file: files[1].path, // babel-loader/src/index.ts fileContent: files[1].content, - } - ] - } + }, + ], + }, }); session.executeCommandSeq({ command: protocol.CommandTypes.Definition, @@ -62,17 +69,15 @@ declare class Stuff { command: protocol.CommandTypes.SemanticDiagnosticsSync, arguments: { file: "/packages/babel-loader/src/index.ts", - } + }, }); baselineTsserverLogs("goToDefinition", "does not issue errors on jsdoc in TS", session); - }); it("does not issue errors on jsdoc in TS", () => { const files: File[] = [ { path: "/packages/babel-loader/tsconfig.json", - content: - ` + content: ` { "compilerOptions": { "target": "ES2018", @@ -84,12 +89,11 @@ declare class Stuff { }, "include": ["src"], } -` +`, }, { path: "/packages/babel-loader/src/index.ts", - content: - ` + content: ` declare class Stuff { /** * Register a function to be run on mod initialization... @@ -102,7 +106,7 @@ declare class Stuff { */ on_init(f: (() => void) | undefined): void } -` +`, }, ]; const host = createServerHost(files); @@ -115,9 +119,9 @@ declare class Stuff { { file: files[1].path, // babel-loader/src/index.ts fileContent: files[1].content, - } - ] - } + }, + ], + }, }); session.executeCommandSeq({ command: protocol.CommandTypes.Definition, @@ -132,9 +136,8 @@ declare class Stuff { command: protocol.CommandTypes.SemanticDiagnosticsSync, arguments: { file: "/packages/babel-loader/src/index.ts", - } + }, }); baselineTsserverLogs("goToDefinition", "does not issue errors on jsdoc in TS2", session); - }); }); diff --git a/src/testRunner/unittests/tsserver/importHelpers.ts b/src/testRunner/unittests/tsserver/importHelpers.ts index cad9e1c491552..dba1ac21e5cf0 100644 --- a/src/testRunner/unittests/tsserver/importHelpers.ts +++ b/src/testRunner/unittests/tsserver/importHelpers.ts @@ -5,21 +5,27 @@ import { openExternalProjectForSession, toExternalFile, } from "../helpers/tsserver"; -import { createServerHost } from "../helpers/virtualFileSystemWithWatch"; +import { + createServerHost, +} from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: tsserver:: importHelpers", () => { it("should not crash in tsserver", () => { const f1 = { path: "/a/app.ts", - content: "export async function foo() { return 100; }" + content: "export async function foo() { return 100; }", }; const tslib = { path: "/a/node_modules/tslib/index.d.ts", - content: "" + content: "", }; const host = createServerHost([f1, tslib]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); - openExternalProjectForSession({ projectFileName: "p", rootFiles: [toExternalFile(f1.path)], options: { importHelpers: true } }, session); + openExternalProjectForSession({ + projectFileName: "p", + rootFiles: [toExternalFile(f1.path)], + options: { importHelpers: true }, + }, session); baselineTsserverLogs("importHelpers", "should not crash in tsserver", session); }); }); diff --git a/src/testRunner/unittests/tsserver/inconsistentErrorInEditor.ts b/src/testRunner/unittests/tsserver/inconsistentErrorInEditor.ts index fdee92a017186..2c9c789d24bdc 100644 --- a/src/testRunner/unittests/tsserver/inconsistentErrorInEditor.ts +++ b/src/testRunner/unittests/tsserver/inconsistentErrorInEditor.ts @@ -11,7 +11,11 @@ import { describe("unittests:: tsserver:: inconsistentErrorInEditor", () => { it("should not error", () => { const host = createServerHost([]); - const session = createSession(host, { canUseEvents: true, noGetErrOnBackgroundUpdate: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + canUseEvents: true, + noGetErrOnBackgroundUpdate: true, + logger: createLoggerWithInMemoryLogs(host), + }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { @@ -20,11 +24,12 @@ describe("unittests:: tsserver:: inconsistentErrorInEditor", () => { openFiles: [ { file: "^/untitled/ts-nul-authority/Untitled-1", - fileContent: "export function foo() {\r\n /*$*/return bar;\r\n}\r\n\r\nexport function bar(x: T) {\r\n return x;\r\n}\r\n\r\nlet x = foo()(42);", - scriptKindName: "TS" - } - ] - } + fileContent: + "export function foo() {\r\n /*$*/return bar;\r\n}\r\n\r\nexport function bar(x: T) {\r\n return x;\r\n}\r\n\r\nlet x = foo()(42);", + scriptKindName: "TS", + }, + ], + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EncodedSemanticClassificationsFull, @@ -32,8 +37,8 @@ describe("unittests:: tsserver:: inconsistentErrorInEditor", () => { file: "^/untitled/ts-nul-authority/Untitled-1", start: 0, length: 128, - format: "2020" - } + format: "2020", + }, }); verifyGetErrRequest({ session, files: ["^/untitled/ts-nul-authority/Untitled-1"] }); baselineTsserverLogs("inconsistentErrorInEditor", "should not error", session); @@ -43,7 +48,11 @@ describe("unittests:: tsserver:: inconsistentErrorInEditor", () => { describe("unittests:: tsserver:: inconsistentErrorInEditor2", () => { it("should not error", () => { const host = createServerHost([]); - const session = createSession(host, { canUseEvents: true, noGetErrOnBackgroundUpdate: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + canUseEvents: true, + noGetErrOnBackgroundUpdate: true, + logger: createLoggerWithInMemoryLogs(host), + }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { @@ -52,11 +61,12 @@ describe("unittests:: tsserver:: inconsistentErrorInEditor2", () => { openFiles: [ { file: "^/untitled/ts-nul-authority/Untitled-1", - fileContent: "function fn(Foo: number) {\r\n type Foo = typeof Foo;\r\n return 0 as any as {x: Foo};\r\n}", - scriptKindName: "TS" - } - ] - } + fileContent: + "function fn(Foo: number) {\r\n type Foo = typeof Foo;\r\n return 0 as any as {x: Foo};\r\n}", + scriptKindName: "TS", + }, + ], + }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EncodedSemanticClassificationsFull, @@ -64,8 +74,8 @@ describe("unittests:: tsserver:: inconsistentErrorInEditor2", () => { file: "^/untitled/ts-nul-authority/Untitled-1", start: 0, length: 128, - format: "2020" - } + format: "2020", + }, }); verifyGetErrRequest({ session, files: ["^/untitled/ts-nul-authority/Untitled-1"] }); baselineTsserverLogs("inconsistentErrorInEditor2", "should not error", session); diff --git a/src/testRunner/unittests/tsserver/inferredProjects.ts b/src/testRunner/unittests/tsserver/inferredProjects.ts index abe55289e5222..e16bda2866d6c 100644 --- a/src/testRunner/unittests/tsserver/inferredProjects.ts +++ b/src/testRunner/unittests/tsserver/inferredProjects.ts @@ -1,5 +1,7 @@ import * as ts from "../../_namespaces/ts"; -import { commonFile1 } from "../helpers/tscWatch"; +import { + commonFile1, +} from "../helpers/tscWatch"; import { baselineTsserverLogs, closeFilesForSession, @@ -23,12 +25,12 @@ describe("unittests:: tsserver:: inferredProjects", () => { content: ` import {f} from "./module" console.log(f) - ` + `, }; const moduleFile: File = { path: `/user/username/projects/myproject/module.d.ts`, - content: `export let x: number` + content: `export let x: number`, }; const host = createServerHost([appFile, moduleFile, libFile]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -39,7 +41,7 @@ describe("unittests:: tsserver:: inferredProjects", () => { it("should use only one inferred project if 'useOneInferredProject' is set", () => { const file1 = { path: `/user/username/projects/myproject/a/b/main.ts`, - content: "let x =1;" + content: "let x =1;", }; const configFile: File = { path: `/user/username/projects/myproject/a/b/tsconfig.json`, @@ -48,52 +50,65 @@ describe("unittests:: tsserver:: inferredProjects", () => { "target": "es6" }, "files": [ "main.ts" ] - }` + }`, }; const file2 = { path: `/user/username/projects/myproject/a/c/main.ts`, - content: "let x =1;" + content: "let x =1;", }; const file3 = { path: `/user/username/projects/myproject/a/d/main.ts`, - content: "let x =1;" + content: "let x =1;", }; const host = createServerHost([file1, file2, file3, libFile]); - const projectService = createProjectService(host, { useSingleInferredProject: true, logger: createLoggerWithInMemoryLogs(host) }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + logger: createLoggerWithInMemoryLogs(host), + }); projectService.openClientFile(file1.path); projectService.openClientFile(file2.path); projectService.openClientFile(file3.path); host.writeFile(configFile.path, configFile.content); host.runQueuedTimeoutCallbacks(); // load configured project from disk + ensureProjectsForOpenFiles - baselineTsserverLogs("inferredProjects", "should use only one inferred project if useOneInferredProject is set", projectService); + baselineTsserverLogs( + "inferredProjects", + "should use only one inferred project if useOneInferredProject is set", + projectService, + ); }); it("disable inferred project", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x =1;" + content: "let x =1;", }; const host = createServerHost([file1]); - const projectService = createProjectService(host, { useSingleInferredProject: true, serverMode: ts.LanguageServiceMode.Syntactic, logger: createLoggerWithInMemoryLogs(host) }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + serverMode: ts.LanguageServiceMode.Syntactic, + logger: createLoggerWithInMemoryLogs(host), + }); projectService.openClientFile(file1.path, file1.content); - projectService.logger.log(`LanguageServiceEnabled:: ${projectService.inferredProjects[0].languageServiceEnabled}`); + projectService.logger.log( + `LanguageServiceEnabled:: ${projectService.inferredProjects[0].languageServiceEnabled}`, + ); baselineTsserverLogs("inferredProjects", "disable inferred project", projectService); }); it("project settings for inferred projects", () => { const file1 = { path: "/a/b/app.ts", - content: `import {x} from "mod"` + content: `import {x} from "mod"`, }; const modFile = { path: "/a/mod.ts", - content: "export let x: number" + content: "export let x: number", }; const host = createServerHost([file1, modFile]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -109,7 +124,7 @@ describe("unittests:: tsserver:: inferredProjects", () => { it("should support files without extensions", () => { const f = { path: "/a/compile", - content: "let x = 1" + content: "let x = 1", }; const host = createServerHost([f]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -127,41 +142,41 @@ describe("unittests:: tsserver:: inferredProjects", () => { const session = createSession(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true, - logger: createLoggerWithInMemoryLogs(host) + logger: createLoggerWithInMemoryLogs(host), }); setCompilerOptionsForInferredProjectsRequestForSession({ allowJs: true, - target: ts.ScriptTarget.ESNext + target: ts.ScriptTarget.ESNext, }, session); setCompilerOptionsForInferredProjectsRequestForSession({ options: { allowJs: true, - target: ts.ScriptTarget.ES2015 + target: ts.ScriptTarget.ES2015, }, - projectRootPath: "/b" + projectRootPath: "/b", }, session); openFilesForSession([{ file: file1.path, content: file1.content, scriptKindName: "JS", - projectRootPath: file1.projectRootPath + projectRootPath: file1.projectRootPath, }], session); openFilesForSession([{ file: file2.path, content: file2.content, scriptKindName: "JS", - projectRootPath: file2.projectRootPath + projectRootPath: file2.projectRootPath, }], session); openFilesForSession([{ file: file3.path, content: file3.content, scriptKindName: "JS", - projectRootPath: file3.projectRootPath + projectRootPath: file3.projectRootPath, }], session); openFilesForSession([{ file: file4.path, content: file4.content, - scriptKindName: "JS" + scriptKindName: "JS", }], session); const projectService = session.getProjectService(); @@ -177,20 +192,24 @@ describe("unittests:: tsserver:: inferredProjects", () => { { path: "/a/file1.ts", content: "let x = 1;" }, { path: "/A/file2.ts", content: "let y = 2;" }, { path: "/b/file2.ts", content: "let x = 3;" }, - { path: "/c/file3.ts", content: "let z = 4;" } + { path: "/c/file3.ts", content: "let z = 4;" }, ]; const host = createServerHost(files, { useCaseSensitiveFileNames }); - const session = createSession(host, { useSingleInferredProject: true, useInferredProjectPerProjectRoot: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + useSingleInferredProject: true, + useInferredProjectPerProjectRoot: true, + logger: createLoggerWithInMemoryLogs(host), + }); setCompilerOptionsForInferredProjectsRequestForSession({ allowJs: true, - target: ts.ScriptTarget.ESNext + target: ts.ScriptTarget.ESNext, }, session); setCompilerOptionsForInferredProjectsRequestForSession({ options: { allowJs: true, - target: ts.ScriptTarget.ES2015 + target: ts.ScriptTarget.ES2015, }, - projectRootPath: "/a" + projectRootPath: "/a", }, session); openClientFiles(["/a", "/a", "/b", undefined]); @@ -202,9 +221,9 @@ describe("unittests:: tsserver:: inferredProjects", () => { setCompilerOptionsForInferredProjectsRequestForSession({ options: { allowJs: true, - target: ts.ScriptTarget.ES2017 + target: ts.ScriptTarget.ES2017, }, - projectRootPath: "/A" + projectRootPath: "/A", }, session); openClientFiles(["/a", "/a", "/b", undefined]); @@ -214,9 +233,16 @@ describe("unittests:: tsserver:: inferredProjects", () => { closeClientFiles(); baselineTsserverLogs("inferredProjects", subScenario, session); - function openClientFiles(projectRoots: [string | undefined, string | undefined, string | undefined, string | undefined]) { + function openClientFiles( + projectRoots: [string | undefined, string | undefined, string | undefined, string | undefined], + ) { files.forEach((file, index) => - openFilesForSession([{ file: file.path, content: file.content, scriptKindName: "JS", projectRootPath: projectRoots[index] }], session) + openFilesForSession([{ + file: file.path, + content: file.content, + scriptKindName: "JS", + projectRootPath: projectRoots[index], + }], session) ); } @@ -226,25 +252,31 @@ describe("unittests:: tsserver:: inferredProjects", () => { }); } - verifyProjectRootWithCaseSensitivity("inferred projects per project root with case sensitive system", /*useCaseSensitiveFileNames*/ true); - verifyProjectRootWithCaseSensitivity("inferred projects per project root with case insensitive system", /*useCaseSensitiveFileNames*/ false); + verifyProjectRootWithCaseSensitivity( + "inferred projects per project root with case sensitive system", + /*useCaseSensitiveFileNames*/ true, + ); + verifyProjectRootWithCaseSensitivity( + "inferred projects per project root with case insensitive system", + /*useCaseSensitiveFileNames*/ false, + ); it("should still retain configured project created while opening the file", () => { const appFile: File = { path: `/user/username/projects/myproject/app.ts`, - content: `const app = 20;` + content: `const app = 20;`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const jsFile1: File = { path: `/user/username/projects/myproject/jsFile1.js`, - content: `const jsFile1 = 10;` + content: `const jsFile1 = 10;`, }; const jsFile2: File = { path: `/user/username/projects/myproject/jsFile2.js`, - content: `const jsFile2 = 10;` + content: `const jsFile2 = 10;`, }; const host = createServerHost([appFile, libFile, config, jsFile1, jsFile2]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -261,7 +293,11 @@ describe("unittests:: tsserver:: inferredProjects", () => { // When opening file that doesnt fall back to the config file, we remove the config project openFilesForSession([libFile], session); - baselineTsserverLogs("inferredProjects", "should still retain configured project created while opening the file", session); + baselineTsserverLogs( + "inferredProjects", + "should still retain configured project created while opening the file", + session, + ); }); it("regression test - should infer typeAcquisition for inferred projects when set undefined", () => { @@ -275,8 +311,16 @@ describe("unittests:: tsserver:: inferredProjects", () => { const inferredProject = projectService.inferredProjects[0]; projectService.logger.log(`typeAcquisition : setting to undefined`); inferredProject.setTypeAcquisition(undefined); - projectService.logger.log(`typeAcquisition should be inferred for inferred projects: ${JSON.stringify(inferredProject.getTypeAcquisition(), undefined, " ")}`); - baselineTsserverLogs("inferredProjects", "regression test - should infer typeAcquisition for inferred projects when set undefined", projectService); + projectService.logger.log( + `typeAcquisition should be inferred for inferred projects: ${ + JSON.stringify(inferredProject.getTypeAcquisition(), undefined, " ") + }`, + ); + baselineTsserverLogs( + "inferredProjects", + "regression test - should infer typeAcquisition for inferred projects when set undefined", + projectService, + ); }); it("Setting compiler options for inferred projects when there are no open files should not schedule any refresh", () => { @@ -284,9 +328,13 @@ describe("unittests:: tsserver:: inferredProjects", () => { const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); setCompilerOptionsForInferredProjectsRequestForSession({ allowJs: true, - target: ts.ScriptTarget.ES2015 + target: ts.ScriptTarget.ES2015, }, session); session.testhost.logTimeoutQueueLength(); - baselineTsserverLogs("inferredProjects", "Setting compiler options for inferred projects when there are no open files should not schedule any refresh", session); + baselineTsserverLogs( + "inferredProjects", + "Setting compiler options for inferred projects when there are no open files should not schedule any refresh", + session, + ); }); }); diff --git a/src/testRunner/unittests/tsserver/inlayHints.ts b/src/testRunner/unittests/tsserver/inlayHints.ts index 375393932892b..fbc3bb25e63f6 100644 --- a/src/testRunner/unittests/tsserver/inlayHints.ts +++ b/src/testRunner/unittests/tsserver/inlayHints.ts @@ -18,11 +18,11 @@ import { describe("unittests:: tsserver:: inlayHints", () => { const configFile: File = { path: "/a/b/tsconfig.json", - content: "{}" + content: "{}", }; const app: File = { path: "/a/b/app.ts", - content: "declare function foo(param: any): void;\nfoo(12);" + content: "declare function foo(param: any): void;\nfoo(12);", }; it("with updateOpen request does not corrupt documents", () => { @@ -30,29 +30,35 @@ describe("unittests:: tsserver:: inlayHints", () => { const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Open, - arguments: { file: app.path } + arguments: { file: app.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, arguments: { preferences: { - includeInlayParameterNameHints: "all" - } as ts.UserPreferences - } + includeInlayParameterNameHints: "all", + } as ts.UserPreferences, + }, }); verifyInlayHintResponse(session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { - changedFiles: [{ fileName: app.path, textChanges: [{ start: { line: 1, offset: 39 }, end: { line: 1, offset: 39 }, newText: "//" }] }] - } + changedFiles: [{ + fileName: app.path, + textChanges: [{ start: { line: 1, offset: 39 }, end: { line: 1, offset: 39 }, newText: "//" }], + }], + }, }); verifyInlayHintResponse(session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.UpdateOpen, arguments: { - changedFiles: [{ fileName: app.path, textChanges: [{ start: { line: 1, offset: 41 }, end: { line: 1, offset: 41 }, newText: "c" }] }] - } + changedFiles: [{ + fileName: app.path, + textChanges: [{ start: { line: 1, offset: 41 }, end: { line: 1, offset: 41 }, newText: "c" }], + }], + }, }); verifyInlayHintResponse(session); baselineTsserverLogs("inlayHints", "with updateOpen request does not corrupt documents", session); @@ -64,7 +70,7 @@ describe("unittests:: tsserver:: inlayHints", () => { file: app.path, start: 0, length: app.content.length, - } + }, }); } }); diff --git a/src/testRunner/unittests/tsserver/jsdocTag.ts b/src/testRunner/unittests/tsserver/jsdocTag.ts index 1c1ffd51a1003..5900914bd8217 100644 --- a/src/testRunner/unittests/tsserver/jsdocTag.ts +++ b/src/testRunner/unittests/tsserver/jsdocTag.ts @@ -20,11 +20,11 @@ describe("unittests:: tsserver:: jsdocTag:: jsdoc @link ", () => { } "files": ["someFile1.js"] } -` +`, }; function assertQuickInfoJSDoc(subScenario: string, file: File, options: { - displayPartsForJSDoc: boolean, - command: ts.server.protocol.CommandTypes, + displayPartsForJSDoc: boolean; + command: ts.server.protocol.CommandTypes; }) { it(subScenario, () => { const { command, displayPartsForJSDoc } = options; @@ -32,7 +32,7 @@ describe("unittests:: tsserver:: jsdocTag:: jsdoc @link ", () => { const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { preferences: { displayPartsForJSDoc } } + arguments: { preferences: { displayPartsForJSDoc } }, }); openFilesForSession([file], session); const indexOfX = file.content.indexOf("x"); @@ -41,7 +41,7 @@ describe("unittests:: tsserver:: jsdocTag:: jsdoc @link ", () => { arguments: { file: file.path, position: indexOfX, - } as ts.server.protocol.FileLocationRequestArgs + } as ts.server.protocol.FileLocationRequestArgs, }); baselineTsserverLogs("jsdocTag", subScenario, session); }); @@ -51,20 +51,24 @@ describe("unittests:: tsserver:: jsdocTag:: jsdoc @link ", () => { path: "/a/someFile1.js", content: `class C { } /** @wat {@link C} */ -var x = 1` +var x = 1`, }; const linkInComment: File = { path: "/a/someFile1.js", content: `class C { } /** {@link C} */ var x = 1 -;` +;`, }; - assertQuickInfoJSDoc("for quickinfo, should provide display parts plus a span for a working link in a tag", linkInTag, { - command: ts.server.protocol.CommandTypes.Quickinfo, - displayPartsForJSDoc: true, - }); + assertQuickInfoJSDoc( + "for quickinfo, should provide display parts plus a span for a working link in a tag", + linkInTag, + { + command: ts.server.protocol.CommandTypes.Quickinfo, + displayPartsForJSDoc: true, + }, + ); assertQuickInfoJSDoc("for quickinfo, should provide a string for a working link in a tag", linkInTag, { command: ts.server.protocol.CommandTypes.Quickinfo, @@ -81,20 +85,28 @@ var x = 1 displayPartsForJSDoc: false, }); - assertQuickInfoJSDoc("for quickinfo-full, should provide display parts plus a span for a working link in a tag", linkInTag, { - command: ts.server.protocol.CommandTypes.QuickinfoFull, - displayPartsForJSDoc: true, - }); + assertQuickInfoJSDoc( + "for quickinfo-full, should provide display parts plus a span for a working link in a tag", + linkInTag, + { + command: ts.server.protocol.CommandTypes.QuickinfoFull, + displayPartsForJSDoc: true, + }, + ); assertQuickInfoJSDoc("for quickinfo-full, should provide a string for a working link in a tag", linkInTag, { command: ts.server.protocol.CommandTypes.QuickinfoFull, displayPartsForJSDoc: false, }); - assertQuickInfoJSDoc("for quickinfo-full, should provide display parts plus a span for a working link in a comment", linkInComment, { - command: ts.server.protocol.CommandTypes.QuickinfoFull, - displayPartsForJSDoc: true, - }); + assertQuickInfoJSDoc( + "for quickinfo-full, should provide display parts plus a span for a working link in a comment", + linkInComment, + { + command: ts.server.protocol.CommandTypes.QuickinfoFull, + displayPartsForJSDoc: true, + }, + ); assertQuickInfoJSDoc("for quickinfo-full, should provide a string for a working link in a comment", linkInComment, { command: ts.server.protocol.CommandTypes.QuickinfoFull, @@ -102,8 +114,8 @@ var x = 1 }); function assertSignatureHelpJSDoc(subScenario: string, options: { - displayPartsForJSDoc: boolean, - command: ts.server.protocol.CommandTypes, + displayPartsForJSDoc: boolean; + command: ts.server.protocol.CommandTypes; }) { it(subScenario, () => { const linkInParamTag: File = { @@ -111,7 +123,7 @@ var x = 1 content: `class C { } /** @param y - {@link C} */ function x(y) { } -x(1)` +x(1)`, }; const { command, displayPartsForJSDoc } = options; @@ -119,7 +131,7 @@ x(1)` const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { preferences: { displayPartsForJSDoc } } + arguments: { preferences: { displayPartsForJSDoc } }, }); openFilesForSession([linkInParamTag], session); const indexOfX = linkInParamTag.content.lastIndexOf("1"); @@ -127,11 +139,11 @@ x(1)` command: command as ts.server.protocol.CommandTypes.SignatureHelp, arguments: { triggerReason: { - kind: "invoked" + kind: "invoked", }, file: linkInParamTag.path, position: indexOfX, - } as ts.server.protocol.SignatureHelpRequestArgs + } as ts.server.protocol.SignatureHelpRequestArgs, }); baselineTsserverLogs("jsdocTag", subScenario, session); }); @@ -156,8 +168,8 @@ x(1)` }); function assertCompletionsJSDoc(subScenario: string, options: { - displayPartsForJSDoc: boolean, - command: ts.server.protocol.CommandTypes, + displayPartsForJSDoc: boolean; + command: ts.server.protocol.CommandTypes; }) { it(subScenario, () => { const linkInParamJSDoc: File = { @@ -165,14 +177,14 @@ x(1)` content: `class C { } /** @param x - see {@link C} */ function foo (x) { } -foo` +foo`, }; const { command, displayPartsForJSDoc } = options; const host = createServerHost([linkInParamJSDoc, config]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { preferences: { displayPartsForJSDoc } } + arguments: { preferences: { displayPartsForJSDoc } }, }); openFilesForSession([linkInParamJSDoc], session); const indexOfFoo = linkInParamJSDoc.content.lastIndexOf("fo"); @@ -182,7 +194,7 @@ foo` entryNames: ["foo"], file: linkInParamJSDoc.path, position: indexOfFoo, - } as ts.server.protocol.CompletionDetailsRequestArgs + } as ts.server.protocol.CompletionDetailsRequestArgs, }); baselineTsserverLogs("jsdocTag", subScenario, session); }); diff --git a/src/testRunner/unittests/tsserver/languageService.ts b/src/testRunner/unittests/tsserver/languageService.ts index ae95669213adb..4db3656854e92 100644 --- a/src/testRunner/unittests/tsserver/languageService.ts +++ b/src/testRunner/unittests/tsserver/languageService.ts @@ -1,18 +1,28 @@ import * as Utils from "../../_namespaces/Utils"; -import { baselineTsserverLogs, createLoggerWithInMemoryLogs, createProjectService, logDiagnostics } from "../helpers/tsserver"; -import { createServerHost } from "../helpers/virtualFileSystemWithWatch"; +import { + baselineTsserverLogs, + createLoggerWithInMemoryLogs, + createProjectService, + logDiagnostics, +} from "../helpers/tsserver"; +import { + createServerHost, +} from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: tsserver:: languageService", () => { it("should work correctly on case-sensitive file systems", () => { const lib = { path: "/a/Lib/lib.d.ts", - content: "let x: number" + content: "let x: number", }; const f = { path: "/a/b/app.ts", - content: "let x = 1;" + content: "let x = 1;", }; - const host = createServerHost([lib, f], { executingFilePath: "/a/Lib/tsc.js", useCaseSensitiveFileNames: true }); + const host = createServerHost([lib, f], { + executingFilePath: "/a/Lib/tsc.js", + useCaseSensitiveFileNames: true, + }); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.openClientFile(f.path); projectService.inferredProjects[0].getLanguageService().getProgram(); @@ -25,36 +35,38 @@ describe("unittests:: tsserver:: languageService", () => { path: "/project/shared.ts", content: Utils.dedent` import {foo_a} from "foo"; - ` + `, }, { path: `/project/a/tsconfig.json`, - content: `{ "compilerOptions": { "paths": { "foo": ["./foo.d.ts"] } }, "files": ["./index.ts", "./foo.d.ts"] }` + content: + `{ "compilerOptions": { "paths": { "foo": ["./foo.d.ts"] } }, "files": ["./index.ts", "./foo.d.ts"] }`, }, { path: `/project/a/foo.d.ts`, content: Utils.dedent` export const foo_a = 1; - ` + `, }, { path: "/project/a/index.ts", - content: `import "../shared";` + content: `import "../shared";`, }, { path: `/project/b/tsconfig.json`, - content: `{ "compilerOptions": { "paths": { "foo": ["./foo.d.ts"] } }, "files": ["./index.ts", "./foo.d.ts"] }` + content: + `{ "compilerOptions": { "paths": { "foo": ["./foo.d.ts"] } }, "files": ["./index.ts", "./foo.d.ts"] }`, }, { path: `/project/b/foo.d.ts`, content: Utils.dedent` export const foo_b = 1; - ` + `, }, { path: "/project/b/index.ts", - content: `import "../shared";` - } + content: `import "../shared";`, + }, ]; const host = createServerHost(files, { executingFilePath: "/project/tsc.js", useCaseSensitiveFileNames: true }); @@ -65,14 +77,20 @@ describe("unittests:: tsserver:: languageService", () => { projectService, `getSemanticDiagnostics:: ${files[1].path}`, projectService.configuredProjects.get(files[1].path)!, - projectService.configuredProjects.get(files[1].path)!.getLanguageService().getProgram()!.getSemanticDiagnostics(), + projectService.configuredProjects.get(files[1].path)!.getLanguageService().getProgram()! + .getSemanticDiagnostics(), ); logDiagnostics( projectService, `getSemanticDiagnostics:: ${files[4].path}`, projectService.configuredProjects.get(files[4].path)!, - projectService.configuredProjects.get(files[4].path)!.getLanguageService().getProgram()!.getSemanticDiagnostics(), + projectService.configuredProjects.get(files[4].path)!.getLanguageService().getProgram()! + .getSemanticDiagnostics(), + ); + baselineTsserverLogs( + "languageService", + "should support multiple projects with the same file under differing paths settings", + projectService, ); - baselineTsserverLogs("languageService", "should support multiple projects with the same file under differing paths settings", projectService); }); }); diff --git a/src/testRunner/unittests/tsserver/libraryResolution.ts b/src/testRunner/unittests/tsserver/libraryResolution.ts index 213e538ed70c7..7aadb4d5a9fbe 100644 --- a/src/testRunner/unittests/tsserver/libraryResolution.ts +++ b/src/testRunner/unittests/tsserver/libraryResolution.ts @@ -1,9 +1,11 @@ -import { getServerHosForLibResolution } from "../helpers/libraryResolution"; +import { + getServerHosForLibResolution, +} from "../helpers/libraryResolution"; import { baselineTsserverLogs, createLoggerWithInMemoryLogs, createSession, - openFilesForSession + openFilesForSession, } from "../helpers/tsserver"; describe("unittests:: tsserver:: libraryResolution", () => { @@ -11,7 +13,10 @@ describe("unittests:: tsserver:: libraryResolution", () => { const host = getServerHosForLibResolution(); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession(["/home/src/projects/project1/index.ts"], session); - host.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", content: "interface DOMInterface { }" }); + host.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", + content: "interface DOMInterface { }", + }); host.runQueuedTimeoutCallbacks(); host.runQueuedTimeoutCallbacks(); host.appendFile("/home/src/projects/project1/file.ts", "export const xyz = 10;"); @@ -20,26 +25,38 @@ describe("unittests:: tsserver:: libraryResolution", () => { host.runQueuedTimeoutCallbacks(); host.deleteFile("/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts"); host.runQueuedTimeoutCallbacks(); - host.writeFile("/home/src/projects/project1/tsconfig.json", JSON.stringify({ - compilerOptions: { - composite: true, - typeRoots: ["./typeroot1", "./typeroot2"], - lib: ["es5", "dom"], - traceResolution: true, - }, - })); - host.runQueuedTimeoutCallbacks(); - host.writeFile("/home/src/projects/project1/tsconfig.json", JSON.stringify({ - compilerOptions: { - composite: true, - typeRoots: ["./typeroot1"], - lib: ["es5", "dom"], - traceResolution: true, - }, - })); - host.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", content: "interface DOMInterface { }" }); - host.runQueuedTimeoutCallbacks(); - host.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts", content: "interface WebWorkerInterface { }" }); + host.writeFile( + "/home/src/projects/project1/tsconfig.json", + JSON.stringify({ + compilerOptions: { + composite: true, + typeRoots: ["./typeroot1", "./typeroot2"], + lib: ["es5", "dom"], + traceResolution: true, + }, + }), + ); + host.runQueuedTimeoutCallbacks(); + host.writeFile( + "/home/src/projects/project1/tsconfig.json", + JSON.stringify({ + compilerOptions: { + composite: true, + typeRoots: ["./typeroot1"], + lib: ["es5", "dom"], + traceResolution: true, + }, + }), + ); + host.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", + content: "interface DOMInterface { }", + }); + host.runQueuedTimeoutCallbacks(); + host.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts", + content: "interface WebWorkerInterface { }", + }); host.runQueuedTimeoutCallbacks(); host.runQueuedTimeoutCallbacks(); host.deleteFile("/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts"); @@ -56,33 +73,45 @@ describe("unittests:: tsserver:: libraryResolution", () => { host.runQueuedTimeoutCallbacks(); host.deleteFile("/home/src/projects/project1/core.d.ts"); host.runQueuedTimeoutCallbacks(); - host.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", content: "interface DOMInterface { }" }); - host.runQueuedTimeoutCallbacks(); - host.runQueuedTimeoutCallbacks(); - host.writeFile("/home/src/projects/project1/tsconfig.json", JSON.stringify({ - compilerOptions: { - composite: true, - typeRoots: ["./typeroot1", "./typeroot2"], - lib: ["es5", "dom"], - traceResolution: true, - }, - })); - host.runQueuedTimeoutCallbacks(); - host.writeFile("/home/src/projects/project1/tsconfig.json", JSON.stringify({ - compilerOptions: { - composite: true, - typeRoots: ["./typeroot1"], - lib: ["es5", "dom"], - traceResolution: true, - }, - })); + host.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts", + content: "interface DOMInterface { }", + }); + host.runQueuedTimeoutCallbacks(); + host.runQueuedTimeoutCallbacks(); + host.writeFile( + "/home/src/projects/project1/tsconfig.json", + JSON.stringify({ + compilerOptions: { + composite: true, + typeRoots: ["./typeroot1", "./typeroot2"], + lib: ["es5", "dom"], + traceResolution: true, + }, + }), + ); + host.runQueuedTimeoutCallbacks(); + host.writeFile( + "/home/src/projects/project1/tsconfig.json", + JSON.stringify({ + compilerOptions: { + composite: true, + typeRoots: ["./typeroot1"], + lib: ["es5", "dom"], + traceResolution: true, + }, + }), + ); host.deleteFile("/home/src/projects/node_modules/@typescript/lib-dom/index.d.ts"); host.runQueuedTimeoutCallbacks(); host.deleteFile("/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts"); host.runQueuedTimeoutCallbacks(); - host.ensureFileOrFolder({ path: "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts", content: "interface WebWorkerInterface { }" }); + host.ensureFileOrFolder({ + path: "/home/src/projects/node_modules/@typescript/lib-webworker/index.d.ts", + content: "interface WebWorkerInterface { }", + }); host.runQueuedTimeoutCallbacks(); host.runQueuedTimeoutCallbacks(); baselineTsserverLogs("libraryResolution", "with config with redirection", session); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/maxNodeModuleJsDepth.ts b/src/testRunner/unittests/tsserver/maxNodeModuleJsDepth.ts index 02b722bf0165d..1e0c5a3a4b4f3 100644 --- a/src/testRunner/unittests/tsserver/maxNodeModuleJsDepth.ts +++ b/src/testRunner/unittests/tsserver/maxNodeModuleJsDepth.ts @@ -17,46 +17,73 @@ describe("unittests:: tsserver:: maxNodeModuleJsDepth for inferred projects", () it("should be set to 2 if the project has js root files", () => { const file1: File = { path: "/a/b/file1.js", - content: `var t = require("test"); t.` + content: `var t = require("test"); t.`, }; const moduleFile: File = { path: "/a/b/node_modules/test/index.js", - content: `var v = 10; module.exports = v;` + content: `var v = 10; module.exports = v;`, }; const host = createServerHost([file1, moduleFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file1], session); - session.logger.log(`maxNodeModuleJsDepth: ${session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth}`); + session.logger.log( + `maxNodeModuleJsDepth: ${ + session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth + }`, + ); // Assert the option sticks setCompilerOptionsForInferredProjectsRequestForSession({ target: ts.ScriptTarget.ES2016 }, session); - session.logger.log(`maxNodeModuleJsDepth: ${session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth}`); + session.logger.log( + `maxNodeModuleJsDepth: ${ + session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth + }`, + ); baselineTsserverLogs("maxNodeModuleJsDepth", "should be set to 2 if the project has js root files", session); }); it("should return to normal state when all js root files are removed from project", () => { const file1 = { path: "/a/file1.ts", - content: "let x =1;" + content: "let x =1;", }; const file2 = { path: "/a/file2.js", - content: "let x =1;" + content: "let x =1;", }; const host = createServerHost([file1, file2, libFile]); - const session = createSession(host, { useSingleInferredProject: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + useSingleInferredProject: true, + logger: createLoggerWithInMemoryLogs(host), + }); openFilesForSession([file1], session); - session.logger.log(`maxNodeModuleJsDepth: ${session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth}`); + session.logger.log( + `maxNodeModuleJsDepth: ${ + session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth + }`, + ); openFilesForSession([file2], session); - session.logger.log(`maxNodeModuleJsDepth: ${session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth}`); + session.logger.log( + `maxNodeModuleJsDepth: ${ + session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth + }`, + ); closeFilesForSession([file2], session); - session.logger.log(`maxNodeModuleJsDepth: ${session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth}`); - baselineTsserverLogs("maxNodeModuleJsDepth", "should return to normal state when all js root files are removed from project", session); + session.logger.log( + `maxNodeModuleJsDepth: ${ + session.getProjectService().inferredProjects[0].getCompilationSettings().maxNodeModuleJsDepth + }`, + ); + baselineTsserverLogs( + "maxNodeModuleJsDepth", + "should return to normal state when all js root files are removed from project", + session, + ); }); }); diff --git a/src/testRunner/unittests/tsserver/metadataInResponse.ts b/src/testRunner/unittests/tsserver/metadataInResponse.ts index e69b1ab1f198c..726f3ddefcd01 100644 --- a/src/testRunner/unittests/tsserver/metadataInResponse.ts +++ b/src/testRunner/unittests/tsserver/metadataInResponse.ts @@ -17,8 +17,8 @@ describe("unittests:: tsserver:: with metadataInResponse::", () => { const tsconfig: File = { path: "/tsconfig.json", content: JSON.stringify({ - compilerOptions: { plugins: [{ name: "myplugin" }] } - }) + compilerOptions: { plugins: [{ name: "myplugin" }] }, + }), }; function createHostWithPlugin(files: readonly File[]) { const host = createServerHost(files); @@ -36,9 +36,9 @@ describe("unittests:: tsserver:: with metadataInResponse::", () => { return result; }; return proxy; - } + }, }), - error: undefined + error: undefined, }; }; return host; @@ -48,7 +48,7 @@ describe("unittests:: tsserver:: with metadataInResponse::", () => { const completionRequestArgs: ts.server.protocol.CompletionsRequestArgs = { file: aTs.path, line: 1, - offset: aTs.content.indexOf("this.") + 1 + "this.".length + offset: aTs.content.indexOf("this.") + 1 + "this.".length, }; it("can pass through metadata when the command returns array", () => { @@ -57,9 +57,13 @@ describe("unittests:: tsserver:: with metadataInResponse::", () => { openFilesForSession([aTs], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Completions, - arguments: completionRequestArgs + arguments: completionRequestArgs, }); - baselineTsserverLogs("metadataInResponse", "can pass through metadata when the command returns array", session); + baselineTsserverLogs( + "metadataInResponse", + "can pass through metadata when the command returns array", + session, + ); }); it("can pass through metadata when the command returns object", () => { @@ -68,9 +72,13 @@ describe("unittests:: tsserver:: with metadataInResponse::", () => { openFilesForSession([aTs], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompletionInfo, - arguments: completionRequestArgs + arguments: completionRequestArgs, }); - baselineTsserverLogs("metadataInResponse", "can pass through metadata when the command returns object", session); + baselineTsserverLogs( + "metadataInResponse", + "can pass through metadata when the command returns object", + session, + ); }); it("returns undefined correctly", () => { @@ -80,7 +88,7 @@ describe("unittests:: tsserver:: with metadataInResponse::", () => { openFilesForSession([aTs], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Completions, - arguments: { file: aTs.path, line: 1, offset: aTs.content.indexOf("x") + 1 } + arguments: { file: aTs.path, line: 1, offset: aTs.content.indexOf("x") + 1 }, }); baselineTsserverLogs("metadataInResponse", "returns undefined correctly", session); }); diff --git a/src/testRunner/unittests/tsserver/moduleResolution.ts b/src/testRunner/unittests/tsserver/moduleResolution.ts index f0ff49c993cfb..585d07175475a 100644 --- a/src/testRunner/unittests/tsserver/moduleResolution.ts +++ b/src/testRunner/unittests/tsserver/moduleResolution.ts @@ -1,5 +1,10 @@ import * as Utils from "../../_namespaces/Utils"; -import { getFsConentsForNode10ResultAtTypesPackageJson, getFsContentsForNode10Result, getFsContentsForNode10ResultDts, getFsContentsForNode10ResultPackageJson } from "../helpers/node10Result"; +import { + getFsConentsForNode10ResultAtTypesPackageJson, + getFsContentsForNode10Result, + getFsContentsForNode10ResultDts, + getFsContentsForNode10ResultPackageJson, +} from "../helpers/node10Result"; import { baselineTsserverLogs, createLoggerWithInMemoryLogs, @@ -24,32 +29,37 @@ describe("unittests:: tsserver:: moduleResolution", () => { module: "Node16", outDir: "../out", traceResolution: true, - } - }) + }, + }), }; const packageFile: File = { path: `/user/username/projects/myproject/package.json`, - content: packageFileContents + content: packageFileContents, }; const fileA: File = { path: `/user/username/projects/myproject/src/fileA.ts`, content: Utils.dedent` import { foo } from "./fileB.mjs"; foo(); - ` + `, }; const fileB: File = { path: `/user/username/projects/myproject/src/fileB.mts`, content: Utils.dedent` export function foo() { } - ` + `, }; - const host = createServerHost([configFile, fileA, fileB, packageFile, { ...libFile, path: "/a/lib/lib.es2016.full.d.ts" }]); + const host = createServerHost([configFile, fileA, fileB, packageFile, { + ...libFile, + path: "/a/lib/lib.es2016.full.d.ts", + }]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([fileA], session); return { - host, session, packageFile, + host, + session, + packageFile, verifyErr: () => verifyGetErrRequest({ files: [fileA], session }), }; } @@ -57,9 +67,14 @@ describe("unittests:: tsserver:: moduleResolution", () => { const { host, session, packageFile, verifyErr } = setup(JSON.stringify({ name: "app", version: "1.0.0" })); session.logger.info("Modify package json file to add type module"); - host.writeFile(packageFile.path, JSON.stringify({ - name: "app", version: "1.0.0", type: "module", - })); + host.writeFile( + packageFile.path, + JSON.stringify({ + name: "app", + version: "1.0.0", + type: "module", + }), + ); host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update verifyErr(); @@ -77,9 +92,14 @@ describe("unittests:: tsserver:: moduleResolution", () => { verifyErr(); session.logger.info("Modify package json file to add type module"); - host.writeFile(packageFile.path, JSON.stringify({ - name: "app", version: "1.0.0", type: "module", - })); + host.writeFile( + packageFile.path, + JSON.stringify({ + name: "app", + version: "1.0.0", + type: "module", + }), + ); host.runQueuedTimeoutCallbacks(); // Failed lookup updates host.runQueuedTimeoutCallbacks(); // Actual update verifyErr(); @@ -95,7 +115,9 @@ describe("unittests:: tsserver:: moduleResolution", () => { it("package json file is edited when package json with type module exists", () => { const { host, session, packageFile, verifyErr } = setup(JSON.stringify({ - name: "app", version: "1.0.0", type: "module", + name: "app", + version: "1.0.0", + type: "module", })); session.logger.info("Modify package json file to remove type module"); @@ -128,7 +150,11 @@ describe("unittests:: tsserver:: moduleResolution", () => { host.runQueuedTimeoutCallbacks(); // Actual update verifyErr(); - baselineTsserverLogs("moduleResolution", "package json file is edited when package json with type module exists", session); + baselineTsserverLogs( + "moduleResolution", + "package json file is edited when package json with type module exists", + session, + ); }); }); @@ -144,25 +170,49 @@ describe("unittests:: tsserver:: moduleResolution", () => { verifyErrors(); host.deleteFile("/home/src/projects/project/node_modules/foo/index.d.ts"); verifyErrors(); - host.writeFile("/home/src/projects/project/node_modules/@types/bar/index.d.ts", getFsContentsForNode10ResultDts("bar")); + host.writeFile( + "/home/src/projects/project/node_modules/@types/bar/index.d.ts", + getFsContentsForNode10ResultDts("bar"), + ); verifyErrors(); - host.writeFile("/home/src/projects/project/node_modules/foo/index.d.ts", getFsContentsForNode10ResultDts("foo")); + host.writeFile( + "/home/src/projects/project/node_modules/foo/index.d.ts", + getFsContentsForNode10ResultDts("foo"), + ); verifyErrors(); - host.writeFile("/home/src/projects/project/node_modules/@types/bar/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true)); + host.writeFile( + "/home/src/projects/project/node_modules/@types/bar/package.json", + getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true), + ); verifyErrors(); - host.writeFile("/home/src/projects/project/node_modules/foo/package.json", getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true)); + host.writeFile( + "/home/src/projects/project/node_modules/foo/package.json", + getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true), + ); verifyErrors(); - host.writeFile("/home/src/projects/project/node_modules/@types/bar2/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false)); + host.writeFile( + "/home/src/projects/project/node_modules/@types/bar2/package.json", + getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false), + ); verifyErrors(); - host.writeFile("/home/src/projects/project/node_modules/foo2/package.json", getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false)); + host.writeFile( + "/home/src/projects/project/node_modules/foo2/package.json", + getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false), + ); verifyErrors(); host.deleteFile("/home/src/projects/project/node_modules/@types/bar2/index.d.ts"); verifyErrors(); host.deleteFile("/home/src/projects/project/node_modules/foo2/index.d.ts"); verifyErrors(); - host.writeFile("/home/src/projects/project/node_modules/@types/bar2/index.d.ts", getFsContentsForNode10ResultDts("bar2")); + host.writeFile( + "/home/src/projects/project/node_modules/@types/bar2/index.d.ts", + getFsContentsForNode10ResultDts("bar2"), + ); verifyErrors(); - host.writeFile("/home/src/projects/project/node_modules/foo2/index.d.ts", getFsContentsForNode10ResultDts("foo2")); + host.writeFile( + "/home/src/projects/project/node_modules/foo2/index.d.ts", + getFsContentsForNode10ResultDts("foo2"), + ); verifyErrors(); baselineTsserverLogs("moduleResolution", "node10Result", session); @@ -176,4 +226,4 @@ describe("unittests:: tsserver:: moduleResolution", () => { }); } }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts b/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts index 5e06f62d75a52..b80e6289bad2c 100644 --- a/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts +++ b/src/testRunner/unittests/tsserver/moduleSpecifierCache.ts @@ -13,7 +13,7 @@ import { const packageJson: File = { path: "/package.json", - content: `{ "dependencies": { "mobx": "*" } }` + content: `{ "dependencies": { "mobx": "*" } }`, }; const aTs: File = { path: "/src/a.ts", @@ -37,21 +37,24 @@ const tsconfig: File = { }; const ambientDeclaration: File = { path: "/src/ambient.d.ts", - content: "declare module 'ambient' {}" + content: "declare module 'ambient' {}", }; const mobxPackageJson: File = { path: "/node_modules/mobx/package.json", - content: `{ "name": "mobx", "version": "1.0.0" }` + content: `{ "name": "mobx", "version": "1.0.0" }`, }; const mobxDts: File = { path: "/node_modules/mobx/index.d.ts", - content: "export declare function observable(): unknown;" + content: "export declare function observable(): unknown;", }; describe("unittests:: tsserver:: moduleSpecifierCache", () => { it("caches importability within a file", () => { const { session, moduleSpecifierCache } = setup(); - session.logger.info(`importability: ${moduleSpecifierCache.get(bTs.path as ts.Path, aTs.path as ts.Path, {}, {})?.isBlockedByPackageJsonDependencies}`); + session.logger.info( + `importability: ${moduleSpecifierCache.get(bTs.path as ts.Path, aTs.path as ts.Path, {}, {}) + ?.isBlockedByPackageJsonDependencies}`, + ); baselineTsserverLogs("moduleSpecifierCache", "caches importability within a file", session); }); @@ -59,7 +62,15 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { const { session, moduleSpecifierCache, triggerCompletions } = setup(); // Completion at an import statement will calculate and cache module specifiers triggerCompletions({ file: cTs.path, line: 1, offset: cTs.content.length + 1 }); - session.logger.info(`mobxCache: ${JSON.stringify(moduleSpecifierCache.get(cTs.path as ts.Path, mobxDts.path as ts.Path, {}, {}), undefined, " ")}`); + session.logger.info( + `mobxCache: ${ + JSON.stringify( + moduleSpecifierCache.get(cTs.path as ts.Path, mobxDts.path as ts.Path, {}, {}), + undefined, + " ", + ) + }`, + ); baselineTsserverLogs("moduleSpecifierCache", "caches module specifiers within a file", session); }); @@ -70,14 +81,21 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { host.writeFile("/node_modules/.staging/mobx-12345678/package.json", "{}"); host.runQueuedTimeoutCallbacks(); assert.equal(moduleSpecifierCache.count(), 0); - baselineTsserverLogs("moduleSpecifierCache", "invalidates module specifiers when changes happen in contained node_modules directories", session); + baselineTsserverLogs( + "moduleSpecifierCache", + "invalidates module specifiers when changes happen in contained node_modules directories", + session, + ); }); it("does not invalidate the cache when new files are added", () => { const { session, host, moduleSpecifierCache } = setup(); host.writeFile("/src/a2.ts", aTs.content); host.runQueuedTimeoutCallbacks(); - session.logger.info(`importability: ${moduleSpecifierCache.get(bTs.path as ts.Path, aTs.path as ts.Path, {}, {})?.isBlockedByPackageJsonDependencies}`); + session.logger.info( + `importability: ${moduleSpecifierCache.get(bTs.path as ts.Path, aTs.path as ts.Path, {}, {}) + ?.isBlockedByPackageJsonDependencies}`, + ); baselineTsserverLogs("moduleSpecifierCache", "does not invalidate the cache when new files are added", session); }); @@ -86,7 +104,11 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { host.renameFile(bSymlink.path, "/src/b-link2.ts"); host.runQueuedTimeoutCallbacks(); session.logger.info(`moduleSpecifierCache count: ${moduleSpecifierCache.count()}`); - baselineTsserverLogs("moduleSpecifierCache", "invalidates the cache when symlinks are added or removed", session); + baselineTsserverLogs( + "moduleSpecifierCache", + "invalidates the cache when symlinks are added or removed", + session, + ); }); it("invalidates the cache when local package.json changes", () => { @@ -102,7 +124,11 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { host.writeFile(tsconfig.path, `{ "compilerOptions": { "moduleResolution": "classic" }, "include": ["src"] }`); host.runQueuedTimeoutCallbacks(); session.logger.info(`moduleSpecifierCache count: ${moduleSpecifierCache.count()}`); - baselineTsserverLogs("moduleSpecifierCache", "invalidates the cache when module resolution settings change", session); + baselineTsserverLogs( + "moduleSpecifierCache", + "invalidates the cache when module resolution settings change", + session, + ); }); it("invalidates the cache when user preferences change", () => { @@ -112,7 +138,7 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { getWithPreferences({}); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { preferences } + arguments: { preferences }, }); // Nothing changes yet getWithPreferences({}); @@ -125,20 +151,38 @@ describe("unittests:: tsserver:: moduleSpecifierCache", () => { // Test other affecting preference session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { preferences: { importModuleSpecifierEnding: "js" } } + arguments: { preferences: { importModuleSpecifierEnding: "js" } }, }); triggerCompletions({ file: bTs.path, line: 1, offset: 3 }); getWithPreferences(preferences); baselineTsserverLogs("moduleSpecifierCache", "invalidates the cache when user preferences change", session); function getWithPreferences(preferences: ts.UserPreferences) { - session.logger.info(`moduleSpecifierCache for ${JSON.stringify(preferences)} (${bTs.path} -> ${aTs.path}) ${JSON.stringify(moduleSpecifierCache.get(bTs.path as ts.Path, aTs.path as ts.Path, preferences, {}), undefined, " ")}`); + session.logger.info( + `moduleSpecifierCache for ${JSON.stringify(preferences)} (${bTs.path} -> ${aTs.path}) ${ + JSON.stringify( + moduleSpecifierCache.get(bTs.path as ts.Path, aTs.path as ts.Path, preferences, {}), + undefined, + " ", + ) + }`, + ); } }); }); function setup() { - const host = createServerHost([aTs, bTs, cTs, bSymlink, ambientDeclaration, tsconfig, packageJson, mobxPackageJson, mobxDts]); + const host = createServerHost([ + aTs, + bTs, + cTs, + bSymlink, + ambientDeclaration, + tsconfig, + packageJson, + mobxPackageJson, + mobxDts, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([aTs, bTs, cTs], session); const projectService = session.getProjectService(); @@ -152,11 +196,18 @@ function setup() { includeCompletionsWithInsertText: true, includeCompletionsWithSnippetText: true, }, - } + }, }); triggerCompletions({ file: bTs.path, line: 1, offset: 3 }); - return { host, project, projectService, session, moduleSpecifierCache: project.getModuleSpecifierCache(), triggerCompletions }; + return { + host, + project, + projectService, + session, + moduleSpecifierCache: project.getModuleSpecifierCache(), + triggerCompletions, + }; function triggerCompletions(requestLocation: ts.server.protocol.FileLocationRequestArgs) { session.executeCommandSeq({ diff --git a/src/testRunner/unittests/tsserver/navTo.ts b/src/testRunner/unittests/tsserver/navTo.ts index db9303a635ee2..883d5bdbda56b 100644 --- a/src/testRunner/unittests/tsserver/navTo.ts +++ b/src/testRunner/unittests/tsserver/navTo.ts @@ -15,11 +15,11 @@ describe("unittests:: tsserver:: navigate-to for javascript project", () => { it("should not include type symbols", () => { const file1: File = { path: "/a/b/file1.js", - content: "function foo() {}" + content: "function foo() {}", }; const configFile: File = { path: "/a/b/jsconfig.json", - content: "{}" + content: "{}", }; const host = createServerHost([file1, configFile, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -28,12 +28,12 @@ describe("unittests:: tsserver:: navigate-to for javascript project", () => { // Try to find some interface type defined in lib.d.ts session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Navto, - arguments: { searchValue: "Document", file: file1.path, projectFileName: configFile.path } + arguments: { searchValue: "Document", file: file1.path, projectFileName: configFile.path }, }).response as ts.server.protocol.NavtoItem[]; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Navto, - arguments: { searchValue: "foo", file: file1.path, projectFileName: configFile.path } + arguments: { searchValue: "foo", file: file1.path, projectFileName: configFile.path }, }).response as ts.server.protocol.NavtoItem[]; baselineTsserverLogs("navTo", "should not include type symbols", session); }); @@ -45,11 +45,11 @@ describe("unittests:: tsserver:: navigate-to for javascript project", () => { "compilerOptions": { "composite": true } -}` +}`, }; const file1: File = { path: "/a/index.ts", - content: "export const abcdef = 1;" + content: "export const abcdef = 1;", }; const configFile2: File = { path: "/b/tsconfig.json", @@ -60,12 +60,12 @@ describe("unittests:: tsserver:: navigate-to for javascript project", () => { "references": [ { "path": "../a" } ] -}` +}`, }; const file2: File = { path: "/b/index.ts", content: `import a = require("../a"); -export const ghijkl = a.abcdef;` +export const ghijkl = a.abcdef;`, }; const host = createServerHost([configFile1, file1, configFile2, file2]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -73,7 +73,7 @@ export const ghijkl = a.abcdef;` session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Navto, - arguments: { searchValue: "abcdef", file: file1.path } + arguments: { searchValue: "abcdef", file: file1.path }, }); baselineTsserverLogs("navTo", "should de-duplicate symbols", session); @@ -85,7 +85,7 @@ export const ghijkl = a.abcdef;` content: JSON.stringify({ references: [{ path: "./a" }, { path: "./b" }], files: [], - }) + }), }; const configFile1: File = { path: "/a/tsconfig.json", @@ -93,11 +93,11 @@ export const ghijkl = a.abcdef;` "compilerOptions": { "composite": true } -}` +}`, }; const file1: File = { path: "/a/index.ts", - content: "export const abcdef = 1;" + content: "export const abcdef = 1;", }; const configFile2: File = { path: "/b/tsconfig.json", @@ -108,12 +108,12 @@ export const ghijkl = a.abcdef;` "references": [ { "path": "../a" } ] -}` +}`, }; const file2: File = { path: "/b/index.ts", content: `import a = require("../a"); -export const ghijkl = a.abcdef;` +export const ghijkl = a.abcdef;`, }; const host = createServerHost([configFile1, file1, configFile2, file2, solutionConfig]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -121,7 +121,7 @@ export const ghijkl = a.abcdef;` session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Navto, - arguments: { searchValue: "abcdef" } + arguments: { searchValue: "abcdef" }, }); baselineTsserverLogs("navTo", "should de-duplicate symbols when searching all projects", session); }); @@ -129,11 +129,11 @@ export const ghijkl = a.abcdef;` it("should work with Deprecated", () => { const file1: File = { path: "/a/b/file1.js", - content: "/** @deprecated */\nfunction foo () {}" + content: "/** @deprecated */\nfunction foo () {}", }; const configFile: File = { path: "/a/b/jsconfig.json", - content: "{}" + content: "{}", }; const host = createServerHost([file1, configFile, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -142,7 +142,7 @@ export const ghijkl = a.abcdef;` // Try to find some interface type defined in lib.d.ts session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Navto, - arguments: { searchValue: "foo", file: file1.path, projectFileName: configFile.path } + arguments: { searchValue: "foo", file: file1.path, projectFileName: configFile.path }, }); baselineTsserverLogs("navTo", "should work with Deprecated", session); }); diff --git a/src/testRunner/unittests/tsserver/occurences.ts b/src/testRunner/unittests/tsserver/occurences.ts index e9eb1552bf3e3..c89b4754db866 100644 --- a/src/testRunner/unittests/tsserver/occurences.ts +++ b/src/testRunner/unittests/tsserver/occurences.ts @@ -14,7 +14,7 @@ describe("unittests:: tsserver:: occurrence highlight on string", () => { it("should be marked if only on string values", () => { const file1: File = { path: "/a/b/file1.ts", - content: `let t1 = "div";\nlet t2 = "div";\nlet t3 = { "div": 123 };\nlet t4 = t3["div"];` + content: `let t1 = "div";\nlet t2 = "div";\nlet t3 = { "div": 123 };\nlet t4 = t3["div"];`, }; const host = createServerHost([file1]); @@ -22,17 +22,17 @@ describe("unittests:: tsserver:: occurrence highlight on string", () => { openFilesForSession([file1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DocumentHighlights, - arguments: { file: file1.path, line: 1, offset: 11, filesToSearch: [file1.path] } + arguments: { file: file1.path, line: 1, offset: 11, filesToSearch: [file1.path] }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DocumentHighlights, - arguments: { file: file1.path, line: 3, offset: 13, filesToSearch: [file1.path] } + arguments: { file: file1.path, line: 3, offset: 13, filesToSearch: [file1.path] }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DocumentHighlights, - arguments: { file: file1.path, line: 4, offset: 14, filesToSearch: [file1.path] } + arguments: { file: file1.path, line: 4, offset: 14, filesToSearch: [file1.path] }, }); baselineTsserverLogs("occurences", "should be marked if only on string values", session); }); diff --git a/src/testRunner/unittests/tsserver/openFile.ts b/src/testRunner/unittests/tsserver/openFile.ts index 3d3c9c1929a85..b3b3f38d3826f 100644 --- a/src/testRunner/unittests/tsserver/openFile.ts +++ b/src/testRunner/unittests/tsserver/openFile.ts @@ -21,7 +21,7 @@ describe("unittests:: tsserver:: Open-file", () => { it("can be reloaded with empty content", () => { const f = { path: "/a/b/app.ts", - content: "let x = 1" + content: "let x = 1", }; const projectFileName = "externalProject"; const host = createServerHost([f]); @@ -46,22 +46,22 @@ describe("unittests:: tsserver:: Open-file", () => { it(subScenario, () => { const file1: File = { path: "/a/b/src/app.ts", - content: "let x = 10;" + content: "let x = 10;", }; const file2: File = { path: "/a/B/lib/module2.ts", - content: "let z = 10;" + content: "let z = 10;", }; const configFile: File = { path: "/a/b/tsconfig.json", - content: "" + content: "", }; const configFile2: File = { path: "/a/tsconfig.json", - content: "" + content: "", }; const host = createServerHost([file1, file2, configFile, configFile2], { - useCaseSensitiveFileNames + useCaseSensitiveFileNames, }); const service = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -77,7 +77,12 @@ describe("unittests:: tsserver:: Open-file", () => { baselineTsserverLogs("openfile", subScenario, service); function verifyConfigFileName(file: File, projectRoot: string) { - const { configFileName } = service.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, projectRoot); + const { configFileName } = service.openClientFile( + file.path, + /*fileContent*/ undefined, + /*scriptKind*/ undefined, + projectRoot, + ); service.logger.log(`file: ${file.path} configFile: ${configFileName}`); service.closeClientFile(file.path); } @@ -90,11 +95,11 @@ describe("unittests:: tsserver:: Open-file", () => { const projectFolder = "/user/someuser/projects/myproject"; const aFile: File = { path: `${projectFolder}/src/a.ts`, - content: "export const x = 0;" + content: "export const x = 0;", }; const configFile: File = { path: `${projectFolder}/tsconfig.json`, - content: "{}" + content: "{}", }; const files = [aFile, configFile, libFile]; const host = createServerHost(files); @@ -103,7 +108,7 @@ describe("unittests:: tsserver:: Open-file", () => { const bFile: File = { path: `${projectFolder}/src/b.ts`, - content: `export {}; declare module "./a" { export const y: number; }` + content: `export {}; declare module "./a" { export const y: number; }`, }; host.writeFile(bFile.path, bFile.content); service.openClientFile(bFile.path, /*fileContent*/ undefined, ts.ScriptKind.TS, projectFolder); @@ -114,11 +119,11 @@ describe("unittests:: tsserver:: Open-file", () => { const projectFolder = "/user/someuser/projects/myproject"; const aFile: File = { path: `${projectFolder}/src/a.ts`, - content: "export const x = 0;" + content: "export const x = 0;", }; const configFile: File = { path: `${projectFolder}/tsconfig.json`, - content: "{}" + content: "{}", }; const files = [aFile, configFile, libFile]; const host = createServerHost(files); @@ -129,7 +134,12 @@ describe("unittests:: tsserver:: Open-file", () => { function verifyProject(aFileContent: string) { service.openClientFile(aFile.path, aFileContent, ts.ScriptKind.TS, projectFolder); - service.logger.log(`aFileContent: ${service.configuredProjects.get(configFile.path)!.getCurrentProgram()?.getSourceFile(aFile.path)!.text}`); + service.logger.log( + `aFileContent: ${ + service.configuredProjects.get(configFile.path)!.getCurrentProgram()?.getSourceFile(aFile.path)! + .text + }`, + ); } }); @@ -148,7 +158,7 @@ function bar() { return z; } foo(); -bar();` +bar();`, }; const host = createServerHost([file, libFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -165,10 +175,10 @@ bar();` fileName: file.path, textChanges: [{ newText: " ", - ...locationOfTsIgnore - }] - }] - } + ...locationOfTsIgnore, + }], + }], + }, }); verifyGetErrRequest({ session, files: [file] }); // Revert the change and no errors should be reported @@ -179,13 +189,17 @@ bar();` fileName: file.path, textChanges: [{ newText: tsIgnoreComment, - ...locationOfTsIgnore - }] - }] - } + ...locationOfTsIgnore, + }], + }], + }, }); verifyGetErrRequest({ session, files: [file] }); - baselineTsserverLogs("openfile", "when file makes edits to add/remove comment directives, they are handled correcrly", session); + baselineTsserverLogs( + "openfile", + "when file makes edits to add/remove comment directives, they are handled correcrly", + session, + ); }); describe("opening file and refreshing program", () => { @@ -208,10 +222,10 @@ bar();` fileName, changes: [{ span: { start: 0, length: 0 }, - newText: "export const y = 10;" - }] - }] - } + newText: "export const y = 10;", + }], + }], + }, }); } @@ -269,7 +283,11 @@ bar();` session.getProjectService().configuredProjects.get("/project/tsconfig.json")!.updateGraph(); host.appendFile("/project/b.ts", "export const x = 10;"); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("openfile", "edits on file and then close does not refresh sourceFile if contents match", session); + baselineTsserverLogs( + "openfile", + "edits on file and then close does not refresh sourceFile if contents match", + session, + ); }); }); }); diff --git a/src/testRunner/unittests/tsserver/packageJsonInfo.ts b/src/testRunner/unittests/tsserver/packageJsonInfo.ts index 1f7e4a740c5f1..57cda4f68bb75 100644 --- a/src/testRunner/unittests/tsserver/packageJsonInfo.ts +++ b/src/testRunner/unittests/tsserver/packageJsonInfo.ts @@ -12,25 +12,25 @@ import { const tsConfig: File = { path: "/tsconfig.json", - content: "{}" + content: "{}", }; const packageJsonContent = { dependencies: { - redux: "*" + redux: "*", }, peerDependencies: { - react: "*" + react: "*", }, optionalDependencies: { - typescript: "*" + typescript: "*", }, devDependencies: { - webpack: "*" - } + webpack: "*", + }, }; const packageJson: File = { path: "/package.json", - content: JSON.stringify(packageJsonContent, undefined, 2) + content: JSON.stringify(packageJsonContent, undefined, 2), }; describe("unittests:: tsserver:: packageJsonInfo::", () => { @@ -50,20 +50,27 @@ describe("unittests:: tsserver:: packageJsonInfo::", () => { assert.ok(packageJsonInfo.optionalDependencies); // Edit package.json - host.writeFile(packageJson.path, JSON.stringify({ - ...packageJsonContent, - dependencies: undefined - })); + host.writeFile( + packageJson.path, + JSON.stringify({ + ...packageJsonContent, + dependencies: undefined, + }), + ); session.testhost.baselineHost("Edit package.json"); packageJsonInfo = projectService.packageJsonCache.getInDirectory("/" as ts.Path)!; assert.isUndefined(packageJsonInfo.dependencies); - baselineTsserverLogs("packageJsonInfo", "detects new package.json files that are added, caches them, and watches them", session); + baselineTsserverLogs( + "packageJsonInfo", + "detects new package.json files that are added, caches them, and watches them", + session, + ); }); it("finds package.json on demand, watches for deletion, and removes them from cache", () => { // Initialize project with package.json - const { session , projectService, host } = setup(); + const { session, projectService, host } = setup(); projectService.getPackageJsonsVisibleToFile("/src/whatever/blah.ts" as ts.Path); assert.ok(projectService.packageJsonCache.getInDirectory("/" as ts.Path)); @@ -71,7 +78,11 @@ describe("unittests:: tsserver:: packageJsonInfo::", () => { host.deleteFile(packageJson.path); session.testhost.baselineHost("delete packageJson"); assert.isUndefined(projectService.packageJsonCache.getInDirectory("/" as ts.Path)); - baselineTsserverLogs("packageJsonInfo", "finds package.json on demand, watches for deletion, and removes them from cache", session); + baselineTsserverLogs( + "packageJsonInfo", + "finds package.json on demand, watches for deletion, and removes them from cache", + session, + ); }); it("finds multiple package.json files when present", () => { @@ -87,7 +98,10 @@ describe("unittests:: tsserver:: packageJsonInfo::", () => { it("handles errors in json parsing of package.json", () => { const packageJsonContent = `{ "mod" }`; - const { session, projectService, host } = setup([tsConfig, { path: packageJson.path, content: packageJsonContent }]); + const { session, projectService, host } = setup([tsConfig, { + path: packageJson.path, + content: packageJsonContent, + }]); projectService.getPackageJsonsVisibleToFile("/src/whatever/blah.ts" as ts.Path); const packageJsonInfo = projectService.packageJsonCache.getInDirectory("/" as ts.Path)!; assert.isFalse(packageJsonInfo.parseable); @@ -106,7 +120,10 @@ describe("unittests:: tsserver:: packageJsonInfo::", () => { it("handles empty package.json", () => { const packageJsonContent = ""; - const { session, projectService, host } = setup([tsConfig, { path: packageJson.path, content: packageJsonContent }]); + const { session, projectService, host } = setup([tsConfig, { + path: packageJson.path, + content: packageJsonContent, + }]); projectService.getPackageJsonsVisibleToFile("/src/whatever/blah.ts" as ts.Path); const packageJsonInfo = projectService.packageJsonCache.getInDirectory("/" as ts.Path)!; assert.isFalse(packageJsonInfo.parseable); diff --git a/src/testRunner/unittests/tsserver/partialSemanticServer.ts b/src/testRunner/unittests/tsserver/partialSemanticServer.ts index ed8d7a988dad4..1c9dd0c1f1150 100644 --- a/src/testRunner/unittests/tsserver/partialSemanticServer.ts +++ b/src/testRunner/unittests/tsserver/partialSemanticServer.ts @@ -20,25 +20,25 @@ describe("unittests:: tsserver:: Semantic operations on partialSemanticServer", path: `/user/username/projects/myproject/a.ts`, content: `import { y, cc } from "./b"; import { something } from "something"; -class c { prop = "hello"; foo() { return this.prop; } }` +class c { prop = "hello"; foo() { return this.prop; } }`, }; const file2: File = { path: `/user/username/projects/myproject/b.ts`, content: `export { cc } from "./c"; import { something } from "something"; - export const y = 10;` + export const y = 10;`, }; const file3: File = { path: `/user/username/projects/myproject/c.ts`, - content: `export const cc = 10;` + content: `export const cc = 10;`, }; const something: File = { path: `/user/username/projects/myproject/node_modules/something/index.d.ts`, - content: "export const something = 10;" + content: "export const something = 10;", }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const host = createServerHost([file1, file2, file3, something, libFile, configFile]); const session = createSession(host, { @@ -62,7 +62,7 @@ import { something } from "something"; function verifyCompletions() { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Completions, - arguments: protocolFileLocationFromSubstring(file1, "prop", { index: 1 }) + arguments: protocolFileLocationFromSubstring(file1, "prop", { index: 1 }), }); } }); @@ -74,7 +74,7 @@ import { something } from "something"; try { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); } catch (e) { @@ -94,11 +94,11 @@ import { something } from "something"; it("allows syntactic diagnostic commands", () => { const file1: File = { path: `/user/username/projects/myproject/a.ts`, - content: `if (a < (b + c) { }` + content: `if (a < (b + c) { }`, }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: `{}` + content: `{}`, }; const expectedErrorMessage = "')' expected."; @@ -106,7 +106,7 @@ import { something } from "something"; const session = createSession(host, { serverMode: ts.LanguageServiceMode.PartialSemantic, useSingleInferredProject: true, - logger: createLoggerWithInMemoryLogs(host) + logger: createLoggerWithInMemoryLogs(host), }); const service = session.getProjectService(); @@ -115,9 +115,10 @@ import { something } from "something"; type: "request", seq: 1, command: ts.server.protocol.CommandTypes.SyntacticDiagnosticsSync, - arguments: { file: file1.path } + arguments: { file: file1.path }, }; - const response = session.executeCommandSeq(request).response as ts.server.protocol.SyntacticDiagnosticsSyncResponse["body"]; + const response = session.executeCommandSeq(request) + .response as ts.server.protocol.SyntacticDiagnosticsSyncResponse["body"]; assert.isDefined(response); assert.equal(response!.length, 1); assert.equal((response![0] as ts.server.protocol.Diagnostic).text, expectedErrorMessage); @@ -135,7 +136,7 @@ import { something } from "something"; const { host, session, file1 } = setup(); const atTypes: File = { path: `/node_modules/@types/somemodule/index.d.ts`, - content: "export const something = 10;" + content: "export const something = 10;", }; host.ensureFileOrFolder(atTypes); openFilesForSession([file1], session); @@ -147,25 +148,25 @@ import { something } from "something"; path: `/user/username/projects/myproject/a.ts`, content: `/// /// -function fooA() { }` +function fooA() { }`, }; const file2: File = { path: `/user/username/projects/myproject/b.ts`, content: `/// /// -function fooB() { }` +function fooB() { }`, }; const file3: File = { path: `/user/username/projects/myproject/c.ts`, - content: `function fooC() { }` + content: `function fooC() { }`, }; const something: File = { path: `/user/username/projects/myproject/node_modules/something/index.d.ts`, - content: "function something() {}" + content: "function something() {}", }; const configFile: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; const host = createServerHost([file1, file2, file3, something, libFile, configFile]); const session = createSession(host, { @@ -174,7 +175,11 @@ function fooB() { }` logger: createLoggerWithInMemoryLogs(host), }); openFilesForSession([file1], session); - baselineTsserverLogs("partialSemanticServer", "should not include referenced files from unopened files", session); + baselineTsserverLogs( + "partialSemanticServer", + "should not include referenced files from unopened files", + session, + ); }); it("should not crash when external module name resolution is reused", () => { @@ -187,7 +192,11 @@ function fooB() { }` // Open file with non relative external module name openFilesForSession([file2], session); - baselineTsserverLogs("partialSemanticServer", "should not crash when external module name resolution is reused", session); + baselineTsserverLogs( + "partialSemanticServer", + "should not crash when external module name resolution is reused", + session, + ); }); it("should not create autoImportProvider or handle package jsons", () => { @@ -205,21 +214,36 @@ function fooB() { }` }; const packageJson: File = { path: "/package.json", - content: `{ "dependencies": { "@angular/forms": "*", "@angular/core": "*" } }` + content: `{ "dependencies": { "@angular/forms": "*", "@angular/core": "*" } }`, }; const indexTs: File = { path: "/index.ts", - content: "" + content: "", }; - const host = createServerHost([angularFormsDts, angularFormsPackageJson, tsconfig, packageJson, indexTs, libFile]); - const session = createSession(host, { serverMode: ts.LanguageServiceMode.PartialSemantic, useSingleInferredProject: true, logger: createLoggerWithInMemoryLogs(host) }); + const host = createServerHost([ + angularFormsDts, + angularFormsPackageJson, + tsconfig, + packageJson, + indexTs, + libFile, + ]); + const session = createSession(host, { + serverMode: ts.LanguageServiceMode.PartialSemantic, + useSingleInferredProject: true, + logger: createLoggerWithInMemoryLogs(host), + }); const service = session.getProjectService(); openFilesForSession([indexTs], session); const project = service.inferredProjects[0]; assert.isFalse(project.autoImportProviderHost); assert.isUndefined(project.getPackageJsonAutoImportProvider()); assert.deepEqual(project.getPackageJsonsForAutoImport(), ts.emptyArray); - baselineTsserverLogs("partialSemanticServer", "should not create autoImportProvider or handle package jsons", session); + baselineTsserverLogs( + "partialSemanticServer", + "should not create autoImportProvider or handle package jsons", + session, + ); }); it("should support go-to-definition on module specifiers", () => { @@ -227,7 +251,7 @@ function fooB() { }` openFilesForSession([file1], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: protocolFileLocationFromSubstring(file1, `"./b"`) + arguments: protocolFileLocationFromSubstring(file1, `"./b"`), }); baselineTsserverLogs("partialSemanticServer", "should support go-to-definition on module specifiers", session); }); diff --git a/src/testRunner/unittests/tsserver/plugins.ts b/src/testRunner/unittests/tsserver/plugins.ts index df0befc74e0d1..da37ac6094a4c 100644 --- a/src/testRunner/unittests/tsserver/plugins.ts +++ b/src/testRunner/unittests/tsserver/plugins.ts @@ -28,13 +28,13 @@ describe("unittests:: tsserver:: plugins:: loading", () => { info.session?.addProtocolHandler(testProtocolCommand, request => { session.logger.log(`addProtocolHandler: ${JSON.stringify(request, undefined, " ")}`); return { - response: testProtocolCommandResponse + response: testProtocolCommandResponse, }; }); return Harness.LanguageService.makeDefaultProxy(info); - } + }, }), - error: undefined + error: undefined, }; }; const session = createSession(host, { ...opts, logger: createLoggerWithInMemoryLogs(host) }); @@ -51,10 +51,10 @@ describe("unittests:: tsserver:: plugins:: loading", () => { compilerOptions: { plugins: [ ...[...expectedToLoad, ...notToLoad].map(name => ({ name })), - { transform: "some-transform" } - ] - } - }) + { transform: "some-transform" }, + ], + }, + }), }; const { session } = createHostWithPlugin([aTs, tsconfig, libFile]); openFilesForSession([aTs], session); @@ -67,9 +67,11 @@ describe("unittests:: tsserver:: plugins:: loading", () => { const aTs: File = { path: "/a.ts", content: `class c { prop = "hello"; foo() { return this.prop; } }` }; const tsconfig: File = { path: "/tsconfig.json", - content: "{}" + content: "{}", }; - const { session } = createHostWithPlugin([aTs, tsconfig, libFile], { globalPlugins: [...expectedToLoad, ...notToLoad] }); + const { session } = createHostWithPlugin([aTs, tsconfig, libFile], { + globalPlugins: [...expectedToLoad, ...notToLoad], + }); openFilesForSession([aTs], session); baselineTsserverLogs("plugins", "With global plugins", session); }); @@ -82,10 +84,10 @@ describe("unittests:: tsserver:: plugins:: loading", () => { content: JSON.stringify({ compilerOptions: { plugins: [ - { name: pluginName } - ] - } - }) + { name: pluginName }, + ], + }, + }), }; const { session } = createHostWithPlugin([aTs, tsconfig, libFile]); @@ -94,7 +96,7 @@ describe("unittests:: tsserver:: plugins:: loading", () => { session.executeCommandSeq({ command: testProtocolCommand, - arguments: testProtocolCommandRequest + arguments: testProtocolCommandRequest, }); baselineTsserverLogs("plugins", "With session and custom protocol message", session); @@ -106,9 +108,9 @@ describe("unittests:: tsserver:: plugins:: loading", () => { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - plugins: [{ name: "some-plugin" }] - } - }) + plugins: [{ name: "some-plugin" }], + }, + }), }; const externalFiles: ts.MapLike = { @@ -124,23 +126,34 @@ describe("unittests:: tsserver:: plugins:: loading", () => { session.logger.log(`PluginFactory Invoke`); return { create: Harness.LanguageService.makeDefaultProxy, - getExternalFiles: () => externalFiles[moduleName] + getExternalFiles: () => externalFiles[moduleName], }; }, - error: undefined + error: undefined, }; }; const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([aTs], session); - session.logger.log(`ExternalFiles:: ${JSON.stringify(session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles())}`); - - host.writeFile(tsconfig.path, JSON.stringify({ - compilerOptions: { - plugins: [{ name: "some-other-plugin" }] - } - })); + session.logger.log( + `ExternalFiles:: ${ + JSON.stringify(session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles()) + }`, + ); + + host.writeFile( + tsconfig.path, + JSON.stringify({ + compilerOptions: { + plugins: [{ name: "some-other-plugin" }], + }, + }), + ); host.runQueuedTimeoutCallbacks(); - session.logger.log(`ExternalFiles:: ${JSON.stringify(session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles())}`); + session.logger.log( + `ExternalFiles:: ${ + JSON.stringify(session.getProjectService().configuredProjects.get(tsconfig.path)!.getExternalFiles()) + }`, + ); baselineTsserverLogs("plugins", "gets external files with config file reload", session); }); @@ -150,21 +163,21 @@ describe("unittests:: tsserver:: plugins:: overriding getSupportedCodeFixes", () it("getSupportedCodeFixes can be proxied", () => { const aTs: File = { path: "/a.ts", - content: `class c { prop = "hello"; foo() { const x = 0; } }` + content: `class c { prop = "hello"; foo() { const x = 0; } }`, }; const bTs: File = { path: "/b.ts", - content: aTs.content + content: aTs.content, }; const cTs: File = { path: "/c.ts", - content: aTs.content + content: aTs.content, }; const config: File = { path: "/tsconfig.json", content: JSON.stringify({ - compilerOptions: { plugins: [{ name: "myplugin" }] } - }) + compilerOptions: { plugins: [{ name: "myplugin" }] }, + }), }; const host = createServerHost([aTs, bTs, cTs, config, libFile]); host.require = () => { @@ -172,7 +185,7 @@ describe("unittests:: tsserver:: plugins:: overriding getSupportedCodeFixes", () module: () => ({ create(info: ts.server.PluginCreateInfo) { const proxy = Harness.LanguageService.makeDefaultProxy(info); - proxy.getSupportedCodeFixes = (fileName) => { + proxy.getSupportedCodeFixes = fileName => { switch (fileName) { case "/a.ts": return ["a"]; @@ -184,9 +197,9 @@ describe("unittests:: tsserver:: plugins:: overriding getSupportedCodeFixes", () } }; return proxy; - } + }, }), - error: undefined + error: undefined, }; }; const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -197,21 +210,21 @@ describe("unittests:: tsserver:: plugins:: overriding getSupportedCodeFixes", () }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetSupportedCodeFixes, - arguments: { file: aTs.path } + arguments: { file: aTs.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetSupportedCodeFixes, - arguments: { file: bTs.path } + arguments: { file: bTs.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetSupportedCodeFixes, - arguments: { file: cTs.path } + arguments: { file: cTs.path }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.GetSupportedCodeFixes, - arguments: { projectFileName: config.path } + arguments: { projectFileName: config.path }, }); baselineTsserverLogs("plugins", "getSupportedCodeFixes can be proxied", session); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/pluginsAsync.ts b/src/testRunner/unittests/tsserver/pluginsAsync.ts index 1dda2ff6d5dce..6275792e306dc 100644 --- a/src/testRunner/unittests/tsserver/pluginsAsync.ts +++ b/src/testRunner/unittests/tsserver/pluginsAsync.ts @@ -1,5 +1,7 @@ import * as ts from "../../_namespaces/ts"; -import { defer } from "../../_namespaces/Utils"; +import { + defer, +} from "../../_namespaces/Utils"; import { baselineTsserverLogs, closeFilesForSession, @@ -7,12 +9,19 @@ import { createSession, openFilesForSession, } from "../helpers/tsserver"; -import { createServerHost, libFile } from "../helpers/virtualFileSystemWithWatch"; +import { + createServerHost, + libFile, +} from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { function setup(globalPlugins: string[]) { const host = createServerHost([libFile]); - const session = createSession(host, { canUseEvents: true, globalPlugins, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + canUseEvents: true, + globalPlugins, + logger: createLoggerWithInMemoryLogs(host), + }); return { host, session }; } @@ -28,14 +37,16 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { pluginInvoked = true; return { create: info => info.languageService }; }) as ts.server.PluginModuleFactory, - error: undefined + error: undefined, }; }; openFilesForSession([{ file: "^memfs:/foo.ts", content: "" }], session); const projectService = session.getProjectService(); - session.logger.log(`This should be false because 'executeCommand' should have already triggered plugin enablement asynchronously and there are no plugin enablements currently being processed`); + session.logger.log( + `This should be false because 'executeCommand' should have already triggered plugin enablement asynchronously and there are no plugin enablements currently being processed`, + ); session.logger.log(`hasNewPluginEnablementRequests:: ${projectService.hasNewPluginEnablementRequests()}`); session.logger.log(`Should be true because async imports have already been triggered in the background`); @@ -46,7 +57,9 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { await projectService.waitForPendingPlugins(); - session.logger.log(`at this point all plugin modules should have been instantiated and all plugins should have been invoked`); + session.logger.log( + `at this point all plugin modules should have been instantiated and all plugins should have been invoked`, + ); session.logger.log(`pluginModuleInstantiated:: ${pluginModuleInstantiated}`); session.logger.log(`pluginInvoked:: ${pluginInvoked}`); @@ -67,7 +80,7 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { session.logger.log(`invoke plugin ${moduleName}`); return { create: info => info.languageService }; }) as ts.server.PluginModuleFactory, - error: undefined + error: undefined, }; }; @@ -84,7 +97,11 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { // wait for load to complete await projectService.waitForPendingPlugins(); - baselineTsserverLogs("pluginsAsync", "plugins evaluation in correct order even if imports resolve out of order", session); + baselineTsserverLogs( + "pluginsAsync", + "plugins evaluation in correct order even if imports resolve out of order", + session, + ); }); it("sends projectsUpdatedInBackground event", async () => { @@ -93,14 +110,13 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { await Promise.resolve(); // simulate at least a single turn delay return { module: (() => ({ create: info => info.languageService })) as ts.server.PluginModuleFactory, - error: undefined + error: undefined, }; }; openFilesForSession([{ file: "^memfs:/foo.ts", content: "" }], session); const projectService = session.getProjectService(); - await projectService.waitForPendingPlugins(); baselineTsserverLogs("pluginsAsync", "sends projectsUpdatedInBackground event", session); @@ -118,7 +134,7 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { create: info => info.languageService, getExternalFiles: () => ["external.txt"], })) as ts.server.PluginModuleFactory, - error: undefined + error: undefined, }; }; @@ -136,7 +152,9 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { host.runQueuedTimeoutCallbacks(); - session.logger.log(`External files before plugin after plugin is loaded: ${project.getExternalFiles().join(",")}`); + session.logger.log( + `External files before plugin after plugin is loaded: ${project.getExternalFiles().join(",")}`, + ); baselineTsserverLogs("pluginsAsync", "adds external files", session); }); @@ -152,14 +170,13 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { await projectClosed.promise; return { module: (() => ({ create: info => info.languageService })) as ts.server.PluginModuleFactory, - error: undefined + error: undefined, }; }; openFilesForSession([{ file: "^memfs:/foo.ts", content: "" }], session); const projectService = session.getProjectService(); - // wait for the plugin to start loading await pluginALoaded.promise; @@ -174,4 +191,4 @@ describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { // the project was closed before plugins were ready. no project update should have been requested baselineTsserverLogs("pluginsAsync", "project is closed before plugins are loaded", session); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/projectErrors.ts b/src/testRunner/unittests/tsserver/projectErrors.ts index 20f38c4ab8fc4..2c7e3629836a2 100644 --- a/src/testRunner/unittests/tsserver/projectErrors.ts +++ b/src/testRunner/unittests/tsserver/projectErrors.ts @@ -25,25 +25,25 @@ describe("unittests:: tsserver:: projectErrors::", () => { it("external project - diagnostics for missing files", () => { const file1 = { path: "/a/b/app.ts", - content: "" + content: "", }; const file2 = { path: "/a/b/applib.ts", - content: "" + content: "", }; const host = createServerHost([file1, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); const projectFileName = "/a/b/test.csproj"; const compilerOptionsRequest: TestSessionRequest = { command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, - arguments: { projectFileName } + arguments: { projectFileName }, }; { openExternalProjectForSession({ projectFileName, options: {}, - rootFiles: toExternalFiles([file1.path, file2.path]) + rootFiles: toExternalFiles([file1.path, file2.path]), }, session); session.executeCommandSeq(compilerOptionsRequest); @@ -66,22 +66,22 @@ describe("unittests:: tsserver:: projectErrors::", () => { it("configured projects - diagnostics for missing files", () => { const file1 = { path: "/a/b/app.ts", - content: "" + content: "", }; const file2 = { path: "/a/b/applib.ts", - content: "" + content: "", }; const config = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ files: [file1, file2].map(f => ts.getBaseFileName(f.path)) }) + content: JSON.stringify({ files: [file1, file2].map(f => ts.getBaseFileName(f.path)) }), }; const host = createServerHost([file1, config, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file1], session); const compilerOptionsRequest: TestSessionRequest = { command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, - arguments: { projectFileName: config.path } + arguments: { projectFileName: config.path }, }; session.executeCommandSeq(compilerOptionsRequest); @@ -94,19 +94,19 @@ describe("unittests:: tsserver:: projectErrors::", () => { it("configured projects - diagnostics for corrupted config 1", () => { const file1 = { path: "/a/b/app.ts", - content: "" + content: "", }; const file2 = { path: "/a/b/lib.ts", - content: "" + content: "", }; const correctConfig = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ files: [file1, file2].map(f => ts.getBaseFileName(f.path)) }) + content: JSON.stringify({ files: [file1, file2].map(f => ts.getBaseFileName(f.path)) }), }; const corruptedConfig = { path: correctConfig.path, - content: correctConfig.content.substr(1) + content: correctConfig.content.substr(1), }; const host = createServerHost([file1, file2, corruptedConfig]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -115,14 +115,14 @@ describe("unittests:: tsserver:: projectErrors::", () => { { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SynchronizeProjectList, - arguments: { knownProjects: [] } + arguments: { knownProjects: [] }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, arguments: { file: corruptedConfig.path, - projectFileName: corruptedConfig.path - } + projectFileName: corruptedConfig.path, + }, }); } // fix config and trigger watcher @@ -130,14 +130,14 @@ describe("unittests:: tsserver:: projectErrors::", () => { { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SynchronizeProjectList, - arguments: { knownProjects: [] } + arguments: { knownProjects: [] }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, arguments: { file: correctConfig.path, - projectFileName: correctConfig.path - } + projectFileName: correctConfig.path, + }, }); } baselineTsserverLogs("projectErrors", "configured projects - diagnostics for corrupted config 1", session); @@ -146,19 +146,19 @@ describe("unittests:: tsserver:: projectErrors::", () => { it("configured projects - diagnostics for corrupted config 2", () => { const file1 = { path: "/a/b/app.ts", - content: "" + content: "", }; const file2 = { path: "/a/b/lib.ts", - content: "" + content: "", }; const correctConfig = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ files: [file1, file2].map(f => ts.getBaseFileName(f.path)) }) + content: JSON.stringify({ files: [file1, file2].map(f => ts.getBaseFileName(f.path)) }), }; const corruptedConfig = { path: correctConfig.path, - content: correctConfig.content.substr(1) + content: correctConfig.content.substr(1), }; const host = createServerHost([file1, file2, correctConfig]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -167,14 +167,14 @@ describe("unittests:: tsserver:: projectErrors::", () => { { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SynchronizeProjectList, - arguments: { knownProjects: [] } + arguments: { knownProjects: [] }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, arguments: { file: correctConfig.path, - projectFileName: correctConfig.path - } + projectFileName: correctConfig.path, + }, }); } // break config and trigger watcher @@ -182,14 +182,14 @@ describe("unittests:: tsserver:: projectErrors::", () => { { session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SynchronizeProjectList, - arguments: { knownProjects: [] } + arguments: { knownProjects: [] }, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, arguments: { file: corruptedConfig.path, - projectFileName: corruptedConfig.path - } + projectFileName: corruptedConfig.path, + }, }); } baselineTsserverLogs("projectErrors", "configured projects - diagnostics for corrupted config 2", session); @@ -200,11 +200,11 @@ describe("unittests:: tsserver:: projectErrors:: are reported as appropriate", ( it("document is not contained in project", () => { const file1 = { path: "/a/b/app.ts", - content: "" + content: "", }; const corruptedConfig = { path: "/a/b/tsconfig.json", - content: "{" + content: "{", }; const host = createServerHost([file1, corruptedConfig]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -217,14 +217,18 @@ describe("unittests:: tsserver:: projectErrors:: are reported as appropriate", ( const folderPath = "/user/someuser/projects/someFolder"; const fileInRoot: File = { path: `/src/somefile.d.ts`, - content: "class c { }" + content: "class c { }", }; const fileInProjectRoot: File = { path: `${folderPath}/src/somefile.d.ts`, - content: "class c { }" + content: "class c { }", }; const host = createServerHost([libFile, fileInRoot, fileInProjectRoot]); - const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host), useInferredProjectPerProjectRoot: true }); + const session = createSession(host, { + canUseEvents: true, + logger: createLoggerWithInMemoryLogs(host), + useInferredProjectPerProjectRoot: true, + }); const untitledFile = "untitled:Untitled-1"; const refPathNotFound1 = "../../../../../../typings/@epic/Core.d.ts"; @@ -237,14 +241,20 @@ describe("unittests:: tsserver:: projectErrors:: are reported as appropriate", ( file: untitledFile, fileContent, scriptKindName: "TS", - projectRootPath: useProjectRoot ? folderPath : undefined - } + projectRootPath: useProjectRoot ? folderPath : undefined, + }, }); appendAllScriptInfos(session); // Since this is not js project so no typings are queued verifyGetErrRequest({ session, files: [untitledFile] }); - baselineTsserverLogs("projectErrors", `when opening new file that doesnt exist on disk yet ${useProjectRoot ? "with projectRoot" : "without projectRoot"}`, session); + baselineTsserverLogs( + "projectErrors", + `when opening new file that doesnt exist on disk yet ${ + useProjectRoot ? "with projectRoot" : "without projectRoot" + }`, + session, + ); } it("has projectRoot", () => { @@ -260,22 +270,22 @@ describe("unittests:: tsserver:: projectErrors:: are reported as appropriate", ( const projectDir = "/a/b/projects/myproject"; const app: File = { path: `${projectDir}/bar/app.ts`, - content: "class Bar implements foo.Foo { getFoo() { return ''; } get2() { return 1; } }" + content: "class Bar implements foo.Foo { getFoo() { return ''; } get2() { return 1; } }", }; const foo: File = { path: `${projectDir}/foo/foo.ts`, - content: "declare namespace foo { interface Foo { get2(): number; getFoo(): string; } }" + content: "declare namespace foo { interface Foo { get2(): number; getFoo(): string; } }", }; const configFile: File = { path: `${projectDir}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { module: "none", targer: "es5" }, exclude: ["node_modules"] }) + content: JSON.stringify({ compilerOptions: { module: "none", targer: "es5" }, exclude: ["node_modules"] }), }; const host = createServerHost([app, foo, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Open, - arguments: { file: app.path, } + arguments: { file: app.path }, }); verifyGetErrRequest({ session, files: [app] }); @@ -289,7 +299,7 @@ describe("unittests:: tsserver:: projectErrors:: are reported as appropriate", ( it("Getting errors before opening file", () => { const file: File = { path: "/a/b/project/file.ts", - content: "let x: number = false;" + content: "let x: number = false;", }; const host = createServerHost([file, libFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -297,8 +307,8 @@ describe("unittests:: tsserver:: projectErrors:: are reported as appropriate", ( command: ts.server.protocol.CommandTypes.Geterr, arguments: { delay: 0, - files: [file.path] - } + files: [file.path], + }, }); host.runQueuedTimeoutCallbacks(); @@ -308,26 +318,37 @@ describe("unittests:: tsserver:: projectErrors:: are reported as appropriate", ( it("Reports errors correctly when file referenced by inferred project root, is opened right after closing the root file", () => { const app: File = { path: `/user/username/projects/myproject/src/client/app.js`, - content: "" + content: "", }; const serverUtilities: File = { path: `/user/username/projects/myproject/src/server/utilities.js`, - content: `function getHostName() { return "hello"; } export { getHostName };` + content: `function getHostName() { return "hello"; } export { getHostName };`, }; const backendTest: File = { path: `/user/username/projects/myproject/test/backend/index.js`, - content: `import { getHostName } from '../../src/server/utilities';export default getHostName;` + content: `import { getHostName } from '../../src/server/utilities';export default getHostName;`, }; const files = [libFile, app, serverUtilities, backendTest]; const host = createServerHost(files); - const session = createSession(host, { useInferredProjectPerProjectRoot: true, canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + useInferredProjectPerProjectRoot: true, + canUseEvents: true, + logger: createLoggerWithInMemoryLogs(host), + }); openFilesForSession([{ file: app, projectRootPath: "/user/username/projects/myproject" }], session); openFilesForSession([{ file: backendTest, projectRootPath: "/user/username/projects/myproject" }], session); verifyGetErrRequest({ session, files: [backendTest.path, app.path] }); closeFilesForSession([backendTest], session); - openFilesForSession([{ file: serverUtilities.path, projectRootPath: "/user/username/projects/myproject" }], session); + openFilesForSession( + [{ file: serverUtilities.path, projectRootPath: "/user/username/projects/myproject" }], + session, + ); verifyGetErrRequest({ session, files: [serverUtilities.path, app.path] }); - baselineTsserverLogs("projectErrors", `reports errors correctly when file referenced by inferred project root, is opened right after closing the root file`, session); + baselineTsserverLogs( + "projectErrors", + `reports errors correctly when file referenced by inferred project root, is opened right after closing the root file`, + session, + ); }); it("Correct errors when resolution resolves to file that has same ambient module and is also module", () => { @@ -337,24 +358,24 @@ describe("unittests:: tsserver:: projectErrors:: are reported as appropriate", ( content: `import * as myModule from "@custom/plugin"; function foo() { // hello -}` +}`, }; const config: File = { path: `${projectRootPath}/tsconfig.json`, - content: JSON.stringify({ include: ["src"] }) + content: JSON.stringify({ include: ["src"] }), }; const plugin: File = { path: `${projectRootPath}/node_modules/@custom/plugin/index.d.ts`, content: `import './proposed'; declare module '@custom/plugin' { export const version: string; -}` +}`, }; const pluginProposed: File = { path: `${projectRootPath}/node_modules/@custom/plugin/proposed.d.ts`, content: `declare module '@custom/plugin' { export const bar = 10; -}` +}`, }; const files = [libFile, aFile, config, plugin, pluginProposed]; const host = createServerHost(files); @@ -371,22 +392,26 @@ declare module '@custom/plugin' { offset: 8, endLine: 3, endOffset: 8, - insertString: "o" - } + insertString: "o", + }, }); verifyGetErrRequest({ session, files: [aFile] }); - baselineTsserverLogs("projectErrors", `correct errors when resolution resolves to file that has same ambient module and is also module`, session); + baselineTsserverLogs( + "projectErrors", + `correct errors when resolution resolves to file that has same ambient module and is also module`, + session, + ); }); describe("when semantic error returns includes global error", () => { const file: File = { path: `/user/username/projects/myproject/ui.ts`, content: `const x = async (_action: string) => { -};` +};`, }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; verifyGetErrScenario({ scenario: "projectErrors", @@ -404,7 +429,7 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e it("are generated when the config file has errors", () => { const file: File = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const configFile: File = { path: "/a/b/tsconfig.json", @@ -413,41 +438,49 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e "foo": "bar", "allowJS": true } - }` + }`, }; const host = createServerHost([file, libFile, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file has errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are generated when the config file has errors", + session, + ); }); it("are generated when the config file doesn't have errors", () => { const file: File = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": {} - }` + }`, }; const host = createServerHost([file, libFile, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file doesnt have errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are generated when the config file doesnt have errors", + session, + ); }); it("are generated when the config file changes", () => { const file: File = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const configFile = { path: "/a/b/tsconfig.json", content: `{ "compilerOptions": {} - }` + }`, }; const host = createServerHost([file, libFile, configFile]); @@ -467,21 +500,25 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e }`; host.writeFile(configFile.path, configFile.content); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are generated when the config file changes", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are generated when the config file changes", + session, + ); }); it("are not generated when the config file does not include file opened and config file has errors", () => { const file: File = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const file2: File = { path: "/a/b/test.ts", - content: "let x = 10" + content: "let x = 10", }; const file3: File = { path: "/a/b/test2.ts", - content: "let xy = 10" + content: "let xy = 10", }; const configFile: File = { path: "/a/b/tsconfig.json", @@ -491,7 +528,7 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e "allowJS": true }, "files": ["app.ts"] - }` + }`, }; const host = createServerHost([file, libFile, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -499,13 +536,17 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e openFilesForSession([file], session); // We generate only if project is created when opening file from the project openFilesForSession([file3], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file does not include file opened and config file has errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are not generated when the config file does not include file opened and config file has errors", + session, + ); }); it("are not generated when the config file has errors but suppressDiagnosticEvents is true", () => { const file: File = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const configFile: File = { path: "/a/b/tsconfig.json", @@ -514,32 +555,40 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e "foo": "bar", "allowJS": true } - }` + }`, }; const host = createServerHost([file, libFile, configFile]); - const session = createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + canUseEvents: true, + suppressDiagnosticEvents: true, + logger: createLoggerWithInMemoryLogs(host), + }); openFilesForSession([file], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file has errors but suppressDiagnosticEvents is true", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are not generated when the config file has errors but suppressDiagnosticEvents is true", + session, + ); }); it("are not generated when the config file does not include file opened and doesnt contain any errors", () => { const file: File = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const file2: File = { path: "/a/b/test.ts", - content: "let x = 10" + content: "let x = 10", }; const file3: File = { path: "/a/b/test2.ts", - content: "let xy = 10" + content: "let xy = 10", }; const configFile: File = { path: "/a/b/tsconfig.json", content: `{ "files": ["app.ts"] - }` + }`, }; const host = createServerHost([file, file2, file3, libFile, configFile]); @@ -548,13 +597,17 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e openFilesForSession([file], session); // We generate only if project is created when opening file from the project openFilesForSession([file3], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events are not generated when the config file does not include file opened and doesnt contain any errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events are not generated when the config file does not include file opened and doesnt contain any errors", + session, + ); }); it("contains the project reference errors", () => { const file: File = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const noSuchTsconfig = "no-such-tsconfig.json"; const configFile: File = { @@ -562,13 +615,17 @@ describe("unittests:: tsserver:: Project Errors for Configure file diagnostics e content: `{ "files": ["app.ts"], "references": [{"path":"./${noSuchTsconfig}"}] - }` + }`, }; const host = createServerHost([file, libFile, configFile]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([file], session); - baselineTsserverLogs("projectErrors", "configFileDiagnostic events contains the project reference errors", session); + baselineTsserverLogs( + "projectErrors", + "configFileDiagnostic events contains the project reference errors", + session, + ); }); }); @@ -576,7 +633,7 @@ describe("unittests:: tsserver:: projectErrors:: dont include overwrite emit err it("for inferred project", () => { const f1 = { path: "/a/b/f1.js", - content: "function test1() { }" + content: "function test1() { }", }; const host = createServerHost([f1, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -586,13 +643,13 @@ describe("unittests:: tsserver:: projectErrors:: dont include overwrite emit err const projectFileName = projectService.inferredProjects[0].getProjectName(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, - arguments: { projectFileName } + arguments: { projectFileName }, }); setCompilerOptionsForInferredProjectsRequestForSession({ module: ts.ModuleKind.CommonJS }, session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, - arguments: { projectFileName } + arguments: { projectFileName }, }); baselineTsserverLogs("projectErrors", "for inferred project", session); }); @@ -600,7 +657,7 @@ describe("unittests:: tsserver:: projectErrors:: dont include overwrite emit err it("for external project", () => { const f1 = { path: "/a/b/f1.js", - content: "function test1() { }" + content: "function test1() { }", }; const host = createServerHost([f1, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -609,22 +666,22 @@ describe("unittests:: tsserver:: projectErrors:: dont include overwrite emit err openExternalProjectForSession({ projectFileName, rootFiles: externalFiles, - options: {} + options: {}, }, session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, - arguments: { projectFileName } + arguments: { projectFileName }, }); openExternalProjectForSession({ projectFileName, rootFiles: externalFiles, - options: { module: ts.ModuleKind.CommonJS } + options: { module: ts.ModuleKind.CommonJS }, }, session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, - arguments: { projectFileName } + arguments: { projectFileName }, }); baselineTsserverLogs("projectErrors", "for external project", session); }); @@ -634,7 +691,7 @@ describe("unittests:: tsserver:: projectErrors:: reports Options Diagnostic loca it("when options change", () => { const file = { path: "/a/b/app.ts", - content: "let x = 10" + content: "let x = 10", }; const configFileContentBeforeComment = `{`; const configFileContentComment = ` @@ -645,12 +702,13 @@ describe("unittests:: tsserver:: projectErrors:: reports Options Diagnostic loca "mapRoot": "./" } }`; - const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + configFileContentAfterComment; + const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + + configFileContentAfterComment; const configFileContentWithoutCommentLine = configFileContentBeforeComment + configFileContentAfterComment; const configFile = { path: "/a/b/tsconfig.json", - content: configFileContentWithComment + content: configFileContentWithComment, }; const host = createServerHost([file, libFile, configFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -658,14 +716,14 @@ describe("unittests:: tsserver:: projectErrors:: reports Options Diagnostic loca session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, - arguments: { file: configFile.path, projectFileName: configFile.path, includeLinePosition: true } + arguments: { file: configFile.path, projectFileName: configFile.path, includeLinePosition: true }, }); host.writeFile(configFile.path, configFileContentWithoutCommentLine); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, - arguments: { file: configFile.path, projectFileName: configFile.path, includeLinePosition: true } + arguments: { file: configFile.path, projectFileName: configFile.path, includeLinePosition: true }, }); baselineTsserverLogs("projectErrors", "when options change", session); }); @@ -674,7 +732,8 @@ describe("unittests:: tsserver:: projectErrors:: reports Options Diagnostic loca describe("unittests:: tsserver:: projectErrors:: with config file change", () => { it("Updates diagnostics when '--noUnusedLabels' changes", () => { const aTs: File = { path: "/a.ts", content: "label: while (1) {}" }; - const options = (allowUnusedLabels: boolean) => `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`; + const options = (allowUnusedLabels: boolean) => + `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`; const tsconfig: File = { path: "/tsconfig.json", content: options(/*allowUnusedLabels*/ true) }; const host = createServerHost([aTs, tsconfig]); @@ -686,7 +745,7 @@ describe("unittests:: tsserver:: projectErrors:: with config file change", () => session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, - arguments: { file: aTs.path } + arguments: { file: aTs.path }, }); baselineTsserverLogs("projectErrors", `diagnostics after noUnusedLabels changes`, session); }); @@ -698,21 +757,21 @@ describe("unittests:: tsserver:: projectErrors:: with resolveJsonModule", () => path: `/user/username/projects/myproject/src/test.ts`, content: `import * as blabla from "./blabla.json"; declare var console: any; -console.log(blabla);` +console.log(blabla);`, }; const blabla: File = { path: `/user/username/projects/myproject/src/blabla.json`, - content: "{}" + content: "{}", }; const tsconfig: File = { path: `/user/username/projects/myproject/tsconfig.json`, content: JSON.stringify({ compilerOptions: { resolveJsonModule: true, - composite: true + composite: true, }, - include - }) + include, + }), }; const host = createServerHost([test, blabla, libFile, tsconfig]); @@ -723,18 +782,26 @@ console.log(blabla);` it("should not report incorrect error when json is root file found by tsconfig", () => { const { session, test } = createSessionForTest({ - include: ["./src/*.ts", "./src/*.json"] + include: ["./src/*.ts", "./src/*.json"], }); verifyGetErrRequest({ session, files: [test] }); - baselineTsserverLogs("projectErrors", `should not report incorrect error when json is root file found by tsconfig`, session); + baselineTsserverLogs( + "projectErrors", + `should not report incorrect error when json is root file found by tsconfig`, + session, + ); }); it("should report error when json is not root file found by tsconfig", () => { const { session, test } = createSessionForTest({ - include: ["./src/*.ts"] + include: ["./src/*.ts"], }); verifyGetErrRequest({ session, files: [test] }); - baselineTsserverLogs("projectErrors", `should report error when json is not root file found by tsconfig`, session); + baselineTsserverLogs( + "projectErrors", + `should report error when json is not root file found by tsconfig`, + session, + ); }); }); @@ -742,16 +809,16 @@ describe("unittests:: tsserver:: projectErrors:: with npm install when", () => { function verifyNpmInstall(timeoutDuringPartialInstallation: boolean) { const main: File = { path: `/user/username/projects/myproject/src/main.ts`, - content: "import * as _a from '@angular/core';" + content: "import * as _a from '@angular/core';", }; const config: File = { path: `/user/username/projects/myproject/tsconfig.json`, - content: "{}" + content: "{}", }; // Move things from staging to node_modules without triggering watch const moduleFile: File = { path: `/user/username/projects/myproject/node_modules/@angular/core/index.d.ts`, - content: `export const y = 10;` + content: `export const y = 10;`, }; const projectFiles = [main, libFile, config]; const host = createServerHost(projectFiles); @@ -772,15 +839,29 @@ describe("unittests:: tsserver:: projectErrors:: with npm install when", () => { verifyWhileNpmInstall(); filesAndFoldersToAdd = [ - { path: `/user/username/projects/myproject/node_modules/.staging/@angular/platform-browser-dynamic-5efaaa1a` }, - { path: `/user/username/projects/myproject/node_modules/.staging/@angular/cli-c1e44b05/models/analytics.d.ts`, content: `export const x = 10;` }, - { path: `/user/username/projects/myproject/node_modules/.staging/@angular/core-0963aebf/index.d.ts`, content: `export const y = 10;` }, + { + path: + `/user/username/projects/myproject/node_modules/.staging/@angular/platform-browser-dynamic-5efaaa1a`, + }, + { + path: + `/user/username/projects/myproject/node_modules/.staging/@angular/cli-c1e44b05/models/analytics.d.ts`, + content: `export const x = 10;`, + }, + { + path: `/user/username/projects/myproject/node_modules/.staging/@angular/core-0963aebf/index.d.ts`, + content: `export const y = 10;`, + }, ]; // Since we added/removed in .staging no timeout verifyWhileNpmInstall(); filesAndFoldersToAdd = []; - host.ensureFileOrFolder(moduleFile, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true, /*ignoreParentWatch*/ true); + host.ensureFileOrFolder( + moduleFile, + /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true, + /*ignoreParentWatch*/ true, + ); // Since we added/removed in .staging no timeout verifyWhileNpmInstall(); @@ -791,7 +872,11 @@ describe("unittests:: tsserver:: projectErrors:: with npm install when", () => { // Additional watch for watching script infos from node_modules verifyWhileNpmInstall(); - baselineTsserverLogs("projectErrors", `npm install when timeout occurs ${timeoutDuringPartialInstallation ? "inbetween" : "after"} installation`, session); + baselineTsserverLogs( + "projectErrors", + `npm install when timeout occurs ${timeoutDuringPartialInstallation ? "inbetween" : "after"} installation`, + session, + ); function verifyWhileNpmInstall() { filesAndFoldersToAdd.forEach(f => host.ensureFileOrFolder(f)); @@ -802,7 +887,11 @@ describe("unittests:: tsserver:: projectErrors:: with npm install when", () => { else { session.testhost.logTimeoutQueueLength(); } - verifyGetErrRequest({ session, files: [main], existingTimeouts: !npmInstallComplete && !timeoutDuringPartialInstallation }); + verifyGetErrRequest({ + session, + files: [main], + existingTimeouts: !npmInstallComplete && !timeoutDuringPartialInstallation, + }); } } diff --git a/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts b/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts index e9f24f00bf8b0..49a92747aa780 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceCompileOnSave.ts @@ -1,5 +1,7 @@ import * as ts from "../../_namespaces/ts"; -import { ensureErrorFreeBuild } from "../helpers/solutionBuilder"; +import { + ensureErrorFreeBuild, +} from "../helpers/solutionBuilder"; import { baselineTsserverLogs, createLoggerWithInMemoryLogs, @@ -20,14 +22,14 @@ describe("unittests:: tsserver:: with project references and compile on save", ( path: `${dependecyLocation}/fns.ts`, content: `export function fn1() { } export function fn2() { } -` +`, }; const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" }, - compileOnSave: true - }) + compileOnSave: true, + }), }; const usageTs: File = { path: `${usageLocation}/usage.ts`, @@ -37,14 +39,14 @@ export function fn2() { } } from '../decls/fns' fn1(); fn2(); -` +`, }; const usageConfig: File = { path: `${usageLocation}/tsconfig.json`, content: JSON.stringify({ compileOnSave: true, - references: [{ path: "../dependency" }] - }) + references: [{ path: "../dependency" }], + }), }; const localChange = "function fn3() { }"; @@ -60,21 +62,25 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage", + session, + ); }); it("with initial file open, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -84,21 +90,25 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project", + session, + ); }); it("with local change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -107,28 +117,32 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${localChange}`); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage and local change to dependency", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -137,28 +151,32 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${localChange}`); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project and local change to dependency", + session, + ); }); it("with local change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -167,7 +185,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -178,28 +196,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage and local change to usage", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -208,7 +230,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -219,28 +241,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project and local change to usage", + session, + ); }); it("with change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -249,28 +275,32 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${change}`); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and change to depenedency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage and change to depenedency", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -279,28 +309,32 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${change}`); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and change to depenedency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project and change to depenedency", + session, + ); }); it("with change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -309,7 +343,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -320,28 +354,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage and change to usage", + session, + ); }); it("with change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -350,7 +388,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -361,28 +399,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on usage with project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on usage with project and change to usage", + session, + ); }); }); @@ -395,21 +437,25 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency", + session, + ); }); it("with initial file open, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -419,21 +465,25 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project", + session, + ); }); it("with local change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -442,28 +492,32 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${localChange}`); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency and local change to dependency", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -472,28 +526,32 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${localChange}`); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project and local change to dependency", + session, + ); }); it("with local change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -502,7 +560,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -513,28 +571,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency and local change to usage", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -543,7 +605,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -554,28 +616,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project and local change to usage", + session, + ); }); it("with change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -584,28 +650,32 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${change}`); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency and change to dependency", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -614,28 +684,32 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); host.writeFile(dependencyTs.path, `${dependencyTs.content}${change}`); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project and change to dependency", + session, + ); }); it("with change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -644,7 +718,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -655,28 +729,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency and change to usage", + session, + ); }); it("with change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -685,7 +763,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -696,28 +774,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "when dependency project is not open and save on dependency with project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "when dependency project is not open and save on dependency with project and change to usage", + session, + ); }); }); }); @@ -732,19 +814,19 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage", session); }); @@ -756,19 +838,19 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project", session); }); @@ -779,7 +861,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -790,28 +872,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and local change to dependency", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -820,7 +906,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -831,28 +917,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to dependency with file", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and local change to dependency with file", + session, + ); }); it("with local change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -861,7 +951,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -872,28 +962,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and local change to usage", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -902,7 +996,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -913,28 +1007,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and local change to usage with project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and local change to usage with project", + session, + ); }); it("with change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -943,7 +1041,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -954,28 +1052,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage and change to dependency", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -984,7 +1086,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -995,28 +1097,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage with project and change to dependency", + session, + ); }); it("with change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1025,7 +1131,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -1036,26 +1142,26 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path } + arguments: { file: usageTs.path }, }); baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage and change to usage", session); }); @@ -1066,7 +1172,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -1077,27 +1183,31 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: usageTs.path, projectFileName: usageConfig.path } + arguments: { file: usageTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on usage with project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on usage with project and change to usage", + session, + ); }); }); @@ -1110,19 +1220,19 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project", session); }); @@ -1133,7 +1243,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -1144,28 +1254,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project and local change to dependency", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1174,7 +1288,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -1185,28 +1299,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project and local change to usage", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1215,7 +1333,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -1226,28 +1344,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project and change to dependency", + session, + ); }); it("with change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1256,7 +1378,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -1267,28 +1389,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: usageConfig.path } + arguments: { file: dependencyTs.path, projectFileName: usageConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with usage project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with usage project and change to usage", + session, + ); }); }); @@ -1301,19 +1427,19 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency", session); }); @@ -1325,19 +1451,19 @@ fn2(); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project", session); }); @@ -1348,7 +1474,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -1359,28 +1485,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency and local change to dependency", + session, + ); }); it("with local change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1389,7 +1519,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -1400,28 +1530,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and local change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with project and local change to dependency", + session, + ); }); it("with local change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1430,7 +1564,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -1441,28 +1575,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency and local change to usage", + session, + ); }); it("with local change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1471,7 +1609,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -1482,28 +1620,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: localChange - } + insertString: localChange, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and local change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with project and local change to usage", + session, + ); }); it("with change to dependency, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1512,7 +1654,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -1523,28 +1665,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency and change to dependency", + session, + ); }); it("with change to dependency, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1553,7 +1699,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(dependencyTs.content); const location = toLocation(dependencyTs.content.length); @@ -1564,28 +1710,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and change to dependency", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with project and change to dependency", + session, + ); }); it("with change to usage, without specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1594,7 +1744,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -1605,28 +1755,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency and change to usage", + session, + ); }); it("with change to usage, with specifying project file", () => { const host = createServerHost([dependencyTs, dependencyConfig, usageTs, usageConfig, libFile]); @@ -1635,7 +1789,7 @@ fn2(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path } + arguments: { file: dependencyTs.path }, }); const toLocation = protocolToLocation(usageTs.content); const location = toLocation(usageTs.content.length); @@ -1646,28 +1800,32 @@ fn2(); ...location, endLine: location.line, endOffset: location.offset, - insertString: change - } + insertString: change, + }, }); // Verify CompileOnSaveAffectedFileList session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveAffectedFileList, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify CompileOnSaveEmit session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); // Verify EmitOutput session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.EmitOutput, - arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path } + arguments: { file: dependencyTs.path, projectFileName: dependencyConfig.path }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "save on dependency with project and change to usage", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "save on dependency with project and change to usage", + session, + ); }); }); }); @@ -1681,9 +1839,9 @@ describe("unittests:: tsserver:: with project references and compile on save wit compileOnSave: true, compilerOptions: { module: "none", - composite: true - } - }) + composite: true, + }, + }), }; const buttonClass = `/user/username/projects/myproject/buttonClass`; const buttonConfig: File = { @@ -1691,10 +1849,10 @@ describe("unittests:: tsserver:: with project references and compile on save wit content: JSON.stringify({ extends: "../tsbase.json", compilerOptions: { - outFile: "Source.js" + outFile: "Source.js", }, - files: ["Source.ts"] - }) + files: ["Source.ts"], + }), }; const buttonSource: File = { path: `${buttonClass}/Source.ts`, @@ -1703,7 +1861,7 @@ describe("unittests:: tsserver:: with project references and compile on save wit public static myStaticFunction() { } } -}` +}`, }; const siblingClass = `/user/username/projects/myproject/SiblingClass`; @@ -1712,13 +1870,13 @@ describe("unittests:: tsserver:: with project references and compile on save wit content: JSON.stringify({ extends: "../tsbase.json", references: [{ - path: "../buttonClass/" + path: "../buttonClass/", }], compilerOptions: { - outFile: "Source.js" + outFile: "Source.js", }, - files: ["Source.ts"] - }) + files: ["Source.ts"], + }), }; const siblingSource: File = { path: `${siblingClass}/Source.ts`, @@ -1727,9 +1885,11 @@ describe("unittests:: tsserver:: with project references and compile on save wit public mySiblingFunction() { } } -}` +}`, }; - const host = createServerHost([libFile, tsbaseJson, buttonConfig, buttonSource, siblingConfig, siblingSource], { useCaseSensitiveFileNames: true }); + const host = createServerHost([libFile, tsbaseJson, buttonConfig, buttonSource, siblingConfig, siblingSource], { + useCaseSensitiveFileNames: true, + }); // ts build should succeed ensureErrorFreeBuild(host, [siblingConfig.path]); @@ -1741,9 +1901,13 @@ describe("unittests:: tsserver:: with project references and compile on save wit command: ts.server.protocol.CommandTypes.CompileOnSaveEmitFile, arguments: { file: siblingSource.path, - projectFileName: siblingConfig.path - } + projectFileName: siblingConfig.path, + }, }); - baselineTsserverLogs("projectReferenceCompileOnSave", "compile on save emits same output as project build with external project", session); + baselineTsserverLogs( + "projectReferenceCompileOnSave", + "compile on save emits same output as project build with external project", + session, + ); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts index 9b92d6c7cf0f7..d17b3df0796ad 100644 --- a/src/testRunner/unittests/tsserver/projectReferenceErrors.ts +++ b/src/testRunner/unittests/tsserver/projectReferenceErrors.ts @@ -2,13 +2,21 @@ import { GetErrForProjectDiagnostics, verifyGetErrScenario, } from "../helpers/tsserver"; -import { File } from "../helpers/virtualFileSystemWithWatch"; +import { + File, +} from "../helpers/virtualFileSystemWithWatch"; describe("unittests:: tsserver:: with project references and error reporting", () => { const dependecyLocation = `/user/username/projects/myproject/dependency`; const usageLocation = `/user/username/projects/myproject/usage`; - function verifyUsageAndDependency(scenario: string, dependencyTs: File, dependencyConfig: File, usageTs: File, usageConfig: File) { + function verifyUsageAndDependency( + scenario: string, + dependencyTs: File, + dependencyConfig: File, + usageTs: File, + usageConfig: File, + ) { function usageProjectDiagnostics(): GetErrForProjectDiagnostics { return { project: usageTs, files: [usageTs, dependencyTs] }; } @@ -28,8 +36,8 @@ describe("unittests:: tsserver:: with project references and error reporting", ( usageProjectDiagnostics(), { project: dependencyTs, - files: [dependencyTs, usageTs] - } + files: [dependencyTs, usageTs], + }, ], syncDiagnostics: () => [ // Without project @@ -51,7 +59,7 @@ describe("unittests:: tsserver:: with project references and error reporting", ( getErrRequest: () => [usageTs, dependencyTs], getErrForProjectRequest: () => [ usageProjectDiagnostics(), - dependencyProjectDiagnostics() + dependencyProjectDiagnostics(), ], syncDiagnostics: () => [ // Without project @@ -74,11 +82,11 @@ export function fn2() { } // Introduce error for fnErr import in main // export function fnErr() { } // Error in dependency ts file -export let x: string = 10;` +export let x: string = 10;`, }; const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" } }) + content: JSON.stringify({ compilerOptions: { composite: true, declarationDir: "../decls" } }), }; const usageTs: File = { path: `${usageLocation}/usage.ts`, @@ -90,14 +98,14 @@ export let x: string = 10;` fn1(); fn2(); fnErr(); -` +`, }; const usageConfig: File = { path: `${usageLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true }, - references: [{ path: "../dependency" }] - }) + references: [{ path: "../dependency" }], + }), }; verifyUsageAndDependency("with module scenario", dependencyTs, dependencyConfig, usageTs, usageConfig); }); @@ -110,25 +118,25 @@ function fn2() { } // Introduce error for fnErr import in main // function fnErr() { } // Error in dependency ts file -let x: string = 10;` +let x: string = 10;`, }; const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true, outFile: "../dependency.js" } }) + content: JSON.stringify({ compilerOptions: { composite: true, outFile: "../dependency.js" } }), }; const usageTs: File = { path: `${usageLocation}/usage.ts`, content: `fn1(); fn2(); fnErr(); -` +`, }; const usageConfig: File = { path: `${usageLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, outFile: "../usage.js" }, - references: [{ path: "../dependency" }] - }) + references: [{ path: "../dependency" }], + }), }; verifyUsageAndDependency("with non module", dependencyTs, dependencyConfig, usageTs, usageConfig); }); diff --git a/src/testRunner/unittests/tsserver/projectReferences.ts b/src/testRunner/unittests/tsserver/projectReferences.ts index e9d07963f0cab..15558f1b498a2 100644 --- a/src/testRunner/unittests/tsserver/projectReferences.ts +++ b/src/testRunner/unittests/tsserver/projectReferences.ts @@ -1,5 +1,7 @@ import * as ts from "../../_namespaces/ts"; -import { solutionBuildWithBaseline } from "../helpers/solutionBuilder"; +import { + solutionBuildWithBaseline, +} from "../helpers/solutionBuilder"; import { baselineTsserverLogs, createHostWithSolutionBuild, @@ -45,26 +47,26 @@ describe("unittests:: tsserver:: with project references and tsbuild", () => { service.openExternalProjects([{ projectFileName: getTsBuildProjectFilePath(project, project), rootFiles: files.map(f => ({ fileName: f.path })), - options: {} + options: {}, }]); files.forEach(f => { const args: ts.server.protocol.FileRequestArgs = { file: f.path, - projectFileName: ts.endsWith(f.path, "tsconfig.json") ? f.path : undefined + projectFileName: ts.endsWith(f.path, "tsconfig.json") ? f.path : undefined, }; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SyntacticDiagnosticsSync, - arguments: args + arguments: args, }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, - arguments: args + arguments: args, }); }); const containerProject = service.configuredProjects.get(containerConfig.path)!; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompilerOptionsDiagnosticsFull, - arguments: { projectFileName: containerProject.projectName } + arguments: { projectFileName: containerProject.projectName }, }); baselineTsserverLogs("projectReferences", `does not error on container only project`, session); }); @@ -76,7 +78,7 @@ describe("unittests:: tsserver:: with project references and tsbuild", () => { const myConstStart = protocolLocationFromSubstring(containerCompositeExec[1].content, "myConst"); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Rename, - arguments: { file: containerCompositeExec[1].path, ...myConstStart } + arguments: { file: containerCompositeExec[1].path, ...myConstStart }, }); baselineTsserverLogs("projectReferences", `can successfully find references with out option`, session); @@ -85,7 +87,7 @@ describe("unittests:: tsserver:: with project references and tsbuild", () => { it("ancestor and project ref management", () => { const tempFile: File = { path: `/user/username/projects/temp/temp.ts`, - content: "let x = 10" + content: "let x = 10", }; const host = createHostWithSolutionBuild(files.concat([tempFile]), [containerConfig.path]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -101,8 +103,8 @@ describe("unittests:: tsserver:: with project references and tsbuild", () => { command: ts.server.protocol.CommandTypes.Rename, arguments: { file: containerCompositeExec[1].path, - ...locationOfMyConst - } + ...locationOfMyConst, + }, }); // Open temp file and verify all projects alive @@ -128,15 +130,15 @@ describe("unittests:: tsserver:: with project references and tsbuild", () => { declarationMap: true, outDir: "../../out", baseUrl: "..", - disableSourceOfProjectReferenceRedirect + disableSourceOfProjectReferenceRedirect, }, - include: ["./**/*"] - }) + include: ["./**/*"], + }), }; const keyboardTs: File = { path: `${projectLocation}/src/common/input/keyboard.ts`, content: `function bar() { return "just a random function so .d.ts location doesnt match"; } -export function evaluateKeyboardEvent() { }` +export function evaluateKeyboardEvent() { }`, }; const keyboardTestTs: File = { path: `${projectLocation}/src/common/input/keyboard.test.ts`, @@ -144,7 +146,7 @@ export function evaluateKeyboardEvent() { }` function testEvaluateKeyboardEvent() { return evaluateKeyboardEvent(); } -` +`, }; const srcConfig: File = { path: `${projectLocation}/src/tsconfig.json`, @@ -158,13 +160,13 @@ function testEvaluateKeyboardEvent() { "common/*": ["./common/*"], }, tsBuildInfoFile: "../out/src.tsconfig.tsbuildinfo", - disableSourceOfProjectReferenceRedirect + disableSourceOfProjectReferenceRedirect, }, include: ["./**/*"], references: [ - { path: "./common" } - ] - }) + { path: "./common" }, + ], + }), }; const terminalTs: File = { path: `${projectLocation}/src/terminal.ts`, @@ -172,11 +174,11 @@ function testEvaluateKeyboardEvent() { function foo() { return evaluateKeyboardEvent(); } -` +`, }; const host = createHostWithSolutionBuild( [commonConfig, keyboardTs, keyboardTestTs, srcConfig, terminalTs, libFile], - [srcConfig.path] + [srcConfig.path], ); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([keyboardTs, terminalTs], session); @@ -184,9 +186,15 @@ function foo() { const searchStr = "evaluateKeyboardEvent"; session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(keyboardTs, searchStr) + arguments: protocolFileLocationFromSubstring(keyboardTs, searchStr), }); - baselineTsserverLogs("projectReferences", `root file is file from referenced project${disableSourceOfProjectReferenceRedirect ? " and using declaration maps" : ""}`, session); + baselineTsserverLogs( + "projectReferences", + `root file is file from referenced project${ + disableSourceOfProjectReferenceRedirect ? " and using declaration maps" : "" + }`, + session, + ); } it(`when using declaration file maps to navigate between projects`, () => { @@ -206,29 +214,29 @@ function foo() { outDir: "../dist/", rootDir: "../", baseUrl: "../", - paths: { "@ref/*": ["./dist/*"] } - } - }) + paths: { "@ref/*": ["./dist/*"] }, + }, + }), }; const aTs: File = { path: `/user/username/projects/myproject/compositea/a.ts`, - content: `import { b } from "@ref/compositeb/b";` + content: `import { b } from "@ref/compositeb/b";`, }; const a2Ts: File = { path: `/user/username/projects/myproject/compositea/a2.ts`, - content: `export const x = 10;` + content: `export const x = 10;`, }; const configB: File = { path: `/user/username/projects/myproject/compositeb/tsconfig.json`, - content: configA.content + content: configA.content, }; const bTs: File = { path: `/user/username/projects/myproject/compositeb/b.ts`, - content: "export function b() {}" + content: "export function b() {}", }; const bDts: File = { path: `/user/username/projects/myproject/dist/compositeb/b.d.ts`, - content: "export declare function b(): void;" + content: "export declare function b(): void;", }; const configC: File = { path: `/user/username/projects/myproject/compositec/tsconfig.json`, @@ -238,14 +246,14 @@ function foo() { outDir: "../dist/", rootDir: "../", baseUrl: "../", - paths: { "@ref/*": ["./*"] } + paths: { "@ref/*": ["./*"] }, }, - references: [{ path: "../compositeb" }] - }) + references: [{ path: "../compositeb" }], + }), }; const cTs: File = { path: `/user/username/projects/myproject/compositec/c.ts`, - content: aTs.content + content: aTs.content, }; const files = [libFile, aTs, a2Ts, configA, bDts, bTs, configB, cTs, configC]; const host = createServerHost(files); @@ -265,7 +273,11 @@ function foo() { service.testhost.baselineHost("a2Ts modified"); assert.isTrue(projectA.dirty); projectA.updateGraph(); - baselineTsserverLogs("projectReferences", "reusing d.ts files from composite and non composite projects", service); + baselineTsserverLogs( + "projectReferences", + "reusing d.ts files from composite and non composite projects", + service, + ); }); describe("when references are monorepo like with symlinks", () => { @@ -298,13 +310,18 @@ function foo() { }); } - function verifySession(scenario: string, { bPackageJson, aTest, bFoo, bBar, bSymlink }: Packages, alreadyBuilt: boolean, extraOptions: ts.CompilerOptions) { + function verifySession( + scenario: string, + { bPackageJson, aTest, bFoo, bBar, bSymlink }: Packages, + alreadyBuilt: boolean, + extraOptions: ts.CompilerOptions, + ) { const aConfig = config("A", extraOptions, ["../B"]); const bConfig = config("B", extraOptions); const files = [libFile, bPackageJson, aConfig, bConfig, aTest, bFoo, bBar, bSymlink]; - const host = alreadyBuilt ? - createHostWithSolutionBuild(files, [aConfig.path]) : - createServerHost(files); + const host = alreadyBuilt + ? createHostWithSolutionBuild(files, [aConfig.path]) + : createServerHost(files); // Create symlink in node module const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); @@ -318,13 +335,19 @@ function foo() { textChanges: [{ newText: "\n", start: { line: 5, offset: 1 }, - end: { line: 5, offset: 1 } - }] - }] - } + end: { line: 5, offset: 1 }, + }], + }], + }, }); verifyGetErrRequest({ session, files: [aTest] }); - baselineTsserverLogs("projectReferences", `monorepo like with symlinks ${scenario} and solution is ${alreadyBuilt ? "built" : "not built"}${extraOptions.preserveSymlinks ? " with preserveSymlinks" : ""}`, session); + baselineTsserverLogs( + "projectReferences", + `monorepo like with symlinks ${scenario} and solution is ${alreadyBuilt ? "built" : "not built"}${ + extraOptions.preserveSymlinks ? " with preserveSymlinks" : "" + }`, + session, + ); } function config(packageName: string, extraOptions: ts.CompilerOptions, references?: string[]): File { @@ -335,59 +358,70 @@ function foo() { outDir: "lib", rootDir: "src", composite: true, - ...extraOptions + ...extraOptions, }, include: ["src"], - ...(references ? { references: references.map(path => ({ path })) } : {}) - }) + ...(references ? { references: references.map(path => ({ path })) } : {}), + }), }; } function file(packageName: string, fileName: string, content: string): File { return { path: `/user/username/projects/myproject/packages/${packageName}/src/${fileName}`, - content + content, }; } function verifyMonoRepoLike(scope = "") { - verifySymlinkScenario(`when packageJson has types field and has index.ts${scope ? " with scoped package" : ""}`, () => ({ - bPackageJson: { - path: `/user/username/projects/myproject/packages/B/package.json`, - content: JSON.stringify({ - main: "lib/index.js", - types: "lib/index.d.ts" - }) - }, - aTest: file("A", "index.ts", `import { foo } from '${scope}b'; + verifySymlinkScenario( + `when packageJson has types field and has index.ts${scope ? " with scoped package" : ""}`, + () => ({ + bPackageJson: { + path: `/user/username/projects/myproject/packages/B/package.json`, + content: JSON.stringify({ + main: "lib/index.js", + types: "lib/index.d.ts", + }), + }, + aTest: file( + "A", + "index.ts", + `import { foo } from '${scope}b'; import { bar } from '${scope}b/lib/bar'; foo(); bar(); -`), - bFoo: file("B", "index.ts", `export function foo() { }`), - bBar: file("B", "bar.ts", `export function bar() { }`), - bSymlink: { - path: `/user/username/projects/myproject/node_modules/${scope}b`, - symLink: `/user/username/projects/myproject/packages/B` - } - })); +`, + ), + bFoo: file("B", "index.ts", `export function foo() { }`), + bBar: file("B", "bar.ts", `export function bar() { }`), + bSymlink: { + path: `/user/username/projects/myproject/node_modules/${scope}b`, + symLink: `/user/username/projects/myproject/packages/B`, + }, + }), + ); verifySymlinkScenario(`when referencing file from subFolder${scope ? " with scoped package" : ""}`, () => ({ bPackageJson: { path: `/user/username/projects/myproject/packages/B/package.json`, - content: "{}" + content: "{}", }, - aTest: file("A", "test.ts", `import { foo } from '${scope}b/lib/foo'; + aTest: file( + "A", + "test.ts", + `import { foo } from '${scope}b/lib/foo'; import { bar } from '${scope}b/lib/bar/foo'; foo(); bar(); -`), +`, + ), bFoo: file("B", "foo.ts", `export function foo() { }`), bBar: file("B", "bar/foo.ts", `export function bar() { }`), bSymlink: { path: `/user/username/projects/myproject/node_modules/${scope}b`, - symLink: `/user/username/projects/myproject/packages/B` - } + symLink: `/user/username/projects/myproject/packages/B`, + }, })); } @@ -408,10 +442,10 @@ bar(); allowJs: true, emitDeclarationOnly: true, outDir: "lib", - rootDir: "src" + rootDir: "src", }, - include: ["src"] - }) + include: ["src"], + }), }; const compositePackageJson: File = { path: `/user/username/projects/myproject/packages/emit-composite/package.json`, @@ -419,15 +453,15 @@ bar(); name: "emit-composite", version: "1.0.0", main: "src/index.js", - typings: "lib/index.d.ts" - }) + typings: "lib/index.d.ts", + }), }; const compositeIndex: File = { path: `/user/username/projects/myproject/packages/emit-composite/src/index.js`, content: `const testModule = require('./testModule'); module.exports = { ...testModule -}` +}`, }; const compositeTestModule: File = { path: `/user/username/projects/myproject/packages/emit-composite/src/testModule.js`, @@ -438,30 +472,43 @@ module.exports = { } module.exports = { testCompositeFunction -}` +}`, }; const consumerConfig: File = { path: `/user/username/projects/myproject/packages/consumer/tsconfig.json`, content: JSON.stringify({ include: ["src"], - references: [{ path: "../emit-composite" }] - }) + references: [{ path: "../emit-composite" }], + }), }; const consumerIndex: File = { path: `/user/username/projects/myproject/packages/consumer/src/index.ts`, content: `import { testCompositeFunction } from 'emit-composite'; testCompositeFunction('why hello there'); -testCompositeFunction('why hello there', 42);` +testCompositeFunction('why hello there', 42);`, }; const symlink: SymLink = { path: `/user/username/projects/myproject/node_modules/emit-composite`, - symLink: `/user/username/projects/myproject/packages/emit-composite` + symLink: `/user/username/projects/myproject/packages/emit-composite`, }; - const host = createServerHost([libFile, compositeConfig, compositePackageJson, compositeIndex, compositeTestModule, consumerConfig, consumerIndex, symlink], { useCaseSensitiveFileNames: true }); + const host = createServerHost([ + libFile, + compositeConfig, + compositePackageJson, + compositeIndex, + compositeTestModule, + consumerConfig, + consumerIndex, + symlink, + ], { useCaseSensitiveFileNames: true }); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([consumerIndex], session); verifyGetErrRequest({ session, files: [consumerIndex] }); - baselineTsserverLogs("projectReferences", `when the referenced projects have allowJs and emitDeclarationOnly`, session); + baselineTsserverLogs( + "projectReferences", + `when the referenced projects have allowJs and emitDeclarationOnly`, + session, + ); }); it("when finding local reference doesnt load ancestor/sibling projects", () => { @@ -474,18 +521,18 @@ testCompositeFunction('why hello there', 42);` references: [ { path: "./compiler" }, { path: "./services" }, - ] - }) + ], + }), }; const compilerConfig: File = { path: `${solutionLocation}/compiler/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, - module: "none" + module: "none", }, - files: ["./types.ts", "./program.ts"] - }) + files: ["./types.ts", "./program.ts"], + }), }; const typesFile: File = { path: `${solutionLocation}/compiler/types.ts`, @@ -494,7 +541,7 @@ testCompositeFunction('why hello there', 42);` export interface Program { getSourceFiles(): string[]; } - }` + }`, }; const programFile: File = { path: `${solutionLocation}/compiler/program.ts`, @@ -504,29 +551,38 @@ testCompositeFunction('why hello there', 42);` getSourceFiles: () => [getSourceFile()] }; function getSourceFile() { return "something"; } - }` + }`, }; const servicesConfig: File = { path: `${solutionLocation}/services/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - composite: true + composite: true, }, files: ["./services.ts"], references: [ - { path: "../compiler" } - ] - }) + { path: "../compiler" }, + ], + }), }; const servicesFile: File = { path: `${solutionLocation}/services/services.ts`, content: ` namespace ts { const result = program.getSourceFiles(); - }` + }`, }; - const files = [libFile, solution, compilerConfig, typesFile, programFile, servicesConfig, servicesFile, libFile]; + const files = [ + libFile, + solution, + compilerConfig, + typesFile, + programFile, + servicesConfig, + servicesFile, + libFile, + ]; const host = createServerHost(files); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([programFile], session); @@ -535,16 +591,20 @@ testCompositeFunction('why hello there', 42);` // Shouldnt load more projects session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(programFile, "getSourceFile", { index: 1 }) + arguments: protocolFileLocationFromSubstring(programFile, "getSourceFile", { index: 1 }), }); // Find all references for getSourceFiles // Should load more projects session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles") + arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles"), }); - baselineTsserverLogs("projectReferences", `finding local reference doesnt load ancestor/sibling projects`, session); + baselineTsserverLogs( + "projectReferences", + `finding local reference doesnt load ancestor/sibling projects`, + session, + ); }); it("when finding references in overlapping projects", () => { @@ -559,38 +619,38 @@ testCompositeFunction('why hello there', 42);` { path: "./b" }, { path: "./c" }, { path: "./d" }, - ] - }) + ], + }), }; const aConfig: File = { path: `${solutionLocation}/a/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, - module: "none" + module: "none", }, - files: ["./index.ts"] - }) + files: ["./index.ts"], + }), }; const aFile: File = { path: `${solutionLocation}/a/index.ts`, content: ` export interface I { M(): void; - }` + }`, }; const bConfig: File = { path: `${solutionLocation}/b/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - composite: true + composite: true, }, files: ["./index.ts"], references: [ - { path: "../a" } - ] - }) + { path: "../a" }, + ], + }), }; const bFile: File = { path: `${solutionLocation}/b/index.ts`, @@ -599,20 +659,20 @@ testCompositeFunction('why hello there', 42);` export class B implements I { M() {} - }` + }`, }; const cConfig: File = { path: `${solutionLocation}/c/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - composite: true + composite: true, }, files: ["./index.ts"], references: [ - { path: "../b" } - ] - }) + { path: "../b" }, + ], + }), }; const cFile: File = { path: `${solutionLocation}/c/index.ts`, @@ -621,20 +681,20 @@ testCompositeFunction('why hello there', 42);` import { B } from "../b"; export const C: I = new B(); - ` + `, }; const dConfig: File = { path: `${solutionLocation}/d/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - composite: true + composite: true, }, files: ["./index.ts"], references: [ - { path: "../c" } - ] - }) + { path: "../c" }, + ], + }), }; const dFile: File = { path: `${solutionLocation}/d/index.ts`, @@ -643,10 +703,22 @@ testCompositeFunction('why hello there', 42);` import { C } from "../c"; export const D: I = C; - ` + `, }; - const files = [libFile, solutionConfig, aConfig, aFile, bConfig, bFile, cConfig, cFile, dConfig, dFile, libFile]; + const files = [ + libFile, + solutionConfig, + aConfig, + aFile, + bConfig, + bFile, + cConfig, + cFile, + dConfig, + dFile, + libFile, + ]; const host = createServerHost(files); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([bFile], session); @@ -654,14 +726,14 @@ testCompositeFunction('why hello there', 42);` // The first search will trigger project loads session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(bFile, "I", { index: 1 }) + arguments: protocolFileLocationFromSubstring(bFile, "I", { index: 1 }), }); // The second search starts with the projects already loaded // Formerly, this would search some projects multiple times session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(bFile, "I", { index: 1 }) + arguments: protocolFileLocationFromSubstring(bFile, "I", { index: 1 }), }); baselineTsserverLogs("projectReferences", `finding references in overlapping projects`, session); @@ -678,8 +750,8 @@ testCompositeFunction('why hello there', 42);` references: [ { path: "./api" }, { path: "./app" }, - ] - }) + ], + }), }; const apiConfig: File = { path: `${solutionLocation}/api/tsconfig.json`, @@ -690,21 +762,21 @@ testCompositeFunction('why hello there', 42);` rootDir: "src", }, include: ["src"], - references: [{ path: "../shared" }] - }) + references: [{ path: "../shared" }], + }), }; const apiFile: File = { path: `${solutionLocation}/api/src/server.ts`, content: `import * as shared from "../../shared/dist"; -${usage}` +${usage}`, }; const appConfig: File = { path: `${solutionLocation}/app/tsconfig.json`, - content: apiConfig.content + content: apiConfig.content, }; const appFile: File = { path: `${solutionLocation}/app/src/app.ts`, - content: apiFile.content + content: apiFile.content, }; const sharedConfig: File = { path: `${solutionLocation}/shared/tsconfig.json`, @@ -714,21 +786,31 @@ ${usage}` outDir: "dist", rootDir: "src", }, - include: ["src"] - }) + include: ["src"], + }), }; const sharedFile: File = { path: `${solutionLocation}/shared/src/index.ts`, - content: definition + content: definition, }; - const host = createServerHost([libFile, solution, libFile, apiConfig, apiFile, appConfig, appFile, sharedConfig, sharedFile]); + const host = createServerHost([ + libFile, + solution, + libFile, + apiConfig, + apiFile, + appConfig, + appFile, + sharedConfig, + sharedFile, + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([apiFile], session); // Find all references session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(apiFile, referenceTerm) + arguments: protocolFileLocationFromSubstring(apiFile, referenceTerm), }); baselineTsserverLogs("projectReferences", `special handling of localness ${scenario}`, session); @@ -739,21 +821,21 @@ ${usage}` "when using arrow function assignment", `export const dog = () => { };`, `shared.dog();`, - "dog" + "dog", ); verify( "when using arrow function as object literal property types", `export const foo = { bar: () => { } };`, `shared.foo.bar();`, - "bar" + "bar", ); verify( "when using object literal property", `export const foo = { baz: "BAZ" };`, `shared.foo.baz;`, - "baz" + "baz", ); verify( @@ -761,17 +843,16 @@ ${usage}` `export const foo = class { fly() {} };`, `const instance = new shared.foo(); instance.fly();`, - "fly" + "fly", ); - verify( // when using arrow function as object literal property is loaded through indirect assignment with original declaration local to project is treated as local "when using arrow function as object literal property", `const local = { bar: () => { } }; export const foo = local;`, `shared.foo.bar();`, - "bar" + "bar", ); }); @@ -785,8 +866,8 @@ export const foo = local;`, references: [ { path: "./compiler" }, { path: "./services" }, - ] - }) + ], + }), }; const compilerConfig: File = { path: `${solutionLocation}/compiler/tsconfig.json`, @@ -794,10 +875,10 @@ export const foo = local;`, compilerOptions: { composite: true, module: "none", - disableSolutionSearching: true + disableSolutionSearching: true, }, - files: ["./types.ts", "./program.ts"] - }) + files: ["./types.ts", "./program.ts"], + }), }; const typesFile: File = { path: `${solutionLocation}/compiler/types.ts`, @@ -806,7 +887,7 @@ export const foo = local;`, export interface Program { getSourceFiles(): string[]; } - }` + }`, }; const programFile: File = { path: `${solutionLocation}/compiler/program.ts`, @@ -816,29 +897,38 @@ export const foo = local;`, getSourceFiles: () => [getSourceFile()] }; function getSourceFile() { return "something"; } - }` + }`, }; const servicesConfig: File = { path: `${solutionLocation}/services/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - composite: true + composite: true, }, files: ["./services.ts"], references: [ - { path: "../compiler" } - ] - }) + { path: "../compiler" }, + ], + }), }; const servicesFile: File = { path: `${solutionLocation}/services/services.ts`, content: ` namespace ts { const result = program.getSourceFiles(); - }` + }`, }; - const files = [libFile, solution, compilerConfig, typesFile, programFile, servicesConfig, servicesFile, libFile]; + const files = [ + libFile, + solution, + compilerConfig, + typesFile, + programFile, + servicesConfig, + servicesFile, + libFile, + ]; const host = createServerHost(files); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([programFile], session); @@ -847,9 +937,13 @@ export const foo = local;`, // No new solutions/projects loaded session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles") + arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles"), }); - baselineTsserverLogs("projectReferences", `with disableSolutionSearching solution and siblings are not loaded`, session); + baselineTsserverLogs( + "projectReferences", + `with disableSolutionSearching solution and siblings are not loaded`, + session, + ); }); describe("when default project is solution project", () => { @@ -863,44 +957,46 @@ export const foo = local;`, const main: File = { path: `/user/username/projects/myproject/src/main.ts`, content: `import { foo } from 'helpers/functions'; -export { foo };` +export { foo };`, }; const helper: File = { path: `/user/username/projects/myproject/src/helpers/functions.ts`, - content: `export const foo = 1;` + content: `export const foo = 1;`, }; const mainDts: File = { path: `/user/username/projects/myproject/target/src/main.d.ts`, content: `import { foo } from 'helpers/functions'; export { foo }; -//# sourceMappingURL=main.d.ts.map` +//# sourceMappingURL=main.d.ts.map`, }; const mainDtsMap: File = { path: `/user/username/projects/myproject/target/src/main.d.ts.map`, - content: `{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAExC,OAAO,EAAC,GAAG,EAAC,CAAC"}` + content: + `{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAExC,OAAO,EAAC,GAAG,EAAC,CAAC"}`, }; const helperDts: File = { path: `/user/username/projects/myproject/target/src/helpers/functions.d.ts`, content: `export declare const foo = 1; -//# sourceMappingURL=functions.d.ts.map` +//# sourceMappingURL=functions.d.ts.map`, }; const helperDtsMap: File = { path: `/user/username/projects/myproject/target/src/helpers/functions.d.ts.map`, - content: `{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/helpers/functions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,GAAG,IAAI,CAAC"}` + content: + `{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/helpers/functions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,GAAG,IAAI,CAAC"}`, }; const tsconfigIndirect3: File = { path: `/user/username/projects/myproject/indirect3/tsconfig.json`, content: JSON.stringify({ compilerOptions: { - baseUrl: "../target/src/" + baseUrl: "../target/src/", }, - }) + }), }; const fileResolvingToMainDts: File = { path: `/user/username/projects/myproject/indirect3/main.ts`, content: `import { foo } from 'main'; foo; -export function bar() {}` +export function bar() {}`, }; const tsconfigSrcPath = `/user/username/projects/myproject/tsconfig-src.json`; const tsconfigPath = `/user/username/projects/myproject/tsconfig.json`; @@ -912,29 +1008,38 @@ export function bar() {}` compilerOptions: { composite: true, outDir: "./target/", - baseUrl: "./src/" + baseUrl: "./src/", }, - include: ["./src/**/*"] - }) + include: ["./src/**/*"], + }), }; const tsconfig: File = { path: tsconfigPath, content: JSON.stringify({ - ... (solutionOptions ? { compilerOptions: solutionOptions } : {}), + ...(solutionOptions ? { compilerOptions: solutionOptions } : {}), references: configRefs.map(path => ({ path })), - files: solutionFiles || [] - }) + files: solutionFiles || [], + }), }; const dummyFile: File = { path: dummyFilePath, - content: "let a = 10;" + content: "let a = 10;", }; const host = createServerHost([ - tsconfigSrc, tsconfig, main, helper, - libFile, dummyFile, - mainDts, mainDtsMap, helperDts, helperDtsMap, - tsconfigIndirect3, fileResolvingToMainDts, - ...additionalFiles]); + tsconfigSrc, + tsconfig, + main, + helper, + libFile, + dummyFile, + mainDts, + mainDtsMap, + helperDts, + helperDtsMap, + tsconfigIndirect3, + fileResolvingToMainDts, + ...additionalFiles, + ]); const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) }); const service = session.getProjectService(); service.openClientFile(main.path); @@ -947,7 +1052,11 @@ export function bar() {}` const info = service.getScriptInfoForPath(main.path as ts.Path)!; session.logger.startGroup(); session.logger.info(`getDefaultProject for ${main.path}: ${info.getDefaultProject().projectName}`); - session.logger.info(`findDefaultConfiguredProject for ${main.path}: ${service.findDefaultConfiguredProject(info)!.projectName}`); + session.logger.info( + `findDefaultConfiguredProject for ${main.path}: ${ + service.findDefaultConfiguredProject(info)!.projectName + }`, + ); session.logger.endGroup(); // Verify errors @@ -970,7 +1079,7 @@ export function bar() {}` // Find all refs session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(main, "foo", { index: 1 }) + arguments: protocolFileLocationFromSubstring(main, "foo", { index: 1 }), }).response as ts.server.protocol.ReferencesResponseBody; service.closeClientFile(main.path); @@ -982,7 +1091,7 @@ export function bar() {}` // Find all refs from dts include session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(fileResolvingToMainDts, "foo") + arguments: protocolFileLocationFromSubstring(fileResolvingToMainDts, "foo"), }).response as ts.server.protocol.ReferencesResponseBody; baselineTsserverLogs("projectReferences", input.scenario, session); } @@ -995,15 +1104,15 @@ export function bar() {}` composite: true, outDir: "./target/", baseUrl: "./src/", - ...optionsToExtend + ...optionsToExtend, }, files: [`./indirect${postfix}/main.ts`], - references: [{ path: "./tsconfig-src.json" }] - }) + references: [{ path: "./tsconfig-src.json" }], + }), }; const indirect: File = { path: `/user/username/projects/myproject/indirect${postfix}/main.ts`, - content: fileResolvingToMainDts.content + content: fileResolvingToMainDts.content, }; return { tsconfigIndirect, indirect }; } @@ -1014,7 +1123,10 @@ export function bar() {}` const info = service.getScriptInfoForPath(main.path as ts.Path)!; session.logger.startGroup(); session.logger.info(`getDefaultProject for ${main.path}: ${info.getDefaultProject().projectName}`); - session.logger.info(`findDefaultConfiguredProject for ${main.path}: ${service.findDefaultConfiguredProject(info)?.projectName}`); + session.logger.info( + `findDefaultConfiguredProject for ${main.path}: ${service.findDefaultConfiguredProject(info) + ?.projectName}`, + ); session.logger.endGroup(); // Verify collection of script infos @@ -1061,7 +1173,8 @@ export function bar() {}` it("disables looking into the child project if disableReferencedProjectLoad is set in indirect project", () => { const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true }); verifyDisableReferencedProjectLoad({ - scenario: "disables looking into the child project if disableReferencedProjectLoad is set in indirect project", + scenario: + "disables looking into the child project if disableReferencedProjectLoad is set in indirect project", configRefs: ["./tsconfig-indirect1.json"], additionalFiles: [tsconfigIndirect, indirect], }); @@ -1071,7 +1184,8 @@ export function bar() {}` const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true }); const { tsconfigIndirect: tsconfigIndirect2, indirect: indirect2 } = getIndirectProject("2"); verifyDisableReferencedProjectLoad({ - scenario: "disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", + scenario: + "disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", configRefs: ["./tsconfig-indirect1.json", "./tsconfig-indirect2.json"], additionalFiles: [tsconfigIndirect, indirect, tsconfigIndirect2, indirect2], }); @@ -1081,14 +1195,15 @@ export function bar() {}` it("when the project found is not solution but references open file through project reference", () => { const ownMain: File = { path: `/user/username/projects/myproject/own/main.ts`, - content: fileResolvingToMainDts.content + content: fileResolvingToMainDts.content, }; verifySolutionScenario({ - scenario: "solution with its own files and project found is not solution but references open file through project reference", + scenario: + "solution with its own files and project found is not solution but references open file through project reference", solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", - baseUrl: "./src/" + baseUrl: "./src/", }, configRefs: ["./tsconfig-src.json"], additionalFiles: [ownMain], @@ -1099,7 +1214,7 @@ export function bar() {}` const ownMain: File = { path: `/user/username/projects/myproject/own/main.ts`, content: `import { bar } from 'main'; -bar;` +bar;`, }; const { tsconfigIndirect, indirect } = getIndirectProject("1"); const { tsconfigIndirect: tsconfigIndirect2, indirect: indirect2 } = getIndirectProject("2"); @@ -1108,7 +1223,7 @@ bar;` solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", - baseUrl: "./indirect1/" + baseUrl: "./indirect1/", }, configRefs: ["./tsconfig-indirect1.json", "./tsconfig-indirect2.json"], additionalFiles: [tsconfigIndirect, indirect, tsconfigIndirect2, indirect2, ownMain], @@ -1118,15 +1233,16 @@ bar;` it("disables looking into the child project if disableReferencedProjectLoad is set", () => { const ownMain: File = { path: `/user/username/projects/myproject/own/main.ts`, - content: fileResolvingToMainDts.content + content: fileResolvingToMainDts.content, }; verifyDisableReferencedProjectLoad({ - scenario: "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set", + scenario: + "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set", solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", baseUrl: "./src/", - disableReferencedProjectLoad: true + disableReferencedProjectLoad: true, }, configRefs: ["./tsconfig-src.json"], additionalFiles: [ownMain], @@ -1137,11 +1253,12 @@ bar;` const ownMain: File = { path: `/user/username/projects/myproject/own/main.ts`, content: `import { bar } from 'main'; -bar;` +bar;`, }; const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true }); verifyDisableReferencedProjectLoad({ - scenario: "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set in indirect project", + scenario: + "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set in indirect project", solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", @@ -1156,12 +1273,13 @@ bar;` const ownMain: File = { path: `/user/username/projects/myproject/own/main.ts`, content: `import { bar } from 'main'; -bar;` +bar;`, }; const { tsconfigIndirect, indirect } = getIndirectProject("1", { disableReferencedProjectLoad: true }); const { tsconfigIndirect: tsconfigIndirect2, indirect: indirect2 } = getIndirectProject("2"); verifyDisableReferencedProjectLoad({ - scenario: "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", + scenario: + "solution with its own files and disables looking into the child project if disableReferencedProjectLoad is set in first indirect project but not in another one", solutionFiles: [`./own/main.ts`], solutionOptions: { outDir: "./target/", @@ -1181,18 +1299,18 @@ bar;` content: JSON.stringify({ compilerOptions: { module: "none", - composite: true + composite: true, }, - exclude: ["temp"] - }) + exclude: ["temp"], + }), }; const class1: File = { path: `/user/username/projects/myproject/projects/project1/class1.ts`, - content: `class class1 {}` + content: `class class1 {}`, }; const class1Dts: File = { path: `/user/username/projects/myproject/projects/project1/class1.d.ts`, - content: `declare class class1 {}` + content: `declare class class1 {}`, }; const config2: File = { path: `/user/username/projects/myproject/projects/project2/tsconfig.json`, @@ -1200,16 +1318,16 @@ bar;` compilerOptions: { module: "none", composite: true, - ...(extendOptionsProject2 || {}) + ...(extendOptionsProject2 || {}), }, references: [ - { path: "../project1" } - ] - }) + { path: "../project1" }, + ], + }), }; const class2: File = { path: `/user/username/projects/myproject/projects/project2/class2.ts`, - content: `class class2 {}` + content: `class class2 {}`, }; const host = createServerHost([config1, class1, class1Dts, config2, class2, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -1226,14 +1344,21 @@ bar;` host.runQueuedTimeoutCallbacks(); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); host.runQueuedTimeoutCallbacks(); // Add output from new class to referenced project const class3Dts = `/user/username/projects/myproject/projects/project1/class3.d.ts`; host.writeFile(class3Dts, `declare class class3 {}`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is not open`, session); + baselineTsserverLogs( + "projectReferences", + `new file is added to the referenced project when referenced project is not open`, + session, + ); }); it("when referenced project is open", () => { @@ -1245,13 +1370,20 @@ bar;` host.writeFile(class3, `class class3 {}`); host.runQueuedTimeoutCallbacks(); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); host.runQueuedTimeoutCallbacks(); // Add output from new class to referenced project const class3Dts = `/user/username/projects/myproject/projects/project1/class3.d.ts`; host.writeFile(class3Dts, `declare class class3 {}`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is open`, session); + baselineTsserverLogs( + "projectReferences", + `new file is added to the referenced project when referenced project is open`, + session, + ); }); it("when referenced project is not open with disableSourceOfProjectReferenceRedirect", () => { @@ -1266,7 +1398,10 @@ bar;` host.writeFile(class3Dts, `declare class class3 {}`); host.runQueuedTimeoutCallbacks(); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); host.runQueuedTimeoutCallbacks(); // Delete output from new class to referenced project host.deleteFile(class3Dts); @@ -1274,7 +1409,11 @@ bar;` // Write back output of new class to referenced project host.writeFile(class3Dts, `declare class class3 {}`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is not open with disableSourceOfProjectReferenceRedirect`, session); + baselineTsserverLogs( + "projectReferences", + `new file is added to the referenced project when referenced project is not open with disableSourceOfProjectReferenceRedirect`, + session, + ); }); it("when referenced project is open with disableSourceOfProjectReferenceRedirect", () => { @@ -1290,7 +1429,10 @@ bar;` host.writeFile(class3Dts, `declare class class3 {}`); host.runQueuedTimeoutCallbacks(); // Add excluded file to referenced project - host.ensureFileOrFolder({ path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, content: `declare class file {}` }); + host.ensureFileOrFolder({ + path: `/user/username/projects/myproject/projects/project1/temp/file.d.ts`, + content: `declare class file {}`, + }); host.runQueuedTimeoutCallbacks(); // Delete output from new class to referenced project host.deleteFile(class3Dts); @@ -1298,7 +1440,11 @@ bar;` // Write back output of new class to referenced project host.writeFile(class3Dts, `declare class class3 {}`); host.runQueuedTimeoutCallbacks(); - baselineTsserverLogs("projectReferences", `new file is added to the referenced project when referenced project is open with disableSourceOfProjectReferenceRedirect`, session); + baselineTsserverLogs( + "projectReferences", + `new file is added to the referenced project when referenced project is open with disableSourceOfProjectReferenceRedirect`, + session, + ); }); }); @@ -1310,22 +1456,22 @@ bar;` files: [], references: [ { path: "shared/src/library" }, - { path: "app/src/program" } - ] - }) + { path: "app/src/program" }, + ], + }), }; const sharedConfig: File = { path: `/user/username/projects/myproject/shared/src/library/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, - outDir: "../../bld/library" - } - }) + outDir: "../../bld/library", + }, + }), }; const sharedIndex: File = { path: `/user/username/projects/myproject/shared/src/library/index.ts`, - content: `export function foo() {}` + content: `export function foo() {}`, }; const sharedPackage: File = { path: `/user/username/projects/myproject/shared/package.json`, @@ -1333,8 +1479,8 @@ bar;` name: "shared", version: "1.0.0", main: "bld/library/index.js", - types: "bld/library/index.d.ts" - }) + types: "bld/library/index.d.ts", + }), }; const appConfig: File = { path: `/user/username/projects/myproject/app/src/program/tsconfig.json`, @@ -1342,26 +1488,36 @@ bar;` compilerOptions: { composite: true, outDir: "../../bld/program", - disableSourceOfProjectReferenceRedirect + disableSourceOfProjectReferenceRedirect, }, references: [ - { path: "../../../shared/src/library" } - ] - }) + { path: "../../../shared/src/library" }, + ], + }), }; const appBar: File = { path: `/user/username/projects/myproject/app/src/program/bar.ts`, - content: `import {foo} from "shared";` + content: `import {foo} from "shared";`, }; const appIndex: File = { path: `/user/username/projects/myproject/app/src/program/index.ts`, - content: `foo` + content: `foo`, }; const sharedSymlink: SymLink = { path: `/user/username/projects/myproject/node_modules/shared`, - symLink: `/user/username/projects/myproject/shared` + symLink: `/user/username/projects/myproject/shared`, }; - const files = [solnConfig, sharedConfig, sharedIndex, sharedPackage, appConfig, appBar, appIndex, sharedSymlink, libFile]; + const files = [ + solnConfig, + sharedConfig, + sharedIndex, + sharedPackage, + appConfig, + appBar, + appIndex, + sharedSymlink, + libFile, + ]; const host = createServerHost(files); if (built) { solutionBuildWithBaseline(host, [solnConfig.path]); @@ -1378,9 +1534,15 @@ bar;` endLine: 1, endOffset: 4, errorCodes: [ts.Diagnostics.Cannot_find_name_0.code], - } + }, }); - baselineTsserverLogs("projectReferences", `auto import with referenced project${built ? " when built" : ""}${disableSourceOfProjectReferenceRedirect ? " with disableSourceOfProjectReferenceRedirect": ""}`, session); + baselineTsserverLogs( + "projectReferences", + `auto import with referenced project${built ? " when built" : ""}${ + disableSourceOfProjectReferenceRedirect ? " with disableSourceOfProjectReferenceRedirect" : "" + }`, + session, + ); } it("when project is built", () => { @@ -1395,40 +1557,79 @@ bar;` }); it("when files from two projects are open and one project references", () => { - function getPackageAndFile(packageName: string, references?: string[], optionsToExtend?: ts.CompilerOptions): [file: File, config: File] { + function getPackageAndFile( + packageName: string, + references?: string[], + optionsToExtend?: ts.CompilerOptions, + ): [file: File, config: File] { const file: File = { path: `/user/username/projects/myproject/${packageName}/src/file1.ts`, - content: `export const ${packageName}Const = 10;` + content: `export const ${packageName}Const = 10;`, }; const config: File = { path: `/user/username/projects/myproject/${packageName}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, ...optionsToExtend || {} }, - references: references?.map(path => ({ path: `../${path}` })) - }) + references: references?.map(path => ({ path: `../${path}` })), + }), }; return [file, config]; } - const [mainFile, mainConfig] = getPackageAndFile("main", ["core", "indirect", "noCoreRef1", "indirectDisabledChildLoad1", "indirectDisabledChildLoad2", "refToCoreRef3", "indirectNoCoreRef"]); + const [mainFile, mainConfig] = getPackageAndFile("main", [ + "core", + "indirect", + "noCoreRef1", + "indirectDisabledChildLoad1", + "indirectDisabledChildLoad2", + "refToCoreRef3", + "indirectNoCoreRef", + ]); const [coreFile, coreConfig] = getPackageAndFile("core"); const [noCoreRef1File, noCoreRef1Config] = getPackageAndFile("noCoreRef1"); const [indirectFile, indirectConfig] = getPackageAndFile("indirect", ["coreRef1"]); const [coreRef1File, coreRef1Config] = getPackageAndFile("coreRef1", ["core"]); - const [indirectDisabledChildLoad1File, indirectDisabledChildLoad1Config] = getPackageAndFile("indirectDisabledChildLoad1", ["coreRef2"], { disableReferencedProjectLoad: true }); + const [indirectDisabledChildLoad1File, indirectDisabledChildLoad1Config] = getPackageAndFile( + "indirectDisabledChildLoad1", + ["coreRef2"], + { disableReferencedProjectLoad: true }, + ); const [coreRef2File, coreRef2Config] = getPackageAndFile("coreRef2", ["core"]); - const [indirectDisabledChildLoad2File, indirectDisabledChildLoad2Config] = getPackageAndFile("indirectDisabledChildLoad2", ["coreRef3"], { disableReferencedProjectLoad: true }); + const [indirectDisabledChildLoad2File, indirectDisabledChildLoad2Config] = getPackageAndFile( + "indirectDisabledChildLoad2", + ["coreRef3"], + { disableReferencedProjectLoad: true }, + ); const [coreRef3File, coreRef3Config] = getPackageAndFile("coreRef3", ["core"]); const [refToCoreRef3File, refToCoreRef3Config] = getPackageAndFile("refToCoreRef3", ["coreRef3"]); const [indirectNoCoreRefFile, indirectNoCoreRefConfig] = getPackageAndFile("indirectNoCoreRef", ["noCoreRef2"]); const [noCoreRef2File, noCoreRef2Config] = getPackageAndFile("noCoreRef2"); const host = createServerHost([ - libFile, mainFile, mainConfig, coreFile, coreConfig, noCoreRef1File, noCoreRef1Config, - indirectFile, indirectConfig, coreRef1File, coreRef1Config, - indirectDisabledChildLoad1File, indirectDisabledChildLoad1Config, coreRef2File, coreRef2Config, - indirectDisabledChildLoad2File, indirectDisabledChildLoad2Config, coreRef3File, coreRef3Config, - refToCoreRef3File, refToCoreRef3Config, - indirectNoCoreRefFile, indirectNoCoreRefConfig, noCoreRef2File, noCoreRef2Config + libFile, + mainFile, + mainConfig, + coreFile, + coreConfig, + noCoreRef1File, + noCoreRef1Config, + indirectFile, + indirectConfig, + coreRef1File, + coreRef1Config, + indirectDisabledChildLoad1File, + indirectDisabledChildLoad1Config, + coreRef2File, + coreRef2Config, + indirectDisabledChildLoad2File, + indirectDisabledChildLoad2Config, + coreRef3File, + coreRef3Config, + refToCoreRef3File, + refToCoreRef3Config, + indirectNoCoreRefFile, + indirectNoCoreRefConfig, + noCoreRef2File, + noCoreRef2Config, ], { useCaseSensitiveFileNames: true }); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([mainFile, coreFile], session); @@ -1436,9 +1637,13 @@ bar;` // Find all refs in coreFile session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(coreFile, `coreConst`) + arguments: protocolFileLocationFromSubstring(coreFile, `coreConst`), }); - baselineTsserverLogs("projectReferences", `when files from two projects are open and one project references`, session); + baselineTsserverLogs( + "projectReferences", + `when files from two projects are open and one project references`, + session, + ); }); describe("find refs to decl in other proj", () => { @@ -1446,7 +1651,7 @@ bar;` path: `/user/username/projects/myproject/a/index.ts`, content: `import { B } from "../b/lib"; -const b: B = new B();` +const b: B = new B();`, }; const configB: File = { @@ -1457,21 +1662,21 @@ const b: B = new B();` "outDir": "lib", "composite": true } -}` +}`, }; const indexB: File = { path: `/user/username/projects/myproject/b/index.ts`, content: `export class B { M() {} -}` +}`, }; const helperB: File = { path: `/user/username/projects/myproject/b/helper.ts`, content: `import { B } from "."; -const b: B = new B();` +const b: B = new B();`, }; const dtsB: File = { @@ -1479,30 +1684,30 @@ const b: B = new B();` content: `export declare class B { M(): void; } -//# sourceMappingURL=index.d.ts.map` +//# sourceMappingURL=index.d.ts.map`, }; const dtsMapB: File = { path: `/user/username/projects/myproject/b/lib/index.d.ts.map`, - content: `{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;IACV,CAAC;CACJ"}` + content: + `{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;IACV,CAAC;CACJ"}`, }; function baselineDisableReferencedProjectLoad( projectAlreadyLoaded: boolean, disableReferencedProjectLoad: boolean, disableSourceOfProjectReferenceRedirect: boolean, - dtsMapPresent: boolean) { - + dtsMapPresent: boolean, + ) { // Mangled to stay under windows path length limit - const subScenario = - `when proj ${projectAlreadyLoaded ? "is" : "is not"} loaded` + - ` and refd proj loading is ${disableReferencedProjectLoad ? "disabled" : "enabled"}` + - ` and proj ref redirects are ${disableSourceOfProjectReferenceRedirect ? "disabled" : "enabled"}` + - ` and a decl map is ${dtsMapPresent ? "present" : "missing"}`; + const subScenario = `when proj ${projectAlreadyLoaded ? "is" : "is not"} loaded` + + ` and refd proj loading is ${disableReferencedProjectLoad ? "disabled" : "enabled"}` + + ` and proj ref redirects are ${disableSourceOfProjectReferenceRedirect ? "disabled" : "enabled"}` + + ` and a decl map is ${dtsMapPresent ? "present" : "missing"}`; const compilerOptions: ts.CompilerOptions = { disableReferencedProjectLoad, disableSourceOfProjectReferenceRedirect, - composite: true + composite: true, }; it(subScenario, () => { @@ -1511,48 +1716,57 @@ const b: B = new B();` content: `{ "compilerOptions": ${JSON.stringify(compilerOptions)}, "references": [{ "path": "../b" }] - }` + }`, }; - const host = createServerHost([configA, indexA, configB, indexB, helperB, dtsB, ...(dtsMapPresent ? [dtsMapB] : [])]); + const host = createServerHost([ + configA, + indexA, + configB, + indexB, + helperB, + dtsB, + ...(dtsMapPresent ? [dtsMapB] : []), + ]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); openFilesForSession([indexA, ...(projectAlreadyLoaded ? [helperB] : [])], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.References, - arguments: protocolFileLocationFromSubstring(indexA, `B`, { index: 1 }) + arguments: protocolFileLocationFromSubstring(indexA, `B`, { index: 1 }), }); baselineTsserverLogs("projectReferences", `find refs to decl in other proj ${subScenario}`, session); }); } /* eslint-disable local/argument-trivia */ - - // Pre-loaded = A file from project B is already open when FAR is invoked - // dRPL = Project A has disableReferencedProjectLoad - // dSOPRR = Project A has disableSourceOfProjectReferenceRedirect - // Map = The declaration map file b/lib/index.d.ts.map exists - // B refs = files under directory b in which references are found (all scenarios find all references in a/index.ts) - - // Pre-loaded | dRPL | dSOPRR | Map | B state | Notes | B refs | Notes - // -----------+--------+--------+----------+------------+--------------+---------------------+--------------------------------------------------- - baselineDisableReferencedProjectLoad(true, true, true, true); // Pre-loaded | | index.ts, helper.ts | Via map and pre-loaded project - baselineDisableReferencedProjectLoad(true, true, true, false); // Pre-loaded | | lib/index.d.ts | Even though project is loaded - baselineDisableReferencedProjectLoad(true, true, false, true); // Pre-loaded | | index.ts, helper.ts | - baselineDisableReferencedProjectLoad(true, true, false, false); // Pre-loaded | | index.ts, helper.ts | - baselineDisableReferencedProjectLoad(true, false, true, true); // Pre-loaded | | index.ts, helper.ts | Via map and pre-loaded project - baselineDisableReferencedProjectLoad(true, false, true, false); // Pre-loaded | | lib/index.d.ts | Even though project is loaded - baselineDisableReferencedProjectLoad(true, false, false, true); // Pre-loaded | | index.ts, helper.ts | - baselineDisableReferencedProjectLoad(true, false, false, false); // Pre-loaded | | index.ts, helper.ts | - baselineDisableReferencedProjectLoad(false, true, true, true); // Not loaded | | lib/index.d.ts | Even though map is present - baselineDisableReferencedProjectLoad(false, true, true, false); // Not loaded | | lib/index.d.ts | - baselineDisableReferencedProjectLoad(false, true, false, true); // Not loaded | | index.ts | But not helper.ts, which is not referenced from a - baselineDisableReferencedProjectLoad(false, true, false, false); // Not loaded | | index.ts | But not helper.ts, which is not referenced from a - baselineDisableReferencedProjectLoad(false, false, true, true); // Loaded | Via map | index.ts, helper.ts | Via map and newly loaded project - baselineDisableReferencedProjectLoad(false, false, true, false); // Not loaded | | lib/index.d.ts | - baselineDisableReferencedProjectLoad(false, false, false, true); // Loaded | Via redirect | index.ts, helper.ts | - baselineDisableReferencedProjectLoad(false, false, false, false); // Loaded | Via redirect | index.ts, helper.ts | - + // dprint-ignore + { + // Pre-loaded = A file from project B is already open when FAR is invoked + // dRPL = Project A has disableReferencedProjectLoad + // dSOPRR = Project A has disableSourceOfProjectReferenceRedirect + // Map = The declaration map file b/lib/index.d.ts.map exists + // B refs = files under directory b in which references are found (all scenarios find all references in a/index.ts) + + // Pre-loaded | dRPL | dSOPRR | Map | B state | Notes | B refs | Notes + // -----------+--------+--------+----------+------------+--------------+---------------------+--------------------------------------------------- + baselineDisableReferencedProjectLoad(true, true, true, true); // Pre-loaded | | index.ts, helper.ts | Via map and pre-loaded project + baselineDisableReferencedProjectLoad(true, true, true, false); // Pre-loaded | | lib/index.d.ts | Even though project is loaded + baselineDisableReferencedProjectLoad(true, true, false, true); // Pre-loaded | | index.ts, helper.ts | + baselineDisableReferencedProjectLoad(true, true, false, false); // Pre-loaded | | index.ts, helper.ts | + baselineDisableReferencedProjectLoad(true, false, true, true); // Pre-loaded | | index.ts, helper.ts | Via map and pre-loaded project + baselineDisableReferencedProjectLoad(true, false, true, false); // Pre-loaded | | lib/index.d.ts | Even though project is loaded + baselineDisableReferencedProjectLoad(true, false, false, true); // Pre-loaded | | index.ts, helper.ts | + baselineDisableReferencedProjectLoad(true, false, false, false); // Pre-loaded | | index.ts, helper.ts | + baselineDisableReferencedProjectLoad(false, true, true, true); // Not loaded | | lib/index.d.ts | Even though map is present + baselineDisableReferencedProjectLoad(false, true, true, false); // Not loaded | | lib/index.d.ts | + baselineDisableReferencedProjectLoad(false, true, false, true); // Not loaded | | index.ts | But not helper.ts, which is not referenced from a + baselineDisableReferencedProjectLoad(false, true, false, false); // Not loaded | | index.ts | But not helper.ts, which is not referenced from a + baselineDisableReferencedProjectLoad(false, false, true, true); // Loaded | Via map | index.ts, helper.ts | Via map and newly loaded project + baselineDisableReferencedProjectLoad(false, false, true, false); // Not loaded | | lib/index.d.ts | + baselineDisableReferencedProjectLoad(false, false, false, true); // Loaded | Via redirect | index.ts, helper.ts | + baselineDisableReferencedProjectLoad(false, false, false, false); // Loaded | Via redirect | index.ts, helper.ts | + } /* eslint-enable local/argument-trivia */ }); }); diff --git a/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts b/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts index d4b0637994224..d81ac9cc106e5 100644 --- a/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts +++ b/src/testRunner/unittests/tsserver/projectReferencesSourcemap.ts @@ -27,11 +27,13 @@ export function fn2() { } export function fn3() { } export function fn4() { } export function fn5() { } -` +`, }; const dependencyConfig: File = { path: `${dependecyLocation}/tsconfig.json`, - content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true, declarationDir: "../decls" } }) + content: JSON.stringify({ + compilerOptions: { composite: true, declarationMap: true, declarationDir: "../decls" }, + }), }; const mainTs: File = { @@ -49,23 +51,23 @@ fn2(); fn3(); fn4(); fn5(); -` +`, }; const mainConfig: File = { path: `${mainLocation}/tsconfig.json`, content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true }, - references: [{ path: "../dependency" }] - }) + references: [{ path: "../dependency" }], + }), }; const randomFile: File = { path: `/user/username/projects/myproject/random/random.ts`, - content: "let a = 10;" + content: "let a = 10;", }; const randomConfig: File = { path: `/user/username/projects/myproject/random/tsconfig.json`, - content: "{}" + content: "{}", }; const dtsLocation = `${dependecyDeclsLocation}/FnS.d.ts`; const dtsPath = dtsLocation.toLowerCase() as ts.Path; @@ -80,29 +82,29 @@ fn5(); host.readFile(dtsLocation)!.replace( "//# sourceMappingURL=FnS.d.ts.map", `export declare function fn6(): void; -//# sourceMappingURL=FnS.d.ts.map` - ) +//# sourceMappingURL=FnS.d.ts.map`, + ), ); } function changeDtsMapFile(host: TestServerHost) { host.writeFile( dtsMapLocation, - `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["../dependency/FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}` + `{"version":3,"file":"FnS.d.ts","sourceRoot":"","sources":["../dependency/FnS.ts"],"names":[],"mappings":"AAAA,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,wBAAgB,GAAG,SAAM;AACzB,eAAO,MAAM,CAAC,KAAK,CAAC"}`, ); } function goToDefFromMainTs(fn: number): TestSessionRequest { return { command: ts.server.protocol.CommandTypes.DefinitionAndBoundSpan, - arguments: { file: mainTs.path, line: fn + 8, offset: 1 } + arguments: { file: mainTs.path, line: fn + 8, offset: 1 }, }; } function renameFromDependencyTs(fn: number): TestSessionRequest { return { command: ts.server.protocol.CommandTypes.Rename, - arguments: { file: dependencyTs.path, line: fn, offset: 17 } + arguments: { file: dependencyTs.path, line: fn, offset: 17 }, }; } @@ -117,9 +119,18 @@ fn5(); equal: boolean, debugInfo?: string, ) { - assert.strictEqual(session.getProjectService().filenameToScriptInfo.get(dtsMapPath), dependencyMap, `${debugInfo} dependencyMap`); + assert.strictEqual( + session.getProjectService().filenameToScriptInfo.get(dtsMapPath), + dependencyMap, + `${debugInfo} dependencyMap`, + ); if (dependencyMap) { - verifyEquality(dependencyMap.documentPositionMapper, documentPositionMapper, equal, `${debugInfo} DocumentPositionMapper`); + verifyEquality( + dependencyMap.documentPositionMapper, + documentPositionMapper, + equal, + `${debugInfo} DocumentPositionMapper`, + ); } } @@ -148,7 +159,7 @@ fn5(); existingDocumentPositionMapper: ts.server.ScriptInfo["documentPositionMapper"], existingMapEqual: boolean, existingDocumentPositionMapperEqual: boolean, - skipMapPathInDtsInfo?: boolean + skipMapPathInDtsInfo?: boolean, ) { let sourceMapPath: ts.server.ScriptInfo["sourceMapFilePath"] | undefined; let dependencyMap: ts.server.ScriptInfo | undefined; @@ -174,7 +185,12 @@ fn5(); } } verifyEquality(dtsMapInfo, existingDependencyMap, existingMapEqual, `${debugInfo} dependencyMap`); - verifyEquality(existingDocumentPositionMapper, dtsMapInfo?.documentPositionMapper, existingDocumentPositionMapperEqual, `${debugInfo} DocumentPositionMapper`); + verifyEquality( + existingDocumentPositionMapper, + dtsMapInfo?.documentPositionMapper, + existingDocumentPositionMapperEqual, + `${debugInfo} DocumentPositionMapper`, + ); sourceMapPath = dtsInfo?.sourceMapFilePath; dependencyMap = dtsMapInfo; documentPositionMapper = dependencyMap?.documentPositionMapper; @@ -208,7 +224,11 @@ fn5(); type OnHostCreate = (host: TestServerHost) => void; type CreateSessionFn = (onHostCreate?: OnHostCreate) => { host: TestServerHost; session: TestSession; }; - function setupWith(createSession: CreateSessionFn, openFiles: readonly File[], onHostCreate: OnHostCreate | undefined) { + function setupWith( + createSession: CreateSessionFn, + openFiles: readonly File[], + onHostCreate: OnHostCreate | undefined, + ) { const result = createSession(onHostCreate); openFilesForSession(openFiles, result.session); return result; @@ -229,9 +249,12 @@ fn5(); function createSessionWithoutProjectReferences(onHostCreate?: OnHostCreate) { const host = createHostWithSolutionBuild(files, [mainConfig.path]); // Erase project reference - host.writeFile(mainConfig.path, JSON.stringify({ - compilerOptions: { composite: true, declarationMap: true } - })); + host.writeFile( + mainConfig.path, + JSON.stringify({ + compilerOptions: { composite: true, declarationMap: true }, + }), + ); onHostCreate?.(host); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); return { host, session }; @@ -247,14 +270,17 @@ fn5(); function createSessionWithDisabledProjectReferences(onHostCreate?: OnHostCreate) { const host = createHostWithSolutionBuild(files, [mainConfig.path]); // Erase project reference - host.writeFile(mainConfig.path, JSON.stringify({ - compilerOptions: { - composite: true, - declarationMap: true, - disableSourceOfProjectReferenceRedirect: true - }, - references: [{ path: "../dependency" }] - })); + host.writeFile( + mainConfig.path, + JSON.stringify({ + compilerOptions: { + composite: true, + declarationMap: true, + disableSourceOfProjectReferenceRedirect: true, + }, + references: [{ path: "../dependency" }], + }), + ); onHostCreate?.(host); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); return { host, session }; @@ -275,8 +301,8 @@ fn5(); offset: 1, endLine: 14, endOffset: 1, - insertString: "const x = 10;" - } + insertString: "const x = 10;", + }, }); } @@ -289,14 +315,16 @@ fn5(); offset: 1, endLine: 6, endOffset: 1, - insertString: "const x = 10;" - } + insertString: "const x = 10;", + }, }); } - describe("from project that uses dependency: goToDef", () => { - function setupWithActionWith(setup: (onHostCreate?: OnHostCreate) => ReturnType, onHostCreate: OnHostCreate | undefined) { + function setupWithActionWith( + setup: (onHostCreate?: OnHostCreate) => ReturnType, + onHostCreate: OnHostCreate | undefined, + ) { const result = setup(onHostCreate); result.session.executeCommandSeq(goToDefFromMainTs(1)); return { ...result, ...getDocumentPositionMapper(result.session) }; @@ -319,10 +347,14 @@ fn5(); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/can go to definition correctly", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/can go to definition correctly", + session, + ); }); // Edit @@ -342,9 +374,13 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -360,9 +396,13 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/usage file changes", session); }); // Edit dts to add new fn @@ -381,10 +421,14 @@ fn5(); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -399,10 +443,14 @@ fn5(); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -421,10 +469,14 @@ fn5(); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -439,10 +491,14 @@ fn5(); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -454,10 +510,14 @@ fn5(); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -473,10 +533,14 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -489,10 +553,14 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -504,10 +572,14 @@ fn5(); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -523,10 +595,14 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -539,10 +615,14 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configHasNoReference/dependency dts deleted", + session, + ); }); }); describe("when main tsconfig has project reference", () => { @@ -562,10 +642,14 @@ fn5(); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/can go to definition correctly", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/can go to definition correctly", + session, + ); }); // Edit @@ -584,10 +668,14 @@ fn5(); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -602,10 +690,14 @@ fn5(); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/usage file changes", session); }); // Edit dts to add new fn @@ -624,10 +716,14 @@ fn5(); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -643,9 +739,13 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -665,9 +765,13 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -682,10 +786,14 @@ fn5(); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -697,10 +805,14 @@ fn5(); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -716,10 +828,14 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -732,10 +848,14 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -747,10 +867,14 @@ fn5(); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -766,10 +890,14 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -782,10 +910,14 @@ fn5(); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency dts deleted", + session, + ); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -793,8 +925,11 @@ fn5(); // change // Make change, without rebuild of solution - host.writeFile(dependencyTs.path, `function fooBar() { } -${dependencyTs.content}`); + host.writeFile( + dependencyTs.path, + `function fooBar() { } +${dependencyTs.content}`, + ); host.runQueuedTimeoutCallbacks(); verifyDocumentPositionMapperEqual(session, dependencyMap, documentPositionMapper); @@ -805,9 +940,13 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency source changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency source changes with timeout before request", session); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -815,8 +954,11 @@ ${dependencyTs.content}`); // change // Make change, without rebuild of solution - host.writeFile(dependencyTs.path, `function fooBar() { } -${dependencyTs.content}`); + host.writeFile( + dependencyTs.path, + `function fooBar() { } +${dependencyTs.content}`, + ); // action verifyAllFnAction( @@ -825,9 +967,13 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/dependency source changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/dependency source changes", session); }); it("when projects are not built", () => { @@ -840,10 +986,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/configWithReference/when projects are not built", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/configWithReference/when projects are not built", + session, + ); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -863,10 +1013,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/can go to definition correctly", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/can go to definition correctly", + session, + ); }); // Edit @@ -886,9 +1040,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -903,10 +1061,14 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/usage file changes", session); }); // Edit dts to add new fn @@ -926,9 +1088,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -943,10 +1109,14 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts changes", session); }); // Edit map file to represent added new line @@ -966,9 +1136,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -984,9 +1158,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -998,10 +1176,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1017,10 +1199,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1033,10 +1219,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1048,10 +1238,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1067,10 +1261,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1083,16 +1281,23 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs]); - baselineTsserverLogs("projectReferencesSourcemap", "usageProject/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "usageProject/disabledSourceRef/dependency dts deleted", + session, + ); }); }); }); describe("from defining project: rename", () => { - function setupWithActionWith(setup: (onHostCreate?: OnHostCreate) => ReturnType, onHostCreate: OnHostCreate | undefined) { + function setupWithActionWith( + setup: (onHostCreate?: OnHostCreate) => ReturnType, + onHostCreate: OnHostCreate | undefined, + ) { const result = setup(onHostCreate); result.session.executeCommandSeq(renameFromDependencyTs(1)); return { ...result, ...getDocumentPositionMapper(result.session) }; @@ -1115,10 +1320,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/rename locations", + session, + ); }); // Edit @@ -1138,9 +1347,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1156,9 +1369,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/usage file changes", session); }); // Edit dts to add new fn @@ -1177,10 +1394,14 @@ ${dependencyTs.content}`); renameFromDependencyTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1196,9 +1417,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -1217,10 +1442,14 @@ ${dependencyTs.content}`); renameFromDependencyTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1236,9 +1465,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -1250,10 +1483,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1269,10 +1506,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1285,10 +1526,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1300,10 +1545,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1319,10 +1568,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1335,10 +1588,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configHasNoReference/dependency dts deleted", + session, + ); }); }); describe("when main tsconfig has project reference", () => { @@ -1358,10 +1615,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/rename locations", + session, + ); }); // Edit @@ -1381,9 +1642,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1398,10 +1663,14 @@ ${dependencyTs.content}`); renameFromDependencyTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/usage file changes", session); }); // Edit dts to add new fn @@ -1421,9 +1690,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1439,9 +1712,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -1461,9 +1738,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1479,9 +1760,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -1493,10 +1778,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1512,10 +1801,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1528,10 +1821,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1543,10 +1840,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1562,10 +1863,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1578,10 +1883,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency dts deleted", + session, + ); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -1592,8 +1901,14 @@ ${dependencyTs.content}`); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Change, arguments: { - file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } -`} + file: dependencyTs.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `function fooBar() { } +`, + }, }); host.runQueuedTimeoutCallbacks(); verifyDocumentPositionMapperEqual(session, dependencyMap, documentPositionMapper); @@ -1605,9 +1920,13 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency source changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency source changes with timeout before request", session); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1618,20 +1937,30 @@ ${dependencyTs.content}`); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Change, arguments: { - file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } -`} + file: dependencyTs.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `function fooBar() { } +`, + }, }); // action verifyAllFnAction( session, renameFromDependencyTsWithDependencyChange, - /*existingDependencyMap*/ undefined, - /*existingDocumentPositionMapper*/ undefined, - /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDependencyMap*/ undefined, + /*existingDocumentPositionMapper*/ undefined, + /*existingMapEqual*/ false, + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/dependency source changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/dependency source changes", session); }); it("when projects are not built", () => { @@ -1644,10 +1973,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/configWithReference/when projects are not built", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/configWithReference/when projects are not built", + session, + ); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -1667,10 +2000,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/rename locations", + session, + ); }); // Edit @@ -1690,9 +2027,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1708,9 +2049,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/usage file changes", session); }); // Edit dts to add new fn @@ -1730,9 +2075,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1748,9 +2097,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts changes", session); }); // Edit map file to represent added new line @@ -1770,9 +2123,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1788,9 +2145,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -1802,10 +2163,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1821,10 +2186,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1837,10 +2206,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -1852,10 +2225,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -1871,10 +2248,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -1887,16 +2268,23 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependency/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependency/disabledSourceRef/dependency dts deleted", + session, + ); }); }); }); describe("when opening depedency and usage project: goToDef and rename", () => { - function setupWithActionWith(setup: (onHostCreate?: OnHostCreate) => ReturnType, onHostCreate: OnHostCreate | undefined) { + function setupWithActionWith( + setup: (onHostCreate?: OnHostCreate) => ReturnType, + onHostCreate: OnHostCreate | undefined, + ) { const result = setup(onHostCreate); result.session.executeCommandSeq(goToDefFromMainTs(1)); result.session.executeCommandSeq(renameFromDependencyTs(1)); @@ -1920,7 +2308,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); const { dependencyMap, documentPositionMapper } = getDocumentPositionMapper(session); verifyAllFnAction( @@ -1929,10 +2317,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/goToDef and rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/goToDef and rename locations", + session, + ); }); // Edit @@ -1953,7 +2345,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -1961,9 +2353,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -1980,7 +2376,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -1988,9 +2384,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/usage file changes", session); }); // Edit dts to add new fn @@ -2010,7 +2410,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2018,9 +2418,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2036,7 +2440,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2044,9 +2448,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -2066,7 +2474,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); const { documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); verifyAllFnAction( @@ -2075,9 +2483,13 @@ ${dependencyTs.content}`); dependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2093,7 +2505,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); const { documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); verifyAllFnAction( @@ -2102,9 +2514,13 @@ ${dependencyTs.content}`); dependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -2116,7 +2532,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2124,10 +2540,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2143,19 +2563,24 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, newDependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2168,19 +2593,24 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, newDependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -2191,7 +2621,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2199,10 +2629,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2218,19 +2652,24 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, newDependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2243,7 +2682,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2251,10 +2690,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configHasNoReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configHasNoReference/dependency dts deleted", + session, + ); }); }); describe("when main tsconfig has project reference", () => { @@ -2274,7 +2717,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2282,10 +2725,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/gotoDef and rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/gotoDef and rename locations", + session, + ); }); // Edit @@ -2305,18 +2752,22 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, renameFromDependencyTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2333,7 +2784,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2341,9 +2792,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/usage file changes", session); }); // Edit dts to add new fn @@ -2362,18 +2817,22 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, renameFromDependencyTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2389,7 +2848,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2397,9 +2856,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts changes", session); }); // Edit map file to represent added new line @@ -2419,7 +2882,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2427,9 +2890,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2444,18 +2911,22 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, renameFromDependencyTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ false, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -2467,7 +2938,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2475,10 +2946,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2495,7 +2970,7 @@ ${dependencyTs.content}`); documentPositionMapper, /*existingMapEqual*/ true, /*existingDocumentPositionMapperEqual*/ true, - /*skipMapPathInDtsInfo*/ true + /*skipMapPathInDtsInfo*/ true, ); verifyAllFnAction( session, @@ -2503,10 +2978,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2520,7 +2999,7 @@ ${dependencyTs.content}`); documentPositionMapper, /*existingMapEqual*/ false, /*existingDocumentPositionMapperEqual*/ false, - /*skipMapPathInDtsInfo*/ true + /*skipMapPathInDtsInfo*/ true, ); verifyAllFnAction( session, @@ -2528,10 +3007,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -2543,7 +3026,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2551,10 +3034,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2570,7 +3057,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2578,10 +3065,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2594,7 +3085,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2602,10 +3093,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency dts deleted", + session, + ); }); it(`when defining project source changes, when timeout occurs before request`, () => { // Create DocumentPositionMapper @@ -2616,8 +3111,14 @@ ${dependencyTs.content}`); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Change, arguments: { - file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } -`} + file: dependencyTs.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `function fooBar() { } +`, + }, }); host.runQueuedTimeoutCallbacks(); verifyDocumentPositionMapperEqual(session, dependencyMap, documentPositionMapper); @@ -2629,7 +3130,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2637,9 +3138,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency source changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency source changes with timeout before request", session); }); it(`when defining project source changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2650,8 +3155,14 @@ ${dependencyTs.content}`); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Change, arguments: { - file: dependencyTs.path, line: 1, offset: 1, endLine: 1, endOffset: 1, insertString: `function fooBar() { } - `} + file: dependencyTs.path, + line: 1, + offset: 1, + endLine: 1, + endOffset: 1, + insertString: `function fooBar() { } + `, + }, }); // action @@ -2660,18 +3171,22 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, renameFromDependencyTsWithDependencyChange, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/dependency source changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/dependency source changes", session); }); it("when projects are not built", () => { @@ -2684,7 +3199,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2692,10 +3207,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/configWithReference/when projects are not built", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/configWithReference/when projects are not built", + session, + ); }); }); describe("when main tsconfig has disableSourceOfProjectReferenceRedirect along with project reference", () => { @@ -2715,7 +3234,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); const { dependencyMap, documentPositionMapper } = getDocumentPositionMapper(session); verifyAllFnAction( @@ -2724,10 +3243,14 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/gotoDef and rename locations", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/gotoDef and rename locations", + session, + ); }); // Edit @@ -2747,18 +3270,22 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, renameFromDependencyTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/usage file changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/usage file changes with timeout before request", session); }); it(`when usage file changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2774,18 +3301,22 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, renameFromDependencyTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/usage file changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/usage file changes", session); }); // Edit dts to add new fn @@ -2805,7 +3336,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2813,9 +3344,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts changes with timeout before request", session); }); it(`when dependency .d.ts changes, document position mapper doesnt change, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2831,7 +3366,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2839,9 +3374,13 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts changes", session); }); // Edit map file to represent added new line @@ -2860,8 +3399,8 @@ ${dependencyTs.content}`); goToDefFromMainTs, dependencyMap, documentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ false, ); const { documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); verifyAllFnAction( @@ -2869,10 +3408,14 @@ ${dependencyTs.content}`); renameFromDependencyTs, dependencyMap, newDocumentPositionMapper, - /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingMapEqual*/ true, + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes with timeout before request", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes with timeout before request", session); }); it(`when dependency file's map changes, when timeout does not occur before request`, () => { // Create DocumentPositionMapper @@ -2888,7 +3431,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); const { documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); verifyAllFnAction( @@ -2897,9 +3440,13 @@ ${dependencyTs.content}`); dependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, + ); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes", + session, ); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap changes", session); }); it(`with depedency files map file, when file is not present`, () => { @@ -2911,7 +3458,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2919,10 +3466,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap not present", + session, + ); }); it(`with depedency files map file, when file is created after actions on projects`, () => { let fileContents: string; @@ -2938,19 +3489,24 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, newDependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap created", + session, + ); }); it(`with depedency files map file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -2963,19 +3519,24 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, newDependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dtsMap deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dtsMap deleted", + session, + ); }); it(`with depedency .d.ts file, when file is not present`, () => { @@ -2987,7 +3548,7 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -2995,10 +3556,14 @@ ${dependencyTs.content}`); /*existingDependencyMap*/ undefined, /*existingDocumentPositionMapper*/ undefined, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts not present", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts not present", + session, + ); }); it(`with depedency .d.ts file, when file is created after actions on projects`, () => { let fileContents: string; @@ -3014,19 +3579,24 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ false, - /*existingDocumentPositionMapperEqual*/ false + /*existingDocumentPositionMapperEqual*/ false, ); - const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = getDocumentPositionMapper(session); + const { dependencyMap: newDependencyMap, documentPositionMapper: newDocumentPositionMapper } = + getDocumentPositionMapper(session); verifyAllFnAction( session, renameFromDependencyTs, newDependencyMap, newDocumentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts created", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts created", + session, + ); }); it(`with depedency .d.ts file, when file is deleted after actions on the projects`, () => { const { host, session, dependencyMap, documentPositionMapper } = setupWithAction(); @@ -3039,7 +3609,7 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyAllFnAction( session, @@ -3047,11 +3617,15 @@ ${dependencyTs.content}`); dependencyMap, documentPositionMapper, /*existingMapEqual*/ true, - /*existingDocumentPositionMapperEqual*/ true + /*existingDocumentPositionMapperEqual*/ true, ); verifyScriptInfoCollectionWith(session, [mainTs, dependencyTs]); - baselineTsserverLogs("projectReferencesSourcemap", "dependencyAndUsage/disabledSourceRef/dependency dts deleted", session); + baselineTsserverLogs( + "projectReferencesSourcemap", + "dependencyAndUsage/disabledSourceRef/dependency dts deleted", + session, + ); }); }); }); -}); \ No newline at end of file +}); diff --git a/src/testRunner/unittests/tsserver/projects.ts b/src/testRunner/unittests/tsserver/projects.ts index 4745650a853d6..345d795292a4a 100644 --- a/src/testRunner/unittests/tsserver/projects.ts +++ b/src/testRunner/unittests/tsserver/projects.ts @@ -32,7 +32,7 @@ describe("unittests:: tsserver:: projects::", () => { const file1: File = { path: "/a/b/commonFile1.ts", content: `/// - let x = y` + let x = y`, }; const host = createServerHost([file1, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -41,14 +41,14 @@ describe("unittests:: tsserver:: projects::", () => { // Two errors: CommonFile2 not found and cannot find name y session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); host.writeFile(commonFile2.path, commonFile2.content); host.runQueuedTimeoutCallbacks(); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.SemanticDiagnosticsSync, - arguments: { file: file1.path } + arguments: { file: file1.path }, }); baselineTsserverLogs("projects", "handles the missing files added with tripleslash ref", session); }); @@ -59,7 +59,7 @@ describe("unittests:: tsserver:: projects::", () => { content: `{ "compilerOptions": {}, "files": ["${commonFile1.path}", "${commonFile2.path}"] - }` + }`, }; const files = [commonFile1, commonFile2, configFile]; const host = createServerHost(files); @@ -75,24 +75,28 @@ describe("unittests:: tsserver:: projects::", () => { host.runQueuedTimeoutCallbacks(); // Update the configured project + refresh inferred projects openFilesForSession([commonFile2], session); - baselineTsserverLogs("projects", "should create new inferred projects for files excluded from a configured project", session); + baselineTsserverLogs( + "projects", + "should create new inferred projects for files excluded from a configured project", + session, + ); }); it("should disable features when the files are too large", () => { const file1 = { path: "/a/b/f1.js", content: "let x =1;", - fileSize: 10 * 1024 * 1024 + fileSize: 10 * 1024 * 1024, }; const file2 = { path: "/a/b/f2.js", content: "let y =1;", - fileSize: 6 * 1024 * 1024 + fileSize: 6 * 1024 * 1024, }; const file3 = { path: "/a/b/f3.js", content: "let y =1;", - fileSize: 6 * 1024 * 1024 + fileSize: 6 * 1024 * 1024, }; const proj1name = "proj1", proj2name = "proj2", proj3name = "proj3"; @@ -100,11 +104,23 @@ describe("unittests:: tsserver:: projects::", () => { const host = createServerHost([file1, file2, file3]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); - openExternalProjectForSession({ rootFiles: toExternalFiles([file1.path]), options: {}, projectFileName: proj1name }, session); + openExternalProjectForSession({ + rootFiles: toExternalFiles([file1.path]), + options: {}, + projectFileName: proj1name, + }, session); - openExternalProjectForSession({ rootFiles: toExternalFiles([file2.path]), options: {}, projectFileName: proj2name }, session); + openExternalProjectForSession({ + rootFiles: toExternalFiles([file2.path]), + options: {}, + projectFileName: proj2name, + }, session); - openExternalProjectForSession({ rootFiles: toExternalFiles([file3.path]), options: {}, projectFileName: proj3name }, session); + openExternalProjectForSession({ + rootFiles: toExternalFiles([file3.path]), + options: {}, + projectFileName: proj3name, + }, session); baselineTsserverLogs("projects", "should disable features when the files are too large", session); }); @@ -112,48 +128,63 @@ describe("unittests:: tsserver:: projects::", () => { const file1 = { path: "/a/b/f1.js", content: "let x =1;", - fileSize: 50 * 1024 * 1024 + fileSize: 50 * 1024 * 1024, }; const file2 = { path: "/a/b/f2.js", content: "let x =1;", - fileSize: 100 + fileSize: 100, }; const projName = "proj1"; const host = createServerHost([file1, file2]); - const session = createSession(host, { useSingleInferredProject: true, logger: createLoggerWithInMemoryLogs(host) }); + const session = createSession(host, { + useSingleInferredProject: true, + logger: createLoggerWithInMemoryLogs(host), + }); - openExternalProjectForSession({ rootFiles: toExternalFiles([file1.path, file2.path]), options: {}, projectFileName: projName }, session); + openExternalProjectForSession({ + rootFiles: toExternalFiles([file1.path, file2.path]), + options: {}, + projectFileName: projName, + }, session); openFilesForSession([file2], session); - baselineTsserverLogs("projects", "should not crash when opening a file in a project with a disabled language service", session); + baselineTsserverLogs( + "projects", + "should not crash when opening a file in a project with a disabled language service", + session, + ); }); describe("ignoreConfigFiles", () => { it("external project including config file", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x =1;" + content: "let x =1;", }; const config1 = { path: "/a/b/tsconfig.json", content: JSON.stringify( { compilerOptions: {}, - files: ["f1.ts"] - } - ) + files: ["f1.ts"], + }, + ), }; const externalProjectName = "externalproject"; const host = createServerHost([file1, config1]); - const projectService = createProjectService(host, { useSingleInferredProject: true, serverMode: ts.LanguageServiceMode.Syntactic, logger: createLoggerWithInMemoryLogs(host) }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + serverMode: ts.LanguageServiceMode.Syntactic, + logger: createLoggerWithInMemoryLogs(host), + }); projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path, config1.path]), options: {}, - projectFileName: externalProjectName + projectFileName: externalProjectName, }); baselineTsserverLogs("projects", "external project including config file", projectService); @@ -162,20 +193,24 @@ describe("unittests:: tsserver:: projects::", () => { it("loose file included in config file (openClientFile)", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x =1;" + content: "let x =1;", }; const config1 = { path: "/a/b/tsconfig.json", content: JSON.stringify( { compilerOptions: {}, - files: ["f1.ts"] - } - ) + files: ["f1.ts"], + }, + ), }; const host = createServerHost([file1, config1]); - const projectService = createProjectService(host, { useSingleInferredProject: true, serverMode: ts.LanguageServiceMode.Syntactic, logger: createLoggerWithInMemoryLogs(host) }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + serverMode: ts.LanguageServiceMode.Syntactic, + logger: createLoggerWithInMemoryLogs(host), + }); projectService.openClientFile(file1.path, file1.content); baselineTsserverLogs("projects", "loose file included in config file (openClientFile)", projectService); }); @@ -183,20 +218,24 @@ describe("unittests:: tsserver:: projects::", () => { it("loose file included in config file (applyCodeChanges)", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x =1;" + content: "let x =1;", }; const config1 = { path: "/a/b/tsconfig.json", content: JSON.stringify( { compilerOptions: {}, - files: ["f1.ts"] - } - ) + files: ["f1.ts"], + }, + ), }; const host = createServerHost([file1, config1]); - const projectService = createProjectService(host, { useSingleInferredProject: true, serverMode: ts.LanguageServiceMode.Syntactic, logger: createLoggerWithInMemoryLogs(host) }); + const projectService = createProjectService(host, { + useSingleInferredProject: true, + serverMode: ts.LanguageServiceMode.Syntactic, + logger: createLoggerWithInMemoryLogs(host), + }); projectService.applyChangesInOpenFiles(ts.singleIterator({ fileName: file1.path, content: file1.content })); baselineTsserverLogs("projects", "loose file included in config file (applyCodeChanges)", projectService); @@ -206,29 +245,33 @@ describe("unittests:: tsserver:: projects::", () => { it("reload regular file after closing", () => { const f1 = { path: "/a/b/app.ts", - content: "x." + content: "x.", }; const f2 = { path: "/a/b/lib.ts", - content: "let x: number;" + content: "let x: number;", }; const host = createServerHost([f1, f2, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); - openExternalProjectForSession({ projectFileName: "/a/b/project", rootFiles: toExternalFiles([f1.path, f2.path]), options: {} }, session); + openExternalProjectForSession({ + projectFileName: "/a/b/project", + rootFiles: toExternalFiles([f1.path, f2.path]), + options: {}, + }, session); openFilesForSession([f1, { file: f2.path, content: "let x: string" }], session); // should contain completions for string session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompletionInfo, - arguments: { file: f1.path, line: 1, offset: 3 } + arguments: { file: f1.path, line: 1, offset: 3 }, }); closeFilesForSession([f2], session); // should contain completions for string session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompletionInfo, - arguments: { file: f1.path, line: 1, offset: 3 } + arguments: { file: f1.path, line: 1, offset: 3 }, }); baselineTsserverLogs("projects", "reload regular file after closing", session); }); @@ -236,27 +279,31 @@ describe("unittests:: tsserver:: projects::", () => { it("clear mixed content file after closing", () => { const f1 = { path: "/a/b/app.ts", - content: " " + content: " ", }; const f2 = { path: "/a/b/lib.html", - content: "" + content: "", }; const host = createServerHost([f1, f2, libFile]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); - openExternalProjectForSession({ projectFileName: "/a/b/project", rootFiles: [{ fileName: f1.path }, { fileName: f2.path, hasMixedContent: true }], options: {} }, session); + openExternalProjectForSession({ + projectFileName: "/a/b/project", + rootFiles: [{ fileName: f1.path }, { fileName: f2.path, hasMixedContent: true }], + options: {}, + }, session); openFilesForSession([f1, { file: f2.path, content: "let somelongname: string" }], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompletionInfo, - arguments: { file: f1.path, line: 1, offset: 1 } + arguments: { file: f1.path, line: 1, offset: 1 }, }); closeFilesForSession([f2], session); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.CompletionInfo, - arguments: { file: f1.path, line: 1, offset: 1 } + arguments: { file: f1.path, line: 1, offset: 1 }, }); baselineTsserverLogs("projects", "clear mixed content file after closing", session); }); @@ -264,15 +311,15 @@ describe("unittests:: tsserver:: projects::", () => { it("changes in closed files are reflected in project structure", () => { const file1 = { path: "/a/b/f1.ts", - content: `export * from "./f2"` + content: `export * from "./f2"`, }; const file2 = { path: "/a/b/f2.ts", - content: `export let x = 1` + content: `export let x = 1`, }; const file3 = { path: "/a/c/f3.ts", - content: `export let y = 1;` + content: `export let y = 1;`, }; const host = createServerHost([file1, file2, file3]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -290,15 +337,15 @@ describe("unittests:: tsserver:: projects::", () => { it("deleted files affect project structure", () => { const file1 = { path: "/a/b/f1.ts", - content: `export * from "./f2"` + content: `export * from "./f2"`, }; const file2 = { path: "/a/b/f2.ts", - content: `export * from "../c/f3"` + content: `export * from "../c/f3"`, }; const file3 = { path: "/a/c/f3.ts", - content: `export let y = 1;` + content: `export let y = 1;`, }; const host = createServerHost([file1, file2, file3]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -314,17 +361,25 @@ describe("unittests:: tsserver:: projects::", () => { it("ignores files excluded by a custom safe type list", () => { const file1 = { path: "/a/b/f1.js", - content: "export let x = 5" + content: "export let x = 5", }; const office = { path: "/lib/duckquack-3.min.js", - content: "whoa do @@ not parse me ok thanks!!!" + content: "whoa do @@ not parse me ok thanks!!!", }; const host = createServerHost([file1, office, customTypesMap]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, office.path]) }); - projectService.logger.log(`TypeAcquisition:: ${JSON.stringify(projectService.externalProjects[0].getTypeAcquisition(), undefined, " ")}`); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles([file1.path, office.path]), + }); + projectService.logger.log( + `TypeAcquisition:: ${ + JSON.stringify(projectService.externalProjects[0].getTypeAcquisition(), undefined, " ") + }`, + ); } finally { projectService.resetSafeList(); @@ -335,15 +390,15 @@ describe("unittests:: tsserver:: projects::", () => { it("file with name constructor.js doesnt cause issue with typeAcquisition when safe type list", () => { const file1 = { path: "/a/b/f1.js", - content: `export let x = 5; import { s } from "s"` + content: `export let x = 5; import { s } from "s"`, }; const constructorFile = { path: "/a/b/constructor.js", - content: "const x = 10;" + content: "const x = 10;", }; const bliss = { path: "/a/b/bliss.js", - content: "export function is() { return true; }" + content: "export function is() { return true; }", }; const host = createServerHost([file1, libFile, constructorFile, bliss, customTypesMap]); let request: string | undefined; @@ -353,26 +408,43 @@ describe("unittests:: tsserver:: projects::", () => { installPackage: ts.notImplemented, enqueueInstallTypingsRequest: (proj, typeAcquisition, unresolvedImports) => { assert.isUndefined(request); - request = JSON.stringify(ts.server.createInstallTypingsRequest(proj, typeAcquisition, unresolvedImports || ts.server.emptyArray, cachePath)); + request = JSON.stringify( + ts.server.createInstallTypingsRequest( + proj, + typeAcquisition, + unresolvedImports || ts.server.emptyArray, + cachePath, + ), + ); }, attach: ts.noop, onProjectClosed: ts.noop, - globalTypingsCacheLocation: cachePath + globalTypingsCacheLocation: cachePath, }; const projectName = "project"; - const projectService = createProjectService(host, { typingsInstaller, logger: createLoggerWithInMemoryLogs(host) }); - projectService.openExternalProject({ projectFileName: projectName, options: {}, rootFiles: toExternalFiles([file1.path, constructorFile.path, bliss.path]) }); - assert.equal(request, JSON.stringify({ - projectName, - fileNames: [libFile.path, file1.path, constructorFile.path, bliss.path], - compilerOptions: { allowNonTsExtensions: true, noEmitForJsFiles: true }, - typeAcquisition: { include: ["blissfuljs"], exclude: [], enable: true }, - unresolvedImports: ["s"], - projectRootPath: "/", - cachePath, - kind: "discover" - })); + const projectService = createProjectService(host, { + typingsInstaller, + logger: createLoggerWithInMemoryLogs(host), + }); + projectService.openExternalProject({ + projectFileName: projectName, + options: {}, + rootFiles: toExternalFiles([file1.path, constructorFile.path, bliss.path]), + }); + assert.equal( + request, + JSON.stringify({ + projectName, + fileNames: [libFile.path, file1.path, constructorFile.path, bliss.path], + compilerOptions: { allowNonTsExtensions: true, noEmitForJsFiles: true }, + typeAcquisition: { include: ["blissfuljs"], exclude: [], enable: true }, + unresolvedImports: ["s"], + projectRootPath: "/", + cachePath, + kind: "discover", + }), + ); const response = JSON.parse(request!); request = undefined; projectService.updateTypingsForProject({ @@ -386,44 +458,56 @@ describe("unittests:: tsserver:: projects::", () => { projectService.testhost.logTimeoutQueueLength(); assert.isUndefined(request); - baselineTsserverLogs("projects", "file with name constructor.js doesnt cause issue with typeAcquisition when safe type list", projectService); + baselineTsserverLogs( + "projects", + "file with name constructor.js doesnt cause issue with typeAcquisition when safe type list", + projectService, + ); }); it("ignores files excluded by the default type list", () => { const file1 = { path: "/a/b/f1.js", - content: "export let x = 5" + content: "export let x = 5", }; const minFile = { path: "/c/moment.min.js", - content: "unspecified" + content: "unspecified", }; const kendoFile1 = { path: "/q/lib/kendo/kendo.all.min.js", - content: "unspecified" + content: "unspecified", }; const kendoFile2 = { path: "/q/lib/kendo/kendo.ui.min.js", - content: "unspecified" + content: "unspecified", }; const kendoFile3 = { path: "/q/lib/kendo-ui/kendo.all.js", - content: "unspecified" + content: "unspecified", }; const officeFile1 = { path: "/scripts/Office/1/excel-15.debug.js", - content: "unspecified" + content: "unspecified", }; const officeFile2 = { path: "/scripts/Office/1/powerpoint.js", - content: "unspecified" + content: "unspecified", }; const files = [file1, minFile, kendoFile1, kendoFile2, kendoFile3, officeFile1, officeFile2]; const host = createServerHost(files); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles(files.map(f => f.path)) }); - projectService.logger.log(`TypeAcquisition:: ${JSON.stringify(projectService.externalProjects[0].getTypeAcquisition(), undefined, " ")}`); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles(files.map(f => f.path)), + }); + projectService.logger.log( + `TypeAcquisition:: ${ + JSON.stringify(projectService.externalProjects[0].getTypeAcquisition(), undefined, " ") + }`, + ); } finally { projectService.resetSafeList(); @@ -440,7 +524,7 @@ describe("unittests:: tsserver:: projects::", () => { ["minimum", "minimum"], ["min", "min"], ["min.3.2", "min"], - ["jquery", "jquery"] + ["jquery", "jquery"], ]; for (const t of testData) { assert.equal(ts.removeMinAndVersionNumbers(t[0]), t[1], t[0]); @@ -450,20 +534,25 @@ describe("unittests:: tsserver:: projects::", () => { it("ignores files excluded by a legacy safe type list", () => { const file1 = { path: "/a/b/bliss.js", - content: "let x = 5" + content: "let x = 5", }; const file2 = { path: "/a/b/foo.js", - content: "" + content: "", }; const file3 = { path: "/a/b/Bacon.js", - content: "let y = 5" + content: "let y = 5", }; const host = createServerHost([file1, file2, file3, customTypesMap]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); try { - projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]), typeAcquisition: { enable: true } }); + projectService.openExternalProject({ + projectFileName: "project", + options: {}, + rootFiles: toExternalFiles([file1.path, file2.path]), + typeAcquisition: { enable: true }, + }); } finally { projectService.resetSafeList(); @@ -476,15 +565,15 @@ describe("unittests:: tsserver:: projects::", () => { path: "/a/b/f1.ts", content: ` export * from "../c/f2"; - export * from "../d/f3";` + export * from "../d/f3";`, }; const file2 = { path: "/a/c/f2.ts", - content: "export let x = 1;" + content: "export let x = 1;", }; const file3 = { path: "/a/d/f3.ts", - content: "export let y = 1;" + content: "export let y = 1;", }; const host = createServerHost([file1, file2, file3]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -513,20 +602,22 @@ describe("unittests:: tsserver:: projects::", () => { const tsFile = { fileName: "/a/b/file1.ts", path: "/a/b/file1.ts", - content: "" + content: "", }; const jsFile = { path: "/a/b/file1.js", content: "var x = 10;", fileName: "/a/b/file1.js", - scriptKind: "JS" as const + scriptKind: "JS" as const, }; const host = createServerHost([]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.applyChangesInOpenFiles(ts.singleIterator(tsFile)); const projs = projectService.synchronizeProjectList([]); - projectService.findProject(projs[0].info!.projectName)!.getLanguageService().getNavigationBarItems(tsFile.fileName); + projectService.findProject(projs[0].info!.projectName)!.getLanguageService().getNavigationBarItems( + tsFile.fileName, + ); projectService.synchronizeProjectList([projs[0].info!]); projectService.applyChangesInOpenFiles(ts.singleIterator(jsFile)); baselineTsserverLogs("projects", "regression test for crash in acquireOrUpdateDocument", projectService); @@ -535,15 +626,15 @@ describe("unittests:: tsserver:: projects::", () => { it("config file is deleted", () => { const file1 = { path: "/a/b/f1.ts", - content: "let x = 1;" + content: "let x = 1;", }; const file2 = { path: "/a/b/f2.ts", - content: "let y = 2;" + content: "let y = 2;", }; const config = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: {} }) + content: JSON.stringify({ compilerOptions: {} }), }; const host = createServerHost([file1, file2, config]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -560,29 +651,29 @@ describe("unittests:: tsserver:: projects::", () => { it("loading files with correct priority", () => { const f1 = { path: "/a/main.ts", - content: "let x = 1" + content: "let x = 1", }; const f2 = { path: "/a/main.js", - content: "var y = 1" + content: "var y = 1", }; const f3 = { path: "/main.js", - content: "var y = 1" + content: "var y = 1", }; const config = { path: "/a/tsconfig.json", content: JSON.stringify({ - compilerOptions: { allowJs: true } - }) + compilerOptions: { allowJs: true }, + }), }; const host = createServerHost([f1, f2, f3, config]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); projectService.setHostConfiguration({ extraFileExtensions: [ { extension: ".js", isMixedContent: false }, - { extension: ".html", isMixedContent: true } - ] + { extension: ".html", isMixedContent: true }, + ], }); projectService.openClientFile(f1.path); @@ -599,15 +690,15 @@ describe("unittests:: tsserver:: projects::", () => { it("tsconfig script block support", () => { const file1 = { path: "/a/b/f1.ts", - content: ` ` + content: ` `, }; const file2 = { path: "/a/b/f2.html", - content: `var hello = "hello";` + content: `var hello = "hello";`, }; const config = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: { allowJs: true } }) + content: JSON.stringify({ compilerOptions: { allowJs: true } }), }; const host = createServerHost([file1, file2, config]); const session = createSession(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -620,7 +711,7 @@ describe("unittests:: tsserver:: projects::", () => { // The configured project should now be updated to include html file session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { extraFileExtensions } + arguments: { extraFileExtensions }, }); // Open HTML file @@ -628,7 +719,7 @@ describe("unittests:: tsserver:: projects::", () => { fileName: file2.path, hasMixedContent: true, scriptKind: ts.ScriptKind.JS, - content: `var hello = "hello";` + content: `var hello = "hello";`, })); // Now HTML file is included in the project @@ -640,14 +731,15 @@ describe("unittests:: tsserver:: projects::", () => { position: 1, line: undefined!, offset: undefined!, - } + }, }); // Close HTML file projectService.applyChangesInOpenFiles( /*openFiles*/ undefined, /*changedFiles*/ undefined, - /*closedFiles*/[file2.path]); + /*closedFiles*/ [file2.path], + ); // HTML file is still included in project @@ -659,72 +751,98 @@ describe("unittests:: tsserver:: projects::", () => { position: 5, line: undefined!, offset: undefined!, - } + }, }); baselineTsserverLogs("projects", "tsconfig script block support", session); }); it("no tsconfig script block diagnostic errors", () => { - // #1. Ensure no diagnostic errors when allowJs is true const file1 = { path: "/a/b/f1.ts", - content: ` ` + content: ` `, }; const file2 = { path: "/a/b/f2.html", - content: `var hello = "hello";` + content: `var hello = "hello";`, }; const config1 = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: { allowJs: true } }) + content: JSON.stringify({ compilerOptions: { allowJs: true } }), }; const logger = createLoggerWithInMemoryLogs(/*host*/ undefined!); // Special // Specify .html extension as mixed content in a configure host request const extraFileExtensions = [{ extension: ".html", scriptKind: ts.ScriptKind.JS, isMixedContent: true }]; - verfiy(config1, createServerHost([file1, file2, config1, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") })); + verfiy( + config1, + createServerHost([file1, file2, config1, libFile], { + executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js"), + }), + ); // #2. Ensure no errors when allowJs is false const config2 = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: { allowJs: false } }) + content: JSON.stringify({ compilerOptions: { allowJs: false } }), }; - verfiy(config2, createServerHost([file1, file2, config2, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") })); + verfiy( + config2, + createServerHost([file1, file2, config2, libFile], { + executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js"), + }), + ); // #3. Ensure no errors when compiler options aren't specified const config3 = { path: "/a/b/tsconfig.json", - content: JSON.stringify({}) + content: JSON.stringify({}), }; - verfiy(config3, createServerHost([file1, file2, config3, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") })); + verfiy( + config3, + createServerHost([file1, file2, config3, libFile], { + executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js"), + }), + ); // #4. Ensure no errors when files are explicitly specified in tsconfig const config4 = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: { allowJs: true }, files: [file1.path, file2.path] }) + content: JSON.stringify({ compilerOptions: { allowJs: true }, files: [file1.path, file2.path] }), }; - verfiy(config4, createServerHost([file1, file2, config4, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") })); + verfiy( + config4, + createServerHost([file1, file2, config4, libFile], { + executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js"), + }), + ); // #4. Ensure no errors when files are explicitly excluded in tsconfig const config5 = { path: "/a/b/tsconfig.json", - content: JSON.stringify({ compilerOptions: { allowJs: true }, exclude: [file2.path] }) + content: JSON.stringify({ compilerOptions: { allowJs: true }, exclude: [file2.path] }), }; - const session = verfiy(config5, createServerHost([file1, file2, config5, libFile], { executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js") })); + const session = verfiy( + config5, + createServerHost([file1, file2, config5, libFile], { + executingFilePath: ts.combinePaths(ts.getDirectoryPath(libFile.path), "tsc.js"), + }), + ); baselineTsserverLogs("projects", "no tsconfig script block diagnostic errors", session); function verfiy(config: File, host: TestServerHost) { logger.host = host; - logger.log(`currentDirectory:: ${host.getCurrentDirectory()} useCaseSensitiveFileNames: ${host.useCaseSensitiveFileNames}`); + logger.log( + `currentDirectory:: ${host.getCurrentDirectory()} useCaseSensitiveFileNames: ${host.useCaseSensitiveFileNames}`, + ); const session = createSession(host, { logger }); session.executeCommandSeq({ command: ts.server.protocol.CommandTypes.Configure, - arguments: { extraFileExtensions } + arguments: { extraFileExtensions }, }); openFilesForSession([file1], session); session.executeCommandSeq({ @@ -732,7 +850,7 @@ describe("unittests:: tsserver:: projects::", () => { arguments: { file: config.path, projectFileName: config.path, - } + }, }); return session; } @@ -741,11 +859,11 @@ describe("unittests:: tsserver:: projects::", () => { it("project structure update is deferred if files are not added or removed", () => { const file1 = { path: "/a/b/f1.ts", - content: `import {x} from "./f2"` + content: `import {x} from "./f2"`, }; const file2 = { path: "/a/b/f2.ts", - content: "export let x = 1" + content: "export let x = 1", }; const host = createServerHost([file1, file2]); const projectService = createProjectService(host, { logger: createLoggerWithInMemoryLogs(host) }); @@ -755,23 +873,34 @@ describe("unittests:: tsserver:: projects::", () => { projectService.applyChangesInOpenFiles( /*openFiles*/ undefined, - /*changedFiles*/ts.singleIterator({ fileName: file1.path, changes: ts.singleIterator({ span: ts.createTextSpan(0, file1.path.length), newText: "let y = 1" }) }), - /*closedFiles*/ undefined); + /*changedFiles*/ ts.singleIterator({ + fileName: file1.path, + changes: ts.singleIterator({ span: ts.createTextSpan(0, file1.path.length), newText: "let y = 1" }), + }), + /*closedFiles*/ undefined, + ); projectService.ensureInferredProjectsUpToDate_TestOnly(); - baselineTsserverLogs("projects", "project structure update is deferred if files are not added or removed", projectService); + baselineTsserverLogs( + "projects", + "project structure update is deferred if files are not added or removed", + projectService, + ); }); it("files with mixed content are handled correctly", () => { const file1 = { path: "/a/b/f1.html", - content: `